source: branches/stable/mindi-busybox/archival/rpm.c @ 1770

Last change on this file since 1770 was 1770, checked in by Bruno Cornec, 13 years ago
  • Better output for mindi-busybox revision
  • Remove dummy file created on NFS - report from Arnaud Tiger <arnaud.tiger_at_hp.com>
  • strace useful for debug
  • fix new versions for pb (2.0.0 for mindi and 1.7.2 for mindi-busybox)
  • fix build process for mindi-busybox + options used in that version (dd for label-partitions-as-necessary)
  • fix typo in label-partitions-as-necessary which doesn't seem to work
  • Update to busybox 1.7.2
  • perl is now required at restore time to support uuid swap partitions (and will be used for many other thigs

in the future for sure)

  • next mindi version will be 2.0.0 due to all the changes made in it (udev may break working distros)
  • small optimization in mindi on keyboard handling (one single find instead of multiple)
  • better interaction for USB device when launching mindi manually
  • attempt to automatically guess block disk size for ramdisk
  • fix typos in bkphw
  • Fix the remaining problem with UUID support for swap partitions
  • Updates mondoarchive man page for USB support
  • Adds preliminary Hardware support to mindi (Proliant SSSTK)
  • Tries to add udev support also for rhel4
  • Fix UUID support which was still broken.
  • Be conservative in test for the start-nfs script
  • Update config file for mindi-busybox for 1.7.2 migration
  • Try to run around a busybox bug (1.2.2 pb on inexistant links)
  • Add build content for mindi-busybox in pb
  • Remove distributions content for mindi-busybox
  • Fix a warning on inexistant raidtab
  • Solve problem on tmpfs in restore init (Problem of inexistant symlink and busybox)
  • Create MONDO_CACHE and use it everywhere + creation at start
  • Really never try to eject a USB device
  • Fix a issue with &> usage (replaced with 1> and 2>)
  • Adds magic file to depllist in order to have file working + ldd which helps for debugging issues
  • tty modes correct to avoid sh error messages
  • Use ext3 normally and not ext2 instead
  • USB device should be corrected after reading (take 1st part)
  • Adds a mount_USB_here function derived from mount_CDROM_here
  • usb detection place before /dev detection in device name at restore time
  • Fix when restoring from USB: media is asked in interactive mode
  • Adds USB support for mondorestore
  • mount_cdrom => mount_media
  • elilo.efi is now searched throughout /boot/efi and not in a fixed place as there is no standard
  • untar-and-softlink => untar (+ interface change)
  • suppress useless softlinks creation/removal in boot process
  • avoids udevd messages on groups
  • Increase # of disks to 99 as in mindi at restore time (should be a conf file parameter)
  • skip existing big file creation
  • seems to work correctly for USB mindi boot
  • Adds group and tty link to udev conf
  • Always load usb-torage (even 2.6) to initiate USB bus discovery
  • Better printing of messages
  • Attempt to fix a bug in supporting OpenSusE 10.3 kernel for initramfs (mindi may now use multiple regex for kernel initrd detection)
  • Links were not correctly done as non relative for modules in mindi
  • exclusion of modules denied now works
  • Also create modules in their ordinary place, so that classical modprobe works + copy modules.dep
  • Fix bugs for DENY_MODS handling
  • Add device /dev/console for udev
  • ide-generic should now really be excluded
  • Fix a bug in major number for tty
  • If udev then adds modprobe/insmod to rootfs
  • tty0 is also cretaed with udev
  • ide-generic put rather in DENY_MODS
  • udevd remove from deplist s handled in mindi directly
  • better default for mindi when using --usb
  • Handles dynamically linked busybox (in case we want to use it soon ;-)
  • Adds fixed devices to create for udev
  • ide-generic should not be part of the initrd when using libata v2
  • support a dynamically linked udev (case on Ubuntu 7.10 and Mandriva 2008.0 so should be quite generic) This will give incitation to move to dyn. linked binaries in the initrd which will help for other tasks (ia6 4)
  • Improvement in udev support (do not use cl options not available in busybox)
  • Udev in mindi
    • auto creation of the right links at boot time with udev-links.conf(from Mandriva 2008.0)
    • rework startup of udev as current makes kernel crash (from Mandriva 2008.0)
    • add support for 64 bits udev
  • Try to render MyInsmod? silent at boot time
  • Adds udev support (mandatory for newest distributions to avoid remapping of devices in a different way as on the original system)
  • We also need vaft format support for USB boot
  • Adds libusual support (Ubuntu 7.10 needs it for USB)
  • Improve Ubuntu/Debian? keyboard detection and support
  • pbinit adapted to new pb (0.8.10). Filtering of docs done in it
  • Suppress some mondo warnings and errors on USB again
  • Tries to fix lack of files in deb mindi package
  • Verify should now work for USB devices
  • More log/mesages improvement for USB support
  • - Supress g_erase_tmpdir_and_scratchdir
  • Improve some log messages for USB support
  • Try to improve install in mindi to avoid issues with isolinux.cfg not installed vene if in the pkg :-(
  • Improve mindi-busybox build
  • In conformity with pb 0.8.9
  • Add support for Ubuntu 7.10 in build process
  • Add USB Key button to Menu UI (CD streamer removed)
  • Attempt to fix error messages on tmp/scratch files at the end by removing those dir at the latest possible.
  • Fix a bug linked to the size of the -E param which could be used (Arnaud Tiger/René? Ribaud).
  • Integrate ~/.pbrc content into mondorescue.pb (required project-builder >= 0.8.7)
  • Put mondorescue in conformity with new pb filtering rules
  • Add USB support at restore time (no test done yet). New start-usb script PB varibale added where useful
  • Unmounting USB device before removal of temporary scratchdir
  • Stil refining USB copy back to mondo (one command was not executed)
  • No need to have the image subdor in the csratchdir when USB.
  • umount the USB partition before attempting to use it
  • Remove useless copy from mindi to mondo at end of USB handling

(risky merge, we are raising the limits of 2 diverging branches. The status of stable is not completely sure as such. Will need lots of tests, but it's not yet done :-()
(merge -r1692:1769 $SVN_M/branches/2.2.5)

File size: 12.8 KB
Line 
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini rpm applet for busybox
4 *
5 * Copyright (C) 2001,2002 by Laurence Anderson
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10#include "libbb.h"
11#include "unarchive.h"
12
13#define RPM_HEADER_MAGIC        "\216\255\350"
14#define RPM_CHAR_TYPE           1
15#define RPM_INT8_TYPE           2
16#define RPM_INT16_TYPE          3
17#define RPM_INT32_TYPE          4
18/* #define RPM_INT64_TYPE       5   ---- These aren't supported (yet) */
19#define RPM_STRING_TYPE         6
20#define RPM_BIN_TYPE            7
21#define RPM_STRING_ARRAY_TYPE   8
22#define RPM_I18NSTRING_TYPE     9
23
24#define TAG_NAME                1000
25#define TAG_VERSION             1001
26#define TAG_RELEASE             1002
27#define TAG_SUMMARY             1004
28#define TAG_DESCRIPTION         1005
29#define TAG_BUILDTIME           1006
30#define TAG_BUILDHOST           1007
31#define TAG_SIZE                1009
32#define TAG_VENDOR              1011
33#define TAG_LICENSE             1014
34#define TAG_PACKAGER            1015
35#define TAG_GROUP               1016
36#define TAG_URL                 1020
37#define TAG_PREIN               1023
38#define TAG_POSTIN              1024
39#define TAG_FILEFLAGS           1037
40#define TAG_FILEUSERNAME        1039
41#define TAG_FILEGROUPNAME       1040
42#define TAG_SOURCERPM           1044
43#define TAG_PREINPROG           1085
44#define TAG_POSTINPROG          1086
45#define TAG_PREFIXS             1098
46#define TAG_DIRINDEXES          1116
47#define TAG_BASENAMES           1117
48#define TAG_DIRNAMES            1118
49#define RPMFILE_CONFIG          (1 << 0)
50#define RPMFILE_DOC             (1 << 1)
51
52enum rpm_functions_e {
53    rpm_query = 1,
54    rpm_install = 2,
55    rpm_query_info = 4,
56    rpm_query_package = 8,
57    rpm_query_list = 16,
58    rpm_query_list_doc = 32,
59    rpm_query_list_config = 64
60};
61
62typedef struct {
63    uint32_t tag; /* 4 byte tag */
64    uint32_t type; /* 4 byte type */
65    uint32_t offset; /* 4 byte offset */
66    uint32_t count; /* 4 byte count */
67} rpm_index;
68
69static void *map;
70static rpm_index **mytags;
71static int tagcount;
72
73static void extract_cpio_gz(int fd);
74static rpm_index **rpm_gettags(int fd, int *num_tags);
75static int bsearch_rpmtag(const void *key, const void *item);
76static char *rpm_getstr(int tag, int itemindex);
77static int rpm_getint(int tag, int itemindex);
78static int rpm_getcount(int tag);
79static void fileaction_dobackup(char *filename, int fileref);
80static void fileaction_setowngrp(char *filename, int fileref);
81static void loop_through_files(int filetag, void (*fileaction)(char *filename, int fileref));
82
83int rpm_main(int argc, char **argv);
84int rpm_main(int argc, char **argv)
85{
86    int opt = 0, func = 0, rpm_fd, offset;
87    const int pagesize = getpagesize();
88
89    while ((opt = getopt(argc, argv, "iqpldc")) != -1) {
90        switch (opt) {
91        case 'i': /* First arg: Install mode, with q: Information */
92            if (!func) func = rpm_install;
93            else func |= rpm_query_info;
94            break;
95        case 'q': /* First arg: Query mode */
96            if (func) bb_show_usage();
97            func = rpm_query;
98            break;
99        case 'p': /* Query a package */
100            func |= rpm_query_package;
101            break;
102        case 'l': /* List files in a package */
103            func |= rpm_query_list;
104            break;
105        case 'd': /* List doc files in a package (implies list) */
106            func |= rpm_query_list;
107            func |= rpm_query_list_doc;
108            break;
109        case 'c': /* List config files in a package (implies list) */
110            func |= rpm_query_list;
111            func |= rpm_query_list_config;
112            break;
113        default:
114            bb_show_usage();
115        }
116    }
117    argv += optind;
118    argc -= optind;
119    if (!argc) bb_show_usage();
120
121    while (*argv) {
122        rpm_fd = xopen(*argv++, O_RDONLY);
123        mytags = rpm_gettags(rpm_fd, &tagcount);
124        if (!mytags)
125            bb_error_msg_and_die("error reading rpm header");
126        offset = xlseek(rpm_fd, 0, SEEK_CUR);
127        /* Mimimum is one page */
128        map = mmap(0, offset > pagesize ? (offset + offset % pagesize) : pagesize, PROT_READ, MAP_PRIVATE, rpm_fd, 0);
129
130        if (func & rpm_install) {
131            /* Backup any config files */
132            loop_through_files(TAG_BASENAMES, fileaction_dobackup);
133            /* Extact the archive */
134            extract_cpio_gz(rpm_fd);
135            /* Set the correct file uid/gid's */
136            loop_through_files(TAG_BASENAMES, fileaction_setowngrp);
137        }
138        else if ((func & (rpm_query|rpm_query_package)) == (rpm_query|rpm_query_package)) {
139            if (!(func & (rpm_query_info|rpm_query_list))) {
140                /* If just a straight query, just give package name */
141                printf("%s-%s-%s\n", rpm_getstr(TAG_NAME, 0), rpm_getstr(TAG_VERSION, 0), rpm_getstr(TAG_RELEASE, 0));
142            }
143            if (func & rpm_query_info) {
144                /* Do the nice printout */
145                time_t bdate_time;
146                struct tm *bdate;
147                char bdatestring[50];
148                printf("Name        : %-29sRelocations: %s\n", rpm_getstr(TAG_NAME, 0), rpm_getstr(TAG_PREFIXS, 0) ? rpm_getstr(TAG_PREFIXS, 0) : "(not relocateable)");
149                printf("Version     : %-34sVendor: %s\n", rpm_getstr(TAG_VERSION, 0), rpm_getstr(TAG_VENDOR, 0) ? rpm_getstr(TAG_VENDOR, 0) : "(none)");
150                bdate_time = rpm_getint(TAG_BUILDTIME, 0);
151                bdate = localtime((time_t *) &bdate_time);
152                strftime(bdatestring, 50, "%a %d %b %Y %T %Z", bdate);
153                printf("Release     : %-30sBuild Date: %s\n", rpm_getstr(TAG_RELEASE, 0), bdatestring);
154                printf("Install date: %-30sBuild Host: %s\n", "(not installed)", rpm_getstr(TAG_BUILDHOST, 0));
155                printf("Group       : %-30sSource RPM: %s\n", rpm_getstr(TAG_GROUP, 0), rpm_getstr(TAG_SOURCERPM, 0));
156                printf("Size        : %-33dLicense: %s\n", rpm_getint(TAG_SIZE, 0), rpm_getstr(TAG_LICENSE, 0));
157                printf("URL         : %s\n", rpm_getstr(TAG_URL, 0));
158                printf("Summary     : %s\n", rpm_getstr(TAG_SUMMARY, 0));
159                printf("Description :\n%s\n", rpm_getstr(TAG_DESCRIPTION, 0));
160            }
161            if (func & rpm_query_list) {
162                int count, it, flags;
163                count = rpm_getcount(TAG_BASENAMES);
164                for (it = 0; it < count; it++) {
165                    flags = rpm_getint(TAG_FILEFLAGS, it);
166                    switch (func & (rpm_query_list_doc|rpm_query_list_config)) {
167                    case rpm_query_list_doc:
168                        if (!(flags & RPMFILE_DOC)) continue;
169                        break;
170                    case rpm_query_list_config:
171                        if (!(flags & RPMFILE_CONFIG)) continue;
172                        break;
173                    case rpm_query_list_doc|rpm_query_list_config:
174                        if (!(flags & (RPMFILE_CONFIG|RPMFILE_DOC))) continue;
175                        break;
176                    }
177                    printf("%s%s\n",
178                        rpm_getstr(TAG_DIRNAMES, rpm_getint(TAG_DIRINDEXES, it)),
179                        rpm_getstr(TAG_BASENAMES, it));
180                }
181            }
182        }
183        free(mytags);
184    }
185    return 0;
186}
187
188static void extract_cpio_gz(int fd)
189{
190    archive_handle_t *archive_handle;
191    unsigned char magic[2];
192#if BB_MMU
193    USE_DESKTOP(long long) int (*xformer)(int src_fd, int dst_fd);
194    enum { xformer_prog = 0 };
195#else
196    enum { xformer = 0 };
197    const char *xformer_prog;
198#endif
199
200    /* Initialize */
201    archive_handle = init_handle();
202    archive_handle->seek = seek_by_read;
203    //archive_handle->action_header = header_list;
204    archive_handle->action_data = data_extract_all;
205    archive_handle->flags |= ARCHIVE_PRESERVE_DATE;
206    archive_handle->flags |= ARCHIVE_CREATE_LEADING_DIRS;
207    archive_handle->src_fd = fd;
208    archive_handle->offset = 0;
209
210    xread(archive_handle->src_fd, &magic, 2);
211#if BB_MMU
212    xformer = unpack_gz_stream;
213#else
214    xformer_prog = "gunzip";
215#endif
216    if ((magic[0] != 0x1f) || (magic[1] != 0x8b)) {
217        if (ENABLE_FEATURE_RPM_BZ2
218         && (magic[0] == 0x42) && (magic[1] == 0x5a)) {
219#if BB_MMU
220            xformer = unpack_bz2_stream;
221#else
222            xformer_prog = "bunzip2";
223#endif
224    /* We can do better, need modifying unpack_bz2_stream to not require
225     * first 2 bytes. Not very hard to do... I mean, TODO :) */
226            xlseek(archive_handle->src_fd, -2, SEEK_CUR);
227        } else
228            bb_error_msg_and_die("no gzip"
229                USE_FEATURE_RPM_BZ2("/bzip")
230                " magic");
231    } else {
232        check_header_gzip_or_die(archive_handle->src_fd);
233#if !BB_MMU
234        /* NOMMU version of open_transformer execs an external unzipper that should
235         * have the file position at the start of the file */
236        xlseek(archive_handle->src_fd, 0, SEEK_SET);
237#endif
238    }
239
240    xchdir("/"); /* Install RPM's to root */
241    archive_handle->src_fd = open_transformer(archive_handle->src_fd, xformer, xformer_prog, xformer_prog, "-cf", "-", NULL);
242    archive_handle->offset = 0;
243    while (get_header_cpio(archive_handle) == EXIT_SUCCESS)
244        continue;
245}
246
247
248static rpm_index **rpm_gettags(int fd, int *num_tags)
249{
250    /* We should never need mode than 200, and realloc later */
251    rpm_index **tags = xzalloc(200 * sizeof(struct rpmtag *));
252    int pass, tagindex = 0;
253
254    xlseek(fd, 96, SEEK_CUR); /* Seek past the unused lead */
255
256    /* 1st pass is the signature headers, 2nd is the main stuff */
257    for (pass = 0; pass < 2; pass++) {
258        struct {
259            char magic[3]; /* 3 byte magic: 0x8e 0xad 0xe8 */
260            uint8_t version; /* 1 byte version number */
261            uint32_t reserved; /* 4 bytes reserved */
262            uint32_t entries; /* Number of entries in header (4 bytes) */
263            uint32_t size; /* Size of store (4 bytes) */
264        } header;
265        rpm_index *tmpindex;
266        int storepos;
267
268        xread(fd, &header, sizeof(header));
269        if (strncmp((char *) &header.magic, RPM_HEADER_MAGIC, 3) != 0)
270            return NULL; /* Invalid magic */
271        if (header.version != 1)
272            return NULL; /* This program only supports v1 headers */
273        header.size = ntohl(header.size);
274        header.entries = ntohl(header.entries);
275        storepos = xlseek(fd,0,SEEK_CUR) + header.entries * 16;
276
277        while (header.entries--) {
278            tmpindex = tags[tagindex++] = xmalloc(sizeof(rpm_index));
279            xread(fd, tmpindex, sizeof(rpm_index));
280            tmpindex->tag = ntohl(tmpindex->tag);
281            tmpindex->type = ntohl(tmpindex->type);
282            tmpindex->count = ntohl(tmpindex->count);
283            tmpindex->offset = storepos + ntohl(tmpindex->offset);
284            if (pass==0)
285                tmpindex->tag -= 743;
286        }
287        xlseek(fd, header.size, SEEK_CUR); /* Seek past store */
288        /* Skip padding to 8 byte boundary after reading signature headers */
289        if (pass==0)
290            xlseek(fd, (8 - (xlseek(fd,0,SEEK_CUR) % 8)) % 8, SEEK_CUR);
291    }
292    tags = xrealloc(tags, tagindex * sizeof(struct rpmtag *)); /* realloc tags to save space */
293    *num_tags = tagindex;
294    return tags; /* All done, leave the file at the start of the gzipped cpio archive */
295}
296
297static int bsearch_rpmtag(const void *key, const void *item)
298{
299    int *tag = (int *)key;
300    rpm_index **tmp = (rpm_index **) item;
301    return (*tag - tmp[0]->tag);
302}
303
304static int rpm_getcount(int tag)
305{
306    rpm_index **found;
307    found = bsearch(&tag, mytags, tagcount, sizeof(struct rpmtag *), bsearch_rpmtag);
308    if (!found)
309        return 0;
310    return found[0]->count;
311}
312
313static char *rpm_getstr(int tag, int itemindex)
314{
315    rpm_index **found;
316    found = bsearch(&tag, mytags, tagcount, sizeof(struct rpmtag *), bsearch_rpmtag);
317    if (!found || itemindex >= found[0]->count)
318        return NULL;
319    if (found[0]->type == RPM_STRING_TYPE || found[0]->type == RPM_I18NSTRING_TYPE || found[0]->type == RPM_STRING_ARRAY_TYPE) {
320        int n;
321        char *tmpstr = (char *) (map + found[0]->offset);
322        for (n=0; n < itemindex; n++)
323            tmpstr = tmpstr + strlen(tmpstr) + 1;
324        return tmpstr;
325    }
326    return NULL;
327}
328
329static int rpm_getint(int tag, int itemindex)
330{
331    rpm_index **found;
332    int *tmpint; /* NB: using int8_t* would be easier to code */
333
334    /* gcc throws warnings here when sizeof(void*)!=sizeof(int) ...
335     * it's ok to ignore it because tag won't be used as a pointer */
336    found = bsearch(&tag, mytags, tagcount, sizeof(struct rpmtag *), bsearch_rpmtag);
337    if (!found || itemindex >= found[0]->count)
338        return -1;
339
340    tmpint = (int *) (map + found[0]->offset);
341
342    if (found[0]->type == RPM_INT32_TYPE) {
343        tmpint = (int *) ((char *) tmpint + itemindex*4);
344        /*return ntohl(*tmpint);*/
345        /* int can be != int32_t */
346        return ntohl(*(int32_t*)tmpint);
347    }
348    if (found[0]->type == RPM_INT16_TYPE) {
349        tmpint = (int *) ((char *) tmpint + itemindex*2);
350        /* ??? read int, and THEN ntohs() it?? */
351        /*return ntohs(*tmpint);*/
352        return ntohs(*(int16_t*)tmpint);
353    }
354    if (found[0]->type == RPM_INT8_TYPE) {
355        tmpint = (int *) ((char *) tmpint + itemindex);
356        /* ??? why we don't read byte here??? */
357        /*return ntohs(*tmpint);*/
358        return *(int8_t*)tmpint;
359    }
360    return -1;
361}
362
363static void fileaction_dobackup(char *filename, int fileref)
364{
365    struct stat oldfile;
366    int stat_res;
367    char *newname;
368    if (rpm_getint(TAG_FILEFLAGS, fileref) & RPMFILE_CONFIG) {
369        /* Only need to backup config files */
370        stat_res = lstat(filename, &oldfile);
371        if (stat_res == 0 && S_ISREG(oldfile.st_mode)) {
372            /* File already exists  - really should check MD5's etc to see if different */
373            newname = xasprintf("%s.rpmorig", filename);
374            copy_file(filename, newname, FILEUTILS_RECUR | FILEUTILS_PRESERVE_STATUS);
375            remove_file(filename, FILEUTILS_RECUR | FILEUTILS_FORCE);
376            free(newname);
377        }
378    }
379}
380
381static void fileaction_setowngrp(char *filename, int fileref)
382{
383    int uid, gid;
384    uid = xuname2uid(rpm_getstr(TAG_FILEUSERNAME, fileref));
385    gid = xgroup2gid(rpm_getstr(TAG_FILEGROUPNAME, fileref));
386    chown(filename, uid, gid);
387}
388
389static void loop_through_files(int filetag, void (*fileaction)(char *filename, int fileref))
390{
391    int count = 0;
392    while (rpm_getstr(filetag, count)) {
393        char* filename = xasprintf("%s%s",
394            rpm_getstr(TAG_DIRNAMES, rpm_getint(TAG_DIRINDEXES, count)),
395            rpm_getstr(TAG_BASENAMES, count));
396        fileaction(filename, count++);
397        free(filename);
398    }
399}
Note: See TracBrowser for help on using the repository browser.