librazor/transaction.c
author J. Ali Harlow <ali@juiblex.co.uk>
Thu Sep 11 18:54:16 2014 +0100 (2014-09-11)
changeset 448 8476d35b048f
parent 442 c4bcba8023a9
child 458 3f841a46eab5
permissions -rw-r--r--
Remove prototype for long-removed razor_set_get_package
     1 /*
     2  * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
     3  * Copyright (C) 2008  Red Hat, Inc
     4  * Copyright (C) 2009, 2011, 2012, 2014  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 "config.h"
    24 #include <stdlib.h>
    25 #include <stddef.h>
    26 #include <stdint.h>
    27 #include <stdio.h>
    28 #include <string.h>
    29 #include <sys/types.h>
    30 #include <sys/stat.h>
    31 #include <unistd.h>
    32 #include <fcntl.h>
    33 #include <errno.h>
    34 #include <ctype.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] & TRANS_PACKAGE_PRESENT))
   160 		return;
   161 
   162 	ts->packages[i] &= ~TRANS_PACKAGE_PRESENT;
   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;
   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 	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 prop_iter spi, upi;
   428 
   429 	prop_iter_init(&spi, &trans->system);
   430 	prop_iter_init(&upi, &trans->upstream);
   431 
   432 	while (prop_iter_next(&upi, RAZOR_PROPERTY_OBSOLETES, &up)) {
   433 		if (!prop_iter_seek_to(&spi, RAZOR_PROPERTY_PROVIDES,
   434 				       &upi.pool[up->name]))
   435 			continue;
   436 		remove_matching_providers(trans, &spi, up->flags,
   437 					  &upi.pool[up->version]);
   438 	}
   439 }
   440 
   441 static int
   442 any_provider_satisfies_requirement(struct prop_iter *ppi,
   443 				   uint32_t flags,
   444 				   const char *version)
   445 {
   446 	struct razor_property *p;
   447 	uint32_t type;
   448 
   449 	type = ppi->p->flags & RAZOR_PROPERTY_TYPE_MASK;
   450 	for (p = ppi->p;
   451 	     p < ppi->end &&
   452 		     p->name == ppi->p->name &&
   453 		     (p->flags & RAZOR_PROPERTY_TYPE_MASK) == type;
   454 	     p++) {
   455 		if (ppi->present[p - ppi->start] > 0 &&
   456 		    provider_satisfies_requirement(p, ppi->pool,
   457 						   flags, version))
   458 			return 1;
   459 	}
   460 
   461 	return 0;
   462 }
   463 
   464 static void
   465 clear_requires_flags(struct transaction_set *ts)
   466 {
   467 	struct razor_property *p;
   468 	const char *pool;
   469 	int i, count;
   470 	char *sub;
   471 
   472 	count = ts->set->properties.size / sizeof *p;
   473 	p = ts->set->properties.data;
   474 	pool = ts->set->string_pool.data;
   475 	for (i = 0; i < count; i++) {
   476 		ts->properties[i] &= ~TRANS_PROPERTY_SATISFIED;
   477 		sub = strchr(&pool[p[i].name], '(');
   478 		if (sub && sub[strlen(sub) - 1] == ')') {
   479 			sub = strdup(sub + 1);
   480 			sub[strlen(sub) - 1] = '\0';
   481 			if (strncmp(&pool[p[i].name], "rpmlib(", 7) == 0)
   482 				ts->properties[i] |= TRANS_PROPERTY_SATISFIED;
   483 			if (strncmp(&pool[p[i].name], "lua(", 4) == 0 &&
   484 			    razor_get_lua_loader(sub) &&
   485 			    p[i].flags & RAZOR_PROPERTY_SCRIPT_MASK)
   486 				ts->properties[i] |= TRANS_PROPERTY_SATISFIED;
   487 			free(sub);
   488 		}
   489 	}
   490 }
   491 
   492 static void
   493 mark_satisfied_requires(struct razor_transaction *trans,
   494 			struct transaction_set *rts,
   495 			struct transaction_set *pts)
   496 {
   497 	struct prop_iter rpi, ppi;
   498 	struct razor_property *rp;
   499 
   500 	prop_iter_init(&rpi, rts);
   501 	prop_iter_init(&ppi, pts);
   502 
   503 	while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) {
   504 		if (!prop_iter_seek_to(&ppi, RAZOR_PROPERTY_PROVIDES,
   505 				       &rpi.pool[rp->name]))
   506 			continue;
   507 
   508 		if (any_provider_satisfies_requirement(&ppi, rp->flags,
   509 						       &rpi.pool[rp->version]))
   510 			rpi.present[rp - rpi.start] |= TRANS_PROPERTY_SATISFIED;
   511 	}
   512 }
   513 
   514 static void
   515 mark_all_satisfied_requires(struct razor_transaction *trans)
   516 {
   517 	clear_requires_flags(&trans->system);
   518 	clear_requires_flags(&trans->upstream);
   519 	mark_satisfied_requires(trans, &trans->system, &trans->system);
   520 	mark_satisfied_requires(trans, &trans->system, &trans->upstream);
   521 	mark_satisfied_requires(trans, &trans->upstream, &trans->system);
   522 	mark_satisfied_requires(trans, &trans->upstream, &trans->upstream);
   523 }
   524 
   525 static void
   526 update_unsatisfied_packages(struct razor_transaction *trans)
   527 {
   528 	struct razor_package *spkgs, *pkg;
   529 	struct razor_property *sp;
   530 	struct prop_iter spi;
   531 	struct razor_package_iterator pkg_iter;
   532 	const char *name;
   533 
   534 	spkgs = trans->system.set->packages.data;
   535 	prop_iter_init(&spi, &trans->system);
   536 
   537 	while (prop_iter_next(&spi, RAZOR_PROPERTY_REQUIRES, &sp)) {
   538 		if (spi.present[sp - spi.start] & TRANS_PROPERTY_SATISFIED)
   539 			continue;
   540 
   541 		razor_package_iterator_init_for_property(&pkg_iter,
   542 							 trans->system.set,
   543 							 sp);
   544 		while (razor_package_iterator_next(&pkg_iter, &pkg,
   545 						   RAZOR_DETAIL_NAME, &name,
   546 						   RAZOR_DETAIL_LAST)) {
   547 			if (!(trans->system.packages[pkg - spkgs] & TRANS_PACKAGE_PRESENT))
   548 				continue;
   549 
   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 		trans->system.packages[p - spkgs] &= ~TRANS_PACKAGE_UPDATE;
   703 
   704 		if (!prop_iter_seek_to(&ppi, RAZOR_PROPERTY_PROVIDES, name))
   705 			continue;
   706 
   707 		if (any_provider_satisfies_requirement(&ppi,
   708 						       RAZOR_PROPERTY_GREATER,
   709 						       version)) {
   710 			razor_transaction_remove_package(trans, p);
   711 			continue;
   712 		}
   713 
   714 		pkg = pick_matching_provider(trans->upstream.set, &ppi,
   715 					     RAZOR_PROPERTY_GREATER, version);
   716 		if (pkg == NULL)
   717 			continue;
   718 
   719 		razor_transaction_remove_package(trans, p);
   720 		razor_transaction_install_package(trans, pkg);
   721 	}
   722 
   723 	razor_package_iterator_destroy(pi);
   724 }
   725 
   726 static void
   727 flush_scheduled_upstream_updates(struct razor_transaction *trans)
   728 {
   729  	struct razor_package_iterator *pi;
   730  	struct razor_package *p, *upkgs;
   731 	struct prop_iter spi;
   732 	const char *name, *version;
   733 
   734 	upkgs = trans->upstream.set->packages.data;
   735 	pi = razor_package_iterator_create(trans->upstream.set);
   736 	prop_iter_init(&spi, &trans->system);
   737 
   738 	while (razor_package_iterator_next(pi, &p,
   739 					   RAZOR_DETAIL_NAME, &name,
   740 					   RAZOR_DETAIL_VERSION, &version,
   741 					   RAZOR_DETAIL_LAST)) {
   742 		if (!(trans->upstream.packages[p - upkgs] & TRANS_PACKAGE_UPDATE))
   743 			continue;
   744 		trans->upstream.packages[p - upkgs] &= ~TRANS_PACKAGE_UPDATE;
   745 
   746 		if (prop_iter_seek_to(&spi, RAZOR_PROPERTY_PROVIDES, name))
   747 			remove_matching_providers(trans,
   748 						  &spi,
   749 						  RAZOR_PROPERTY_LESS,
   750 						  version);
   751 		razor_transaction_install_package(trans, p);
   752 #if 0
   753 		fprintf(stderr, "installing %s-%s\n", name, version);
   754 #endif
   755 	}
   756 }
   757 
   758 RAZOR_EXPORT int
   759 razor_transaction_resolve(struct razor_transaction *trans)
   760 {
   761 	int last = 0;
   762 
   763 	flush_scheduled_system_updates(trans);
   764 	flush_scheduled_upstream_updates(trans);
   765 
   766 	while (last < trans->changes) {
   767 		last = trans->changes;
   768 		remove_obsoleted_packages(trans);
   769 		mark_all_satisfied_requires(trans);
   770 		update_unsatisfied_packages(trans);
   771 		update_conflicted_packages(trans);
   772 		pull_in_all_requirements(trans);
   773 		flush_scheduled_system_updates(trans);
   774 		flush_scheduled_upstream_updates(trans);
   775 	}
   776 
   777 	return trans->changes;
   778 }
   779 
   780 static void
   781 describe_unsatisfied(struct razor_set *set, struct razor_property *rp,
   782 		     razor_unsatisfied_callback_t callback, void *data)
   783 {
   784 	struct razor_package_iterator pi;
   785 	struct razor_package *pkg;
   786 	const char *name, *version, *arch, *pool;
   787 	const char *requirement;
   788 	char *s = NULL;
   789 
   790 	pool = set->string_pool.data;
   791 	if (pool[rp->version] == '\0')
   792 		requirement = &pool[rp->name];
   793 	else {
   794 		s = razor_concat(&pool[rp->name], " ",
   795 				 razor_property_relation_to_string(rp), " ",
   796 				 &pool[rp->version], NULL);
   797 		requirement = s;
   798 	}
   799 
   800 	razor_package_iterator_init_for_property(&pi, set, rp);
   801 	while (razor_package_iterator_next(&pi, &pkg,
   802 					   RAZOR_DETAIL_NAME, &name,
   803 					   RAZOR_DETAIL_VERSION, &version,
   804 					   RAZOR_DETAIL_ARCH, &arch,
   805 					   RAZOR_DETAIL_LAST))
   806 		callback(requirement, pkg, name, version, arch, data);
   807 
   808 	if (s)
   809 		free(s);
   810 }
   811 
   812 RAZOR_EXPORT int
   813 razor_transaction_unsatisfied(struct razor_transaction *trans,
   814 			      razor_unsatisfied_callback_t callback, void *data)
   815 {
   816 	struct prop_iter rpi;
   817 	struct razor_property *rp;
   818 	int unsatisfied;
   819 
   820 	flush_scheduled_system_updates(trans);
   821 	flush_scheduled_upstream_updates(trans);
   822 	mark_all_satisfied_requires(trans);
   823 
   824 	unsatisfied = 0;
   825 	prop_iter_init(&rpi, &trans->system);
   826 	while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) {
   827 		if (!(rpi.present[rp - rpi.start] & TRANS_PROPERTY_SATISFIED)) {
   828 			if (callback)
   829 				describe_unsatisfied(trans->system.set, rp,
   830 						     callback, data);
   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 			if (callback)
   839 				describe_unsatisfied(trans->upstream.set, rp,
   840 						     callback, data);
   841 			unsatisfied++;
   842 		}
   843 	}
   844 
   845 	return unsatisfied;
   846 }
   847 
   848 static void
   849 describe_unsatisfied_callback(const char *requirement,
   850 			      struct razor_package *package, const char *name,
   851 			      const char *version, const char *arch, void *data)
   852 {
   853 	FILE *fp = data;
   854 
   855 	fprintf(fp, "%s is needed by %s-%s.%s\n", requirement,
   856 		name, version, arch);
   857 }
   858 
   859 RAZOR_EXPORT int
   860 razor_transaction_describe(struct razor_transaction *trans)
   861 {
   862 	return razor_transaction_unsatisfied(trans,
   863 					     describe_unsatisfied_callback,
   864 					     stderr);
   865 }
   866 
   867 RAZOR_EXPORT int
   868 razor_transaction_unsatisfied_property(struct razor_transaction *trans,
   869 				       const char *name,
   870 				       uint32_t flags,
   871 				       const char *version)
   872 {
   873 	struct prop_iter pi;
   874 	struct razor_property *p;
   875 
   876 	prop_iter_init(&pi, &trans->system);
   877 	while (prop_iter_next(&pi, flags & RAZOR_PROPERTY_TYPE_MASK, &p)) {
   878 		if (!(trans->system.properties[p - pi.start] & TRANS_PROPERTY_SATISFIED) &&
   879 		    p->flags == flags &&
   880 		    strcmp(&pi.pool[p->name], name) == 0 &&
   881 		    strcmp(&pi.pool[p->version], version) == 0)
   882 
   883 			return 1;
   884 	}
   885 
   886 	prop_iter_init(&pi, &trans->upstream);
   887 	while (prop_iter_next(&pi, flags & RAZOR_PROPERTY_TYPE_MASK, &p)) {
   888 		if (!(trans->upstream.properties[p - pi.start] & TRANS_PROPERTY_SATISFIED) &&
   889 		    p->flags == flags &&
   890 		    strcmp(&pi.pool[p->name], name) == 0 &&
   891 		    strcmp(&pi.pool[p->version], version) == 0)
   892 
   893 			return 1;
   894 	}
   895 
   896 	return 0;
   897 }
   898 
   899 RAZOR_EXPORT struct razor_set *
   900 razor_transaction_commit(struct razor_transaction *trans)
   901 {
   902 	struct razor_package *u, *uend, *upkgs, *s, *send, *spkgs;
   903 	char *upool, *spool;
   904 	int cmp;
   905 
   906 	s = trans->system.set->packages.data;
   907 	spkgs = trans->system.set->packages.data;
   908 	send = trans->system.set->packages.data +
   909 		trans->system.set->packages.size;
   910 	spool = trans->system.set->string_pool.data;
   911 
   912 	u = trans->upstream.set->packages.data;
   913 	upkgs = trans->upstream.set->packages.data;
   914 	uend = trans->upstream.set->packages.data +
   915 		trans->upstream.set->packages.size;
   916 	upool = trans->upstream.set->string_pool.data;
   917 
   918 	trans->merger = razor_merger_create(trans->system.set,
   919 					    trans->upstream.set);
   920 	while (s < send || u < uend) {
   921 		if (s < send && u < uend)
   922 			cmp = strcmp(&spool[s->name], &upool[u->name]);
   923 		else if (s < send)
   924 			cmp = -1;
   925 		else
   926 			cmp = 1;
   927 
   928 		if (cmp < 0) {
   929 			if (trans->system.packages[s - spkgs] & TRANS_PACKAGE_PRESENT)
   930 				razor_merger_add_package(trans->merger, s);
   931 			s++;
   932 		} else if (cmp == 0) {
   933 			if (trans->system.packages[s - spkgs] & TRANS_PACKAGE_PRESENT)
   934 				razor_merger_add_package(trans->merger, s);
   935 			if (trans->upstream.packages[u - upkgs] & TRANS_PACKAGE_PRESENT)
   936 				razor_merger_add_package(trans->merger, u);
   937 
   938 			s++;
   939 			u++;
   940 		} else {
   941 			if (trans->upstream.packages[u - upkgs] & TRANS_PACKAGE_PRESENT)
   942 				razor_merger_add_package(trans->merger, u);
   943 			u++;
   944 		}
   945 	}
   946 
   947 	return razor_merger_commit(trans->merger);
   948 }
   949 
   950 RAZOR_EXPORT void
   951 razor_transaction_fixup_package(struct razor_transaction *trans,
   952 				struct razor_package *package,
   953 				struct razor_rpm *rpm)
   954 {
   955 	const char *preunprog, *preun, *postunprog, *postun;
   956 
   957 	razor_rpm_get_details(rpm,
   958 			      RAZOR_DETAIL_PREUNPROG, &preunprog,
   959 			      RAZOR_DETAIL_PREUN, &preun,
   960 			      RAZOR_DETAIL_POSTUNPROG, &postunprog,
   961 			      RAZOR_DETAIL_POSTUN, &postun,
   962 			      RAZOR_DETAIL_LAST);
   963 
   964 	razor_merger_package_add_script(trans->merger, package,
   965 					RAZOR_PROPERTY_PREUN,
   966 					preunprog, preun);
   967 	razor_merger_package_add_script(trans->merger, package,
   968 					RAZOR_PROPERTY_POSTUN,
   969 					postunprog, postun);
   970 }
   971 
   972 RAZOR_EXPORT void
   973 razor_transaction_destroy(struct razor_transaction *trans)
   974 {
   975 	assert (trans != NULL);
   976 
   977 	if (trans->merger)
   978 		razor_merger_destroy(trans->merger);
   979 	transaction_set_release(&trans->system);
   980 	transaction_set_release(&trans->upstream);
   981 	free(trans);
   982 }