librazor/razor.c
author J. Ali Harlow <ali@juiblex.co.uk>
Thu Aug 13 07:14:51 2009 +0100 (2009-08-13)
changeset 382 4e261a14a6bd
parent 377 5549419824b4
child 383 6e73f3f08309
permissions -rw-r--r--
Basic support for update
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@369
     4
 * Copyright (C) 2009  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>
rhughes@241
    40
krh@253
    41
#include "razor-internal.h"
rhughes@241
    42
#include "razor.h"
rhughes@241
    43
ali@345
    44
#ifndef O_BINARY
ali@345
    45
#define O_BINARY	0
ali@345
    46
#endif
ali@345
    47
krh@248
    48
void *
rhughes@241
    49
zalloc(size_t size)
rhughes@241
    50
{
rhughes@241
    51
	void *p;
rhughes@241
    52
rhughes@241
    53
	p = malloc(size);
rhughes@241
    54
	memset(p, 0, size);
rhughes@241
    55
rhughes@241
    56
	return p;
rhughes@241
    57
}
rhughes@241
    58
jbowes@318
    59
struct razor_set_section_index {
jbowes@318
    60
	const char *name;
jbowes@318
    61
	uint32_t offset;
krh@373
    62
	uint32_t flags;
jbowes@318
    63
};
jbowes@318
    64
krh@373
    65
#define MAIN(type, field) \
krh@373
    66
	{ type, offsetof(struct razor_set, field), RAZOR_SECTION_MAIN }
krh@373
    67
#define FILES(type, field) \
krh@373
    68
	{ type, offsetof(struct razor_set, field), RAZOR_SECTION_FILES }
krh@373
    69
#define DETAILS(type, field) \
krh@373
    70
	{ type, offsetof(struct razor_set, field), RAZOR_SECTION_DETAILS }
krh@373
    71
jbowes@318
    72
struct razor_set_section_index razor_sections[] = {
krh@373
    73
	MAIN(RAZOR_STRING_POOL, string_pool),
krh@373
    74
	MAIN(RAZOR_PACKAGES, packages),
krh@373
    75
	MAIN(RAZOR_PROPERTIES, properties),
krh@373
    76
	MAIN(RAZOR_PACKAGE_POOL, package_pool),
krh@373
    77
	MAIN(RAZOR_PROPERTY_POOL, property_pool),
krh@373
    78
	MAIN(RAZOR_PREFIX_POOL, prefix_pool),
krh@373
    79
	FILES(RAZOR_FILES, files),
krh@373
    80
	FILES(RAZOR_FILE_POOL, file_pool),
krh@373
    81
	FILES(RAZOR_FILE_STRING_POOL, file_string_pool),
krh@373
    82
	DETAILS(RAZOR_DETAILS_STRING_POOL, details_string_pool)
jbowes@258
    83
};
krh@262
    84
krh@269
    85
RAZOR_EXPORT struct razor_set *
ali@363
    86
razor_set_create_without_root(void)
ali@363
    87
{
ali@363
    88
	struct razor_set *set;
ali@363
    89
	char *empty;
ali@363
    90
ali@363
    91
	set = zalloc(sizeof *set);
ali@363
    92
ali@363
    93
	empty = array_add(&set->string_pool, 1);
ali@363
    94
	*empty = '\0';
ali@363
    95
ali@363
    96
	return set;
ali@363
    97
}
ali@363
    98
ali@363
    99
RAZOR_EXPORT struct razor_set *
rhughes@241
   100
razor_set_create(void)
rhughes@241
   101
{
rhughes@241
   102
	struct razor_set *set;
rhughes@241
   103
	struct razor_entry *e;
rhughes@241
   104
ali@363
   105
	set = razor_set_create_without_root();
rhughes@241
   106
rhughes@241
   107
	e = array_add(&set->files, sizeof *e);
rhughes@241
   108
	e->name = 0;
rhughes@241
   109
	e->flags = RAZOR_ENTRY_LAST;
rhughes@241
   110
	e->start = 0;
rhughes@241
   111
	list_set_empty(&e->packages);
rhughes@241
   112
rhughes@241
   113
	return set;
rhughes@241
   114
}
rhughes@241
   115
krh@373
   116
struct razor_mapped_file {
krh@373
   117
	struct razor_set_header *header;
krh@373
   118
	size_t size;
krh@373
   119
	struct razor_mapped_file *next;
krh@373
   120
};
krh@373
   121
krh@373
   122
RAZOR_EXPORT int
krh@373
   123
razor_set_bind_sections(struct razor_set *set, const char *filename)
rhughes@241
   124
{
jbowes@318
   125
	struct razor_set_section *s, *sections;
krh@373
   126
	struct razor_mapped_file *file;
krh@373
   127
	const char *pool;
rhughes@241
   128
	struct array *array;
krh@373
   129
	int i, j;
richard@301
   130
krh@373
   131
	file = zalloc(sizeof *file);
krh@373
   132
	if (file == NULL)
jbowes@288
   133
		return -1;
jbowes@258
   134
krh@373
   135
	file->header = razor_file_get_contents(filename, &file->size);
krh@373
   136
	if (!file->header) {
krh@373
   137
		free(file);
krh@373
   138
		return -1;
krh@373
   139
	}
jbowes@318
   140
krh@373
   141
	file->next = set->mapped_files;
krh@373
   142
	set->mapped_files = file;
krh@373
   143
krh@373
   144
	sections = (void *) file->header + sizeof *file->header;
krh@373
   145
	pool = (void *) sections +
krh@373
   146
		file->header->num_sections * sizeof *sections;
krh@373
   147
krh@373
   148
	for (i = 0; i < file->header->num_sections; i++) {
jbowes@318
   149
		s = sections + i;
krh@373
   150
		for (j = 0; j < ARRAY_SIZE(razor_sections); j++)
krh@373
   151
			if (!strcmp(razor_sections[j].name, &pool[s->name]))
jbowes@318
   152
				break;
krh@373
   153
		if (j == ARRAY_SIZE(razor_sections))
jbowes@258
   154
			continue;
krh@373
   155
		array = (void *) set + razor_sections[j].offset;
krh@373
   156
		array->data = (void *) file->header + s->offset;
jbowes@258
   157
		array->size = s->size;
jbowes@258
   158
		array->alloc = s->size;
jbowes@258
   159
	}
jbowes@288
   160
jbowes@288
   161
	return 0;
jbowes@258
   162
}
jbowes@258
   163
jbowes@318
   164
RAZOR_EXPORT struct razor_set *
jbowes@318
   165
razor_set_open(const char *filename)
jbowes@318
   166
{
jbowes@318
   167
	struct razor_set *set;
jbowes@318
   168
jbowes@318
   169
	set = zalloc(sizeof *set);
krh@373
   170
	if (razor_set_bind_sections(set, filename)){
jbowes@318
   171
		free(set);
jbowes@318
   172
		return NULL;
jbowes@318
   173
	}
jbowes@318
   174
	return set;
jbowes@318
   175
}
jbowes@318
   176
krh@269
   177
RAZOR_EXPORT void
rhughes@241
   178
razor_set_destroy(struct razor_set *set)
rhughes@241
   179
{
krh@373
   180
	struct razor_mapped_file *file, *next;
krh@373
   181
	struct array *array;
rhughes@241
   182
	int i;
rhughes@241
   183
richard@301
   184
	assert (set != NULL);
richard@301
   185
krh@373
   186
	if (set->mapped_files == NULL) {
krh@373
   187
		for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
krh@373
   188
			array = (void *) set + razor_sections[i].offset;
krh@373
   189
			array_release(array);
krh@373
   190
		}
rhughes@241
   191
	} else {
krh@373
   192
		for (file = set->mapped_files; file != NULL; file = next) {
krh@373
   193
			next = file->next;
krh@373
   194
			razor_file_free_contents(file->header, file->size);
krh@373
   195
			free(file);
jbowes@258
   196
		}
jbowes@258
   197
	}
jbowes@258
   198
rhughes@241
   199
	free(set);
rhughes@241
   200
}
rhughes@241
   201
krh@373
   202
RAZOR_EXPORT int
krh@373
   203
razor_set_write_to_fd(struct razor_set *set, int fd, uint32_t section_mask)
rhughes@241
   204
{
jbowes@318
   205
	struct razor_set_header header;
krh@373
   206
	struct razor_set_section sections[ARRAY_SIZE(razor_sections)];
jbowes@318
   207
	struct hashtable table;
krh@373
   208
	struct array pool, *arrays[ARRAY_SIZE(razor_sections)];
rhughes@241
   209
	uint32_t offset;
krh@373
   210
	int count, i, j;
krh@373
   211
	static const char padding[4];
jbowes@318
   212
jbowes@318
   213
	array_init(&pool);
jbowes@318
   214
	hashtable_init(&table, &pool);
jbowes@318
   215
krh@373
   216
	j = 0;
krh@373
   217
	for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
krh@373
   218
		if ((razor_sections[i].flags & section_mask) == 0)
krh@373
   219
			continue;
jbowes@318
   220
krh@373
   221
		arrays[j] = (void *) set + razor_sections[i].offset;
krh@373
   222
		sections[j].name =
krh@373
   223
			hashtable_tokenize(&table, razor_sections[i].name);
krh@373
   224
		j++;
krh@373
   225
	}
rhughes@241
   226
krh@373
   227
	count = j;
krh@373
   228
	header.magic = RAZOR_MAGIC;
krh@373
   229
	header.version = RAZOR_VERSION;
krh@373
   230
	header.num_sections = count;
krh@373
   231
	offset = sizeof header + count * sizeof *sections + ALIGN(pool.size, 4);
krh@373
   232
krh@373
   233
	for (i = 0; i < count; i++) {
krh@373
   234
		sections[i].offset = offset;
krh@373
   235
		sections[i].size = arrays[i]->size;
krh@373
   236
		offset += ALIGN(arrays[i]->size, 4);
rhughes@241
   237
	}
rhughes@241
   238
jbowes@318
   239
	razor_write(fd, &header, sizeof header);
krh@373
   240
	razor_write(fd, sections, count * sizeof *sections);
jbowes@318
   241
	razor_write(fd, pool.data, pool.size);
krh@373
   242
	razor_write(fd, padding, PADDING(pool.size, 4));
rhughes@241
   243
krh@373
   244
	for (i = 0; i < count; i++) {
krh@373
   245
		razor_write(fd, arrays[i]->data, arrays[i]->size);
krh@373
   246
		razor_write(fd, padding, PADDING(arrays[i]->size, 4));
rhughes@241
   247
	}
rhughes@241
   248
krh@373
   249
	array_release(&pool);
krh@373
   250
	hashtable_release(&table);
jbowes@318
   251
rhughes@241
   252
	return 0;
rhughes@241
   253
}
rhughes@241
   254
krh@269
   255
RAZOR_EXPORT int
krh@373
   256
razor_set_write(struct razor_set *set, const char *filename, uint32_t sections)
rhughes@241
   257
{
rhughes@241
   258
	int fd, status;
rhughes@241
   259
ali@345
   260
	fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY, 0666);
rhughes@241
   261
	if (fd < 0)
rhughes@241
   262
		return -1;
rhughes@241
   263
krh@373
   264
	status = razor_set_write_to_fd(set, fd, sections);
rhughes@241
   265
	if (status) {
rhughes@241
   266
	    close(fd);
rhughes@241
   267
	    return status;
rhughes@241
   268
	}
rhughes@241
   269
rhughes@241
   270
	return close(fd);
rhughes@241
   271
}
krh@269
   272
krh@269
   273
RAZOR_EXPORT void
rhughes@241
   274
razor_build_evr(char *evr_buf, int size, const char *epoch,
rhughes@241
   275
		const char *version, const char *release)
rhughes@241
   276
{
rhughes@241
   277
	int len;
rhughes@241
   278
rhughes@241
   279
	if (!version || !*version) {
rhughes@241
   280
		*evr_buf = '\0';
rhughes@241
   281
		return;
rhughes@241
   282
	}
rhughes@241
   283
rhughes@241
   284
	if (epoch && *epoch && strcmp(epoch, "0") != 0) {
rhughes@241
   285
		len = snprintf(evr_buf, size, "%s:", epoch);
rhughes@241
   286
		evr_buf += len;
rhughes@241
   287
		size -= len;
rhughes@241
   288
	}
rhughes@241
   289
	len = snprintf(evr_buf, size, "%s", version);
rhughes@241
   290
	evr_buf += len;
rhughes@241
   291
	size -= len;
rhughes@241
   292
	if (release && *release)
rhughes@241
   293
		snprintf(evr_buf, size, "-%s", release);
rhughes@241
   294
}
rhughes@241
   295
krh@269
   296
RAZOR_EXPORT int
krh@248
   297
razor_versioncmp(const char *s1, const char *s2)
rhughes@241
   298
{
rhughes@241
   299
	const char *p1, *p2;
rhughes@241
   300
	long n1, n2;
rhughes@241
   301
	int res;
rhughes@241
   302
richard@301
   303
	assert (s1 != NULL);
richard@301
   304
	assert (s2 != NULL);
richard@301
   305
rhughes@241
   306
	n1 = strtol(s1, (char **) &p1, 10);
rhughes@241
   307
	n2 = strtol(s2, (char **) &p2, 10);
rhughes@241
   308
rhughes@241
   309
	/* Epoch; if one but not the other has an epoch set, default
rhughes@241
   310
	 * the epoch-less version to 0. */
rhughes@241
   311
	res = (*p1 == ':') - (*p2 == ':');
rhughes@241
   312
	if (res < 0) {
rhughes@241
   313
		n1 = 0;
rhughes@241
   314
		p1 = s1;
rhughes@241
   315
		p2++;
rhughes@241
   316
	} else if (res > 0) {
rhughes@241
   317
		p1++;
rhughes@241
   318
		n2 = 0;
rhughes@241
   319
		p2 = s2;
rhughes@241
   320
	}
rhughes@241
   321
rhughes@241
   322
	if (n1 != n2)
rhughes@241
   323
		return n1 - n2;
rhughes@241
   324
	while (*p1 && *p2) {
rhughes@241
   325
		if (*p1 != *p2)
rhughes@241
   326
			return *p1 - *p2;
rhughes@241
   327
		p1++;
rhughes@241
   328
		p2++;
rhughes@241
   329
		if (isdigit(*p1) && isdigit(*p2))
krh@248
   330
			return razor_versioncmp(p1, p2);
rhughes@241
   331
	}
rhughes@241
   332
rhughes@241
   333
	return *p1 - *p2;
rhughes@241
   334
}
rhughes@241
   335
richard@302
   336
static const char *
ali@372
   337
razor_package_get_details_string(struct razor_set *set,
ali@372
   338
				 struct razor_package *package,
ali@372
   339
				 enum razor_detail_type type)
richard@302
   340
{
richard@302
   341
	const char *pool;
richard@302
   342
richard@302
   343
	switch (type) {
richard@302
   344
	case RAZOR_DETAIL_NAME:
richard@302
   345
		pool = set->string_pool.data;
richard@302
   346
		return &pool[package->name];
richard@302
   347
richard@302
   348
	case RAZOR_DETAIL_VERSION:
richard@302
   349
		pool = set->string_pool.data;
richard@302
   350
		return &pool[package->version];
richard@302
   351
richard@302
   352
	case RAZOR_DETAIL_ARCH:
richard@302
   353
		pool = set->string_pool.data;
richard@302
   354
		return &pool[package->arch];
richard@302
   355
richard@302
   356
	case RAZOR_DETAIL_SUMMARY:
richard@302
   357
		pool = set->details_string_pool.data;
richard@302
   358
		return &pool[package->summary];
richard@302
   359
richard@302
   360
	case RAZOR_DETAIL_DESCRIPTION:
richard@302
   361
		pool = set->details_string_pool.data;
richard@302
   362
		return &pool[package->description];
richard@302
   363
richard@302
   364
	case RAZOR_DETAIL_URL:
richard@302
   365
		pool = set->details_string_pool.data;
richard@302
   366
		return &pool[package->url];
richard@302
   367
richard@302
   368
	case RAZOR_DETAIL_LICENSE:
richard@302
   369
		pool = set->details_string_pool.data;
richard@302
   370
		return &pool[package->license];
richard@302
   371
ali@369
   372
	case RAZOR_DETAIL_PREUNPROG:
ali@369
   373
		pool = set->string_pool.data;
ali@369
   374
		return &pool[package->preun.program];
ali@369
   375
ali@369
   376
	case RAZOR_DETAIL_PREUN:
ali@369
   377
		pool = set->string_pool.data;
ali@369
   378
		return &pool[package->preun.body];
ali@369
   379
ali@369
   380
	case RAZOR_DETAIL_POSTUNPROG:
ali@369
   381
		pool = set->string_pool.data;
ali@369
   382
		return &pool[package->postun.program];
ali@369
   383
ali@369
   384
	case RAZOR_DETAIL_POSTUN:
ali@369
   385
		pool = set->string_pool.data;
ali@369
   386
		return &pool[package->postun.body];
ali@369
   387
richard@302
   388
	default:
richard@302
   389
		fprintf(stderr, "type %u not found\n", type);
richard@302
   390
		return NULL;
richard@302
   391
	}
richard@302
   392
}
richard@302
   393
ali@372
   394
static const char *const *
ali@372
   395
razor_package_get_details_array(struct razor_set *set,
ali@372
   396
				struct razor_package *package,
ali@372
   397
				enum razor_detail_type type)
ali@372
   398
{
ali@372
   399
	switch (type) {
ali@372
   400
	case RAZOR_DETAIL_PREFIXES:
ali@372
   401
		/* We don't track prefixes in packages. Install prefixes
ali@372
   402
		 * are tracked, but we don't provide an API to get them.
ali@372
   403
		 */
ali@372
   404
		return NULL;
ali@372
   405
ali@372
   406
	default:
ali@372
   407
		fprintf(stderr, "type %u not found\n", type);
ali@372
   408
		return NULL;
ali@372
   409
	}
ali@372
   410
}
ali@372
   411
richard@302
   412
/**
richard@302
   413
 * razor_package_get_details_varg:
richard@302
   414
 * @set: a %razor_set
richard@302
   415
 * @package: a %razor_package
richard@302
   416
 * @args: a va_list of arguments to set
richard@302
   417
 **/
richard@302
   418
void
richard@302
   419
razor_package_get_details_varg(struct razor_set *set,
richard@302
   420
			       struct razor_package *package,
richard@302
   421
			       va_list args)
richard@302
   422
{
richard@302
   423
	int i;
richard@302
   424
	enum razor_detail_type type;
ali@372
   425
	const char **string;
ali@372
   426
	const char *const **array;
richard@302
   427
richard@302
   428
	for (i = 0;; i += 2) {
richard@302
   429
		type = va_arg(args, enum razor_detail_type);
richard@307
   430
		if (type == RAZOR_DETAIL_LAST)
richard@302
   431
			break;
ali@372
   432
		if (type == RAZOR_DETAIL_PREFIXES) {
ali@372
   433
			array = va_arg(args, const char *const **);
ali@372
   434
			*array = razor_package_get_details_array(set, package,
ali@372
   435
								 type);
ali@372
   436
		} else {
ali@372
   437
			string = va_arg(args, const char **);
ali@372
   438
			*string = razor_package_get_details_string(set, package,
ali@372
   439
								   type);
ali@372
   440
		}
richard@302
   441
	}
richard@302
   442
richard@302
   443
}
richard@302
   444
richard@302
   445
/**
richard@302
   446
 * razor_package_get_details:
richard@302
   447
 * @set: a %razor_set
richard@302
   448
 * @package: a %razor_package
richard@302
   449
 *
richard@302
   450
 * Gets details about a package using a varg interface
krh@308
   451
 * The vararg must be terminated with %RAZOR_DETAIL_LAST.
richard@302
   452
 *
richard@307
   453
 * Example: razor_package_get_details (set, package,
richard@307
   454
 *				       RAZOR_DETAIL_URL, &url,
richard@307
   455
 *				       RAZOR_DETAIL_LAST);
richard@302
   456
 **/
krh@269
   457
RAZOR_EXPORT void
richard@302
   458
razor_package_get_details(struct razor_set *set, struct razor_package *package, ...)
jbowes@258
   459
{
richard@302
   460
	va_list args;
jbowes@258
   461
richard@301
   462
	assert (set != NULL);
richard@301
   463
	assert (package != NULL);
richard@301
   464
richard@302
   465
	va_start(args, NULL);
richard@302
   466
	razor_package_get_details_varg (set, package, args);
richard@302
   467
	va_end (args);
jbowes@258
   468
}
jbowes@258
   469
ali@369
   470
/**
ali@369
   471
 * razor_package_remove:
ali@382
   472
 * @prev: The %razor_set before the current transaction
ali@382
   473
 * @next: The %razor_set after the current transaction is applied
ali@369
   474
 * @package: a %razor_package
ali@369
   475
 * @root: the root into which the package is currently installed
ali@376
   476
 * @install_count: the value to pass to uninstall scripts
ali@369
   477
 *
ali@369
   478
 * Removes an installed package.
ali@369
   479
 **/
ali@369
   480
RAZOR_EXPORT int
ali@382
   481
razor_package_remove(struct razor_set *prev, struct razor_set *next,
ali@382
   482
		     struct razor_package *package, const char *root,
ali@382
   483
		     int install_count)
ali@369
   484
{
ali@369
   485
	struct razor_file_iterator *fi;
ali@369
   486
	struct razor_package_iterator *pi;
ali@369
   487
	struct razor_package *p;
ali@369
   488
	char buffer[PATH_MAX];
ali@369
   489
	const char *name, *program, *script;
ali@372
   490
	int retval = 0, i, count;
ali@372
   491
	struct environment env;
ali@372
   492
	struct list *link;
ali@372
   493
	const char *prefix;
ali@369
   494
ali@375
   495
	environment_init(&env);
ali@382
   496
	link = list_first(&package->install_prefixes, &prev->prefix_pool);
ali@375
   497
	for (i = 0; link; i++) {
ali@382
   498
		prefix = (const char *)prev->string_pool.data + link->data;
ali@375
   499
		sprintf(buffer, "RPM_INSTALL_PREFIX%d", i);
ali@375
   500
		environment_add_variable(&env, buffer, prefix);
ali@375
   501
		link = list_next(link);
ali@375
   502
	}
ali@377
   503
	environment_set(&env);
ali@375
   504
ali@382
   505
	razor_package_get_details(prev, package,
ali@369
   506
				  RAZOR_DETAIL_PREUNPROG, &program,
ali@369
   507
				  RAZOR_DETAIL_PREUN, &script,
ali@369
   508
				  RAZOR_DETAIL_LAST);
ali@369
   509
ali@376
   510
	retval = razor_run_script(root, RAZOR_PROPERTY_PREUN, program, script,
ali@376
   511
				  install_count);
ali@375
   512
ali@382
   513
	fi = razor_file_iterator_create(prev, package, 1);
ali@369
   514
ali@377
   515
	while (razor_file_iterator_next(fi, &name)) {
ali@382
   516
		pi = razor_package_iterator_create_for_file(next, name);
ali@369
   517
		count = 0;
ali@369
   518
		while (razor_package_iterator_next(pi, &p, RAZOR_DETAIL_LAST))
ali@369
   519
			count++;
ali@369
   520
		razor_package_iterator_destroy(pi);
ali@382
   521
		if (count <= 0) {
ali@369
   522
			snprintf(buffer, sizeof buffer, "%s%s", root, name);
ali@377
   523
			if (razor_remove(buffer) && errno != ENOENT) {
ali@377
   524
				perror(name);
ali@377
   525
				retval = -1;
ali@377
   526
			}
ali@369
   527
		}
ali@369
   528
	}
ali@369
   529
ali@369
   530
	razor_file_iterator_destroy(fi);
ali@369
   531
ali@382
   532
	razor_package_get_details(prev, package,
ali@369
   533
				  RAZOR_DETAIL_POSTUNPROG, &program,
ali@369
   534
				  RAZOR_DETAIL_POSTUN, &script,
ali@369
   535
				  RAZOR_DETAIL_LAST);
ali@369
   536
ali@377
   537
	if (razor_run_script(root, RAZOR_PROPERTY_POSTUN, program, script,
ali@377
   538
			     install_count))
ali@377
   539
		retval = -1;
ali@377
   540
ali@375
   541
	environment_unset(&env);
ali@372
   542
	environment_release(&env);
ali@372
   543
ali@372
   544
	return retval;
ali@369
   545
}
ali@369
   546
krh@270
   547
RAZOR_EXPORT const char *
krh@270
   548
razor_property_relation_to_string(struct razor_property *p)
krh@270
   549
{
richard@301
   550
	assert (p != NULL);
richard@301
   551
krh@270
   552
	switch (p->flags & RAZOR_PROPERTY_RELATION_MASK) {
krh@270
   553
	case RAZOR_PROPERTY_LESS:
krh@270
   554
		return "<";
krh@270
   555
krh@270
   556
	case RAZOR_PROPERTY_LESS | RAZOR_PROPERTY_EQUAL:
krh@270
   557
		return "<=";
krh@270
   558
krh@270
   559
	case RAZOR_PROPERTY_EQUAL:
krh@270
   560
		return "=";
krh@270
   561
krh@270
   562
	case RAZOR_PROPERTY_GREATER | RAZOR_PROPERTY_EQUAL:
krh@270
   563
		return ">=";
krh@270
   564
krh@270
   565
	case RAZOR_PROPERTY_GREATER:
krh@270
   566
		return ">";
krh@270
   567
krh@270
   568
	default:
krh@270
   569
		return "?";
krh@270
   570
	}
krh@270
   571
}
krh@270
   572
krh@270
   573
RAZOR_EXPORT const char *
krh@270
   574
razor_property_type_to_string(struct razor_property *p)
krh@270
   575
{
richard@301
   576
	assert (p != NULL);
richard@301
   577
krh@270
   578
	switch (p->flags & RAZOR_PROPERTY_TYPE_MASK) {
krh@270
   579
	case RAZOR_PROPERTY_REQUIRES:
krh@270
   580
		return "requires";
krh@270
   581
	case RAZOR_PROPERTY_PROVIDES:
krh@270
   582
		return "provides";
krh@270
   583
	case RAZOR_PROPERTY_CONFLICTS:
krh@270
   584
		return "conflicts";
krh@270
   585
	case RAZOR_PROPERTY_OBSOLETES:
krh@270
   586
		return "obsoletes";
krh@270
   587
	default:
krh@270
   588
		return NULL;
krh@270
   589
	}
krh@270
   590
}
krh@270
   591
krh@269
   592
RAZOR_EXPORT struct razor_entry *
krh@248
   593
razor_set_find_entry(struct razor_set *set,
krh@248
   594
		     struct razor_entry *dir, const char *pattern)
rhughes@241
   595
{
ali@359
   596
	struct razor_entry *e, *subdir;
jbowes@264
   597
	const char *n, *pool = set->file_string_pool.data;
rhughes@241
   598
	int len;
rhughes@241
   599
richard@301
   600
	assert (set != NULL);
richard@301
   601
	assert (dir != NULL);
richard@301
   602
	assert (pattern != NULL);
richard@301
   603
ali@359
   604
	e = dir;
rhughes@241
   605
	do {
rhughes@241
   606
		n = pool + e->name;
ali@359
   607
		if (strcmp(pattern, n) == 0)
rhughes@241
   608
			return e;
rhughes@241
   609
		len = strlen(n);
ali@359
   610
		if (e->start != 0 && strncmp(pattern, n, len) == 0 &&
ali@359
   611
		    pattern[len] == '/') {
ali@359
   612
			subdir = (struct razor_entry *) set->files.data +
ali@359
   613
				 e->start;
ali@359
   614
			return razor_set_find_entry(set, subdir,
ali@359
   615
						    pattern + len + 1);
rhughes@241
   616
		}
rhughes@241
   617
	} while (!((e++)->flags & RAZOR_ENTRY_LAST));
rhughes@241
   618
rhughes@241
   619
	return NULL;
rhughes@241
   620
}
rhughes@241
   621
rhughes@241
   622
static void
rhughes@241
   623
list_dir(struct razor_set *set, struct razor_entry *dir,
rhughes@241
   624
	 char *prefix, const char *pattern)
rhughes@241
   625
{
ali@359
   626
	struct razor_entry *e, *subdir;
jbowes@274
   627
	const char *n, *pool = set->file_string_pool.data;
rhughes@241
   628
ali@359
   629
	e = dir;
rhughes@241
   630
	do {
rhughes@241
   631
		n = pool + e->name;
rhughes@241
   632
		if (pattern && pattern[0] && fnmatch(pattern, n, 0) != 0)
rhughes@241
   633
			continue;
rhughes@241
   634
		printf("%s/%s\n", prefix, n);
rhughes@241
   635
		if (e->start) {
rhughes@241
   636
			char *sub = prefix + strlen (prefix);
rhughes@241
   637
			*sub = '/';
rhughes@241
   638
			strcpy (sub + 1, n);
ali@359
   639
			subdir = (struct razor_entry *) set->files.data +
ali@359
   640
				 e->start;
ali@359
   641
			list_dir(set, subdir, prefix, pattern);
rhughes@241
   642
			*sub = '\0';
rhughes@241
   643
		}
rhughes@241
   644
	} while (!((e++)->flags & RAZOR_ENTRY_LAST));
rhughes@241
   645
}
rhughes@241
   646
krh@269
   647
RAZOR_EXPORT void
rhughes@241
   648
razor_set_list_files(struct razor_set *set, const char *pattern)
rhughes@241
   649
{
ali@359
   650
	struct razor_entry *root, *e;
rhughes@241
   651
	char buffer[512], *p, *base;
rhughes@241
   652
richard@301
   653
	assert (set != NULL);
richard@301
   654
ali@359
   655
	root = (struct razor_entry *) set->files.data;
ali@359
   656
ali@359
   657
	if (pattern == NULL) {
ali@359
   658
		p = set->file_string_pool.data;
ali@359
   659
		e = root;
ali@359
   660
		do {
ali@359
   661
			if (e->start) {
ali@359
   662
				strcpy(buffer, p + e->name);
ali@359
   663
				list_dir(set, root + e->start, buffer, NULL);
ali@359
   664
			}
ali@359
   665
		} while (!((e++)->flags & RAZOR_ENTRY_LAST));
rhughes@241
   666
		return;
rhughes@241
   667
	}
rhughes@241
   668
rhughes@241
   669
	strcpy(buffer, pattern);
ali@359
   670
	e = razor_set_find_entry(set, root, buffer);
ali@359
   671
	if (e && e->start) {
rhughes@241
   672
		base = NULL;
rhughes@241
   673
	} else {
rhughes@241
   674
		p = strrchr(buffer, '/');
rhughes@241
   675
		if (p) {
rhughes@241
   676
			*p = '\0';
rhughes@241
   677
			base = p + 1;
rhughes@241
   678
		} else {
rhughes@241
   679
			base = NULL;
rhughes@241
   680
		}
rhughes@241
   681
	}
ali@359
   682
	e = razor_set_find_entry(set, root, buffer);
ali@359
   683
	if (e && e->start)
ali@359
   684
		list_dir(set, root + e->start, buffer, base);
rhughes@241
   685
}
rhughes@241
   686
krh@269
   687
RAZOR_EXPORT void
krh@306
   688
razor_set_list_package_files(struct razor_set *set,
krh@306
   689
			     struct razor_package *package)
rhughes@241
   690
{
ali@351
   691
	struct razor_file_iterator *fi;
ali@351
   692
	const char *name;
rhughes@241
   693
richard@301
   694
	assert (set != NULL);
krh@306
   695
	assert (package != NULL);
rhughes@241
   696
ali@377
   697
	fi = razor_file_iterator_create(set, package, 0);
ali@351
   698
ali@351
   699
	while (razor_file_iterator_next(fi, &name))
ali@351
   700
		printf("%s\n", name);
ali@351
   701
ali@351
   702
	razor_file_iterator_destroy(fi);
rhughes@241
   703
}
rhughes@241
   704
krh@269
   705
RAZOR_EXPORT void
rhughes@241
   706
razor_set_diff(struct razor_set *set, struct razor_set *upstream,
krh@253
   707
	       razor_diff_callback_t callback, void *data)
rhughes@241
   708
{
rhughes@241
   709
 	struct razor_package_iterator *pi1, *pi2;
rhughes@241
   710
 	struct razor_package *p1, *p2;
rhughes@241
   711
	const char *name1, *name2, *version1, *version2, *arch1, *arch2;
rhughes@241
   712
	int res;
rhughes@241
   713
richard@301
   714
	assert (set != NULL);
richard@301
   715
	assert (upstream != NULL);
richard@301
   716
rhughes@241
   717
	pi1 = razor_package_iterator_create(set);
rhughes@241
   718
	pi2 = razor_package_iterator_create(upstream);
rhughes@241
   719
richard@302
   720
	razor_package_iterator_next(pi1, &p1,
richard@302
   721
				    RAZOR_DETAIL_NAME, &name1,
richard@302
   722
				    RAZOR_DETAIL_VERSION, &version1,
richard@302
   723
				    RAZOR_DETAIL_ARCH, &arch1,
richard@307
   724
				    RAZOR_DETAIL_LAST);
richard@302
   725
	razor_package_iterator_next(pi2, &p2,
richard@302
   726
				    RAZOR_DETAIL_NAME, &name2,
richard@302
   727
				    RAZOR_DETAIL_VERSION, &version2,
richard@302
   728
				    RAZOR_DETAIL_ARCH, &arch2,
richard@307
   729
				    RAZOR_DETAIL_LAST);
rhughes@241
   730
rhughes@241
   731
	while (p1 || p2) {
rhughes@241
   732
		if (p1 && p2) {
rhughes@241
   733
			res = strcmp(name1, name2);
rhughes@241
   734
			if (res == 0)
krh@248
   735
				res = razor_versioncmp(version1, version2);
rhughes@241
   736
		} else {
rhughes@241
   737
			res = 0;
rhughes@241
   738
		}
rhughes@241
   739
rhughes@241
   740
		if (p2 == NULL || res < 0)
krh@253
   741
			callback(RAZOR_DIFF_ACTION_REMOVE,
krh@253
   742
				 p1, name1, version1, arch1, data);
rhughes@241
   743
		else if (p1 == NULL || res > 0)
krh@253
   744
			callback(RAZOR_DIFF_ACTION_ADD,
krh@253
   745
				 p2, name2, version2, arch2, data);
rhughes@241
   746
rhughes@241
   747
		if (p1 != NULL && res <= 0)
rhughes@241
   748
			razor_package_iterator_next(pi1, &p1,
richard@302
   749
						    RAZOR_DETAIL_NAME, &name1,
richard@302
   750
						    RAZOR_DETAIL_VERSION, &version1,
richard@302
   751
						    RAZOR_DETAIL_ARCH, &arch1,
richard@307
   752
						    RAZOR_DETAIL_LAST);
rhughes@241
   753
		if (p2 != NULL && res >= 0)
rhughes@241
   754
			razor_package_iterator_next(pi2, &p2,
richard@302
   755
						    RAZOR_DETAIL_NAME, &name2,
richard@302
   756
						    RAZOR_DETAIL_VERSION, &version2,
richard@302
   757
						    RAZOR_DETAIL_ARCH, &arch2,
richard@307
   758
						    RAZOR_DETAIL_LAST);
rhughes@241
   759
	}
rhughes@241
   760
rhughes@241
   761
	razor_package_iterator_destroy(pi1);
rhughes@241
   762
	razor_package_iterator_destroy(pi2);
rhughes@241
   763
}
krh@254
   764
krh@316
   765
struct install_action {
krh@316
   766
	enum razor_install_action action;
krh@316
   767
	struct razor_package *package;
krh@316
   768
};
krh@316
   769
krh@316
   770
struct razor_install_iterator {
krh@316
   771
	struct razor_set *set;
krh@316
   772
	struct razor_set *next;
krh@316
   773
	struct array actions;
ali@367
   774
	struct deque *order;
krh@316
   775
};
krh@316
   776
krh@254
   777
static void
krh@316
   778
add_action(enum razor_diff_action action,
krh@316
   779
	   struct razor_package *package,
krh@316
   780
	   const char *name,
krh@316
   781
	   const char *version,
krh@316
   782
	   const char *arch,
krh@316
   783
	   void *data)
krh@254
   784
{
krh@316
   785
	struct razor_install_iterator *ii = data;
krh@316
   786
	struct install_action *a;
krh@316
   787
krh@316
   788
	a = array_add(&ii->actions, sizeof *a);
krh@316
   789
	a->package = package;
krh@316
   790
krh@316
   791
	switch (action) {
krh@316
   792
	case RAZOR_DIFF_ACTION_ADD:
krh@316
   793
		a->action = RAZOR_INSTALL_ACTION_ADD;
krh@316
   794
		break;
krh@316
   795
	case RAZOR_DIFF_ACTION_REMOVE:
krh@316
   796
		a->action = RAZOR_INSTALL_ACTION_REMOVE;
krh@316
   797
		break;
krh@316
   798
	}
krh@254
   799
}
krh@254
   800
krh@316
   801
RAZOR_EXPORT struct razor_install_iterator *
krh@316
   802
razor_set_create_install_iterator(struct razor_set *set,
krh@316
   803
				  struct razor_set *next)
krh@254
   804
{
krh@316
   805
	struct razor_install_iterator *ii;
ali@367
   806
	struct razor_property *prop;
ali@367
   807
	/* A graph of the actions to be perfomed where
ali@367
   808
	 * A->B means action A should follow action B.
ali@367
   809
	 */
ali@367
   810
	struct graph follows;
ali@367
   811
	struct install_action *actions, *ai, *aj;
ali@367
   812
	int i, j, count, vertex_added;
ali@367
   813
	struct list *link;
ali@367
   814
	struct razor_set *rs;
krh@254
   815
richard@301
   816
	assert (set != NULL);
richard@301
   817
	assert (next != NULL);
richard@301
   818
krh@316
   819
	ii = zalloc(sizeof *ii);
krh@316
   820
	ii->set = set;
krh@316
   821
	ii->next = next;
krh@316
   822
	
krh@316
   823
	razor_set_diff(set, next, add_action, ii);
krh@254
   824
ali@367
   825
	actions = ii->actions.data;
ali@367
   826
	count = ii->actions.size / sizeof (struct install_action);
krh@254
   827
ali@367
   828
	graph_init(&follows);
ali@367
   829
ali@367
   830
	for(i = 0; i < count; i++) {
ali@367
   831
		ai = actions + i;
ali@367
   832
		rs = ai->action == RAZOR_INSTALL_ACTION_ADD ? next : set;
ali@367
   833
		vertex_added = 0;
ali@367
   834
		link = list_first(&ai->package->properties, &rs->property_pool);
ali@367
   835
		for(; link; link = list_next(link)) {
ali@367
   836
			prop = rs->properties.data;
ali@367
   837
			prop += link->data;
ali@367
   838
			switch(prop->flags & RAZOR_PROPERTY_TYPE_MASK) {
ali@367
   839
			case RAZOR_PROPERTY_REQUIRES:
ali@367
   840
			case RAZOR_PROPERTY_CONFLICTS:
ali@367
   841
				for(j = 0; j < count; j++) {
ali@367
   842
					if (j == i)
ali@367
   843
						continue;
ali@367
   844
					aj = actions + j;
ali@367
   845
					if (aj->package->name == prop->name) {
ali@367
   846
						if (ai->action ==
ali@367
   847
						    RAZOR_INSTALL_ACTION_ADD)
ali@367
   848
							graph_add_edge(&follows,
ali@367
   849
								       i, j);
ali@367
   850
						else
ali@367
   851
							graph_add_edge(&follows,
ali@367
   852
								       j, i);
ali@367
   853
						vertex_added++;
ali@367
   854
					}
ali@367
   855
				}
ali@367
   856
				break;
ali@367
   857
			}
ali@367
   858
		}
ali@367
   859
		if (ai->action == RAZOR_INSTALL_ACTION_ADD) {
ali@367
   860
			for(j = 0; j < count; j++) {
ali@367
   861
				if (j == i)
ali@367
   862
					continue;
ali@367
   863
				aj = actions + j;
ali@367
   864
				if (aj->package == ai->package &&
ali@367
   865
				    aj->action == RAZOR_INSTALL_ACTION_REMOVE) {
ali@367
   866
					graph_add_edge(&follows, i, j);
ali@367
   867
					vertex_added++;
ali@367
   868
				}
ali@367
   869
			}
ali@367
   870
		}
ali@367
   871
		if (!vertex_added)
ali@367
   872
			graph_add_edge(&follows, i, i);
ali@367
   873
	}
ali@367
   874
ali@367
   875
	ii->order = graph_sort(&follows);
ali@367
   876
	graph_release(&follows);
krh@254
   877
krh@316
   878
	return ii;
krh@254
   879
}
krh@254
   880
krh@316
   881
RAZOR_EXPORT int
krh@316
   882
razor_install_iterator_next(struct razor_install_iterator *ii,
krh@316
   883
			    struct razor_package **package,
krh@316
   884
			    enum razor_install_action *action,
krh@316
   885
			    int *count)
krh@254
   886
{
ali@367
   887
	struct install_action *a;
ali@382
   888
	struct razor_package_iterator *pi;
ali@382
   889
	struct razor_package *pkg;
ali@382
   890
	const char *removing, *name;
ali@382
   891
ali@367
   892
	if (deque_empty(ii->order))
krh@316
   893
		return 0;
krh@254
   894
ali@367
   895
	a = (struct install_action *)ii->actions.data + deque_pop(ii->order);
ali@367
   896
	*package = a->package;
ali@367
   897
	*action = a->action;
krh@316
   898
	*count = 0;
krh@254
   899
ali@382
   900
	if (a->action == RAZOR_INSTALL_ACTION_REMOVE) {
ali@382
   901
		razor_package_get_details(ii->set, a->package,
ali@382
   902
					  RAZOR_DETAIL_NAME, &removing,
ali@382
   903
					  RAZOR_DETAIL_LAST);
ali@382
   904
ali@382
   905
		pi = razor_package_iterator_create(ii->next);
ali@382
   906
		while (razor_package_iterator_next(pi, &pkg,
ali@382
   907
						   RAZOR_DETAIL_NAME, &name,
ali@382
   908
						   RAZOR_DETAIL_LAST)) {
ali@382
   909
			if (!strcmp(name, removing))
ali@382
   910
				(*count)++;
ali@382
   911
		}
ali@382
   912
		razor_package_iterator_destroy(pi);
ali@382
   913
	}
ali@382
   914
krh@316
   915
	return 1;
krh@316
   916
}
krh@254
   917
krh@316
   918
RAZOR_EXPORT void
krh@316
   919
razor_install_iterator_destroy(struct razor_install_iterator *ii)
krh@316
   920
{
krh@316
   921
	array_release(&ii->actions);
ali@367
   922
	deque_free(ii->order);
krh@316
   923
	free(ii);
krh@254
   924
}