librazor/transaction.c
author Kristian H?gsberg <krh@redhat.com>
Fri Jun 20 21:56:43 2008 -0400 (2008-06-20)
changeset 254 ccb1c11968ab
child 257 0c3db660514d
permissions -rw-r--r--
Introduce install/remove iterators.

These iterator constructors lets you pass in two sets and creates
an iterator for the packages to remove or the packages to install.
The iterators will step through the packages in a sequence that respects
the pre, post, preun and postun modifiers.

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