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

Last change on this file since 1770 was 1770, checked in by Bruno Cornec, 16 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.