rpm.c
author Kristian H?gsberg <krh@jiraiya.boston.redhat.com>
Wed Apr 09 02:41:03 2008 -0400 (2008-04-09)
changeset 211 cf0ca962262b
parent 202 e8594c82dffc
child 212 e8f493d8ff9a
permissions -rw-r--r--
Use the cpio headers instead of the rpm headers when unpacking.

The files in the cpio payload doesn't actually follow the file order
in the rpm headers, so we need to decode the cpio header and use the
information there.
krh@74
     1
#include <stdio.h>
krh@84
     2
#include <stddef.h>
krh@74
     3
#include <string.h>
krh@176
     4
#include <errno.h>
krh@74
     5
#include <sys/stat.h>
krh@74
     6
#include <sys/mman.h>
krh@85
     7
#include <sys/types.h>
krh@85
     8
#include <sys/wait.h>
krh@74
     9
#include <fcntl.h>
krh@74
    10
#include <unistd.h>
krh@74
    11
#include <arpa/inet.h>
krh@74
    12
#include <rpm/rpmlib.h>
danw@109
    13
#include <rpm/rpmdb.h>
krh@77
    14
#include <zlib.h>
krh@74
    15
krh@75
    16
#include "razor.h"
krh@91
    17
#include "razor-internal.h"
krh@75
    18
krh@74
    19
#define	RPM_LEAD_SIZE 96
krh@74
    20
krh@74
    21
struct rpm_header {
krh@74
    22
	unsigned char magic[4];
krh@74
    23
	unsigned char reserved[4];
krh@74
    24
	int nindex;
krh@74
    25
	int hsize;
krh@74
    26
};
krh@74
    27
krh@74
    28
struct rpm_header_index {
krh@74
    29
	int tag;
krh@74
    30
	int type;
krh@74
    31
	int offset;
krh@74
    32
	int count;
krh@74
    33
};
krh@74
    34
krh@77
    35
struct razor_rpm {
krh@75
    36
	struct rpm_header *signature;
krh@75
    37
	struct rpm_header *header;
krh@77
    38
	const char **dirs;
krh@75
    39
	const char *pool;
krh@75
    40
	void *map;
krh@75
    41
	size_t size;
krh@77
    42
	void *payload;
krh@75
    43
};
krh@75
    44
krh@85
    45
static struct rpm_header_index *
krh@85
    46
razor_rpm_get_header(struct razor_rpm *rpm, unsigned int tag)
krh@85
    47
{
krh@85
    48
	struct rpm_header_index *index, *end;
krh@85
    49
krh@85
    50
	index = (struct rpm_header_index *) (rpm->header + 1);
krh@85
    51
	end = index + ntohl(rpm->header->nindex);
krh@85
    52
	while (index < end) {
krh@85
    53
		if (ntohl(index->tag) == tag)
krh@85
    54
			return index;
krh@85
    55
		index++;
krh@85
    56
	}
krh@85
    57
krh@85
    58
	return NULL;
krh@85
    59
}
krh@85
    60
krh@87
    61
static const void *
krh@87
    62
razor_rpm_get_indirect(struct razor_rpm *rpm,
krh@87
    63
		       unsigned int tag, unsigned int *count)
krh@87
    64
{
krh@87
    65
	struct rpm_header_index *index;
krh@87
    66
krh@87
    67
	index = razor_rpm_get_header(rpm, tag);
krh@87
    68
	if (index != NULL) {
krh@87
    69
		if (count)
krh@87
    70
			*count = ntohl(index->count);
krh@87
    71
krh@87
    72
		return rpm->pool + ntohl(index->offset);
krh@87
    73
	}
krh@87
    74
krh@87
    75
	return NULL;
krh@87
    76
}
krh@87
    77
danw@109
    78
static enum razor_version_relation
danw@109
    79
rpm_to_razor_flags (uint_32 flags)
danw@109
    80
{
danw@109
    81
	switch (flags & (RPMSENSE_LESS | RPMSENSE_EQUAL | RPMSENSE_GREATER)) {
danw@109
    82
	case RPMSENSE_LESS:
danw@109
    83
		return RAZOR_VERSION_LESS;
danw@109
    84
	case RPMSENSE_LESS|RPMSENSE_EQUAL:
danw@109
    85
		return RAZOR_VERSION_LESS_OR_EQUAL;
danw@109
    86
	case RPMSENSE_EQUAL:
danw@109
    87
		return RAZOR_VERSION_EQUAL;
danw@109
    88
	case RPMSENSE_GREATER|RPMSENSE_EQUAL:
danw@109
    89
		return RAZOR_VERSION_GREATER_OR_EQUAL;
danw@109
    90
	case RPMSENSE_GREATER:
danw@109
    91
		return RAZOR_VERSION_GREATER;
danw@109
    92
	}
danw@109
    93
danw@109
    94
	/* FIXME? */
danw@109
    95
	return RAZOR_VERSION_EQUAL;
danw@109
    96
}
danw@109
    97
krh@87
    98
static void
krh@87
    99
import_properties(struct razor_importer *importer, unsigned long type,
krh@87
   100
		  struct razor_rpm *rpm,
krh@87
   101
		  int name_tag, int version_tag, int flags_tag)
krh@87
   102
{
krh@87
   103
	const char *name, *version;
krh@172
   104
	const uint_32 *flags;
krh@172
   105
	uint_32 f;
krh@87
   106
	unsigned int i, count;
krh@87
   107
krh@87
   108
	name = razor_rpm_get_indirect(rpm, name_tag, &count);
krh@87
   109
	if (name == NULL)
krh@87
   110
		return;
krh@87
   111
krh@172
   112
	flags = razor_rpm_get_indirect(rpm, flags_tag, &count);
danw@109
   113
krh@87
   114
	version = razor_rpm_get_indirect(rpm, version_tag, &count);
krh@87
   115
	for (i = 0; i < count; i++) {
krh@172
   116
		f = rpm_to_razor_flags(ntohl(flags[i]));
krh@172
   117
		razor_importer_add_property(importer, name, f, 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;
danw@173
   127
	const uint32_t *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@185
   191
	if (name) {
krh@185
   192
		rpm->dirs = calloc(count, sizeof *rpm->dirs);
krh@185
   193
		for (i = 0; i < count; i++) {
krh@185
   194
			rpm->dirs[i] = name;
krh@185
   195
			name += strlen(name) + 1;
krh@185
   196
		}
krh@185
   197
	} else {
krh@185
   198
		name = razor_rpm_get_indirect(rpm, RPMTAG_OLDFILENAMES,
krh@185
   199
					      &count);
krh@185
   200
		if (name) {
krh@185
   201
			fprintf(stderr, "old filenames not supported\n");
krh@185
   202
			return NULL;
krh@185
   203
		}
krh@77
   204
	}
krh@77
   205
krh@77
   206
	return rpm;
krh@77
   207
}
krh@77
   208
krh@77
   209
struct cpio_file_header {
krh@77
   210
	char magic[6];
krh@77
   211
	char inode[8];
krh@77
   212
	char mode[8];
krh@77
   213
	char uid[8];
krh@77
   214
	char gid[8];
krh@77
   215
	char nlink[8];
krh@77
   216
	char mtime[8];
krh@77
   217
	char filesize[8];
krh@77
   218
	char devmajor[8];
krh@77
   219
	char devminor[8];
krh@77
   220
	char rdevmajor[8];
krh@77
   221
	char rdevminor[8];
krh@77
   222
	char namesize[8];
krh@77
   223
	char checksum[8];
krh@77
   224
	char filename[0];
krh@77
   225
};
krh@77
   226
krh@77
   227
/* gzip flags */
krh@77
   228
#define ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
krh@77
   229
#define HEAD_CRC     0x02 /* bit 1 set: header CRC present */
krh@77
   230
#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
krh@77
   231
#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
krh@77
   232
#define COMMENT      0x10 /* bit 4 set: file comment present */
krh@77
   233
#define RESERVED     0xE0 /* bits 5..7: reserved */
krh@77
   234
krh@86
   235
struct installer {
krh@86
   236
	const char *root;
krh@86
   237
	struct razor_rpm *rpm;
krh@86
   238
	z_stream stream;
krh@86
   239
	unsigned char buffer[32768];
krh@86
   240
	size_t rest, length;
krh@86
   241
};
krh@86
   242
krh@77
   243
static int
krh@86
   244
installer_inflate(struct installer *installer)
krh@86
   245
{
krh@86
   246
	size_t length;
krh@86
   247
	int err;
krh@86
   248
krh@211
   249
	if (installer->rest > sizeof installer->buffer)
krh@86
   250
		length = sizeof installer->buffer;
krh@86
   251
	else
krh@86
   252
		length = installer->rest;
krh@86
   253
krh@86
   254
	installer->stream.next_out = installer->buffer;
krh@211
   255
	installer->stream.avail_out = length;
krh@86
   256
	err = inflate(&installer->stream, Z_SYNC_FLUSH);
krh@86
   257
	if (err != Z_OK && err != Z_STREAM_END) {
krh@86
   258
		fprintf(stderr, "inflate error: %d (%m)\n", err);
krh@86
   259
		return -1;
krh@86
   260
	}
krh@86
   261
krh@86
   262
	installer->rest -= length;
krh@86
   263
	installer->length = length;
krh@86
   264
krh@86
   265
	return 0;
krh@86
   266
}
krh@86
   267
krh@86
   268
static int
krh@211
   269
installer_align(struct installer *installer, size_t size)
krh@211
   270
{
krh@211
   271
	unsigned char buffer[4];
krh@211
   272
	int err;
krh@211
   273
krh@211
   274
	installer->stream.next_out = buffer;
krh@211
   275
	installer->stream.avail_out =
krh@211
   276
		(size - installer->stream.total_out) & (size - 1);
krh@211
   277
krh@211
   278
	if (installer->stream.avail_out == 0)
krh@211
   279
		return 0;
krh@211
   280
krh@211
   281
	err = inflate(&installer->stream, Z_SYNC_FLUSH);
krh@211
   282
	if (err != Z_OK && err != Z_STREAM_END) {
krh@211
   283
		fprintf(stderr, "inflate error: %d (%m)\n", err);
krh@211
   284
		return -1;
krh@211
   285
	}
krh@211
   286
krh@211
   287
	return 0;
krh@211
   288
}
krh@211
   289
krh@211
   290
static int
krh@211
   291
create_path(struct installer *installer, const char *path, unsigned int mode)
krh@77
   292
{
krh@91
   293
	char buffer[PATH_MAX];
krh@176
   294
	struct stat buf;
krh@176
   295
	int fd, ret;
krh@77
   296
krh@91
   297
	if (razor_create_dir(installer->root, path) < 0)
krh@91
   298
		return -1;
krh@77
   299
krh@211
   300
	snprintf(buffer, sizeof buffer, "%s%s", installer->root, path);
krh@77
   301
krh@77
   302
	switch (mode >> 12) {
krh@77
   303
	case REG:
krh@176
   304
		/* FIXME: handle the case where a file is already there. */
krh@86
   305
		fd = open(buffer, O_WRONLY | O_CREAT | O_TRUNC, mode & 0x1ff);
krh@86
   306
		if (fd < 0){
krh@86
   307
			fprintf(stderr, "failed to create file %s\n", buffer);
krh@86
   308
			return -1;
krh@86
   309
		}
krh@86
   310
		while (installer->rest > 0) {
krh@86
   311
			if (installer_inflate(installer)) {
krh@86
   312
				fprintf(stderr, "failed to inflate\n");
krh@86
   313
				return -1;
krh@86
   314
			}
krh@91
   315
			if (razor_write(fd, installer->buffer,
krh@91
   316
					installer->length)) {
krh@86
   317
				fprintf(stderr, "failed to write payload\n");
krh@86
   318
				return -1;
krh@86
   319
			}
krh@86
   320
		}
krh@86
   321
		if (close(fd) < 0) {
krh@86
   322
			fprintf(stderr, "failed to close %s: %m\n", buffer);
krh@86
   323
			return -1;
krh@86
   324
		}
krh@86
   325
		return 0;
krh@86
   326
	case XDIR:
krh@176
   327
		ret = mkdir(buffer, mode & 0x1ff);
krh@176
   328
		if (ret == 0 || errno != EEXIST)
krh@176
   329
			return ret;
krh@176
   330
		if (stat(buffer, &buf) || !S_ISDIR(buf.st_mode)) {
krh@176
   331
			/* FIXME: also check that mode match. */
krh@176
   332
			fprintf(stderr,
krh@176
   333
				"%s exists but is not a directory\n", buffer);
krh@176
   334
			return -1;
krh@176
   335
		}
krh@176
   336
		return 0;
krh@86
   337
	case PIPE:
krh@86
   338
	case CDEV:
krh@86
   339
	case BDEV:
krh@86
   340
	case SOCK:
krh@86
   341
		printf("%s: unhandled file type %d\n", buffer, mode >> 12);
krh@86
   342
		return 0;
krh@86
   343
	case LINK:
krh@86
   344
		if (installer_inflate(installer)) {
krh@86
   345
			fprintf(stderr, "failed to inflate\n");
krh@86
   346
			return -1;
krh@86
   347
		}
krh@86
   348
		if (installer->length >= sizeof installer->buffer) {
krh@86
   349
			fprintf(stderr, "link name too long\n");
krh@86
   350
			return -1;
krh@86
   351
		}
krh@86
   352
		installer->buffer[installer->length] = '\0';
krh@86
   353
		if (symlink((const char *) installer->buffer, buffer)) {
krh@86
   354
			fprintf(stderr, "failed to create symlink, %m\n");
krh@86
   355
			return -1;
krh@86
   356
		}
krh@86
   357
		return 0;
krh@77
   358
	default:
krh@86
   359
		printf("%s: unknown file type %d\n", buffer, mode >> 12);
krh@86
   360
		return 0;
krh@77
   361
	}
krh@77
   362
}
krh@77
   363
krh@85
   364
static int
krh@86
   365
run_script(struct installer *installer,
krh@86
   366
	   unsigned int program_tag, unsigned int script_tag)
krh@85
   367
{
krh@85
   368
	int pid, status, fd[2];
krh@86
   369
	const char *script = NULL, *program = NULL;
krh@85
   370
krh@87
   371
	program = razor_rpm_get_indirect(installer->rpm, program_tag, NULL);
krh@87
   372
	script = razor_rpm_get_indirect(installer->rpm, script_tag, NULL);
krh@86
   373
	if (program == NULL && script == NULL) {
krh@202
   374
		return 0;
krh@86
   375
	} else if (program == NULL) {
krh@86
   376
		program = "/bin/sh";
krh@85
   377
	}
krh@85
   378
krh@85
   379
	if (pipe(fd) < 0) {
krh@85
   380
		fprintf(stderr, "failed to create pipe\n");
krh@85
   381
		return -1;
krh@85
   382
	}
krh@85
   383
	pid = fork();
krh@85
   384
	if (pid < 0) {
krh@85
   385
		fprintf(stderr, "failed to fork, %m\n");
krh@85
   386
	} else if (pid == 0) {
krh@85
   387
		if (dup2(fd[0], STDIN_FILENO) < 0) {
krh@85
   388
			fprintf(stderr, "failed redirect stdin, %m\n");
krh@85
   389
			return -1;
krh@85
   390
		}
krh@85
   391
		if (close(fd[0]) < 0 || close(fd[1]) < 0) {
krh@85
   392
			fprintf(stderr, "failed to close pipe, %m\n");
krh@89
   393
			return -1;
krh@85
   394
		}
krh@86
   395
		if (chroot(installer->root) < 0) {
krh@86
   396
			fprintf(stderr, "failed to chroot to %s, %m\n",
krh@86
   397
				installer->root);
krh@85
   398
			return -1;
krh@85
   399
		}
krh@86
   400
		printf("executing program %s in chroot %s\n",
krh@86
   401
		       program, installer->root);
krh@86
   402
		if (execl(program, program, NULL)) {
krh@86
   403
			fprintf(stderr, "failed to exec %s, %m\n", program);
krh@89
   404
			exit(-1);
krh@85
   405
		}
krh@85
   406
	} else {
krh@184
   407
		if (script && razor_write(fd[1], script, strlen(script)) < 0) {
krh@85
   408
			fprintf(stderr, "failed to pipe script, %m\n");
krh@85
   409
			return -1;
krh@85
   410
		}
krh@85
   411
		if (close(fd[0]) || close(fd[1])) {
krh@85
   412
			fprintf(stderr, "failed to close pipe, %m\n");
krh@85
   413
			return -1;
krh@85
   414
		}
krh@85
   415
		if (wait(&status) < 0) {
krh@85
   416
			fprintf(stderr, "wait for child failed, %m");
krh@85
   417
			return -1;
krh@85
   418
		}
krh@199
   419
		if (status)
krh@199
   420
			printf("script exited with status %d\n", status);
krh@85
   421
	}
krh@85
   422
krh@85
   423
	return 0;
krh@85
   424
}
krh@85
   425
krh@86
   426
static int
krh@86
   427
installer_init(struct installer *installer)
krh@77
   428
{
krh@86
   429
	unsigned char *gz_header;
krh@86
   430
	int method, flags, err;
krh@77
   431
krh@86
   432
	gz_header = installer->rpm->payload;
krh@77
   433
	if (gz_header[0] != 0x1f || gz_header[1] != 0x8b) {
krh@77
   434
		fprintf(stderr, "payload section doesn't have gz header\n");
krh@77
   435
		return -1;
krh@77
   436
	}
krh@77
   437
krh@77
   438
	method = gz_header[2];
krh@77
   439
	flags = gz_header[3];
krh@77
   440
krh@77
   441
	if (method != Z_DEFLATED || flags != 0) {
krh@77
   442
		fprintf(stderr,
krh@77
   443
			"unknown payload compression method or flags set\n");
krh@77
   444
		return -1;
krh@77
   445
	}
krh@77
   446
krh@86
   447
	installer->stream.zalloc = NULL;
krh@86
   448
	installer->stream.zfree = NULL;
krh@86
   449
	installer->stream.opaque = NULL;
krh@85
   450
krh@86
   451
	installer->stream.next_in  = gz_header + 10;
krh@86
   452
	installer->stream.avail_in =
krh@86
   453
		(installer->rpm->map + installer->rpm->size) -
krh@86
   454
		(void *) installer->stream.next_in;
krh@86
   455
	installer->stream.next_out = NULL;
krh@86
   456
	installer->stream.avail_out = 0;
krh@77
   457
krh@86
   458
	err = inflateInit2(&installer->stream, -MAX_WBITS);
krh@77
   459
	if (err != Z_OK) {
krh@77
   460
		fprintf(stderr, "inflateInit error: %d\n", err);
krh@77
   461
		return -1;
krh@77
   462
	}
krh@77
   463
krh@86
   464
	return 0;
krh@86
   465
}
krh@77
   466
krh@86
   467
static int
krh@86
   468
installer_finish(struct installer *installer)
krh@86
   469
{
krh@86
   470
	int err;
krh@77
   471
krh@86
   472
	err = inflateEnd(&installer->stream);
krh@77
   473
krh@77
   474
	if (err != Z_OK) {
krh@77
   475
		fprintf(stderr, "inflateEnd error: %d\n", err);
krh@77
   476
		return -1;
krh@77
   477
	}	    
krh@77
   478
krh@86
   479
	return 0;
krh@86
   480
}
krh@86
   481
krh@211
   482
static unsigned long
krh@211
   483
fixed_hex_to_ulong(const char *hex, int length)
krh@211
   484
{
krh@211
   485
	long l;
krh@211
   486
	int i;
krh@211
   487
krh@211
   488
	for (i = 0, l = 0; i < length; i++) {
krh@211
   489
		if (hex[i] < 'a')
krh@211
   490
			l = l * 16 + hex[i] - '0';
krh@211
   491
		else
krh@211
   492
			l = l * 16 + hex[i] - 'a' + 10;
krh@211
   493
	}
krh@211
   494
krh@211
   495
	return l;
krh@211
   496
}
krh@211
   497
krh@86
   498
int
krh@86
   499
razor_rpm_install(struct razor_rpm *rpm, const char *root)
krh@86
   500
{
krh@86
   501
	struct installer installer;
krh@86
   502
	struct cpio_file_header *header;
krh@86
   503
	struct stat buf;
krh@211
   504
	unsigned int mode;
krh@211
   505
	char *path;
krh@211
   506
	size_t filesize;
krh@86
   507
krh@86
   508
	installer.rpm = rpm;
krh@86
   509
	installer.root = root;
krh@86
   510
krh@86
   511
	/* FIXME: Only do this before a transaction, not per rpm. */
krh@86
   512
	if (stat(root, &buf) < 0 || !S_ISDIR(buf.st_mode)) {
krh@86
   513
		fprintf(stderr,
krh@86
   514
			"root installation directory \"%s\" does not exist\n",
krh@86
   515
			root);
krh@86
   516
		return -1;
krh@86
   517
	}
krh@86
   518
krh@86
   519
	if (installer_init(&installer))
krh@86
   520
		return -1;
krh@86
   521
krh@86
   522
	run_script(&installer, RPMTAG_PREINPROG, RPMTAG_PREIN);
krh@86
   523
krh@211
   524
	while (installer.stream.avail_in > 0) {
krh@211
   525
		installer.rest = sizeof *header;
krh@211
   526
		if (installer_inflate(&installer))
krh@211
   527
			return -1;
krh@211
   528
		
krh@211
   529
		header = (struct cpio_file_header *) installer.buffer;
krh@211
   530
		mode = fixed_hex_to_ulong(header->mode, sizeof header->mode);
krh@211
   531
		filesize = fixed_hex_to_ulong(header->filesize,
krh@211
   532
					      sizeof header->filesize);
krh@86
   533
krh@211
   534
		installer.rest = fixed_hex_to_ulong(header->namesize,
krh@211
   535
						    sizeof header->namesize);
krh@86
   536
krh@211
   537
		if (installer_inflate(&installer) ||
krh@211
   538
		    installer_align(&installer, 4))
krh@86
   539
			return -1;
krh@86
   540
krh@211
   541
		path = (char *) installer.buffer;
krh@211
   542
		/* This convention is so lame... */
krh@211
   543
		if (strcmp(path, "TRAILER!!!") == 0)
krh@211
   544
			break;
krh@211
   545
krh@211
   546
		installer.rest = filesize;
krh@211
   547
		if (create_path(&installer, path + 1, mode) < 0)
krh@211
   548
			return -1;
krh@211
   549
		if (installer_align(&installer, 4))
krh@211
   550
			return -1;
krh@86
   551
	}
krh@86
   552
krh@86
   553
	if (installer_finish(&installer))
krh@86
   554
		return -1;
krh@86
   555
krh@86
   556
	run_script(&installer, RPMTAG_POSTINPROG, RPMTAG_POSTIN);
krh@85
   557
krh@75
   558
	return 0;
krh@74
   559
}
krh@74
   560
krh@77
   561
int
krh@77
   562
razor_rpm_close(struct razor_rpm *rpm)
krh@74
   563
{
krh@77
   564
	int err;
krh@77
   565
krh@77
   566
	free(rpm->dirs);
krh@77
   567
	err = munmap(rpm->map, rpm->size);
krh@77
   568
	free(rpm);
krh@77
   569
krh@77
   570
	return err;
krh@75
   571
}
krh@74
   572
krh@75
   573
int
krh@77
   574
razor_importer_add_rpm(struct razor_importer *importer, struct razor_rpm *rpm)
krh@75
   575
{
krh@192
   576
	const char *name, *version, *release, *arch;
krh@148
   577
	const uint_32 *epoch;
krh@148
   578
	char evr[128], buf[16];
krh@75
   579
krh@87
   580
	name = razor_rpm_get_indirect(rpm, RPMTAG_NAME, NULL);
danw@143
   581
	epoch = razor_rpm_get_indirect(rpm, RPMTAG_EPOCH, NULL);
krh@87
   582
	version = razor_rpm_get_indirect(rpm, RPMTAG_VERSION, NULL);
krh@87
   583
	release = razor_rpm_get_indirect(rpm, RPMTAG_RELEASE, NULL);
krh@192
   584
	arch = razor_rpm_get_indirect(rpm, RPMTAG_ARCH, NULL);
krh@87
   585
krh@149
   586
	if (epoch) {
krh@148
   587
		snprintf(buf, sizeof buf, "%u", ntohl(*epoch));
krh@148
   588
		razor_build_evr(evr, sizeof evr, buf, version, release);
krh@148
   589
	} else {
krh@148
   590
		razor_build_evr(evr, sizeof evr, NULL, version, release);
krh@148
   591
	}
krh@192
   592
	razor_importer_begin_package(importer, name, evr, arch);
krh@87
   593
krh@87
   594
	import_properties(importer, RAZOR_PROPERTY_REQUIRES, rpm,
krh@87
   595
			  RPMTAG_REQUIRENAME,
krh@87
   596
			  RPMTAG_REQUIREVERSION,
krh@87
   597
			  RPMTAG_REQUIREFLAGS);
krh@87
   598
krh@87
   599
	import_properties(importer, RAZOR_PROPERTY_PROVIDES, rpm,
krh@87
   600
			  RPMTAG_PROVIDENAME,
krh@87
   601
			  RPMTAG_PROVIDEVERSION,
krh@87
   602
			  RPMTAG_PROVIDEFLAGS);
krh@87
   603
krh@87
   604
	import_properties(importer, RAZOR_PROPERTY_OBSOLETES, rpm,
krh@87
   605
			  RPMTAG_OBSOLETENAME,
krh@87
   606
			  RPMTAG_OBSOLETEVERSION,
krh@87
   607
			  RPMTAG_OBSOLETEFLAGS);
krh@87
   608
krh@87
   609
	import_properties(importer, RAZOR_PROPERTY_CONFLICTS, rpm,
krh@87
   610
			  RPMTAG_CONFLICTNAME,
krh@87
   611
			  RPMTAG_CONFLICTVERSION,
krh@87
   612
			  RPMTAG_CONFLICTFLAGS);
krh@87
   613
krh@77
   614
	import_files(importer, rpm);
krh@74
   615
krh@75
   616
	razor_importer_finish_package(importer);
krh@74
   617
krh@75
   618
	return 0;
krh@74
   619
}
danw@109
   620
danw@109
   621
union rpm_entry {
danw@109
   622
	void *p;
danw@109
   623
	char *string;
danw@109
   624
	char **list;
danw@109
   625
	uint_32 *flags;
krh@148
   626
	uint_32 integer;
danw@109
   627
};
danw@109
   628
danw@109
   629
static void
danw@109
   630
add_properties(struct razor_importer *importer,
danw@109
   631
	       enum razor_property_type property_type,
danw@109
   632
	       Header h, int_32 name_tag, int_32 version_tag, int_32 flags_tag)
danw@109
   633
{
danw@109
   634
	union rpm_entry names, versions, flags;
danw@109
   635
	int_32 i, type, count;
danw@109
   636
danw@109
   637
	headerGetEntry(h, name_tag, &type, &names.p, &count);
danw@109
   638
	headerGetEntry(h, version_tag, &type, &versions.p, &count);
danw@109
   639
	headerGetEntry(h, flags_tag, &type, &flags.p, &count);
danw@109
   640
danw@109
   641
	for (i = 0; i < count; i++)
danw@109
   642
		razor_importer_add_property(importer,
danw@109
   643
					    names.list[i],
danw@109
   644
					    rpm_to_razor_flags (flags.flags[i]),
danw@109
   645
					    versions.list[i],
danw@109
   646
					    property_type);
danw@109
   647
}
danw@109
   648
danw@109
   649
struct razor_set *
danw@109
   650
razor_set_create_from_rpmdb(void)
danw@109
   651
{
danw@109
   652
	struct razor_importer *importer;
danw@109
   653
	rpmdbMatchIterator iter;
danw@109
   654
	Header h;
danw@109
   655
	int_32 type, count, i;
krh@192
   656
	union rpm_entry name, epoch, version, release, arch;
danw@109
   657
	union rpm_entry basenames, dirnames, dirindexes;
krh@148
   658
	char filename[PATH_MAX], evr[128], buf[16];
danw@109
   659
	rpmdb db;
danw@109
   660
danw@109
   661
	rpmReadConfigFiles(NULL, NULL);
danw@109
   662
danw@109
   663
	if (rpmdbOpen("", &db, O_RDONLY, 0644) != 0) {
danw@109
   664
		fprintf(stderr, "cannot open rpm database\n");
danw@109
   665
		exit(1);
danw@109
   666
	}
danw@109
   667
danw@109
   668
	importer = razor_importer_new();
danw@109
   669
danw@109
   670
	iter = rpmdbInitIterator(db, 0, NULL, 0);
danw@109
   671
	while (h = rpmdbNextIterator(iter), h != NULL) {
danw@109
   672
		headerGetEntry(h, RPMTAG_NAME, &type, &name.p, &count);
danw@143
   673
		headerGetEntry(h, RPMTAG_EPOCH, &type, &epoch.p, &count);
danw@109
   674
		headerGetEntry(h, RPMTAG_VERSION, &type, &version.p, &count);
danw@109
   675
		headerGetEntry(h, RPMTAG_RELEASE, &type, &release.p, &count);
krh@192
   676
		headerGetEntry(h, RPMTAG_ARCH, &type, &arch.p, &count);
krh@148
   677
krh@148
   678
		if (epoch.flags != NULL) {
krh@148
   679
			snprintf(buf, sizeof buf, "%u", *epoch.flags);
krh@148
   680
			razor_build_evr(evr, sizeof evr,
krh@148
   681
					buf, version.string, release.string);
krh@148
   682
		} else {
krh@148
   683
			razor_build_evr(evr, sizeof evr,
krh@148
   684
					NULL, version.string, release.string);
krh@148
   685
		}
krh@148
   686
krh@192
   687
		razor_importer_begin_package(importer,
krh@192
   688
					     name.string, evr, arch.string);
danw@109
   689
danw@109
   690
		add_properties(importer, RAZOR_PROPERTY_REQUIRES, h,
danw@109
   691
			       RPMTAG_REQUIRENAME,
danw@109
   692
			       RPMTAG_REQUIREVERSION,
danw@109
   693
			       RPMTAG_REQUIREFLAGS);
danw@109
   694
danw@109
   695
		add_properties(importer, RAZOR_PROPERTY_PROVIDES, h,
danw@109
   696
			       RPMTAG_PROVIDENAME,
danw@109
   697
			       RPMTAG_PROVIDEVERSION,
danw@109
   698
			       RPMTAG_PROVIDEFLAGS);
danw@109
   699
danw@109
   700
		add_properties(importer, RAZOR_PROPERTY_OBSOLETES, h,
danw@109
   701
			       RPMTAG_OBSOLETENAME,
danw@109
   702
			       RPMTAG_OBSOLETEVERSION,
danw@109
   703
			       RPMTAG_OBSOLETEFLAGS);
danw@109
   704
danw@109
   705
		add_properties(importer, RAZOR_PROPERTY_CONFLICTS, h,
danw@109
   706
			       RPMTAG_CONFLICTNAME,
danw@109
   707
			       RPMTAG_CONFLICTVERSION,
danw@109
   708
			       RPMTAG_CONFLICTFLAGS);
danw@109
   709
danw@109
   710
		headerGetEntry(h, RPMTAG_BASENAMES, &type,
danw@109
   711
			       &basenames.p, &count);
danw@109
   712
		headerGetEntry(h, RPMTAG_DIRNAMES, &type,
danw@109
   713
			       &dirnames.p, &count);
danw@109
   714
		headerGetEntry(h, RPMTAG_DIRINDEXES, &type,
danw@109
   715
			       &dirindexes.p, &count);
danw@109
   716
		for (i = 0; i < count; i++) {
danw@109
   717
			snprintf(filename, sizeof filename, "%s%s",
danw@109
   718
				 dirnames.list[dirindexes.flags[i]],
danw@109
   719
				 basenames.list[i]);
danw@109
   720
			razor_importer_add_file(importer, filename);
danw@109
   721
		}
danw@109
   722
danw@109
   723
		razor_importer_finish_package(importer);
danw@109
   724
	}
danw@109
   725
danw@109
   726
	rpmdbClose(db);
danw@109
   727
danw@109
   728
	return razor_importer_finish(importer);
danw@109
   729
}