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