librazor/transaction.c
author J. Ali Harlow <ali@juiblex.co.uk>
Wed Jun 03 08:26:09 2009 +0100 (2009-06-03)
changeset 368 ea743486ba6f
parent 331 890a49fb2c71
child 369 f8c27fe9fe63
permissions -rw-r--r--
Add automatic provides for lua pre-loaded modules
     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 	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 			fprintf(stderr, "updating %s because %s %s %s "
   544 				"isn't satisfied\n",
   545 				name, spi.pool + sp->name,
   546 				razor_property_relation_to_string(sp),
   547 				spi.pool + sp->version);
   548 			trans->system.packages[pkg - spkgs] |=
   549 				TRANS_PACKAGE_UPDATE;
   550 		}
   551 	}
   552 }
   553 
   554 RAZOR_EXPORT void
   555 razor_transaction_update_all(struct razor_transaction *trans)
   556 {
   557 	struct razor_package *p;
   558 	int i, count;
   559 
   560 	assert (trans != NULL);
   561 
   562 	count = trans->system.set->packages.size / sizeof *p;
   563 	for (i = 0; i < count; i++)
   564 		trans->system.packages[i] |= TRANS_PACKAGE_UPDATE;
   565 }
   566 
   567 static void
   568 update_conflicted_packages(struct razor_transaction *trans)
   569 {
   570 	struct razor_package *pkg, *spkgs;
   571 	struct razor_property *up, *sp;
   572 	struct prop_iter spi, upi;
   573 	struct razor_package_iterator pkg_iter;
   574 	const char *name, *version;
   575 
   576 	spkgs = trans->system.set->packages.data;
   577 	prop_iter_init(&spi, &trans->system);
   578 	prop_iter_init(&upi, &trans->upstream);
   579 
   580 	while (prop_iter_next(&spi, RAZOR_PROPERTY_CONFLICTS, &sp)) {
   581 		if (!prop_iter_seek_to(&upi, RAZOR_PROPERTY_PROVIDES,
   582 				       &spi.pool[sp->name]))
   583 			continue;
   584 
   585 		if (!any_provider_satisfies_requirement(&upi, sp->flags,
   586 							&spi.pool[sp->version]))
   587 			continue;
   588 
   589 		razor_package_iterator_init_for_property(&pkg_iter,
   590 							 trans->system.set,
   591 							 sp);
   592 		while (razor_package_iterator_next(&pkg_iter, &pkg,
   593 						   RAZOR_DETAIL_NAME, &name,
   594 						   RAZOR_DETAIL_VERSION, &version,
   595 						   RAZOR_DETAIL_LAST)) {
   596 			fprintf(stderr, "updating %s %s because it "
   597 				"conflicts with %s\n",
   598 				name, version, spi.pool + sp->name);
   599 			trans->system.packages[pkg - spkgs] |=
   600 				TRANS_PACKAGE_UPDATE;
   601 		}
   602 	}
   603 
   604 	prop_iter_init(&spi, &trans->system);
   605 	prop_iter_init(&upi, &trans->upstream);
   606 
   607 	while (prop_iter_next(&upi, RAZOR_PROPERTY_CONFLICTS, &up)) {
   608 		sp = prop_iter_seek_to(&spi, RAZOR_PROPERTY_PROVIDES,
   609 				       &upi.pool[upi.p->name]);
   610 
   611 		if (sp)
   612 			flag_matching_providers(trans, &spi, up, &upi,
   613 						TRANS_PACKAGE_UPDATE);
   614 	}
   615 }
   616 
   617 static void
   618 pull_in_requirements(struct razor_transaction *trans,
   619 		     struct prop_iter *rpi, struct prop_iter *ppi)
   620 {
   621 	struct razor_property *rp, *pp;
   622 	struct razor_package *pkg, *upkgs;
   623 
   624 	upkgs = trans->upstream.set->packages.data;
   625 	while (prop_iter_next(rpi, RAZOR_PROPERTY_REQUIRES, &rp)) {
   626 		if (rpi->present[rp - rpi->start] & TRANS_PROPERTY_SATISFIED)
   627 			continue;
   628 
   629 		pp = prop_iter_seek_to(ppi, RAZOR_PROPERTY_PROVIDES,
   630 				       &rpi->pool[rp->name]);
   631 		if (pp == NULL)
   632 			continue;
   633 		pkg = pick_matching_provider(trans->upstream.set,
   634 					     ppi, rp->flags,
   635 					     &rpi->pool[rp->version]);
   636 		if (pkg == NULL)
   637 			continue;
   638 
   639 		rpi->present[rp - rpi->start] |= TRANS_PROPERTY_SATISFIED;
   640 
   641 		fprintf(stderr, "pulling in %s-%s.%s which provides %s %s %s "
   642 			"to satisfy %s %s %s\n",
   643 			ppi->pool + pkg->name,
   644 			ppi->pool + pkg->version,
   645 			ppi->pool + pkg->arch,
   646 			ppi->pool + pp->name,
   647 			razor_property_relation_to_string(pp),
   648 			ppi->pool + pp->version,
   649 			&rpi->pool[rp->name],
   650 			razor_property_relation_to_string(rp),
   651 			&rpi->pool[rp->version]);
   652 
   653 		trans->upstream.packages[pkg - upkgs] |= TRANS_PACKAGE_UPDATE;
   654 	}
   655 }
   656 
   657 static void
   658 pull_in_all_requirements(struct razor_transaction *trans)
   659 {
   660 	struct prop_iter rpi, ppi;
   661 
   662 	prop_iter_init(&rpi, &trans->system);
   663 	prop_iter_init(&ppi, &trans->upstream);
   664 	pull_in_requirements(trans, &rpi, &ppi);
   665 
   666 	prop_iter_init(&rpi, &trans->upstream);
   667 	prop_iter_init(&ppi, &trans->upstream);
   668 	pull_in_requirements(trans, &rpi, &ppi);
   669 }
   670 
   671 static void
   672 flush_scheduled_system_updates(struct razor_transaction *trans)
   673 {
   674  	struct razor_package_iterator *pi;
   675  	struct razor_package *p, *pkg, *spkgs;
   676 	struct prop_iter ppi;
   677 	const char *name, *version;
   678 
   679 	spkgs = trans->system.set->packages.data;
   680 	pi = razor_package_iterator_create(trans->system.set);
   681 	prop_iter_init(&ppi, &trans->upstream);
   682 
   683 	while (razor_package_iterator_next(pi, &p,
   684 					   RAZOR_DETAIL_NAME, &name,
   685 					   RAZOR_DETAIL_VERSION, &version,
   686 					   RAZOR_DETAIL_LAST)) {
   687 		if (!(trans->system.packages[p - spkgs] & TRANS_PACKAGE_UPDATE))
   688 			continue;
   689 
   690 		if (!prop_iter_seek_to(&ppi, RAZOR_PROPERTY_PROVIDES, name))
   691 			continue;
   692 
   693 		pkg = pick_matching_provider(trans->upstream.set, &ppi,
   694 					     RAZOR_PROPERTY_GREATER, version);
   695 		if (pkg == NULL)
   696 			continue;
   697 
   698 		fprintf(stderr, "updating %s-%s to %s-%s\n",
   699 			name, version,
   700 			&ppi.pool[pkg->name], &ppi.pool[pkg->version]);
   701 
   702 		razor_transaction_remove_package(trans, p);
   703 		razor_transaction_install_package(trans, pkg);
   704 	}
   705 
   706 	razor_package_iterator_destroy(pi);
   707 }
   708 
   709 static void
   710 flush_scheduled_upstream_updates(struct razor_transaction *trans)
   711 {
   712  	struct razor_package_iterator *pi;
   713  	struct razor_package *p, *upkgs;
   714 	struct prop_iter spi;
   715 	const char *name, *version;
   716 
   717 	upkgs = trans->upstream.set->packages.data;
   718 	pi = razor_package_iterator_create(trans->upstream.set);
   719 	prop_iter_init(&spi, &trans->system);
   720 
   721 	while (razor_package_iterator_next(pi, &p,
   722 					   RAZOR_DETAIL_NAME, &name,
   723 					   RAZOR_DETAIL_VERSION, &version,
   724 					   RAZOR_DETAIL_LAST)) {
   725 		if (!(trans->upstream.packages[p - upkgs] & TRANS_PACKAGE_UPDATE))
   726 			continue;
   727 
   728 		if (prop_iter_seek_to(&spi, RAZOR_PROPERTY_PROVIDES, name))
   729 			remove_matching_providers(trans,
   730 						  &spi,
   731 						  RAZOR_PROPERTY_LESS,
   732 						  version);
   733 		razor_transaction_install_package(trans, p);
   734 		fprintf(stderr, "installing %s-%s\n", name, version);
   735 	}
   736 }
   737 
   738 RAZOR_EXPORT int
   739 razor_transaction_resolve(struct razor_transaction *trans)
   740 {
   741 	int last = 0;
   742 
   743 	flush_scheduled_system_updates(trans);
   744 	flush_scheduled_upstream_updates(trans);
   745 
   746 	while (last < trans->changes) {
   747 		last = trans->changes;
   748 		remove_obsoleted_packages(trans);
   749 		mark_all_satisfied_requires(trans);
   750 		update_unsatisfied_packages(trans);
   751 		update_conflicted_packages(trans);
   752 		pull_in_all_requirements(trans);
   753 		flush_scheduled_system_updates(trans);
   754 		flush_scheduled_upstream_updates(trans);
   755 	}
   756 
   757 	return trans->changes;
   758 }
   759 
   760 static void
   761 describe_unsatisfied(struct razor_set *set, struct razor_property *rp)
   762 {
   763 	struct razor_package_iterator pi;
   764 	struct razor_package *pkg;
   765 	const char *name, *version, *arch, *pool;
   766 
   767 	pool = set->string_pool.data;
   768 	if (pool[rp->version] == '\0') {
   769 		razor_package_iterator_init_for_property(&pi, set, rp);
   770 		while (razor_package_iterator_next(&pi, &pkg,
   771 						   RAZOR_DETAIL_NAME, &name,
   772 						   RAZOR_DETAIL_VERSION, &version,
   773 						   RAZOR_DETAIL_ARCH, &arch,
   774 						   RAZOR_DETAIL_LAST))
   775 			fprintf(stderr, "%s is needed by %s-%s.%s\n",
   776 				&pool[rp->name],
   777 				name, version, arch);
   778 	} else {
   779 		razor_package_iterator_init_for_property(&pi, set, rp);
   780 		while (razor_package_iterator_next(&pi, &pkg,
   781 						   RAZOR_DETAIL_NAME, &name,
   782 						   RAZOR_DETAIL_VERSION, &version,
   783 						   RAZOR_DETAIL_ARCH, &arch,
   784 						   RAZOR_DETAIL_LAST))
   785 			fprintf(stderr, "%s %s %s is needed by %s-%s.%s\n",
   786 				&pool[rp->name],
   787 				razor_property_relation_to_string(rp),
   788 				&pool[rp->version],
   789 				name, version, arch);
   790 	}
   791 }
   792 
   793 RAZOR_EXPORT int
   794 razor_transaction_describe(struct razor_transaction *trans)
   795 {
   796 	struct prop_iter rpi;
   797 	struct razor_property *rp;
   798 	int unsatisfied;
   799 
   800 	flush_scheduled_system_updates(trans);
   801 	flush_scheduled_upstream_updates(trans);
   802 	mark_all_satisfied_requires(trans);
   803 
   804 	unsatisfied = 0;
   805 	prop_iter_init(&rpi, &trans->system);
   806 	while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) {
   807 		if (!(rpi.present[rp - rpi.start] & TRANS_PROPERTY_SATISFIED)) {
   808 			describe_unsatisfied(trans->system.set, rp);
   809 		        unsatisfied++;
   810 		}
   811 	}
   812 
   813 	prop_iter_init(&rpi, &trans->upstream);
   814 	while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) {
   815 		if (!(rpi.present[rp - rpi.start] & TRANS_PROPERTY_SATISFIED)) {
   816 			describe_unsatisfied(trans->upstream.set, rp);
   817 			unsatisfied++;
   818 		}
   819 	}
   820 
   821 	return unsatisfied;
   822 }
   823 
   824 RAZOR_EXPORT int
   825 razor_transaction_unsatisfied_property(struct razor_transaction *trans,
   826 				       const char *name,
   827 				       uint32_t flags,
   828 				       const char *version)
   829 {
   830 	struct prop_iter pi;
   831 	struct razor_property *p;
   832 
   833 	prop_iter_init(&pi, &trans->system);
   834 	while (prop_iter_next(&pi, flags & RAZOR_PROPERTY_TYPE_MASK, &p)) {
   835 		if (!(trans->system.properties[p - pi.start] & TRANS_PROPERTY_SATISFIED) &&
   836 		    p->flags == flags &&
   837 		    strcmp(&pi.pool[p->name], name) == 0 &&
   838 		    strcmp(&pi.pool[p->version], version) == 0)
   839 
   840 			return 1;
   841 	}
   842 
   843 	prop_iter_init(&pi, &trans->upstream);
   844 	while (prop_iter_next(&pi, flags & RAZOR_PROPERTY_TYPE_MASK, &p)) {
   845 		if (!(trans->upstream.properties[p - pi.start] & TRANS_PROPERTY_SATISFIED) &&
   846 		    p->flags == flags &&
   847 		    strcmp(&pi.pool[p->name], name) == 0 &&
   848 		    strcmp(&pi.pool[p->version], version) == 0)
   849 
   850 			return 1;
   851 	}
   852 
   853 	return 0;
   854 }
   855 
   856 RAZOR_EXPORT struct razor_set *
   857 razor_transaction_finish(struct razor_transaction *trans)
   858 {
   859 	struct razor_merger *merger;
   860 	struct razor_package *u, *uend, *upkgs, *s, *send, *spkgs;
   861 	char *upool, *spool;
   862 	int cmp;
   863 
   864 	s = trans->system.set->packages.data;
   865 	spkgs = trans->system.set->packages.data;
   866 	send = trans->system.set->packages.data +
   867 		trans->system.set->packages.size;
   868 	spool = trans->system.set->string_pool.data;
   869 
   870 	u = trans->upstream.set->packages.data;
   871 	upkgs = trans->upstream.set->packages.data;
   872 	uend = trans->upstream.set->packages.data +
   873 		trans->upstream.set->packages.size;
   874 	upool = trans->upstream.set->string_pool.data;
   875 
   876 	merger = razor_merger_create(trans->system.set, trans->upstream.set);
   877 	while (s < send || u < uend) {
   878 		if (s < send && u < uend)
   879 			cmp = strcmp(&spool[s->name], &upool[u->name]);
   880 		else if (s < send)
   881 			cmp = -1;
   882 		else
   883 			cmp = 1;
   884 
   885 		if (cmp < 0) {
   886 			if (trans->system.packages[s - spkgs] & TRANS_PACKAGE_PRESENT)
   887 				razor_merger_add_package(merger, s);
   888 			s++;
   889 		} else if (cmp == 0) {
   890 			if (trans->system.packages[s - spkgs] & TRANS_PACKAGE_PRESENT)
   891 				razor_merger_add_package(merger, s);
   892 			if (trans->upstream.packages[u - upkgs] & TRANS_PACKAGE_PRESENT)
   893 				razor_merger_add_package(merger, u);
   894 
   895 			s++;
   896 			u++;
   897 		} else {
   898 			if (trans->upstream.packages[u - upkgs] & TRANS_PACKAGE_PRESENT)
   899 				razor_merger_add_package(merger, u);
   900 			u++;
   901 		}
   902 	}
   903 
   904 	razor_transaction_destroy(trans);
   905 
   906 	return razor_merger_finish(merger);
   907 }
   908 
   909 RAZOR_EXPORT void
   910 razor_transaction_destroy(struct razor_transaction *trans)
   911 {
   912 	assert (trans != NULL);
   913 
   914 	transaction_set_release(&trans->system);
   915 	transaction_set_release(&trans->upstream);
   916 	free(trans);
   917 }