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