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.
11 #include <arpa/inet.h>
12 #include <rpm/rpmlib.h>
13 #include <rpm/rpmdb.h>
17 #include "razor-internal.h"
19 #define RPM_LEAD_SIZE 96
22 unsigned char magic[4];
23 unsigned char reserved[4];
28 struct rpm_header_index {
36 struct rpm_header *signature;
37 struct rpm_header *header;
45 static struct rpm_header_index *
46 razor_rpm_get_header(struct razor_rpm *rpm, unsigned int tag)
48 struct rpm_header_index *index, *end;
50 index = (struct rpm_header_index *) (rpm->header + 1);
51 end = index + ntohl(rpm->header->nindex);
53 if (ntohl(index->tag) == tag)
62 razor_rpm_get_indirect(struct razor_rpm *rpm,
63 unsigned int tag, unsigned int *count)
65 struct rpm_header_index *index;
67 index = razor_rpm_get_header(rpm, tag);
70 *count = ntohl(index->count);
72 return rpm->pool + ntohl(index->offset);
78 static enum razor_version_relation
79 rpm_to_razor_flags (uint_32 flags)
81 switch (flags & (RPMSENSE_LESS | RPMSENSE_EQUAL | RPMSENSE_GREATER)) {
83 return RAZOR_VERSION_LESS;
84 case RPMSENSE_LESS|RPMSENSE_EQUAL:
85 return RAZOR_VERSION_LESS_OR_EQUAL;
87 return RAZOR_VERSION_EQUAL;
88 case RPMSENSE_GREATER|RPMSENSE_EQUAL:
89 return RAZOR_VERSION_GREATER_OR_EQUAL;
90 case RPMSENSE_GREATER:
91 return RAZOR_VERSION_GREATER;
95 return RAZOR_VERSION_EQUAL;
99 import_properties(struct razor_importer *importer, unsigned long type,
100 struct razor_rpm *rpm,
101 int name_tag, int version_tag, int flags_tag)
103 const char *name, *version;
104 const uint_32 *flags;
106 unsigned int i, count;
108 name = razor_rpm_get_indirect(rpm, name_tag, &count);
112 flags = razor_rpm_get_indirect(rpm, flags_tag, &count);
114 version = razor_rpm_get_indirect(rpm, version_tag, &count);
115 for (i = 0; i < count; i++) {
116 f = rpm_to_razor_flags(ntohl(flags[i]));
117 razor_importer_add_property(importer, name, f, version, type);
118 name += strlen(name) + 1;
119 version += strlen(version) + 1;
124 import_files(struct razor_importer *importer, struct razor_rpm *rpm)
127 const uint32_t *index;
128 unsigned int i, count;
131 /* assert: count is the same for all arrays */
133 index = razor_rpm_get_indirect(rpm, RPMTAG_DIRINDEXES, &count);
134 name = razor_rpm_get_indirect(rpm, RPMTAG_BASENAMES, &count);
135 for (i = 0; i < count; i++) {
136 snprintf(buffer, sizeof buffer,
137 "%s%s", rpm->dirs[ntohl(*index)], name);
138 razor_importer_add_file(importer, buffer);
139 name += strlen(name) + 1;
145 razor_rpm_open(const char *filename)
147 struct razor_rpm *rpm;
148 struct rpm_header_index *base, *index;
150 unsigned int count, i, nindex, hsize;
154 rpm = malloc(sizeof *rpm);
155 memset(rpm, 0, sizeof *rpm);
157 fd = open(filename, O_RDONLY);
159 fprintf(stderr, "couldn't open %s\n", filename);
163 if (fstat(fd, &buf) < 0) {
164 fprintf(stderr, "failed to stat %s (%m)\n", filename);
168 rpm->size = buf.st_size;
169 rpm->map = mmap(NULL, rpm->size, PROT_READ, MAP_PRIVATE, fd, 0);
170 if (rpm->map == MAP_FAILED) {
171 fprintf(stderr, "couldn't mmap %s\n", filename);
176 rpm->signature = rpm->map + RPM_LEAD_SIZE;
177 nindex = ntohl(rpm->signature->nindex);
178 hsize = ntohl(rpm->signature->hsize);
179 rpm->header = (void *) (rpm->signature + 1) +
180 ALIGN(nindex * sizeof *index + hsize, 8);
181 nindex = ntohl(rpm->header->nindex);
182 hsize = ntohl(rpm->header->hsize);
183 rpm->payload = (void *) (rpm->header + 1) +
184 nindex * sizeof *index + hsize;
186 base = (struct rpm_header_index *) (rpm->header + 1);
187 rpm->pool = (void *) base + nindex * sizeof *index;
189 /* Look up dir names now so we can index them directly. */
190 name = razor_rpm_get_indirect(rpm, RPMTAG_DIRNAMES, &count);
192 rpm->dirs = calloc(count, sizeof *rpm->dirs);
193 for (i = 0; i < count; i++) {
195 name += strlen(name) + 1;
198 name = razor_rpm_get_indirect(rpm, RPMTAG_OLDFILENAMES,
201 fprintf(stderr, "old filenames not supported\n");
209 struct cpio_file_header {
228 #define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
229 #define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
230 #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
231 #define ORIG_NAME 0x08 /* bit 3 set: original file name present */
232 #define COMMENT 0x10 /* bit 4 set: file comment present */
233 #define RESERVED 0xE0 /* bits 5..7: reserved */
237 struct razor_rpm *rpm;
239 unsigned char buffer[32768];
244 installer_inflate(struct installer *installer)
249 if (installer->rest > sizeof installer->buffer)
250 length = sizeof installer->buffer;
252 length = installer->rest;
254 installer->stream.next_out = installer->buffer;
255 installer->stream.avail_out = length;
256 err = inflate(&installer->stream, Z_SYNC_FLUSH);
257 if (err != Z_OK && err != Z_STREAM_END) {
258 fprintf(stderr, "inflate error: %d (%m)\n", err);
262 installer->rest -= length;
263 installer->length = length;
269 installer_align(struct installer *installer, size_t size)
271 unsigned char buffer[4];
274 installer->stream.next_out = buffer;
275 installer->stream.avail_out =
276 (size - installer->stream.total_out) & (size - 1);
278 if (installer->stream.avail_out == 0)
281 err = inflate(&installer->stream, Z_SYNC_FLUSH);
282 if (err != Z_OK && err != Z_STREAM_END) {
283 fprintf(stderr, "inflate error: %d (%m)\n", err);
291 create_path(struct installer *installer, const char *path, unsigned int mode)
293 char buffer[PATH_MAX];
297 if (razor_create_dir(installer->root, path) < 0)
300 snprintf(buffer, sizeof buffer, "%s%s", installer->root, path);
302 switch (mode >> 12) {
304 /* FIXME: handle the case where a file is already there. */
305 fd = open(buffer, O_WRONLY | O_CREAT | O_TRUNC, mode & 0x1ff);
307 fprintf(stderr, "failed to create file %s\n", buffer);
310 while (installer->rest > 0) {
311 if (installer_inflate(installer)) {
312 fprintf(stderr, "failed to inflate\n");
315 if (razor_write(fd, installer->buffer,
316 installer->length)) {
317 fprintf(stderr, "failed to write payload\n");
322 fprintf(stderr, "failed to close %s: %m\n", buffer);
327 ret = mkdir(buffer, mode & 0x1ff);
328 if (ret == 0 || errno != EEXIST)
330 if (stat(buffer, &buf) || !S_ISDIR(buf.st_mode)) {
331 /* FIXME: also check that mode match. */
333 "%s exists but is not a directory\n", buffer);
341 printf("%s: unhandled file type %d\n", buffer, mode >> 12);
344 if (installer_inflate(installer)) {
345 fprintf(stderr, "failed to inflate\n");
348 if (installer->length >= sizeof installer->buffer) {
349 fprintf(stderr, "link name too long\n");
352 installer->buffer[installer->length] = '\0';
353 if (symlink((const char *) installer->buffer, buffer)) {
354 fprintf(stderr, "failed to create symlink, %m\n");
359 printf("%s: unknown file type %d\n", buffer, mode >> 12);
365 run_script(struct installer *installer,
366 unsigned int program_tag, unsigned int script_tag)
368 int pid, status, fd[2];
369 const char *script = NULL, *program = NULL;
371 program = razor_rpm_get_indirect(installer->rpm, program_tag, NULL);
372 script = razor_rpm_get_indirect(installer->rpm, script_tag, NULL);
373 if (program == NULL && script == NULL) {
375 } else if (program == NULL) {
380 fprintf(stderr, "failed to create pipe\n");
385 fprintf(stderr, "failed to fork, %m\n");
386 } else if (pid == 0) {
387 if (dup2(fd[0], STDIN_FILENO) < 0) {
388 fprintf(stderr, "failed redirect stdin, %m\n");
391 if (close(fd[0]) < 0 || close(fd[1]) < 0) {
392 fprintf(stderr, "failed to close pipe, %m\n");
395 if (chroot(installer->root) < 0) {
396 fprintf(stderr, "failed to chroot to %s, %m\n",
400 printf("executing program %s in chroot %s\n",
401 program, installer->root);
402 if (execl(program, program, NULL)) {
403 fprintf(stderr, "failed to exec %s, %m\n", program);
407 if (script && razor_write(fd[1], script, strlen(script)) < 0) {
408 fprintf(stderr, "failed to pipe script, %m\n");
411 if (close(fd[0]) || close(fd[1])) {
412 fprintf(stderr, "failed to close pipe, %m\n");
415 if (wait(&status) < 0) {
416 fprintf(stderr, "wait for child failed, %m");
420 printf("script exited with status %d\n", status);
427 installer_init(struct installer *installer)
429 unsigned char *gz_header;
430 int method, flags, err;
432 gz_header = installer->rpm->payload;
433 if (gz_header[0] != 0x1f || gz_header[1] != 0x8b) {
434 fprintf(stderr, "payload section doesn't have gz header\n");
438 method = gz_header[2];
439 flags = gz_header[3];
441 if (method != Z_DEFLATED || flags != 0) {
443 "unknown payload compression method or flags set\n");
447 installer->stream.zalloc = NULL;
448 installer->stream.zfree = NULL;
449 installer->stream.opaque = NULL;
451 installer->stream.next_in = gz_header + 10;
452 installer->stream.avail_in =
453 (installer->rpm->map + installer->rpm->size) -
454 (void *) installer->stream.next_in;
455 installer->stream.next_out = NULL;
456 installer->stream.avail_out = 0;
458 err = inflateInit2(&installer->stream, -MAX_WBITS);
460 fprintf(stderr, "inflateInit error: %d\n", err);
468 installer_finish(struct installer *installer)
472 err = inflateEnd(&installer->stream);
475 fprintf(stderr, "inflateEnd error: %d\n", err);
483 fixed_hex_to_ulong(const char *hex, int length)
488 for (i = 0, l = 0; i < length; i++) {
490 l = l * 16 + hex[i] - '0';
492 l = l * 16 + hex[i] - 'a' + 10;
499 razor_rpm_install(struct razor_rpm *rpm, const char *root)
501 struct installer installer;
502 struct cpio_file_header *header;
509 installer.root = root;
511 /* FIXME: Only do this before a transaction, not per rpm. */
512 if (stat(root, &buf) < 0 || !S_ISDIR(buf.st_mode)) {
514 "root installation directory \"%s\" does not exist\n",
519 if (installer_init(&installer))
522 run_script(&installer, RPMTAG_PREINPROG, RPMTAG_PREIN);
524 while (installer.stream.avail_in > 0) {
525 installer.rest = sizeof *header;
526 if (installer_inflate(&installer))
529 header = (struct cpio_file_header *) installer.buffer;
530 mode = fixed_hex_to_ulong(header->mode, sizeof header->mode);
531 filesize = fixed_hex_to_ulong(header->filesize,
532 sizeof header->filesize);
534 installer.rest = fixed_hex_to_ulong(header->namesize,
535 sizeof header->namesize);
537 if (installer_inflate(&installer) ||
538 installer_align(&installer, 4))
541 path = (char *) installer.buffer;
542 /* This convention is so lame... */
543 if (strcmp(path, "TRAILER!!!") == 0)
546 installer.rest = filesize;
547 if (create_path(&installer, path + 1, mode) < 0)
549 if (installer_align(&installer, 4))
553 if (installer_finish(&installer))
556 run_script(&installer, RPMTAG_POSTINPROG, RPMTAG_POSTIN);
562 razor_rpm_close(struct razor_rpm *rpm)
567 err = munmap(rpm->map, rpm->size);
574 razor_importer_add_rpm(struct razor_importer *importer, struct razor_rpm *rpm)
576 const char *name, *version, *release, *arch;
577 const uint_32 *epoch;
578 char evr[128], buf[16];
580 name = razor_rpm_get_indirect(rpm, RPMTAG_NAME, NULL);
581 epoch = razor_rpm_get_indirect(rpm, RPMTAG_EPOCH, NULL);
582 version = razor_rpm_get_indirect(rpm, RPMTAG_VERSION, NULL);
583 release = razor_rpm_get_indirect(rpm, RPMTAG_RELEASE, NULL);
584 arch = razor_rpm_get_indirect(rpm, RPMTAG_ARCH, NULL);
587 snprintf(buf, sizeof buf, "%u", ntohl(*epoch));
588 razor_build_evr(evr, sizeof evr, buf, version, release);
590 razor_build_evr(evr, sizeof evr, NULL, version, release);
592 razor_importer_begin_package(importer, name, evr, arch);
594 import_properties(importer, RAZOR_PROPERTY_REQUIRES, rpm,
596 RPMTAG_REQUIREVERSION,
597 RPMTAG_REQUIREFLAGS);
599 import_properties(importer, RAZOR_PROPERTY_PROVIDES, rpm,
601 RPMTAG_PROVIDEVERSION,
602 RPMTAG_PROVIDEFLAGS);
604 import_properties(importer, RAZOR_PROPERTY_OBSOLETES, rpm,
606 RPMTAG_OBSOLETEVERSION,
607 RPMTAG_OBSOLETEFLAGS);
609 import_properties(importer, RAZOR_PROPERTY_CONFLICTS, rpm,
611 RPMTAG_CONFLICTVERSION,
612 RPMTAG_CONFLICTFLAGS);
614 import_files(importer, rpm);
616 razor_importer_finish_package(importer);
630 add_properties(struct razor_importer *importer,
631 enum razor_property_type property_type,
632 Header h, int_32 name_tag, int_32 version_tag, int_32 flags_tag)
634 union rpm_entry names, versions, flags;
635 int_32 i, type, count;
637 headerGetEntry(h, name_tag, &type, &names.p, &count);
638 headerGetEntry(h, version_tag, &type, &versions.p, &count);
639 headerGetEntry(h, flags_tag, &type, &flags.p, &count);
641 for (i = 0; i < count; i++)
642 razor_importer_add_property(importer,
644 rpm_to_razor_flags (flags.flags[i]),
650 razor_set_create_from_rpmdb(void)
652 struct razor_importer *importer;
653 rpmdbMatchIterator iter;
655 int_32 type, count, i;
656 union rpm_entry name, epoch, version, release, arch;
657 union rpm_entry basenames, dirnames, dirindexes;
658 char filename[PATH_MAX], evr[128], buf[16];
661 rpmReadConfigFiles(NULL, NULL);
663 if (rpmdbOpen("", &db, O_RDONLY, 0644) != 0) {
664 fprintf(stderr, "cannot open rpm database\n");
668 importer = razor_importer_new();
670 iter = rpmdbInitIterator(db, 0, NULL, 0);
671 while (h = rpmdbNextIterator(iter), h != NULL) {
672 headerGetEntry(h, RPMTAG_NAME, &type, &name.p, &count);
673 headerGetEntry(h, RPMTAG_EPOCH, &type, &epoch.p, &count);
674 headerGetEntry(h, RPMTAG_VERSION, &type, &version.p, &count);
675 headerGetEntry(h, RPMTAG_RELEASE, &type, &release.p, &count);
676 headerGetEntry(h, RPMTAG_ARCH, &type, &arch.p, &count);
678 if (epoch.flags != NULL) {
679 snprintf(buf, sizeof buf, "%u", *epoch.flags);
680 razor_build_evr(evr, sizeof evr,
681 buf, version.string, release.string);
683 razor_build_evr(evr, sizeof evr,
684 NULL, version.string, release.string);
687 razor_importer_begin_package(importer,
688 name.string, evr, arch.string);
690 add_properties(importer, RAZOR_PROPERTY_REQUIRES, h,
692 RPMTAG_REQUIREVERSION,
693 RPMTAG_REQUIREFLAGS);
695 add_properties(importer, RAZOR_PROPERTY_PROVIDES, h,
697 RPMTAG_PROVIDEVERSION,
698 RPMTAG_PROVIDEFLAGS);
700 add_properties(importer, RAZOR_PROPERTY_OBSOLETES, h,
702 RPMTAG_OBSOLETEVERSION,
703 RPMTAG_OBSOLETEFLAGS);
705 add_properties(importer, RAZOR_PROPERTY_CONFLICTS, h,
707 RPMTAG_CONFLICTVERSION,
708 RPMTAG_CONFLICTFLAGS);
710 headerGetEntry(h, RPMTAG_BASENAMES, &type,
711 &basenames.p, &count);
712 headerGetEntry(h, RPMTAG_DIRNAMES, &type,
713 &dirnames.p, &count);
714 headerGetEntry(h, RPMTAG_DIRINDEXES, &type,
715 &dirindexes.p, &count);
716 for (i = 0; i < count; i++) {
717 snprintf(filename, sizeof filename, "%s%s",
718 dirnames.list[dirindexes.flags[i]],
720 razor_importer_add_file(importer, filename);
723 razor_importer_finish_package(importer);
728 return razor_importer_finish(importer);