1/* 2 * rpmunpack for busybox 3 * 4 * rpmunpack.c - Utility program to unpack an RPM archive 5 * 6 * Gero Kuhlmann <gero@gkminix.han.de> 1998 7 * 8 * This program is public domain software; you can do whatever you like 9 * with this source, including modifying and redistributing it. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 */ 15 16#include <fcntl.h> 17#include <unistd.h> 18#include <string.h> 19#include <stdlib.h> 20#include "busybox.h" 21 22/* 23 * Some general definitions 24 */ 25 26#define RPM_MAGIC "\355\253\356\333" 27#define GZ_MAGIC_1 '\037' 28#define GZ_MAGIC_2 '\213' 29 30/* 31 * Global variables 32 */ 33static char *progname; 34static int infile, outfile; 35 36/* 37 * Read a specified number of bytes from input file 38 */ 39static void myread(int num, char *buffer) 40{ 41 int err; 42 43 if ((err = read(infile, buffer, num)) != num) { 44 if (err < 0) 45 perror_msg_and_die(progname); 46 else 47 error_msg_and_die("Unexpected end of input file!"); 48 } 49} 50 51/* 52 * Main program 53 */ 54int rpmunpack_main(int argc, char **argv) 55{ 56 int len, status = 0; 57 RESERVE_BB_BUFFER(buffer, BUFSIZ); 58 59 /* Get our own program name */ 60 if ((progname = strrchr(argv[0], '/')) == NULL) 61 progname = argv[0]; 62 else 63 progname++; 64 65 /* Check for command line parameters */ 66 if (argc>=2 && *argv[1]=='-') { 67 show_usage(); 68 } 69 70 /* Open input file */ 71 if (argc == 1) 72 infile = STDIN_FILENO; 73 else if ((infile = open(argv[1], O_RDONLY)) < 0) 74 perror_msg_and_die("%s", argv[1]); 75 76 /* Read magic ID and output filename */ 77 myread(4, buffer); 78 if (strncmp(buffer, RPM_MAGIC, 4)) { 79 fprintf(stderr, "Input file is not in RPM format!\n"); 80 exit(1); 81 } 82 myread(6, buffer); /* Skip flags */ 83 myread(64, buffer); 84 buffer[64] = '\0'; 85 86 /* Open output file */ 87 strcat(buffer, ".cpio.gz"); 88 if (infile == STDIN_FILENO) 89 outfile = STDOUT_FILENO; 90 else if ((outfile = open(buffer, O_WRONLY | O_CREAT | O_TRUNC, 0644)) < 0) 91 perror_msg_and_die("%s", buffer); 92 93 /* 94 * Now search for the GZIP signature. This is rather awkward, but I don't 95 * know any other way how to find out the exact starting position of the 96 * archive within the input file. There are a couple of data structures 97 * and texts (obviously descriptions, installation shell scripts etc.) 98 * coming before the archive, but even they start at different offsets 99 * with different RPM files. However, it looks like the GZIP signature 100 * never appears before offset 0x200, so we skip these first couple of 101 * bytes to make the signature scan a little more reliable. 102 */ 103 myread(0x200 - 74, buffer); 104 while (status < 2) { 105 myread(1, buffer); 106 if (status == 0 && buffer[0] == GZ_MAGIC_1) 107 status++; 108 else if (status == 1 && buffer[0] == GZ_MAGIC_2) 109 status++; 110 else 111 status = 0; 112 } 113 buffer[0] = GZ_MAGIC_1; 114 buffer[1] = GZ_MAGIC_2; 115 if (write(outfile, buffer, 2) < 0) 116 perror_msg_and_die("write"); 117 118 /* Now simply copy the GZIP archive into the output file */ 119 while ((len = read(infile, buffer, BUFSIZ)) > 0) { 120 if (write(outfile, buffer, len) < 0) 121 perror_msg_and_die("write"); 122 } 123 if (len < 0) 124 perror_msg_and_die("read"); 125 return EXIT_SUCCESS; 126} 127