diff --git a/archival/rpm.c b/archival/rpm.c index 98039d4..89b36dd 100644 --- a/archival/rpm.c +++ b/archival/rpm.c @@ -16,18 +16,6 @@ //applet:IF_RPM(APPLET(rpm, BB_DIR_BIN, BB_SUID_DROP)) //kbuild:lib-$(CONFIG_RPM) += rpm.o -//usage:#define rpm_trivial_usage -//usage: "-i PACKAGE.rpm; rpm -qp[ildc] PACKAGE.rpm" -//usage:#define rpm_full_usage "\n\n" -//usage: "Manipulate RPM packages\n" -//usage: "\nCommands:" -//usage: "\n -i Install package" -//usage: "\n -qp Query package" -//usage: "\n -qpi Show information" -//usage: "\n -qpl List contents" -//usage: "\n -qpd List documents" -//usage: "\n -qpc List config files" - #include "libbb.h" #include "common_bufsiz.h" #include "bb_archive.h" @@ -91,8 +79,9 @@ typedef struct { struct globals { void *map; - rpm_index **mytags; + rpm_index *mytags; int tagcount; + unsigned mapsize, pagesize; } FIX_ALIASING; #define G (*(struct globals*)bb_common_bufsiz1) #define INIT_G() do { setup_common_bufsiz(); } while (0) @@ -128,105 +117,122 @@ static void extract_cpio(int fd, const char *source_rpm) continue; } -static rpm_index **rpm_gettags(int fd, int *num_tags) +static rpm_index *rpm_gettags(int fd) { - /* We should never need more than 200 (shrink via realloc later) */ - rpm_index **tags = xzalloc(200 * sizeof(tags[0])); - int pass, tagindex = 0; + rpm_index *tags; + unsigned pass, idx; + unsigned storepos; - xlseek(fd, 96, SEEK_CUR); /* Seek past the unused lead */ + storepos = xlseek(fd, 96, SEEK_CUR); /* Seek past the unused lead */ + G.tagcount = 0; + tags = NULL; + idx = 0; /* 1st pass is the signature headers, 2nd is the main stuff */ for (pass = 0; pass < 2; pass++) { struct rpm_header header; - rpm_index *tmpindex; - int storepos; + unsigned cnt; xread(fd, &header, sizeof(header)); if (header.magic_and_ver != htonl(RPM_HEADER_MAGICnVER)) return NULL; /* Invalid magic, or not version 1 */ header.size = ntohl(header.size); - header.entries = ntohl(header.entries); - storepos = xlseek(fd, 0, SEEK_CUR) + header.entries * 16; - - while (header.entries--) { - tmpindex = tags[tagindex++] = xmalloc(sizeof(*tmpindex)); - xread(fd, tmpindex, sizeof(*tmpindex)); - tmpindex->tag = ntohl(tmpindex->tag); - tmpindex->type = ntohl(tmpindex->type); - tmpindex->count = ntohl(tmpindex->count); - tmpindex->offset = storepos + ntohl(tmpindex->offset); + cnt = ntohl(header.entries); + storepos += sizeof(header) + cnt * 16; + + G.tagcount += cnt; + tags = xrealloc(tags, G.tagcount * sizeof(tags[0])); + xread(fd, &tags[idx], sizeof(tags[0]) * cnt); + while (cnt--) { + rpm_index *tag = &tags[idx]; + tag->tag = ntohl(tag->tag); + tag->type = ntohl(tag->type); + tag->count = ntohl(tag->count); + tag->offset = storepos + ntohl(tag->offset); if (pass == 0) - tmpindex->tag -= 743; + tag->tag -= 743; + idx++; } - storepos = xlseek(fd, header.size, SEEK_CUR); /* Seek past store */ /* Skip padding to 8 byte boundary after reading signature headers */ if (pass == 0) - xlseek(fd, (-storepos) & 0x7, SEEK_CUR); + while (header.size & 7) + header.size++; + /* Seek past store */ + storepos = xlseek(fd, header.size, SEEK_CUR); } - /* realloc tags to save space */ - tags = xrealloc(tags, tagindex * sizeof(tags[0])); - *num_tags = tagindex; - /* All done, leave the file at the start of the gzipped cpio archive */ + + /* Map the store */ + storepos = (storepos + G.pagesize) & -(int)G.pagesize; + /* remember size for munmap */ + G.mapsize = storepos; + /* some NOMMU systems prefer MAP_PRIVATE over MAP_SHARED */ + G.map = mmap(0, storepos, PROT_READ, MAP_PRIVATE, fd, 0); + if (G.map == MAP_FAILED) + return NULL; /* error */ + return tags; } static int bsearch_rpmtag(const void *key, const void *item) { int *tag = (int *)key; - rpm_index **tmp = (rpm_index **) item; - return (*tag - tmp[0]->tag); + rpm_index *tmp = (rpm_index *) item; + return (*tag - tmp->tag); } static int rpm_getcount(int tag) { - rpm_index **found; - found = bsearch(&tag, G.mytags, G.tagcount, sizeof(struct rpmtag *), bsearch_rpmtag); + rpm_index *found; + found = bsearch(&tag, G.mytags, G.tagcount, sizeof(G.mytags[0]), bsearch_rpmtag); if (!found) return 0; - return found[0]->count; + return found->count; } static char *rpm_getstr(int tag, int itemindex) { - rpm_index **found; - found = bsearch(&tag, G.mytags, G.tagcount, sizeof(struct rpmtag *), bsearch_rpmtag); - if (!found || itemindex >= found[0]->count) + rpm_index *found; + found = bsearch(&tag, G.mytags, G.tagcount, sizeof(G.mytags[0]), bsearch_rpmtag); + if (!found || itemindex >= found->count) return NULL; - if (found[0]->type == RPM_STRING_TYPE - || found[0]->type == RPM_I18NSTRING_TYPE - || found[0]->type == RPM_STRING_ARRAY_TYPE + if (found->type == RPM_STRING_TYPE + || found->type == RPM_I18NSTRING_TYPE + || found->type == RPM_STRING_ARRAY_TYPE ) { int n; - char *tmpstr = (char *) G.map + found[0]->offset; + char *tmpstr = (char *) G.map + found->offset; for (n = 0; n < itemindex; n++) tmpstr = tmpstr + strlen(tmpstr) + 1; return tmpstr; } return NULL; } +static char *rpm_getstr0(int tag) +{ + return rpm_getstr(tag, 0); +} static int rpm_getint(int tag, int itemindex) { - rpm_index **found; + rpm_index *found; char *tmpint; /* gcc throws warnings here when sizeof(void*)!=sizeof(int) ... * it's ok to ignore it because tag won't be used as a pointer */ - found = bsearch(&tag, G.mytags, G.tagcount, sizeof(struct rpmtag *), bsearch_rpmtag); - if (!found || itemindex >= found[0]->count) + found = bsearch(&tag, G.mytags, G.tagcount, sizeof(G.mytags[0]), bsearch_rpmtag); + if (!found || itemindex >= found->count) return -1; - tmpint = (char *) G.map + found[0]->offset; - if (found[0]->type == RPM_INT32_TYPE) { + tmpint = (char *) G.map + found->offset; + if (found->type == RPM_INT32_TYPE) { tmpint += itemindex*4; return ntohl(*(int32_t*)tmpint); } - if (found[0]->type == RPM_INT16_TYPE) { + if (found->type == RPM_INT16_TYPE) { tmpint += itemindex*2; return ntohs(*(int16_t*)tmpint); } - if (found[0]->type == RPM_INT8_TYPE) { + if (found->type == RPM_INT8_TYPE) { tmpint += itemindex; return *(int8_t*)tmpint; } @@ -273,11 +279,71 @@ static void loop_through_files(int filetag, void (*fileaction)(char *filename, i } } +#if 0 //DEBUG +static void print_all_tags(void) +{ + unsigned i = 0; + while (i < G.tagcount) { + rpm_index *tag = &G.mytags[i]; + if (tag->type == RPM_STRING_TYPE + || tag->type == RPM_I18NSTRING_TYPE + || tag->type == RPM_STRING_ARRAY_TYPE + ) { + unsigned n; + char *str = (char *) G.map + tag->offset; + + printf("tag[%u] %08x type %08x offset %08x count %d '%s'\n", + i, tag->tag, tag->type, tag->offset, tag->count, str + ); + for (n = 1; n < tag->count; n++) { + str += strlen(str) + 1; + printf("\t'%s'\n", str); + } + } + i++; + } +} +#else +#define print_all_tags() ((void)0) +#endif + +//usage:#define rpm_trivial_usage +//usage: "-i PACKAGE.rpm; rpm -qp[ildc] PACKAGE.rpm" +//usage:#define rpm_full_usage "\n\n" +//usage: "Manipulate RPM packages\n" +//usage: "\nCommands:" +//usage: "\n -i Install package" +//usage: "\n -qp Query package" +//usage: "\n -qpi Show information" +//usage: "\n -qpl List contents" +//usage: "\n -qpd List documents" +//usage: "\n -qpc List config files" + +/* RPM version 4.13.0.1: + * Unlike -q, -i seems to imply -p: -i, -ip and -pi work the same. + * OTOH, with -q order is important: "-piq FILE.rpm" works as -qp, not -qpi + * (IOW: shows only package name, not package info). + * "-iq ARG" works as -q: treats ARG as package name, not a file. + * + * "man rpm" on -l option and options implying it: + * -l, --list List files in package. + * -c, --configfiles List only configuration files (implies -l). + * -d, --docfiles List only documentation files (implies -l). + * -L, --licensefiles List only license files (implies -l). + * --dump Dump file information as follows (implies -l): + * path size mtime digest mode owner group isconfig isdoc rdev symlink + * -s, --state Display the states of files in the package (implies -l). + * The state of each file is one of normal, not installed, or replaced. + * + * Looks like we can switch to getopt32 here: in practice, people + * do place -q first if they intend to use it (misinterpreting "-piq" wouldn't matter). + */ int rpm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int rpm_main(int argc, char **argv) { int opt, func = 0; - const unsigned pagesize = getpagesize(); + + G.pagesize = getpagesize(); while ((opt = getopt(argc, argv, "iqpldc")) != -1) { switch (opt) { @@ -289,17 +355,17 @@ int rpm_main(int argc, char **argv) if (func) bb_show_usage(); func = rpm_query; break; - case 'p': /* Query a package */ + case 'p': /* Query a package (IOW: .rpm file, we are not querying RPMDB) */ func |= rpm_query_package; break; case 'l': /* List files in a package */ func |= rpm_query_list; break; - case 'd': /* List doc files in a package (implies list) */ + case 'd': /* List doc files in a package (implies -l) */ func |= rpm_query_list; func |= rpm_query_list_doc; break; - case 'c': /* List config files in a package (implies list) */ + case 'c': /* List config files in a package (implies -l) */ func |= rpm_query_list; func |= rpm_query_list_config; break; @@ -313,24 +379,22 @@ int rpm_main(int argc, char **argv) bb_show_usage(); } - while (*argv) { + for (;;) { int rpm_fd; - unsigned mapsize; const char *source_rpm; - rpm_fd = xopen(*argv++, O_RDONLY); - G.mytags = rpm_gettags(rpm_fd, &G.tagcount); + rpm_fd = xopen(*argv, O_RDONLY); + G.mytags = rpm_gettags(rpm_fd); if (!G.mytags) - bb_error_msg_and_die("error reading rpm header"); - mapsize = xlseek(rpm_fd, 0, SEEK_CUR); - mapsize = (mapsize + pagesize) & -(int)pagesize; - /* Some NOMMU systems prefer MAP_PRIVATE over MAP_SHARED */ - G.map = mmap(0, mapsize, PROT_READ, MAP_PRIVATE, rpm_fd, 0); -//FIXME: error check? + bb_error_msg_and_die("error reading rpm header from '%s'", *argv); + + print_all_tags(); - source_rpm = rpm_getstr(TAG_SOURCERPM, 0); + source_rpm = rpm_getstr0(TAG_SOURCERPM); if (func & rpm_install) { + /* -i (and not -qi) */ + /* Backup any config files */ loop_through_files(TAG_BASENAMES, fileaction_dobackup); /* Extact the archive */ @@ -338,10 +402,13 @@ int rpm_main(int argc, char **argv) /* Set the correct file uid/gid's */ loop_through_files(TAG_BASENAMES, fileaction_setowngrp); } - else if ((func & (rpm_query|rpm_query_package)) == (rpm_query|rpm_query_package)) { + else + if ((func & (rpm_query|rpm_query_package)) == (rpm_query|rpm_query_package)) { + /* -qp */ + if (!(func & (rpm_query_info|rpm_query_list))) { /* If just a straight query, just give package name */ - printf("%s-%s-%s\n", rpm_getstr(TAG_NAME, 0), rpm_getstr(TAG_VERSION, 0), rpm_getstr(TAG_RELEASE, 0)); + printf("%s-%s-%s\n", rpm_getstr0(TAG_NAME), rpm_getstr0(TAG_VERSION), rpm_getstr0(TAG_RELEASE)); } if (func & rpm_query_info) { /* Do the nice printout */ @@ -350,30 +417,33 @@ int rpm_main(int argc, char **argv) char bdatestring[50]; const char *p; - printf("%-12s: %s\n", "Name" , rpm_getstr(TAG_NAME, 0)); + printf("%-12s: %s\n", "Name" , rpm_getstr0(TAG_NAME)); /* TODO compat: add "Epoch" here */ - printf("%-12s: %s\n", "Version" , rpm_getstr(TAG_VERSION, 0)); - printf("%-12s: %s\n", "Release" , rpm_getstr(TAG_RELEASE, 0)); + printf("%-12s: %s\n", "Version" , rpm_getstr0(TAG_VERSION)); + printf("%-12s: %s\n", "Release" , rpm_getstr0(TAG_RELEASE)); /* add "Architecture" */ - printf("%-12s: %s\n", "Install Date", "(not installed)"); - printf("%-12s: %s\n", "Group" , rpm_getstr(TAG_GROUP, 0)); + /* printf("%-12s: %s\n", "Install Date", "(not installed)"); - we don't know */ + printf("%-12s: %s\n", "Group" , rpm_getstr0(TAG_GROUP)); printf("%-12s: %d\n", "Size" , rpm_getint(TAG_SIZE, 0)); - printf("%-12s: %s\n", "License" , rpm_getstr(TAG_LICENSE, 0)); + printf("%-12s: %s\n", "License" , rpm_getstr0(TAG_LICENSE)); /* add "Signature" */ printf("%-12s: %s\n", "Source RPM" , source_rpm ? source_rpm : "(none)"); bdate_time = rpm_getint(TAG_BUILDTIME, 0); bdate_ptm = localtime(&bdate_time); strftime(bdatestring, 50, "%a %d %b %Y %T %Z", bdate_ptm); printf("%-12s: %s\n", "Build Date" , bdatestring); - printf("%-12s: %s\n", "Build Host" , rpm_getstr(TAG_BUILDHOST, 0)); - p = rpm_getstr(TAG_PREFIXS, 0); + printf("%-12s: %s\n", "Build Host" , rpm_getstr0(TAG_BUILDHOST)); + p = rpm_getstr0(TAG_PREFIXS); printf("%-12s: %s\n", "Relocations" , p ? p : "(not relocatable)"); /* add "Packager" */ - p = rpm_getstr(TAG_VENDOR, 0); - printf("%-12s: %s\n", "Vendor" , p ? p : "(none)"); - printf("%-12s: %s\n", "URL" , rpm_getstr(TAG_URL, 0)); - printf("%-12s: %s\n", "Summary" , rpm_getstr(TAG_SUMMARY, 0)); - printf("Description :\n%s\n", rpm_getstr(TAG_DESCRIPTION, 0)); + p = rpm_getstr0(TAG_VENDOR); + if (p) /* rpm 4.13.0.1 does not show "(none)" for Vendor: */ + printf("%-12s: %s\n", "Vendor" , p); + p = rpm_getstr0(TAG_URL); + if (p) /* rpm 4.13.0.1 does not show "(none)"/"(null)" for URL: */ + printf("%-12s: %s\n", "URL" , p); + printf("%-12s: %s\n", "Summary" , rpm_getstr0(TAG_SUMMARY)); + printf("Description :\n%s\n", rpm_getstr0(TAG_DESCRIPTION)); } if (func & rpm_query_list) { int count, it, flags; @@ -396,10 +466,16 @@ int rpm_main(int argc, char **argv) rpm_getstr(TAG_BASENAMES, it)); } } + } else { + /* Unsupported (help text shows what we support) */ + bb_show_usage(); } - munmap(G.map, mapsize); + if (!*++argv) + break; + munmap(G.map, G.mapsize); free(G.mytags); close(rpm_fd); } + return 0; } diff --git a/archival/rpm2cpio.c b/archival/rpm2cpio.c index 3e4a6a2..a6db19c 100644 --- a/archival/rpm2cpio.c +++ b/archival/rpm2cpio.c @@ -75,11 +75,14 @@ int rpm2cpio_main(int argc UNUSED_PARAM, char **argv) /* Skip the main header */ skip_header(); - //if (SEAMLESS_COMPRESSION) + //if (SEAMLESS_COMPRESSION) - we do this at the end instead. // /* We need to know whether child (gzip/bzip/etc) exits abnormally */ // signal(SIGCHLD, check_errors_in_children); - /* This works, but doesn't report uncompress errors (they happen in child) */ +//TODO: look for rpm tag RPMTAG_PAYLOADCOMPRESSOR (dec 1125, hex 0x465), +// if the value is "lzma", set up decompressor without detection +// (lzma can't be detected). + setup_unzip_on_fd(rpm_fd, /*fail_if_not_compressed:*/ 1); if (bb_copyfd_eof(rpm_fd, STDOUT_FILENO) < 0) bb_error_msg_and_die("error unpacking"); diff --git a/archival/rpm.c b/archival/rpm.c index 89b36dd..bb6cc45 100644 --- a/archival/rpm.c +++ b/archival/rpm.c @@ -6,7 +6,6 @@ * * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ - //config:config RPM //config: bool "rpm (33 kb)" //config: default y @@ -14,6 +13,7 @@ //config: Mini RPM applet - queries and extracts RPM packages. //applet:IF_RPM(APPLET(rpm, BB_DIR_BIN, BB_SUID_DROP)) + //kbuild:lib-$(CONFIG_RPM) += rpm.o #include "libbb.h" @@ -479,3 +479,98 @@ int rpm_main(int argc, char **argv) return 0; } + +/* + * Mini rpm2cpio implementation for busybox + * + * Copyright (C) 2001 by Laurence Anderson + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config RPM2CPIO +//config: bool "rpm2cpio (20 kb)" +//config: default y +//config: help +//config: Converts a RPM file into a CPIO archive. + +//applet:IF_RPM2CPIO(APPLET(rpm2cpio, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_RPM2CPIO) += rpm.o + +//usage:#define rpm2cpio_trivial_usage +//usage: "PACKAGE.rpm" +//usage:#define rpm2cpio_full_usage "\n\n" +//usage: "Output a cpio archive of the rpm file" + +enum { rpm_fd = STDIN_FILENO }; + +static unsigned skip_header(void) +{ + struct rpm_header header; + unsigned len; + + xread(rpm_fd, &header, sizeof(header)); +// if (strncmp((char *) &header.magic, RPM_HEADER_MAGIC_STR, 3) != 0) { +// bb_error_msg_and_die("invalid RPM header magic"); +// } +// if (header.version != 1) { +// bb_error_msg_and_die("unsupported RPM header version"); +// } + if (header.magic_and_ver != htonl(RPM_HEADER_MAGICnVER)) { + bb_error_msg_and_die("invalid RPM header magic or unsupported version"); + // ": %x != %x", header.magic_and_ver, htonl(RPM_HEADER_MAGICnVER)); + } + + /* Seek past index entries, and past store */ + len = 16 * ntohl(header.entries) + ntohl(header.size); + seek_by_jump(rpm_fd, len); + + return sizeof(header) + len; +} + +/* No getopt required */ +int rpm2cpio_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int rpm2cpio_main(int argc UNUSED_PARAM, char **argv) +{ + struct rpm_lead lead; + unsigned pos; + + if (argv[1]) { + xmove_fd(xopen(argv[1], O_RDONLY), rpm_fd); + } + xread(rpm_fd, &lead, sizeof(lead)); + + /* Just check the magic, the rest is irrelevant */ + if (lead.magic != htonl(RPM_LEAD_MAGIC)) { + bb_error_msg_and_die("invalid RPM magic"); + } + + /* Skip the signature header, align to 8 bytes */ + pos = skip_header(); + seek_by_jump(rpm_fd, (-(int)pos) & 7); + + /* Skip the main header */ + skip_header(); + + //if (SEAMLESS_COMPRESSION) - we do this at the end instead. + // /* We need to know whether child (gzip/bzip/etc) exits abnormally */ + // signal(SIGCHLD, check_errors_in_children); + +//TODO: look for rpm tag RPMTAG_PAYLOADCOMPRESSOR (dec 1125, hex 0x465), +// if the value is "lzma", set up decompressor without detection +// (lzma can't be detected). + + setup_unzip_on_fd(rpm_fd, /*fail_if_not_compressed:*/ 1); + if (bb_copyfd_eof(rpm_fd, STDOUT_FILENO) < 0) + bb_error_msg_and_die("error unpacking"); + + if (ENABLE_FEATURE_CLEAN_UP) { + close(rpm_fd); + } + + if (SEAMLESS_COMPRESSION) { + check_errors_in_children(0); + return bb_got_signal; + } + return EXIT_SUCCESS; +} diff --git a/archival/rpm2cpio.c b/archival/rpm2cpio.c deleted file mode 100644 index a6db19c..0000000 --- a/archival/rpm2cpio.c +++ /dev/null @@ -1,99 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini rpm2cpio implementation for busybox - * - * Copyright (C) 2001 by Laurence Anderson - * - * Licensed under GPLv2 or later, see file LICENSE in this source tree. - */ - -//config:config RPM2CPIO -//config: bool "rpm2cpio (20 kb)" -//config: default y -//config: help -//config: Converts a RPM file into a CPIO archive. - -//applet:IF_RPM2CPIO(APPLET(rpm2cpio, BB_DIR_USR_BIN, BB_SUID_DROP)) -//kbuild:lib-$(CONFIG_RPM2CPIO) += rpm2cpio.o - -//usage:#define rpm2cpio_trivial_usage -//usage: "package.rpm" -//usage:#define rpm2cpio_full_usage "\n\n" -//usage: "Output a cpio archive of the rpm file" - -#include "libbb.h" -#include "bb_archive.h" -#include "rpm.h" - -enum { rpm_fd = STDIN_FILENO }; - -static unsigned skip_header(void) -{ - struct rpm_header header; - unsigned len; - - xread(rpm_fd, &header, sizeof(header)); -// if (strncmp((char *) &header.magic, RPM_HEADER_MAGIC_STR, 3) != 0) { -// bb_error_msg_and_die("invalid RPM header magic"); -// } -// if (header.version != 1) { -// bb_error_msg_and_die("unsupported RPM header version"); -// } - if (header.magic_and_ver != htonl(RPM_HEADER_MAGICnVER)) { - bb_error_msg_and_die("invalid RPM header magic or unsupported version"); - // ": %x != %x", header.magic_and_ver, htonl(RPM_HEADER_MAGICnVER)); - } - - /* Seek past index entries, and past store */ - len = 16 * ntohl(header.entries) + ntohl(header.size); - seek_by_jump(rpm_fd, len); - - return sizeof(header) + len; -} - -/* No getopt required */ -int rpm2cpio_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int rpm2cpio_main(int argc UNUSED_PARAM, char **argv) -{ - struct rpm_lead lead; - unsigned pos; - - if (argv[1]) { - xmove_fd(xopen(argv[1], O_RDONLY), rpm_fd); - } - xread(rpm_fd, &lead, sizeof(lead)); - - /* Just check the magic, the rest is irrelevant */ - if (lead.magic != htonl(RPM_LEAD_MAGIC)) { - bb_error_msg_and_die("invalid RPM magic"); - } - - /* Skip the signature header, align to 8 bytes */ - pos = skip_header(); - seek_by_jump(rpm_fd, (-(int)pos) & 7); - - /* Skip the main header */ - skip_header(); - - //if (SEAMLESS_COMPRESSION) - we do this at the end instead. - // /* We need to know whether child (gzip/bzip/etc) exits abnormally */ - // signal(SIGCHLD, check_errors_in_children); - -//TODO: look for rpm tag RPMTAG_PAYLOADCOMPRESSOR (dec 1125, hex 0x465), -// if the value is "lzma", set up decompressor without detection -// (lzma can't be detected). - - setup_unzip_on_fd(rpm_fd, /*fail_if_not_compressed:*/ 1); - if (bb_copyfd_eof(rpm_fd, STDOUT_FILENO) < 0) - bb_error_msg_and_die("error unpacking"); - - if (ENABLE_FEATURE_CLEAN_UP) { - close(rpm_fd); - } - - if (SEAMLESS_COMPRESSION) { - check_errors_in_children(0); - return bb_got_signal; - } - return EXIT_SUCCESS; -} diff --git a/archival/rpm.c b/archival/rpm.c index bb6cc45..461e170 100644 --- a/archival/rpm.c +++ b/archival/rpm.c @@ -117,14 +117,15 @@ static void extract_cpio(int fd, const char *source_rpm) continue; } -static rpm_index *rpm_gettags(int fd) +static int rpm_gettags(const char *filename) { rpm_index *tags; + int fd; unsigned pass, idx; unsigned storepos; + fd = xopen(filename, O_RDONLY); storepos = xlseek(fd, 96, SEEK_CUR); /* Seek past the unused lead */ - G.tagcount = 0; tags = NULL; idx = 0; @@ -135,13 +136,13 @@ static rpm_index *rpm_gettags(int fd) xread(fd, &header, sizeof(header)); if (header.magic_and_ver != htonl(RPM_HEADER_MAGICnVER)) - return NULL; /* Invalid magic, or not version 1 */ + bb_error_msg_and_die("invalid RPM header magic in '%s'", filename); header.size = ntohl(header.size); cnt = ntohl(header.entries); storepos += sizeof(header) + cnt * 16; G.tagcount += cnt; - tags = xrealloc(tags, G.tagcount * sizeof(tags[0])); + tags = xrealloc(tags, sizeof(tags[0]) * G.tagcount); xread(fd, &tags[idx], sizeof(tags[0]) * cnt); while (cnt--) { rpm_index *tag = &tags[idx]; @@ -160,6 +161,7 @@ static rpm_index *rpm_gettags(int fd) /* Seek past store */ storepos = xlseek(fd, header.size, SEEK_CUR); } + G.mytags = tags; /* Map the store */ storepos = (storepos + G.pagesize) & -(int)G.pagesize; @@ -168,9 +170,9 @@ static rpm_index *rpm_gettags(int fd) /* some NOMMU systems prefer MAP_PRIVATE over MAP_SHARED */ G.map = mmap(0, storepos, PROT_READ, MAP_PRIVATE, fd, 0); if (G.map == MAP_FAILED) - return NULL; /* error */ + bb_perror_msg_and_die("mmap '%s'", filename); - return tags; + return fd; } static int bsearch_rpmtag(const void *key, const void *item) @@ -383,11 +385,7 @@ int rpm_main(int argc, char **argv) int rpm_fd; const char *source_rpm; - rpm_fd = xopen(*argv, O_RDONLY); - G.mytags = rpm_gettags(rpm_fd); - if (!G.mytags) - bb_error_msg_and_die("error reading rpm header from '%s'", *argv); - + rpm_fd = rpm_gettags(*argv); print_all_tags(); source_rpm = rpm_getstr0(TAG_SOURCERPM); diff --git a/archival/rpm.c b/archival/rpm.c index 461e170..f46d88b 100644 --- a/archival/rpm.c +++ b/archival/rpm.c @@ -124,7 +124,13 @@ static int rpm_gettags(const char *filename) unsigned pass, idx; unsigned storepos; - fd = xopen(filename, O_RDONLY); + if (!filename) { /* rpm2cpio w/o filename? */ + filename = bb_msg_standard_output; + fd = 0; + } else { + fd = xopen(filename, O_RDONLY); + } + storepos = xlseek(fd, 96, SEEK_CUR); /* Seek past the unused lead */ G.tagcount = 0; tags = NULL; @@ -500,55 +506,15 @@ int rpm_main(int argc, char **argv) //usage:#define rpm2cpio_full_usage "\n\n" //usage: "Output a cpio archive of the rpm file" -enum { rpm_fd = STDIN_FILENO }; - -static unsigned skip_header(void) -{ - struct rpm_header header; - unsigned len; - - xread(rpm_fd, &header, sizeof(header)); -// if (strncmp((char *) &header.magic, RPM_HEADER_MAGIC_STR, 3) != 0) { -// bb_error_msg_and_die("invalid RPM header magic"); -// } -// if (header.version != 1) { -// bb_error_msg_and_die("unsupported RPM header version"); -// } - if (header.magic_and_ver != htonl(RPM_HEADER_MAGICnVER)) { - bb_error_msg_and_die("invalid RPM header magic or unsupported version"); - // ": %x != %x", header.magic_and_ver, htonl(RPM_HEADER_MAGICnVER)); - } - - /* Seek past index entries, and past store */ - len = 16 * ntohl(header.entries) + ntohl(header.size); - seek_by_jump(rpm_fd, len); - - return sizeof(header) + len; -} - /* No getopt required */ int rpm2cpio_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int rpm2cpio_main(int argc UNUSED_PARAM, char **argv) { - struct rpm_lead lead; - unsigned pos; - - if (argv[1]) { - xmove_fd(xopen(argv[1], O_RDONLY), rpm_fd); - } - xread(rpm_fd, &lead, sizeof(lead)); + int rpm_fd; - /* Just check the magic, the rest is irrelevant */ - if (lead.magic != htonl(RPM_LEAD_MAGIC)) { - bb_error_msg_and_die("invalid RPM magic"); - } - - /* Skip the signature header, align to 8 bytes */ - pos = skip_header(); - seek_by_jump(rpm_fd, (-(int)pos) & 7); + G.pagesize = getpagesize(); - /* Skip the main header */ - skip_header(); + rpm_fd = rpm_gettags(argv[1]); //if (SEAMLESS_COMPRESSION) - we do this at the end instead. // /* We need to know whether child (gzip/bzip/etc) exits abnormally */ diff --git a/archival/libarchive/open_transformer.c b/archival/libarchive/open_transformer.c index ac7e5db..290dd13 100644 --- a/archival/libarchive/open_transformer.c +++ b/archival/libarchive/open_transformer.c @@ -225,18 +225,8 @@ static transformer_state_t *setup_transformer_on_fd(int fd, int fail_if_not_comp return xstate; } -/* Used by e.g. rpm which gives us a fd without filename, - * thus we can't guess the format from filename's extension. - */ -int FAST_FUNC setup_unzip_on_fd(int fd, int fail_if_not_compressed) +static void fork_transformer_and_free(transformer_state_t *xstate) { - transformer_state_t *xstate = setup_transformer_on_fd(fd, fail_if_not_compressed); - - if (!xstate || !xstate->xformer) { - free(xstate); - return 1; - } - # if BB_MMU fork_transformer_with_no_sig(xstate->src_fd, xstate->xformer); # else @@ -249,8 +239,34 @@ int FAST_FUNC setup_unzip_on_fd(int fd, int fail_if_not_compressed) fork_transformer_with_sig(xstate->src_fd, xstate->xformer, xstate->xformer_prog); # endif free(xstate); +} + +/* Used by e.g. rpm which gives us a fd without filename, + * thus we can't guess the format from filename's extension. + */ +int FAST_FUNC setup_unzip_on_fd(int fd, int fail_if_not_compressed) +{ + transformer_state_t *xstate = setup_transformer_on_fd(fd, fail_if_not_compressed); + + if (!xstate->xformer) { + free(xstate); + return 1; + } + + fork_transformer_and_free(xstate); return 0; } +#if ENABLE_FEATURE_SEAMLESS_LZMA +/* ...and custom version for LZMA */ +void FAST_FUNC setup_lzma_on_fd(int fd) +{ + transformer_state_t *xstate = xzalloc(sizeof(*xstate)); + xstate->src_fd = fd; + xstate->xformer = unpack_lzma_stream; + USE_FOR_NOMMU(xstate->xformer_prog = "unlzma";) + fork_transformer_and_free(xstate); +} +#endif static transformer_state_t *open_transformer(const char *fname, int fail_if_not_compressed) { diff --git a/archival/rpm.c b/archival/rpm.c index f46d88b..cca17da 100644 --- a/archival/rpm.c +++ b/archival/rpm.c @@ -56,6 +56,8 @@ #define TAG_DIRINDEXES 1116 #define TAG_BASENAMES 1117 #define TAG_DIRNAMES 1118 +#define TAG_PAYLOADCOMPRESSOR 1125 + #define RPMFILE_CONFIG (1 << 0) #define RPMFILE_DOC (1 << 1) @@ -510,6 +512,7 @@ int rpm_main(int argc, char **argv) int rpm2cpio_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int rpm2cpio_main(int argc UNUSED_PARAM, char **argv) { + const char *str; int rpm_fd; G.pagesize = getpagesize(); @@ -520,11 +523,17 @@ int rpm2cpio_main(int argc UNUSED_PARAM, char **argv) // /* We need to know whether child (gzip/bzip/etc) exits abnormally */ // signal(SIGCHLD, check_errors_in_children); -//TODO: look for rpm tag RPMTAG_PAYLOADCOMPRESSOR (dec 1125, hex 0x465), -// if the value is "lzma", set up decompressor without detection -// (lzma can't be detected). + if (ENABLE_FEATURE_SEAMLESS_LZMA + && (str = rpm_getstr0(TAG_PAYLOADCOMPRESSOR)) != NULL + && strcmp(str, "lzma") == 0 + ) { + // lzma compression can't be detected + // set up decompressor without detection + setup_lzma_on_fd(rpm_fd); + } else { + setup_unzip_on_fd(rpm_fd, /*fail_if_not_compressed:*/ 1); + } - setup_unzip_on_fd(rpm_fd, /*fail_if_not_compressed:*/ 1); if (bb_copyfd_eof(rpm_fd, STDOUT_FILENO) < 0) bb_error_msg_and_die("error unpacking"); diff --git a/include/libbb.h b/include/libbb.h index 2eb1fef..86ad0a0 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -863,7 +863,7 @@ unsigned bb_clk_tck(void) FAST_FUNC; #if SEAMLESS_COMPRESSION /* Autodetects gzip/bzip2 formats. fd may be in the middle of the file! */ -extern int setup_unzip_on_fd(int fd, int fail_if_not_compressed) FAST_FUNC; +int setup_unzip_on_fd(int fd, int fail_if_not_compressed) FAST_FUNC; /* Autodetects .gz etc */ extern int open_zipped(const char *fname, int fail_if_not_compressed) FAST_FUNC; extern void *xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC; @@ -872,6 +872,8 @@ extern void *xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p) # define open_zipped(fname, fail_if_not_compressed) open((fname), O_RDONLY); # define xmalloc_open_zipped_read_close(fname, maxsz_p) xmalloc_open_read_close((fname), (maxsz_p)) #endif +/* lzma has no signature, need a little helper. NB: exist only for ENABLE_FEATURE_SEAMLESS_LZMA=y */ +void setup_lzma_on_fd(int fd) FAST_FUNC; extern ssize_t safe_write(int fd, const void *buf, size_t count) FAST_FUNC; // NB: will return short write on error, not -1,