librazor/transaction.c
author J. Ali Harlow <ali@juiblex.co.uk>
Thu Feb 09 20:45:27 2012 +0000 (2012-02-09)
changeset 418 33b825d3128d
parent 386 3d3fab314c4e
child 432 2d8fecb8f024
permissions -rw-r--r--
Add transaction barriers
These allow packages to be installed and removed which have scripts
that depend on each other when atomic transactions are involved.
Note that yum supports pre, but not other requires flags. post will
need similar support to the post scripts themselves pulling in the
requires flags from the rpms. Likewise preun and postun will need
similar handling to those scrips since the requires flags will need
to be stored in the razor database.
     1 /*
     2  * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
     3  * Copyright (C) 2008  Red Hat, Inc
     4  * Copyright (C) 2009, 2011  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 <fnmatch.h>
    35 #include <assert.h>
    36 
    37 #include "razor-internal.h"
    38 #include "razor.h"
    39 
    40 static int
    41 provider_satisfies_requirement(struct razor_property *provider,
    42 			       const char *provider_strings,
    43 			       uint32_t flags,
    44 			       const char *required)
    45 {
    46 	int cmp, len;
    47 	const char *provided = &provider_strings[provider->version];
    48 
    49 	if (!*required)
    50 		return 1;
    51 	if (!*provided) {
    52 		if (flags & RAZOR_PROPERTY_LESS)
    53 			return 0;
    54 		else
    55 			return 1;
    56 	}
    57 
    58 	cmp = razor_versioncmp(provided, required);
    59 
    60 	switch (flags & RAZOR_PROPERTY_RELATION_MASK) {
    61 	case RAZOR_PROPERTY_LESS:
    62 		return cmp < 0;
    63 
    64 	case RAZOR_PROPERTY_LESS | RAZOR_PROPERTY_EQUAL:
    65 		if (cmp <= 0)
    66 			return 1;
    67 		/* fall through: FIXME, make sure this is correct */
    68 
    69 	case RAZOR_PROPERTY_EQUAL:
    70 		if (cmp == 0)
    71 			return 1;
    72 
    73 		/* "foo == 1.1" is satisfied by "foo 1.1-2" */
    74 		len = strlen(required);
    75 		if (!strncmp(required, provided, len) && provided[len] == '-')
    76 			return 1;
    77 		return 0;
    78 
    79 	case RAZOR_PROPERTY_GREATER | RAZOR_PROPERTY_EQUAL:
    80 		return cmp >= 0;
    81 
    82 	case RAZOR_PROPERTY_GREATER:
    83 		return cmp > 0;
    84 	}
    85 
    86 	/* shouldn't happen */
    87 	return 0;
    88 }
    89 
    90 #define TRANS_PACKAGE_PRESENT		1
    91 #define TRANS_PACKAGE_UPDATE		2
    92 #define TRANS_PROPERTY_SATISFIED	0x80000000
    93 
    94 struct transaction_set {
    95 	struct razor_set *set;
    96 	uint32_t *packages;
    97 	uint32_t *properties;
    98 };
    99 
   100 struct razor_transaction {
   101 	int package_count, errors;
   102 	struct transaction_set system, upstream;
   103 	int changes;
   104 	struct razor_merger *merger;
   105 };
   106 
   107 static void
   108 transaction_set_init(struct transaction_set *ts, struct razor_set *set)
   109 {
   110 	int count;
   111 
   112 	ts->set = razor_set_ref(set);
   113 	count = set->packages.size / sizeof (struct razor_package);
   114 	ts->packages = zalloc(count * sizeof *ts->packages);
   115 	count = set->properties.size / sizeof (struct razor_property);
   116 	ts->properties = zalloc(count * sizeof *ts->properties);
   117 }
   118 
   119 static void
   120 transaction_set_release(struct transaction_set *ts)
   121 {
   122 	razor_set_unref(ts->set);
   123 	free(ts->packages);
   124 	free(ts->properties);
   125 }
   126 
   127 static void
   128 transaction_set_install_package(struct transaction_set *ts,
   129 				struct razor_package *package)
   130 {
   131 	struct razor_package *pkgs;
   132 	struct list *prop;
   133 	int i;
   134 
   135 	pkgs = ts->set->packages.data;
   136 	i = package - pkgs;
   137 	if (ts->packages[i] == TRANS_PACKAGE_PRESENT)
   138 		return;
   139 
   140 	ts->packages[i] = TRANS_PACKAGE_PRESENT;
   141 
   142 	prop = list_first(&package->properties, &ts->set->property_pool);
   143 	while (prop) {
   144 		ts->properties[prop->data]++;
   145 		prop = list_next(prop);
   146 	}
   147 }
   148 
   149 static void
   150 transaction_set_remove_package(struct transaction_set *ts,
   151 			       struct razor_package *package)
   152 {
   153 	struct razor_package *pkgs;
   154 	struct list *prop;
   155 	int i;
   156 
   157 	pkgs = ts->set->packages.data;
   158 	i = package - pkgs;
   159 	if (ts->packages[i] == 0)
   160 		return;
   161 
   162 	ts->packages[i] = 0;
   163 
   164 	prop = list_first(&package->properties, &ts->set->property_pool);
   165 	while (prop) {
   166 		ts->properties[prop->data]--;
   167 		prop = list_next(prop);
   168 	}
   169 }
   170 
   171 RAZOR_EXPORT struct razor_transaction *
   172 razor_transaction_create(struct razor_set *system, struct razor_set *upstream)
   173 {
   174 	struct razor_transaction *trans;
   175 	struct razor_package *p, *spkgs, *pend;
   176 
   177 	trans = zalloc(sizeof *trans);
   178 	transaction_set_init(&trans->system, system);
   179 	transaction_set_init(&trans->upstream, upstream);
   180 
   181 	spkgs = trans->system.set->packages.data;
   182 	pend = trans->system.set->packages.data +
   183 		trans->system.set->packages.size;
   184 	for (p = spkgs; p < pend; p++)
   185 		transaction_set_install_package(&trans->system, p);
   186 
   187 	return trans;
   188 }
   189 
   190 RAZOR_EXPORT void
   191 razor_transaction_install_package(struct razor_transaction *trans,
   192 				  struct razor_package *package)
   193 {
   194 	assert (trans != NULL);
   195 	assert (package != NULL);
   196 
   197 	transaction_set_install_package(&trans->upstream, package);
   198 	trans->changes++;
   199 }
   200 
   201 RAZOR_EXPORT void
   202 razor_transaction_remove_package(struct razor_transaction *trans,
   203 				 struct razor_package *package)
   204 {
   205 	assert (trans != NULL);
   206 	assert (package != NULL);
   207 
   208 	transaction_set_remove_package(&trans->system, package);
   209 	trans->changes++;
   210 }
   211 
   212 RAZOR_EXPORT void
   213 razor_transaction_update_package(struct razor_transaction *trans,
   214 				  struct razor_package *package)
   215 {
   216 	struct razor_package *spkgs, *upkgs, *end;
   217 
   218 	assert (trans != NULL);
   219 	assert (package != NULL);
   220 
   221 	spkgs = trans->system.set->packages.data;
   222 	upkgs = trans->upstream.set->packages.data;
   223 	end = trans->system.set->packages.data +
   224 		trans->system.set->packages.size;
   225 	if (spkgs <= package && package < end)
   226 		trans->system.packages[package - spkgs] |= TRANS_PACKAGE_UPDATE;
   227 	else
   228 		trans->upstream.packages[package - upkgs] |= TRANS_PACKAGE_UPDATE;
   229 }
   230 
   231 struct prop_iter {
   232 	struct razor_property *p, *start, *end;
   233 	const char *pool;
   234 	uint32_t *present;
   235 };
   236 
   237 static void
   238 prop_iter_init(struct prop_iter *pi, struct transaction_set *ts)
   239 {
   240 	pi->p = ts->set->properties.data;
   241 	pi->start = ts->set->properties.data;
   242 	pi->end = ts->set->properties.data + ts->set->properties.size;
   243 	pi->pool = ts->set->string_pool.data;
   244 	pi->present = ts->properties;
   245 }
   246 
   247 static int
   248 prop_iter_next(struct prop_iter *pi, uint32_t flags, struct razor_property **p)
   249 {
   250 	while (pi->p < pi->end) {
   251 		if ((pi->present[pi->p - pi->start] & ~TRANS_PROPERTY_SATISFIED) &&
   252 		    (pi->p->flags & RAZOR_PROPERTY_TYPE_MASK) == flags) {
   253 			*p = pi->p++;
   254 			return 1;
   255 		}
   256 		pi->p++;
   257 	}
   258 
   259 	return 0;
   260 }
   261 
   262 static struct razor_property *
   263 prop_iter_seek_to(struct prop_iter *pi,
   264 		  uint32_t flags, const char *match)
   265 {
   266 	uint32_t name;
   267 
   268 	while (pi->p < pi->end && strcmp(&pi->pool[pi->p->name], match) < 0)
   269 		pi->p++;
   270 
   271 	if (pi->p == pi->end || strcmp(&pi->pool[pi->p->name], match) > 0)
   272 		return NULL;
   273 
   274 	name = pi->p->name;
   275 	while (pi->p < pi->end &&
   276 	       pi->p->name == name &&
   277 	       (pi->p->flags & RAZOR_PROPERTY_TYPE_MASK) != flags)
   278 		pi->p++;
   279 
   280 	if (pi->p == pi->end || pi->p->name != name)
   281 		return NULL;
   282 
   283 	return pi->p;
   284 }
   285 
   286 /* Remove packages from set that provide any of the matching (same
   287  * name and type) providers from ppi onwards that match the
   288  * requirement that rpi points to. */
   289 static void
   290 remove_matching_providers(struct razor_transaction *trans,
   291 			  struct prop_iter *ppi,
   292 			  uint32_t flags,
   293 			  const char *version)
   294 {
   295 	struct razor_property *p;
   296 	struct razor_package *pkg, *pkgs;
   297 	struct razor_package_iterator pkg_iter;
   298 	struct razor_set *set;
   299 	const char *n, *v;
   300 	uint32_t type;
   301 
   302 	if (ppi->present == trans->system.properties)
   303 		set = trans->system.set;
   304 	else
   305 		set = trans->upstream.set;
   306 
   307 	pkgs = (struct razor_package *) set->packages.data;
   308 	type = ppi->p->flags & RAZOR_PROPERTY_TYPE_MASK;
   309 	for (p = ppi->p;
   310 	     p < ppi->end &&
   311 	     p->name == ppi->p->name &&
   312 	     (p->flags & RAZOR_PROPERTY_TYPE_MASK) == type;
   313 	     p++) {
   314 		if (!ppi->present[p - ppi->start])
   315 			continue;
   316 		if (!provider_satisfies_requirement(p, ppi->pool,
   317 						    flags, version))
   318 			continue;
   319 
   320 		razor_package_iterator_init_for_property(&pkg_iter, set, p);
   321 		while (razor_package_iterator_next(&pkg_iter, &pkg,
   322 						   RAZOR_DETAIL_NAME, &n,
   323 						   RAZOR_DETAIL_VERSION, &v,
   324 						   RAZOR_DETAIL_LAST)) {
   325 #if 0
   326 			fprintf(stderr, "removing %s-%s\n", n, v);
   327 #endif
   328 			razor_transaction_remove_package(trans, pkg);
   329 		}
   330 	}
   331 }
   332 
   333 static void
   334 flag_matching_providers(struct razor_transaction *trans,
   335 			struct prop_iter *ppi,
   336 			struct razor_property *r,
   337 			struct prop_iter *rpi,
   338 			unsigned int flag)
   339 {
   340 	struct razor_property *p;
   341 	struct razor_package *pkg, *pkgs;
   342 	struct razor_package_iterator pkg_iter;
   343 	struct razor_set *set;
   344 	const char *name, *version;
   345 	uint32_t *flags, type;
   346 
   347 	if (ppi->present == trans->system.properties) {
   348 		set = trans->system.set;
   349 		flags = trans->system.packages;
   350 	} else {
   351 		set = trans->upstream.set;
   352 		flags = trans->upstream.packages;
   353 	}
   354 
   355 	pkgs = (struct razor_package *) set->packages.data;
   356 	type = ppi->p->flags & RAZOR_PROPERTY_TYPE_MASK;
   357 	for (p = ppi->p;
   358 	     p < ppi->end &&
   359 		     p->name == ppi->p->name &&
   360 		     (p->flags & RAZOR_PROPERTY_TYPE_MASK) == type;
   361 	     p++) {
   362 		if (!ppi->present[p - ppi->start])
   363 			continue;
   364 		if (!provider_satisfies_requirement(p, ppi->pool,
   365 						    r->flags,
   366 						    &rpi->pool[r->version]))
   367 			continue;
   368 
   369 		razor_package_iterator_init_for_property(&pkg_iter, set, p);
   370 		while (razor_package_iterator_next(&pkg_iter, &pkg,
   371 						   RAZOR_DETAIL_NAME, &name,
   372 						   RAZOR_DETAIL_VERSION, &version,
   373 						   RAZOR_DETAIL_LAST)) {
   374 
   375 #if 0
   376 			fprintf(stderr, "flagging %s-%s for providing %s matching %s %s\n",
   377 				name, version,
   378 				ppi->pool + p->name,
   379 				rpi->pool + r->name,
   380 				rpi->pool + r->version);
   381 #endif
   382 			flags[pkg - pkgs] |= flag;
   383 		}
   384 	}
   385 }
   386 
   387 static struct razor_package *
   388 pick_matching_provider(struct razor_set *set,
   389 		       struct prop_iter *ppi,
   390 		       uint32_t flags,
   391 		       const char *version)
   392 {
   393 	struct razor_property *p;
   394 	struct razor_package *pkgs;
   395 	struct list *i;
   396 	uint32_t type;
   397 
   398 	/* This is where we decide which pkgs to pull in to satisfy a
   399 	 * requirement.  There may be several different providers
   400 	 * (different versions) and each version of a provider may
   401 	 * come from a number of packages.  We pick the first package
   402 	 * from the first provider that matches. */
   403 
   404 	pkgs = set->packages.data;
   405 	type = ppi->p->flags & RAZOR_PROPERTY_TYPE_MASK;
   406 	for (p = ppi->p;
   407 	     p < ppi->end &&
   408 		     p->name == ppi->p->name &&
   409 		     (p->flags & RAZOR_PROPERTY_TYPE_MASK) == type &&
   410 		     ppi->present[p - ppi->start] == 0;
   411 	     p++) {
   412 		if (!provider_satisfies_requirement(p, ppi->pool,
   413 						    flags, version))
   414 			continue;
   415 
   416 		i = list_first(&p->packages, &set->package_pool);
   417 
   418 		return &pkgs[i->data];
   419 	}
   420 
   421 	return NULL;
   422 }
   423 
   424 static void
   425 remove_obsoleted_packages(struct razor_transaction *trans)
   426 {
   427 	struct razor_property *up;
   428 	struct razor_package *spkgs;
   429 	struct prop_iter spi, upi;
   430 
   431 	spkgs = trans->system.set->packages.data;
   432 	prop_iter_init(&spi, &trans->system);
   433 	prop_iter_init(&upi, &trans->upstream);
   434 
   435 	while (prop_iter_next(&upi, RAZOR_PROPERTY_OBSOLETES, &up)) {
   436 		if (!prop_iter_seek_to(&spi, RAZOR_PROPERTY_PROVIDES,
   437 				       &upi.pool[up->name]))
   438 			continue;
   439 		remove_matching_providers(trans, &spi, up->flags,
   440 					  &upi.pool[up->version]);
   441 	}
   442 }
   443 
   444 static int
   445 any_provider_satisfies_requirement(struct prop_iter *ppi,
   446 				   uint32_t flags,
   447 				   const char *version)
   448 {
   449 	struct razor_property *p;
   450 	uint32_t type;
   451 
   452 	type = ppi->p->flags & RAZOR_PROPERTY_TYPE_MASK;
   453 	for (p = ppi->p;
   454 	     p < ppi->end &&
   455 		     p->name == ppi->p->name &&
   456 		     (p->flags & RAZOR_PROPERTY_TYPE_MASK) == type;
   457 	     p++) {
   458 		if (ppi->present[p - ppi->start] > 0 &&
   459 		    provider_satisfies_requirement(p, ppi->pool,
   460 						   flags, version))
   461 			return 1;
   462 	}
   463 
   464 	return 0;
   465 }
   466 
   467 static void
   468 clear_requires_flags(struct transaction_set *ts)
   469 {
   470 	struct razor_property *p;
   471 	const char *pool;
   472 	int i, count;
   473 	char *sub;
   474 
   475 	count = ts->set->properties.size / sizeof *p;
   476 	p = ts->set->properties.data;
   477 	pool = ts->set->string_pool.data;
   478 	for (i = 0; i < count; i++) {
   479 		ts->properties[i] &= ~TRANS_PROPERTY_SATISFIED;
   480 		sub = strchr(&pool[p[i].name], '(');
   481 		if (sub && sub[strlen(sub) - 1] == ')') {
   482 			sub = strdup(sub + 1);
   483 			sub[strlen(sub) - 1] = '\0';
   484 			if (strncmp(&pool[p[i].name], "rpmlib(", 7) == 0)
   485 				ts->properties[i] |= TRANS_PROPERTY_SATISFIED;
   486 			if (strncmp(&pool[p[i].name], "lua(", 4) == 0 &&
   487 			    razor_get_lua_loader(sub) &&
   488 			    p[i].flags & RAZOR_PROPERTY_SCRIPT_MASK)
   489 				ts->properties[i] |= TRANS_PROPERTY_SATISFIED;
   490 			free(sub);
   491 		}
   492 	}
   493 }
   494 
   495 static void
   496 mark_satisfied_requires(struct razor_transaction *trans,
   497 			struct transaction_set *rts,
   498 			struct transaction_set *pts)
   499 {
   500 	struct prop_iter rpi, ppi;
   501 	struct razor_property *rp;
   502 
   503 	prop_iter_init(&rpi, rts);
   504 	prop_iter_init(&ppi, pts);
   505 
   506 	while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) {
   507 		if (!prop_iter_seek_to(&ppi, RAZOR_PROPERTY_PROVIDES,
   508 				       &rpi.pool[rp->name]))
   509 			continue;
   510 
   511 		if (any_provider_satisfies_requirement(&ppi, rp->flags,
   512 						       &rpi.pool[rp->version]))
   513 			rpi.present[rp - rpi.start] |= TRANS_PROPERTY_SATISFIED;
   514 	}
   515 }
   516 
   517 static void
   518 mark_all_satisfied_requires(struct razor_transaction *trans)
   519 {
   520 	clear_requires_flags(&trans->system);
   521 	clear_requires_flags(&trans->upstream);
   522 	mark_satisfied_requires(trans, &trans->system, &trans->system);
   523 	mark_satisfied_requires(trans, &trans->system, &trans->upstream);
   524 	mark_satisfied_requires(trans, &trans->upstream, &trans->system);
   525 	mark_satisfied_requires(trans, &trans->upstream, &trans->upstream);
   526 }
   527 
   528 static void
   529 update_unsatisfied_packages(struct razor_transaction *trans)
   530 {
   531 	struct razor_package *spkgs, *pkg;
   532 	struct razor_property *sp;
   533 	struct prop_iter spi;
   534 	struct razor_package_iterator pkg_iter;
   535 	const char *name;
   536 
   537 	spkgs = trans->system.set->packages.data;
   538 	prop_iter_init(&spi, &trans->system);
   539 
   540 	while (prop_iter_next(&spi, RAZOR_PROPERTY_REQUIRES, &sp)) {
   541 		if (spi.present[sp - spi.start] & TRANS_PROPERTY_SATISFIED)
   542 			continue;
   543 
   544 		razor_package_iterator_init_for_property(&pkg_iter,
   545 							 trans->system.set,
   546 							 sp);
   547 		while (razor_package_iterator_next(&pkg_iter, &pkg,
   548 						   RAZOR_DETAIL_NAME, &name,
   549 						   RAZOR_DETAIL_LAST)) {
   550 #if 0
   551 			fprintf(stderr, "updating %s because %s %s %s "
   552 				"isn't satisfied\n",
   553 				name, spi.pool + sp->name,
   554 				razor_property_relation_to_string(sp),
   555 				spi.pool + sp->version);
   556 #endif
   557 			trans->system.packages[pkg - spkgs] |=
   558 				TRANS_PACKAGE_UPDATE;
   559 		}
   560 	}
   561 }
   562 
   563 RAZOR_EXPORT void
   564 razor_transaction_update_all(struct razor_transaction *trans)
   565 {
   566 	struct razor_package *p;
   567 	int i, count;
   568 
   569 	assert (trans != NULL);
   570 
   571 	count = trans->system.set->packages.size / sizeof *p;
   572 	for (i = 0; i < count; i++)
   573 		trans->system.packages[i] |= TRANS_PACKAGE_UPDATE;
   574 }
   575 
   576 static void
   577 update_conflicted_packages(struct razor_transaction *trans)
   578 {
   579 	struct razor_package *pkg, *spkgs;
   580 	struct razor_property *up, *sp;
   581 	struct prop_iter spi, upi;
   582 	struct razor_package_iterator pkg_iter;
   583 	const char *name, *version;
   584 
   585 	spkgs = trans->system.set->packages.data;
   586 	prop_iter_init(&spi, &trans->system);
   587 	prop_iter_init(&upi, &trans->upstream);
   588 
   589 	while (prop_iter_next(&spi, RAZOR_PROPERTY_CONFLICTS, &sp)) {
   590 		if (!prop_iter_seek_to(&upi, RAZOR_PROPERTY_PROVIDES,
   591 				       &spi.pool[sp->name]))
   592 			continue;
   593 
   594 		if (!any_provider_satisfies_requirement(&upi, sp->flags,
   595 							&spi.pool[sp->version]))
   596 			continue;
   597 
   598 		razor_package_iterator_init_for_property(&pkg_iter,
   599 							 trans->system.set,
   600 							 sp);
   601 		while (razor_package_iterator_next(&pkg_iter, &pkg,
   602 						   RAZOR_DETAIL_NAME, &name,
   603 						   RAZOR_DETAIL_VERSION, &version,
   604 						   RAZOR_DETAIL_LAST)) {
   605 #if 0
   606 			fprintf(stderr, "updating %s %s because it "
   607 				"conflicts with %s\n",
   608 				name, version, spi.pool + sp->name);
   609 #endif
   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 #if 0
   653 		fprintf(stderr, "pulling in %s-%s.%s which provides %s %s %s "
   654 			"to satisfy %s %s %s\n",
   655 			ppi->pool + pkg->name,
   656 			ppi->pool + pkg->version,
   657 			ppi->pool + pkg->arch,
   658 			ppi->pool + pp->name,
   659 			razor_property_relation_to_string(pp),
   660 			ppi->pool + pp->version,
   661 			&rpi->pool[rp->name],
   662 			razor_property_relation_to_string(rp),
   663 			&rpi->pool[rp->version]);
   664 #endif
   665 
   666 		trans->upstream.packages[pkg - upkgs] |= TRANS_PACKAGE_UPDATE;
   667 	}
   668 }
   669 
   670 static void
   671 pull_in_all_requirements(struct razor_transaction *trans)
   672 {
   673 	struct prop_iter rpi, ppi;
   674 
   675 	prop_iter_init(&rpi, &trans->system);
   676 	prop_iter_init(&ppi, &trans->upstream);
   677 	pull_in_requirements(trans, &rpi, &ppi);
   678 
   679 	prop_iter_init(&rpi, &trans->upstream);
   680 	prop_iter_init(&ppi, &trans->upstream);
   681 	pull_in_requirements(trans, &rpi, &ppi);
   682 }
   683 
   684 static void
   685 flush_scheduled_system_updates(struct razor_transaction *trans)
   686 {
   687  	struct razor_package_iterator *pi;
   688  	struct razor_package *p, *pkg, *spkgs;
   689 	struct prop_iter ppi;
   690 	const char *name, *version;
   691 
   692 	spkgs = trans->system.set->packages.data;
   693 	pi = razor_package_iterator_create(trans->system.set);
   694 	prop_iter_init(&ppi, &trans->upstream);
   695 
   696 	while (razor_package_iterator_next(pi, &p,
   697 					   RAZOR_DETAIL_NAME, &name,
   698 					   RAZOR_DETAIL_VERSION, &version,
   699 					   RAZOR_DETAIL_LAST)) {
   700 		if (!(trans->system.packages[p - spkgs] & TRANS_PACKAGE_UPDATE))
   701 			continue;
   702 
   703 		if (!prop_iter_seek_to(&ppi, RAZOR_PROPERTY_PROVIDES, name))
   704 			continue;
   705 
   706 		if (any_provider_satisfies_requirement(&ppi,
   707 						       RAZOR_PROPERTY_GREATER,
   708 						       version)) {
   709 			razor_transaction_remove_package(trans, p);
   710 			continue;
   711 		}
   712 
   713 		pkg = pick_matching_provider(trans->upstream.set, &ppi,
   714 					     RAZOR_PROPERTY_GREATER, version);
   715 		if (pkg == NULL)
   716 			continue;
   717 
   718 		razor_transaction_remove_package(trans, p);
   719 		razor_transaction_install_package(trans, pkg);
   720 	}
   721 
   722 	razor_package_iterator_destroy(pi);
   723 }
   724 
   725 static void
   726 flush_scheduled_upstream_updates(struct razor_transaction *trans)
   727 {
   728  	struct razor_package_iterator *pi;
   729  	struct razor_package *p, *upkgs;
   730 	struct prop_iter spi;
   731 	const char *name, *version;
   732 
   733 	upkgs = trans->upstream.set->packages.data;
   734 	pi = razor_package_iterator_create(trans->upstream.set);
   735 	prop_iter_init(&spi, &trans->system);
   736 
   737 	while (razor_package_iterator_next(pi, &p,
   738 					   RAZOR_DETAIL_NAME, &name,
   739 					   RAZOR_DETAIL_VERSION, &version,
   740 					   RAZOR_DETAIL_LAST)) {
   741 		if (!(trans->upstream.packages[p - upkgs] & TRANS_PACKAGE_UPDATE))
   742 			continue;
   743 
   744 		if (prop_iter_seek_to(&spi, RAZOR_PROPERTY_PROVIDES, name))
   745 			remove_matching_providers(trans,
   746 						  &spi,
   747 						  RAZOR_PROPERTY_LESS,
   748 						  version);
   749 		razor_transaction_install_package(trans, p);
   750 #if 0
   751 		fprintf(stderr, "installing %s-%s\n", name, version);
   752 #endif
   753 	}
   754 }
   755 
   756 RAZOR_EXPORT int
   757 razor_transaction_resolve(struct razor_transaction *trans)
   758 {
   759 	int last = 0;
   760 
   761 	flush_scheduled_system_updates(trans);
   762 	flush_scheduled_upstream_updates(trans);
   763 
   764 	while (last < trans->changes) {
   765 		last = trans->changes;
   766 		remove_obsoleted_packages(trans);
   767 		mark_all_satisfied_requires(trans);
   768 		update_unsatisfied_packages(trans);
   769 		update_conflicted_packages(trans);
   770 		pull_in_all_requirements(trans);
   771 		flush_scheduled_system_updates(trans);
   772 		flush_scheduled_upstream_updates(trans);
   773 	}
   774 
   775 	return trans->changes;
   776 }
   777 
   778 static void
   779 describe_unsatisfied(struct razor_set *set, struct razor_property *rp)
   780 {
   781 	struct razor_package_iterator pi;
   782 	struct razor_package *pkg;
   783 	const char *name, *version, *arch, *pool;
   784 
   785 	pool = set->string_pool.data;
   786 	if (pool[rp->version] == '\0') {
   787 		razor_package_iterator_init_for_property(&pi, set, rp);
   788 		while (razor_package_iterator_next(&pi, &pkg,
   789 						   RAZOR_DETAIL_NAME, &name,
   790 						   RAZOR_DETAIL_VERSION, &version,
   791 						   RAZOR_DETAIL_ARCH, &arch,
   792 						   RAZOR_DETAIL_LAST))
   793 			fprintf(stderr, "%s is needed by %s-%s.%s\n",
   794 				&pool[rp->name],
   795 				name, version, arch);
   796 	} else {
   797 		razor_package_iterator_init_for_property(&pi, set, rp);
   798 		while (razor_package_iterator_next(&pi, &pkg,
   799 						   RAZOR_DETAIL_NAME, &name,
   800 						   RAZOR_DETAIL_VERSION, &version,
   801 						   RAZOR_DETAIL_ARCH, &arch,
   802 						   RAZOR_DETAIL_LAST))
   803 			fprintf(stderr, "%s %s %s is needed by %s-%s.%s\n",
   804 				&pool[rp->name],
   805 				razor_property_relation_to_string(rp),
   806 				&pool[rp->version],
   807 				name, version, arch);
   808 	}
   809 }
   810 
   811 RAZOR_EXPORT int
   812 razor_transaction_describe(struct razor_transaction *trans)
   813 {
   814 	struct prop_iter rpi;
   815 	struct razor_property *rp;
   816 	int unsatisfied;
   817 
   818 	flush_scheduled_system_updates(trans);
   819 	flush_scheduled_upstream_updates(trans);
   820 	mark_all_satisfied_requires(trans);
   821 
   822 	unsatisfied = 0;
   823 	prop_iter_init(&rpi, &trans->system);
   824 	while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) {
   825 		if (!(rpi.present[rp - rpi.start] & TRANS_PROPERTY_SATISFIED)) {
   826 			describe_unsatisfied(trans->system.set, rp);
   827 		        unsatisfied++;
   828 		}
   829 	}
   830 
   831 	prop_iter_init(&rpi, &trans->upstream);
   832 	while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) {
   833 		if (!(rpi.present[rp - rpi.start] & TRANS_PROPERTY_SATISFIED)) {
   834 			describe_unsatisfied(trans->upstream.set, rp);
   835 			unsatisfied++;
   836 		}
   837 	}
   838 
   839 	return unsatisfied;
   840 }
   841 
   842 RAZOR_EXPORT int
   843 razor_transaction_unsatisfied_property(struct razor_transaction *trans,
   844 				       const char *name,
   845 				       uint32_t flags,
   846 				       const char *version)
   847 {
   848 	struct prop_iter pi;
   849 	struct razor_property *p;
   850 
   851 	prop_iter_init(&pi, &trans->system);
   852 	while (prop_iter_next(&pi, flags & RAZOR_PROPERTY_TYPE_MASK, &p)) {
   853 		if (!(trans->system.properties[p - pi.start] & TRANS_PROPERTY_SATISFIED) &&
   854 		    p->flags == flags &&
   855 		    strcmp(&pi.pool[p->name], name) == 0 &&
   856 		    strcmp(&pi.pool[p->version], version) == 0)
   857 
   858 			return 1;
   859 	}
   860 
   861 	prop_iter_init(&pi, &trans->upstream);
   862 	while (prop_iter_next(&pi, flags & RAZOR_PROPERTY_TYPE_MASK, &p)) {
   863 		if (!(trans->upstream.properties[p - pi.start] & TRANS_PROPERTY_SATISFIED) &&
   864 		    p->flags == flags &&
   865 		    strcmp(&pi.pool[p->name], name) == 0 &&
   866 		    strcmp(&pi.pool[p->version], version) == 0)
   867 
   868 			return 1;
   869 	}
   870 
   871 	return 0;
   872 }
   873 
   874 RAZOR_EXPORT struct razor_set *
   875 razor_transaction_commit(struct razor_transaction *trans)
   876 {
   877 	struct razor_package *u, *uend, *upkgs, *s, *send, *spkgs;
   878 	char *upool, *spool;
   879 	int cmp;
   880 
   881 	s = trans->system.set->packages.data;
   882 	spkgs = trans->system.set->packages.data;
   883 	send = trans->system.set->packages.data +
   884 		trans->system.set->packages.size;
   885 	spool = trans->system.set->string_pool.data;
   886 
   887 	u = trans->upstream.set->packages.data;
   888 	upkgs = trans->upstream.set->packages.data;
   889 	uend = trans->upstream.set->packages.data +
   890 		trans->upstream.set->packages.size;
   891 	upool = trans->upstream.set->string_pool.data;
   892 
   893 	trans->merger = razor_merger_create(trans->system.set,
   894 					    trans->upstream.set);
   895 	while (s < send || u < uend) {
   896 		if (s < send && u < uend)
   897 			cmp = strcmp(&spool[s->name], &upool[u->name]);
   898 		else if (s < send)
   899 			cmp = -1;
   900 		else
   901 			cmp = 1;
   902 
   903 		if (cmp < 0) {
   904 			if (trans->system.packages[s - spkgs] & TRANS_PACKAGE_PRESENT)
   905 				razor_merger_add_package(trans->merger, s);
   906 			s++;
   907 		} else if (cmp == 0) {
   908 			if (trans->system.packages[s - spkgs] & TRANS_PACKAGE_PRESENT)
   909 				razor_merger_add_package(trans->merger, s);
   910 			if (trans->upstream.packages[u - upkgs] & TRANS_PACKAGE_PRESENT)
   911 				razor_merger_add_package(trans->merger, u);
   912 
   913 			s++;
   914 			u++;
   915 		} else {
   916 			if (trans->upstream.packages[u - upkgs] & TRANS_PACKAGE_PRESENT)
   917 				razor_merger_add_package(trans->merger, u);
   918 			u++;
   919 		}
   920 	}
   921 
   922 	return razor_merger_commit(trans->merger);
   923 }
   924 
   925 RAZOR_EXPORT void
   926 razor_transaction_fixup_package(struct razor_transaction *trans,
   927 				struct razor_package *package,
   928 				struct razor_rpm *rpm)
   929 {
   930 	const char *preunprog, *preun, *postunprog, *postun;
   931 
   932 	razor_rpm_get_details(rpm,
   933 			      RAZOR_DETAIL_PREUNPROG, &preunprog,
   934 			      RAZOR_DETAIL_PREUN, &preun,
   935 			      RAZOR_DETAIL_POSTUNPROG, &postunprog,
   936 			      RAZOR_DETAIL_POSTUN, &postun,
   937 			      RAZOR_DETAIL_LAST);
   938 
   939 	razor_merger_package_add_script(trans->merger, package,
   940 					RAZOR_PROPERTY_PREUN,
   941 					preunprog, preun);
   942 	razor_merger_package_add_script(trans->merger, package,
   943 					RAZOR_PROPERTY_POSTUN,
   944 					postunprog, postun);
   945 }
   946 
   947 RAZOR_EXPORT void
   948 razor_transaction_destroy(struct razor_transaction *trans)
   949 {
   950 	assert (trans != NULL);
   951 
   952 	if (trans->merger)
   953 		razor_merger_destroy(trans->merger);
   954 	transaction_set_release(&trans->system);
   955 	transaction_set_release(&trans->upstream);
   956 	free(trans);
   957 }