blob: 2178a247dd72a27ecc611d2931b8050c353be833 [file] [log] [blame]
Eric Andersencff3fe32000-09-20 19:22:26 +00001/*
Eric Andersen4bfb6b72000-11-29 21:39:02 +00002 * rpmunpack for busybox
Eric Andersencff3fe32000-09-20 19:22:26 +00003 *
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
Eric Andersen3570a342000-09-25 21:45:58 +000016#include "busybox.h"
Eric Andersencff3fe32000-09-20 19:22:26 +000017#include <fcntl.h>
Eric Andersencff3fe32000-09-20 19:22:26 +000018
19/*
20 * Some general definitions
21 */
22#define BUFSIZE 512
23#define RPM_MAGIC "\355\253\356\333"
24#define GZ_MAGIC_1 '\037'
25#define GZ_MAGIC_2 '\213'
26
27/*
28 * Global variables
29 */
30static char buffer[BUFSIZE];
31static char *progname;
32static int infile, outfile;
33
34/*
35 * Read a specified number of bytes from input file
36 */
37static void myread(int num)
38{
39 int err;
40
41 if ((err = read(infile, buffer, num)) != num) {
42 if (err < 0)
43 perror(progname);
44 else
Eric Andersen4bfb6b72000-11-29 21:39:02 +000045 fprintf(stderr, "Unexpected end of input file!\n");
Eric Andersencff3fe32000-09-20 19:22:26 +000046 exit(1);
47 }
48}
49
50/*
51 * Main program
52 */
Eric Andersen4bfb6b72000-11-29 21:39:02 +000053int rpmunpack_main(int argc, char **argv)
Eric Andersencff3fe32000-09-20 19:22:26 +000054{
55 int len, status = 0;
56
57 /* Get our own program name */
58 if ((progname = strrchr(argv[0], '/')) == NULL)
59 progname = argv[0];
60 else
61 progname++;
62
63 /* Check for command line parameters */
64 if (argc>=2 && *argv[1]=='-') {
Eric Andersen4bfb6b72000-11-29 21:39:02 +000065 usage(rpmunpack_usage);
Eric Andersencff3fe32000-09-20 19:22:26 +000066 }
67
68 /* Open input file */
69 if (argc == 1)
70 infile = STDIN_FILENO;
71 else if ((infile = open(argv[1], O_RDONLY)) < 0) {
72 perror(progname);
73 exit(1);
74 }
75
76 /* Read magic ID and output filename */
77 myread(4);
78 if (strncmp(buffer, RPM_MAGIC, 4)) {
Eric Andersen4bfb6b72000-11-29 21:39:02 +000079 fprintf(stderr, "Input file is not in RPM format!\n");
Eric Andersencff3fe32000-09-20 19:22:26 +000080 exit(1);
81 }
82 myread(6); /* Skip flags */
83 myread(64);
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(progname);
92 exit(1);
93 }
94
95 /*
96 * Now search for the GZIP signature. This is rather awkward, but I don't
97 * know any other way how to find out the exact starting position of the
98 * archive within the input file. There are a couple of data structures
99 * and texts (obviously descriptions, installation shell scripts etc.)
100 * coming before the archive, but even they start at different offsets
101 * with different RPM files. However, it looks like the GZIP signature
102 * never appears before offset 0x200, so we skip these first couple of
103 * bytes to make the signature scan a little more reliable.
104 */
105 myread(0x200 - 74);
106 while (status < 2) {
107 myread(1);
108 if (status == 0 && buffer[0] == GZ_MAGIC_1)
109 status++;
110 else if (status == 1 && buffer[0] == GZ_MAGIC_2)
111 status++;
112 else
113 status = 0;
114 }
115 buffer[0] = GZ_MAGIC_1;
116 buffer[1] = GZ_MAGIC_2;
117 if (write(outfile, buffer, 2) < 0) {
118 perror(progname);
119 exit(1);
120 }
121
122 /* Now simply copy the GZIP archive into the output file */
123 while ((len = read(infile, buffer, BUFSIZE)) > 0) {
124 if (write(outfile, buffer, len) < 0) {
125 perror(progname);
126 exit(1);
127 }
128 }
129 if (len < 0) {
130 perror(progname);
131 exit(1);
132 }
133 close(outfile);
134 close(infile);
135 exit(0);
136}