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