Changeset 3621 in MondoRescue for branches/3.3/mindi-busybox/archival/rpm.c


Ignore:
Timestamp:
Dec 20, 2016, 4:07:32 PM (7 years ago)
Author:
Bruno Cornec
Message:

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

Location:
branches/3.3
Files:
1 edited
1 copied

Legend:

Unmodified
Added
Removed
  • branches/3.3/mindi-busybox/archival/rpm.c

    r3232 r3621  
    88 */
    99
     10//config:config RPM
     11//config:   bool "rpm"
     12//config:   default y
     13//config:   help
     14//config:     Mini RPM applet - queries and extracts RPM packages.
     15
     16//applet:IF_RPM(APPLET(rpm, BB_DIR_BIN, BB_SUID_DROP))
     17//kbuild:lib-$(CONFIG_RPM) += rpm.o
     18
    1019//usage:#define rpm_trivial_usage
    1120//usage:       "-i PACKAGE.rpm; rpm -qp[ildc] PACKAGE.rpm"
     
    1524//usage:     "\n    -i  Install package"
    1625//usage:     "\n    -qp Query package"
    17 //usage:     "\n    -i  Show information"
    18 //usage:     "\n    -l  List contents"
    19 //usage:     "\n    -d  List documents"
    20 //usage:     "\n    -c  List config files"
     26//usage:     "\n    -qpi    Show information"
     27//usage:     "\n    -qpl    List contents"
     28//usage:     "\n    -qpd    List documents"
     29//usage:     "\n    -qpc    List config files"
    2130
    2231#include "libbb.h"
     32#include "common_bufsiz.h"
    2333#include "bb_archive.h"
    2434#include "rpm.h"
     
    8090} rpm_index;
    8191
    82 static void *map;
    83 static rpm_index **mytags;
    84 static int tagcount;
    85 
    86 static void extract_cpio(int fd, const char *source_rpm);
    87 static rpm_index **rpm_gettags(int fd, int *num_tags);
    88 static int bsearch_rpmtag(const void *key, const void *item);
    89 static char *rpm_getstr(int tag, int itemindex);
    90 static int rpm_getint(int tag, int itemindex);
    91 static int rpm_getcount(int tag);
    92 static void fileaction_dobackup(char *filename, int fileref);
    93 static void fileaction_setowngrp(char *filename, int fileref);
    94 static void loop_through_files(int filetag, void (*fileaction)(char *filename, int fileref));
     92struct globals {
     93    void *map;
     94    rpm_index **mytags;
     95    int tagcount;
     96} FIX_ALIASING;
     97#define G (*(struct globals*)bb_common_bufsiz1)
     98#define INIT_G() do { setup_common_bufsiz(); } while (0)
     99
     100static void extract_cpio(int fd, const char *source_rpm)
     101{
     102    archive_handle_t *archive_handle;
     103
     104    if (source_rpm != NULL) {
     105        /* Binary rpm (it was built from some SRPM), install to root */
     106        xchdir("/");
     107    } /* else: SRPM, install to current dir */
     108
     109    /* Initialize */
     110    archive_handle = init_handle();
     111    archive_handle->seek = seek_by_read;
     112    archive_handle->action_data = data_extract_all;
     113#if 0 /* For testing (rpm -i only lists the files in internal cpio): */
     114    archive_handle->action_header = header_list;
     115    archive_handle->action_data = data_skip;
     116#endif
     117    archive_handle->ah_flags = ARCHIVE_RESTORE_DATE | ARCHIVE_CREATE_LEADING_DIRS
     118        /* compat: overwrite existing files.
     119         * try "rpm -i foo.src.rpm" few times in a row -
     120         * standard rpm will not complain.
     121         */
     122        | ARCHIVE_REPLACE_VIA_RENAME;
     123    archive_handle->src_fd = fd;
     124    /*archive_handle->offset = 0; - init_handle() did it */
     125
     126    setup_unzip_on_fd(archive_handle->src_fd, /*fail_if_not_compressed:*/ 1);
     127    while (get_header_cpio(archive_handle) == EXIT_SUCCESS)
     128        continue;
     129}
     130
     131static rpm_index **rpm_gettags(int fd, int *num_tags)
     132{
     133    /* We should never need more than 200 (shrink via realloc later) */
     134    rpm_index **tags = xzalloc(200 * sizeof(tags[0]));
     135    int pass, tagindex = 0;
     136
     137    xlseek(fd, 96, SEEK_CUR); /* Seek past the unused lead */
     138
     139    /* 1st pass is the signature headers, 2nd is the main stuff */
     140    for (pass = 0; pass < 2; pass++) {
     141        struct rpm_header header;
     142        rpm_index *tmpindex;
     143        int storepos;
     144
     145        xread(fd, &header, sizeof(header));
     146        if (header.magic_and_ver != htonl(RPM_HEADER_MAGICnVER))
     147            return NULL; /* Invalid magic, or not version 1 */
     148        header.size = ntohl(header.size);
     149        header.entries = ntohl(header.entries);
     150        storepos = xlseek(fd, 0, SEEK_CUR) + header.entries * 16;
     151
     152        while (header.entries--) {
     153            tmpindex = tags[tagindex++] = xmalloc(sizeof(*tmpindex));
     154            xread(fd, tmpindex, sizeof(*tmpindex));
     155            tmpindex->tag = ntohl(tmpindex->tag);
     156            tmpindex->type = ntohl(tmpindex->type);
     157            tmpindex->count = ntohl(tmpindex->count);
     158            tmpindex->offset = storepos + ntohl(tmpindex->offset);
     159            if (pass == 0)
     160                tmpindex->tag -= 743;
     161        }
     162        storepos = xlseek(fd, header.size, SEEK_CUR); /* Seek past store */
     163        /* Skip padding to 8 byte boundary after reading signature headers */
     164        if (pass == 0)
     165            xlseek(fd, (-storepos) & 0x7, SEEK_CUR);
     166    }
     167    /* realloc tags to save space */
     168    tags = xrealloc(tags, tagindex * sizeof(tags[0]));
     169    *num_tags = tagindex;
     170    /* All done, leave the file at the start of the gzipped cpio archive */
     171    return tags;
     172}
     173
     174static int bsearch_rpmtag(const void *key, const void *item)
     175{
     176    int *tag = (int *)key;
     177    rpm_index **tmp = (rpm_index **) item;
     178    return (*tag - tmp[0]->tag);
     179}
     180
     181static int rpm_getcount(int tag)
     182{
     183    rpm_index **found;
     184    found = bsearch(&tag, G.mytags, G.tagcount, sizeof(struct rpmtag *), bsearch_rpmtag);
     185    if (!found)
     186        return 0;
     187    return found[0]->count;
     188}
     189
     190static char *rpm_getstr(int tag, int itemindex)
     191{
     192    rpm_index **found;
     193    found = bsearch(&tag, G.mytags, G.tagcount, sizeof(struct rpmtag *), bsearch_rpmtag);
     194    if (!found || itemindex >= found[0]->count)
     195        return NULL;
     196    if (found[0]->type == RPM_STRING_TYPE
     197     || found[0]->type == RPM_I18NSTRING_TYPE
     198     || found[0]->type == RPM_STRING_ARRAY_TYPE
     199    ) {
     200        int n;
     201        char *tmpstr = (char *) G.map + found[0]->offset;
     202        for (n = 0; n < itemindex; n++)
     203            tmpstr = tmpstr + strlen(tmpstr) + 1;
     204        return tmpstr;
     205    }
     206    return NULL;
     207}
     208
     209static int rpm_getint(int tag, int itemindex)
     210{
     211    rpm_index **found;
     212    char *tmpint;
     213
     214    /* gcc throws warnings here when sizeof(void*)!=sizeof(int) ...
     215     * it's ok to ignore it because tag won't be used as a pointer */
     216    found = bsearch(&tag, G.mytags, G.tagcount, sizeof(struct rpmtag *), bsearch_rpmtag);
     217    if (!found || itemindex >= found[0]->count)
     218        return -1;
     219
     220    tmpint = (char *) G.map + found[0]->offset;
     221    if (found[0]->type == RPM_INT32_TYPE) {
     222        tmpint += itemindex*4;
     223        return ntohl(*(int32_t*)tmpint);
     224    }
     225    if (found[0]->type == RPM_INT16_TYPE) {
     226        tmpint += itemindex*2;
     227        return ntohs(*(int16_t*)tmpint);
     228    }
     229    if (found[0]->type == RPM_INT8_TYPE) {
     230        tmpint += itemindex;
     231        return *(int8_t*)tmpint;
     232    }
     233    return -1;
     234}
     235
     236static void fileaction_dobackup(char *filename, int fileref)
     237{
     238    struct stat oldfile;
     239    int stat_res;
     240    char *newname;
     241    if (rpm_getint(TAG_FILEFLAGS, fileref) & RPMFILE_CONFIG) {
     242        /* Only need to backup config files */
     243        stat_res = lstat(filename, &oldfile);
     244        if (stat_res == 0 && S_ISREG(oldfile.st_mode)) {
     245            /* File already exists  - really should check MD5's etc to see if different */
     246            newname = xasprintf("%s.rpmorig", filename);
     247            copy_file(filename, newname, FILEUTILS_RECUR | FILEUTILS_PRESERVE_STATUS);
     248            remove_file(filename, FILEUTILS_RECUR | FILEUTILS_FORCE);
     249            free(newname);
     250        }
     251    }
     252}
     253
     254static void fileaction_setowngrp(char *filename, int fileref)
     255{
     256    /* real rpm warns: "user foo does not exist - using <you>" */
     257    struct passwd *pw = getpwnam(rpm_getstr(TAG_FILEUSERNAME, fileref));
     258    int uid = pw ? pw->pw_uid : getuid(); /* or euid? */
     259    struct group *gr = getgrnam(rpm_getstr(TAG_FILEGROUPNAME, fileref));
     260    int gid = gr ? gr->gr_gid : getgid();
     261    chown(filename, uid, gid);
     262}
     263
     264static void loop_through_files(int filetag, void (*fileaction)(char *filename, int fileref))
     265{
     266    int count = 0;
     267    while (rpm_getstr(filetag, count)) {
     268        char* filename = xasprintf("%s%s",
     269            rpm_getstr(TAG_DIRNAMES, rpm_getint(TAG_DIRINDEXES, count)),
     270            rpm_getstr(TAG_BASENAMES, count));
     271        fileaction(filename, count++);
     272        free(filename);
     273    }
     274}
    95275
    96276int rpm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
    97277int rpm_main(int argc, char **argv)
    98278{
    99     int opt = 0, func = 0, rpm_fd, offset;
    100     const int pagesize = getpagesize();
     279    int opt, func = 0;
     280    const unsigned pagesize = getpagesize();
    101281
    102282    while ((opt = getopt(argc, argv, "iqpldc")) != -1) {
     
    135315
    136316    while (*argv) {
     317        int rpm_fd;
     318        unsigned mapsize;
    137319        const char *source_rpm;
    138320
    139321        rpm_fd = xopen(*argv++, O_RDONLY);
    140         mytags = rpm_gettags(rpm_fd, &tagcount);
    141         if (!mytags)
     322        G.mytags = rpm_gettags(rpm_fd, &G.tagcount);
     323        if (!G.mytags)
    142324            bb_error_msg_and_die("error reading rpm header");
    143         offset = xlseek(rpm_fd, 0, SEEK_CUR);
    144         /* Mimimum is one page */
    145         map = mmap(0, offset > pagesize ? (offset + offset % pagesize) : pagesize, PROT_READ, MAP_PRIVATE, rpm_fd, 0);
     325        mapsize = xlseek(rpm_fd, 0, SEEK_CUR);
     326        mapsize = (mapsize + pagesize) & -(int)pagesize;
     327        /* Some NOMMU systems prefer MAP_PRIVATE over MAP_SHARED */
     328        G.map = mmap(0, mapsize, PROT_READ, MAP_PRIVATE, rpm_fd, 0);
     329//FIXME: error check?
    146330
    147331        source_rpm = rpm_getstr(TAG_SOURCERPM, 0);
     
    167351                const char *p;
    168352
    169                 p = rpm_getstr(TAG_PREFIXS, 0);
    170                 if (!p) p = "(not relocateable)";
    171                 printf("Name        : %-29sRelocations: %s\n", rpm_getstr(TAG_NAME, 0), p);
    172                 p = rpm_getstr(TAG_VENDOR, 0);
    173                 if (!p) p = "(none)";
    174                 printf("Version     : %-34sVendor: %s\n", rpm_getstr(TAG_VERSION, 0), p);
     353                printf("%-12s: %s\n", "Name"        , rpm_getstr(TAG_NAME, 0));
     354                /* TODO compat: add "Epoch" here */
     355                printf("%-12s: %s\n", "Version"     , rpm_getstr(TAG_VERSION, 0));
     356                printf("%-12s: %s\n", "Release"     , rpm_getstr(TAG_RELEASE, 0));
     357                /* add "Architecture" */
     358                printf("%-12s: %s\n", "Install Date", "(not installed)");
     359                printf("%-12s: %s\n", "Group"       , rpm_getstr(TAG_GROUP, 0));
     360                printf("%-12s: %d\n", "Size"        , rpm_getint(TAG_SIZE, 0));
     361                printf("%-12s: %s\n", "License"     , rpm_getstr(TAG_LICENSE, 0));
     362                /* add "Signature" */
     363                printf("%-12s: %s\n", "Source RPM"  , source_rpm ? source_rpm : "(none)");
    175364                bdate_time = rpm_getint(TAG_BUILDTIME, 0);
    176365                bdate_ptm = localtime(&bdate_time);
    177366                strftime(bdatestring, 50, "%a %d %b %Y %T %Z", bdate_ptm);
    178                 printf("Release     : %-30sBuild Date: %s\n", rpm_getstr(TAG_RELEASE, 0), bdatestring);
    179                 printf("Install date: %-30sBuild Host: %s\n", "(not installed)", rpm_getstr(TAG_BUILDHOST, 0));
    180                 printf("Group       : %-30sSource RPM: %s\n", rpm_getstr(TAG_GROUP, 0), source_rpm);
    181                 printf("Size        : %-33dLicense: %s\n", rpm_getint(TAG_SIZE, 0), rpm_getstr(TAG_LICENSE, 0));
    182                 printf("URL         : %s\n", rpm_getstr(TAG_URL, 0));
    183                 printf("Summary     : %s\n", rpm_getstr(TAG_SUMMARY, 0));
     367                printf("%-12s: %s\n", "Build Date"  , bdatestring);
     368                printf("%-12s: %s\n", "Build Host"  , rpm_getstr(TAG_BUILDHOST, 0));
     369                p = rpm_getstr(TAG_PREFIXS, 0);
     370                printf("%-12s: %s\n", "Relocations" , p ? p : "(not relocatable)");
     371                /* add "Packager" */
     372                p = rpm_getstr(TAG_VENDOR, 0);
     373                printf("%-12s: %s\n", "Vendor"      , p ? p : "(none)");
     374                printf("%-12s: %s\n", "URL"         , rpm_getstr(TAG_URL, 0));
     375                printf("%-12s: %s\n", "Summary"     , rpm_getstr(TAG_SUMMARY, 0));
    184376                printf("Description :\n%s\n", rpm_getstr(TAG_DESCRIPTION, 0));
    185377            }
     
    206398            }
    207399        }
    208         free(mytags);
     400        munmap(G.map, mapsize);
     401        free(G.mytags);
     402        close(rpm_fd);
    209403    }
    210404    return 0;
    211405}
    212 
    213 static void extract_cpio(int fd, const char *source_rpm)
    214 {
    215     archive_handle_t *archive_handle;
    216 
    217     if (source_rpm != NULL) {
    218         /* Binary rpm (it was built from some SRPM), install to root */
    219         xchdir("/");
    220     } /* else: SRPM, install to current dir */
    221 
    222     /* Initialize */
    223     archive_handle = init_handle();
    224     archive_handle->seek = seek_by_read;
    225     archive_handle->action_data = data_extract_all;
    226 #if 0 /* For testing (rpm -i only lists the files in internal cpio): */
    227     archive_handle->action_header = header_list;
    228     archive_handle->action_data = data_skip;
    229 #endif
    230     archive_handle->ah_flags = ARCHIVE_RESTORE_DATE | ARCHIVE_CREATE_LEADING_DIRS
    231         /* compat: overwrite existing files.
    232          * try "rpm -i foo.src.rpm" few times in a row -
    233          * standard rpm will not complain.
    234          * (TODO? real rpm creates "file;1234" and then renames it) */
    235         | ARCHIVE_UNLINK_OLD;
    236     archive_handle->src_fd = fd;
    237     /*archive_handle->offset = 0; - init_handle() did it */
    238 
    239     setup_unzip_on_fd(archive_handle->src_fd, /*fail_if_not_detected:*/ 1);
    240     while (get_header_cpio(archive_handle) == EXIT_SUCCESS)
    241         continue;
    242 }
    243 
    244 static rpm_index **rpm_gettags(int fd, int *num_tags)
    245 {
    246     /* We should never need more than 200 (shrink via realloc later) */
    247     rpm_index **tags = xzalloc(200 * sizeof(tags[0]));
    248     int pass, tagindex = 0;
    249 
    250     xlseek(fd, 96, SEEK_CUR); /* Seek past the unused lead */
    251 
    252     /* 1st pass is the signature headers, 2nd is the main stuff */
    253     for (pass = 0; pass < 2; pass++) {
    254         struct rpm_header header;
    255         rpm_index *tmpindex;
    256         int storepos;
    257 
    258         xread(fd, &header, sizeof(header));
    259         if (header.magic_and_ver != htonl(RPM_HEADER_MAGICnVER))
    260             return NULL; /* Invalid magic, or not version 1 */
    261         header.size = ntohl(header.size);
    262         header.entries = ntohl(header.entries);
    263         storepos = xlseek(fd, 0, SEEK_CUR) + header.entries * 16;
    264 
    265         while (header.entries--) {
    266             tmpindex = tags[tagindex++] = xmalloc(sizeof(*tmpindex));
    267             xread(fd, tmpindex, sizeof(*tmpindex));
    268             tmpindex->tag = ntohl(tmpindex->tag);
    269             tmpindex->type = ntohl(tmpindex->type);
    270             tmpindex->count = ntohl(tmpindex->count);
    271             tmpindex->offset = storepos + ntohl(tmpindex->offset);
    272             if (pass == 0)
    273                 tmpindex->tag -= 743;
    274         }
    275         storepos = xlseek(fd, header.size, SEEK_CUR); /* Seek past store */
    276         /* Skip padding to 8 byte boundary after reading signature headers */
    277         if (pass == 0)
    278             xlseek(fd, (-storepos) & 0x7, SEEK_CUR);
    279     }
    280     /* realloc tags to save space */
    281     tags = xrealloc(tags, tagindex * sizeof(tags[0]));
    282     *num_tags = tagindex;
    283     /* All done, leave the file at the start of the gzipped cpio archive */
    284     return tags;
    285 }
    286 
    287 static int bsearch_rpmtag(const void *key, const void *item)
    288 {
    289     int *tag = (int *)key;
    290     rpm_index **tmp = (rpm_index **) item;
    291     return (*tag - tmp[0]->tag);
    292 }
    293 
    294 static int rpm_getcount(int tag)
    295 {
    296     rpm_index **found;
    297     found = bsearch(&tag, mytags, tagcount, sizeof(struct rpmtag *), bsearch_rpmtag);
    298     if (!found)
    299         return 0;
    300     return found[0]->count;
    301 }
    302 
    303 static char *rpm_getstr(int tag, int itemindex)
    304 {
    305     rpm_index **found;
    306     found = bsearch(&tag, mytags, tagcount, sizeof(struct rpmtag *), bsearch_rpmtag);
    307     if (!found || itemindex >= found[0]->count)
    308         return NULL;
    309     if (found[0]->type == RPM_STRING_TYPE
    310      || found[0]->type == RPM_I18NSTRING_TYPE
    311      || found[0]->type == RPM_STRING_ARRAY_TYPE
    312     ) {
    313         int n;
    314         char *tmpstr = (char *) map + found[0]->offset;
    315         for (n = 0; n < itemindex; n++)
    316             tmpstr = tmpstr + strlen(tmpstr) + 1;
    317         return tmpstr;
    318     }
    319     return NULL;
    320 }
    321 
    322 static int rpm_getint(int tag, int itemindex)
    323 {
    324     rpm_index **found;
    325     int *tmpint; /* NB: using int8_t* would be easier to code */
    326 
    327     /* gcc throws warnings here when sizeof(void*)!=sizeof(int) ...
    328      * it's ok to ignore it because tag won't be used as a pointer */
    329     found = bsearch(&tag, mytags, tagcount, sizeof(struct rpmtag *), bsearch_rpmtag);
    330     if (!found || itemindex >= found[0]->count)
    331         return -1;
    332 
    333     tmpint = (int *) ((char *) map + found[0]->offset);
    334 
    335     if (found[0]->type == RPM_INT32_TYPE) {
    336         tmpint = (int *) ((char *) tmpint + itemindex*4);
    337         /*return ntohl(*tmpint);*/
    338         /* int can be != int32_t */
    339         return ntohl(*(int32_t*)tmpint);
    340     }
    341     if (found[0]->type == RPM_INT16_TYPE) {
    342         tmpint = (int *) ((char *) tmpint + itemindex*2);
    343         /* ??? read int, and THEN ntohs() it?? */
    344         /*return ntohs(*tmpint);*/
    345         return ntohs(*(int16_t*)tmpint);
    346     }
    347     if (found[0]->type == RPM_INT8_TYPE) {
    348         tmpint = (int *) ((char *) tmpint + itemindex);
    349         /* ??? why we don't read byte here??? */
    350         /*return ntohs(*tmpint);*/
    351         return *(int8_t*)tmpint;
    352     }
    353     return -1;
    354 }
    355 
    356 static void fileaction_dobackup(char *filename, int fileref)
    357 {
    358     struct stat oldfile;
    359     int stat_res;
    360     char *newname;
    361     if (rpm_getint(TAG_FILEFLAGS, fileref) & RPMFILE_CONFIG) {
    362         /* Only need to backup config files */
    363         stat_res = lstat(filename, &oldfile);
    364         if (stat_res == 0 && S_ISREG(oldfile.st_mode)) {
    365             /* File already exists  - really should check MD5's etc to see if different */
    366             newname = xasprintf("%s.rpmorig", filename);
    367             copy_file(filename, newname, FILEUTILS_RECUR | FILEUTILS_PRESERVE_STATUS);
    368             remove_file(filename, FILEUTILS_RECUR | FILEUTILS_FORCE);
    369             free(newname);
    370         }
    371     }
    372 }
    373 
    374 static void fileaction_setowngrp(char *filename, int fileref)
    375 {
    376     /* real rpm warns: "user foo does not exist - using <you>" */
    377     struct passwd *pw = getpwnam(rpm_getstr(TAG_FILEUSERNAME, fileref));
    378     int uid = pw ? pw->pw_uid : getuid(); /* or euid? */
    379     struct group *gr = getgrnam(rpm_getstr(TAG_FILEGROUPNAME, fileref));
    380     int gid = gr ? gr->gr_gid : getgid();
    381     chown(filename, uid, gid);
    382 }
    383 
    384 static void loop_through_files(int filetag, void (*fileaction)(char *filename, int fileref))
    385 {
    386     int count = 0;
    387     while (rpm_getstr(filetag, count)) {
    388         char* filename = xasprintf("%s%s",
    389             rpm_getstr(TAG_DIRNAMES, rpm_getint(TAG_DIRINDEXES, count)),
    390             rpm_getstr(TAG_BASENAMES, count));
    391         fileaction(filename, count++);
    392         free(filename);
    393     }
    394 }
Note: See TracChangeset for help on using the changeset viewer.