librazor/transaction.c
author J. Ali Harlow <ali@juiblex.co.uk>
Thu Jul 07 15:18:02 2016 +0100 (2016-07-07)
changeset 480 18c1225cfa1b
parent 458 3f841a46eab5
permissions -rw-r--r--
Release 0.6.3.100
     1 /*
     2  * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
     3  * Copyright (C) 2008  Red Hat, Inc
     4  * Copyright (C) 2009, 2011, 2012, 2014  J. Ali Harlow <ali@juiblex.co.uk>
     5  *
     6  * This program is free software; you can redistribute it and/or modify
     7  * it under the terms of the GNU General Public License as published by
     8  * the Free Software Foundation; either version 2 of the License, or
     9  * (at your option) any later version.
    10  *
    11  * This program is distributed in the hope that it will be useful,
    12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    14  * GNU General Public License for more details.
    15  *
    16  * You should have received a copy of the GNU General Public License along
    17  * with this program; if not, write to the Free Software Foundation, Inc.,
    18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
    19  */
    20 
    21 #define _GNU_SOURCE
    22 
    23 #include "config.h"
    24 #include <stdlib.h>
    25 #include <stddef.h>
    26 #include <stdint.h>
    27 #include <stdio.h>
    28 #include <string.h>
    29 #include <unistd.h>
    30 #include <ctype.h>
    31 #include <assert.h>
    32 
    33 #include "razor-internal.h"
    34 #include "razor.h"
    35 
    36 static int
    37 provider_satisfies_requirement(struct razor_property *provider,
    38 			       const char *provider_strings,
    39 			       uint32_t flags,
    40 			       const char *required)
    41 {
    42 	int cmp, len;
    43 	const char *provided = &provider_strings[provider->version];
    44 
    45 	if (!*required)
    46 		return 1;
    47 	if (!*provided) {
    48 		if (flags & RAZOR_PROPERTY_LESS)
    49 			return 0;
    50 		else
    51 			return 1;
    52 	}
    53 
    54 	cmp = razor_versioncmp(provided, required);
    55 
    56 	switch (flags & RAZOR_PROPERTY_RELATION_MASK) {
    57 	case RAZOR_PROPERTY_LESS:
    58 		return cmp < 0;
    59 
    60 	case RAZOR_PROPERTY_LESS | RAZOR_PROPERTY_EQUAL:
    61 		if (cmp <= 0)
    62 			return 1;
    63 		/* fall through: FIXME, make sure this is correct */
    64 
    65 	case RAZOR_PROPERTY_EQUAL:
    66 		if (cmp == 0)
    67 			return 1;
    68 
    69 		/* "foo == 1.1" is satisfied by "foo 1.1-2" */
    70 		len = strlen(required);
    71 		if (!strncmp(required, provided, len) && provided[len] == '-')
    72 			return 1;
    73 		return 0;
    74 
    75 	case RAZOR_PROPERTY_GREATER | RAZOR_PROPERTY_EQUAL:
    76 		return cmp >= 0;
    77 
    78 	case RAZOR_PROPERTY_GREATER:
    79 		return cmp > 0;
    80 	}
    81 
    82 	/* shouldn't happen */
    83 	return 0;
    84 }
    85 
    86 #define TRANS_PACKAGE_PRESENT		1
    87 #define TRANS_PACKAGE_UPDATE		2
    88 #define TRANS_PROPERTY_SATISFIED	0x80000000
    89 
    90 struct transaction_set {
    91 	struct razor_set *set;
    92 	uint32_t *packages;
    93 	uint32_t *properties;
    94 };
    95 
    96 struct razor_transaction {
    97 	int package_count, errors;
    98 	struct transaction_set system, upstream;
    99 	int changes;
   100 	struct razor_merger *merger;
   101 };
   102 
   103 static void
   104 transaction_set_init(struct transaction_set *ts, struct razor_set *set)
   105 {
   106 	int count;
   107 
   108 	ts->set = razor_set_ref(set);
   109 	count = set->packages.size / sizeof (struct razor_package);
   110 	ts->packages = zalloc(count * sizeof *ts->packages);
   111 	count = set->properties.size / sizeof (struct razor_property);
   112 	ts->properties = zalloc(count * sizeof *ts->properties);
   113 }
   114 
   115 static void
   116 transaction_set_release(struct transaction_set *ts)
   117 {
   118 	razor_set_unref(ts->set);
   119 	free(ts->packages);
   120 	free(ts->properties);
   121 }
   122 
   123 static void
   124 transaction_set_install_package(struct transaction_set *ts,
   125 				struct razor_package *package)
   126 {
   127 	struct razor_package *pkgs;
   128 	struct list *prop;
   129 	int i;
   130 
   131 	pkgs = ts->set->packages.data;
   132 	i = package - pkgs;
   133 	if (ts->packages[i] & TRANS_PACKAGE_PRESENT)
   134 		return;
   135 
   136 	ts->packages[i] |= TRANS_PACKAGE_PRESENT;
   137 
   138 	prop = list_first(&package->properties, &ts->set->property_pool);
   139 	while (prop) {
   140 		ts->properties[prop->data]++;
   141 		prop = list_next(prop);
   142 	}
   143 }
   144 
   145 static void
   146 transaction_set_remove_package(struct transaction_set *ts,
   147 			       struct razor_package *package)
   148 {
   149 	struct razor_package *pkgs;
   150 	struct list *prop;
   151 	int i;
   152 
   153 	pkgs = ts->set->packages.data;
   154 	i = package - pkgs;
   155 	if (!(ts->packages[i] & TRANS_PACKAGE_PRESENT))
   156 		return;
   157 
   158 	ts->packages[i] &= ~TRANS_PACKAGE_PRESENT;
   159 
   160 	prop = list_first(&package->properties, &ts->set->property_pool);
   161 	while (prop) {
   162 		ts->properties[prop->data]--;
   163 		prop = list_next(prop);
   164 	}
   165 }
   166 
   167 RAZOR_EXPORT struct razor_transaction *
   168 razor_transaction_create(struct razor_set *system, struct razor_set *upstream)
   169 {
   170 	struct razor_transaction *trans;
   171 	struct razor_package *p, *spkgs, *pend;
   172 
   173 	trans = zalloc(sizeof *trans);
   174 	transaction_set_init(&trans->system, system);
   175 	transaction_set_init(&trans->upstream, upstream);
   176 
   177 	spkgs = trans->system.set->packages.data;
   178 	pend = trans->system.set->packages.data +
   179 		trans->system.set->packages.size;
   180 	for (p = spkgs; p < pend; p++)
   181 		transaction_set_install_package(&trans->system, p);
   182 
   183 	return trans;
   184 }
   185 
   186 RAZOR_EXPORT void
   187 razor_transaction_install_package(struct razor_transaction *trans,
   188 				  struct razor_package *package)
   189 {
   190 	assert (trans != NULL);
   191 	assert (package != NULL);
   192 
   193 	transaction_set_install_package(&trans->upstream, package);
   194 	trans->changes++;
   195 }
   196 
   197 RAZOR_EXPORT void
   198 razor_transaction_remove_package(struct razor_transaction *trans,
   199 				 struct razor_package *package)
   200 {
   201 	assert (trans != NULL);
   202 	assert (package != NULL);
   203 
   204 	transaction_set_remove_package(&trans->system, package);
   205 	trans->changes++;
   206 }
   207 
   208 RAZOR_EXPORT void
   209 razor_transaction_update_package(struct razor_transaction *trans,
   210 				  struct razor_package *package)
   211 {
   212 	struct razor_package *spkgs, *upkgs, *end;
   213 
   214 	assert (trans != NULL);
   215 	assert (package != NULL);
   216 
   217 	spkgs = trans->system.set->packages.data;
   218 	upkgs = trans->upstream.set->packages.data;
   219 	end = trans->system.set->packages.data +
   220 		trans->system.set->packages.size;
   221 	if (spkgs <= package && package < end)
   222 		trans->system.packages[package - spkgs] |= TRANS_PACKAGE_UPDATE;
   223 	else
   224 		trans->upstream.packages[package - upkgs] |= TRANS_PACKAGE_UPDATE;
   225 }
   226 
   227 struct prop_iter {
   228 	struct razor_property *p, *start, *end;
   229 	const char *pool;
   230 	uint32_t *present;
   231 };
   232 
   233 static void
   234 prop_iter_init(struct prop_iter *pi, struct transaction_set *ts)
   235 {
   236 	pi->p = ts->set->properties.data;
   237 	pi->start = ts->set->properties.data;
   238 	pi->end = ts->set->properties.data + ts->set->properties.size;
   239 	pi->pool = ts->set->string_pool.data;
   240 	pi->present = ts->properties;
   241 }
   242 
   243 static int
   244 prop_iter_next(struct prop_iter *pi, uint32_t flags, struct razor_property **p)
   245 {
   246 	while (pi->p < pi->end) {
   247 		if ((pi->present[pi->p - pi->start] & ~TRANS_PROPERTY_SATISFIED) &&
   248 		    (pi->p->flags & RAZOR_PROPERTY_TYPE_MASK) == flags) {
   249 			*p = pi->p++;
   250 			return 1;
   251 		}
   252 		pi->p++;
   253 	}
   254 
   255 	return 0;
   256 }
   257 
   258 static struct razor_property *
   259 prop_iter_seek_to(struct prop_iter *pi,
   260 		  uint32_t flags, const char *match)
   261 {
   262 	uint32_t name;
   263 
   264 	while (pi->p < pi->end && strcmp(&pi->pool[pi->p->name], match) < 0)
   265 		pi->p++;
   266 
   267 	if (pi->p == pi->end || strcmp(&pi->pool[pi->p->name], match) > 0)
   268 		return NULL;
   269 
   270 	name = pi->p->name;
   271 	while (pi->p < pi->end &&
   272 	       pi->p->name == name &&
   273 	       (pi->p->flags & RAZOR_PROPERTY_TYPE_MASK) != flags)
   274 		pi->p++;
   275 
   276 	if (pi->p == pi->end || pi->p->name != name)
   277 		return NULL;
   278 
   279 	return pi->p;
   280 }
   281 
   282 /* Remove packages from set that provide any of the matching (same
   283  * name and type) providers from ppi onwards that match the
   284  * requirement that rpi points to. */
   285 static void
   286 remove_matching_providers(struct razor_transaction *trans,
   287 			  struct prop_iter *ppi,
   288 			  uint32_t flags,
   289 			  const char *version)
   290 {
   291 	struct razor_property *p;
   292 	struct razor_package *pkg;
   293 	struct razor_package_iterator pkg_iter;
   294 	struct razor_set *set;
   295 	const char *n, *v;
   296 	uint32_t type;
   297 
   298 	if (ppi->present == trans->system.properties)
   299 		set = trans->system.set;
   300 	else
   301 		set = trans->upstream.set;
   302 
   303 	type = ppi->p->flags & RAZOR_PROPERTY_TYPE_MASK;
   304 	for (p = ppi->p;
   305 	     p < ppi->end &&
   306 	     p->name == ppi->p->name &&
   307 	     (p->flags & RAZOR_PROPERTY_TYPE_MASK) == type;
   308 	     p++) {
   309 		if (!ppi->present[p - ppi->start])
   310 			continue;
   311 		if (!provider_satisfies_requirement(p, ppi->pool,
   312 						    flags, version))
   313 			continue;
   314 
   315 		razor_package_iterator_init_for_property(&pkg_iter, set, p);
   316 		while (razor_package_iterator_next(&pkg_iter, &pkg,
   317 						   RAZOR_DETAIL_NAME, &n,
   318 						   RAZOR_DETAIL_VERSION, &v,
   319 						   RAZOR_DETAIL_LAST)) {
   320 #if 0
   321 			fprintf(stderr, "removing %s-%s\n", n, v);
   322 #endif
   323 			razor_transaction_remove_package(trans, pkg);
   324 		}
   325 	}
   326 }
   327 
   328 static void
   329 flag_matching_providers(struct razor_transaction *trans,
   330 			struct prop_iter *ppi,
   331 			struct razor_property *r,
   332 			struct prop_iter *rpi,
   333 			unsigned int flag)
   334 {
   335 	struct razor_property *p;
   336 	struct razor_package *pkg, *pkgs;
   337 	struct razor_package_iterator pkg_iter;
   338 	struct razor_set *set;
   339 	const char *name, *version;
   340 	uint32_t *flags, type;
   341 
   342 	if (ppi->present == trans->system.properties) {
   343 		set = trans->system.set;
   344 		flags = trans->system.packages;
   345 	} else {
   346 		set = trans->upstream.set;
   347 		flags = trans->upstream.packages;
   348 	}
   349 
   350 	pkgs = (struct razor_package *) set->packages.data;
   351 	type = ppi->p->flags & RAZOR_PROPERTY_TYPE_MASK;
   352 	for (p = ppi->p;
   353 	     p < ppi->end &&
   354 		     p->name == ppi->p->name &&
   355 		     (p->flags & RAZOR_PROPERTY_TYPE_MASK) == type;
   356 	     p++) {
   357 		if (!ppi->present[p - ppi->start])
   358 			continue;
   359 		if (!provider_satisfies_requirement(p, ppi->pool,
   360 						    r->flags,
   361 						    &rpi->pool[r->version]))
   362 			continue;
   363 
   364 		razor_package_iterator_init_for_property(&pkg_iter, set, p);
   365 		while (razor_package_iterator_next(&pkg_iter, &pkg,
   366 						   RAZOR_DETAIL_NAME, &name,
   367 						   RAZOR_DETAIL_VERSION, &version,
   368 						   RAZOR_DETAIL_LAST)) {
   369 
   370 #if 0
   371 			fprintf(stderr, "flagging %s-%s for providing %s matching %s %s\n",
   372 				name, version,
   373 				ppi->pool + p->name,
   374 				rpi->pool + r->name,
   375 				rpi->pool + r->version);
   376 #endif
   377 			flags[pkg - pkgs] |= flag;
   378 		}
   379 	}
   380 }
   381 
   382 static struct razor_package *
   383 pick_matching_provider(struct razor_set *set,
   384 		       struct prop_iter *ppi,
   385 		       uint32_t flags,
   386 		       const char *version)
   387 {
   388 	struct razor_property *p;
   389 	struct razor_package *pkgs;
   390 	struct list *i;
   391 	uint32_t type;
   392 
   393 	/* This is where we decide which pkgs to pull in to satisfy a
   394 	 * requirement.  There may be several different providers
   395 	 * (different versions) and each version of a provider may
   396 	 * come from a number of packages.  We pick the first package
   397 	 * from the first provider that matches. */
   398 
   399 	pkgs = set->packages.data;
   400 	type = ppi->p->flags & RAZOR_PROPERTY_TYPE_MASK;
   401 	for (p = ppi->p;
   402 	     p < ppi->end &&
   403 		     p->name == ppi->p->name &&
   404 		     (p->flags & RAZOR_PROPERTY_TYPE_MASK) == type &&
   405 		     ppi->present[p - ppi->start] == 0;
   406 	     p++) {
   407 		if (!provider_satisfies_requirement(p, ppi->pool,
   408 						    flags, version))
   409 			continue;
   410 
   411 		i = list_first(&p->packages, &set->package_pool);
   412 
   413 		return &pkgs[i->data];
   414 	}
   415 
   416 	return NULL;
   417 }
   418 
   419 static void
   420 remove_obsoleted_packages(struct razor_transaction *trans)
   421 {
   422 	struct razor_property *up;
   423 	struct prop_iter spi, upi;
   424 
   425 	prop_iter_init(&spi, &trans->system);
   426 	prop_iter_init(&upi, &trans->upstream);
   427 
   428 	while (prop_iter_next(&upi, RAZOR_PROPERTY_OBSOLETES, &up)) {
   429 		if (!prop_iter_seek_to(&spi, RAZOR_PROPERTY_PROVIDES,
   430 				       &upi.pool[up->name]))
   431 			continue;
   432 		remove_matching_providers(trans, &spi, up->flags,
   433 					  &upi.pool[up->version]);
   434 	}
   435 }
   436 
   437 static int
   438 any_provider_satisfies_requirement(struct prop_iter *ppi,
   439 				   uint32_t flags,
   440 				   const char *version)
   441 {
   442 	struct razor_property *p;
   443 	uint32_t type;
   444 
   445 	type = ppi->p->flags & RAZOR_PROPERTY_TYPE_MASK;
   446 	for (p = ppi->p;
   447 	     p < ppi->end &&
   448 		     p->name == ppi->p->name &&
   449 		     (p->flags & RAZOR_PROPERTY_TYPE_MASK) == type;
   450 	     p++) {
   451 		if (ppi->present[p - ppi->start] > 0 &&
   452 		    provider_satisfies_requirement(p, ppi->pool,
   453 						   flags, version))
   454 			return 1;
   455 	}
   456 
   457 	return 0;
   458 }
   459 
   460 static void
   461 clear_requires_flags(struct transaction_set *ts)
   462 {
   463 	struct razor_property *p;
   464 	const char *pool;
   465 	int i, count;
   466 	char *sub;
   467 
   468 	count = ts->set->properties.size / sizeof *p;
   469 	p = ts->set->properties.data;
   470 	pool = ts->set->string_pool.data;
   471 	for (i = 0; i < count; i++) {
   472 		ts->properties[i] &= ~TRANS_PROPERTY_SATISFIED;
   473 		sub = strchr(&pool[p[i].name], '(');
   474 		if (sub && sub[strlen(sub) - 1] == ')') {
   475 			sub = strdup(sub + 1);
   476 			sub[strlen(sub) - 1] = '\0';
   477 			if (strncmp(&pool[p[i].name], "rpmlib(", 7) == 0)
   478 				ts->properties[i] |= TRANS_PROPERTY_SATISFIED;
   479 			if (strncmp(&pool[p[i].name], "lua(", 4) == 0 &&
   480 			    razor_get_lua_loader(sub) &&
   481 			    p[i].flags & RAZOR_PROPERTY_SCRIPT_MASK)
   482 				ts->properties[i] |= TRANS_PROPERTY_SATISFIED;
   483 			free(sub);
   484 		}
   485 	}
   486 }
   487 
   488 static void
   489 mark_satisfied_requires(struct razor_transaction *trans,
   490 			struct transaction_set *rts,
   491 			struct transaction_set *pts)
   492 {
   493 	struct prop_iter rpi, ppi;
   494 	struct razor_property *rp;
   495 
   496 	prop_iter_init(&rpi, rts);
   497 	prop_iter_init(&ppi, pts);
   498 
   499 	while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) {
   500 		if (!prop_iter_seek_to(&ppi, RAZOR_PROPERTY_PROVIDES,
   501 				       &rpi.pool[rp->name]))
   502 			continue;
   503 
   504 		if (any_provider_satisfies_requirement(&ppi, rp->flags,
   505 						       &rpi.pool[rp->version]))
   506 			rpi.present[rp - rpi.start] |= TRANS_PROPERTY_SATISFIED;
   507 	}
   508 }
   509 
   510 static void
   511 mark_all_satisfied_requires(struct razor_transaction *trans)
   512 {
   513 	clear_requires_flags(&trans->system);
   514 	clear_requires_flags(&trans->upstream);
   515 	mark_satisfied_requires(trans, &trans->system, &trans->system);
   516 	mark_satisfied_requires(trans, &trans->system, &trans->upstream);
   517 	mark_satisfied_requires(trans, &trans->upstream, &trans->system);
   518 	mark_satisfied_requires(trans, &trans->upstream, &trans->upstream);
   519 }
   520 
   521 static void
   522 update_unsatisfied_packages(struct razor_transaction *trans)
   523 {
   524 	struct razor_package *spkgs, *pkg;
   525 	struct razor_property *sp;
   526 	struct prop_iter spi;
   527 	struct razor_package_iterator pkg_iter;
   528 	const char *name;
   529 
   530 	spkgs = trans->system.set->packages.data;
   531 	prop_iter_init(&spi, &trans->system);
   532 
   533 	while (prop_iter_next(&spi, RAZOR_PROPERTY_REQUIRES, &sp)) {
   534 		if (spi.present[sp - spi.start] & TRANS_PROPERTY_SATISFIED)
   535 			continue;
   536 
   537 		razor_package_iterator_init_for_property(&pkg_iter,
   538 							 trans->system.set,
   539 							 sp);
   540 		while (razor_package_iterator_next(&pkg_iter, &pkg,
   541 						   RAZOR_DETAIL_NAME, &name,
   542 						   RAZOR_DETAIL_LAST)) {
   543 			if (!(trans->system.packages[pkg - spkgs] & TRANS_PACKAGE_PRESENT))
   544 				continue;
   545 
   546 #if 0
   547 			fprintf(stderr, "updating %s because %s %s %s "
   548 				"isn't satisfied\n",
   549 				name, spi.pool + sp->name,
   550 				razor_property_relation_to_string(sp),
   551 				spi.pool + sp->version);
   552 #endif
   553 			trans->system.packages[pkg - spkgs] |=
   554 				TRANS_PACKAGE_UPDATE;
   555 		}
   556 	}
   557 }
   558 
   559 RAZOR_EXPORT void
   560 razor_transaction_update_all(struct razor_transaction *trans)
   561 {
   562 	struct razor_package *p;
   563 	int i, count;
   564 
   565 	assert (trans != NULL);
   566 
   567 	count = trans->system.set->packages.size / sizeof *p;
   568 	for (i = 0; i < count; i++)
   569 		trans->system.packages[i] |= TRANS_PACKAGE_UPDATE;
   570 }
   571 
   572 static void
   573 update_conflicted_packages(struct razor_transaction *trans)
   574 {
   575 	struct razor_package *pkg, *spkgs;
   576 	struct razor_property *up, *sp;
   577 	struct prop_iter spi, upi;
   578 	struct razor_package_iterator pkg_iter;
   579 	const char *name, *version;
   580 
   581 	spkgs = trans->system.set->packages.data;
   582 	prop_iter_init(&spi, &trans->system);
   583 	prop_iter_init(&upi, &trans->upstream);
   584 
   585 	while (prop_iter_next(&spi, RAZOR_PROPERTY_CONFLICTS, &sp)) {
   586 		if (!prop_iter_seek_to(&upi, RAZOR_PROPERTY_PROVIDES,
   587 				       &spi.pool[sp->name]))
   588 			continue;
   589 
   590 		if (!any_provider_satisfies_requirement(&upi, sp->flags,
   591 							&spi.pool[sp->version]))
   592 			continue;
   593 
   594 		razor_package_iterator_init_for_property(&pkg_iter,
   595 							 trans->system.set,
   596 							 sp);
   597 		while (razor_package_iterator_next(&pkg_iter, &pkg,
   598 						   RAZOR_DETAIL_NAME, &name,
   599 						   RAZOR_DETAIL_VERSION, &version,
   600 						   RAZOR_DETAIL_LAST)) {
   601 #if 0
   602 			fprintf(stderr, "updating %s %s because it "
   603 				"conflicts with %s\n",
   604 				name, version, spi.pool + sp->name);
   605 #endif
   606 			trans->system.packages[pkg - spkgs] |=
   607 				TRANS_PACKAGE_UPDATE;
   608 		}
   609 	}
   610 
   611 	prop_iter_init(&spi, &trans->system);
   612 	prop_iter_init(&upi, &trans->upstream);
   613 
   614 	while (prop_iter_next(&upi, RAZOR_PROPERTY_CONFLICTS, &up)) {
   615 		sp = prop_iter_seek_to(&spi, RAZOR_PROPERTY_PROVIDES,
   616 				       &upi.pool[upi.p->name]);
   617 
   618 		if (sp)
   619 			flag_matching_providers(trans, &spi, up, &upi,
   620 						TRANS_PACKAGE_UPDATE);
   621 	}
   622 }
   623 
   624 static void
   625 pull_in_requirements(struct razor_transaction *trans,
   626 		     struct prop_iter *rpi, struct prop_iter *ppi)
   627 {
   628 	struct razor_property *rp, *pp;
   629 	struct razor_package *pkg, *upkgs;
   630 
   631 	upkgs = trans->upstream.set->packages.data;
   632 	while (prop_iter_next(rpi, RAZOR_PROPERTY_REQUIRES, &rp)) {
   633 		if (rpi->present[rp - rpi->start] & TRANS_PROPERTY_SATISFIED)
   634 			continue;
   635 
   636 		pp = prop_iter_seek_to(ppi, RAZOR_PROPERTY_PROVIDES,
   637 				       &rpi->pool[rp->name]);
   638 		if (pp == NULL)
   639 			continue;
   640 		pkg = pick_matching_provider(trans->upstream.set,
   641 					     ppi, rp->flags,
   642 					     &rpi->pool[rp->version]);
   643 		if (pkg == NULL)
   644 			continue;
   645 
   646 		rpi->present[rp - rpi->start] |= TRANS_PROPERTY_SATISFIED;
   647 
   648 #if 0
   649 		fprintf(stderr, "pulling in %s-%s.%s which provides %s %s %s "
   650 			"to satisfy %s %s %s\n",
   651 			ppi->pool + pkg->name,
   652 			ppi->pool + pkg->version,
   653 			ppi->pool + pkg->arch,
   654 			ppi->pool + pp->name,
   655 			razor_property_relation_to_string(pp),
   656 			ppi->pool + pp->version,
   657 			&rpi->pool[rp->name],
   658 			razor_property_relation_to_string(rp),
   659 			&rpi->pool[rp->version]);
   660 #endif
   661 
   662 		trans->upstream.packages[pkg - upkgs] |= TRANS_PACKAGE_UPDATE;
   663 	}
   664 }
   665 
   666 static void
   667 pull_in_all_requirements(struct razor_transaction *trans)
   668 {
   669 	struct prop_iter rpi, ppi;
   670 
   671 	prop_iter_init(&rpi, &trans->system);
   672 	prop_iter_init(&ppi, &trans->upstream);
   673 	pull_in_requirements(trans, &rpi, &ppi);
   674 
   675 	prop_iter_init(&rpi, &trans->upstream);
   676 	prop_iter_init(&ppi, &trans->upstream);
   677 	pull_in_requirements(trans, &rpi, &ppi);
   678 }
   679 
   680 static void
   681 flush_scheduled_system_updates(struct razor_transaction *trans)
   682 {
   683  	struct razor_package_iterator *pi;
   684  	struct razor_package *p, *pkg, *spkgs;
   685 	struct prop_iter ppi;
   686 	const char *name, *version;
   687 
   688 	spkgs = trans->system.set->packages.data;
   689 	pi = razor_package_iterator_create(trans->system.set);
   690 	prop_iter_init(&ppi, &trans->upstream);
   691 
   692 	while (razor_package_iterator_next(pi, &p,
   693 					   RAZOR_DETAIL_NAME, &name,
   694 					   RAZOR_DETAIL_VERSION, &version,
   695 					   RAZOR_DETAIL_LAST)) {
   696 		if (!(trans->system.packages[p - spkgs] & TRANS_PACKAGE_UPDATE))
   697 			continue;
   698 		trans->system.packages[p - spkgs] &= ~TRANS_PACKAGE_UPDATE;
   699 
   700 		if (!prop_iter_seek_to(&ppi, RAZOR_PROPERTY_PROVIDES, name))
   701 			continue;
   702 
   703 		if (any_provider_satisfies_requirement(&ppi,
   704 						       RAZOR_PROPERTY_GREATER,
   705 						       version)) {
   706 			razor_transaction_remove_package(trans, p);
   707 			continue;
   708 		}
   709 
   710 		pkg = pick_matching_provider(trans->upstream.set, &ppi,
   711 					     RAZOR_PROPERTY_GREATER, version);
   712 		if (pkg == NULL)
   713 			continue;
   714 
   715 		razor_transaction_remove_package(trans, p);
   716 		razor_transaction_install_package(trans, pkg);
   717 	}
   718 
   719 	razor_package_iterator_destroy(pi);
   720 }
   721 
   722 static void
   723 flush_scheduled_upstream_updates(struct razor_transaction *trans)
   724 {
   725  	struct razor_package_iterator *pi;
   726  	struct razor_package *p, *upkgs;
   727 	struct prop_iter spi;
   728 	const char *name, *version;
   729 
   730 	upkgs = trans->upstream.set->packages.data;
   731 	pi = razor_package_iterator_create(trans->upstream.set);
   732 	prop_iter_init(&spi, &trans->system);
   733 
   734 	while (razor_package_iterator_next(pi, &p,
   735 					   RAZOR_DETAIL_NAME, &name,
   736 					   RAZOR_DETAIL_VERSION, &version,
   737 					   RAZOR_DETAIL_LAST)) {
   738 		if (!(trans->upstream.packages[p - upkgs] & TRANS_PACKAGE_UPDATE))
   739 			continue;
   740 		trans->upstream.packages[p - upkgs] &= ~TRANS_PACKAGE_UPDATE;
   741 
   742 		if (prop_iter_seek_to(&spi, RAZOR_PROPERTY_PROVIDES, name))
   743 			remove_matching_providers(trans,
   744 						  &spi,
   745 						  RAZOR_PROPERTY_LESS,
   746 						  version);
   747 		razor_transaction_install_package(trans, p);
   748 #if 0
   749 		fprintf(stderr, "installing %s-%s\n", name, version);
   750 #endif
   751 	}
   752 
   753 	razor_package_iterator_destroy(pi);
   754 }
   755 
   756 RAZOR_EXPORT int
   757 razor_transaction_resolve(struct razor_transaction *trans)
   758 {
   759 	int last = 0;
   760 
   761 	flush_scheduled_system_updates(trans);
   762 	flush_scheduled_upstream_updates(trans);
   763 
   764 	while (last < trans->changes) {
   765 		last = trans->changes;
   766 		remove_obsoleted_packages(trans);
   767 		mark_all_satisfied_requires(trans);
   768 		update_unsatisfied_packages(trans);
   769 		update_conflicted_packages(trans);
   770 		pull_in_all_requirements(trans);
   771 		flush_scheduled_system_updates(trans);
   772 		flush_scheduled_upstream_updates(trans);
   773 	}
   774 
   775 	return trans->changes;
   776 }
   777 
   778 static void
   779 describe_unsatisfied(struct razor_set *set, struct razor_property *rp,
   780 		     razor_unsatisfied_callback_t callback, void *data)
   781 {
   782 	struct razor_package_iterator pi;
   783 	struct razor_package *pkg;
   784 	const char *name, *version, *arch, *pool;
   785 	const char *requirement;
   786 	char *s = NULL;
   787 
   788 	pool = set->string_pool.data;
   789 	if (pool[rp->version] == '\0')
   790 		requirement = &pool[rp->name];
   791 	else {
   792 		s = razor_concat(&pool[rp->name], " ",
   793 				 razor_property_relation_to_string(rp), " ",
   794 				 &pool[rp->version], NULL);
   795 		requirement = s;
   796 	}
   797 
   798 	razor_package_iterator_init_for_property(&pi, set, rp);
   799 	while (razor_package_iterator_next(&pi, &pkg,
   800 					   RAZOR_DETAIL_NAME, &name,
   801 					   RAZOR_DETAIL_VERSION, &version,
   802 					   RAZOR_DETAIL_ARCH, &arch,
   803 					   RAZOR_DETAIL_LAST))
   804 		callback(requirement, pkg, name, version, arch, data);
   805 
   806 	if (s)
   807 		free(s);
   808 }
   809 
   810 RAZOR_EXPORT int
   811 razor_transaction_unsatisfied(struct razor_transaction *trans,
   812 			      razor_unsatisfied_callback_t callback, void *data)
   813 {
   814 	struct prop_iter rpi;
   815 	struct razor_property *rp;
   816 	int unsatisfied;
   817 
   818 	flush_scheduled_system_updates(trans);
   819 	flush_scheduled_upstream_updates(trans);
   820 	mark_all_satisfied_requires(trans);
   821 
   822 	unsatisfied = 0;
   823 	prop_iter_init(&rpi, &trans->system);
   824 	while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) {
   825 		if (!(rpi.present[rp - rpi.start] & TRANS_PROPERTY_SATISFIED)) {
   826 			if (callback)
   827 				describe_unsatisfied(trans->system.set, rp,
   828 						     callback, data);
   829 		        unsatisfied++;
   830 		}
   831 	}
   832 
   833 	prop_iter_init(&rpi, &trans->upstream);
   834 	while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) {
   835 		if (!(rpi.present[rp - rpi.start] & TRANS_PROPERTY_SATISFIED)) {
   836 			if (callback)
   837 				describe_unsatisfied(trans->upstream.set, rp,
   838 						     callback, data);
   839 			unsatisfied++;
   840 		}
   841 	}
   842 
   843 	return unsatisfied;
   844 }
   845 
   846 static void
   847 describe_unsatisfied_callback(const char *requirement,
   848 			      struct razor_package *package, const char *name,
   849 			      const char *version, const char *arch, void *data)
   850 {
   851 	FILE *fp = data;
   852 
   853 	fprintf(fp, "%s is needed by %s-%s.%s\n", requirement,
   854 		name, version, arch);
   855 }
   856 
   857 RAZOR_EXPORT int
   858 razor_transaction_describe(struct razor_transaction *trans)
   859 {
   860 	return razor_transaction_unsatisfied(trans,
   861 					     describe_unsatisfied_callback,
   862 					     stderr);
   863 }
   864 
   865 RAZOR_EXPORT int
   866 razor_transaction_unsatisfied_property(struct razor_transaction *trans,
   867 				       const char *name,
   868 				       uint32_t flags,
   869 				       const char *version)
   870 {
   871 	struct prop_iter pi;
   872 	struct razor_property *p;
   873 
   874 	prop_iter_init(&pi, &trans->system);
   875 	while (prop_iter_next(&pi, flags & RAZOR_PROPERTY_TYPE_MASK, &p)) {
   876 		if (!(trans->system.properties[p - pi.start] & TRANS_PROPERTY_SATISFIED) &&
   877 		    p->flags == flags &&
   878 		    strcmp(&pi.pool[p->name], name) == 0 &&
   879 		    strcmp(&pi.pool[p->version], version) == 0)
   880 
   881 			return 1;
   882 	}
   883 
   884 	prop_iter_init(&pi, &trans->upstream);
   885 	while (prop_iter_next(&pi, flags & RAZOR_PROPERTY_TYPE_MASK, &p)) {
   886 		if (!(trans->upstream.properties[p - pi.start] & TRANS_PROPERTY_SATISFIED) &&
   887 		    p->flags == flags &&
   888 		    strcmp(&pi.pool[p->name], name) == 0 &&
   889 		    strcmp(&pi.pool[p->version], version) == 0)
   890 
   891 			return 1;
   892 	}
   893 
   894 	return 0;
   895 }
   896 
   897 RAZOR_EXPORT struct razor_set *
   898 razor_transaction_commit(struct razor_transaction *trans)
   899 {
   900 	struct razor_package *u, *uend, *upkgs, *s, *send, *spkgs;
   901 	char *upool, *spool;
   902 	int cmp;
   903 
   904 	s = trans->system.set->packages.data;
   905 	spkgs = trans->system.set->packages.data;
   906 	send = trans->system.set->packages.data +
   907 		trans->system.set->packages.size;
   908 	spool = trans->system.set->string_pool.data;
   909 
   910 	u = trans->upstream.set->packages.data;
   911 	upkgs = trans->upstream.set->packages.data;
   912 	uend = trans->upstream.set->packages.data +
   913 		trans->upstream.set->packages.size;
   914 	upool = trans->upstream.set->string_pool.data;
   915 
   916 	trans->merger = razor_merger_create(trans->system.set,
   917 					    trans->upstream.set);
   918 	while (s < send || u < uend) {
   919 		if (s < send && u < uend)
   920 			cmp = strcmp(&spool[s->name], &upool[u->name]);
   921 		else if (s < send)
   922 			cmp = -1;
   923 		else
   924 			cmp = 1;
   925 
   926 		if (cmp < 0) {
   927 			if (trans->system.packages[s - spkgs] & TRANS_PACKAGE_PRESENT)
   928 				razor_merger_add_package(trans->merger, s);
   929 			s++;
   930 		} else if (cmp == 0) {
   931 			if (trans->system.packages[s - spkgs] & TRANS_PACKAGE_PRESENT)
   932 				razor_merger_add_package(trans->merger, s);
   933 			if (trans->upstream.packages[u - upkgs] & TRANS_PACKAGE_PRESENT)
   934 				razor_merger_add_package(trans->merger, u);
   935 
   936 			s++;
   937 			u++;
   938 		} else {
   939 			if (trans->upstream.packages[u - upkgs] & TRANS_PACKAGE_PRESENT)
   940 				razor_merger_add_package(trans->merger, u);
   941 			u++;
   942 		}
   943 	}
   944 
   945 	return razor_merger_commit(trans->merger);
   946 }
   947 
   948 RAZOR_EXPORT void
   949 razor_transaction_fixup_package(struct razor_transaction *trans,
   950 				struct razor_package *package,
   951 				struct razor_rpm *rpm)
   952 {
   953 	const char *preunprog, *preun, *postunprog, *postun;
   954 
   955 	razor_rpm_get_details(rpm,
   956 			      RAZOR_DETAIL_PREUNPROG, &preunprog,
   957 			      RAZOR_DETAIL_PREUN, &preun,
   958 			      RAZOR_DETAIL_POSTUNPROG, &postunprog,
   959 			      RAZOR_DETAIL_POSTUN, &postun,
   960 			      RAZOR_DETAIL_LAST);
   961 
   962 	razor_merger_package_add_script(trans->merger, package,
   963 					RAZOR_PROPERTY_PREUN,
   964 					preunprog, preun);
   965 	razor_merger_package_add_script(trans->merger, package,
   966 					RAZOR_PROPERTY_POSTUN,
   967 					postunprog, postun);
   968 }
   969 
   970 RAZOR_EXPORT void
   971 razor_transaction_destroy(struct razor_transaction *trans)
   972 {
   973 	assert (trans != NULL);
   974 
   975 	if (trans->merger)
   976 		razor_merger_destroy(trans->merger);
   977 	transaction_set_release(&trans->system);
   978 	transaction_set_release(&trans->upstream);
   979 	free(trans);
   980 }