- Fix comment.
[dragonfly/port-amd64.git] / usr.bin / kzip / kzip.c
blob861a1d1a18324183f532b5d50b4f40583b6e3d67
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 * ----------------------------------------------------------------------------
9 * Copyright (C) 1993 Hannu Savolainen
10 * Ported to 386bsd by Serge Vakulenko
11 * based on tools/build.c by Linus Torvalds
13 * $FreeBSD: src/usr.bin/kzip/kzip.c,v 1.13.2.2 2000/07/20 10:35:20 kris Exp $
14 * $DragonFly: src/usr.bin/kzip/kzip.c,v 1.3 2003/10/04 20:36:47 hmp Exp $
17 #include <err.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <unistd.h>
21 #include <sys/file.h>
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <sys/param.h>
25 #include <sys/wait.h>
26 #include <a.out.h>
27 #include <string.h>
29 #define MAXIMAGE (2*1024*1024)
30 /* This is the limit because a kzip'ed kernel loads at 3Mb and
31 * ends up at 1Mb
33 static void
34 usage(void)
36 fprintf(stderr, "usage: kzip [-v] [ -l loadaddr] kernel\n");
37 exit(1);
40 int
41 main(int argc, char **argv)
43 pid_t Pext, Pgzip, Ppiggy, Pld;
44 int pipe1[2], pipe2[2];
45 int status, fdi, fdo, fdn, c, verbose;
46 int size;
47 struct exec hdr;
48 int zip_size, offset;
49 struct stat st;
50 u_long forceaddr = 0, entry;
51 char *kernname;
52 char obj[MAXPATHLEN + 1];
53 char out[MAXPATHLEN + 1];
54 char base[32];
56 while ((c = getopt(argc, argv, "l:v")) != -1) {
57 switch (c) {
58 case 'l':
59 forceaddr = strtoul(optarg, NULL, 0);
60 if (forceaddr == 0)
61 errx(1, "invalid load address");
62 break;
63 case 'v':
64 verbose++;
65 break;
66 default:
67 usage();
71 if ((argc - optind) != 1)
72 usage();
74 argc -= optind;
75 argv += optind;
77 kernname = argv[0];
79 if (strlen(kernname) > MAXPATHLEN - 3)
80 errx(1, "%s: File name too long", kernname);
81 strcpy(obj, kernname); strcat(obj,".o");
82 strcpy(out, kernname); strcat(out,".kz");
84 fdi = open(kernname ,O_RDONLY);
85 if(fdi<0) {
86 warn("%s", kernname);
87 return 2;
90 /* figure out how big the uncompressed image will be */
91 if (read (fdi, (char *)&hdr, sizeof(hdr)) != sizeof(hdr))
92 err(2, "%s", argv[1]);
94 size = hdr.a_text + hdr.a_data + hdr.a_bss;
95 entry = hdr.a_entry & 0x00FFFFFF;
97 lseek (fdi, 0, SEEK_SET);
99 if (verbose) {
100 printf("real kernel start address will be: 0x%x\n", entry);
101 printf("real kernel end address will be: 0x%x\n", entry+size);
105 fdo = open(obj,O_WRONLY|O_TRUNC|O_CREAT,0666);
106 if(fdo<0) {
107 warn("%s", obj);
108 return 2;
111 if (pipe(pipe1) < 0) { perror("pipe()"); return 1; }
113 if (pipe(pipe2) < 0) { perror("pipe()"); return 1; }
115 Pext = fork();
116 if (Pext < 0) { perror("fork()"); return 1; }
117 if (!Pext) {
118 dup2(fdi,0);
119 dup2(pipe1[1],1);
120 close(pipe1[0]); close(pipe1[1]);
121 close(pipe2[0]); close(pipe2[1]);
122 close(fdi); close(fdo);
123 extract(kernname);
124 exit(0);
127 Pgzip = fork();
128 if (Pgzip < 0) { perror("fork()"); return 1; }
129 if (!Pgzip) {
130 dup2(pipe1[0],0);
131 dup2(pipe2[1],1);
132 close(pipe1[0]); close(pipe1[1]);
133 close(pipe2[0]); close(pipe2[1]);
134 close(fdi); close(fdo);
135 execlp("gzip", "gzip", "-9", "-n", 0);
136 exit (0);
139 Ppiggy = fork();
140 if (Ppiggy < 0) { warn("fork()"); return 1; }
141 if (!Ppiggy) {
142 dup2(pipe2[0],0);
143 dup2(fdo,1);
144 close(pipe1[0]); close(pipe1[1]);
145 close(pipe2[0]); close(pipe2[1]);
146 close(fdi); close(fdo);
147 piggyback(obj);
148 exit(0);
151 close(pipe1[0]); close(pipe1[1]);
152 close(pipe2[0]); close(pipe2[1]);
153 close(fdi); close(fdo);
155 if (waitpid(Pext, &status,0) < 0)
156 { warn("waitpid(Pextract)"); return 1; }
158 if(status) {
159 warnx("extract returned %x",status);
160 return 3;
163 if (waitpid(Pgzip, &status,0) < 0)
164 { perror("waitpid(Pgzip)"); return 1; }
166 if(status) {
167 warnx("gzip returned %x",status);
168 return 3;
171 if (waitpid(Ppiggy, &status,0) < 0)
172 { warn("waitpid(Ppiggy)"); return 1; }
174 if(status) {
175 warnx("piggyback returned %x",status);
176 return 3;
179 if (forceaddr)
180 offset = forceaddr;
181 else {
182 /* a kludge to dynamically figure out where to start it */
183 if (stat (obj, &st) < 0) {
184 warn("cannot get size of compressed data");
185 return 3;
187 zip_size = (int)st.st_size;
188 offset = entry + size - zip_size + 0x8000; /* fudge factor */
190 sprintf(base, "0x%x", roundup(offset, 4096));
192 Pld = fork();
193 if (Pld < 0) { warn("fork()"); return 1; }
194 if (!Pld) {
195 execlp("ld",
196 "ld",
197 "-aout",
198 "-Bstatic",
199 "-Z",
200 "-T",
201 base,
202 "-o",
203 out,
204 "/usr/lib/aout/kzhead.o",
205 obj,
206 "/usr/lib/aout/kztail.o",
208 exit(2);
211 if (waitpid(Pld, &status,0) < 0)
212 { warn("waitpid(Pld)"); return 1; }
214 if(status) {
215 warnx("ld returned %x",status);
216 return 3;
219 if (verbose) {
221 fdn = open(obj ,O_RDONLY);
222 if(fdn<0) {
223 warn("%s", obj);
224 return 3;
227 /* figure out how big the compressed image is */
228 if (read (fdn, (char *)&hdr, sizeof(hdr)) != sizeof(hdr)) {
229 warn("%s", obj);
230 return 3;
232 close(fdn);
234 size = hdr.a_text + hdr.a_data + hdr.a_bss;
236 printf("kzip data start address will be: 0x%x\n",offset);
237 printf("kzip data end address will be: 0x%x\n",offset+size);
240 unlink(obj);
241 exit(0);
245 extract (char *file)
247 int sz;
248 char buf[BUFSIZ];
249 struct exec hdr;
251 if (read (0, (char *)&hdr, sizeof(hdr)) != sizeof(hdr))
252 err(2, "%s", file);
253 if (hdr.a_magic != ZMAGIC)
254 errx(2, "bad magic in file %s, probably not a kernel", file);
255 if (lseek (0, N_TXTOFF(hdr), 0) < 0)
256 err(2, "%s", file);
258 sz = N_SYMOFF (hdr) - N_TXTOFF (hdr);
260 while (sz) {
261 int l, n;
263 l = sz;
264 if (l > sizeof(buf))
265 l = sizeof(buf);
267 n = read (0, buf, l);
268 if (n != l) {
269 if (n == -1)
270 err(1, "%s", file);
271 else
272 errx(1, "unexpected EOF");
275 write (1, buf, l);
276 sz -= l;
278 exit(0);
282 char string_names[] = {"_input_data\0_input_len\0"};
284 struct nlist var_names[2] = { /* Symbol table */
285 { { (char*) 4 }, N_EXT|N_TEXT, 0, 0, 0 }, /* _input_data */
286 { { (char*) 16 }, N_EXT|N_TEXT, 0, 0, 0 }, /* _input_len */
290 piggyback(char *file)
292 int n, len;
293 struct exec hdr; /* object header */
294 char image[MAXIMAGE]; /* kernel image buffer */
296 len = 0;
297 while ((n = read (0, &image[len], sizeof(image)-len+1)) > 0)
298 len += n;
300 if (n < 0)
301 err(1, "stdin");
303 if (len >= sizeof(image))
304 errx(1, "input too large");
307 * Output object header
309 memset(&hdr,0,sizeof hdr);
310 hdr.a_magic = OMAGIC;
311 hdr.a_text = len + sizeof(long);
312 hdr.a_syms = sizeof(var_names);
313 write (1, (char *)&hdr, sizeof(hdr));
316 * Output text segment (compressed system & len)
318 write (1, image, len);
319 write (1, (char *)&len, sizeof(len));
322 * Output symbol table
324 var_names[1].n_value = len;
325 write (1, (char *)&var_names, sizeof(var_names));
328 * Output string table
330 len = sizeof(string_names) + sizeof(len);
331 write (1, (char *)&len, sizeof(len));
332 write (1, string_names, sizeof(string_names));
334 return (0);