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