Changeset 3621 in MondoRescue for branches/3.3/mindi-busybox/archival/rpm.c
- Timestamp:
- Dec 20, 2016, 4:07:32 PM (7 years ago)
- Location:
- branches/3.3
- Files:
-
- 1 edited
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
branches/3.3/mindi-busybox/archival/rpm.c
r3232 r3621 8 8 */ 9 9 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 10 19 //usage:#define rpm_trivial_usage 11 20 //usage: "-i PACKAGE.rpm; rpm -qp[ildc] PACKAGE.rpm" … … 15 24 //usage: "\n -i Install package" 16 25 //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" 21 30 22 31 #include "libbb.h" 32 #include "common_bufsiz.h" 23 33 #include "bb_archive.h" 24 34 #include "rpm.h" … … 80 90 } rpm_index; 81 91 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)); 92 struct 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 100 static 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 131 static 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 174 static 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 181 static 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 190 static 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 209 static 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 236 static 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 254 static 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 264 static 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 } 95 275 96 276 int rpm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 97 277 int rpm_main(int argc, char **argv) 98 278 { 99 int opt = 0, func = 0, rpm_fd, offset;100 const intpagesize = getpagesize();279 int opt, func = 0; 280 const unsigned pagesize = getpagesize(); 101 281 102 282 while ((opt = getopt(argc, argv, "iqpldc")) != -1) { … … 135 315 136 316 while (*argv) { 317 int rpm_fd; 318 unsigned mapsize; 137 319 const char *source_rpm; 138 320 139 321 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) 142 324 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? 146 330 147 331 source_rpm = rpm_getstr(TAG_SOURCERPM, 0); … … 167 351 const char *p; 168 352 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)"); 175 364 bdate_time = rpm_getint(TAG_BUILDTIME, 0); 176 365 bdate_ptm = localtime(&bdate_time); 177 366 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)); 184 376 printf("Description :\n%s\n", rpm_getstr(TAG_DESCRIPTION, 0)); 185 377 } … … 206 398 } 207 399 } 208 free(mytags); 400 munmap(G.map, mapsize); 401 free(G.mytags); 402 close(rpm_fd); 209 403 } 210 404 return 0; 211 405 } 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 #endif230 archive_handle->ah_flags = ARCHIVE_RESTORE_DATE | ARCHIVE_CREATE_LEADING_DIRS231 /* 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_TYPE310 || found[0]->type == RPM_I18NSTRING_TYPE311 || found[0]->type == RPM_STRING_ARRAY_TYPE312 ) {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.