Initial import from FreeBSD RELENG_4:
[games.git] / usr.bin / kzip / kzip.c
1 /*
2  * ----------------------------------------------------------------------------
3  * "THE BEER-WARE LICENSE" (Revision 42):
4  * <phk@login.dknet.dk> wrote this file.  As long as you retain this notice you
5  * can do whatever you want with this stuff. If we meet some day, and you think
6  * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
7  * ----------------------------------------------------------------------------
8  *
9  * Copyright (C) 1993  Hannu Savolainen
10  * Ported to 386bsd by Serge Vakulenko
11  * based on tools/build.c by Linus Torvalds
12  */
13
14 #ifndef lint
15 static const char rcsid[] =
16   "$FreeBSD: src/usr.bin/kzip/kzip.c,v 1.13.2.2 2000/07/20 10:35:20 kris Exp $";
17 #endif /* not lint */
18
19 #include <err.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <sys/file.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <sys/param.h>
27 #include <sys/wait.h>
28 #include <a.out.h>
29 #include <string.h>
30
31 #define MAXIMAGE        (2*1024*1024)
32         /* This is the limit because a kzip'ed kernel loads at 3Mb and
33          * ends up at 1Mb
34          */
35 static void
36 usage()
37 {
38         fprintf(stderr, "usage: kzip [-v] [ -l loadaddr] kernel\n");
39         exit(1);
40 }
41
42 int
43 main(int argc, char **argv)
44 {
45         pid_t Pext, Pgzip, Ppiggy, Pld;
46         int pipe1[2], pipe2[2];
47         int status, fdi, fdo, fdn, c, verbose;
48         int size;
49         struct exec hdr;
50         int zip_size, offset;
51         struct stat st;
52         u_long forceaddr = 0, entry;
53         char *kernname;
54         char obj[MAXPATHLEN + 1];
55         char out[MAXPATHLEN + 1];
56         char base[32];
57         
58         while ((c = getopt(argc, argv, "l:v")) != -1) {
59                 switch (c) {
60                 case 'l':
61                         forceaddr = strtoul(optarg, NULL, 0);
62                         if (forceaddr == 0)
63                                 errx(1, "invalid load address");
64                         break;
65                 case 'v':
66                         verbose++;
67                         break;
68                 default:
69                         usage();
70                 }
71         }
72
73         if ((argc - optind) != 1)
74                 usage();
75
76         argc -= optind;
77         argv += optind;
78
79         kernname = argv[0];
80                         
81         if (strlen(kernname) > MAXPATHLEN - 3)
82                 errx(1, "%s: File name too long", kernname);
83         strcpy(obj, kernname); strcat(obj,".o");
84         strcpy(out, kernname); strcat(out,".kz");
85
86         fdi = open(kernname ,O_RDONLY);
87         if(fdi<0) {
88                 warn("%s", kernname);
89                 return 2;
90         }
91
92         /* figure out how big the uncompressed image will be */
93         if (read (fdi, (char *)&hdr, sizeof(hdr)) != sizeof(hdr))
94                 err(2, "%s", argv[1]);
95
96         size = hdr.a_text + hdr.a_data + hdr.a_bss;
97         entry = hdr.a_entry & 0x00FFFFFF;
98
99         lseek (fdi, 0, SEEK_SET);
100
101         if (verbose) {
102                 printf("real kernel start address will be: 0x%x\n", entry);
103                 printf("real kernel end   address will be: 0x%x\n", entry+size);
104         }
105
106
107         fdo = open(obj,O_WRONLY|O_TRUNC|O_CREAT,0666);
108         if(fdo<0) {
109                 warn("%s", obj);
110                 return 2;
111         }
112
113         if (pipe(pipe1) < 0) { perror("pipe()"); return 1; }
114
115         if (pipe(pipe2) < 0) { perror("pipe()"); return 1; }
116
117         Pext = fork();
118         if (Pext < 0) { perror("fork()"); return 1; }
119         if (!Pext) {
120                 dup2(fdi,0);
121                 dup2(pipe1[1],1);
122                 close(pipe1[0]); close(pipe1[1]);
123                 close(pipe2[0]); close(pipe2[1]);
124                 close(fdi); close(fdo);
125                 extract(kernname);
126                 exit(0);
127         }
128
129         Pgzip = fork();
130         if (Pgzip < 0) { perror("fork()"); return 1; }
131         if (!Pgzip) {
132                 dup2(pipe1[0],0);
133                 dup2(pipe2[1],1);
134                 close(pipe1[0]); close(pipe1[1]);
135                 close(pipe2[0]); close(pipe2[1]);
136                 close(fdi); close(fdo);
137                 execlp("gzip", "gzip", "-9", "-n", 0);
138                 exit (0);
139         }
140
141         Ppiggy = fork();
142         if (Ppiggy < 0) { warn("fork()"); return 1; }
143         if (!Ppiggy) {
144                 dup2(pipe2[0],0);
145                 dup2(fdo,1);
146                 close(pipe1[0]); close(pipe1[1]);
147                 close(pipe2[0]); close(pipe2[1]);
148                 close(fdi); close(fdo);
149                 piggyback(obj);
150                 exit(0);
151         }
152
153         close(pipe1[0]); close(pipe1[1]);
154         close(pipe2[0]); close(pipe2[1]);
155         close(fdi); close(fdo);
156
157         if (waitpid(Pext, &status,0) < 0)
158                 { warn("waitpid(Pextract)"); return 1; }
159
160         if(status) {
161                 warnx("extract returned %x",status);
162                 return 3;
163         }
164
165         if (waitpid(Pgzip, &status,0) < 0)
166                 { perror("waitpid(Pgzip)"); return 1; }
167
168         if(status) {
169                 warnx("gzip returned %x",status);
170                 return 3;
171         }
172
173         if (waitpid(Ppiggy, &status,0) < 0)
174                 { warn("waitpid(Ppiggy)"); return 1; }
175
176         if(status) {
177                 warnx("piggyback returned %x",status);
178                 return 3;
179         }
180
181         if (forceaddr)
182                 offset = forceaddr;
183         else {
184                 /* a kludge to dynamically figure out where to start it */
185                 if (stat (obj, &st) < 0) {
186                         warn("cannot get size of compressed data");
187                         return 3;
188                 }
189                 zip_size = (int)st.st_size;
190                 offset = entry + size - zip_size + 0x8000; /* fudge factor */
191         }
192         sprintf(base, "0x%x", roundup(offset, 4096));
193
194         Pld = fork();
195         if (Pld < 0) { warn("fork()"); return 1; }
196         if (!Pld) {
197                 execlp("ld",
198                         "ld",
199                         "-aout",
200                         "-Bstatic",
201                         "-Z",
202                         "-T",
203                         base,
204                         "-o",
205                         out,
206                         "/usr/lib/aout/kzhead.o",
207                         obj,
208                         "/usr/lib/aout/kztail.o",
209                         0);
210                 exit(2);
211         }
212
213         if (waitpid(Pld, &status,0) < 0)
214                 { warn("waitpid(Pld)"); return 1; }
215
216         if(status) {
217                 warnx("ld returned %x",status);
218                 return 3;
219         }
220
221         if (verbose) {
222
223                 fdn = open(obj ,O_RDONLY);
224                 if(fdn<0) {
225                         warn("%s", obj);
226                         return 3;
227                 }
228
229                 /* figure out how big the compressed image is */
230                 if (read (fdn, (char *)&hdr, sizeof(hdr)) != sizeof(hdr)) {
231                         warn("%s", obj);
232                         return 3;
233                 }
234                 close(fdn);
235
236                 size = hdr.a_text + hdr.a_data + hdr.a_bss;
237
238                 printf("kzip data   start address will be: 0x%x\n",offset);
239                 printf("kzip data   end   address will be: 0x%x\n",offset+size);
240         }
241
242         unlink(obj);
243         exit(0);
244 }
245
246 int
247 extract (char *file)
248 {
249         int sz;
250         char buf[BUFSIZ];
251         struct exec hdr;
252
253         if (read (0, (char *)&hdr, sizeof(hdr)) != sizeof(hdr))
254                 err(2, "%s", file);
255         if (hdr.a_magic != ZMAGIC)
256                 errx(2, "bad magic in file %s, probably not a kernel", file);
257         if (lseek (0, N_TXTOFF(hdr), 0) < 0)
258                 err(2, "%s", file);
259
260         sz = N_SYMOFF (hdr) - N_TXTOFF (hdr);
261
262         while (sz) {
263                 int l, n;
264
265                 l = sz;
266                 if (l > sizeof(buf))
267                         l = sizeof(buf);
268
269                 n = read (0, buf, l);
270                 if (n != l) {
271                         if (n == -1)
272                                 err(1, "%s", file);
273                         else
274                                 errx(1, "unexpected EOF");
275                 }
276
277                 write (1, buf, l);
278                 sz -= l;
279         }
280         exit(0);
281 }
282
283
284 char string_names[] = {"_input_data\0_input_len\0"};
285
286 struct nlist var_names[2] = {                           /* Symbol table */
287         { { (char*)  4 }, N_EXT|N_TEXT, 0, 0, 0 },      /* _input_data  */
288         { { (char*) 16 }, N_EXT|N_TEXT, 0, 0, 0 },      /* _input_len */
289 };
290
291 int
292 piggyback(char *file)
293 {
294         int n, len;
295         struct exec hdr;                        /* object header */
296         char image[MAXIMAGE];                   /* kernel image buffer */
297
298         len = 0;
299         while ((n = read (0, &image[len], sizeof(image)-len+1)) > 0)
300               len += n;
301
302         if (n < 0)
303                 err(1, "stdin");
304
305         if (len >= sizeof(image))
306                 errx(1, "input too large");
307
308         /*
309          *      Output object header
310          */
311         memset(&hdr,0,sizeof hdr);
312         hdr.a_magic = OMAGIC;
313         hdr.a_text = len + sizeof(long);
314         hdr.a_syms = sizeof(var_names);
315         write (1, (char *)&hdr, sizeof(hdr));
316
317         /*
318          *      Output text segment (compressed system & len)
319          */
320         write (1, image, len);
321         write (1, (char *)&len, sizeof(len));
322
323         /*
324          *      Output symbol table
325          */
326         var_names[1].n_value = len;
327         write (1, (char *)&var_names, sizeof(var_names));
328
329         /*
330          *      Output string table
331          */
332         len = sizeof(string_names) + sizeof(len);
333         write (1, (char *)&len, sizeof(len));
334         write (1, string_names, sizeof(string_names));
335
336         return (0);
337 }