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