File: | src/usr.sbin/installboot/i386_installboot.c |
Warning: | line 637, column 10 Assigned value is garbage or undefined |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: i386_installboot.c,v 1.46 2023/06/11 14:00:04 krw Exp $ */ | |||
2 | /* $NetBSD: installboot.c,v 1.5 1995/11/17 23:23:50 gwr Exp $ */ | |||
3 | ||||
4 | /* | |||
5 | * Copyright (c) 2013 Pedro Martelletto | |||
6 | * Copyright (c) 2011 Joel Sing <jsing@openbsd.org> | |||
7 | * Copyright (c) 2003 Tom Cosgrove <tom.cosgrove@arches-consulting.com> | |||
8 | * Copyright (c) 1997 Michael Shalayeff | |||
9 | * Copyright (c) 1994 Paul Kranenburg | |||
10 | * All rights reserved. | |||
11 | * | |||
12 | * Redistribution and use in source and binary forms, with or without | |||
13 | * modification, are permitted provided that the following conditions | |||
14 | * are met: | |||
15 | * 1. Redistributions of source code must retain the above copyright | |||
16 | * notice, this list of conditions and the following disclaimer. | |||
17 | * 2. Redistributions in binary form must reproduce the above copyright | |||
18 | * notice, this list of conditions and the following disclaimer in the | |||
19 | * documentation and/or other materials provided with the distribution. | |||
20 | * 3. All advertising materials mentioning features or use of this software | |||
21 | * must display the following acknowledgement: | |||
22 | * This product includes software developed by Paul Kranenburg. | |||
23 | * 4. The name of the author may not be used to endorse or promote products | |||
24 | * derived from this software without specific prior written permission | |||
25 | * | |||
26 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |||
27 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
28 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |||
29 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |||
30 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |||
31 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |||
32 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |||
33 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
34 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |||
35 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
36 | */ | |||
37 | ||||
38 | #define ELFSIZE32 32 | |||
39 | ||||
40 | #include <sys/param.h> /* DEV_BSIZE */ | |||
41 | #include <sys/disklabel.h> | |||
42 | #include <sys/dkio.h> | |||
43 | #include <sys/ioctl.h> | |||
44 | #include <sys/mount.h> | |||
45 | #include <sys/reboot.h> | |||
46 | #include <sys/stat.h> | |||
47 | #include <sys/sysctl.h> | |||
48 | #include <sys/time.h> | |||
49 | ||||
50 | #include <ufs/ufs/dinode.h> | |||
51 | #include <ufs/ufs/dir.h> | |||
52 | #include <ufs/ffs/fs.h> | |||
53 | ||||
54 | #include <machine/cpu.h> | |||
55 | #include <machine/biosvar.h> | |||
56 | ||||
57 | #include <elf.h> | |||
58 | #include <err.h> | |||
59 | #include <errno(*__errno()).h> | |||
60 | #include <fcntl.h> | |||
61 | #include <nlist.h> | |||
62 | #include <stdlib.h> | |||
63 | #include <stdio.h> | |||
64 | #include <stdint.h> | |||
65 | #include <string.h> | |||
66 | #include <unistd.h> | |||
67 | #include <util.h> | |||
68 | #include <uuid.h> | |||
69 | ||||
70 | #include "installboot.h" | |||
71 | #include "i386_installboot.h" | |||
72 | ||||
73 | char *bootldr; | |||
74 | ||||
75 | char *blkstore; | |||
76 | size_t blksize; | |||
77 | ||||
78 | struct sym_data pbr_symbols[] = { | |||
79 | {"_fs_bsize_p", 2}, | |||
80 | {"_fs_bsize_s", 2}, | |||
81 | {"_fsbtodb", 1}, | |||
82 | {"_p_offset", 4}, | |||
83 | {"_inodeblk", 4}, | |||
84 | {"_inodedbl", 4}, | |||
85 | {"_nblocks", 2}, | |||
86 | {"_blkincr", 1}, | |||
87 | {NULL((void *)0)} | |||
88 | }; | |||
89 | ||||
90 | static void devread(int, void *, daddr_t, size_t, char *); | |||
91 | static u_int findopenbsd(int, struct disklabel *); | |||
92 | static int getbootparams(char *, int, struct disklabel *); | |||
93 | static char *loadproto(char *, long *); | |||
94 | static int gpt_chk_mbr(struct dos_partition *, u_int64_t); | |||
95 | static int sbchk(struct fs *, daddr_t); | |||
96 | static void sbread(int, daddr_t, struct fs **, char *); | |||
97 | ||||
98 | static const daddr_t sbtry[] = SBLOCKSEARCH{ 65536, 8192, 262144, -1 }; | |||
99 | ||||
100 | /* | |||
101 | * Read information about /boot's inode and filesystem parameters, then | |||
102 | * put biosboot (partition boot record) on the target drive with these | |||
103 | * parameters patched in. | |||
104 | */ | |||
105 | ||||
106 | void | |||
107 | md_init(void) | |||
108 | { | |||
109 | stages = 2; | |||
110 | stage1 = "/usr/mdec/biosboot"; | |||
111 | stage2 = "/usr/mdec/boot"; | |||
112 | ||||
113 | bootldr = "/boot"; | |||
114 | } | |||
115 | ||||
116 | void | |||
117 | md_loadboot(void) | |||
118 | { | |||
119 | /* Load prototype boot blocks. */ | |||
120 | if ((blkstore = loadproto(stage1, &blksize)) == NULL((void *)0)) | |||
121 | exit(1); | |||
122 | ||||
123 | /* XXX - Paranoia: Make sure size is aligned! */ | |||
124 | if (blksize & (DEV_BSIZE(1 << 9) - 1)) | |||
125 | errx(1, "proto %s bad size=%ld", stage1, blksize); | |||
126 | ||||
127 | if (blksize > SBSIZE8192 - DEV_BSIZE(1 << 9)) | |||
128 | errx(1, "proto bootblocks too big"); | |||
129 | } | |||
130 | ||||
131 | void | |||
132 | md_prepareboot(int devfd, char *dev) | |||
133 | { | |||
134 | struct disklabel dl; | |||
135 | int part; | |||
136 | ||||
137 | /* Get and check disklabel. */ | |||
138 | if (ioctl(devfd, DIOCGDINFO((unsigned long)0x40000000 | ((sizeof(struct disklabel) & 0x1fff) << 16) | ((('d')) << 8) | ((101))), &dl) == -1) | |||
139 | err(1, "disklabel: %s", dev); | |||
140 | if (dl.d_magic != DISKMAGIC((u_int32_t)0x82564557)) | |||
141 | errx(1, "bad disklabel magic=0x%08x", dl.d_magic); | |||
142 | ||||
143 | /* Warn on unknown disklabel types. */ | |||
144 | if (dl.d_type == 0) | |||
145 | warnx("disklabel type unknown"); | |||
146 | ||||
147 | part = findgptefisys(devfd, &dl); | |||
148 | if (part != -1) { | |||
149 | create_filesystem(&dl, (char)part); | |||
150 | return; | |||
151 | } | |||
152 | } | |||
153 | ||||
154 | void | |||
155 | md_installboot(int devfd, char *dev) | |||
156 | { | |||
157 | struct disklabel dl; | |||
158 | int part; | |||
159 | ||||
160 | /* Get and check disklabel. */ | |||
161 | if (ioctl(devfd, DIOCGDINFO((unsigned long)0x40000000 | ((sizeof(struct disklabel) & 0x1fff) << 16) | ((('d')) << 8) | ((101))), &dl) == -1) | |||
| ||||
162 | err(1, "disklabel: %s", dev); | |||
163 | if (dl.d_magic != DISKMAGIC((u_int32_t)0x82564557)) | |||
164 | errx(1, "bad disklabel magic=0x%08x", dl.d_magic); | |||
165 | ||||
166 | /* Warn on unknown disklabel types. */ | |||
167 | if (dl.d_type == 0) | |||
168 | warnx("disklabel type unknown"); | |||
169 | ||||
170 | part = findgptefisys(devfd, &dl); | |||
171 | if (part != -1) { | |||
172 | write_filesystem(&dl, (char)part); | |||
173 | return; | |||
174 | } | |||
175 | ||||
176 | bootldr = fileprefix(root, bootldr); | |||
177 | if (bootldr == NULL((void *)0)) | |||
178 | exit(1); | |||
179 | if (verbose) | |||
180 | fprintf(stderr(&__sF[2]), "%s %s to %s\n", | |||
181 | (nowrite ? "would copy" : "copying"), stage2, bootldr); | |||
182 | if (!nowrite) | |||
183 | if (filecopy(stage2, bootldr) == -1) | |||
184 | exit(1); | |||
185 | ||||
186 | /* Get bootstrap parameters to patch into proto. */ | |||
187 | if (getbootparams(bootldr, devfd, &dl) != 0) | |||
188 | exit(1); | |||
189 | ||||
190 | /* Write boot blocks to device. */ | |||
191 | write_bootblocks(devfd, dev, &dl); | |||
192 | } | |||
193 | ||||
194 | void | |||
195 | write_bootblocks(int devfd, char *dev, struct disklabel *dl) | |||
196 | { | |||
197 | struct stat sb; | |||
198 | u_int8_t *secbuf; | |||
199 | u_int start; | |||
200 | ||||
201 | /* Write patched proto bootblock(s) into the superblock. */ | |||
202 | if (fstat(devfd, &sb) == -1) | |||
203 | err(1, "fstat: %s", dev); | |||
204 | ||||
205 | if (!S_ISCHR(sb.st_mode)((sb.st_mode & 0170000) == 0020000)) | |||
206 | errx(1, "%s: not a character device", dev); | |||
207 | ||||
208 | /* Patch the parameters into the proto bootstrap sector. */ | |||
209 | pbr_set_symbols(stage1, blkstore, pbr_symbols); | |||
210 | ||||
211 | if (!nowrite) { | |||
212 | /* Sync filesystems (to clean in-memory superblock?). */ | |||
213 | sync(); sleep(1); | |||
214 | } | |||
215 | ||||
216 | /* | |||
217 | * Find bootstrap sector. | |||
218 | */ | |||
219 | start = findopenbsd(devfd, dl); | |||
220 | if (verbose) { | |||
221 | if (start == 0) | |||
222 | fprintf(stderr(&__sF[2]), "no MBR, "); | |||
223 | fprintf(stderr(&__sF[2]), "%s will be written at sector %u\n", | |||
224 | stage1, start); | |||
225 | } | |||
226 | ||||
227 | if (start + (blksize / dl->d_secsize) > BOOTBIOS_MAXSEC((1 << 28) - 1)) | |||
228 | warnx("%s extends beyond sector %u. OpenBSD might not boot.", | |||
229 | stage1, BOOTBIOS_MAXSEC((1 << 28) - 1)); | |||
230 | ||||
231 | if (!nowrite) { | |||
232 | secbuf = calloc(1, dl->d_secsize); | |||
233 | if (pread(devfd, secbuf, dl->d_secsize, (off_t)start * | |||
234 | dl->d_secsize) != dl->d_secsize) | |||
235 | err(1, "pread boot sector"); | |||
236 | bcopy(blkstore, secbuf, blksize); | |||
237 | if (pwrite(devfd, secbuf, dl->d_secsize, (off_t)start * | |||
238 | dl->d_secsize) != dl->d_secsize) | |||
239 | err(1, "pwrite bootstrap"); | |||
240 | free(secbuf); | |||
241 | } | |||
242 | } | |||
243 | ||||
244 | int | |||
245 | create_filesystem(struct disklabel *dl, char part) | |||
246 | { | |||
247 | static const char *newfsfmt = "/sbin/newfs -t msdos %s >/dev/null"; | |||
248 | struct msdosfs_args args; | |||
249 | char cmd[60]; | |||
250 | int rslt; | |||
251 | ||||
252 | /* Newfs <duid>.<part> as msdos filesystem. */ | |||
253 | memset(&args, 0, sizeof(args)); | |||
254 | rslt = asprintf(&args.fspec, | |||
255 | "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx.%c", | |||
256 | dl->d_uid[0], dl->d_uid[1], dl->d_uid[2], dl->d_uid[3], | |||
257 | dl->d_uid[4], dl->d_uid[5], dl->d_uid[6], dl->d_uid[7], | |||
258 | part); | |||
259 | if (rslt == -1) { | |||
260 | warn("bad special device"); | |||
261 | return rslt; | |||
262 | } | |||
263 | ||||
264 | rslt = snprintf(cmd, sizeof(cmd), newfsfmt, args.fspec); | |||
265 | if (rslt >= sizeof(cmd)) { | |||
266 | warnx("can't build newfs command"); | |||
267 | free(args.fspec); | |||
268 | rslt = -1; | |||
269 | return rslt; | |||
270 | } | |||
271 | ||||
272 | if (verbose) | |||
273 | fprintf(stderr(&__sF[2]), "%s %s\n", | |||
274 | (nowrite ? "would newfs" : "newfsing"), args.fspec); | |||
275 | if (!nowrite) { | |||
276 | rslt = system(cmd); | |||
277 | if (rslt == -1) { | |||
278 | warn("system('%s') failed", cmd); | |||
279 | free(args.fspec); | |||
280 | return rslt; | |||
281 | } | |||
282 | } | |||
283 | ||||
284 | free(args.fspec); | |||
285 | return 0; | |||
286 | } | |||
287 | ||||
288 | void | |||
289 | write_filesystem(struct disklabel *dl, char part) | |||
290 | { | |||
291 | static const char *fsckfmt = "/sbin/fsck -t msdos %s >/dev/null"; | |||
292 | struct msdosfs_args args; | |||
293 | char cmd[60]; | |||
294 | char dst[PATH_MAX1024]; | |||
295 | char *src; | |||
296 | size_t mntlen, pathlen, srclen; | |||
297 | int rslt; | |||
298 | ||||
299 | src = NULL((void *)0); | |||
300 | ||||
301 | /* Create directory for temporary mount point. */ | |||
302 | strlcpy(dst, "/tmp/installboot.XXXXXXXXXX", sizeof(dst)); | |||
303 | if (mkdtemp(dst) == NULL((void *)0)) | |||
304 | err(1, "mkdtemp('%s') failed", dst); | |||
305 | mntlen = strlen(dst); | |||
306 | ||||
307 | /* Mount <duid>.<part> as msdos filesystem. */ | |||
308 | memset(&args, 0, sizeof(args)); | |||
309 | rslt = asprintf(&args.fspec, | |||
310 | "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx.%c", | |||
311 | dl->d_uid[0], dl->d_uid[1], dl->d_uid[2], dl->d_uid[3], | |||
312 | dl->d_uid[4], dl->d_uid[5], dl->d_uid[6], dl->d_uid[7], | |||
313 | part); | |||
314 | if (rslt == -1) { | |||
315 | warn("bad special device"); | |||
316 | goto rmdir; | |||
317 | } | |||
318 | ||||
319 | args.export_info.ex_root = -2; /* unchecked anyway on DOS fs */ | |||
320 | args.export_info.ex_flags = 0; | |||
321 | args.flags = MSDOSFSMNT_LONGNAME0x02; | |||
322 | ||||
323 | if (mount(MOUNT_MSDOS"msdos", dst, 0, &args) == -1) { | |||
324 | /* Try fsck'ing it. */ | |||
325 | rslt = snprintf(cmd, sizeof(cmd), fsckfmt, args.fspec); | |||
326 | if (rslt >= sizeof(cmd)) { | |||
327 | warnx("can't build fsck command"); | |||
328 | rslt = -1; | |||
329 | goto rmdir; | |||
330 | } | |||
331 | rslt = system(cmd); | |||
332 | if (rslt == -1) { | |||
333 | warn("system('%s') failed", cmd); | |||
334 | goto rmdir; | |||
335 | } | |||
336 | if (mount(MOUNT_MSDOS"msdos", dst, 0, &args) == -1) { | |||
337 | /* Try newfs'ing it. */ | |||
338 | rslt = create_filesystem(dl, part); | |||
339 | if (rslt == -1) | |||
340 | goto rmdir; | |||
341 | rslt = mount(MOUNT_MSDOS"msdos", dst, 0, &args); | |||
342 | if (rslt == -1) { | |||
343 | warn("unable to mount EFI System partition"); | |||
344 | goto rmdir; | |||
345 | } | |||
346 | } | |||
347 | } | |||
348 | ||||
349 | /* Create "/efi/BOOT" directory in <duid>.<part>. */ | |||
350 | if (strlcat(dst, "/efi", sizeof(dst)) >= sizeof(dst)) { | |||
351 | rslt = -1; | |||
352 | warn("unable to build /efi directory"); | |||
353 | goto umount; | |||
354 | } | |||
355 | rslt = mkdir(dst, 0); | |||
356 | if (rslt == -1 && errno(*__errno()) != EEXIST17) { | |||
357 | warn("mkdir('%s') failed", dst); | |||
358 | goto umount; | |||
359 | } | |||
360 | if (strlcat(dst, "/BOOT", sizeof(dst)) >= sizeof(dst)) { | |||
361 | rslt = -1; | |||
362 | warn("unable to build /BOOT directory"); | |||
363 | goto umount; | |||
364 | } | |||
365 | rslt = mkdir(dst, 0); | |||
366 | if (rslt == -1 && errno(*__errno()) != EEXIST17) { | |||
367 | warn("mkdir('%s') failed", dst); | |||
368 | goto umount; | |||
369 | } | |||
370 | ||||
371 | /* | |||
372 | * Copy BOOTIA32.EFI and BOOTX64.EFI to /efi/BOOT/. | |||
373 | * | |||
374 | * N.B.: BOOTIA32.EFI is longer than BOOTX64.EFI, so src can be reused! | |||
375 | */ | |||
376 | pathlen = strlen(dst); | |||
377 | if (strlcat(dst, "/BOOTIA32.EFI", sizeof(dst)) >= sizeof(dst)) { | |||
378 | rslt = -1; | |||
379 | warn("unable to build /BOOTIA32.EFI path"); | |||
380 | goto umount; | |||
381 | } | |||
382 | src = fileprefix(root, "/usr/mdec/BOOTIA32.EFI"); | |||
383 | if (src == NULL((void *)0)) { | |||
384 | rslt = -1; | |||
385 | goto umount; | |||
386 | } | |||
387 | srclen = strlen(src); | |||
388 | if (verbose) | |||
389 | fprintf(stderr(&__sF[2]), "%s %s to %s\n", | |||
390 | (nowrite ? "would copy" : "copying"), src, dst); | |||
391 | if (!nowrite) { | |||
392 | rslt = filecopy(src, dst); | |||
393 | if (rslt == -1) | |||
394 | goto umount; | |||
395 | } | |||
396 | src[srclen - strlen("/BOOTIA32.EFI")] = '\0'; | |||
397 | ||||
398 | dst[pathlen] = '\0'; | |||
399 | if (strlcat(dst, "/BOOTX64.EFI", sizeof(dst)) >= sizeof(dst)) { | |||
400 | rslt = -1; | |||
401 | warn("unable to build /BOOTX64.EFI dst path"); | |||
402 | goto umount; | |||
403 | } | |||
404 | if (strlcat(src, "/BOOTX64.EFI", srclen+1) >= srclen+1) { | |||
405 | rslt = -1; | |||
406 | warn("unable to build /BOOTX64.EFI src path"); | |||
407 | goto umount; | |||
408 | } | |||
409 | if (verbose) | |||
410 | fprintf(stderr(&__sF[2]), "%s %s to %s\n", | |||
411 | (nowrite ? "would copy" : "copying"), src, dst); | |||
412 | if (!nowrite) { | |||
413 | rslt = filecopy(src, dst); | |||
414 | if (rslt == -1) | |||
415 | goto umount; | |||
416 | } | |||
417 | ||||
418 | rslt = 0; | |||
419 | ||||
420 | umount: | |||
421 | dst[mntlen] = '\0'; | |||
422 | if (unmount(dst, MNT_FORCE0x00080000) == -1) | |||
423 | err(1, "unmount('%s') failed", dst); | |||
424 | ||||
425 | rmdir: | |||
426 | free(args.fspec); | |||
427 | dst[mntlen] = '\0'; | |||
428 | if (rmdir(dst) == -1) | |||
429 | err(1, "rmdir('%s') failed", dst); | |||
430 | ||||
431 | free(src); | |||
432 | ||||
433 | if (rslt == -1) | |||
434 | exit(1); | |||
435 | } | |||
436 | ||||
437 | /* | |||
438 | * a) For media w/o an MBR use sector 0. | |||
439 | * b) For media with an MBR and an OpenBSD (A6) partition use the first | |||
440 | * sector of the OpenBSD partition. | |||
441 | * c) For media with an MBR and no OpenBSD partition error out. | |||
442 | */ | |||
443 | u_int | |||
444 | findopenbsd(int devfd, struct disklabel *dl) | |||
445 | { | |||
446 | struct dos_mbr mbr; | |||
447 | u_int mbroff = DOSBBSECTOR0; | |||
448 | u_int mbr_eoff = DOSBBSECTOR0; /* Offset of extended part. */ | |||
449 | struct dos_partition *dp; | |||
450 | u_int8_t *secbuf; | |||
451 | u_int maxebr = DOS_MAXEBR256, nextebr; | |||
452 | int i; | |||
453 | ||||
454 | again: | |||
455 | if (!maxebr--) { | |||
456 | if (verbose) | |||
457 | fprintf(stderr(&__sF[2]), "Traversed more than %d Extended Boot " | |||
458 | "Records (EBRs)\n", DOS_MAXEBR256); | |||
459 | goto done; | |||
460 | } | |||
461 | ||||
462 | if (verbose) | |||
463 | fprintf(stderr(&__sF[2]), "%s boot record (%cBR) at sector %u\n", | |||
464 | (mbroff == DOSBBSECTOR0) ? "master" : "extended", | |||
465 | (mbroff == DOSBBSECTOR0) ? 'M' : 'E', mbroff); | |||
466 | ||||
467 | if ((secbuf = malloc(dl->d_secsize)) == NULL((void *)0)) | |||
468 | err(1, NULL((void *)0)); | |||
469 | if (pread(devfd, secbuf, dl->d_secsize, (off_t)mbroff * dl->d_secsize) | |||
470 | < (ssize_t)sizeof(mbr)) | |||
471 | err(4, "can't pread boot record"); | |||
472 | bcopy(secbuf, &mbr, sizeof(mbr)); | |||
473 | free(secbuf); | |||
474 | ||||
475 | if (mbr.dmbr_sign != DOSMBR_SIGNATURE(0xaa55)) { | |||
476 | if (mbroff == DOSBBSECTOR0) | |||
477 | return 0; | |||
478 | errx(1, "invalid boot record signature (0x%04X) @ sector %u", | |||
479 | mbr.dmbr_sign, mbroff); | |||
480 | } | |||
481 | ||||
482 | nextebr = 0; | |||
483 | for (i = 0; i < NDOSPART4; i++) { | |||
484 | dp = &mbr.dmbr_parts[i]; | |||
485 | if (!dp->dp_size) | |||
486 | continue; | |||
487 | ||||
488 | if (verbose) | |||
489 | fprintf(stderr(&__sF[2]), | |||
490 | "\tpartition %d: type 0x%02X offset %u size %u\n", | |||
491 | i, dp->dp_typ, dp->dp_start, dp->dp_size); | |||
492 | ||||
493 | if (dp->dp_typ == DOSPTYP_OPENBSD0xa6) { | |||
494 | if (dp->dp_start > (dp->dp_start + mbroff)) | |||
495 | continue; | |||
496 | return (dp->dp_start + mbroff); | |||
497 | } | |||
498 | ||||
499 | if (!nextebr && (dp->dp_typ == DOSPTYP_EXTEND0x05 || | |||
500 | dp->dp_typ == DOSPTYP_EXTENDL0x0f)) { | |||
501 | nextebr = dp->dp_start + mbr_eoff; | |||
502 | if (nextebr < dp->dp_start) | |||
503 | nextebr = (u_int)-1; | |||
504 | if (mbr_eoff == DOSBBSECTOR0) | |||
505 | mbr_eoff = dp->dp_start; | |||
506 | } | |||
507 | } | |||
508 | ||||
509 | if (nextebr && nextebr != (u_int)-1) { | |||
510 | mbroff = nextebr; | |||
511 | goto again; | |||
512 | } | |||
513 | ||||
514 | done: | |||
515 | errx(1, "no OpenBSD partition"); | |||
516 | } | |||
517 | ||||
518 | /* | |||
519 | * Returns 0 if the MBR with the provided partition array is a GPT protective | |||
520 | * MBR, and returns 1 otherwise. A GPT protective MBR would have one and only | |||
521 | * one MBR partition, an EFI partition that either covers the whole disk or as | |||
522 | * much of it as is possible with a 32bit size field. | |||
523 | * | |||
524 | * NOTE: MS always uses a size of UINT32_MAX for the EFI partition!** | |||
525 | */ | |||
526 | static int | |||
527 | gpt_chk_mbr(struct dos_partition *dp, u_int64_t dsize) | |||
528 | { | |||
529 | struct dos_partition *dp2; | |||
530 | int efi, found, i; | |||
531 | u_int32_t psize; | |||
532 | ||||
533 | found = efi = 0; | |||
534 | for (dp2=dp, i=0; i < NDOSPART4; i++, dp2++) { | |||
535 | if (dp2->dp_typ == DOSPTYP_UNUSED0x00) | |||
536 | continue; | |||
537 | found++; | |||
538 | if (dp2->dp_typ != DOSPTYP_EFI0xee) | |||
539 | continue; | |||
540 | if (letoh32(dp2->dp_start)((__uint32_t)(dp2->dp_start)) != GPTSECTOR1) | |||
541 | continue; | |||
542 | psize = letoh32(dp2->dp_size)((__uint32_t)(dp2->dp_size)); | |||
543 | if (psize <= (dsize - GPTSECTOR1) || psize == UINT32_MAX0xffffffffU) | |||
544 | efi++; | |||
545 | } | |||
546 | if (found == 1 && efi == 1) | |||
547 | return (0); | |||
548 | ||||
549 | return (1); | |||
550 | } | |||
551 | ||||
552 | int | |||
553 | findgptefisys(int devfd, struct disklabel *dl) | |||
554 | { | |||
555 | struct gpt_partition gp[NGPTPARTITIONS128]; | |||
556 | struct gpt_header gh; | |||
557 | struct dos_partition dp[NDOSPART4]; | |||
558 | struct uuid efisys_uuid; | |||
559 | const char efisys_uuid_code[] = GPT_UUID_EFI_SYSTEM{ 0xc1, 0x2a, 0x73, 0x28, 0xf8, 0x1f, 0x11, 0xd2, 0xba, 0x4b, 0x00, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b }; | |||
560 | off_t off; | |||
561 | ssize_t len; | |||
562 | u_int64_t start; | |||
563 | int i; | |||
564 | uint32_t orig_csum, new_csum; | |||
565 | uint32_t ghsize, ghpartsize, ghpartnum, ghpartspersec; | |||
566 | u_int8_t *secbuf; | |||
567 | ||||
568 | /* Prepare EFI System UUID */ | |||
569 | uuid_dec_be(efisys_uuid_code, &efisys_uuid); | |||
570 | ||||
571 | if ((secbuf = malloc(dl->d_secsize)) == NULL((void *)0)) | |||
572 | err(1, NULL((void *)0)); | |||
573 | ||||
574 | /* Check that there is a protective MBR. */ | |||
575 | len = pread(devfd, secbuf, dl->d_secsize, 0); | |||
576 | if (len != dl->d_secsize) | |||
577 | err(4, "can't read mbr"); | |||
578 | memcpy(dp, &secbuf[DOSPARTOFF446], sizeof(dp)); | |||
579 | if (gpt_chk_mbr(dp, DL_GETDSIZE(dl)(((u_int64_t)(dl)->d_secperunith << 32) + (dl)->d_secperunit ))) { | |||
580 | free(secbuf); | |||
581 | return (-1); | |||
582 | } | |||
583 | ||||
584 | /* Check GPT Header. */ | |||
585 | off = dl->d_secsize; /* Read header from sector 1. */ | |||
586 | len = pread(devfd, secbuf, dl->d_secsize, off); | |||
587 | if (len != dl->d_secsize) | |||
588 | err(4, "can't pread gpt header"); | |||
589 | ||||
590 | memcpy(&gh, secbuf, sizeof(gh)); | |||
591 | free(secbuf); | |||
592 | ||||
593 | /* Check signature */ | |||
594 | if (letoh64(gh.gh_sig)((__uint64_t)(gh.gh_sig)) != GPTSIGNATURE0x5452415020494645LL) | |||
595 | return (-1); | |||
596 | ||||
597 | if (letoh32(gh.gh_rev)((__uint32_t)(gh.gh_rev)) != GPTREVISION0x10000) | |||
598 | return (-1); | |||
599 | ||||
600 | ghsize = letoh32(gh.gh_size)((__uint32_t)(gh.gh_size)); | |||
601 | if (ghsize < GPTMINHDRSIZE92 || ghsize > sizeof(struct gpt_header)) | |||
602 | return (-1); | |||
603 | ||||
604 | /* Check checksum */ | |||
605 | orig_csum = gh.gh_csum; | |||
606 | gh.gh_csum = 0; | |||
607 | new_csum = crc32((unsigned char *)&gh, ghsize); | |||
608 | gh.gh_csum = orig_csum; | |||
609 | if (letoh32(orig_csum)((__uint32_t)(orig_csum)) != new_csum) | |||
610 | return (-1); | |||
611 | ||||
612 | off = letoh64(gh.gh_part_lba)((__uint64_t)(gh.gh_part_lba)) * dl->d_secsize; | |||
613 | ghpartsize = letoh32(gh.gh_part_size)((__uint32_t)(gh.gh_part_size)); | |||
614 | ghpartspersec = dl->d_secsize / ghpartsize; | |||
615 | ghpartnum = letoh32(gh.gh_part_num)((__uint32_t)(gh.gh_part_num)); | |||
616 | if ((secbuf = malloc(dl->d_secsize)) == NULL((void *)0)) | |||
617 | err(1, NULL((void *)0)); | |||
618 | for (i = 0; i < (ghpartnum + ghpartspersec - 1) / ghpartspersec; i++) { | |||
619 | len = pread(devfd, secbuf, dl->d_secsize, off); | |||
620 | if (len != dl->d_secsize) { | |||
621 | free(secbuf); | |||
622 | return (-1); | |||
623 | } | |||
624 | memcpy(gp + i * ghpartspersec, secbuf, | |||
625 | ghpartspersec * sizeof(struct gpt_partition)); | |||
626 | off += dl->d_secsize; | |||
627 | } | |||
628 | free(secbuf); | |||
629 | new_csum = crc32((unsigned char *)&gp, ghpartnum * ghpartsize); | |||
630 | if (new_csum != letoh32(gh.gh_part_csum)((__uint32_t)(gh.gh_part_csum))) | |||
631 | return (-1); | |||
632 | ||||
633 | start = 0; | |||
634 | for (i = 0; i < ghpartnum && start == 0; i++) { | |||
635 | if (memcmp(&gp[i].gp_type, &efisys_uuid, | |||
636 | sizeof(struct uuid)) == 0) | |||
637 | start = letoh64(gp[i].gp_lba_start)((__uint64_t)(gp[i].gp_lba_start)); | |||
| ||||
638 | } | |||
639 | ||||
640 | if (start) { | |||
641 | for (i = 0; i < MAXPARTITIONS16; i++) { | |||
642 | if (DL_GETPSIZE(&dl->d_partitions[i])(((u_int64_t)(&dl->d_partitions[i])->p_sizeh << 32) + (&dl->d_partitions[i])->p_size) > 0 && | |||
643 | DL_GETPOFFSET(&dl->d_partitions[i])(((u_int64_t)(&dl->d_partitions[i])->p_offseth << 32) + (&dl->d_partitions[i])->p_offset) == start) | |||
644 | return ('a' + i); | |||
645 | } | |||
646 | } | |||
647 | ||||
648 | return (-1); | |||
649 | } | |||
650 | ||||
651 | /* | |||
652 | * Load the prototype boot sector (biosboot) into memory. | |||
653 | */ | |||
654 | static char * | |||
655 | loadproto(char *fname, long *size) | |||
656 | { | |||
657 | int fd; | |||
658 | size_t tdsize; /* text+data size */ | |||
659 | char *bp; | |||
660 | Elf_EhdrElf32_Ehdr eh; | |||
661 | Elf_WordElf32_Word phsize; | |||
662 | Elf_PhdrElf32_Phdr *ph; | |||
663 | ||||
664 | if ((fd = open(fname, O_RDONLY0x0000)) == -1) | |||
665 | err(1, "%s", fname); | |||
666 | ||||
667 | if (read(fd, &eh, sizeof(eh)) != sizeof(eh)) | |||
668 | errx(1, "%s: read failed", fname); | |||
669 | ||||
670 | if (!IS_ELF(eh)((eh).e_ident[0] == 0x7f && (eh).e_ident[1] == 'E' && (eh).e_ident[2] == 'L' && (eh).e_ident[3] == 'F')) | |||
671 | errx(1, "%s: bad magic: 0x%02x%02x%02x%02x", fname, | |||
672 | eh.e_ident[EI_MAG00], eh.e_ident[EI_MAG11], | |||
673 | eh.e_ident[EI_MAG22], eh.e_ident[EI_MAG33]); | |||
674 | ||||
675 | /* | |||
676 | * We have to include the exec header in the beginning of | |||
677 | * the buffer, and leave extra space at the end in case | |||
678 | * the actual write to disk wants to skip the header. | |||
679 | */ | |||
680 | ||||
681 | /* Program load header. */ | |||
682 | if (eh.e_phnum != 1) | |||
683 | errx(1, "%s: %u ELF load sections (only support 1)", | |||
684 | fname, eh.e_phnum); | |||
685 | ||||
686 | ph = reallocarray(NULL((void *)0), eh.e_phnum, sizeof(Elf_PhdrElf32_Phdr)); | |||
687 | if (ph == NULL((void *)0)) | |||
688 | err(1, NULL((void *)0)); | |||
689 | phsize = eh.e_phnum * sizeof(Elf_PhdrElf32_Phdr); | |||
690 | ||||
691 | if (pread(fd, ph, phsize, eh.e_phoff) != phsize) | |||
692 | errx(1, "%s: can't pread header", fname); | |||
693 | ||||
694 | tdsize = ph->p_filesz; | |||
695 | ||||
696 | /* | |||
697 | * Allocate extra space here because the caller may copy | |||
698 | * the boot block starting at the end of the exec header. | |||
699 | * This prevents reading beyond the end of the buffer. | |||
700 | */ | |||
701 | if ((bp = calloc(tdsize, 1)) == NULL((void *)0)) | |||
702 | err(1, NULL((void *)0)); | |||
703 | ||||
704 | /* Read the rest of the file. */ | |||
705 | if (pread(fd, bp, tdsize, ph->p_offset) != (ssize_t)tdsize) | |||
706 | errx(1, "%s: pread failed", fname); | |||
707 | ||||
708 | *size = tdsize; /* not aligned to DEV_BSIZE */ | |||
709 | ||||
710 | close(fd); | |||
711 | return bp; | |||
712 | } | |||
713 | ||||
714 | static void | |||
715 | devread(int fd, void *buf, daddr_t blk, size_t size, char *msg) | |||
716 | { | |||
717 | if (pread(fd, buf, size, dbtob((off_t)blk)(((off_t)blk) << 9)) != (ssize_t)size) | |||
718 | err(1, "%s: devread: pread", msg); | |||
719 | } | |||
720 | ||||
721 | /* | |||
722 | * Read information about /boot's inode, then put this and filesystem | |||
723 | * parameters from the superblock into pbr_symbols. | |||
724 | */ | |||
725 | static int | |||
726 | getbootparams(char *boot, int devfd, struct disklabel *dl) | |||
727 | { | |||
728 | int fd; | |||
729 | struct stat dsb, fsb; | |||
730 | struct statfs fssb; | |||
731 | struct partition *pp; | |||
732 | struct fs *fs; | |||
733 | char *sblock, *buf; | |||
734 | u_int blk, *ap; | |||
735 | int ndb; | |||
736 | int mib[3]; | |||
737 | size_t size; | |||
738 | dev_t dev; | |||
739 | int incr; | |||
740 | ||||
741 | /* | |||
742 | * Open 2nd-level boot program and record enough details about | |||
743 | * where it is on the filesystem represented by `devfd' | |||
744 | * (inode block, offset within that block, and various filesystem | |||
745 | * parameters essentially taken from the superblock) for biosboot | |||
746 | * to be able to load it later. | |||
747 | */ | |||
748 | ||||
749 | /* Make sure the (probably new) boot file is on disk. */ | |||
750 | sync(); sleep(1); | |||
751 | ||||
752 | if ((fd = open(boot, O_RDONLY0x0000)) == -1) | |||
753 | err(1, "open: %s", boot); | |||
754 | ||||
755 | if (fstatfs(fd, &fssb) == -1) | |||
756 | err(1, "statfs: %s", boot); | |||
757 | ||||
758 | if (strncmp(fssb.f_fstypename, "ffs", MFSNAMELEN16) && | |||
759 | strncmp(fssb.f_fstypename, "ufs", MFSNAMELEN16) ) | |||
760 | errx(1, "%s: not on an FFS filesystem", boot); | |||
761 | ||||
762 | #if 0 | |||
763 | if (read(fd, &eh, sizeof(eh)) != sizeof(eh)) | |||
764 | errx(1, "read: %s", boot); | |||
765 | ||||
766 | if (!IS_ELF(eh)((eh).e_ident[0] == 0x7f && (eh).e_ident[1] == 'E' && (eh).e_ident[2] == 'L' && (eh).e_ident[3] == 'F')) { | |||
767 | errx(1, "%s: bad magic: 0x%02x%02x%02x%02x", | |||
768 | boot, | |||
769 | eh.e_ident[EI_MAG00], eh.e_ident[EI_MAG11], | |||
770 | eh.e_ident[EI_MAG22], eh.e_ident[EI_MAG33]); | |||
771 | } | |||
772 | #endif | |||
773 | ||||
774 | if (fsync(fd) != 0) | |||
775 | err(1, "fsync: %s", boot); | |||
776 | ||||
777 | if (fstat(fd, &fsb) != 0) | |||
778 | err(1, "fstat: %s", boot); | |||
779 | ||||
780 | if (fstat(devfd, &dsb) != 0) | |||
781 | err(1, "fstat: %d", devfd); | |||
782 | ||||
783 | /* Check devices. */ | |||
784 | mib[0] = CTL_MACHDEP7; | |||
785 | mib[1] = CPU_CHR2BLK4; | |||
786 | mib[2] = dsb.st_rdev; | |||
787 | size = sizeof(dev); | |||
788 | if (sysctl(mib, 3, &dev, &size, NULL((void *)0), 0) >= 0) { | |||
789 | if (fsb.st_dev / MAXPARTITIONS16 != dev / MAXPARTITIONS16) | |||
790 | errx(1, "cross-device install"); | |||
791 | } | |||
792 | ||||
793 | pp = &dl->d_partitions[DISKPART(fsb.st_dev)(((unsigned)((fsb.st_dev) & 0xff) | (((fsb.st_dev) & 0xffff0000 ) >> 8)) % 16)]; | |||
794 | close(fd); | |||
795 | ||||
796 | if ((sblock = malloc(SBSIZE8192)) == NULL((void *)0)) | |||
797 | err(1, NULL((void *)0)); | |||
798 | ||||
799 | sbread(devfd, DL_SECTOBLK(dl, pp->p_offset)((pp->p_offset) * ((dl)->d_secsize / (1 << 9))), &fs, sblock); | |||
800 | ||||
801 | /* Read inode. */ | |||
802 | if ((buf = malloc(fs->fs_bsize)) == NULL((void *)0)) | |||
803 | err(1, NULL((void *)0)); | |||
804 | ||||
805 | blk = fsbtodb(fs, ino_to_fsba(fs, fsb.st_ino))((((daddr_t)(((((daddr_t)(fs)->fs_fpg * (((fsb.st_ino) / ( fs)->fs_ipg))) + (fs)->fs_cgoffset * ((((fsb.st_ino) / ( fs)->fs_ipg)) & ~((fs)->fs_cgmask))) + (fs)->fs_iblkno ) + ((((((fsb.st_ino) % (fs)->fs_ipg) / ((fs)->fs_inopb ))) << ((fs))->fs_fragshift))))) << (fs)->fs_fsbtodb ); | |||
806 | ||||
807 | /* | |||
808 | * Have the inode. Figure out how many filesystem blocks (not disk | |||
809 | * sectors) there are for biosboot to load. | |||
810 | */ | |||
811 | devread(devfd, buf, DL_SECTOBLK(dl, pp->p_offset)((pp->p_offset) * ((dl)->d_secsize / (1 << 9))) + blk, | |||
812 | fs->fs_bsize, "inode"); | |||
813 | if (fs->fs_magic == FS_UFS2_MAGIC0x19540119) { | |||
814 | struct ufs2_dinode *ip2 = (struct ufs2_dinode *)(buf) + | |||
815 | ino_to_fsbo(fs, fsb.st_ino)((fsb.st_ino) % ((fs)->fs_inopb)); | |||
816 | ndb = howmany(ip2->di_size, fs->fs_bsize)(((ip2->di_size) + ((fs->fs_bsize) - 1)) / (fs->fs_bsize )); | |||
817 | ap = (u_int *)ip2->di_db; | |||
818 | incr = sizeof(u_int32_t); | |||
819 | } else { | |||
820 | struct ufs1_dinode *ip1 = (struct ufs1_dinode *)(buf) + | |||
821 | ino_to_fsbo(fs, fsb.st_ino)((fsb.st_ino) % ((fs)->fs_inopb)); | |||
822 | ndb = howmany(ip1->di_size, fs->fs_bsize)(((ip1->di_size) + ((fs->fs_bsize) - 1)) / (fs->fs_bsize )); | |||
823 | ap = (u_int *)ip1->di_db; | |||
824 | incr = 0; | |||
825 | } | |||
826 | ||||
827 | if (ndb <= 0) | |||
828 | errx(1, "No blocks to load"); | |||
829 | ||||
830 | /* | |||
831 | * Now set the values that will need to go into biosboot | |||
832 | * (the partition boot record, a.k.a. the PBR). | |||
833 | */ | |||
834 | sym_set_value(pbr_symbols, "_fs_bsize_p", (fs->fs_bsize / 16)); | |||
835 | sym_set_value(pbr_symbols, "_fs_bsize_s", (fs->fs_bsize / | |||
836 | dl->d_secsize)); | |||
837 | ||||
838 | /* | |||
839 | * fs_fsbtodb is the shift to convert fs_fsize to DEV_BSIZE. The | |||
840 | * ino_to_fsba() return value is the number of fs_fsize units. | |||
841 | * Calculate the shift to convert fs_fsize into physical sectors, | |||
842 | * which are added to p_offset to get the sector address BIOS | |||
843 | * will use. | |||
844 | * | |||
845 | * N.B.: ASSUMES fs_fsize is a power of 2 of d_secsize. | |||
846 | */ | |||
847 | sym_set_value(pbr_symbols, "_fsbtodb", | |||
848 | ffs(fs->fs_fsize / dl->d_secsize) - 1); | |||
849 | ||||
850 | sym_set_value(pbr_symbols, "_p_offset", pp->p_offset); | |||
851 | sym_set_value(pbr_symbols, "_inodeblk", | |||
852 | ino_to_fsba(fs, fsb.st_ino)((daddr_t)(((((daddr_t)(fs)->fs_fpg * (((fsb.st_ino) / (fs )->fs_ipg))) + (fs)->fs_cgoffset * ((((fsb.st_ino) / (fs )->fs_ipg)) & ~((fs)->fs_cgmask))) + (fs)->fs_iblkno ) + ((((((fsb.st_ino) % (fs)->fs_ipg) / ((fs)->fs_inopb ))) << ((fs))->fs_fragshift))))); | |||
853 | sym_set_value(pbr_symbols, "_inodedbl", | |||
854 | ((((char *)ap) - buf) + INODEOFF((0x07e0 -0x07c0) << 4))); | |||
855 | sym_set_value(pbr_symbols, "_nblocks", ndb); | |||
856 | sym_set_value(pbr_symbols, "_blkincr", incr); | |||
857 | ||||
858 | if (verbose) { | |||
859 | fprintf(stderr(&__sF[2]), "%s is %d blocks x %d bytes\n", | |||
860 | boot, ndb, fs->fs_bsize); | |||
861 | fprintf(stderr(&__sF[2]), "fs block shift %u; part offset %u; " | |||
862 | "inode block %lld, offset %u\n", | |||
863 | ffs(fs->fs_fsize / dl->d_secsize) - 1, | |||
864 | pp->p_offset, | |||
865 | ino_to_fsba(fs, fsb.st_ino)((daddr_t)(((((daddr_t)(fs)->fs_fpg * (((fsb.st_ino) / (fs )->fs_ipg))) + (fs)->fs_cgoffset * ((((fsb.st_ino) / (fs )->fs_ipg)) & ~((fs)->fs_cgmask))) + (fs)->fs_iblkno ) + ((((((fsb.st_ino) % (fs)->fs_ipg) / ((fs)->fs_inopb ))) << ((fs))->fs_fragshift)))), | |||
866 | (unsigned int)((((char *)ap) - buf) + INODEOFF((0x07e0 -0x07c0) << 4))); | |||
867 | fprintf(stderr(&__sF[2]), "expecting %d-bit fs blocks (incr %d)\n", | |||
868 | incr ? 64 : 32, incr); | |||
869 | } | |||
870 | ||||
871 | free (sblock); | |||
872 | free (buf); | |||
873 | ||||
874 | return 0; | |||
875 | } | |||
876 | ||||
877 | void | |||
878 | sym_set_value(struct sym_data *sym_list, char *sym, u_int32_t value) | |||
879 | { | |||
880 | struct sym_data *p; | |||
881 | ||||
882 | for (p = sym_list; p->sym_name != NULL((void *)0); p++) { | |||
883 | if (strcmp(p->sym_name, sym) == 0) | |||
884 | break; | |||
885 | } | |||
886 | ||||
887 | if (p->sym_name == NULL((void *)0)) | |||
888 | errx(1, "%s: no such symbol", sym); | |||
889 | ||||
890 | p->sym_value = value; | |||
891 | p->sym_set = 1; | |||
892 | } | |||
893 | ||||
894 | /* | |||
895 | * Write the parameters stored in sym_list into the in-memory copy of | |||
896 | * the prototype biosboot (proto), ready for it to be written to disk. | |||
897 | */ | |||
898 | void | |||
899 | pbr_set_symbols(char *fname, char *proto, struct sym_data *sym_list) | |||
900 | { | |||
901 | struct sym_data *sym; | |||
902 | struct nlist *nl; | |||
903 | char *vp; | |||
904 | u_int32_t *lp; | |||
905 | u_int16_t *wp; | |||
906 | u_int8_t *bp; | |||
907 | ||||
908 | for (sym = sym_list; sym->sym_name != NULL((void *)0); sym++) { | |||
909 | if (!sym->sym_set) | |||
910 | errx(1, "%s not set", sym->sym_name); | |||
911 | ||||
912 | /* Allocate space for 2; second is null-terminator for list. */ | |||
913 | nl = calloc(2, sizeof(struct nlist)); | |||
914 | if (nl == NULL((void *)0)) | |||
915 | err(1, NULL((void *)0)); | |||
916 | ||||
917 | nl->n_name = sym->sym_name; | |||
918 | ||||
919 | if (nlist_elf32(fname, nl) != 0) | |||
920 | errx(1, "%s: symbol %s not found", | |||
921 | fname, sym->sym_name); | |||
922 | ||||
923 | if (nl->n_type != (N_TEXT0x04)) | |||
924 | errx(1, "%s: %s: wrong type (%x)", | |||
925 | fname, sym->sym_name, nl->n_type); | |||
926 | ||||
927 | /* Get a pointer to where the symbol's value needs to go. */ | |||
928 | vp = proto + nl->n_value; | |||
929 | ||||
930 | switch (sym->sym_size) { | |||
931 | case 4: /* u_int32_t */ | |||
932 | lp = (u_int32_t *) vp; | |||
933 | *lp = sym->sym_value; | |||
934 | break; | |||
935 | case 2: /* u_int16_t */ | |||
936 | if (sym->sym_value >= 0x10000) /* out of range */ | |||
937 | errx(1, "%s: symbol out of range (%u)", | |||
938 | sym->sym_name, sym->sym_value); | |||
939 | wp = (u_int16_t *) vp; | |||
940 | *wp = (u_int16_t) sym->sym_value; | |||
941 | break; | |||
942 | case 1: /* u_int16_t */ | |||
943 | if (sym->sym_value >= 0x100) /* out of range */ | |||
944 | errx(1, "%s: symbol out of range (%u)", | |||
945 | sym->sym_name, sym->sym_value); | |||
946 | bp = (u_int8_t *) vp; | |||
947 | *bp = (u_int8_t) sym->sym_value; | |||
948 | break; | |||
949 | default: | |||
950 | errx(1, "%s: bad symbol size %d", | |||
951 | sym->sym_name, sym->sym_size); | |||
952 | /* NOTREACHED */ | |||
953 | } | |||
954 | ||||
955 | free(nl); | |||
956 | } | |||
957 | } | |||
958 | ||||
959 | static int | |||
960 | sbchk(struct fs *fs, daddr_t sbloc) | |||
961 | { | |||
962 | if (verbose) | |||
963 | fprintf(stderr(&__sF[2]), "looking for superblock at %lld\n", sbloc); | |||
964 | ||||
965 | if (fs->fs_magic != FS_UFS2_MAGIC0x19540119 && fs->fs_magic != FS_UFS1_MAGIC0x011954) { | |||
966 | if (verbose) | |||
967 | fprintf(stderr(&__sF[2]), "bad superblock magic 0x%x\n", | |||
968 | fs->fs_magic); | |||
969 | return (0); | |||
970 | } | |||
971 | ||||
972 | /* | |||
973 | * Looking for an FFS1 file system at SBLOCK_UFS2 will find the | |||
974 | * wrong superblock for file systems with 64k block size. | |||
975 | */ | |||
976 | if (fs->fs_magic == FS_UFS1_MAGIC0x011954 && sbloc == SBLOCK_UFS265536) { | |||
977 | if (verbose) | |||
978 | fprintf(stderr(&__sF[2]), "skipping ffs1 superblock at %lld\n", | |||
979 | sbloc); | |||
980 | return (0); | |||
981 | } | |||
982 | ||||
983 | if (fs->fs_bsize <= 0 || fs->fs_bsize < sizeof(struct fs) || | |||
984 | fs->fs_bsize > MAXBSIZE(64 * 1024)) { | |||
985 | if (verbose) | |||
986 | fprintf(stderr(&__sF[2]), "invalid superblock block size %d\n", | |||
987 | fs->fs_bsize); | |||
988 | return (0); | |||
989 | } | |||
990 | ||||
991 | if (fs->fs_sbsize <= 0 || fs->fs_sbsize > SBSIZE8192) { | |||
992 | if (verbose) | |||
993 | fprintf(stderr(&__sF[2]), "invalid superblock size %d\n", | |||
994 | fs->fs_sbsize); | |||
995 | return (0); | |||
996 | } | |||
997 | ||||
998 | if (fs->fs_inopb <= 0) { | |||
999 | if (verbose) | |||
1000 | fprintf(stderr(&__sF[2]), "invalid superblock inodes/block %d\n", | |||
1001 | fs->fs_inopb); | |||
1002 | return (0); | |||
1003 | } | |||
1004 | ||||
1005 | if (verbose) | |||
1006 | fprintf(stderr(&__sF[2]), "found valid %s superblock\n", | |||
1007 | fs->fs_magic == FS_UFS2_MAGIC0x19540119 ? "ffs2" : "ffs1"); | |||
1008 | ||||
1009 | return (1); | |||
1010 | } | |||
1011 | ||||
1012 | static void | |||
1013 | sbread(int fd, daddr_t poffset, struct fs **fs, char *sblock) | |||
1014 | { | |||
1015 | int i; | |||
1016 | daddr_t sboff; | |||
1017 | ||||
1018 | for (i = 0; sbtry[i] != -1; i++) { | |||
1019 | sboff = sbtry[i] / DEV_BSIZE(1 << 9); | |||
1020 | devread(fd, sblock, poffset + sboff, SBSIZE8192, "superblock"); | |||
1021 | *fs = (struct fs *)sblock; | |||
1022 | if (sbchk(*fs, sbtry[i])) | |||
1023 | break; | |||
1024 | } | |||
1025 | ||||
1026 | if (sbtry[i] == -1) | |||
1027 | errx(1, "couldn't find ffs superblock"); | |||
1028 | } |