librazor/transaction.c
author Kristian H?gsberg <krh@redhat.com>
Wed Jul 02 14:37:38 2008 -0400 (2008-07-02)
changeset 311 cd292c2de0b6
parent 304 bf23ba00db03
child 331 890a49fb2c71
permissions -rw-r--r--
Move DEPSOLVE.txt and REPO.txt into docbook.

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