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