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