librazor/transaction.c
author Kristian H?gsberg <krh@redhat.com>
Fri Jun 20 23:13:09 2008 -0400 (2008-06-20)
changeset 257 0c3db660514d
parent 248 057933050c42
child 269 03fc85294bc9
permissions -rw-r--r--
When uniquifying properties, also sort them on the owning package.

This ensures that whenever two packages provide or (or require, obsolete
or conflict) the same property, they appear in the same order in the
propertys list of packages.
     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 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 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 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 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 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 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 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 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 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 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 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 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 }