mkboot.c revision 1.21 1 /* $NetBSD: mkboot.c,v 1.21 2025/04/05 19:57:46 tsutsui 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 #if HAVE_NBTOOL_CONFIG_H
35 #include "nbtool_config.h"
36 #endif
37
38 #include <sys/cdefs.h>
39
40 #ifndef lint
41 __COPYRIGHT("@(#) Copyright (c) 1990, 1993\
42 The Regents of the University of California. All rights reserved.");
43 #endif /* not lint */
44
45 #ifndef lint
46 #ifdef notdef
47 static char sccsid[] = "@(#)mkboot.c 7.2 (Berkeley) 12/16/90";
48 #endif
49 __RCSID("$NetBSD: mkboot.c,v 1.21 2025/04/05 19:57:46 tsutsui Exp $");
50 #endif /* not lint */
51
52 #include <sys/param.h>
53 #include <sys/file.h>
54 #include <sys/stat.h>
55 #if HAVE_NBTOOL_CONFIG_H
56 #include "nbtool_config.h"
57 #include "../../sys/sys/bootblock.h"
58 #else
59 #include <sys/bootblock.h>
60 #include <sys/endian.h>
61 #endif
62
63 #include <time.h>
64
65 #include <ctype.h>
66 #include <err.h>
67 #include <stdio.h>
68 #include <stdlib.h>
69 #include <string.h>
70 #include <unistd.h>
71
72 #define bintobcd(bin) ((((bin) / 10) << 4) | ((bin) % 10))
73
74 static uint32_t loadpoint = ULONG_MAX;
75 static struct hp300_load ld;
76 static struct hp300_lifvol lifv;
77 static struct hp300_lifdir lifd[HP300_LIF_NUMDIR];
78 static time_t repro_epoch = 0;
79
80 int main(int, char **);
81
82 static void bcddate(char *, char *);
83 static char *lifname(char *);
84 static size_t putfile(char *, int);
85 static void usage(void);
86
87 #ifndef __CTASSERT
88 #define __CTASSERT(X)
89 #endif
90
91 #define CLEAR(a, b, c) \
92 __CTASSERT(sizeof(b) - 1 == c); \
93 memcpy((a), (b), (c))
94
95 /*
96 * Old Format:
97 * sector 0: LIF volume header (40 bytes)
98 * sector 1: <unused>
99 * sector 2: LIF directory (8 x 32 == 256 bytes)
100 * sector 3-: LIF file 0, LIF file 1, etc.
101 * where sectors are 256 bytes.
102 *
103 * New Format:
104 * sector 0: LIF volume header (40 bytes)
105 * sector 1: <unused>
106 * sector 2: LIF directory (8 x 32 == 256 bytes)
107 * sector 3: <unused>
108 * sector 4-31: disklabel (~300 bytes right now)
109 * sector 32-: LIF file 0, LIF file 1, etc.
110 */
111 int
112 main(int argc, char **argv)
113 {
114 char *name1, *name2, *name3;
115 int to, ch;
116 uint32_t count, nsec;
117
118 while ((ch = getopt(argc, argv, "l:t:")) != -1)
119 switch (ch) {
120 case 'l':
121 loadpoint = strtoul(optarg, NULL, 0);
122 break;
123 case 't':
124 repro_epoch = (time_t)atoll(optarg);
125 break;
126 default:
127 usage();
128 }
129
130 argc -= optind;
131 argv += optind;
132 if (loadpoint == ULONG_MAX || argc == 0)
133 usage();
134 name1 = argv[0];
135 argv++;
136 argc--;
137 if (argc == 0)
138 usage();
139 if (argc > 1) {
140 name2 = argv[0];
141 argv++;
142 argc--;
143 if (argc > 1) {
144 name3 = argv[0];
145 argv++;
146 argc--;
147 } else
148 name3 = NULL;
149 } else
150 name2 = name3 = NULL;
151
152 if ((to = open(argv[0], O_WRONLY | O_TRUNC | O_CREAT, 0644)) == -1)
153 err(1, "Can't open `%s'", argv[0]);
154
155 /* clear possibly unused directory entries */
156 CLEAR(lifd[1].dir_name, " ", sizeof(lifd[1].dir_name));
157 lifd[1].dir_type = htobe16(0xFFFF);
158 lifd[1].dir_addr = htobe32(0);
159 lifd[1].dir_length = htobe32(0);
160 lifd[1].dir_flag = htobe16(0x00FF);
161 lifd[1].dir_exec = htobe32(0);
162 lifd[7] = lifd[6] = lifd[5] = lifd[4] = lifd[3] = lifd[2] = lifd[1];
163
164 /* record volume info */
165 lifv.vol_id = htobe16(HP300_VOL_ID);
166 CLEAR(lifv.vol_label, "BOOT43", sizeof(lifv.vol_label));
167 lifv.vol_addr = htobe32(hp300_btolifs(HP300_LIF_DIRSTART));
168 lifv.vol_oct = htobe16(HP300_VOL_OCT);
169 lifv.vol_dirsize = htobe32(hp300_btolifs(HP300_LIF_DIRSIZE));
170 lifv.vol_version = htobe16(1);
171
172 /* output bootfile one */
173 lseek(to, HP300_LIF_FILESTART, SEEK_SET);
174 count = putfile(name1, to);
175 nsec = hp300_btolifs(count);
176 strcpy(lifd[0].dir_name, lifname(name1));
177 lifd[0].dir_type = htobe16(HP300_DIR_TYPE);
178 lifd[0].dir_addr = htobe32(hp300_btolifs(HP300_LIF_FILESTART));
179 lifd[0].dir_length = htobe32(nsec);
180 bcddate(name1, lifd[0].dir_toc);
181 lifd[0].dir_flag = htobe16(HP300_DIR_FLAG);
182 lifd[0].dir_exec = htobe32(loadpoint);
183 lifv.vol_length = htobe32(be32toh(lifd[0].dir_addr) +
184 be32toh(lifd[0].dir_length));
185
186 /* if there is an optional second boot program, output it */
187 if (name2 != NULL) {
188 lseek(to, HP300_LIF_FILESTART + hp300_lifstob(nsec), SEEK_SET);
189 count = putfile(name2, to);
190 nsec = hp300_btolifs(count);
191 strcpy(lifd[1].dir_name, lifname(name2));
192 lifd[1].dir_type = htobe16(HP300_DIR_TYPE);
193 lifd[1].dir_addr = htobe32(lifv.vol_length);
194 lifd[1].dir_length = htobe32(nsec);
195 bcddate(name2, lifd[1].dir_toc);
196 lifd[1].dir_flag = htobe16(HP300_DIR_FLAG);
197 lifd[1].dir_exec = htobe32(loadpoint);
198 lifv.vol_length = htobe32(be32toh(lifd[1].dir_addr) +
199 be32toh(lifd[1].dir_length));
200 }
201
202 /* ditto for three */
203 if (name3 != NULL) {
204 lseek(to, HP300_LIF_FILESTART + hp300_lifstob(lifd[0].dir_length
205 + nsec), SEEK_SET);
206 count = putfile(name3, to);
207 nsec = hp300_btolifs(count);
208 strcpy(lifd[2].dir_name, lifname(name3));
209 lifd[2].dir_type = htobe16(HP300_DIR_TYPE);
210 lifd[2].dir_addr = htobe32(lifv.vol_length);
211 lifd[2].dir_length = htobe32(nsec);
212 bcddate(name3, lifd[2].dir_toc);
213 lifd[2].dir_flag = htobe16(HP300_DIR_FLAG);
214 lifd[2].dir_exec = htobe32(loadpoint);
215 lifv.vol_length = htobe32(be32toh(lifd[2].dir_addr) +
216 be32toh(lifd[2].dir_length));
217 }
218
219 /* output volume/directory header info */
220 lseek(to, HP300_LIF_VOLSTART, SEEK_SET);
221 write(to, &lifv, HP300_LIF_VOLSIZE);
222 lseek(to, HP300_LIF_DIRSTART, SEEK_SET);
223 write(to, lifd, HP300_LIF_DIRSIZE);
224
225 return EXIT_SUCCESS;
226 }
227
228 static size_t
229 putfile(char *from, int to)
230 {
231 int fd;
232 struct stat statb;
233 void *bp;
234
235 if ((fd = open(from, 0)) < 0)
236 err(EXIT_FAILURE, "Unable to open file `%s'", from);
237 fstat(fd, &statb);
238 ld.address = htobe32(loadpoint);
239 ld.count = htobe32(statb.st_size);
240 if ((bp = malloc(statb.st_size)) == NULL)
241 err(EXIT_FAILURE, "Can't allocate buffer");
242 if (read(fd, bp, statb.st_size) < 0)
243 err(EXIT_FAILURE, "Error reading from file `%s'", from);
244 (void)close(fd);
245 write(to, &ld, sizeof(ld));
246 write(to, bp, statb.st_size);
247 free(bp);
248
249 return statb.st_size + sizeof(ld);
250 }
251
252 static void
253 usage(void)
254 {
255
256 fprintf(stderr, "Usage: %s -l <loadpoint> [-t <timestamp>] prog1 "
257 "[ prog2 ] outfile\n", getprogname());
258 exit(EXIT_FAILURE);
259 }
260
261 static char *
262 lifname(char *str)
263 {
264 static char lname[10] = "SYS_XXXXX";
265 char *cp;
266 int i;
267
268 if ((cp = strrchr(str, '/')) != NULL)
269 str = ++cp;
270 for (i = 4; i < 9; i++) {
271 if (islower((unsigned char)*str))
272 lname[i] = toupper((unsigned char)*str);
273 else if (isalnum((unsigned char)*str) || *str == '_')
274 lname[i] = *str;
275 else
276 break;
277 str++;
278 }
279 for (; i < 10; i++)
280 lname[i] = '\0';
281
282 return lname;
283 }
284
285 static void
286 bcddate(char *name, char *toc)
287 {
288 struct stat statb;
289 struct tm *tm;
290
291 if (repro_epoch != 0)
292 tm = gmtime(&repro_epoch);
293 else {
294 stat(name, &statb);
295 tm = localtime(&statb.st_ctime);
296 }
297 *toc++ = bintobcd(tm->tm_mon + 1);
298 *toc++ = bintobcd(tm->tm_mday);
299 *toc++ = bintobcd(tm->tm_year);
300 *toc++ = bintobcd(tm->tm_hour);
301 *toc++ = bintobcd(tm->tm_min);
302 *toc = bintobcd(tm->tm_sec);
303 }
304