xref: /openbsd/sys/arch/hppa/stand/mkboot/mkboot.c (revision 898184e3)
1 /*	$OpenBSD: mkboot.c,v 1.16 2009/10/27 23:59:34 deraadt Exp $	*/
2 
3 /*
4  * Copyright (c) 1990, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  *
31  *	@(#)mkboot.c	8.1 (Berkeley) 7/15/93
32  */
33 
34 #include <sys/param.h>
35 #include <sys/file.h>
36 #include <sys/stat.h>
37 #include <string.h>
38 #include <stdlib.h>
39 #include <unistd.h>
40 #include <time.h>
41 #ifdef __OpenBSD__
42 #include <err.h>
43 #endif
44 
45 #include <sys/exec_aout.h>
46 #include <sys/exec_elf.h>
47 
48 #ifndef hppa
49 /* hack for cross compile XXX */
50 #include "../../include/disklabel.h"
51 #else
52 #include <sys/disklabel.h>
53 #endif
54 
55 #include <stdio.h>
56 #include <ctype.h>
57 
58 int putfile(char *, int);
59 void __dead usage(void);
60 void bcddate(char *, char *);
61 char *lifname(char *);
62 int cksum(int, int *, int);
63 
64 char *to_file;
65 int loadpoint, verbose;
66 u_long entry;
67 #ifndef __OpenBSD__
68 char *__progname = "mkboot";
69 #endif
70 
71 /*
72  * Old Format:
73  *	sector 0:	LIF volume header (40 bytes)
74  *	sector 1:	<unused>
75  *	sector 2:	LIF directory (8 x 32 == 256 bytes)
76  *	sector 3-:	LIF file 0, LIF file 1, etc.
77  * where sectors are 256 bytes.
78  *
79  * New Format:
80  *	sector 0:	LIF volume header (40 bytes)
81  *	sector 1:	<unused>
82  *	sector 2:	LIF directory (8 x 32 == 256 bytes)
83  *	sector 3:	<unused>
84  *	sector 4-31:	disklabel (~300 bytes right now)
85  *	sector 32-:	LIF file 0, LIF file 1, etc.
86  */
87 int
88 main(int argc, char **argv)
89 {
90 	int to;
91 	register int n, pos, c;
92 	char buf[LIF_FILESTART];
93 	struct lifvol *lifv = (struct lifvol *)buf;
94 	struct lifdir *lifd = (struct lifdir *)(buf + LIF_DIRSTART);
95 
96 	while ((c = getopt(argc, argv, "vl:")) != -1) {
97 		switch (c) {
98 		case 'v':
99 			verbose++;
100 			break;
101 		case 'l':
102 			sscanf(optarg, "0x%x", &loadpoint);
103 			break;
104 		default:
105 			usage();
106 		}
107 	}
108 	if (argc - optind < 2)
109 		usage();
110 	else if (argc - optind > 8)
111 		errx(1, "too many boot programs (max 8 supported)");
112 
113 	to_file = argv[--argc];
114 	if ((to = open(to_file, O_RDWR | O_TRUNC | O_CREAT, 0644)) < 0)
115 		err(1, "%s: open", to_file);
116 
117 	bzero(buf, sizeof(buf));
118 	/* clear possibly unused directory entries */
119 	memset(lifd[1].dir_name, ' ', sizeof lifd[1].dir_name);
120 	lifd[1].dir_type = -1;
121 	lifd[1].dir_addr = 0;
122 	lifd[1].dir_length = 0;
123 	lifd[1].dir_flag = 0xFF;
124 	lifd[1].dir_implement = 0;
125 	lifd[7] = lifd[6] = lifd[5] = lifd[4] = lifd[3] = lifd[2] = lifd[1];
126 
127 	/* record volume info */
128 	lifv->vol_id = htobe16(LIF_VOL_ID);
129 	strncpy(lifv->vol_label, "BOOT44", 6);
130 	lifv->vol_addr = htobe32(btolifs(LIF_DIRSTART));
131 	lifv->vol_oct = htobe16(LIF_VOL_OCT);
132 	lifv->vol_dirsize = htobe32(btolifs(LIF_DIRSIZE));
133 	lifv->vol_version = htobe16(1);
134 	lifv->vol_lastvol = lifv->vol_number =  htobe16(1);
135 	lifv->vol_length = LIF_FILESTART;
136 	bcddate(to_file, lifv->vol_toc);
137 	lifv->ipl_addr = htobe32(LIF_FILESTART);
138 	lifv->ipl_size = 0;
139 	lifv->ipl_entry = 0;
140 
141 	argv += optind;
142 	argc -= optind;
143 	optind = 0;
144 	for (pos = LIF_FILESTART; optind < argc; optind++) {
145 
146 		/* output bootfile */
147 		lseek(to, pos, 0);
148 		lifd[optind].dir_addr = htobe32(btolifs(pos));
149 		n = btolifs(putfile(argv[optind], to));
150 		if (lifv->ipl_entry == 0) {
151 			lifv->ipl_entry = htobe32(loadpoint + entry);
152 			lifv->ipl_size = htobe32(lifstob(n));
153 			lifd[optind].dir_type = htobe16(LIF_DIR_ISL);
154 			lifd[optind].dir_implement = 0;
155 		} else {
156 			lifd[optind].dir_type = htobe16(LIF_DIR_TYPE);
157 			lifd[1].dir_implement = htobe32(loadpoint + entry);
158 		}
159 
160 		strlcpy(lifd[optind].dir_name, lifname(argv[optind]),
161 		    sizeof lifd[optind].dir_name);
162 		lifd[optind].dir_length = htobe32(n);
163 		bcddate(argv[optind], lifd[optind].dir_toc);
164 		lifd[optind].dir_flag = htobe16(LIF_DIR_FLAG);
165 
166 		lifv->vol_length += n;
167 		pos += lifstob(n);
168 	}
169 
170 	lifv->vol_length = htobe32(lifv->vol_length);
171 
172 	/* output volume/directory header info */
173 	lseek(to, LIF_VOLSTART, 0);
174 	if (write(to, buf, sizeof(buf)) != sizeof(buf))
175 		err(1, "%s: write LIF volume", to_file);
176 	lseek(to, 0, SEEK_END);
177 
178 	if (close(to) < 0)
179 		err(1, "%s", to_file);
180 
181 	return(0);
182 }
183 
184 int
185 putfile(from_file, to)
186 	char *from_file;
187 	int to;
188 {
189 	struct exec ex;
190 	register int n, total;
191 	char buf[2048];
192 	int from, check_sum = 0;
193 	struct lif_load load;
194 
195 	if ((from = open(from_file, O_RDONLY)) < 0)
196 		err(1, "%s", from_file);
197 
198 	n = read(from, &ex, sizeof(ex));
199 	if (n != sizeof(ex))
200 		err(1, "%s: reading file header", from_file);
201 
202 	entry = ex.a_entry;
203 	if (N_GETMAGIC(ex) == OMAGIC || N_GETMAGIC(ex) == NMAGIC)
204 		entry += sizeof(ex);
205 	else if (IS_ELF(*(Elf32_Ehdr *)&ex)) {
206 		Elf32_Ehdr elf_header;
207 		Elf32_Phdr *elf_segments;
208 		int i,header_count, memory_needed, elf_load_image_segment;
209 
210 		(void) lseek(from, 0, SEEK_SET);
211 		n = read(from, &elf_header, sizeof (elf_header));
212 		if (n != sizeof (elf_header))
213 			err(1, "%s: reading ELF header", from_file);
214 		header_count = ntohs(elf_header.e_phnum);
215 		memory_needed = header_count * sizeof (*elf_segments);
216 		elf_segments = malloc(memory_needed);
217 		if (elf_segments == NULL)
218 			err(1, "malloc");
219 		(void) lseek(from, ntohl(elf_header.e_phoff), SEEK_SET);
220 		n = read(from, elf_segments, memory_needed);
221 		if (n != memory_needed)
222 			err(1, "%s: reading ELF segments", from_file);
223 		elf_load_image_segment = -1;
224 		for (i = 0; i < header_count; i++) {
225 			if (elf_segments[i].p_filesz &&
226 			    ntohl(elf_segments[i].p_flags) & PF_X) {
227 				if (elf_load_image_segment != -1)
228 					errx(1, "%s: more than one ELF program segment", from_file);
229 				elf_load_image_segment = i;
230 			}
231 			if (elf_load_image_segment == -1)
232 				errx(1, "%s: no suitable ELF program segment", from_file);
233 		}
234 		entry = ntohl(elf_header.e_entry) +
235 			ntohl(elf_segments[elf_load_image_segment].p_offset) -
236 			ntohl(elf_segments[elf_load_image_segment].p_vaddr);
237 	} else if (*(u_char *)&ex == 0x1f && ((u_char *)&ex)[1] == 0x8b) {
238 		entry = 0;
239 	} else
240 		errx(1, "%s: bad magic number", from_file);
241 
242 	entry += sizeof(load);
243 	lseek(to, sizeof(load), SEEK_CUR);
244 	total = 0;
245 	n = sizeof(buf) - sizeof(load);
246 	/* copy the whole file */
247 	for (lseek(from, 0, 0); ; n = sizeof(buf)) {
248 		bzero(buf, sizeof(buf));
249 		if ((n = read(from, buf, n)) < 0)
250 			err(1, "%s", from_file);
251 		else if (n == 0)
252 			break;
253 
254 		if (write(to, buf, n) != n)
255 			err(1, "%s", to_file);
256 
257 		total += n;
258 		check_sum = cksum(check_sum, (int *)buf, n);
259 	}
260 
261 	/* load header */
262 	load.address = htobe32(loadpoint + sizeof(load));
263 	load.count = htobe32(4 + total);
264 	check_sum = cksum(check_sum, (int *)&load, sizeof(load));
265 
266 	if (verbose)
267 		warnx("wrote %d bytes of file \'%s\'", total, from_file);
268 
269 	total += sizeof(load);
270 	/* insert the header */
271 	lseek(to, -total, SEEK_CUR);
272 	if (write(to, &load, sizeof(load)) != sizeof(load))
273 		err(1, "%s", to_file);
274 	lseek(to, total - sizeof(load), SEEK_CUR);
275 
276 	bzero(buf, sizeof(buf));
277 	/* pad to int */
278 	n = sizeof(int) - total % sizeof(int);
279 	if (total % sizeof(int)) {
280 		if (write(to, buf, n) != n)
281 			err(1, "%s", to_file);
282 		else
283 			total += n;
284 	}
285 
286 	/* pad to the blocksize */
287 	n = sizeof(buf) - total % sizeof(buf);
288 
289 	if (n < sizeof(int)) {
290 		n += sizeof(buf);
291 		total += sizeof(buf);
292 	} else
293 		total += n;
294 
295 	/* TODO should pad here to the 65k boundary for tape boot */
296 
297 	if (verbose)
298 		warnx("checksum is 0x%08x", -check_sum);
299 
300 	check_sum = htobe32(-check_sum);
301 	if (write(to, &check_sum, sizeof(int)) != sizeof(int))
302 		err(1, "%s", to_file);
303 
304 	n -= sizeof(int);
305 
306 	if (write(to, buf, n) != n)
307 		err(1, "%s", to_file);
308 
309 	if (close(from) < 0 )
310 		err(1, "%s", from_file);
311 
312 	return total;
313 }
314 
315 int
316 cksum(ck, p, size)
317 	int ck;
318 	int *p;
319 	int size;
320 {
321 	/* we assume size is int-aligned */
322 	for (size = (size + sizeof(int) - 1) / sizeof(int); size--; p++ )
323 		ck += betoh32(*p);
324 
325 	return ck;
326 }
327 
328 void __dead
329 usage()
330 {
331 	extern char *__progname;
332 	fprintf(stderr,
333 		"usage: %s [-v] [-l loadpoint] prog1 {progN} outfile\n",
334 		__progname);
335 	exit(1);
336 }
337 
338 char *
339 lifname(str)
340 	char *str;
341 {
342 	static char lname[10] = "XXXXXXXXXX";
343 	register int i;
344 
345 	for (i = 0; i < 9; i++) {
346 		if (islower(*str))
347 			lname[i] = toupper(*str);
348 		else if (isalnum(*str) || *str == '_')
349 			lname[i] = *str;
350 		else
351 			break;
352 		str++;
353 	}
354 	for ( ; i < 10; i++)
355 		lname[i] = ' ';
356 	return(lname);
357 }
358 
359 
360 void
361 bcddate(file, toc)
362 	char *file;
363 	char *toc;
364 {
365 	struct stat statb;
366 #ifndef __OpenBSD__
367 	struct tm {
368 		int tm_sec;    /* second (0-61, allows for leap seconds) */
369 		int tm_min;    /* minute (0-59) */
370 		int tm_hour;   /* hour (0-23) */
371 		int tm_mday;   /* day of the month (1-31) */
372 		int tm_mon;    /* month (0-11) */
373 		int tm_year;   /* years since 1900 */
374 		int tm_wday;   /* day of the week (0-6) */
375 		int tm_yday;   /* day of the year (0-365) */
376 		int tm_isdst;  /* non-0 if daylight saving time is in effect */
377 	} *tm;
378 #else
379 	struct tm *tm;
380 #endif
381 
382 	stat(file, &statb);
383 	tm = localtime(&statb.st_ctime);
384 	*toc = (tm->tm_year / 10) << 4;
385 	*toc++ |= tm->tm_year % 10;
386 	*toc = ((tm->tm_mon+1) / 10) << 4;
387 	*toc++ |= (tm->tm_mon+1) % 10;
388 	*toc = (tm->tm_mday / 10) << 4;
389 	*toc++ |= tm->tm_mday % 10;
390 	*toc = (tm->tm_hour / 10) << 4;
391 	*toc++ |= tm->tm_hour % 10;
392 	*toc = (tm->tm_min / 10) << 4;
393 	*toc++ |= tm->tm_min % 10;
394 	*toc = (tm->tm_sec / 10) << 4;
395 	*toc |= tm->tm_sec % 10;
396 }
397 
398 #ifndef __OpenBSD__
399 int
400 err(ex, str)
401 	int ex;
402 	char *str;
403 {
404 	perror(str);
405 	exit(ex);
406 }
407 
408 int
409 errx(ex, str)
410 	int ex;
411 	char *str;
412 {
413 	perror(str);
414 	exit(ex);
415 }
416 #endif
417