librazor/transaction.c
author J. Ali Harlow <ali@juiblex.co.uk>
Wed Oct 22 12:09:47 2014 +0100 (2014-10-22)
changeset 460 b8638c3c7eee
parent 446 4277359896dc
child 475 008c75a5e08d
permissions -rw-r--r--
Add basic checks for rpm file format
     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 	razor_package_iterator_destroy(pi);
   758 }
   759 
   760 RAZOR_EXPORT int
   761 razor_transaction_resolve(struct razor_transaction *trans)
   762 {
   763 	int last = 0;
   764 
   765 	flush_scheduled_system_updates(trans);
   766 	flush_scheduled_upstream_updates(trans);
   767 
   768 	while (last < trans->changes) {
   769 		last = trans->changes;
   770 		remove_obsoleted_packages(trans);
   771 		mark_all_satisfied_requires(trans);
   772 		update_unsatisfied_packages(trans);
   773 		update_conflicted_packages(trans);
   774 		pull_in_all_requirements(trans);
   775 		flush_scheduled_system_updates(trans);
   776 		flush_scheduled_upstream_updates(trans);
   777 	}
   778 
   779 	return trans->changes;
   780 }
   781 
   782 static void
   783 describe_unsatisfied(struct razor_set *set, struct razor_property *rp,
   784 		     razor_unsatisfied_callback_t callback, void *data)
   785 {
   786 	struct razor_package_iterator pi;
   787 	struct razor_package *pkg;
   788 	const char *name, *version, *arch, *pool;
   789 	const char *requirement;
   790 	char *s = NULL;
   791 
   792 	pool = set->string_pool.data;
   793 	if (pool[rp->version] == '\0')
   794 		requirement = &pool[rp->name];
   795 	else {
   796 		s = razor_concat(&pool[rp->name], " ",
   797 				 razor_property_relation_to_string(rp), " ",
   798 				 &pool[rp->version], NULL);
   799 		requirement = s;
   800 	}
   801 
   802 	razor_package_iterator_init_for_property(&pi, set, rp);
   803 	while (razor_package_iterator_next(&pi, &pkg,
   804 					   RAZOR_DETAIL_NAME, &name,
   805 					   RAZOR_DETAIL_VERSION, &version,
   806 					   RAZOR_DETAIL_ARCH, &arch,
   807 					   RAZOR_DETAIL_LAST))
   808 		callback(requirement, pkg, name, version, arch, data);
   809 
   810 	if (s)
   811 		free(s);
   812 }
   813 
   814 RAZOR_EXPORT int
   815 razor_transaction_unsatisfied(struct razor_transaction *trans,
   816 			      razor_unsatisfied_callback_t callback, void *data)
   817 {
   818 	struct prop_iter rpi;
   819 	struct razor_property *rp;
   820 	int unsatisfied;
   821 
   822 	flush_scheduled_system_updates(trans);
   823 	flush_scheduled_upstream_updates(trans);
   824 	mark_all_satisfied_requires(trans);
   825 
   826 	unsatisfied = 0;
   827 	prop_iter_init(&rpi, &trans->system);
   828 	while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) {
   829 		if (!(rpi.present[rp - rpi.start] & TRANS_PROPERTY_SATISFIED)) {
   830 			if (callback)
   831 				describe_unsatisfied(trans->system.set, rp,
   832 						     callback, data);
   833 		        unsatisfied++;
   834 		}
   835 	}
   836 
   837 	prop_iter_init(&rpi, &trans->upstream);
   838 	while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) {
   839 		if (!(rpi.present[rp - rpi.start] & TRANS_PROPERTY_SATISFIED)) {
   840 			if (callback)
   841 				describe_unsatisfied(trans->upstream.set, rp,
   842 						     callback, data);
   843 			unsatisfied++;
   844 		}
   845 	}
   846 
   847 	return unsatisfied;
   848 }
   849 
   850 static void
   851 describe_unsatisfied_callback(const char *requirement,
   852 			      struct razor_package *package, const char *name,
   853 			      const char *version, const char *arch, void *data)
   854 {
   855 	FILE *fp = data;
   856 
   857 	fprintf(fp, "%s is needed by %s-%s.%s\n", requirement,
   858 		name, version, arch);
   859 }
   860 
   861 RAZOR_EXPORT int
   862 razor_transaction_describe(struct razor_transaction *trans)
   863 {
   864 	return razor_transaction_unsatisfied(trans,
   865 					     describe_unsatisfied_callback,
   866 					     stderr);
   867 }
   868 
   869 RAZOR_EXPORT int
   870 razor_transaction_unsatisfied_property(struct razor_transaction *trans,
   871 				       const char *name,
   872 				       uint32_t flags,
   873 				       const char *version)
   874 {
   875 	struct prop_iter pi;
   876 	struct razor_property *p;
   877 
   878 	prop_iter_init(&pi, &trans->system);
   879 	while (prop_iter_next(&pi, flags & RAZOR_PROPERTY_TYPE_MASK, &p)) {
   880 		if (!(trans->system.properties[p - pi.start] & TRANS_PROPERTY_SATISFIED) &&
   881 		    p->flags == flags &&
   882 		    strcmp(&pi.pool[p->name], name) == 0 &&
   883 		    strcmp(&pi.pool[p->version], version) == 0)
   884 
   885 			return 1;
   886 	}
   887 
   888 	prop_iter_init(&pi, &trans->upstream);
   889 	while (prop_iter_next(&pi, flags & RAZOR_PROPERTY_TYPE_MASK, &p)) {
   890 		if (!(trans->upstream.properties[p - pi.start] & TRANS_PROPERTY_SATISFIED) &&
   891 		    p->flags == flags &&
   892 		    strcmp(&pi.pool[p->name], name) == 0 &&
   893 		    strcmp(&pi.pool[p->version], version) == 0)
   894 
   895 			return 1;
   896 	}
   897 
   898 	return 0;
   899 }
   900 
   901 RAZOR_EXPORT struct razor_set *
   902 razor_transaction_commit(struct razor_transaction *trans)
   903 {
   904 	struct razor_package *u, *uend, *upkgs, *s, *send, *spkgs;
   905 	char *upool, *spool;
   906 	int cmp;
   907 
   908 	s = trans->system.set->packages.data;
   909 	spkgs = trans->system.set->packages.data;
   910 	send = trans->system.set->packages.data +
   911 		trans->system.set->packages.size;
   912 	spool = trans->system.set->string_pool.data;
   913 
   914 	u = trans->upstream.set->packages.data;
   915 	upkgs = trans->upstream.set->packages.data;
   916 	uend = trans->upstream.set->packages.data +
   917 		trans->upstream.set->packages.size;
   918 	upool = trans->upstream.set->string_pool.data;
   919 
   920 	trans->merger = razor_merger_create(trans->system.set,
   921 					    trans->upstream.set);
   922 	while (s < send || u < uend) {
   923 		if (s < send && u < uend)
   924 			cmp = strcmp(&spool[s->name], &upool[u->name]);
   925 		else if (s < send)
   926 			cmp = -1;
   927 		else
   928 			cmp = 1;
   929 
   930 		if (cmp < 0) {
   931 			if (trans->system.packages[s - spkgs] & TRANS_PACKAGE_PRESENT)
   932 				razor_merger_add_package(trans->merger, s);
   933 			s++;
   934 		} else if (cmp == 0) {
   935 			if (trans->system.packages[s - spkgs] & TRANS_PACKAGE_PRESENT)
   936 				razor_merger_add_package(trans->merger, s);
   937 			if (trans->upstream.packages[u - upkgs] & TRANS_PACKAGE_PRESENT)
   938 				razor_merger_add_package(trans->merger, u);
   939 
   940 			s++;
   941 			u++;
   942 		} else {
   943 			if (trans->upstream.packages[u - upkgs] & TRANS_PACKAGE_PRESENT)
   944 				razor_merger_add_package(trans->merger, u);
   945 			u++;
   946 		}
   947 	}
   948 
   949 	return razor_merger_commit(trans->merger);
   950 }
   951 
   952 RAZOR_EXPORT void
   953 razor_transaction_fixup_package(struct razor_transaction *trans,
   954 				struct razor_package *package,
   955 				struct razor_rpm *rpm)
   956 {
   957 	const char *preunprog, *preun, *postunprog, *postun;
   958 
   959 	razor_rpm_get_details(rpm,
   960 			      RAZOR_DETAIL_PREUNPROG, &preunprog,
   961 			      RAZOR_DETAIL_PREUN, &preun,
   962 			      RAZOR_DETAIL_POSTUNPROG, &postunprog,
   963 			      RAZOR_DETAIL_POSTUN, &postun,
   964 			      RAZOR_DETAIL_LAST);
   965 
   966 	razor_merger_package_add_script(trans->merger, package,
   967 					RAZOR_PROPERTY_PREUN,
   968 					preunprog, preun);
   969 	razor_merger_package_add_script(trans->merger, package,
   970 					RAZOR_PROPERTY_POSTUN,
   971 					postunprog, postun);
   972 }
   973 
   974 RAZOR_EXPORT void
   975 razor_transaction_destroy(struct razor_transaction *trans)
   976 {
   977 	assert (trans != NULL);
   978 
   979 	if (trans->merger)
   980 		razor_merger_destroy(trans->merger);
   981 	transaction_set_release(&trans->system);
   982 	transaction_set_release(&trans->upstream);
   983 	free(trans);
   984 }