librazor/razor.c
author J. Ali Harlow <ali@juiblex.co.uk>
Thu Feb 09 20:45:27 2012 +0000 (2012-02-09)
changeset 418 33b825d3128d
parent 411 b1dcf22c0418
child 422 6fa783097ca1
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.
rhughes@241
     1
/*
rhughes@241
     2
 * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
rhughes@241
     3
 * Copyright (C) 2008  Red Hat, Inc
ali@418
     4
 * Copyright (C) 2009-2012  J. Ali Harlow <ali@juiblex.co.uk>
rhughes@241
     5
 *
rhughes@241
     6
 * This program is free software; you can redistribute it and/or modify
rhughes@241
     7
 * it under the terms of the GNU General Public License as published by
rhughes@241
     8
 * the Free Software Foundation; either version 2 of the License, or
rhughes@241
     9
 * (at your option) any later version.
rhughes@241
    10
 *
rhughes@241
    11
 * This program is distributed in the hope that it will be useful,
rhughes@241
    12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
rhughes@241
    13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
rhughes@241
    14
 * GNU General Public License for more details.
rhughes@241
    15
 *
rhughes@241
    16
 * You should have received a copy of the GNU General Public License along
rhughes@241
    17
 * with this program; if not, write to the Free Software Foundation, Inc.,
rhughes@241
    18
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
rhughes@241
    19
 */
rhughes@241
    20
rhughes@241
    21
#define _GNU_SOURCE
rhughes@241
    22
ali@334
    23
#include "config.h"
ali@334
    24
rhughes@241
    25
#include <stdlib.h>
rhughes@241
    26
#include <stddef.h>
rhughes@241
    27
#include <stdint.h>
rhughes@241
    28
#include <stdio.h>
richard@302
    29
#include <stdarg.h>
rhughes@241
    30
#include <string.h>
rhughes@241
    31
#include <sys/types.h>
rhughes@241
    32
#include <sys/stat.h>
rhughes@241
    33
#include <unistd.h>
rhughes@241
    34
#include <fcntl.h>
rhughes@241
    35
#include <errno.h>
rhughes@241
    36
#include <ctype.h>
rhughes@241
    37
#include <fnmatch.h>
ali@369
    38
#include <limits.h>
richard@301
    39
#include <assert.h>
ali@388
    40
#ifdef MSWIN_API
ali@388
    41
#include <windows.h>
ali@388
    42
#endif
rhughes@241
    43
krh@253
    44
#include "razor-internal.h"
rhughes@241
    45
#include "razor.h"
rhughes@241
    46
ali@345
    47
#ifndef O_BINARY
ali@345
    48
#define O_BINARY	0
ali@345
    49
#endif
ali@345
    50
krh@248
    51
void *
rhughes@241
    52
zalloc(size_t size)
rhughes@241
    53
{
rhughes@241
    54
	void *p;
rhughes@241
    55
rhughes@241
    56
	p = malloc(size);
rhughes@241
    57
	memset(p, 0, size);
rhughes@241
    58
rhughes@241
    59
	return p;
rhughes@241
    60
}
rhughes@241
    61
jbowes@318
    62
struct razor_set_section_index {
jbowes@318
    63
	const char *name;
jbowes@318
    64
	uint32_t offset;
krh@373
    65
	uint32_t flags;
jbowes@318
    66
};
jbowes@318
    67
krh@373
    68
#define MAIN(type, field) \
krh@373
    69
	{ type, offsetof(struct razor_set, field), RAZOR_SECTION_MAIN }
krh@373
    70
#define FILES(type, field) \
krh@373
    71
	{ type, offsetof(struct razor_set, field), RAZOR_SECTION_FILES }
krh@373
    72
#define DETAILS(type, field) \
krh@373
    73
	{ type, offsetof(struct razor_set, field), RAZOR_SECTION_DETAILS }
krh@373
    74
jbowes@318
    75
struct razor_set_section_index razor_sections[] = {
krh@373
    76
	MAIN(RAZOR_STRING_POOL, string_pool),
krh@373
    77
	MAIN(RAZOR_PACKAGES, packages),
krh@373
    78
	MAIN(RAZOR_PROPERTIES, properties),
krh@373
    79
	MAIN(RAZOR_PACKAGE_POOL, package_pool),
krh@373
    80
	MAIN(RAZOR_PROPERTY_POOL, property_pool),
krh@373
    81
	MAIN(RAZOR_PREFIX_POOL, prefix_pool),
krh@373
    82
	FILES(RAZOR_FILES, files),
krh@373
    83
	FILES(RAZOR_FILE_POOL, file_pool),
krh@373
    84
	FILES(RAZOR_FILE_STRING_POOL, file_string_pool),
krh@373
    85
	DETAILS(RAZOR_DETAILS_STRING_POOL, details_string_pool)
jbowes@258
    86
};
krh@262
    87
krh@269
    88
RAZOR_EXPORT struct razor_set *
ali@363
    89
razor_set_create_without_root(void)
ali@363
    90
{
ali@363
    91
	struct razor_set *set;
ali@363
    92
	char *empty;
ali@363
    93
ali@363
    94
	set = zalloc(sizeof *set);
ali@363
    95
ali@403
    96
	if (set) {
ali@403
    97
		empty = array_add(&set->string_pool, 1);
ali@403
    98
		*empty = '\0';
ali@363
    99
ali@403
   100
		set->lock_fd = -1;
ali@403
   101
ali@403
   102
		set->ref_count = 1;
ali@403
   103
ali@403
   104
		set->header_version = RAZOR_HEADER_VERSION;
ali@403
   105
	}
ali@388
   106
ali@363
   107
	return set;
ali@363
   108
}
ali@363
   109
ali@363
   110
RAZOR_EXPORT struct razor_set *
rhughes@241
   111
razor_set_create(void)
rhughes@241
   112
{
rhughes@241
   113
	struct razor_set *set;
rhughes@241
   114
	struct razor_entry *e;
rhughes@241
   115
ali@363
   116
	set = razor_set_create_without_root();
rhughes@241
   117
rhughes@241
   118
	e = array_add(&set->files, sizeof *e);
rhughes@241
   119
	e->name = 0;
rhughes@241
   120
	e->flags = RAZOR_ENTRY_LAST;
rhughes@241
   121
	e->start = 0;
rhughes@241
   122
	list_set_empty(&e->packages);
rhughes@241
   123
rhughes@241
   124
	return set;
rhughes@241
   125
}
rhughes@241
   126
ali@403
   127
RAZOR_EXPORT uint32_t
ali@403
   128
razor_set_get_header_version(struct razor_set *set)
ali@403
   129
{
ali@403
   130
	return set->header_version;
ali@403
   131
}
ali@403
   132
ali@403
   133
RAZOR_EXPORT int
ali@403
   134
razor_set_set_header_version(struct razor_set *set, uint32_t header_version)
ali@403
   135
{
ali@403
   136
	if (header_version<RAZOR_HEADER_VERSION_MIN ||
ali@403
   137
	    header_version>RAZOR_HEADER_VERSION)
ali@403
   138
		return -1;
ali@403
   139
	else {
ali@403
   140
		set->header_version = header_version;
ali@403
   141
		return 0;
ali@403
   142
	}
ali@403
   143
}
ali@403
   144
krh@373
   145
struct razor_mapped_file {
krh@373
   146
	struct razor_set_header *header;
krh@373
   147
	size_t size;
krh@373
   148
	struct razor_mapped_file *next;
krh@373
   149
};
krh@373
   150
krh@373
   151
RAZOR_EXPORT int
ali@403
   152
razor_set_bind_sections(struct razor_set *set, struct razor_atomic *atomic,
ali@403
   153
			const char *filename)
rhughes@241
   154
{
jbowes@318
   155
	struct razor_set_section *s, *sections;
krh@373
   156
	struct razor_mapped_file *file;
ali@403
   157
	const char *pool, *reason;
ali@403
   158
	char *msg;
rhughes@241
   159
	struct array *array;
krh@373
   160
	int i, j;
richard@301
   161
krh@373
   162
	file = zalloc(sizeof *file);
ali@403
   163
	if (file == NULL) {
ali@403
   164
		razor_atomic_abort(atomic, "Not enough memory");
jbowes@288
   165
		return -1;
ali@403
   166
	}
jbowes@258
   167
krh@373
   168
	file->header = razor_file_get_contents(filename, &file->size);
krh@373
   169
	if (!file->header) {
ali@403
   170
		msg = razor_concat(filename, ": ", strerror(errno), NULL);
ali@403
   171
		razor_atomic_abort(atomic, msg);
ali@403
   172
		free(msg);
krh@373
   173
		free(file);
krh@373
   174
		return -1;
krh@373
   175
	}
jbowes@318
   176
ali@403
   177
	if (file->size < sizeof *file->header)
ali@403
   178
		reason = "Premature EOF";
ali@403
   179
	else if (file->header->magic != RAZOR_MAGIC)
ali@403
   180
		reason = "Bad magic number";
ali@403
   181
	else if (file->header->version < RAZOR_HEADER_VERSION_MIN ||
ali@403
   182
		 file->header->version > RAZOR_HEADER_VERSION)
ali@403
   183
		reason = "Incompatible file version";
ali@403
   184
	else
ali@403
   185
		reason = NULL;
ali@403
   186
ali@403
   187
	if (reason) {
ali@403
   188
		msg = razor_concat(filename, ": ", reason, NULL);
ali@403
   189
		razor_atomic_abort(atomic, msg);
ali@403
   190
		free(msg);
ali@390
   191
		razor_file_free_contents(file->header, file->size);
ali@390
   192
		free(file);
ali@390
   193
		return -1;
ali@390
   194
	}
ali@390
   195
ali@403
   196
	set->header_version = file->header->version;
ali@403
   197
ali@388
   198
	if (set->mapped_files == NULL) {
ali@388
   199
		for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
ali@388
   200
			array = (void *) set + razor_sections[i].offset;
ali@388
   201
			array_release(array);
ali@388
   202
		}
ali@388
   203
	}
ali@388
   204
krh@373
   205
	file->next = set->mapped_files;
krh@373
   206
	set->mapped_files = file;
krh@373
   207
krh@373
   208
	sections = (void *) file->header + sizeof *file->header;
krh@373
   209
	pool = (void *) sections +
krh@373
   210
		file->header->num_sections * sizeof *sections;
krh@373
   211
krh@373
   212
	for (i = 0; i < file->header->num_sections; i++) {
jbowes@318
   213
		s = sections + i;
krh@373
   214
		for (j = 0; j < ARRAY_SIZE(razor_sections); j++)
krh@373
   215
			if (!strcmp(razor_sections[j].name, &pool[s->name]))
jbowes@318
   216
				break;
krh@373
   217
		if (j == ARRAY_SIZE(razor_sections))
jbowes@258
   218
			continue;
krh@373
   219
		array = (void *) set + razor_sections[j].offset;
krh@373
   220
		array->data = (void *) file->header + s->offset;
jbowes@258
   221
		array->size = s->size;
jbowes@258
   222
		array->alloc = s->size;
jbowes@258
   223
	}
jbowes@288
   224
jbowes@288
   225
	return 0;
jbowes@258
   226
}
jbowes@258
   227
jbowes@318
   228
RAZOR_EXPORT struct razor_set *
ali@403
   229
razor_set_open(const char *filename, struct razor_atomic *atomic)
jbowes@318
   230
{
jbowes@318
   231
	struct razor_set *set;
jbowes@318
   232
jbowes@318
   233
	set = zalloc(sizeof *set);
ali@403
   234
	if (!set) {
ali@403
   235
		razor_atomic_abort(atomic, "Not enough memory");
ali@403
   236
		return NULL;
ali@403
   237
	}
ali@403
   238
ali@388
   239
	set->lock_fd = -1;
ali@406
   240
	set->ref_count = 1;
ali@403
   241
	if (razor_set_bind_sections(set, atomic, filename)) {
jbowes@318
   242
		free(set);
jbowes@318
   243
		return NULL;
jbowes@318
   244
	}
jbowes@318
   245
	return set;
jbowes@318
   246
}
jbowes@318
   247
ali@388
   248
int
ali@388
   249
razor_set_aquire_lock(struct razor_set *set, const char *path, int exclusive)
ali@388
   250
{
ali@388
   251
	int fd;
ali@388
   252
	assert(set != NULL);
ali@388
   253
ali@388
   254
	if (path) {
ali@388
   255
		fd = open(path, O_CREAT | O_RDWR | O_TRUNC | O_BINARY, 0666);
ali@388
   256
		if (fd < 0)
ali@388
   257
			return -1;
ali@388
   258
	} else {
ali@388
   259
		fd = -1;
ali@388
   260
	}
ali@388
   261
ali@388
   262
#ifdef MSWIN_API
ali@388
   263
	DWORD flags = LOCKFILE_FAIL_IMMEDIATELY;
ali@388
   264
	OVERLAPPED lock = {0};
ali@388
   265
ali@388
   266
	if (exclusive)
ali@388
   267
		flags |= LOCKFILE_EXCLUSIVE_LOCK;
ali@403
   268
	if (fd >= 0 && !LockFileEx((HANDLE)_get_osfhandle(fd), flags, 0, 1, 0,
ali@403
   269
				   &lock)) {
ali@388
   270
		close(fd);
ali@388
   271
		return -1;
ali@388
   272
	}
ali@388
   273
	if (set->lock_fd >= 0)
ali@403
   274
		(void)UnlockFile((HANDLE)_get_osfhandle(set->lock_fd), 0, 0, 1,
ali@403
   275
				 0);
ali@388
   276
#else
ali@388
   277
	struct flock lock = {0};
ali@388
   278
ali@388
   279
	lock.l_type = exclusive ? F_WRLCK : F_RDLCK;
ali@388
   280
	lock.l_whence = SEEK_SET;
ali@388
   281
	lock.l_start = 0;
ali@388
   282
	lock.l_len = 0;
ali@388
   283
	if (fd >= 0 && fcntl(fd, F_SETLK, &lock) < 0) {
ali@388
   284
		close(fd);
ali@388
   285
		return -1;
ali@388
   286
	}
ali@388
   287
	if (set->lock_fd >= 0) {
ali@388
   288
		lock.l_type = F_UNLCK;
ali@388
   289
		(void)fcntl(set->lock_fd, F_SETLK, &lock);
ali@388
   290
	}
ali@388
   291
#endif
ali@388
   292
ali@388
   293
	if (set->lock_fd >= 0)
ali@388
   294
		close(set->lock_fd);
ali@388
   295
	set->lock_fd = fd;
ali@388
   296
ali@388
   297
	return 0;
ali@388
   298
}
ali@388
   299
ali@403
   300
static void
rhughes@241
   301
razor_set_destroy(struct razor_set *set)
rhughes@241
   302
{
krh@373
   303
	struct razor_mapped_file *file, *next;
krh@373
   304
	struct array *array;
rhughes@241
   305
	int i;
rhughes@241
   306
richard@301
   307
	assert (set != NULL);
richard@301
   308
krh@373
   309
	if (set->mapped_files == NULL) {
krh@373
   310
		for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
krh@373
   311
			array = (void *) set + razor_sections[i].offset;
krh@373
   312
			array_release(array);
krh@373
   313
		}
rhughes@241
   314
	} else {
krh@373
   315
		for (file = set->mapped_files; file != NULL; file = next) {
krh@373
   316
			next = file->next;
krh@373
   317
			razor_file_free_contents(file->header, file->size);
krh@373
   318
			free(file);
jbowes@258
   319
		}
jbowes@258
   320
	}
jbowes@258
   321
ali@388
   322
	razor_set_aquire_lock(set, NULL, 0);
rhughes@241
   323
	free(set);
rhughes@241
   324
}
rhughes@241
   325
ali@403
   326
RAZOR_EXPORT void
ali@403
   327
razor_set_unref(struct razor_set *set)
ali@403
   328
{
ali@403
   329
	if (set && !--set->ref_count)
ali@403
   330
		razor_set_destroy(set);
ali@403
   331
}
ali@403
   332
ali@403
   333
RAZOR_EXPORT struct razor_set *
ali@403
   334
razor_set_ref(struct razor_set *set)
ali@403
   335
{
ali@403
   336
	if (set)
ali@403
   337
		set->ref_count++;
ali@403
   338
	return set;
ali@403
   339
}
ali@403
   340
ali@403
   341
RAZOR_EXPORT void
ali@403
   342
razor_set_write_to_handle(struct razor_set *set, struct razor_atomic *atomic,
ali@403
   343
			  int handle, uint32_t section_mask)
rhughes@241
   344
{
jbowes@318
   345
	struct razor_set_header header;
krh@373
   346
	struct razor_set_section sections[ARRAY_SIZE(razor_sections)];
jbowes@318
   347
	struct hashtable table;
krh@373
   348
	struct array pool, *arrays[ARRAY_SIZE(razor_sections)];
rhughes@241
   349
	uint32_t offset;
krh@373
   350
	int count, i, j;
krh@373
   351
	static const char padding[4];
jbowes@318
   352
jbowes@318
   353
	array_init(&pool);
jbowes@318
   354
	hashtable_init(&table, &pool);
jbowes@318
   355
krh@373
   356
	j = 0;
krh@373
   357
	for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
krh@373
   358
		if ((razor_sections[i].flags & section_mask) == 0)
krh@373
   359
			continue;
jbowes@318
   360
krh@373
   361
		arrays[j] = (void *) set + razor_sections[i].offset;
krh@373
   362
		sections[j].name =
krh@373
   363
			hashtable_tokenize(&table, razor_sections[i].name);
krh@373
   364
		j++;
krh@373
   365
	}
rhughes@241
   366
krh@373
   367
	count = j;
krh@373
   368
	header.magic = RAZOR_MAGIC;
ali@403
   369
	header.version = set->header_version;
krh@373
   370
	header.num_sections = count;
krh@373
   371
	offset = sizeof header + count * sizeof *sections + ALIGN(pool.size, 4);
krh@373
   372
krh@373
   373
	for (i = 0; i < count; i++) {
krh@373
   374
		sections[i].offset = offset;
krh@373
   375
		sections[i].size = arrays[i]->size;
krh@373
   376
		offset += ALIGN(arrays[i]->size, 4);
rhughes@241
   377
	}
rhughes@241
   378
ali@403
   379
	razor_atomic_write(atomic, handle, &header, sizeof header);
ali@403
   380
	razor_atomic_write(atomic, handle, sections, count * sizeof *sections);
ali@403
   381
	razor_atomic_write(atomic, handle, pool.data, pool.size);
ali@403
   382
	razor_atomic_write(atomic, handle, padding, PADDING(pool.size, 4));
rhughes@241
   383
krh@373
   384
	for (i = 0; i < count; i++) {
ali@403
   385
		razor_atomic_write(atomic, handle, arrays[i]->data,
ali@403
   386
				   arrays[i]->size);
ali@403
   387
		razor_atomic_write(atomic, handle, padding,
ali@403
   388
				   PADDING(arrays[i]->size, 4));
rhughes@241
   389
	}
rhughes@241
   390
krh@373
   391
	array_release(&pool);
krh@373
   392
	hashtable_release(&table);
rhughes@241
   393
}
rhughes@241
   394
krh@269
   395
RAZOR_EXPORT int
ali@403
   396
razor_set_write(struct razor_set *set, struct razor_atomic *atomic,
ali@403
   397
		const char *filename, uint32_t sections)
rhughes@241
   398
{
ali@403
   399
	int h;
rhughes@241
   400
ali@403
   401
	h = razor_atomic_create_file(atomic, filename,
ali@403
   402
				     S_IRWXU | S_IRWXG | S_IRWXO);
ali@403
   403
	if (h < 0)
rhughes@241
   404
		return -1;
rhughes@241
   405
ali@403
   406
	razor_set_write_to_handle(set, atomic, h, sections);
rhughes@241
   407
ali@403
   408
	return razor_atomic_close(atomic, h);
rhughes@241
   409
}
krh@269
   410
krh@269
   411
RAZOR_EXPORT void
rhughes@241
   412
razor_build_evr(char *evr_buf, int size, const char *epoch,
rhughes@241
   413
		const char *version, const char *release)
rhughes@241
   414
{
rhughes@241
   415
	int len;
rhughes@241
   416
rhughes@241
   417
	if (!version || !*version) {
rhughes@241
   418
		*evr_buf = '\0';
rhughes@241
   419
		return;
rhughes@241
   420
	}
rhughes@241
   421
rhughes@241
   422
	if (epoch && *epoch && strcmp(epoch, "0") != 0) {
rhughes@241
   423
		len = snprintf(evr_buf, size, "%s:", epoch);
rhughes@241
   424
		evr_buf += len;
rhughes@241
   425
		size -= len;
rhughes@241
   426
	}
rhughes@241
   427
	len = snprintf(evr_buf, size, "%s", version);
rhughes@241
   428
	evr_buf += len;
rhughes@241
   429
	size -= len;
rhughes@241
   430
	if (release && *release)
rhughes@241
   431
		snprintf(evr_buf, size, "-%s", release);
rhughes@241
   432
}
rhughes@241
   433
krh@269
   434
RAZOR_EXPORT int
krh@248
   435
razor_versioncmp(const char *s1, const char *s2)
rhughes@241
   436
{
rhughes@241
   437
	const char *p1, *p2;
rhughes@241
   438
	long n1, n2;
rhughes@241
   439
	int res;
rhughes@241
   440
richard@301
   441
	assert (s1 != NULL);
richard@301
   442
	assert (s2 != NULL);
richard@301
   443
rhughes@241
   444
	n1 = strtol(s1, (char **) &p1, 10);
rhughes@241
   445
	n2 = strtol(s2, (char **) &p2, 10);
rhughes@241
   446
rhughes@241
   447
	/* Epoch; if one but not the other has an epoch set, default
rhughes@241
   448
	 * the epoch-less version to 0. */
rhughes@241
   449
	res = (*p1 == ':') - (*p2 == ':');
rhughes@241
   450
	if (res < 0) {
rhughes@241
   451
		n1 = 0;
rhughes@241
   452
		p1 = s1;
rhughes@241
   453
		p2++;
rhughes@241
   454
	} else if (res > 0) {
rhughes@241
   455
		p1++;
rhughes@241
   456
		n2 = 0;
rhughes@241
   457
		p2 = s2;
rhughes@241
   458
	}
rhughes@241
   459
rhughes@241
   460
	if (n1 != n2)
rhughes@241
   461
		return n1 - n2;
rhughes@241
   462
	while (*p1 && *p2) {
rhughes@241
   463
		if (*p1 != *p2)
rhughes@241
   464
			return *p1 - *p2;
rhughes@241
   465
		p1++;
rhughes@241
   466
		p2++;
rhughes@241
   467
		if (isdigit(*p1) && isdigit(*p2))
krh@248
   468
			return razor_versioncmp(p1, p2);
rhughes@241
   469
	}
rhughes@241
   470
rhughes@241
   471
	return *p1 - *p2;
rhughes@241
   472
}
rhughes@241
   473
richard@302
   474
static const char *
ali@372
   475
razor_package_get_details_string(struct razor_set *set,
ali@372
   476
				 struct razor_package *package,
ali@372
   477
				 enum razor_detail_type type)
richard@302
   478
{
richard@302
   479
	const char *pool;
richard@302
   480
richard@302
   481
	switch (type) {
richard@302
   482
	case RAZOR_DETAIL_NAME:
richard@302
   483
		pool = set->string_pool.data;
richard@302
   484
		return &pool[package->name];
richard@302
   485
richard@302
   486
	case RAZOR_DETAIL_VERSION:
richard@302
   487
		pool = set->string_pool.data;
richard@302
   488
		return &pool[package->version];
richard@302
   489
richard@302
   490
	case RAZOR_DETAIL_ARCH:
richard@302
   491
		pool = set->string_pool.data;
richard@302
   492
		return &pool[package->arch];
richard@302
   493
richard@302
   494
	case RAZOR_DETAIL_SUMMARY:
ali@395
   495
		if (!set->details_string_pool.size)
ali@395
   496
			return "";
richard@302
   497
		pool = set->details_string_pool.data;
richard@302
   498
		return &pool[package->summary];
richard@302
   499
richard@302
   500
	case RAZOR_DETAIL_DESCRIPTION:
ali@395
   501
		if (!set->details_string_pool.size)
ali@395
   502
			return "";
richard@302
   503
		pool = set->details_string_pool.data;
richard@302
   504
		return &pool[package->description];
richard@302
   505
richard@302
   506
	case RAZOR_DETAIL_URL:
ali@395
   507
		if (!set->details_string_pool.size)
ali@395
   508
			return "";
richard@302
   509
		pool = set->details_string_pool.data;
richard@302
   510
		return &pool[package->url];
richard@302
   511
richard@302
   512
	case RAZOR_DETAIL_LICENSE:
ali@395
   513
		if (!set->details_string_pool.size)
ali@395
   514
			return "";
richard@302
   515
		pool = set->details_string_pool.data;
richard@302
   516
		return &pool[package->license];
richard@302
   517
ali@369
   518
	case RAZOR_DETAIL_PREUNPROG:
ali@369
   519
		pool = set->string_pool.data;
ali@369
   520
		return &pool[package->preun.program];
ali@369
   521
ali@369
   522
	case RAZOR_DETAIL_PREUN:
ali@369
   523
		pool = set->string_pool.data;
ali@369
   524
		return &pool[package->preun.body];
ali@369
   525
ali@369
   526
	case RAZOR_DETAIL_POSTUNPROG:
ali@369
   527
		pool = set->string_pool.data;
ali@369
   528
		return &pool[package->postun.program];
ali@369
   529
ali@369
   530
	case RAZOR_DETAIL_POSTUN:
ali@369
   531
		pool = set->string_pool.data;
ali@369
   532
		return &pool[package->postun.body];
ali@369
   533
richard@302
   534
	default:
richard@302
   535
		fprintf(stderr, "type %u not found\n", type);
richard@302
   536
		return NULL;
richard@302
   537
	}
richard@302
   538
}
richard@302
   539
ali@372
   540
static const char *const *
ali@372
   541
razor_package_get_details_array(struct razor_set *set,
ali@372
   542
				struct razor_package *package,
ali@372
   543
				enum razor_detail_type type)
ali@372
   544
{
ali@372
   545
	switch (type) {
ali@372
   546
	case RAZOR_DETAIL_PREFIXES:
ali@372
   547
		/* We don't track prefixes in packages. Install prefixes
ali@372
   548
		 * are tracked, but we don't provide an API to get them.
ali@372
   549
		 */
ali@372
   550
		return NULL;
ali@372
   551
ali@372
   552
	default:
ali@372
   553
		fprintf(stderr, "type %u not found\n", type);
ali@372
   554
		return NULL;
ali@372
   555
	}
ali@372
   556
}
ali@372
   557
richard@302
   558
/**
richard@302
   559
 * razor_package_get_details_varg:
richard@302
   560
 * @set: a %razor_set
richard@302
   561
 * @package: a %razor_package
richard@302
   562
 * @args: a va_list of arguments to set
richard@302
   563
 **/
richard@302
   564
void
richard@302
   565
razor_package_get_details_varg(struct razor_set *set,
richard@302
   566
			       struct razor_package *package,
richard@302
   567
			       va_list args)
richard@302
   568
{
richard@302
   569
	int i;
richard@302
   570
	enum razor_detail_type type;
ali@372
   571
	const char **string;
ali@372
   572
	const char *const **array;
richard@302
   573
richard@302
   574
	for (i = 0;; i += 2) {
richard@302
   575
		type = va_arg(args, enum razor_detail_type);
richard@307
   576
		if (type == RAZOR_DETAIL_LAST)
richard@302
   577
			break;
ali@372
   578
		if (type == RAZOR_DETAIL_PREFIXES) {
ali@372
   579
			array = va_arg(args, const char *const **);
ali@372
   580
			*array = razor_package_get_details_array(set, package,
ali@372
   581
								 type);
ali@372
   582
		} else {
ali@372
   583
			string = va_arg(args, const char **);
ali@372
   584
			*string = razor_package_get_details_string(set, package,
ali@372
   585
								   type);
ali@372
   586
		}
richard@302
   587
	}
richard@302
   588
richard@302
   589
}
richard@302
   590
richard@302
   591
/**
richard@302
   592
 * razor_package_get_details:
richard@302
   593
 * @set: a %razor_set
richard@302
   594
 * @package: a %razor_package
richard@302
   595
 *
richard@302
   596
 * Gets details about a package using a varg interface
krh@308
   597
 * The vararg must be terminated with %RAZOR_DETAIL_LAST.
richard@302
   598
 *
richard@307
   599
 * Example: razor_package_get_details (set, package,
richard@307
   600
 *				       RAZOR_DETAIL_URL, &url,
richard@307
   601
 *				       RAZOR_DETAIL_LAST);
richard@302
   602
 **/
krh@269
   603
RAZOR_EXPORT void
richard@302
   604
razor_package_get_details(struct razor_set *set, struct razor_package *package, ...)
jbowes@258
   605
{
richard@302
   606
	va_list args;
jbowes@258
   607
richard@301
   608
	assert (set != NULL);
richard@301
   609
	assert (package != NULL);
richard@301
   610
richard@302
   611
	va_start(args, NULL);
richard@302
   612
	razor_package_get_details_varg (set, package, args);
richard@302
   613
	va_end (args);
jbowes@258
   614
}
jbowes@258
   615
ali@369
   616
/**
ali@369
   617
 * razor_package_remove:
ali@382
   618
 * @prev: The %razor_set before the current transaction
ali@382
   619
 * @next: The %razor_set after the current transaction is applied
ali@369
   620
 * @package: a %razor_package
ali@369
   621
 * @root: the root into which the package is currently installed
ali@376
   622
 * @install_count: the value to pass to uninstall scripts
ali@403
   623
 * @stage: Limit the removal to just the scripts or the files
ali@369
   624
 *
ali@369
   625
 * Removes an installed package.
ali@369
   626
 **/
ali@369
   627
RAZOR_EXPORT int
ali@382
   628
razor_package_remove(struct razor_set *prev, struct razor_set *next,
ali@403
   629
		     struct razor_atomic *atomic, struct razor_package *package,
ali@403
   630
		     const char *root, int install_count,
ali@403
   631
		     enum razor_stage_type stage)
ali@369
   632
{
ali@369
   633
	struct razor_file_iterator *fi;
ali@369
   634
	struct razor_package_iterator *pi;
ali@369
   635
	struct razor_package *p;
ali@411
   636
	char *buffer, buf[32];
ali@369
   637
	const char *name, *program, *script;
ali@403
   638
	int i, count;
ali@372
   639
	struct environment env;
ali@372
   640
	struct list *link;
ali@372
   641
	const char *prefix;
ali@369
   642
ali@403
   643
	if (stage & RAZOR_STAGE_SCRIPTS) {
ali@403
   644
		environment_init(&env);
ali@403
   645
		link = list_first(&package->install_prefixes,
ali@403
   646
				  &prev->prefix_pool);
ali@403
   647
		for (i = 0; link; i++) {
ali@403
   648
			prefix = (const char *)prev->string_pool.data +
ali@403
   649
				 link->data;
ali@411
   650
			sprintf(buf, "RPM_INSTALL_PREFIX%d", i);
ali@411
   651
			environment_add_variable(&env, buf, prefix);
ali@403
   652
			link = list_next(link);
ali@403
   653
		}
ali@403
   654
		environment_set(&env);
ali@375
   655
	}
ali@375
   656
ali@403
   657
	if (stage & RAZOR_STAGE_SCRIPTS_PRE) {
ali@403
   658
		razor_package_get_details(prev, package,
ali@403
   659
					  RAZOR_DETAIL_PREUNPROG, &program,
ali@403
   660
					  RAZOR_DETAIL_PREUN, &script,
ali@403
   661
					  RAZOR_DETAIL_LAST);
ali@369
   662
ali@403
   663
		razor_run_script(root, RAZOR_PROPERTY_PREUN, program,
ali@403
   664
				 script, install_count);
ali@403
   665
	}
ali@375
   666
ali@403
   667
	if (stage & RAZOR_STAGE_FILES) {
ali@403
   668
		fi = razor_file_iterator_create(prev, package, 1);
ali@369
   669
ali@403
   670
		while (razor_file_iterator_next(fi, &name)) {
ali@403
   671
			pi = razor_package_iterator_create_for_file(next, name);
ali@403
   672
			count = 0;
ali@403
   673
			while (razor_package_iterator_next(pi, &p,
ali@403
   674
							   RAZOR_DETAIL_LAST))
ali@403
   675
				count++;
ali@403
   676
			razor_package_iterator_destroy(pi);
ali@403
   677
			if (count <= 0) {
ali@403
   678
				buffer = razor_concat(root, name, NULL);
ali@403
   679
				razor_atomic_remove(atomic, buffer);
ali@403
   680
				free(buffer);
ali@377
   681
			}
ali@369
   682
		}
ali@403
   683
ali@403
   684
		razor_file_iterator_destroy(fi);
ali@369
   685
	}
ali@369
   686
ali@403
   687
	if (stage & RAZOR_STAGE_SCRIPTS_POST) {
ali@403
   688
		razor_package_get_details(prev, package,
ali@403
   689
					  RAZOR_DETAIL_POSTUNPROG, &program,
ali@403
   690
					  RAZOR_DETAIL_POSTUN, &script,
ali@403
   691
					  RAZOR_DETAIL_LAST);
ali@369
   692
ali@403
   693
		razor_run_script(root, RAZOR_PROPERTY_POSTUN, program, script,
ali@403
   694
				 install_count);
ali@403
   695
	}
ali@369
   696
ali@403
   697
	if (stage & RAZOR_STAGE_SCRIPTS) {
ali@403
   698
		environment_unset(&env);
ali@403
   699
		environment_release(&env);
ali@403
   700
	}
ali@377
   701
ali@403
   702
	return razor_atomic_in_error_state(atomic);
ali@369
   703
}
ali@369
   704
krh@270
   705
RAZOR_EXPORT const char *
krh@270
   706
razor_property_relation_to_string(struct razor_property *p)
krh@270
   707
{
richard@301
   708
	assert (p != NULL);
richard@301
   709
krh@270
   710
	switch (p->flags & RAZOR_PROPERTY_RELATION_MASK) {
krh@270
   711
	case RAZOR_PROPERTY_LESS:
krh@270
   712
		return "<";
krh@270
   713
krh@270
   714
	case RAZOR_PROPERTY_LESS | RAZOR_PROPERTY_EQUAL:
krh@270
   715
		return "<=";
krh@270
   716
krh@270
   717
	case RAZOR_PROPERTY_EQUAL:
krh@270
   718
		return "=";
krh@270
   719
krh@270
   720
	case RAZOR_PROPERTY_GREATER | RAZOR_PROPERTY_EQUAL:
krh@270
   721
		return ">=";
krh@270
   722
krh@270
   723
	case RAZOR_PROPERTY_GREATER:
krh@270
   724
		return ">";
krh@270
   725
krh@270
   726
	default:
krh@270
   727
		return "?";
krh@270
   728
	}
krh@270
   729
}
krh@270
   730
krh@270
   731
RAZOR_EXPORT const char *
krh@270
   732
razor_property_type_to_string(struct razor_property *p)
krh@270
   733
{
richard@301
   734
	assert (p != NULL);
richard@301
   735
krh@270
   736
	switch (p->flags & RAZOR_PROPERTY_TYPE_MASK) {
krh@270
   737
	case RAZOR_PROPERTY_REQUIRES:
krh@270
   738
		return "requires";
krh@270
   739
	case RAZOR_PROPERTY_PROVIDES:
krh@270
   740
		return "provides";
krh@270
   741
	case RAZOR_PROPERTY_CONFLICTS:
krh@270
   742
		return "conflicts";
krh@270
   743
	case RAZOR_PROPERTY_OBSOLETES:
krh@270
   744
		return "obsoletes";
krh@270
   745
	default:
krh@270
   746
		return NULL;
krh@270
   747
	}
krh@270
   748
}
krh@270
   749
krh@269
   750
RAZOR_EXPORT struct razor_entry *
krh@248
   751
razor_set_find_entry(struct razor_set *set,
krh@248
   752
		     struct razor_entry *dir, const char *pattern)
rhughes@241
   753
{
ali@359
   754
	struct razor_entry *e, *subdir;
jbowes@264
   755
	const char *n, *pool = set->file_string_pool.data;
rhughes@241
   756
	int len;
rhughes@241
   757
richard@301
   758
	assert (set != NULL);
richard@301
   759
	assert (pattern != NULL);
richard@301
   760
ali@383
   761
	if (dir == NULL)
ali@383
   762
		return NULL;
ali@383
   763
ali@359
   764
	e = dir;
rhughes@241
   765
	do {
rhughes@241
   766
		n = pool + e->name;
ali@359
   767
		if (strcmp(pattern, n) == 0)
rhughes@241
   768
			return e;
rhughes@241
   769
		len = strlen(n);
ali@359
   770
		if (e->start != 0 && strncmp(pattern, n, len) == 0 &&
ali@359
   771
		    pattern[len] == '/') {
ali@359
   772
			subdir = (struct razor_entry *) set->files.data +
ali@359
   773
				 e->start;
ali@359
   774
			return razor_set_find_entry(set, subdir,
ali@359
   775
						    pattern + len + 1);
rhughes@241
   776
		}
rhughes@241
   777
	} while (!((e++)->flags & RAZOR_ENTRY_LAST));
rhughes@241
   778
rhughes@241
   779
	return NULL;
rhughes@241
   780
}
rhughes@241
   781
rhughes@241
   782
static void
rhughes@241
   783
list_dir(struct razor_set *set, struct razor_entry *dir,
rhughes@241
   784
	 char *prefix, const char *pattern)
rhughes@241
   785
{
ali@359
   786
	struct razor_entry *e, *subdir;
jbowes@274
   787
	const char *n, *pool = set->file_string_pool.data;
rhughes@241
   788
ali@359
   789
	e = dir;
rhughes@241
   790
	do {
rhughes@241
   791
		n = pool + e->name;
rhughes@241
   792
		if (pattern && pattern[0] && fnmatch(pattern, n, 0) != 0)
rhughes@241
   793
			continue;
rhughes@241
   794
		printf("%s/%s\n", prefix, n);
rhughes@241
   795
		if (e->start) {
rhughes@241
   796
			char *sub = prefix + strlen (prefix);
rhughes@241
   797
			*sub = '/';
rhughes@241
   798
			strcpy (sub + 1, n);
ali@359
   799
			subdir = (struct razor_entry *) set->files.data +
ali@359
   800
				 e->start;
ali@359
   801
			list_dir(set, subdir, prefix, pattern);
rhughes@241
   802
			*sub = '\0';
rhughes@241
   803
		}
rhughes@241
   804
	} while (!((e++)->flags & RAZOR_ENTRY_LAST));
rhughes@241
   805
}
rhughes@241
   806
krh@269
   807
RAZOR_EXPORT void
rhughes@241
   808
razor_set_list_files(struct razor_set *set, const char *pattern)
rhughes@241
   809
{
ali@359
   810
	struct razor_entry *root, *e;
rhughes@241
   811
	char buffer[512], *p, *base;
rhughes@241
   812
richard@301
   813
	assert (set != NULL);
richard@301
   814
ali@359
   815
	root = (struct razor_entry *) set->files.data;
ali@359
   816
ali@359
   817
	if (pattern == NULL) {
ali@359
   818
		p = set->file_string_pool.data;
ali@359
   819
		e = root;
ali@359
   820
		do {
ali@359
   821
			if (e->start) {
ali@359
   822
				strcpy(buffer, p + e->name);
ali@359
   823
				list_dir(set, root + e->start, buffer, NULL);
ali@359
   824
			}
ali@359
   825
		} while (!((e++)->flags & RAZOR_ENTRY_LAST));
rhughes@241
   826
		return;
rhughes@241
   827
	}
rhughes@241
   828
rhughes@241
   829
	strcpy(buffer, pattern);
ali@359
   830
	e = razor_set_find_entry(set, root, buffer);
ali@359
   831
	if (e && e->start) {
rhughes@241
   832
		base = NULL;
rhughes@241
   833
	} else {
rhughes@241
   834
		p = strrchr(buffer, '/');
rhughes@241
   835
		if (p) {
rhughes@241
   836
			*p = '\0';
rhughes@241
   837
			base = p + 1;
rhughes@241
   838
		} else {
rhughes@241
   839
			base = NULL;
rhughes@241
   840
		}
rhughes@241
   841
	}
ali@359
   842
	e = razor_set_find_entry(set, root, buffer);
ali@359
   843
	if (e && e->start)
ali@359
   844
		list_dir(set, root + e->start, buffer, base);
rhughes@241
   845
}
rhughes@241
   846
krh@269
   847
RAZOR_EXPORT void
krh@306
   848
razor_set_list_package_files(struct razor_set *set,
krh@306
   849
			     struct razor_package *package)
rhughes@241
   850
{
ali@351
   851
	struct razor_file_iterator *fi;
ali@351
   852
	const char *name;
rhughes@241
   853
richard@301
   854
	assert (set != NULL);
krh@306
   855
	assert (package != NULL);
rhughes@241
   856
ali@377
   857
	fi = razor_file_iterator_create(set, package, 0);
ali@351
   858
ali@351
   859
	while (razor_file_iterator_next(fi, &name))
ali@351
   860
		printf("%s\n", name);
ali@351
   861
ali@351
   862
	razor_file_iterator_destroy(fi);
rhughes@241
   863
}
rhughes@241
   864
ali@387
   865
/*
ali@387
   866
 * Package data can potentially come from two places. The so-called
ali@387
   867
 * metadata (eg., from comps.xml) and from an RPM file. We consider
ali@387
   868
 * a package which has additional data from an RPM file as "fixed".
ali@387
   869
 * If a package needs fixing, then razor_transaction_fixup_package()
ali@387
   870
 * will do so. When considering what packages to add and to remove
ali@387
   871
 * we need to take this into account since we always want to add
ali@387
   872
 * unfixed packages (otherwise we have a potential conflict between
ali@387
   873
 * the existing package data and that present in the RPM).
ali@387
   874
 */
ali@387
   875
static int
ali@387
   876
razor_package_is_fixed(struct razor_set *set, struct razor_package *p)
ali@387
   877
{
ali@387
   878
	const char *preunprog, *preun, *postunprog, *postun;
ali@387
   879
ali@387
   880
	if (!p)
ali@387
   881
		return 0;
ali@387
   882
	razor_package_get_details(set, p,
ali@387
   883
				  RAZOR_DETAIL_PREUNPROG, &preunprog,
ali@387
   884
				  RAZOR_DETAIL_PREUN, &preun,
ali@387
   885
				  RAZOR_DETAIL_POSTUNPROG, &postunprog,
ali@387
   886
				  RAZOR_DETAIL_POSTUN, &postun,
ali@387
   887
				  RAZOR_DETAIL_LAST);
ali@387
   888
	return *preunprog || *preun || *postunprog || *postun;
ali@387
   889
}
ali@387
   890
krh@269
   891
RAZOR_EXPORT void
rhughes@241
   892
razor_set_diff(struct razor_set *set, struct razor_set *upstream,
krh@253
   893
	       razor_diff_callback_t callback, void *data)
rhughes@241
   894
{
rhughes@241
   895
 	struct razor_package_iterator *pi1, *pi2;
rhughes@241
   896
 	struct razor_package *p1, *p2;
rhughes@241
   897
	const char *name1, *name2, *version1, *version2, *arch1, *arch2;
ali@387
   898
	int res, is_fixed1, is_fixed2;
rhughes@241
   899
richard@301
   900
	assert (set != NULL);
richard@301
   901
	assert (upstream != NULL);
richard@301
   902
rhughes@241
   903
	pi1 = razor_package_iterator_create(set);
rhughes@241
   904
	pi2 = razor_package_iterator_create(upstream);
rhughes@241
   905
richard@302
   906
	razor_package_iterator_next(pi1, &p1,
richard@302
   907
				    RAZOR_DETAIL_NAME, &name1,
richard@302
   908
				    RAZOR_DETAIL_VERSION, &version1,
richard@302
   909
				    RAZOR_DETAIL_ARCH, &arch1,
richard@307
   910
				    RAZOR_DETAIL_LAST);
ali@387
   911
	is_fixed1 = razor_package_is_fixed(set, p1);
richard@302
   912
	razor_package_iterator_next(pi2, &p2,
richard@302
   913
				    RAZOR_DETAIL_NAME, &name2,
richard@302
   914
				    RAZOR_DETAIL_VERSION, &version2,
richard@302
   915
				    RAZOR_DETAIL_ARCH, &arch2,
richard@307
   916
				    RAZOR_DETAIL_LAST);
ali@387
   917
	is_fixed2 = razor_package_is_fixed(upstream, p2);
rhughes@241
   918
rhughes@241
   919
	while (p1 || p2) {
rhughes@241
   920
		if (p1 && p2) {
rhughes@241
   921
			res = strcmp(name1, name2);
rhughes@241
   922
			if (res == 0)
krh@248
   923
				res = razor_versioncmp(version1, version2);
ali@387
   924
			if (res == 0)
ali@387
   925
				res = is_fixed1 - is_fixed2;
rhughes@241
   926
		} else {
rhughes@241
   927
			res = 0;
rhughes@241
   928
		}
rhughes@241
   929
rhughes@241
   930
		if (p2 == NULL || res < 0)
krh@253
   931
			callback(RAZOR_DIFF_ACTION_REMOVE,
krh@253
   932
				 p1, name1, version1, arch1, data);
rhughes@241
   933
		else if (p1 == NULL || res > 0)
krh@253
   934
			callback(RAZOR_DIFF_ACTION_ADD,
krh@253
   935
				 p2, name2, version2, arch2, data);
rhughes@241
   936
ali@387
   937
		if (p1 != NULL && res <= 0) {
rhughes@241
   938
			razor_package_iterator_next(pi1, &p1,
richard@302
   939
						    RAZOR_DETAIL_NAME, &name1,
richard@302
   940
						    RAZOR_DETAIL_VERSION, &version1,
richard@302
   941
						    RAZOR_DETAIL_ARCH, &arch1,
richard@307
   942
						    RAZOR_DETAIL_LAST);
ali@387
   943
			is_fixed1 = razor_package_is_fixed(set, p1);
ali@387
   944
		}
ali@387
   945
		if (p2 != NULL && res >= 0) {
rhughes@241
   946
			razor_package_iterator_next(pi2, &p2,
richard@302
   947
						    RAZOR_DETAIL_NAME, &name2,
richard@302
   948
						    RAZOR_DETAIL_VERSION, &version2,
richard@302
   949
						    RAZOR_DETAIL_ARCH, &arch2,
richard@307
   950
						    RAZOR_DETAIL_LAST);
ali@387
   951
			is_fixed2 = razor_package_is_fixed(upstream, p2);
ali@387
   952
		}
rhughes@241
   953
	}
rhughes@241
   954
rhughes@241
   955
	razor_package_iterator_destroy(pi1);
rhughes@241
   956
	razor_package_iterator_destroy(pi2);
rhughes@241
   957
}
krh@254
   958
krh@316
   959
struct install_action {
krh@316
   960
	enum razor_install_action action;
krh@316
   961
	struct razor_package *package;
krh@316
   962
};
krh@316
   963
krh@316
   964
struct razor_install_iterator {
krh@316
   965
	struct razor_set *set;
krh@316
   966
	struct razor_set *next;
krh@316
   967
	struct array actions;
ali@403
   968
	struct deque *order, *left;
krh@316
   969
};
krh@316
   970
krh@254
   971
static void
krh@316
   972
add_action(enum razor_diff_action action,
krh@316
   973
	   struct razor_package *package,
krh@316
   974
	   const char *name,
krh@316
   975
	   const char *version,
krh@316
   976
	   const char *arch,
krh@316
   977
	   void *data)
krh@254
   978
{
krh@316
   979
	struct razor_install_iterator *ii = data;
krh@316
   980
	struct install_action *a;
krh@316
   981
krh@316
   982
	a = array_add(&ii->actions, sizeof *a);
krh@316
   983
	a->package = package;
krh@316
   984
krh@316
   985
	switch (action) {
krh@316
   986
	case RAZOR_DIFF_ACTION_ADD:
krh@316
   987
		a->action = RAZOR_INSTALL_ACTION_ADD;
krh@316
   988
		break;
krh@316
   989
	case RAZOR_DIFF_ACTION_REMOVE:
krh@316
   990
		a->action = RAZOR_INSTALL_ACTION_REMOVE;
krh@316
   991
		break;
krh@316
   992
	}
krh@254
   993
}
krh@254
   994
ali@418
   995
/*
ali@418
   996
 * Does <package> have a requirement for <script> which is
ali@418
   997
 * satisfied by <provider> ?
ali@418
   998
 * Note: We already know that <provider> is to be added as part of this install
ali@418
   999
 * so there is no need to check the relation.
ali@418
  1000
 */
ali@418
  1001
static int
ali@418
  1002
package_script_requires(struct razor_set *set, struct razor_package *package,
ali@418
  1003
			enum razor_property_flags script,
ali@418
  1004
			struct razor_package *provider)
ali@418
  1005
{
ali@418
  1006
	struct list *link;
ali@418
  1007
	struct razor_property *prop;
ali@418
  1008
ali@418
  1009
	link = list_first(&package->properties, &set->property_pool);
ali@418
  1010
	for(; link; link = list_next(link)) {
ali@418
  1011
		prop = set->properties.data;
ali@418
  1012
		prop += link->data;
ali@418
  1013
		if ((prop->flags & RAZOR_PROPERTY_SCRIPT_MASK) & script &&
ali@418
  1014
		    (prop->flags & RAZOR_PROPERTY_TYPE_MASK) == RAZOR_PROPERTY_REQUIRES &&
ali@418
  1015
		    provider->name == prop->name)
ali@418
  1016
			return 1;
ali@418
  1017
	}
ali@418
  1018
	return 0;
ali@418
  1019
}
ali@418
  1020
krh@316
  1021
RAZOR_EXPORT struct razor_install_iterator *
krh@316
  1022
razor_set_create_install_iterator(struct razor_set *set,
krh@316
  1023
				  struct razor_set *next)
krh@254
  1024
{
krh@316
  1025
	struct razor_install_iterator *ii;
ali@367
  1026
	struct razor_property *prop;
ali@367
  1027
	/* A graph of the actions to be perfomed where
ali@367
  1028
	 * A->B means action A should follow action B.
ali@367
  1029
	 */
ali@367
  1030
	struct graph follows;
ali@418
  1031
	struct install_action *actions, *ai, *aj, *an;
ali@367
  1032
	int i, j, count, vertex_added;
ali@367
  1033
	struct list *link;
ali@367
  1034
	struct razor_set *rs;
ali@418
  1035
	struct deque *order;
ali@418
  1036
	int barrier_needed;
krh@254
  1037
richard@301
  1038
	assert (set != NULL);
richard@301
  1039
	assert (next != NULL);
richard@301
  1040
krh@316
  1041
	ii = zalloc(sizeof *ii);
krh@316
  1042
	ii->set = set;
krh@316
  1043
	ii->next = next;
krh@316
  1044
	
krh@316
  1045
	razor_set_diff(set, next, add_action, ii);
krh@254
  1046
ali@367
  1047
	actions = ii->actions.data;
ali@367
  1048
	count = ii->actions.size / sizeof (struct install_action);
krh@254
  1049
ali@367
  1050
	graph_init(&follows);
ali@367
  1051
ali@367
  1052
	for(i = 0; i < count; i++) {
ali@367
  1053
		ai = actions + i;
ali@367
  1054
		rs = ai->action == RAZOR_INSTALL_ACTION_ADD ? next : set;
ali@367
  1055
		vertex_added = 0;
ali@367
  1056
		link = list_first(&ai->package->properties, &rs->property_pool);
ali@367
  1057
		for(; link; link = list_next(link)) {
ali@367
  1058
			prop = rs->properties.data;
ali@367
  1059
			prop += link->data;
ali@367
  1060
			switch(prop->flags & RAZOR_PROPERTY_TYPE_MASK) {
ali@367
  1061
			case RAZOR_PROPERTY_REQUIRES:
ali@367
  1062
			case RAZOR_PROPERTY_CONFLICTS:
ali@367
  1063
				for(j = 0; j < count; j++) {
ali@367
  1064
					if (j == i)
ali@367
  1065
						continue;
ali@367
  1066
					aj = actions + j;
ali@367
  1067
					if (aj->package->name == prop->name) {
ali@367
  1068
						if (ai->action ==
ali@367
  1069
						    RAZOR_INSTALL_ACTION_ADD)
ali@367
  1070
							graph_add_edge(&follows,
ali@367
  1071
								       i, j);
ali@367
  1072
						else
ali@367
  1073
							graph_add_edge(&follows,
ali@367
  1074
								       j, i);
ali@367
  1075
						vertex_added++;
ali@367
  1076
					}
ali@367
  1077
				}
ali@367
  1078
				break;
ali@367
  1079
			}
ali@367
  1080
		}
ali@367
  1081
		if (ai->action == RAZOR_INSTALL_ACTION_ADD) {
ali@367
  1082
			for(j = 0; j < count; j++) {
ali@367
  1083
				if (j == i)
ali@367
  1084
					continue;
ali@367
  1085
				aj = actions + j;
ali@367
  1086
				if (aj->package == ai->package &&
ali@367
  1087
				    aj->action == RAZOR_INSTALL_ACTION_REMOVE) {
ali@367
  1088
					graph_add_edge(&follows, i, j);
ali@367
  1089
					vertex_added++;
ali@367
  1090
				}
ali@367
  1091
			}
ali@367
  1092
		}
ali@367
  1093
		if (!vertex_added)
ali@367
  1094
			graph_add_edge(&follows, i, i);
ali@367
  1095
	}
ali@367
  1096
ali@418
  1097
	/*
ali@418
  1098
	 * Because files are installed and removed using razor_atomic,
ali@418
  1099
	 * but scripts are run with no regard for these, we need some
ali@418
  1100
	 * means for synchronisation between the two. We support this
ali@418
  1101
	 * via transaction barriers which are points where
ali@418
  1102
	 * razor_atomic_commit() should be called so that scripts can
ali@418
  1103
	 * rely on the files they need being present.
ali@418
  1104
	 *
ali@418
  1105
	 * Rules:
ali@418
  1106
	 *   1)	Transaction barriers never occur within a dependency
ali@418
  1107
	 *	loop. Since we can't guarantee any ordering of actions
ali@418
  1108
	 *	within such a loop, they make no sense.
ali@418
  1109
	 *   2) Otherwise the following table applies:
ali@418
  1110
	 *	Action I    Action J	Barrier between I and J iff
ali@418
  1111
	 *	ADD P	    ADD Q	%pre(Q) requires P
ali@418
  1112
	 *	ADD P	    REMOVE Q	%preun(Q) requires P
ali@418
  1113
	 *	REMOVE P    ADD Q	never
ali@418
  1114
	 *	REMOVE P    REMOVE Q	%postun(P) requires Q
ali@418
  1115
	 *
ali@418
  1116
	 * FIXME:
ali@418
  1117
	 *	This should take account of conflicts somehow.
ali@418
  1118
	 */
ali@418
  1119
	order = graph_sort(&follows);
ali@418
  1120
	ii->order = deque_new(0);
ali@418
  1121
	if (!deque_empty(order)) {
ali@418
  1122
		j = deque_pop(order);
ali@418
  1123
		deque_unshift(ii->order, j);
ali@418
  1124
	}
ali@418
  1125
	while (!deque_empty(order)) {
ali@418
  1126
		i = j;
ali@418
  1127
		j = deque_pop(order);
ali@418
  1128
		ai = actions + i;
ali@418
  1129
		aj = actions + j;
ali@418
  1130
		if (graph_is_connected(&follows, i, j) &&
ali@418
  1131
		    graph_is_connected(&follows, j, i))
ali@418
  1132
			barrier_needed = 0;
ali@418
  1133
		else if (ai->action == RAZOR_INSTALL_ACTION_ADD &&
ali@418
  1134
			 aj->action == RAZOR_INSTALL_ACTION_ADD &&
ali@418
  1135
			 package_script_requires(next, aj->package,
ali@418
  1136
						 RAZOR_PROPERTY_PRE,
ali@418
  1137
						 ai->package))
ali@418
  1138
			barrier_needed = 1;
ali@418
  1139
		else if (ai->action == RAZOR_INSTALL_ACTION_ADD &&
ali@418
  1140
			 aj->action == RAZOR_INSTALL_ACTION_REMOVE &&
ali@418
  1141
			 package_script_requires(set, aj->package,
ali@418
  1142
						 RAZOR_PROPERTY_PREUN,
ali@418
  1143
						 ai->package))
ali@418
  1144
			barrier_needed = 1;
ali@418
  1145
		else if (ai->action == RAZOR_INSTALL_ACTION_REMOVE &&
ali@418
  1146
			 aj->action == RAZOR_INSTALL_ACTION_REMOVE &&
ali@418
  1147
			 package_script_requires(set, ai->package,
ali@418
  1148
						 RAZOR_PROPERTY_POSTUN,
ali@418
  1149
						 aj->package))
ali@418
  1150
			barrier_needed = 1;
ali@418
  1151
		else
ali@418
  1152
			barrier_needed = 0;
ali@418
  1153
		if (barrier_needed) {
ali@418
  1154
			an = array_add(&ii->actions, sizeof *an);
ali@418
  1155
			actions = ii->actions.data;
ali@418
  1156
			an->package = NULL;
ali@418
  1157
			an->action = RAZOR_INSTALL_ACTION_COMMIT;
ali@418
  1158
			deque_unshift(ii->order, an - actions);
ali@418
  1159
		}
ali@418
  1160
		deque_unshift(ii->order, j);
ali@418
  1161
	}
ali@418
  1162
	deque_free(order);
ali@418
  1163
ali@403
  1164
	ii->left = deque_dup(ii->order);
ali@367
  1165
	graph_release(&follows);
krh@254
  1166
krh@316
  1167
	return ii;
krh@254
  1168
}
krh@254
  1169
krh@316
  1170
RAZOR_EXPORT int
krh@316
  1171
razor_install_iterator_next(struct razor_install_iterator *ii,
krh@316
  1172
			    struct razor_package **package,
krh@316
  1173
			    enum razor_install_action *action,
krh@316
  1174
			    int *count)
krh@254
  1175
{
ali@367
  1176
	struct install_action *a;
ali@382
  1177
	struct razor_package_iterator *pi;
ali@382
  1178
	struct razor_package *pkg;
ali@382
  1179
	const char *removing, *name;
ali@382
  1180
ali@403
  1181
	if (deque_empty(ii->left))
krh@316
  1182
		return 0;
krh@254
  1183
ali@403
  1184
	a = (struct install_action *)ii->actions.data + deque_pop(ii->left);
ali@367
  1185
	*package = a->package;
ali@367
  1186
	*action = a->action;
krh@316
  1187
	*count = 0;
krh@254
  1188
ali@382
  1189
	if (a->action == RAZOR_INSTALL_ACTION_REMOVE) {
ali@382
  1190
		razor_package_get_details(ii->set, a->package,
ali@382
  1191
					  RAZOR_DETAIL_NAME, &removing,
ali@382
  1192
					  RAZOR_DETAIL_LAST);
ali@382
  1193
ali@382
  1194
		pi = razor_package_iterator_create(ii->next);
ali@382
  1195
		while (razor_package_iterator_next(pi, &pkg,
ali@382
  1196
						   RAZOR_DETAIL_NAME, &name,
ali@382
  1197
						   RAZOR_DETAIL_LAST)) {
ali@382
  1198
			if (!strcmp(name, removing))
ali@382
  1199
				(*count)++;
ali@382
  1200
		}
ali@382
  1201
		razor_package_iterator_destroy(pi);
ali@418
  1202
	} else if (a->action == RAZOR_INSTALL_ACTION_ADD)
ali@403
  1203
		*count = 1;
ali@382
  1204
krh@316
  1205
	return 1;
krh@316
  1206
}
krh@254
  1207
ali@418
  1208
static int
ali@418
  1209
action_is_included(struct razor_install_iterator *ii, struct deque *done,
ali@418
  1210
		   struct razor_package *package,
ali@418
  1211
		   enum razor_install_action action)
ali@418
  1212
{
ali@418
  1213
	struct deque *t;
ali@418
  1214
	struct install_action *a;
ali@418
  1215
	int retval;
ali@418
  1216
ali@418
  1217
	t = deque_dup(done);
ali@418
  1218
ali@418
  1219
	while(!deque_empty(t)) {
ali@418
  1220
		a = (struct install_action *)ii->actions.data + deque_pop(t);
ali@418
  1221
		if (a->package == package && a->action == action)
ali@418
  1222
			break;
ali@418
  1223
	}
ali@418
  1224
	retval = !deque_empty(t);
ali@418
  1225
ali@418
  1226
	deque_free(t);
ali@418
  1227
ali@418
  1228
	return retval;
ali@418
  1229
}
ali@418
  1230
ali@418
  1231
RAZOR_EXPORT struct razor_set *
ali@418
  1232
razor_install_iterator_commit_set(struct razor_install_iterator *ii)
ali@418
  1233
{
ali@418
  1234
	struct razor_merger *merger;
ali@418
  1235
	struct razor_set *set;
ali@418
  1236
	struct razor_package *n, *nend, *npkgs, *s, *send, *spkgs;
ali@418
  1237
	struct deque *done;
ali@418
  1238
	size_t pos;
ali@418
  1239
	char *npool, *spool;
ali@418
  1240
	int cmp;
ali@418
  1241
ali@418
  1242
	done = deque_dup(ii->order);
ali@418
  1243
	pos = razor_install_iterator_tell(ii);
ali@418
  1244
	while(deque_length(done) > pos)
ali@418
  1245
		deque_shift(done);
ali@418
  1246
ali@418
  1247
	s = ii->set->packages.data;
ali@418
  1248
	spkgs = ii->set->packages.data;
ali@418
  1249
	send = ii->set->packages.data + ii->set->packages.size;
ali@418
  1250
	spool = ii->set->string_pool.data;
ali@418
  1251
ali@418
  1252
	n = ii->next->packages.data;
ali@418
  1253
	npkgs = ii->next->packages.data;
ali@418
  1254
	nend = ii->next->packages.data + ii->next->packages.size;
ali@418
  1255
	npool = ii->next->string_pool.data;
ali@418
  1256
ali@418
  1257
	merger = razor_merger_create(ii->set, ii->next);
ali@418
  1258
	while (s < send || n < nend) {
ali@418
  1259
		if (s < send && n < nend)
ali@418
  1260
			cmp = strcmp(&spool[s->name], &npool[n->name]);
ali@418
  1261
		else if (s < send)
ali@418
  1262
			cmp = -1;
ali@418
  1263
		else
ali@418
  1264
			cmp = 1;
ali@418
  1265
ali@418
  1266
		if (cmp < 0) {
ali@418
  1267
			if (!action_is_included(ii, done, s,
ali@418
  1268
						RAZOR_INSTALL_ACTION_REMOVE))
ali@418
  1269
				razor_merger_add_package(merger, s);
ali@418
  1270
			s++;
ali@418
  1271
		} else if (cmp == 0) {
ali@418
  1272
			if (!action_is_included(ii, done, s,
ali@418
  1273
						RAZOR_INSTALL_ACTION_REMOVE))
ali@418
  1274
				razor_merger_add_package(merger, s);
ali@418
  1275
			if (action_is_included(ii, done, n,
ali@418
  1276
					       RAZOR_INSTALL_ACTION_ADD))
ali@418
  1277
				razor_merger_add_package(merger, n);
ali@418
  1278
ali@418
  1279
			s++;
ali@418
  1280
			n++;
ali@418
  1281
		} else {
ali@418
  1282
			if (action_is_included(ii, done, n,
ali@418
  1283
					       RAZOR_INSTALL_ACTION_ADD))
ali@418
  1284
				razor_merger_add_package(merger, n);
ali@418
  1285
			n++;
ali@418
  1286
		}
ali@418
  1287
	}
ali@418
  1288
ali@418
  1289
	set = razor_merger_commit(merger);
ali@418
  1290
	razor_merger_destroy(merger);
ali@418
  1291
ali@418
  1292
	return set;
ali@418
  1293
}
ali@418
  1294
krh@316
  1295
RAZOR_EXPORT void
ali@403
  1296
razor_install_iterator_rewind(struct razor_install_iterator *ii)
ali@403
  1297
{
ali@403
  1298
	deque_free(ii->left);
ali@403
  1299
	ii->left=deque_dup(ii->order);
ali@403
  1300
}
ali@403
  1301
ali@418
  1302
RAZOR_EXPORT size_t
ali@418
  1303
razor_install_iterator_tell(struct razor_install_iterator *ii)
ali@418
  1304
{
ali@418
  1305
	return deque_length(ii->order) - deque_length(ii->left);
ali@418
  1306
}
ali@418
  1307
ali@418
  1308
RAZOR_EXPORT size_t
ali@418
  1309
razor_install_iterator_seek(struct razor_install_iterator *ii, size_t pos)
ali@418
  1310
{
ali@418
  1311
	size_t current_pos;
ali@418
  1312
ali@418
  1313
	if (pos > deque_length(ii->order))
ali@418
  1314
		pos = deque_length(ii->order);
ali@418
  1315
ali@418
  1316
	current_pos = razor_install_iterator_tell(ii);
ali@418
  1317
ali@418
  1318
	if (pos < current_pos) {
ali@418
  1319
		razor_install_iterator_rewind(ii);
ali@418
  1320
		current_pos = 0;
ali@418
  1321
	}
ali@418
  1322
ali@418
  1323
	while(current_pos < pos) {
ali@418
  1324
		(void) deque_pop(ii->left);
ali@418
  1325
		current_pos++;
ali@418
  1326
	}
ali@418
  1327
ali@418
  1328
	return current_pos;
ali@418
  1329
}
ali@418
  1330
ali@403
  1331
RAZOR_EXPORT void
krh@316
  1332
razor_install_iterator_destroy(struct razor_install_iterator *ii)
krh@316
  1333
{
krh@316
  1334
	array_release(&ii->actions);
ali@367
  1335
	deque_free(ii->order);
ali@403
  1336
	deque_free(ii->left);
krh@316
  1337
	free(ii);
krh@254
  1338
}