1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19#include "libbb.h"
20#include "common_bufsiz.h"
21#include "bb_archive.h"
22#include "rpm.h"
23
24#define RPM_CHAR_TYPE 1
25#define RPM_INT8_TYPE 2
26#define RPM_INT16_TYPE 3
27#define RPM_INT32_TYPE 4
28
29#define RPM_STRING_TYPE 6
30#define RPM_BIN_TYPE 7
31#define RPM_STRING_ARRAY_TYPE 8
32#define RPM_I18NSTRING_TYPE 9
33
34#define TAG_NAME 1000
35#define TAG_VERSION 1001
36#define TAG_RELEASE 1002
37#define TAG_SUMMARY 1004
38#define TAG_DESCRIPTION 1005
39#define TAG_BUILDTIME 1006
40#define TAG_BUILDHOST 1007
41#define TAG_SIZE 1009
42#define TAG_VENDOR 1011
43#define TAG_LICENSE 1014
44#define TAG_PACKAGER 1015
45#define TAG_GROUP 1016
46#define TAG_URL 1020
47#define TAG_PREIN 1023
48#define TAG_POSTIN 1024
49#define TAG_FILEFLAGS 1037
50#define TAG_FILEUSERNAME 1039
51#define TAG_FILEGROUPNAME 1040
52#define TAG_SOURCERPM 1044
53#define TAG_PREINPROG 1085
54#define TAG_POSTINPROG 1086
55#define TAG_PREFIXS 1098
56#define TAG_DIRINDEXES 1116
57#define TAG_BASENAMES 1117
58#define TAG_DIRNAMES 1118
59#define TAG_PAYLOADCOMPRESSOR 1125
60
61
62#define RPMFILE_CONFIG (1 << 0)
63#define RPMFILE_DOC (1 << 1)
64
65enum rpm_functions_e {
66 rpm_query = 1,
67 rpm_install = 2,
68 rpm_query_info = 4,
69 rpm_query_package = 8,
70 rpm_query_list = 16,
71 rpm_query_list_doc = 32,
72 rpm_query_list_config = 64
73};
74
75typedef struct {
76 uint32_t tag;
77 uint32_t type;
78 uint32_t offset;
79 uint32_t count;
80} rpm_index;
81
82struct globals {
83 void *map;
84 rpm_index *mytags;
85 int tagcount;
86 unsigned mapsize;
87 IF_VARIABLE_ARCH_PAGESIZE(unsigned pagesize;)
88#define G_pagesize cached_pagesize(G.pagesize)
89} FIX_ALIASING;
90#define G (*(struct globals*)bb_common_bufsiz1)
91#define INIT_G() do { setup_common_bufsiz(); } while (0)
92
93static int rpm_gettags(const char *filename)
94{
95 rpm_index *tags;
96 int fd;
97 unsigned pass, idx;
98 unsigned storepos;
99
100 if (!filename) {
101 filename = bb_msg_standard_output;
102 fd = 0;
103 } else {
104 fd = xopen(filename, O_RDONLY);
105 }
106
107 storepos = xlseek(fd, 96, SEEK_CUR);
108 G.tagcount = 0;
109 tags = NULL;
110 idx = 0;
111
112 for (pass = 0; pass < 2; pass++) {
113 struct rpm_header header;
114 unsigned cnt;
115
116 xread(fd, &header, sizeof(header));
117 if (header.magic_and_ver != htonl(RPM_HEADER_MAGICnVER))
118 bb_error_msg_and_die("invalid RPM header magic in '%s'", filename);
119 header.size = ntohl(header.size);
120 cnt = ntohl(header.entries);
121 storepos += sizeof(header) + cnt * 16;
122
123 G.tagcount += cnt;
124 tags = xrealloc(tags, sizeof(tags[0]) * G.tagcount);
125 xread(fd, &tags[idx], sizeof(tags[0]) * cnt);
126 while (cnt--) {
127 rpm_index *tag = &tags[idx];
128 tag->tag = ntohl(tag->tag);
129 tag->type = ntohl(tag->type);
130 tag->count = ntohl(tag->count);
131 tag->offset = storepos + ntohl(tag->offset);
132 if (pass == 0)
133 tag->tag -= 743;
134 idx++;
135 }
136
137 if (pass == 0)
138 while (header.size & 7)
139 header.size++;
140
141 storepos = xlseek(fd, header.size, SEEK_CUR);
142 }
143 G.mytags = tags;
144
145
146 storepos = (storepos + G_pagesize) & -(int)G_pagesize;
147
148 G.mapsize = storepos;
149
150 G.map = mmap_read(fd, storepos);
151 if (G.map == MAP_FAILED)
152 bb_perror_msg_and_die("mmap '%s'", filename);
153
154 return fd;
155}
156
157static int bsearch_rpmtag(const void *key, const void *item)
158{
159 int *tag = (int *)key;
160 rpm_index *tmp = (rpm_index *) item;
161 return (*tag - tmp->tag);
162}
163
164static char *rpm_getstr(int tag, int itemindex)
165{
166 rpm_index *found;
167 found = bsearch(&tag, G.mytags, G.tagcount, sizeof(G.mytags[0]), bsearch_rpmtag);
168 if (!found || itemindex >= found->count)
169 return NULL;
170 if (found->type == RPM_STRING_TYPE
171 || found->type == RPM_I18NSTRING_TYPE
172 || found->type == RPM_STRING_ARRAY_TYPE
173 ) {
174 int n;
175 char *tmpstr = (char *) G.map + found->offset;
176 for (n = 0; n < itemindex; n++)
177 tmpstr = tmpstr + strlen(tmpstr) + 1;
178 return tmpstr;
179 }
180 return NULL;
181}
182static char *rpm_getstr0(int tag)
183{
184 return rpm_getstr(tag, 0);
185}
186
187#if ENABLE_RPM
188
189static int rpm_getint(int tag, int itemindex)
190{
191 rpm_index *found;
192 char *tmpint;
193
194
195
196 found = bsearch(&tag, G.mytags, G.tagcount, sizeof(G.mytags[0]), bsearch_rpmtag);
197 if (!found || itemindex >= found->count)
198 return -1;
199
200 tmpint = (char *) G.map + found->offset;
201 if (found->type == RPM_INT32_TYPE) {
202 tmpint += itemindex*4;
203 return ntohl(*(int32_t*)tmpint);
204 }
205 if (found->type == RPM_INT16_TYPE) {
206 tmpint += itemindex*2;
207 return ntohs(*(int16_t*)tmpint);
208 }
209 if (found->type == RPM_INT8_TYPE) {
210 tmpint += itemindex;
211 return *(int8_t*)tmpint;
212 }
213 return -1;
214}
215
216static int rpm_getcount(int tag)
217{
218 rpm_index *found;
219 found = bsearch(&tag, G.mytags, G.tagcount, sizeof(G.mytags[0]), bsearch_rpmtag);
220 if (!found)
221 return 0;
222 return found->count;
223}
224
225static void fileaction_dobackup(char *filename, int fileref)
226{
227 struct stat oldfile;
228 int stat_res;
229 char *newname;
230 if (rpm_getint(TAG_FILEFLAGS, fileref) & RPMFILE_CONFIG) {
231
232 stat_res = lstat(filename, &oldfile);
233 if (stat_res == 0 && S_ISREG(oldfile.st_mode)) {
234
235 newname = xasprintf("%s.rpmorig", filename);
236 copy_file(filename, newname, FILEUTILS_RECUR | FILEUTILS_PRESERVE_STATUS);
237 remove_file(filename, FILEUTILS_RECUR | FILEUTILS_FORCE);
238 free(newname);
239 }
240 }
241}
242
243static void fileaction_setowngrp(char *filename, int fileref)
244{
245
246 struct passwd *pw = getpwnam(rpm_getstr(TAG_FILEUSERNAME, fileref));
247 int uid = pw ? pw->pw_uid : getuid();
248 struct group *gr = getgrnam(rpm_getstr(TAG_FILEGROUPNAME, fileref));
249 int gid = gr ? gr->gr_gid : getgid();
250 chown(filename, uid, gid);
251}
252
253static void loop_through_files(int filetag, void (*fileaction)(char *filename, int fileref))
254{
255 int count = 0;
256 while (rpm_getstr(filetag, count)) {
257 char* filename = xasprintf("%s%s",
258 rpm_getstr(TAG_DIRNAMES, rpm_getint(TAG_DIRINDEXES, count)),
259 rpm_getstr(TAG_BASENAMES, count));
260 fileaction(filename, count++);
261 free(filename);
262 }
263}
264
265#if 0
266static void print_all_tags(void)
267{
268 unsigned i = 0;
269 while (i < G.tagcount) {
270 rpm_index *tag = &G.mytags[i];
271 if (tag->type == RPM_STRING_TYPE
272 || tag->type == RPM_I18NSTRING_TYPE
273 || tag->type == RPM_STRING_ARRAY_TYPE
274 ) {
275 unsigned n;
276 char *str = (char *) G.map + tag->offset;
277
278 printf("tag[%u] %08x type %08x offset %08x count %d '%s'\n",
279 i, tag->tag, tag->type, tag->offset, tag->count, str
280 );
281 for (n = 1; n < tag->count; n++) {
282 str += strlen(str) + 1;
283 printf("\t'%s'\n", str);
284 }
285 }
286 i++;
287 }
288}
289#else
290#define print_all_tags() ((void)0)
291#endif
292
293static void extract_cpio(int fd, const char *source_rpm)
294{
295 archive_handle_t *archive_handle;
296
297 if (source_rpm != NULL) {
298
299 xchdir("/");
300 }
301
302
303 archive_handle = init_handle();
304 archive_handle->seek = seek_by_read;
305 archive_handle->action_data = data_extract_all;
306#if 0
307 archive_handle->action_header = header_list;
308 archive_handle->action_data = data_skip;
309#endif
310 archive_handle->ah_flags = ARCHIVE_RESTORE_DATE | ARCHIVE_CREATE_LEADING_DIRS
311
312
313
314
315 | ARCHIVE_REPLACE_VIA_RENAME;
316 archive_handle->src_fd = fd;
317
318
319 setup_unzip_on_fd(archive_handle->src_fd, 1);
320 while (get_header_cpio(archive_handle) == EXIT_SUCCESS)
321 continue;
322}
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355int rpm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
356int rpm_main(int argc, char **argv)
357{
358 int opt, func = 0;
359
360 INIT_G();
361 INIT_PAGESIZE(G.pagesize);
362
363 while ((opt = getopt(argc, argv, "iqpldc")) != -1) {
364 switch (opt) {
365 case 'i':
366 if (!func) func = rpm_install;
367 else func |= rpm_query_info;
368 break;
369 case 'q':
370 if (func) bb_show_usage();
371 func = rpm_query;
372 break;
373 case 'p':
374 func |= rpm_query_package;
375 break;
376 case 'l':
377 func |= rpm_query_list;
378 break;
379 case 'd':
380 func |= rpm_query_list;
381 func |= rpm_query_list_doc;
382 break;
383 case 'c':
384 func |= rpm_query_list;
385 func |= rpm_query_list_config;
386 break;
387 default:
388 bb_show_usage();
389 }
390 }
391 argv += optind;
392
393 if (!argv[0]) {
394 bb_show_usage();
395 }
396
397 for (;;) {
398 int rpm_fd;
399 const char *source_rpm;
400
401 rpm_fd = rpm_gettags(*argv);
402 print_all_tags();
403
404 source_rpm = rpm_getstr0(TAG_SOURCERPM);
405
406 if (func & rpm_install) {
407
408
409
410 loop_through_files(TAG_BASENAMES, fileaction_dobackup);
411
412 extract_cpio(rpm_fd, source_rpm);
413
414 loop_through_files(TAG_BASENAMES, fileaction_setowngrp);
415 }
416 else
417 if ((func & (rpm_query|rpm_query_package)) == (rpm_query|rpm_query_package)) {
418
419
420 if (!(func & (rpm_query_info|rpm_query_list))) {
421
422 printf("%s-%s-%s\n", rpm_getstr0(TAG_NAME), rpm_getstr0(TAG_VERSION), rpm_getstr0(TAG_RELEASE));
423 }
424 if (func & rpm_query_info) {
425
426 time_t bdate_time;
427 struct tm *bdate_ptm;
428 char bdatestring[50];
429 const char *p;
430
431 printf("%-12s: %s\n", "Name" , rpm_getstr0(TAG_NAME));
432
433 printf("%-12s: %s\n", "Version" , rpm_getstr0(TAG_VERSION));
434 printf("%-12s: %s\n", "Release" , rpm_getstr0(TAG_RELEASE));
435
436
437 printf("%-12s: %s\n", "Group" , rpm_getstr0(TAG_GROUP));
438 printf("%-12s: %d\n", "Size" , rpm_getint(TAG_SIZE, 0));
439 printf("%-12s: %s\n", "License" , rpm_getstr0(TAG_LICENSE));
440
441 printf("%-12s: %s\n", "Source RPM" , source_rpm ? source_rpm : "(none)");
442 bdate_time = rpm_getint(TAG_BUILDTIME, 0);
443 bdate_ptm = localtime(&bdate_time);
444 strftime(bdatestring, 50, "%a %d %b %Y %T %Z", bdate_ptm);
445 printf("%-12s: %s\n", "Build Date" , bdatestring);
446 printf("%-12s: %s\n", "Build Host" , rpm_getstr0(TAG_BUILDHOST));
447 p = rpm_getstr0(TAG_PREFIXS);
448 printf("%-12s: %s\n", "Relocations" , p ? p : "(not relocatable)");
449
450 p = rpm_getstr0(TAG_VENDOR);
451 if (p)
452 printf("%-12s: %s\n", "Vendor" , p);
453 p = rpm_getstr0(TAG_URL);
454 if (p)
455 printf("%-12s: %s\n", "URL" , p);
456 printf("%-12s: %s\n", "Summary" , rpm_getstr0(TAG_SUMMARY));
457 printf("Description :\n%s\n", rpm_getstr0(TAG_DESCRIPTION));
458 }
459 if (func & rpm_query_list) {
460 int count, it, flags;
461 count = rpm_getcount(TAG_BASENAMES);
462 for (it = 0; it < count; it++) {
463 flags = rpm_getint(TAG_FILEFLAGS, it);
464 switch (func & (rpm_query_list_doc|rpm_query_list_config)) {
465 case rpm_query_list_doc:
466 if (!(flags & RPMFILE_DOC)) continue;
467 break;
468 case rpm_query_list_config:
469 if (!(flags & RPMFILE_CONFIG)) continue;
470 break;
471 case rpm_query_list_doc|rpm_query_list_config:
472 if (!(flags & (RPMFILE_CONFIG|RPMFILE_DOC))) continue;
473 break;
474 }
475 printf("%s%s\n",
476 rpm_getstr(TAG_DIRNAMES, rpm_getint(TAG_DIRINDEXES, it)),
477 rpm_getstr(TAG_BASENAMES, it));
478 }
479 }
480 } else {
481
482 bb_show_usage();
483 }
484 if (!*++argv)
485 break;
486 munmap(G.map, G.mapsize);
487 free(G.mytags);
488 close(rpm_fd);
489 }
490
491 return 0;
492}
493
494#endif
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518#if ENABLE_RPM2CPIO
519
520
521int rpm2cpio_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
522int rpm2cpio_main(int argc UNUSED_PARAM, char **argv)
523{
524 const char *str;
525 int rpm_fd;
526
527 INIT_G();
528 INIT_PAGESIZE(G.pagesize);
529
530 rpm_fd = rpm_gettags(argv[1]);
531
532
533
534
535
536 if (ENABLE_FEATURE_SEAMLESS_LZMA
537 && (str = rpm_getstr0(TAG_PAYLOADCOMPRESSOR)) != NULL
538 && strcmp(str, "lzma") == 0
539 ) {
540
541
542 setup_lzma_on_fd(rpm_fd);
543 } else {
544 setup_unzip_on_fd(rpm_fd, 1);
545 }
546
547 if (bb_copyfd_eof(rpm_fd, STDOUT_FILENO) < 0)
548 bb_simple_error_msg_and_die("error unpacking");
549
550 if (ENABLE_FEATURE_CLEAN_UP) {
551 close(rpm_fd);
552 }
553
554 if (SEAMLESS_COMPRESSION) {
555 check_errors_in_children(0);
556 return bb_got_signal;
557 }
558 return EXIT_SUCCESS;
559}
560
561#endif
562