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