rpm.c
author Dan Winship <danw@gnome.org>
Fri Feb 29 12:45:08 2008 -0500 (2008-02-29)
changeset 138 49deac048d07
parent 91 6884cefd1b8c
child 143 59a9513fac54
permissions -rw-r--r--
implement file dependencies for installs

removes are trickier because there are no backlinks from the files array
the properties array, so there's currently no way to efficiently determine
what packages are affected by the removal of a particular file
krh@74
     1
#include <stdio.h>
krh@84
     2
#include <stddef.h>
krh@74
     3
#include <string.h>
krh@74
     4
#include <sys/stat.h>
krh@74
     5
#include <sys/mman.h>
krh@85
     6
#include <sys/types.h>
krh@85
     7
#include <sys/wait.h>
krh@74
     8
#include <fcntl.h>
krh@74
     9
#include <unistd.h>
krh@74
    10
#include <arpa/inet.h>
krh@74
    11
#include <rpm/rpmlib.h>
danw@109
    12
#include <rpm/rpmdb.h>
krh@77
    13
#include <zlib.h>
krh@74
    14
krh@75
    15
#include "razor.h"
krh@91
    16
#include "razor-internal.h"
krh@75
    17
krh@74
    18
#define	RPM_LEAD_SIZE 96
krh@74
    19
krh@74
    20
struct rpm_header {
krh@74
    21
	unsigned char magic[4];
krh@74
    22
	unsigned char reserved[4];
krh@74
    23
	int nindex;
krh@74
    24
	int hsize;
krh@74
    25
};
krh@74
    26
krh@74
    27
struct rpm_header_index {
krh@74
    28
	int tag;
krh@74
    29
	int type;
krh@74
    30
	int offset;
krh@74
    31
	int count;
krh@74
    32
};
krh@74
    33
krh@77
    34
struct razor_rpm {
krh@75
    35
	struct rpm_header *signature;
krh@75
    36
	struct rpm_header *header;
krh@77
    37
	const char **dirs;
krh@75
    38
	const char *pool;
krh@75
    39
	void *map;
krh@75
    40
	size_t size;
krh@77
    41
	void *payload;
krh@75
    42
};
krh@75
    43
krh@85
    44
static struct rpm_header_index *
krh@85
    45
razor_rpm_get_header(struct razor_rpm *rpm, unsigned int tag)
krh@85
    46
{
krh@85
    47
	struct rpm_header_index *index, *end;
krh@85
    48
krh@85
    49
	index = (struct rpm_header_index *) (rpm->header + 1);
krh@85
    50
	end = index + ntohl(rpm->header->nindex);
krh@85
    51
	while (index < end) {
krh@85
    52
		if (ntohl(index->tag) == tag)
krh@85
    53
			return index;
krh@85
    54
		index++;
krh@85
    55
	}
krh@85
    56
krh@85
    57
	return NULL;
krh@85
    58
}
krh@85
    59
krh@87
    60
static const void *
krh@87
    61
razor_rpm_get_indirect(struct razor_rpm *rpm,
krh@87
    62
		       unsigned int tag, unsigned int *count)
krh@87
    63
{
krh@87
    64
	struct rpm_header_index *index;
krh@87
    65
krh@87
    66
	index = razor_rpm_get_header(rpm, tag);
krh@87
    67
	if (index != NULL) {
krh@87
    68
		if (count)
krh@87
    69
			*count = ntohl(index->count);
krh@87
    70
krh@87
    71
		return rpm->pool + ntohl(index->offset);
krh@87
    72
	}
krh@87
    73
krh@87
    74
	return NULL;
krh@87
    75
}
krh@87
    76
danw@109
    77
static enum razor_version_relation
danw@109
    78
rpm_to_razor_flags (uint_32 flags)
danw@109
    79
{
danw@109
    80
	switch (flags & (RPMSENSE_LESS | RPMSENSE_EQUAL | RPMSENSE_GREATER)) {
danw@109
    81
	case RPMSENSE_LESS:
danw@109
    82
		return RAZOR_VERSION_LESS;
danw@109
    83
	case RPMSENSE_LESS|RPMSENSE_EQUAL:
danw@109
    84
		return RAZOR_VERSION_LESS_OR_EQUAL;
danw@109
    85
	case RPMSENSE_EQUAL:
danw@109
    86
		return RAZOR_VERSION_EQUAL;
danw@109
    87
	case RPMSENSE_GREATER|RPMSENSE_EQUAL:
danw@109
    88
		return RAZOR_VERSION_GREATER_OR_EQUAL;
danw@109
    89
	case RPMSENSE_GREATER:
danw@109
    90
		return RAZOR_VERSION_GREATER;
danw@109
    91
	}
danw@109
    92
danw@109
    93
	/* FIXME? */
danw@109
    94
	return RAZOR_VERSION_EQUAL;
danw@109
    95
}
danw@109
    96
krh@87
    97
static void
krh@87
    98
import_properties(struct razor_importer *importer, unsigned long type,
krh@87
    99
		  struct razor_rpm *rpm,
krh@87
   100
		  int name_tag, int version_tag, int flags_tag)
krh@87
   101
{
krh@87
   102
	const char *name, *version;
danw@109
   103
	uint_32 flags;
krh@87
   104
	unsigned int i, count;
krh@87
   105
krh@87
   106
	name = razor_rpm_get_indirect(rpm, name_tag, &count);
krh@87
   107
	if (name == NULL)
krh@87
   108
		return;
krh@87
   109
danw@109
   110
	flags = *(uint_32 *)razor_rpm_get_indirect(rpm, flags_tag, &count);
danw@109
   111
krh@87
   112
	/* FIXME: Concat version and release. */
krh@87
   113
	version = razor_rpm_get_indirect(rpm, version_tag, &count);
krh@87
   114
	for (i = 0; i < count; i++) {
danw@109
   115
		razor_importer_add_property(importer, name,
danw@109
   116
					    rpm_to_razor_flags (flags),
danw@109
   117
					    version, type);
krh@87
   118
		name += strlen(name) + 1;
krh@87
   119
		version += strlen(version) + 1;
krh@87
   120
	}
krh@87
   121
}
krh@87
   122
krh@87
   123
static void
krh@87
   124
import_files(struct razor_importer *importer, struct razor_rpm *rpm)
krh@87
   125
{
krh@87
   126
	const char *name;
krh@87
   127
	const unsigned long *index;
krh@87
   128
	unsigned int i, count;
krh@87
   129
	char buffer[256];
krh@87
   130
krh@87
   131
	/* assert: count is the same for all arrays */
krh@87
   132
krh@87
   133
	index = razor_rpm_get_indirect(rpm, RPMTAG_DIRINDEXES, &count);
krh@87
   134
	name = razor_rpm_get_indirect(rpm, RPMTAG_BASENAMES, &count);
krh@87
   135
	for (i = 0; i < count; i++) {
krh@87
   136
		snprintf(buffer, sizeof buffer,
krh@87
   137
			 "%s%s", rpm->dirs[ntohl(*index)], name);
krh@87
   138
		razor_importer_add_file(importer, buffer);
krh@87
   139
		name += strlen(name) + 1;
krh@87
   140
		index++;
krh@87
   141
	}
krh@87
   142
}
krh@87
   143
krh@77
   144
struct razor_rpm *
krh@77
   145
razor_rpm_open(const char *filename)
krh@74
   146
{
krh@77
   147
	struct razor_rpm *rpm;
krh@74
   148
	struct rpm_header_index *base, *index;
krh@75
   149
	struct stat buf;
krh@87
   150
	unsigned int count, i, nindex, hsize;
krh@77
   151
	const char *name;
krh@87
   152
	int fd;
krh@74
   153
krh@77
   154
	rpm = malloc(sizeof *rpm);
krh@75
   155
	memset(rpm, 0, sizeof *rpm);
krh@74
   156
krh@75
   157
	fd = open(filename, O_RDONLY);
krh@75
   158
	if (fd < 0) {
krh@75
   159
		fprintf(stderr, "couldn't open %s\n", filename);
krh@77
   160
		return NULL;
krh@75
   161
	}
krh@88
   162
krh@88
   163
	if (fstat(fd, &buf) < 0) {
krh@88
   164
		fprintf(stderr, "failed to stat %s (%m)\n", filename);
krh@88
   165
		return NULL;
krh@88
   166
	}
krh@88
   167
krh@75
   168
	rpm->size = buf.st_size;
krh@75
   169
	rpm->map = mmap(NULL, rpm->size, PROT_READ, MAP_PRIVATE, fd, 0);
krh@75
   170
	if (rpm->map == MAP_FAILED) {
krh@75
   171
		fprintf(stderr, "couldn't mmap %s\n", filename);
krh@77
   172
		return NULL;
krh@75
   173
	}
krh@75
   174
	close(fd);
krh@75
   175
krh@75
   176
	rpm->signature = rpm->map + RPM_LEAD_SIZE;
krh@75
   177
	nindex = ntohl(rpm->signature->nindex);
krh@75
   178
	hsize = ntohl(rpm->signature->hsize);
krh@75
   179
	rpm->header = (void *) (rpm->signature + 1) +
krh@75
   180
		ALIGN(nindex * sizeof *index + hsize, 8);
krh@77
   181
	nindex = ntohl(rpm->header->nindex);
krh@77
   182
	hsize = ntohl(rpm->header->hsize);
krh@77
   183
	rpm->payload = (void *) (rpm->header + 1) +
krh@77
   184
		nindex * sizeof *index + hsize;
krh@75
   185
krh@75
   186
	base = (struct rpm_header_index *) (rpm->header + 1);
krh@75
   187
	rpm->pool = (void *) base + nindex * sizeof *index;
krh@75
   188
krh@87
   189
	/* Look up dir names now so we can index them directly. */
krh@87
   190
	name = razor_rpm_get_indirect(rpm, RPMTAG_DIRNAMES, &count);
krh@87
   191
	if (name == NULL) {
krh@87
   192
		fprintf(stderr, "old filename style not handled\n");
krh@87
   193
		return NULL;
krh@74
   194
	}
krh@75
   195
krh@87
   196
	rpm->dirs = calloc(count, sizeof *rpm->dirs);
krh@87
   197
	for (i = 0; i < count; i++) {
krh@87
   198
		rpm->dirs[i] = name;
krh@87
   199
		name += strlen(name) + 1;
krh@77
   200
	}
krh@77
   201
krh@77
   202
	return rpm;
krh@77
   203
}
krh@77
   204
krh@77
   205
struct cpio_file_header {
krh@77
   206
	char magic[6];
krh@77
   207
	char inode[8];
krh@77
   208
	char mode[8];
krh@77
   209
	char uid[8];
krh@77
   210
	char gid[8];
krh@77
   211
	char nlink[8];
krh@77
   212
	char mtime[8];
krh@77
   213
	char filesize[8];
krh@77
   214
	char devmajor[8];
krh@77
   215
	char devminor[8];
krh@77
   216
	char rdevmajor[8];
krh@77
   217
	char rdevminor[8];
krh@77
   218
	char namesize[8];
krh@77
   219
	char checksum[8];
krh@77
   220
	char filename[0];
krh@77
   221
};
krh@77
   222
krh@77
   223
/* gzip flags */
krh@77
   224
#define ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
krh@77
   225
#define HEAD_CRC     0x02 /* bit 1 set: header CRC present */
krh@77
   226
#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
krh@77
   227
#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
krh@77
   228
#define COMMENT      0x10 /* bit 4 set: file comment present */
krh@77
   229
#define RESERVED     0xE0 /* bits 5..7: reserved */
krh@77
   230
krh@86
   231
struct installer {
krh@86
   232
	const char *root;
krh@86
   233
	struct razor_rpm *rpm;
krh@86
   234
	z_stream stream;
krh@86
   235
	unsigned char buffer[32768];
krh@86
   236
	size_t rest, length;
krh@86
   237
};
krh@86
   238
krh@77
   239
static int
krh@86
   240
installer_inflate(struct installer *installer)
krh@86
   241
{
krh@86
   242
	size_t length;
krh@86
   243
	int err;
krh@86
   244
krh@86
   245
	if (ALIGN(installer->rest, 4) > sizeof installer->buffer)
krh@86
   246
		length = sizeof installer->buffer;
krh@86
   247
	else
krh@86
   248
		length = installer->rest;
krh@86
   249
krh@86
   250
	installer->stream.next_out = installer->buffer;
krh@86
   251
	installer->stream.avail_out = ALIGN(length, 4);
krh@86
   252
	err = inflate(&installer->stream, Z_SYNC_FLUSH);
krh@86
   253
	if (err != Z_OK && err != Z_STREAM_END) {
krh@86
   254
		fprintf(stderr, "inflate error: %d (%m)\n", err);
krh@86
   255
		return -1;
krh@86
   256
	}
krh@86
   257
krh@86
   258
	installer->rest -= length;
krh@86
   259
	installer->length = length;
krh@86
   260
krh@86
   261
	return 0;
krh@86
   262
}
krh@86
   263
krh@86
   264
static int
krh@86
   265
create_path(struct installer *installer,
krh@86
   266
	    const char *path, const char *name, unsigned int mode)
krh@77
   267
{
krh@91
   268
	char buffer[PATH_MAX];
krh@86
   269
	int fd;
krh@77
   270
krh@91
   271
	if (razor_create_dir(installer->root, path) < 0)
krh@91
   272
		return -1;
krh@77
   273
krh@91
   274
	snprintf(buffer, sizeof buffer, "%s%s/%s",
krh@91
   275
		 installer->root, path, name);
krh@77
   276
krh@77
   277
	switch (mode >> 12) {
krh@77
   278
	case REG:
krh@86
   279
		fd = open(buffer, O_WRONLY | O_CREAT | O_TRUNC, mode & 0x1ff);
krh@86
   280
		if (fd < 0){
krh@86
   281
			fprintf(stderr, "failed to create file %s\n", buffer);
krh@86
   282
			return -1;
krh@86
   283
		}
krh@86
   284
		while (installer->rest > 0) {
krh@86
   285
			if (installer_inflate(installer)) {
krh@86
   286
				fprintf(stderr, "failed to inflate\n");
krh@86
   287
				return -1;
krh@86
   288
			}
krh@91
   289
			if (razor_write(fd, installer->buffer,
krh@91
   290
					installer->length)) {
krh@86
   291
				fprintf(stderr, "failed to write payload\n");
krh@86
   292
				return -1;
krh@86
   293
			}
krh@86
   294
		}
krh@86
   295
		if (close(fd) < 0) {
krh@86
   296
			fprintf(stderr, "failed to close %s: %m\n", buffer);
krh@86
   297
			return -1;
krh@86
   298
		}
krh@86
   299
		return 0;
krh@86
   300
	case XDIR:
krh@86
   301
		return mkdir(buffer, mode & 0x1ff);
krh@86
   302
	case PIPE:
krh@86
   303
	case CDEV:
krh@86
   304
	case BDEV:
krh@86
   305
	case SOCK:
krh@86
   306
		printf("%s: unhandled file type %d\n", buffer, mode >> 12);
krh@86
   307
		return 0;
krh@86
   308
	case LINK:
krh@86
   309
		if (installer_inflate(installer)) {
krh@86
   310
			fprintf(stderr, "failed to inflate\n");
krh@86
   311
			return -1;
krh@86
   312
		}
krh@86
   313
		if (installer->length >= sizeof installer->buffer) {
krh@86
   314
			fprintf(stderr, "link name too long\n");
krh@86
   315
			return -1;
krh@86
   316
		}
krh@86
   317
		installer->buffer[installer->length] = '\0';
krh@86
   318
		if (symlink((const char *) installer->buffer, buffer)) {
krh@86
   319
			fprintf(stderr, "failed to create symlink, %m\n");
krh@86
   320
			return -1;
krh@86
   321
		}
krh@86
   322
		return 0;
krh@77
   323
	default:
krh@86
   324
		printf("%s: unknown file type %d\n", buffer, mode >> 12);
krh@86
   325
		return 0;
krh@77
   326
	}
krh@77
   327
}
krh@77
   328
krh@85
   329
static int
krh@86
   330
run_script(struct installer *installer,
krh@86
   331
	   unsigned int program_tag, unsigned int script_tag)
krh@85
   332
{
krh@85
   333
	int pid, status, fd[2];
krh@86
   334
	const char *script = NULL, *program = NULL;
krh@85
   335
krh@87
   336
	program = razor_rpm_get_indirect(installer->rpm, program_tag, NULL);
krh@87
   337
	script = razor_rpm_get_indirect(installer->rpm, script_tag, NULL);
krh@86
   338
	if (program == NULL && script == NULL) {
krh@86
   339
		printf("no script or program for tags %d and %d\n",
krh@86
   340
		       program_tag, script_tag);
krh@86
   341
		return -1;
krh@86
   342
	} else if (program == NULL) {
krh@86
   343
		program = "/bin/sh";
krh@85
   344
	}
krh@85
   345
krh@85
   346
	if (pipe(fd) < 0) {
krh@85
   347
		fprintf(stderr, "failed to create pipe\n");
krh@85
   348
		return -1;
krh@85
   349
	}
krh@85
   350
	pid = fork();
krh@85
   351
	if (pid < 0) {
krh@85
   352
		fprintf(stderr, "failed to fork, %m\n");
krh@85
   353
	} else if (pid == 0) {
krh@85
   354
		if (dup2(fd[0], STDIN_FILENO) < 0) {
krh@85
   355
			fprintf(stderr, "failed redirect stdin, %m\n");
krh@85
   356
			return -1;
krh@85
   357
		}
krh@85
   358
		if (close(fd[0]) < 0 || close(fd[1]) < 0) {
krh@85
   359
			fprintf(stderr, "failed to close pipe, %m\n");
krh@89
   360
			return -1;
krh@85
   361
		}
krh@86
   362
		if (chroot(installer->root) < 0) {
krh@86
   363
			fprintf(stderr, "failed to chroot to %s, %m\n",
krh@86
   364
				installer->root);
krh@85
   365
			return -1;
krh@85
   366
		}
krh@86
   367
		printf("executing program %s in chroot %s\n",
krh@86
   368
		       program, installer->root);
krh@86
   369
		if (execl(program, program, NULL)) {
krh@86
   370
			fprintf(stderr, "failed to exec %s, %m\n", program);
krh@89
   371
			exit(-1);
krh@85
   372
		}
krh@85
   373
	} else {
krh@86
   374
		if (script && write(fd[1], script, strlen(script)) < 0) {
krh@85
   375
			fprintf(stderr, "failed to pipe script, %m\n");
krh@85
   376
			return -1;
krh@85
   377
		}
krh@85
   378
		if (close(fd[0]) || close(fd[1])) {
krh@85
   379
			fprintf(stderr, "failed to close pipe, %m\n");
krh@85
   380
			return -1;
krh@85
   381
		}
krh@85
   382
		if (wait(&status) < 0) {
krh@85
   383
			fprintf(stderr, "wait for child failed, %m");
krh@85
   384
			return -1;
krh@85
   385
		}
krh@85
   386
		printf("script exited with status %d\n", status);
krh@85
   387
	}
krh@85
   388
krh@85
   389
	return 0;
krh@85
   390
}
krh@85
   391
krh@86
   392
static int
krh@86
   393
installer_init(struct installer *installer)
krh@77
   394
{
krh@86
   395
	unsigned char *gz_header;
krh@86
   396
	int method, flags, err;
krh@77
   397
krh@86
   398
	gz_header = installer->rpm->payload;
krh@77
   399
	if (gz_header[0] != 0x1f || gz_header[1] != 0x8b) {
krh@77
   400
		fprintf(stderr, "payload section doesn't have gz header\n");
krh@77
   401
		return -1;
krh@77
   402
	}
krh@77
   403
krh@77
   404
	method = gz_header[2];
krh@77
   405
	flags = gz_header[3];
krh@77
   406
krh@77
   407
	if (method != Z_DEFLATED || flags != 0) {
krh@77
   408
		fprintf(stderr,
krh@77
   409
			"unknown payload compression method or flags set\n");
krh@77
   410
		return -1;
krh@77
   411
	}
krh@77
   412
krh@86
   413
	installer->stream.zalloc = NULL;
krh@86
   414
	installer->stream.zfree = NULL;
krh@86
   415
	installer->stream.opaque = NULL;
krh@85
   416
krh@86
   417
	installer->stream.next_in  = gz_header + 10;
krh@86
   418
	installer->stream.avail_in =
krh@86
   419
		(installer->rpm->map + installer->rpm->size) -
krh@86
   420
		(void *) installer->stream.next_in;
krh@86
   421
	installer->stream.next_out = NULL;
krh@86
   422
	installer->stream.avail_out = 0;
krh@77
   423
krh@86
   424
	err = inflateInit2(&installer->stream, -MAX_WBITS);
krh@77
   425
	if (err != Z_OK) {
krh@77
   426
		fprintf(stderr, "inflateInit error: %d\n", err);
krh@77
   427
		return -1;
krh@77
   428
	}
krh@77
   429
krh@86
   430
	return 0;
krh@86
   431
}
krh@77
   432
krh@86
   433
static int
krh@86
   434
installer_finish(struct installer *installer)
krh@86
   435
{
krh@86
   436
	int err;
krh@77
   437
krh@86
   438
	err = inflateEnd(&installer->stream);
krh@77
   439
krh@77
   440
	if (err != Z_OK) {
krh@77
   441
		fprintf(stderr, "inflateEnd error: %d\n", err);
krh@77
   442
		return -1;
krh@77
   443
	}	    
krh@77
   444
krh@86
   445
	return 0;
krh@86
   446
}
krh@86
   447
krh@86
   448
int
krh@86
   449
razor_rpm_install(struct razor_rpm *rpm, const char *root)
krh@86
   450
{
krh@86
   451
	struct installer installer;
krh@87
   452
	unsigned int count, i, length;
krh@86
   453
	struct cpio_file_header *header;
krh@87
   454
	const unsigned long *size, *index, *flags;
krh@87
   455
	const unsigned short *mode;
krh@86
   456
	const char *name, *dir;
krh@86
   457
	struct stat buf;
krh@86
   458
krh@86
   459
	installer.rpm = rpm;
krh@86
   460
	installer.root = root;
krh@86
   461
krh@86
   462
	/* FIXME: Only do this before a transaction, not per rpm. */
krh@86
   463
	if (stat(root, &buf) < 0 || !S_ISDIR(buf.st_mode)) {
krh@86
   464
		fprintf(stderr,
krh@86
   465
			"root installation directory \"%s\" does not exist\n",
krh@86
   466
			root);
krh@86
   467
		return -1;
krh@86
   468
	}
krh@86
   469
krh@86
   470
	if (installer_init(&installer))
krh@86
   471
		return -1;
krh@86
   472
krh@86
   473
	run_script(&installer, RPMTAG_PREINPROG, RPMTAG_PREIN);
krh@86
   474
krh@87
   475
	name = razor_rpm_get_indirect(rpm, RPMTAG_BASENAMES, &count);
krh@87
   476
	size = razor_rpm_get_indirect(rpm, RPMTAG_FILESIZES, &count);
krh@87
   477
	index = razor_rpm_get_indirect(rpm, RPMTAG_DIRINDEXES, &count);
krh@87
   478
	mode = razor_rpm_get_indirect(rpm, RPMTAG_FILEMODES, &count);
krh@87
   479
	flags = razor_rpm_get_indirect(rpm, RPMTAG_FILEFLAGS, &count);
krh@86
   480
krh@86
   481
	for (i = 0; i < count; i++) {
krh@86
   482
		dir = rpm->dirs[ntohl(*index)];
krh@86
   483
krh@86
   484
		/* Skip past the cpio header block unless it's a ghost file,
krh@86
   485
		 * in which case doesn't appear in the cpio archive. */
krh@86
   486
		if (!(ntohl(*flags) & RPMFILE_GHOST)) {
krh@86
   487
			/* Plus two for the leading '.' and the terminating NUL. */
krh@86
   488
			length = sizeof *header + strlen(dir) + strlen(name) + 2;
krh@86
   489
			installer.rest = ALIGN(length, 4);
krh@86
   490
			if (installer_inflate(&installer))
krh@86
   491
				return -1;
krh@86
   492
		}
krh@86
   493
krh@86
   494
		installer.rest = ntohl(*size);
krh@86
   495
		if (create_path(&installer, dir, name, ntohs(*mode)) < 0)
krh@86
   496
			return -1;
krh@86
   497
krh@86
   498
		name += strlen(name) + 1;
krh@86
   499
		index++;
krh@86
   500
		size++;
krh@86
   501
		mode++;
krh@86
   502
		flags++;
krh@86
   503
	}
krh@86
   504
krh@86
   505
	if (installer_finish(&installer))
krh@86
   506
		return -1;
krh@86
   507
krh@86
   508
	run_script(&installer, RPMTAG_POSTINPROG, RPMTAG_POSTIN);
krh@85
   509
krh@75
   510
	return 0;
krh@74
   511
}
krh@74
   512
krh@77
   513
int
krh@77
   514
razor_rpm_close(struct razor_rpm *rpm)
krh@74
   515
{
krh@77
   516
	int err;
krh@77
   517
krh@77
   518
	free(rpm->dirs);
krh@77
   519
	err = munmap(rpm->map, rpm->size);
krh@77
   520
	free(rpm);
krh@77
   521
krh@77
   522
	return err;
krh@75
   523
}
krh@74
   524
krh@75
   525
int
krh@77
   526
razor_importer_add_rpm(struct razor_importer *importer, struct razor_rpm *rpm)
krh@75
   527
{
krh@87
   528
	const char *name, *version, *release;
krh@75
   529
krh@87
   530
	name = razor_rpm_get_indirect(rpm, RPMTAG_NAME, NULL);
krh@87
   531
	version = razor_rpm_get_indirect(rpm, RPMTAG_VERSION, NULL);
krh@87
   532
	release = razor_rpm_get_indirect(rpm, RPMTAG_RELEASE, NULL);
krh@87
   533
krh@87
   534
	/* FIXME: Concatenate version and release. */
krh@87
   535
	razor_importer_begin_package(importer, name, version);
krh@87
   536
krh@87
   537
	import_properties(importer, RAZOR_PROPERTY_REQUIRES, rpm,
krh@87
   538
			  RPMTAG_REQUIRENAME,
krh@87
   539
			  RPMTAG_REQUIREVERSION,
krh@87
   540
			  RPMTAG_REQUIREFLAGS);
krh@87
   541
krh@87
   542
	import_properties(importer, RAZOR_PROPERTY_PROVIDES, rpm,
krh@87
   543
			  RPMTAG_PROVIDENAME,
krh@87
   544
			  RPMTAG_PROVIDEVERSION,
krh@87
   545
			  RPMTAG_PROVIDEFLAGS);
krh@87
   546
krh@87
   547
	import_properties(importer, RAZOR_PROPERTY_OBSOLETES, rpm,
krh@87
   548
			  RPMTAG_OBSOLETENAME,
krh@87
   549
			  RPMTAG_OBSOLETEVERSION,
krh@87
   550
			  RPMTAG_OBSOLETEFLAGS);
krh@87
   551
krh@87
   552
	import_properties(importer, RAZOR_PROPERTY_CONFLICTS, rpm,
krh@87
   553
			  RPMTAG_CONFLICTNAME,
krh@87
   554
			  RPMTAG_CONFLICTVERSION,
krh@87
   555
			  RPMTAG_CONFLICTFLAGS);
krh@87
   556
krh@77
   557
	import_files(importer, rpm);
krh@74
   558
krh@75
   559
	razor_importer_finish_package(importer);
krh@74
   560
krh@75
   561
	return 0;
krh@74
   562
}
danw@109
   563
danw@109
   564
union rpm_entry {
danw@109
   565
	void *p;
danw@109
   566
	char *string;
danw@109
   567
	char **list;
danw@109
   568
	uint_32 *flags;
danw@109
   569
};
danw@109
   570
danw@109
   571
static void
danw@109
   572
add_properties(struct razor_importer *importer,
danw@109
   573
	       enum razor_property_type property_type,
danw@109
   574
	       Header h, int_32 name_tag, int_32 version_tag, int_32 flags_tag)
danw@109
   575
{
danw@109
   576
	union rpm_entry names, versions, flags;
danw@109
   577
	int_32 i, type, count;
danw@109
   578
danw@109
   579
	headerGetEntry(h, name_tag, &type, &names.p, &count);
danw@109
   580
	headerGetEntry(h, version_tag, &type, &versions.p, &count);
danw@109
   581
	headerGetEntry(h, flags_tag, &type, &flags.p, &count);
danw@109
   582
danw@109
   583
	for (i = 0; i < count; i++)
danw@109
   584
		razor_importer_add_property(importer,
danw@109
   585
					    names.list[i],
danw@109
   586
					    rpm_to_razor_flags (flags.flags[i]),
danw@109
   587
					    versions.list[i],
danw@109
   588
					    property_type);
danw@109
   589
}
danw@109
   590
danw@109
   591
struct razor_set *
danw@109
   592
razor_set_create_from_rpmdb(void)
danw@109
   593
{
danw@109
   594
	struct razor_importer *importer;
danw@109
   595
	rpmdbMatchIterator iter;
danw@109
   596
	Header h;
danw@109
   597
	int_32 type, count, i;
danw@109
   598
	union rpm_entry name, version, release;
danw@109
   599
	union rpm_entry basenames, dirnames, dirindexes;
danw@109
   600
	char filename[PATH_MAX];
danw@109
   601
	rpmdb db;
danw@109
   602
danw@109
   603
	rpmReadConfigFiles(NULL, NULL);
danw@109
   604
danw@109
   605
	if (rpmdbOpen("", &db, O_RDONLY, 0644) != 0) {
danw@109
   606
		fprintf(stderr, "cannot open rpm database\n");
danw@109
   607
		exit(1);
danw@109
   608
	}
danw@109
   609
danw@109
   610
	importer = razor_importer_new();
danw@109
   611
danw@109
   612
	iter = rpmdbInitIterator(db, 0, NULL, 0);
danw@109
   613
	while (h = rpmdbNextIterator(iter), h != NULL) {
danw@109
   614
		headerGetEntry(h, RPMTAG_NAME, &type, &name.p, &count);
danw@109
   615
		headerGetEntry(h, RPMTAG_VERSION, &type, &version.p, &count);
danw@109
   616
		headerGetEntry(h, RPMTAG_RELEASE, &type, &release.p, &count);
danw@109
   617
		snprintf(filename, sizeof filename, "%s-%s",
danw@109
   618
			 version.string, release.string);
danw@109
   619
		razor_importer_begin_package(importer, name.string, filename);
danw@109
   620
danw@109
   621
		add_properties(importer, RAZOR_PROPERTY_REQUIRES, h,
danw@109
   622
			       RPMTAG_REQUIRENAME,
danw@109
   623
			       RPMTAG_REQUIREVERSION,
danw@109
   624
			       RPMTAG_REQUIREFLAGS);
danw@109
   625
danw@109
   626
		add_properties(importer, RAZOR_PROPERTY_PROVIDES, h,
danw@109
   627
			       RPMTAG_PROVIDENAME,
danw@109
   628
			       RPMTAG_PROVIDEVERSION,
danw@109
   629
			       RPMTAG_PROVIDEFLAGS);
danw@109
   630
danw@109
   631
		add_properties(importer, RAZOR_PROPERTY_OBSOLETES, h,
danw@109
   632
			       RPMTAG_OBSOLETENAME,
danw@109
   633
			       RPMTAG_OBSOLETEVERSION,
danw@109
   634
			       RPMTAG_OBSOLETEFLAGS);
danw@109
   635
danw@109
   636
		add_properties(importer, RAZOR_PROPERTY_CONFLICTS, h,
danw@109
   637
			       RPMTAG_CONFLICTNAME,
danw@109
   638
			       RPMTAG_CONFLICTVERSION,
danw@109
   639
			       RPMTAG_CONFLICTFLAGS);
danw@109
   640
danw@109
   641
		headerGetEntry(h, RPMTAG_BASENAMES, &type,
danw@109
   642
			       &basenames.p, &count);
danw@109
   643
		headerGetEntry(h, RPMTAG_DIRNAMES, &type,
danw@109
   644
			       &dirnames.p, &count);
danw@109
   645
		headerGetEntry(h, RPMTAG_DIRINDEXES, &type,
danw@109
   646
			       &dirindexes.p, &count);
danw@109
   647
		for (i = 0; i < count; i++) {
danw@109
   648
			snprintf(filename, sizeof filename, "%s%s",
danw@109
   649
				 dirnames.list[dirindexes.flags[i]],
danw@109
   650
				 basenames.list[i]);
danw@109
   651
			razor_importer_add_file(importer, filename);
danw@109
   652
		}
danw@109
   653
danw@109
   654
		razor_importer_finish_package(importer);
danw@109
   655
	}
danw@109
   656
danw@109
   657
	rpmdbClose(db);
danw@109
   658
danw@109
   659
	return razor_importer_finish(importer);
danw@109
   660
}