Renamed "internal.h" to the more sensible "busybox.h".
[oweals/busybox.git] / unrpm.c
1 /*
2  * Mini unrpm implementation 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 "busybox.h" 
17 #include <unistd.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <fcntl.h>
21 #include <string.h>
22
23 /*
24  * Some general definitions
25  */
26 #define BUFSIZE         512
27 #define RPM_MAGIC       "\355\253\356\333"
28 #define GZ_MAGIC_1      '\037'
29 #define GZ_MAGIC_2      '\213'
30
31 /*
32  * Global variables
33  */
34 static char buffer[BUFSIZE];
35 static char *progname;
36 static int infile, outfile;
37
38 /*
39  * Read a specified number of bytes from input file
40  */
41 static void myread(int num)
42 {
43   int err;
44
45   if ((err = read(infile, buffer, num)) != num) {
46         if (err < 0)
47                 perror(progname);
48         else
49                 fprintf(stderr, "unexpected end of input file\n");
50         exit(1);
51   }
52 }
53
54 /*
55  * Main program
56  */
57 int unrpm_main(int argc, char **argv)
58 {
59   int len, status = 0;
60
61   /* Get our own program name */
62   if ((progname = strrchr(argv[0], '/')) == NULL)
63         progname = argv[0];
64   else
65         progname++;
66
67   /* Check for command line parameters */
68         if (argc>=2 && *argv[1]=='-') {
69            usage(unrpm_usage);
70         }
71
72   /* Open input file */
73   if (argc == 1)
74         infile = STDIN_FILENO;
75   else if ((infile = open(argv[1], O_RDONLY)) < 0) {
76         perror(progname);
77         exit(1);
78   }
79
80   /* Read magic ID and output filename */
81   myread(4);
82   if (strncmp(buffer, RPM_MAGIC, 4)) {
83         fprintf(stderr, "input file is not in RPM format\n");
84         exit(1);
85   }
86   myread(6);            /* Skip flags */
87   myread(64);
88   buffer[64] = '\0';
89
90   /* Open output file */
91   strcat(buffer, ".cpio.gz");
92   if (infile == STDIN_FILENO)
93         outfile = STDOUT_FILENO;
94   else if ((outfile = open(buffer, O_WRONLY | O_CREAT | O_TRUNC, 0644)) < 0) {
95         perror(progname);
96         exit(1);
97   }
98
99   /*
100    * Now search for the GZIP signature. This is rather awkward, but I don't
101    * know any other way how to find out the exact starting position of the
102    * archive within the input file. There are a couple of data structures
103    * and texts (obviously descriptions, installation shell scripts etc.)
104    * coming before the archive, but even they start at different offsets
105    * with different RPM files. However, it looks like the GZIP signature
106    * never appears before offset 0x200, so we skip these first couple of
107    * bytes to make the signature scan a little more reliable.
108    */
109   myread(0x200 - 74);
110   while (status < 2) {
111         myread(1);
112         if (status == 0 && buffer[0] == GZ_MAGIC_1)
113                 status++;
114         else if (status == 1 && buffer[0] == GZ_MAGIC_2)
115                 status++;
116         else
117                 status = 0;
118   }
119   buffer[0] = GZ_MAGIC_1;
120   buffer[1] = GZ_MAGIC_2;
121   if (write(outfile, buffer, 2) < 0) {
122         perror(progname);
123         exit(1);
124   }
125
126   /* Now simply copy the GZIP archive into the output file */
127   while ((len = read(infile, buffer, BUFSIZE)) > 0) {
128         if (write(outfile, buffer, len) < 0) {
129                 perror(progname);
130                 exit(1);
131         }
132   }
133   if (len < 0) {
134         perror(progname);
135         exit(1);
136   }
137   close(outfile);
138   close(infile);
139   exit(0);
140 }