librazor/transaction.c
author J. Ali Harlow <ali@juiblex.co.uk>
Sat Oct 04 18:12:58 2014 +0100 (2014-10-04)
changeset 454 56ff755c268c
parent 442 c4bcba8023a9
child 458 3f841a46eab5
permissions -rw-r--r--
Only export symbols starting with razor_ in dynamic library.

Apart from being good practice to avoid clashes with higher-level
libraries and the application, this also fixes an obscure bug: The
gnulib library is used both by librazor (the dynamic library) and
by razor (the executable). In doing so, we want to have two separate
copies of the library despite the code duplication this involves.
Without the explicit limit to export only razor_ symbols, the razor
executable under mingw64 was picking up the getopt_long function
from librazor and the optind variable from libgnu which meant that
it did not see optind changing. Hiding librazor's copy of getopt
causes the linker to find libgnu's copy and everything works.

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