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