librazor/transaction.c
author J. Ali Harlow <ali@juiblex.co.uk>
Sat Aug 23 11:13:48 2014 +0100 (2014-08-23)
changeset 440 48204dea0b9f
parent 432 2d8fecb8f024
child 442 c4bcba8023a9
permissions -rw-r--r--
Remove INTLLIBS from librazor_la_LIBADD.

This partially reverts 611c84a3f4b4538a65d186050608c17adbf17770.
It's not clear what motivated the initial inclusion of INTLLIBS
here since the net effect is only seen in librazor.la and not
in razor.pc and librazor.la is not normally packaged. Certainly
neither the static nor the dynamic versions of librazor currently
use libintl. At best this would cause the linker to search a
static libintl for undefined symbols without finding any; at worse
it causes a static build of plover using librazor.la to fail if
no static version of libintl is installed.
     1 /*
     2  * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
     3  * Copyright (C) 2008  Red Hat, Inc
     4  * Copyright (C) 2009, 2011, 2012  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, *pkgs;
   297 	struct razor_package_iterator pkg_iter;
   298 	struct razor_set *set;
   299 	const char *n, *v;
   300 	uint32_t type;
   301 
   302 	if (ppi->present == trans->system.properties)
   303 		set = trans->system.set;
   304 	else
   305 		set = trans->upstream.set;
   306 
   307 	pkgs = (struct razor_package *) set->packages.data;
   308 	type = ppi->p->flags & RAZOR_PROPERTY_TYPE_MASK;
   309 	for (p = ppi->p;
   310 	     p < ppi->end &&
   311 	     p->name == ppi->p->name &&
   312 	     (p->flags & RAZOR_PROPERTY_TYPE_MASK) == type;
   313 	     p++) {
   314 		if (!ppi->present[p - ppi->start])
   315 			continue;
   316 		if (!provider_satisfies_requirement(p, ppi->pool,
   317 						    flags, version))
   318 			continue;
   319 
   320 		razor_package_iterator_init_for_property(&pkg_iter, set, p);
   321 		while (razor_package_iterator_next(&pkg_iter, &pkg,
   322 						   RAZOR_DETAIL_NAME, &n,
   323 						   RAZOR_DETAIL_VERSION, &v,
   324 						   RAZOR_DETAIL_LAST)) {
   325 #if 0
   326 			fprintf(stderr, "removing %s-%s\n", n, v);
   327 #endif
   328 			razor_transaction_remove_package(trans, pkg);
   329 		}
   330 	}
   331 }
   332 
   333 static void
   334 flag_matching_providers(struct razor_transaction *trans,
   335 			struct prop_iter *ppi,
   336 			struct razor_property *r,
   337 			struct prop_iter *rpi,
   338 			unsigned int flag)
   339 {
   340 	struct razor_property *p;
   341 	struct razor_package *pkg, *pkgs;
   342 	struct razor_package_iterator pkg_iter;
   343 	struct razor_set *set;
   344 	const char *name, *version;
   345 	uint32_t *flags, type;
   346 
   347 	if (ppi->present == trans->system.properties) {
   348 		set = trans->system.set;
   349 		flags = trans->system.packages;
   350 	} else {
   351 		set = trans->upstream.set;
   352 		flags = trans->upstream.packages;
   353 	}
   354 
   355 	pkgs = (struct razor_package *) set->packages.data;
   356 	type = ppi->p->flags & RAZOR_PROPERTY_TYPE_MASK;
   357 	for (p = ppi->p;
   358 	     p < ppi->end &&
   359 		     p->name == ppi->p->name &&
   360 		     (p->flags & RAZOR_PROPERTY_TYPE_MASK) == type;
   361 	     p++) {
   362 		if (!ppi->present[p - ppi->start])
   363 			continue;
   364 		if (!provider_satisfies_requirement(p, ppi->pool,
   365 						    r->flags,
   366 						    &rpi->pool[r->version]))
   367 			continue;
   368 
   369 		razor_package_iterator_init_for_property(&pkg_iter, set, p);
   370 		while (razor_package_iterator_next(&pkg_iter, &pkg,
   371 						   RAZOR_DETAIL_NAME, &name,
   372 						   RAZOR_DETAIL_VERSION, &version,
   373 						   RAZOR_DETAIL_LAST)) {
   374 
   375 #if 0
   376 			fprintf(stderr, "flagging %s-%s for providing %s matching %s %s\n",
   377 				name, version,
   378 				ppi->pool + p->name,
   379 				rpi->pool + r->name,
   380 				rpi->pool + r->version);
   381 #endif
   382 			flags[pkg - pkgs] |= flag;
   383 		}
   384 	}
   385 }
   386 
   387 static struct razor_package *
   388 pick_matching_provider(struct razor_set *set,
   389 		       struct prop_iter *ppi,
   390 		       uint32_t flags,
   391 		       const char *version)
   392 {
   393 	struct razor_property *p;
   394 	struct razor_package *pkgs;
   395 	struct list *i;
   396 	uint32_t type;
   397 
   398 	/* This is where we decide which pkgs to pull in to satisfy a
   399 	 * requirement.  There may be several different providers
   400 	 * (different versions) and each version of a provider may
   401 	 * come from a number of packages.  We pick the first package
   402 	 * from the first provider that matches. */
   403 
   404 	pkgs = set->packages.data;
   405 	type = ppi->p->flags & RAZOR_PROPERTY_TYPE_MASK;
   406 	for (p = ppi->p;
   407 	     p < ppi->end &&
   408 		     p->name == ppi->p->name &&
   409 		     (p->flags & RAZOR_PROPERTY_TYPE_MASK) == type &&
   410 		     ppi->present[p - ppi->start] == 0;
   411 	     p++) {
   412 		if (!provider_satisfies_requirement(p, ppi->pool,
   413 						    flags, version))
   414 			continue;
   415 
   416 		i = list_first(&p->packages, &set->package_pool);
   417 
   418 		return &pkgs[i->data];
   419 	}
   420 
   421 	return NULL;
   422 }
   423 
   424 static void
   425 remove_obsoleted_packages(struct razor_transaction *trans)
   426 {
   427 	struct razor_property *up;
   428 	struct razor_package *spkgs;
   429 	struct prop_iter spi, upi;
   430 
   431 	spkgs = trans->system.set->packages.data;
   432 	prop_iter_init(&spi, &trans->system);
   433 	prop_iter_init(&upi, &trans->upstream);
   434 
   435 	while (prop_iter_next(&upi, RAZOR_PROPERTY_OBSOLETES, &up)) {
   436 		if (!prop_iter_seek_to(&spi, RAZOR_PROPERTY_PROVIDES,
   437 				       &upi.pool[up->name]))
   438 			continue;
   439 		remove_matching_providers(trans, &spi, up->flags,
   440 					  &upi.pool[up->version]);
   441 	}
   442 }
   443 
   444 static int
   445 any_provider_satisfies_requirement(struct prop_iter *ppi,
   446 				   uint32_t flags,
   447 				   const char *version)
   448 {
   449 	struct razor_property *p;
   450 	uint32_t type;
   451 
   452 	type = ppi->p->flags & RAZOR_PROPERTY_TYPE_MASK;
   453 	for (p = ppi->p;
   454 	     p < ppi->end &&
   455 		     p->name == ppi->p->name &&
   456 		     (p->flags & RAZOR_PROPERTY_TYPE_MASK) == type;
   457 	     p++) {
   458 		if (ppi->present[p - ppi->start] > 0 &&
   459 		    provider_satisfies_requirement(p, ppi->pool,
   460 						   flags, version))
   461 			return 1;
   462 	}
   463 
   464 	return 0;
   465 }
   466 
   467 static void
   468 clear_requires_flags(struct transaction_set *ts)
   469 {
   470 	struct razor_property *p;
   471 	const char *pool;
   472 	int i, count;
   473 	char *sub;
   474 
   475 	count = ts->set->properties.size / sizeof *p;
   476 	p = ts->set->properties.data;
   477 	pool = ts->set->string_pool.data;
   478 	for (i = 0; i < count; i++) {
   479 		ts->properties[i] &= ~TRANS_PROPERTY_SATISFIED;
   480 		sub = strchr(&pool[p[i].name], '(');
   481 		if (sub && sub[strlen(sub) - 1] == ')') {
   482 			sub = strdup(sub + 1);
   483 			sub[strlen(sub) - 1] = '\0';
   484 			if (strncmp(&pool[p[i].name], "rpmlib(", 7) == 0)
   485 				ts->properties[i] |= TRANS_PROPERTY_SATISFIED;
   486 			if (strncmp(&pool[p[i].name], "lua(", 4) == 0 &&
   487 			    razor_get_lua_loader(sub) &&
   488 			    p[i].flags & RAZOR_PROPERTY_SCRIPT_MASK)
   489 				ts->properties[i] |= TRANS_PROPERTY_SATISFIED;
   490 			free(sub);
   491 		}
   492 	}
   493 }
   494 
   495 static void
   496 mark_satisfied_requires(struct razor_transaction *trans,
   497 			struct transaction_set *rts,
   498 			struct transaction_set *pts)
   499 {
   500 	struct prop_iter rpi, ppi;
   501 	struct razor_property *rp;
   502 
   503 	prop_iter_init(&rpi, rts);
   504 	prop_iter_init(&ppi, pts);
   505 
   506 	while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) {
   507 		if (!prop_iter_seek_to(&ppi, RAZOR_PROPERTY_PROVIDES,
   508 				       &rpi.pool[rp->name]))
   509 			continue;
   510 
   511 		if (any_provider_satisfies_requirement(&ppi, rp->flags,
   512 						       &rpi.pool[rp->version]))
   513 			rpi.present[rp - rpi.start] |= TRANS_PROPERTY_SATISFIED;
   514 	}
   515 }
   516 
   517 static void
   518 mark_all_satisfied_requires(struct razor_transaction *trans)
   519 {
   520 	clear_requires_flags(&trans->system);
   521 	clear_requires_flags(&trans->upstream);
   522 	mark_satisfied_requires(trans, &trans->system, &trans->system);
   523 	mark_satisfied_requires(trans, &trans->system, &trans->upstream);
   524 	mark_satisfied_requires(trans, &trans->upstream, &trans->system);
   525 	mark_satisfied_requires(trans, &trans->upstream, &trans->upstream);
   526 }
   527 
   528 static void
   529 update_unsatisfied_packages(struct razor_transaction *trans)
   530 {
   531 	struct razor_package *spkgs, *pkg;
   532 	struct razor_property *sp;
   533 	struct prop_iter spi;
   534 	struct razor_package_iterator pkg_iter;
   535 	const char *name;
   536 
   537 	spkgs = trans->system.set->packages.data;
   538 	prop_iter_init(&spi, &trans->system);
   539 
   540 	while (prop_iter_next(&spi, RAZOR_PROPERTY_REQUIRES, &sp)) {
   541 		if (spi.present[sp - spi.start] & TRANS_PROPERTY_SATISFIED)
   542 			continue;
   543 
   544 		razor_package_iterator_init_for_property(&pkg_iter,
   545 							 trans->system.set,
   546 							 sp);
   547 		while (razor_package_iterator_next(&pkg_iter, &pkg,
   548 						   RAZOR_DETAIL_NAME, &name,
   549 						   RAZOR_DETAIL_LAST)) {
   550 			if (!(trans->system.packages[pkg - spkgs] & TRANS_PACKAGE_PRESENT))
   551 				continue;
   552 
   553 #if 0
   554 			fprintf(stderr, "updating %s because %s %s %s "
   555 				"isn't satisfied\n",
   556 				name, spi.pool + sp->name,
   557 				razor_property_relation_to_string(sp),
   558 				spi.pool + sp->version);
   559 #endif
   560 			trans->system.packages[pkg - spkgs] |=
   561 				TRANS_PACKAGE_UPDATE;
   562 		}
   563 	}
   564 }
   565 
   566 RAZOR_EXPORT void
   567 razor_transaction_update_all(struct razor_transaction *trans)
   568 {
   569 	struct razor_package *p;
   570 	int i, count;
   571 
   572 	assert (trans != NULL);
   573 
   574 	count = trans->system.set->packages.size / sizeof *p;
   575 	for (i = 0; i < count; i++)
   576 		trans->system.packages[i] |= TRANS_PACKAGE_UPDATE;
   577 }
   578 
   579 static void
   580 update_conflicted_packages(struct razor_transaction *trans)
   581 {
   582 	struct razor_package *pkg, *spkgs;
   583 	struct razor_property *up, *sp;
   584 	struct prop_iter spi, upi;
   585 	struct razor_package_iterator pkg_iter;
   586 	const char *name, *version;
   587 
   588 	spkgs = trans->system.set->packages.data;
   589 	prop_iter_init(&spi, &trans->system);
   590 	prop_iter_init(&upi, &trans->upstream);
   591 
   592 	while (prop_iter_next(&spi, RAZOR_PROPERTY_CONFLICTS, &sp)) {
   593 		if (!prop_iter_seek_to(&upi, RAZOR_PROPERTY_PROVIDES,
   594 				       &spi.pool[sp->name]))
   595 			continue;
   596 
   597 		if (!any_provider_satisfies_requirement(&upi, sp->flags,
   598 							&spi.pool[sp->version]))
   599 			continue;
   600 
   601 		razor_package_iterator_init_for_property(&pkg_iter,
   602 							 trans->system.set,
   603 							 sp);
   604 		while (razor_package_iterator_next(&pkg_iter, &pkg,
   605 						   RAZOR_DETAIL_NAME, &name,
   606 						   RAZOR_DETAIL_VERSION, &version,
   607 						   RAZOR_DETAIL_LAST)) {
   608 #if 0
   609 			fprintf(stderr, "updating %s %s because it "
   610 				"conflicts with %s\n",
   611 				name, version, spi.pool + sp->name);
   612 #endif
   613 			trans->system.packages[pkg - spkgs] |=
   614 				TRANS_PACKAGE_UPDATE;
   615 		}
   616 	}
   617 
   618 	prop_iter_init(&spi, &trans->system);
   619 	prop_iter_init(&upi, &trans->upstream);
   620 
   621 	while (prop_iter_next(&upi, RAZOR_PROPERTY_CONFLICTS, &up)) {
   622 		sp = prop_iter_seek_to(&spi, RAZOR_PROPERTY_PROVIDES,
   623 				       &upi.pool[upi.p->name]);
   624 
   625 		if (sp)
   626 			flag_matching_providers(trans, &spi, up, &upi,
   627 						TRANS_PACKAGE_UPDATE);
   628 	}
   629 }
   630 
   631 static void
   632 pull_in_requirements(struct razor_transaction *trans,
   633 		     struct prop_iter *rpi, struct prop_iter *ppi)
   634 {
   635 	struct razor_property *rp, *pp;
   636 	struct razor_package *pkg, *upkgs;
   637 
   638 	upkgs = trans->upstream.set->packages.data;
   639 	while (prop_iter_next(rpi, RAZOR_PROPERTY_REQUIRES, &rp)) {
   640 		if (rpi->present[rp - rpi->start] & TRANS_PROPERTY_SATISFIED)
   641 			continue;
   642 
   643 		pp = prop_iter_seek_to(ppi, RAZOR_PROPERTY_PROVIDES,
   644 				       &rpi->pool[rp->name]);
   645 		if (pp == NULL)
   646 			continue;
   647 		pkg = pick_matching_provider(trans->upstream.set,
   648 					     ppi, rp->flags,
   649 					     &rpi->pool[rp->version]);
   650 		if (pkg == NULL)
   651 			continue;
   652 
   653 		rpi->present[rp - rpi->start] |= TRANS_PROPERTY_SATISFIED;
   654 
   655 #if 0
   656 		fprintf(stderr, "pulling in %s-%s.%s which provides %s %s %s "
   657 			"to satisfy %s %s %s\n",
   658 			ppi->pool + pkg->name,
   659 			ppi->pool + pkg->version,
   660 			ppi->pool + pkg->arch,
   661 			ppi->pool + pp->name,
   662 			razor_property_relation_to_string(pp),
   663 			ppi->pool + pp->version,
   664 			&rpi->pool[rp->name],
   665 			razor_property_relation_to_string(rp),
   666 			&rpi->pool[rp->version]);
   667 #endif
   668 
   669 		trans->upstream.packages[pkg - upkgs] |= TRANS_PACKAGE_UPDATE;
   670 	}
   671 }
   672 
   673 static void
   674 pull_in_all_requirements(struct razor_transaction *trans)
   675 {
   676 	struct prop_iter rpi, ppi;
   677 
   678 	prop_iter_init(&rpi, &trans->system);
   679 	prop_iter_init(&ppi, &trans->upstream);
   680 	pull_in_requirements(trans, &rpi, &ppi);
   681 
   682 	prop_iter_init(&rpi, &trans->upstream);
   683 	prop_iter_init(&ppi, &trans->upstream);
   684 	pull_in_requirements(trans, &rpi, &ppi);
   685 }
   686 
   687 static void
   688 flush_scheduled_system_updates(struct razor_transaction *trans)
   689 {
   690  	struct razor_package_iterator *pi;
   691  	struct razor_package *p, *pkg, *spkgs;
   692 	struct prop_iter ppi;
   693 	const char *name, *version;
   694 
   695 	spkgs = trans->system.set->packages.data;
   696 	pi = razor_package_iterator_create(trans->system.set);
   697 	prop_iter_init(&ppi, &trans->upstream);
   698 
   699 	while (razor_package_iterator_next(pi, &p,
   700 					   RAZOR_DETAIL_NAME, &name,
   701 					   RAZOR_DETAIL_VERSION, &version,
   702 					   RAZOR_DETAIL_LAST)) {
   703 		if (!(trans->system.packages[p - spkgs] & TRANS_PACKAGE_UPDATE))
   704 			continue;
   705 		trans->system.packages[p - spkgs] &= ~TRANS_PACKAGE_UPDATE;
   706 
   707 		if (!prop_iter_seek_to(&ppi, RAZOR_PROPERTY_PROVIDES, name))
   708 			continue;
   709 
   710 		if (any_provider_satisfies_requirement(&ppi,
   711 						       RAZOR_PROPERTY_GREATER,
   712 						       version)) {
   713 			razor_transaction_remove_package(trans, p);
   714 			continue;
   715 		}
   716 
   717 		pkg = pick_matching_provider(trans->upstream.set, &ppi,
   718 					     RAZOR_PROPERTY_GREATER, version);
   719 		if (pkg == NULL)
   720 			continue;
   721 
   722 		razor_transaction_remove_package(trans, p);
   723 		razor_transaction_install_package(trans, pkg);
   724 	}
   725 
   726 	razor_package_iterator_destroy(pi);
   727 }
   728 
   729 static void
   730 flush_scheduled_upstream_updates(struct razor_transaction *trans)
   731 {
   732  	struct razor_package_iterator *pi;
   733  	struct razor_package *p, *upkgs;
   734 	struct prop_iter spi;
   735 	const char *name, *version;
   736 
   737 	upkgs = trans->upstream.set->packages.data;
   738 	pi = razor_package_iterator_create(trans->upstream.set);
   739 	prop_iter_init(&spi, &trans->system);
   740 
   741 	while (razor_package_iterator_next(pi, &p,
   742 					   RAZOR_DETAIL_NAME, &name,
   743 					   RAZOR_DETAIL_VERSION, &version,
   744 					   RAZOR_DETAIL_LAST)) {
   745 		if (!(trans->upstream.packages[p - upkgs] & TRANS_PACKAGE_UPDATE))
   746 			continue;
   747 		trans->upstream.packages[p - upkgs] &= ~TRANS_PACKAGE_UPDATE;
   748 
   749 		if (prop_iter_seek_to(&spi, RAZOR_PROPERTY_PROVIDES, name))
   750 			remove_matching_providers(trans,
   751 						  &spi,
   752 						  RAZOR_PROPERTY_LESS,
   753 						  version);
   754 		razor_transaction_install_package(trans, p);
   755 #if 0
   756 		fprintf(stderr, "installing %s-%s\n", name, version);
   757 #endif
   758 	}
   759 }
   760 
   761 RAZOR_EXPORT int
   762 razor_transaction_resolve(struct razor_transaction *trans)
   763 {
   764 	int last = 0;
   765 
   766 	flush_scheduled_system_updates(trans);
   767 	flush_scheduled_upstream_updates(trans);
   768 
   769 	while (last < trans->changes) {
   770 		last = trans->changes;
   771 		remove_obsoleted_packages(trans);
   772 		mark_all_satisfied_requires(trans);
   773 		update_unsatisfied_packages(trans);
   774 		update_conflicted_packages(trans);
   775 		pull_in_all_requirements(trans);
   776 		flush_scheduled_system_updates(trans);
   777 		flush_scheduled_upstream_updates(trans);
   778 	}
   779 
   780 	return trans->changes;
   781 }
   782 
   783 static void
   784 describe_unsatisfied(struct razor_set *set, struct razor_property *rp)
   785 {
   786 	struct razor_package_iterator pi;
   787 	struct razor_package *pkg;
   788 	const char *name, *version, *arch, *pool;
   789 
   790 	pool = set->string_pool.data;
   791 	if (pool[rp->version] == '\0') {
   792 		razor_package_iterator_init_for_property(&pi, set, rp);
   793 		while (razor_package_iterator_next(&pi, &pkg,
   794 						   RAZOR_DETAIL_NAME, &name,
   795 						   RAZOR_DETAIL_VERSION, &version,
   796 						   RAZOR_DETAIL_ARCH, &arch,
   797 						   RAZOR_DETAIL_LAST))
   798 			fprintf(stderr, "%s is needed by %s-%s.%s\n",
   799 				&pool[rp->name],
   800 				name, version, arch);
   801 	} else {
   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 			fprintf(stderr, "%s %s %s is needed by %s-%s.%s\n",
   809 				&pool[rp->name],
   810 				razor_property_relation_to_string(rp),
   811 				&pool[rp->version],
   812 				name, version, arch);
   813 	}
   814 }
   815 
   816 RAZOR_EXPORT int
   817 razor_transaction_describe(struct razor_transaction *trans)
   818 {
   819 	struct prop_iter rpi;
   820 	struct razor_property *rp;
   821 	int unsatisfied;
   822 
   823 	flush_scheduled_system_updates(trans);
   824 	flush_scheduled_upstream_updates(trans);
   825 	mark_all_satisfied_requires(trans);
   826 
   827 	unsatisfied = 0;
   828 	prop_iter_init(&rpi, &trans->system);
   829 	while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) {
   830 		if (!(rpi.present[rp - rpi.start] & TRANS_PROPERTY_SATISFIED)) {
   831 			describe_unsatisfied(trans->system.set, rp);
   832 		        unsatisfied++;
   833 		}
   834 	}
   835 
   836 	prop_iter_init(&rpi, &trans->upstream);
   837 	while (prop_iter_next(&rpi, RAZOR_PROPERTY_REQUIRES, &rp)) {
   838 		if (!(rpi.present[rp - rpi.start] & TRANS_PROPERTY_SATISFIED)) {
   839 			describe_unsatisfied(trans->upstream.set, rp);
   840 			unsatisfied++;
   841 		}
   842 	}
   843 
   844 	return unsatisfied;
   845 }
   846 
   847 RAZOR_EXPORT int
   848 razor_transaction_unsatisfied_property(struct razor_transaction *trans,
   849 				       const char *name,
   850 				       uint32_t flags,
   851 				       const char *version)
   852 {
   853 	struct prop_iter pi;
   854 	struct razor_property *p;
   855 
   856 	prop_iter_init(&pi, &trans->system);
   857 	while (prop_iter_next(&pi, flags & RAZOR_PROPERTY_TYPE_MASK, &p)) {
   858 		if (!(trans->system.properties[p - pi.start] & TRANS_PROPERTY_SATISFIED) &&
   859 		    p->flags == flags &&
   860 		    strcmp(&pi.pool[p->name], name) == 0 &&
   861 		    strcmp(&pi.pool[p->version], version) == 0)
   862 
   863 			return 1;
   864 	}
   865 
   866 	prop_iter_init(&pi, &trans->upstream);
   867 	while (prop_iter_next(&pi, flags & RAZOR_PROPERTY_TYPE_MASK, &p)) {
   868 		if (!(trans->upstream.properties[p - pi.start] & TRANS_PROPERTY_SATISFIED) &&
   869 		    p->flags == flags &&
   870 		    strcmp(&pi.pool[p->name], name) == 0 &&
   871 		    strcmp(&pi.pool[p->version], version) == 0)
   872 
   873 			return 1;
   874 	}
   875 
   876 	return 0;
   877 }
   878 
   879 RAZOR_EXPORT struct razor_set *
   880 razor_transaction_commit(struct razor_transaction *trans)
   881 {
   882 	struct razor_package *u, *uend, *upkgs, *s, *send, *spkgs;
   883 	char *upool, *spool;
   884 	int cmp;
   885 
   886 	s = trans->system.set->packages.data;
   887 	spkgs = trans->system.set->packages.data;
   888 	send = trans->system.set->packages.data +
   889 		trans->system.set->packages.size;
   890 	spool = trans->system.set->string_pool.data;
   891 
   892 	u = trans->upstream.set->packages.data;
   893 	upkgs = trans->upstream.set->packages.data;
   894 	uend = trans->upstream.set->packages.data +
   895 		trans->upstream.set->packages.size;
   896 	upool = trans->upstream.set->string_pool.data;
   897 
   898 	trans->merger = razor_merger_create(trans->system.set,
   899 					    trans->upstream.set);
   900 	while (s < send || u < uend) {
   901 		if (s < send && u < uend)
   902 			cmp = strcmp(&spool[s->name], &upool[u->name]);
   903 		else if (s < send)
   904 			cmp = -1;
   905 		else
   906 			cmp = 1;
   907 
   908 		if (cmp < 0) {
   909 			if (trans->system.packages[s - spkgs] & TRANS_PACKAGE_PRESENT)
   910 				razor_merger_add_package(trans->merger, s);
   911 			s++;
   912 		} else if (cmp == 0) {
   913 			if (trans->system.packages[s - spkgs] & TRANS_PACKAGE_PRESENT)
   914 				razor_merger_add_package(trans->merger, s);
   915 			if (trans->upstream.packages[u - upkgs] & TRANS_PACKAGE_PRESENT)
   916 				razor_merger_add_package(trans->merger, u);
   917 
   918 			s++;
   919 			u++;
   920 		} else {
   921 			if (trans->upstream.packages[u - upkgs] & TRANS_PACKAGE_PRESENT)
   922 				razor_merger_add_package(trans->merger, u);
   923 			u++;
   924 		}
   925 	}
   926 
   927 	return razor_merger_commit(trans->merger);
   928 }
   929 
   930 RAZOR_EXPORT void
   931 razor_transaction_fixup_package(struct razor_transaction *trans,
   932 				struct razor_package *package,
   933 				struct razor_rpm *rpm)
   934 {
   935 	const char *preunprog, *preun, *postunprog, *postun;
   936 
   937 	razor_rpm_get_details(rpm,
   938 			      RAZOR_DETAIL_PREUNPROG, &preunprog,
   939 			      RAZOR_DETAIL_PREUN, &preun,
   940 			      RAZOR_DETAIL_POSTUNPROG, &postunprog,
   941 			      RAZOR_DETAIL_POSTUN, &postun,
   942 			      RAZOR_DETAIL_LAST);
   943 
   944 	razor_merger_package_add_script(trans->merger, package,
   945 					RAZOR_PROPERTY_PREUN,
   946 					preunprog, preun);
   947 	razor_merger_package_add_script(trans->merger, package,
   948 					RAZOR_PROPERTY_POSTUN,
   949 					postunprog, postun);
   950 }
   951 
   952 RAZOR_EXPORT void
   953 razor_transaction_destroy(struct razor_transaction *trans)
   954 {
   955 	assert (trans != NULL);
   956 
   957 	if (trans->merger)
   958 		razor_merger_destroy(trans->merger);
   959 	transaction_set_release(&trans->system);
   960 	transaction_set_release(&trans->upstream);
   961 	free(trans);
   962 }