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

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