librazor/transaction.c
author ali <j.a.harlow@letterboxes.org>
Thu Nov 10 10:35:21 2011 +0000 (2011-11-10)
changeset 404 bd740859c4a0
parent 386 3d3fab314c4e
child 432 2d8fecb8f024
permissions -rw-r--r--
Release version 0.5
     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 }