librazor/transaction.c
author J. Ali Harlow <ali@juiblex.co.uk>
Wed Apr 29 17:00:01 2009 +0100 (2009-04-29)
changeset 361 2523d03a840e
parent 307 95b6bcadd6c4
child 368 ea743486ba6f
permissions -rw-r--r--
Add support for preloading lua modules. This is useful both when
providing lua bindings to applications based on librazor and when
producing static binaries using librazor (where otherwise the lua
POSIX library would need to be included as an additional dynamic
object).
     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 <unistd.h>
    30 #include <fcntl.h>
    31 #include <errno.h>
    32 #include <ctype.h>
    33 #include <fnmatch.h>
    34 #include <assert.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 	assert (trans != NULL);
   192 	assert (package != NULL);
   193 
   194 	transaction_set_install_package(&trans->upstream, package);
   195 	trans->changes++;
   196 }
   197 
   198 RAZOR_EXPORT void
   199 razor_transaction_remove_package(struct razor_transaction *trans,
   200 				 struct razor_package *package)
   201 {
   202 	assert (trans != NULL);
   203 	assert (package != NULL);
   204 
   205 	transaction_set_remove_package(&trans->system, package);
   206 	trans->changes++;
   207 }
   208 
   209 RAZOR_EXPORT void
   210 razor_transaction_update_package(struct razor_transaction *trans,
   211 				  struct razor_package *package)
   212 {
   213 	struct razor_package *spkgs, *upkgs, *end;
   214 
   215 	assert (trans != NULL);
   216 	assert (package != NULL);
   217 
   218 	spkgs = trans->system.set->packages.data;
   219 	upkgs = trans->upstream.set->packages.data;
   220 	end = trans->system.set->packages.data +
   221 		trans->system.set->packages.size;
   222 	if (spkgs <= package && package < end)
   223 		trans->system.packages[package - spkgs] |= TRANS_PACKAGE_UPDATE;
   224 	else
   225 		trans->upstream.packages[package - upkgs] |= TRANS_PACKAGE_UPDATE;
   226 }
   227 
   228 struct prop_iter {
   229 	struct razor_property *p, *start, *end;
   230 	const char *pool;
   231 	uint32_t *present;
   232 };
   233 
   234 static void
   235 prop_iter_init(struct prop_iter *pi, struct transaction_set *ts)
   236 {
   237 	pi->p = ts->set->properties.data;
   238 	pi->start = ts->set->properties.data;
   239 	pi->end = ts->set->properties.data + ts->set->properties.size;
   240 	pi->pool = ts->set->string_pool.data;
   241 	pi->present = ts->properties;
   242 }
   243 
   244 static int
   245 prop_iter_next(struct prop_iter *pi, uint32_t flags, struct razor_property **p)
   246 {
   247 	while (pi->p < pi->end) {
   248 		if ((pi->present[pi->p - pi->start] & ~TRANS_PROPERTY_SATISFIED) &&
   249 		    (pi->p->flags & RAZOR_PROPERTY_TYPE_MASK) == flags) {
   250 			*p = pi->p++;
   251 			return 1;
   252 		}
   253 		pi->p++;
   254 	}
   255 
   256 	return 0;
   257 }
   258 
   259 static struct razor_property *
   260 prop_iter_seek_to(struct prop_iter *pi,
   261 		  uint32_t flags, const char *match)
   262 {
   263 	uint32_t name;
   264 
   265 	while (pi->p < pi->end && strcmp(&pi->pool[pi->p->name], match) < 0)
   266 		pi->p++;
   267 
   268 	if (pi->p == pi->end || strcmp(&pi->pool[pi->p->name], match) > 0)
   269 		return NULL;
   270 
   271 	name = pi->p->name;
   272 	while (pi->p < pi->end &&
   273 	       pi->p->name == name &&
   274 	       (pi->p->flags & RAZOR_PROPERTY_TYPE_MASK) != flags)
   275 		pi->p++;
   276 
   277 	if (pi->p == pi->end || pi->p->name != name)
   278 		return NULL;
   279 
   280 	return pi->p;
   281 }
   282 
   283 /* Remove packages from set that provide any of the matching (same
   284  * name and type) providers from ppi onwards that match the
   285  * requirement that rpi points to. */
   286 static void
   287 remove_matching_providers(struct razor_transaction *trans,
   288 			  struct prop_iter *ppi,
   289 			  uint32_t flags,
   290 			  const char *version)
   291 {
   292 	struct razor_property *p;
   293 	struct razor_package *pkg, *pkgs;
   294 	struct razor_package_iterator pkg_iter;
   295 	struct razor_set *set;
   296 	const char *n, *v;
   297 	uint32_t type;
   298 
   299 	if (ppi->present == trans->system.properties)
   300 		set = trans->system.set;
   301 	else
   302 		set = trans->upstream.set;
   303 
   304 	pkgs = (struct razor_package *) set->packages.data;
   305 	type = ppi->p->flags & RAZOR_PROPERTY_TYPE_MASK;
   306 	for (p = ppi->p;
   307 	     p < ppi->end &&
   308 	     p->name == ppi->p->name &&
   309 	     (p->flags & RAZOR_PROPERTY_TYPE_MASK) == type;
   310 	     p++) {
   311 		if (!ppi->present[p - ppi->start])
   312 			continue;
   313 		if (!provider_satisfies_requirement(p, ppi->pool,
   314 						    flags, version))
   315 			continue;
   316 
   317 		razor_package_iterator_init_for_property(&pkg_iter, set, p);
   318 		while (razor_package_iterator_next(&pkg_iter, &pkg,
   319 						   RAZOR_DETAIL_NAME, &n,
   320 						   RAZOR_DETAIL_VERSION, &v,
   321 						   RAZOR_DETAIL_LAST)) {
   322 			fprintf(stderr, "removing %s-%s\n", n, v);
   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 			fprintf(stderr, "flagging %s-%s for providing %s matching %s %s\n",
   371 				name, version,
   372 				ppi->pool + p->name,
   373 				rpi->pool + r->name,
   374 				rpi->pool + r->version);
   375 			flags[pkg - pkgs] |= flag;
   376 		}
   377 	}
   378 }
   379 
   380 static struct razor_package *
   381 pick_matching_provider(struct razor_set *set,
   382 		       struct prop_iter *ppi,
   383 		       uint32_t flags,
   384 		       const char *version)
   385 {
   386 	struct razor_property *p;
   387 	struct razor_package *pkgs;
   388 	struct list *i;
   389 	uint32_t type;
   390 
   391 	/* This is where we decide which pkgs to pull in to satisfy a
   392 	 * requirement.  There may be several different providers
   393 	 * (different versions) and each version of a provider may
   394 	 * come from a number of packages.  We pick the first package
   395 	 * from the first provider that matches. */
   396 
   397 	pkgs = set->packages.data;
   398 	type = ppi->p->flags & RAZOR_PROPERTY_TYPE_MASK;
   399 	for (p = ppi->p;
   400 	     p < ppi->end &&
   401 		     p->name == ppi->p->name &&
   402 		     (p->flags & RAZOR_PROPERTY_TYPE_MASK) == type &&
   403 		     ppi->present[p - ppi->start] == 0;
   404 	     p++) {
   405 		if (!provider_satisfies_requirement(p, ppi->pool,
   406 						    flags, version))
   407 			continue;
   408 
   409 		i = list_first(&p->packages, &set->package_pool);
   410 
   411 		return &pkgs[i->data];
   412 	}
   413 
   414 	return NULL;
   415 }
   416 
   417 static void
   418 remove_obsoleted_packages(struct razor_transaction *trans)
   419 {
   420 	struct razor_property *up;
   421 	struct razor_package *spkgs;
   422 	struct prop_iter spi, upi;
   423 
   424 	spkgs = trans->system.set->packages.data;
   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 
   467 	count = ts->set->properties.size / sizeof *p;
   468 	p = ts->set->properties.data;
   469 	pool = ts->set->string_pool.data;
   470 	for (i = 0; i < count; i++) {
   471 		ts->properties[i] &= ~TRANS_PROPERTY_SATISFIED;
   472 		if (strncmp(&pool[p[i].name], "rpmlib(", 7) == 0)
   473 			ts->properties[i] |= TRANS_PROPERTY_SATISFIED;
   474 	}
   475 }
   476 
   477 static void
   478 mark_satisfied_requires(struct razor_transaction *trans,
   479 			struct transaction_set *rts,
   480 			struct transaction_set *pts)
   481 {
   482 	struct prop_iter rpi, ppi;
   483 	struct razor_property *rp;
   484 
   485 	prop_iter_init(&rpi, rts);
   486 	prop_iter_init(&ppi, pts);
   487 
   488 	while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) {
   489 		if (!prop_iter_seek_to(&ppi, RAZOR_PROPERTY_PROVIDES,
   490 				       &rpi.pool[rp->name]))
   491 			continue;
   492 
   493 		if (any_provider_satisfies_requirement(&ppi, rp->flags,
   494 						       &rpi.pool[rp->version]))
   495 			rpi.present[rp - rpi.start] |= TRANS_PROPERTY_SATISFIED;
   496 	}
   497 }
   498 
   499 static void
   500 mark_all_satisfied_requires(struct razor_transaction *trans)
   501 {
   502 	clear_requires_flags(&trans->system);
   503 	clear_requires_flags(&trans->upstream);
   504 	mark_satisfied_requires(trans, &trans->system, &trans->system);
   505 	mark_satisfied_requires(trans, &trans->system, &trans->upstream);
   506 	mark_satisfied_requires(trans, &trans->upstream, &trans->system);
   507 	mark_satisfied_requires(trans, &trans->upstream, &trans->upstream);
   508 }
   509 
   510 static void
   511 update_unsatisfied_packages(struct razor_transaction *trans)
   512 {
   513 	struct razor_package *spkgs, *pkg;
   514 	struct razor_property *sp;
   515 	struct prop_iter spi;
   516 	struct razor_package_iterator pkg_iter;
   517 	const char *name;
   518 
   519 	spkgs = trans->system.set->packages.data;
   520 	prop_iter_init(&spi, &trans->system);
   521 
   522 	while (prop_iter_next(&spi, RAZOR_PROPERTY_REQUIRES, &sp)) {
   523 		if (spi.present[sp - spi.start] & TRANS_PROPERTY_SATISFIED)
   524 			continue;
   525 
   526 		razor_package_iterator_init_for_property(&pkg_iter,
   527 							 trans->system.set,
   528 							 sp);
   529 		while (razor_package_iterator_next(&pkg_iter, &pkg,
   530 						   RAZOR_DETAIL_NAME, &name,
   531 						   RAZOR_DETAIL_LAST)) {
   532 			fprintf(stderr, "updating %s because %s %s %s "
   533 				"isn't satisfied\n",
   534 				name, spi.pool + sp->name,
   535 				razor_property_relation_to_string(sp),
   536 				spi.pool + sp->version);
   537 			trans->system.packages[pkg - spkgs] |=
   538 				TRANS_PACKAGE_UPDATE;
   539 		}
   540 	}
   541 }
   542 
   543 RAZOR_EXPORT void
   544 razor_transaction_update_all(struct razor_transaction *trans)
   545 {
   546 	struct razor_package *p;
   547 	int i, count;
   548 
   549 	assert (trans != NULL);
   550 
   551 	count = trans->system.set->packages.size / sizeof *p;
   552 	for (i = 0; i < count; i++)
   553 		trans->system.packages[i] |= TRANS_PACKAGE_UPDATE;
   554 }
   555 
   556 static void
   557 update_conflicted_packages(struct razor_transaction *trans)
   558 {
   559 	struct razor_package *pkg, *spkgs;
   560 	struct razor_property *up, *sp;
   561 	struct prop_iter spi, upi;
   562 	struct razor_package_iterator pkg_iter;
   563 	const char *name, *version;
   564 
   565 	spkgs = trans->system.set->packages.data;
   566 	prop_iter_init(&spi, &trans->system);
   567 	prop_iter_init(&upi, &trans->upstream);
   568 
   569 	while (prop_iter_next(&spi, RAZOR_PROPERTY_CONFLICTS, &sp)) {
   570 		if (!prop_iter_seek_to(&upi, RAZOR_PROPERTY_PROVIDES,
   571 				       &spi.pool[sp->name]))
   572 			continue;
   573 
   574 		if (!any_provider_satisfies_requirement(&upi, sp->flags,
   575 							&spi.pool[sp->version]))
   576 			continue;
   577 
   578 		razor_package_iterator_init_for_property(&pkg_iter,
   579 							 trans->system.set,
   580 							 sp);
   581 		while (razor_package_iterator_next(&pkg_iter, &pkg,
   582 						   RAZOR_DETAIL_NAME, &name,
   583 						   RAZOR_DETAIL_VERSION, &version,
   584 						   RAZOR_DETAIL_LAST)) {
   585 			fprintf(stderr, "updating %s %s because it "
   586 				"conflicts with %s\n",
   587 				name, version, spi.pool + sp->name);
   588 			trans->system.packages[pkg - spkgs] |=
   589 				TRANS_PACKAGE_UPDATE;
   590 		}
   591 	}
   592 
   593 	prop_iter_init(&spi, &trans->system);
   594 	prop_iter_init(&upi, &trans->upstream);
   595 
   596 	while (prop_iter_next(&upi, RAZOR_PROPERTY_CONFLICTS, &up)) {
   597 		sp = prop_iter_seek_to(&spi, RAZOR_PROPERTY_PROVIDES,
   598 				       &upi.pool[upi.p->name]);
   599 
   600 		if (sp)
   601 			flag_matching_providers(trans, &spi, up, &upi,
   602 						TRANS_PACKAGE_UPDATE);
   603 	}
   604 }
   605 
   606 static void
   607 pull_in_requirements(struct razor_transaction *trans,
   608 		     struct prop_iter *rpi, struct prop_iter *ppi)
   609 {
   610 	struct razor_property *rp, *pp;
   611 	struct razor_package *pkg, *upkgs;
   612 
   613 	upkgs = trans->upstream.set->packages.data;
   614 	while (prop_iter_next(rpi, RAZOR_PROPERTY_REQUIRES, &rp)) {
   615 		if (rpi->present[rp - rpi->start] & TRANS_PROPERTY_SATISFIED)
   616 			continue;
   617 
   618 		pp = prop_iter_seek_to(ppi, RAZOR_PROPERTY_PROVIDES,
   619 				       &rpi->pool[rp->name]);
   620 		if (pp == NULL)
   621 			continue;
   622 		pkg = pick_matching_provider(trans->upstream.set,
   623 					     ppi, rp->flags,
   624 					     &rpi->pool[rp->version]);
   625 		if (pkg == NULL)
   626 			continue;
   627 
   628 		rpi->present[rp - rpi->start] |= TRANS_PROPERTY_SATISFIED;
   629 
   630 		fprintf(stderr, "pulling in %s-%s.%s which provides %s %s %s "
   631 			"to satisfy %s %s %s\n",
   632 			ppi->pool + pkg->name,
   633 			ppi->pool + pkg->version,
   634 			ppi->pool + pkg->arch,
   635 			ppi->pool + pp->name,
   636 			razor_property_relation_to_string(pp),
   637 			ppi->pool + pp->version,
   638 			&rpi->pool[rp->name],
   639 			razor_property_relation_to_string(rp),
   640 			&rpi->pool[rp->version]);
   641 
   642 		trans->upstream.packages[pkg - upkgs] |= TRANS_PACKAGE_UPDATE;
   643 	}
   644 }
   645 
   646 static void
   647 pull_in_all_requirements(struct razor_transaction *trans)
   648 {
   649 	struct prop_iter rpi, ppi;
   650 
   651 	prop_iter_init(&rpi, &trans->system);
   652 	prop_iter_init(&ppi, &trans->upstream);
   653 	pull_in_requirements(trans, &rpi, &ppi);
   654 
   655 	prop_iter_init(&rpi, &trans->upstream);
   656 	prop_iter_init(&ppi, &trans->upstream);
   657 	pull_in_requirements(trans, &rpi, &ppi);
   658 }
   659 
   660 static void
   661 flush_scheduled_system_updates(struct razor_transaction *trans)
   662 {
   663  	struct razor_package_iterator *pi;
   664  	struct razor_package *p, *pkg, *spkgs;
   665 	struct prop_iter ppi;
   666 	const char *name, *version;
   667 
   668 	spkgs = trans->system.set->packages.data;
   669 	pi = razor_package_iterator_create(trans->system.set);
   670 	prop_iter_init(&ppi, &trans->upstream);
   671 
   672 	while (razor_package_iterator_next(pi, &p,
   673 					   RAZOR_DETAIL_NAME, &name,
   674 					   RAZOR_DETAIL_VERSION, &version,
   675 					   RAZOR_DETAIL_LAST)) {
   676 		if (!(trans->system.packages[p - spkgs] & TRANS_PACKAGE_UPDATE))
   677 			continue;
   678 
   679 		if (!prop_iter_seek_to(&ppi, RAZOR_PROPERTY_PROVIDES, name))
   680 			continue;
   681 
   682 		pkg = pick_matching_provider(trans->upstream.set, &ppi,
   683 					     RAZOR_PROPERTY_GREATER, version);
   684 		if (pkg == NULL)
   685 			continue;
   686 
   687 		fprintf(stderr, "updating %s-%s to %s-%s\n",
   688 			name, version,
   689 			&ppi.pool[pkg->name], &ppi.pool[pkg->version]);
   690 
   691 		razor_transaction_remove_package(trans, p);
   692 		razor_transaction_install_package(trans, pkg);
   693 	}
   694 
   695 	razor_package_iterator_destroy(pi);
   696 }
   697 
   698 static void
   699 flush_scheduled_upstream_updates(struct razor_transaction *trans)
   700 {
   701  	struct razor_package_iterator *pi;
   702  	struct razor_package *p, *upkgs;
   703 	struct prop_iter spi;
   704 	const char *name, *version;
   705 
   706 	upkgs = trans->upstream.set->packages.data;
   707 	pi = razor_package_iterator_create(trans->upstream.set);
   708 	prop_iter_init(&spi, &trans->system);
   709 
   710 	while (razor_package_iterator_next(pi, &p,
   711 					   RAZOR_DETAIL_NAME, &name,
   712 					   RAZOR_DETAIL_VERSION, &version,
   713 					   RAZOR_DETAIL_LAST)) {
   714 		if (!(trans->upstream.packages[p - upkgs] & TRANS_PACKAGE_UPDATE))
   715 			continue;
   716 
   717 		if (prop_iter_seek_to(&spi, RAZOR_PROPERTY_PROVIDES, name))
   718 			remove_matching_providers(trans,
   719 						  &spi,
   720 						  RAZOR_PROPERTY_LESS,
   721 						  version);
   722 		razor_transaction_install_package(trans, p);
   723 		fprintf(stderr, "installing %s-%s\n", name, version);
   724 	}
   725 }
   726 
   727 RAZOR_EXPORT int
   728 razor_transaction_resolve(struct razor_transaction *trans)
   729 {
   730 	int last = 0;
   731 
   732 	flush_scheduled_system_updates(trans);
   733 	flush_scheduled_upstream_updates(trans);
   734 
   735 	while (last < trans->changes) {
   736 		last = trans->changes;
   737 		remove_obsoleted_packages(trans);
   738 		mark_all_satisfied_requires(trans);
   739 		update_unsatisfied_packages(trans);
   740 		update_conflicted_packages(trans);
   741 		pull_in_all_requirements(trans);
   742 		flush_scheduled_system_updates(trans);
   743 		flush_scheduled_upstream_updates(trans);
   744 	}
   745 
   746 	return trans->changes;
   747 }
   748 
   749 static void
   750 describe_unsatisfied(struct razor_set *set, struct razor_property *rp)
   751 {
   752 	struct razor_package_iterator pi;
   753 	struct razor_package *pkg;
   754 	const char *name, *version, *arch, *pool;
   755 
   756 	pool = set->string_pool.data;
   757 	if (pool[rp->version] == '\0') {
   758 		razor_package_iterator_init_for_property(&pi, set, rp);
   759 		while (razor_package_iterator_next(&pi, &pkg,
   760 						   RAZOR_DETAIL_NAME, &name,
   761 						   RAZOR_DETAIL_VERSION, &version,
   762 						   RAZOR_DETAIL_ARCH, &arch,
   763 						   RAZOR_DETAIL_LAST))
   764 			fprintf(stderr, "%s is needed by %s-%s.%s\n",
   765 				&pool[rp->name],
   766 				name, version, arch);
   767 	} else {
   768 		razor_package_iterator_init_for_property(&pi, set, rp);
   769 		while (razor_package_iterator_next(&pi, &pkg,
   770 						   RAZOR_DETAIL_NAME, &name,
   771 						   RAZOR_DETAIL_VERSION, &version,
   772 						   RAZOR_DETAIL_ARCH, &arch,
   773 						   RAZOR_DETAIL_LAST))
   774 			fprintf(stderr, "%s %s %s is needed by %s-%s.%s\n",
   775 				&pool[rp->name],
   776 				razor_property_relation_to_string(rp),
   777 				&pool[rp->version],
   778 				name, version, arch);
   779 	}
   780 }
   781 
   782 RAZOR_EXPORT int
   783 razor_transaction_describe(struct razor_transaction *trans)
   784 {
   785 	struct prop_iter rpi;
   786 	struct razor_property *rp;
   787 	int unsatisfied;
   788 
   789 	flush_scheduled_system_updates(trans);
   790 	flush_scheduled_upstream_updates(trans);
   791 	mark_all_satisfied_requires(trans);
   792 
   793 	unsatisfied = 0;
   794 	prop_iter_init(&rpi, &trans->system);
   795 	while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) {
   796 		if (!(rpi.present[rp - rpi.start] & TRANS_PROPERTY_SATISFIED)) {
   797 			describe_unsatisfied(trans->system.set, rp);
   798 		        unsatisfied++;
   799 		}
   800 	}
   801 
   802 	prop_iter_init(&rpi, &trans->upstream);
   803 	while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) {
   804 		if (!(rpi.present[rp - rpi.start] & TRANS_PROPERTY_SATISFIED)) {
   805 			describe_unsatisfied(trans->upstream.set, rp);
   806 			unsatisfied++;
   807 		}
   808 	}
   809 
   810 	return unsatisfied;
   811 }
   812 
   813 RAZOR_EXPORT int
   814 razor_transaction_unsatisfied_property(struct razor_transaction *trans,
   815 				       const char *name,
   816 				       uint32_t flags,
   817 				       const char *version)
   818 {
   819 	struct prop_iter pi;
   820 	struct razor_property *p;
   821 
   822 	prop_iter_init(&pi, &trans->system);
   823 	while (prop_iter_next(&pi, flags & RAZOR_PROPERTY_TYPE_MASK, &p)) {
   824 		if (!(trans->system.properties[p - pi.start] & TRANS_PROPERTY_SATISFIED) &&
   825 		    p->flags == flags &&
   826 		    strcmp(&pi.pool[p->name], name) == 0 &&
   827 		    strcmp(&pi.pool[p->version], version) == 0)
   828 
   829 			return 1;
   830 	}
   831 
   832 	prop_iter_init(&pi, &trans->upstream);
   833 	while (prop_iter_next(&pi, flags & RAZOR_PROPERTY_TYPE_MASK, &p)) {
   834 		if (!(trans->upstream.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 	return 0;
   843 }
   844 
   845 RAZOR_EXPORT struct razor_set *
   846 razor_transaction_finish(struct razor_transaction *trans)
   847 {
   848 	struct razor_merger *merger;
   849 	struct razor_package *u, *uend, *upkgs, *s, *send, *spkgs;
   850 	char *upool, *spool;
   851 	int cmp;
   852 
   853 	s = trans->system.set->packages.data;
   854 	spkgs = trans->system.set->packages.data;
   855 	send = trans->system.set->packages.data +
   856 		trans->system.set->packages.size;
   857 	spool = trans->system.set->string_pool.data;
   858 
   859 	u = trans->upstream.set->packages.data;
   860 	upkgs = trans->upstream.set->packages.data;
   861 	uend = trans->upstream.set->packages.data +
   862 		trans->upstream.set->packages.size;
   863 	upool = trans->upstream.set->string_pool.data;
   864 
   865 	merger = razor_merger_create(trans->system.set, trans->upstream.set);
   866 	while (s < send || u < uend) {
   867 		if (s < send && u < uend)
   868 			cmp = strcmp(&spool[s->name], &upool[u->name]);
   869 		else if (s < send)
   870 			cmp = -1;
   871 		else
   872 			cmp = 1;
   873 
   874 		if (cmp < 0) {
   875 			if (trans->system.packages[s - spkgs] & TRANS_PACKAGE_PRESENT)
   876 				razor_merger_add_package(merger, s);
   877 			s++;
   878 		} else if (cmp == 0) {
   879 			if (trans->system.packages[s - spkgs] & TRANS_PACKAGE_PRESENT)
   880 				razor_merger_add_package(merger, s);
   881 			if (trans->upstream.packages[u - upkgs] & TRANS_PACKAGE_PRESENT)
   882 				razor_merger_add_package(merger, u);
   883 
   884 			s++;
   885 			u++;
   886 		} else {
   887 			if (trans->upstream.packages[u - upkgs] & TRANS_PACKAGE_PRESENT)
   888 				razor_merger_add_package(merger, u);
   889 			u++;
   890 		}
   891 	}
   892 
   893 	razor_transaction_destroy(trans);
   894 
   895 	return razor_merger_finish(merger);
   896 }
   897 
   898 RAZOR_EXPORT void
   899 razor_transaction_destroy(struct razor_transaction *trans)
   900 {
   901 	assert (trans != NULL);
   902 
   903 	transaction_set_release(&trans->system);
   904 	transaction_set_release(&trans->upstream);
   905 	free(trans);
   906 }