File: | src/usr.sbin/installboot/i386_installboot.c |
Warning: | line 627, column 10 Assigned value is garbage or undefined |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: i386_installboot.c,v 1.40 2021/07/20 14:51:56 kettenis 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 = 0; | |||
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 OpenBSD partition. Floppies are special, getting an | |||
218 | * everything-in-one /boot starting at sector 0. | |||
219 | */ | |||
220 | if (dl->d_type != DTYPE_FLOPPY10) { | |||
221 | start = findopenbsd(devfd, dl); | |||
222 | if (start == (u_int)-1) | |||
223 | errx(1, "no OpenBSD partition"); | |||
224 | } | |||
225 | ||||
226 | if (verbose) | |||
227 | fprintf(stderr(&__sF[2]), "%s will be written at sector %u\n", | |||
228 | stage1, start); | |||
229 | ||||
230 | if (start + (blksize / dl->d_secsize) > BOOTBIOS_MAXSEC((1 << 28) - 1)) | |||
231 | warnx("%s extends beyond sector %u. OpenBSD might not boot.", | |||
232 | stage1, BOOTBIOS_MAXSEC((1 << 28) - 1)); | |||
233 | ||||
234 | if (!nowrite) { | |||
235 | secbuf = calloc(1, dl->d_secsize); | |||
236 | if (pread(devfd, secbuf, dl->d_secsize, (off_t)start * | |||
237 | dl->d_secsize) != dl->d_secsize) | |||
238 | err(1, "pread boot sector"); | |||
239 | bcopy(blkstore, secbuf, blksize); | |||
240 | if (pwrite(devfd, secbuf, dl->d_secsize, (off_t)start * | |||
241 | dl->d_secsize) != dl->d_secsize) | |||
242 | err(1, "pwrite bootstrap"); | |||
243 | free(secbuf); | |||
244 | } | |||
245 | } | |||
246 | ||||
247 | int | |||
248 | create_filesystem(struct disklabel *dl, char part) | |||
249 | { | |||
250 | static char *newfsfmt ="/sbin/newfs_msdos %s >/dev/null"; | |||
251 | struct msdosfs_args args; | |||
252 | char cmd[60]; | |||
253 | int rslt; | |||
254 | ||||
255 | /* Mount <duid>.<part> as msdos filesystem. */ | |||
256 | memset(&args, 0, sizeof(args)); | |||
257 | rslt = asprintf(&args.fspec, | |||
258 | "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx.%c", | |||
259 | dl->d_uid[0], dl->d_uid[1], dl->d_uid[2], dl->d_uid[3], | |||
260 | dl->d_uid[4], dl->d_uid[5], dl->d_uid[6], dl->d_uid[7], | |||
261 | part); | |||
262 | if (rslt == -1) { | |||
263 | warn("bad special device"); | |||
264 | return rslt; | |||
265 | } | |||
266 | ||||
267 | rslt = snprintf(cmd, sizeof(cmd), newfsfmt, args.fspec); | |||
268 | if (rslt >= sizeof(cmd)) { | |||
269 | warnx("can't build newfs command"); | |||
270 | rslt = -1; | |||
271 | return rslt; | |||
272 | } | |||
273 | ||||
274 | if (verbose) | |||
275 | fprintf(stderr(&__sF[2]), "%s %s\n", | |||
276 | (nowrite ? "would newfs" : "newfsing"), args.fspec); | |||
277 | if (!nowrite) { | |||
278 | rslt = system(cmd); | |||
279 | if (rslt == -1) { | |||
280 | warn("system('%s') failed", cmd); | |||
281 | return rslt; | |||
282 | } | |||
283 | } | |||
284 | ||||
285 | return 0; | |||
286 | } | |||
287 | ||||
288 | void | |||
289 | write_filesystem(struct disklabel *dl, char part) | |||
290 | { | |||
291 | static char *fsckfmt = "/sbin/fsck_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 | u_int | |||
438 | findopenbsd(int devfd, struct disklabel *dl) | |||
439 | { | |||
440 | struct dos_mbr mbr; | |||
441 | u_int mbroff = DOSBBSECTOR0; | |||
442 | u_int mbr_eoff = DOSBBSECTOR0; /* Offset of extended part. */ | |||
443 | struct dos_partition *dp; | |||
444 | u_int8_t *secbuf; | |||
445 | u_int maxebr = DOS_MAXEBR256, nextebr; | |||
446 | int i; | |||
447 | ||||
448 | again: | |||
449 | if (!maxebr--) { | |||
450 | if (verbose) | |||
451 | fprintf(stderr(&__sF[2]), "Traversed more than %d Extended Boot " | |||
452 | "Records (EBRs)\n", DOS_MAXEBR256); | |||
453 | return ((u_int)-1); | |||
454 | } | |||
455 | ||||
456 | if (verbose) | |||
457 | fprintf(stderr(&__sF[2]), "%s boot record (%cBR) at sector %u\n", | |||
458 | (mbroff == DOSBBSECTOR0) ? "master" : "extended", | |||
459 | (mbroff == DOSBBSECTOR0) ? 'M' : 'E', mbroff); | |||
460 | ||||
461 | if ((secbuf = malloc(dl->d_secsize)) == NULL((void *)0)) | |||
462 | err(1, NULL((void *)0)); | |||
463 | if (pread(devfd, secbuf, dl->d_secsize, (off_t)mbroff * dl->d_secsize) | |||
464 | < (ssize_t)sizeof(mbr)) | |||
465 | err(4, "can't pread boot record"); | |||
466 | bcopy(secbuf, &mbr, sizeof(mbr)); | |||
467 | free(secbuf); | |||
468 | ||||
469 | if (mbr.dmbr_sign != DOSMBR_SIGNATURE(0xaa55)) | |||
470 | errx(1, "invalid boot record signature (0x%04X) @ sector %u", | |||
471 | mbr.dmbr_sign, mbroff); | |||
472 | ||||
473 | nextebr = 0; | |||
474 | for (i = 0; i < NDOSPART4; i++) { | |||
475 | dp = &mbr.dmbr_parts[i]; | |||
476 | if (!dp->dp_size) | |||
477 | continue; | |||
478 | ||||
479 | if (verbose) | |||
480 | fprintf(stderr(&__sF[2]), | |||
481 | "\tpartition %d: type 0x%02X offset %u size %u\n", | |||
482 | i, dp->dp_typ, dp->dp_start, dp->dp_size); | |||
483 | ||||
484 | if (dp->dp_typ == DOSPTYP_OPENBSD0xa6) { | |||
485 | if (dp->dp_start > (dp->dp_start + mbroff)) | |||
486 | continue; | |||
487 | return (dp->dp_start + mbroff); | |||
488 | } | |||
489 | ||||
490 | if (!nextebr && (dp->dp_typ == DOSPTYP_EXTEND0x05 || | |||
491 | dp->dp_typ == DOSPTYP_EXTENDL0x0f)) { | |||
492 | nextebr = dp->dp_start + mbr_eoff; | |||
493 | if (nextebr < dp->dp_start) | |||
494 | nextebr = (u_int)-1; | |||
495 | if (mbr_eoff == DOSBBSECTOR0) | |||
496 | mbr_eoff = dp->dp_start; | |||
497 | } | |||
498 | } | |||
499 | ||||
500 | if (nextebr && nextebr != (u_int)-1) { | |||
501 | mbroff = nextebr; | |||
502 | goto again; | |||
503 | } | |||
504 | ||||
505 | return ((u_int)-1); | |||
506 | } | |||
507 | ||||
508 | /* | |||
509 | * Returns 0 if the MBR with the provided partition array is a GPT protective | |||
510 | * MBR, and returns 1 otherwise. A GPT protective MBR would have one and only | |||
511 | * one MBR partition, an EFI partition that either covers the whole disk or as | |||
512 | * much of it as is possible with a 32bit size field. | |||
513 | * | |||
514 | * NOTE: MS always uses a size of UINT32_MAX for the EFI partition!** | |||
515 | */ | |||
516 | static int | |||
517 | gpt_chk_mbr(struct dos_partition *dp, u_int64_t dsize) | |||
518 | { | |||
519 | struct dos_partition *dp2; | |||
520 | int efi, found, i; | |||
521 | u_int32_t psize; | |||
522 | ||||
523 | found = efi = 0; | |||
524 | for (dp2=dp, i=0; i < NDOSPART4; i++, dp2++) { | |||
525 | if (dp2->dp_typ == DOSPTYP_UNUSED0x00) | |||
526 | continue; | |||
527 | found++; | |||
528 | if (dp2->dp_typ != DOSPTYP_EFI0xee) | |||
529 | continue; | |||
530 | if (letoh32(dp2->dp_start)((__uint32_t)(dp2->dp_start)) != GPTSECTOR1) | |||
531 | continue; | |||
532 | psize = letoh32(dp2->dp_size)((__uint32_t)(dp2->dp_size)); | |||
533 | if (psize <= (dsize - GPTSECTOR1) || psize == UINT32_MAX0xffffffffU) | |||
534 | efi++; | |||
535 | } | |||
536 | if (found == 1 && efi == 1) | |||
537 | return (0); | |||
538 | ||||
539 | return (1); | |||
540 | } | |||
541 | ||||
542 | int | |||
543 | findgptefisys(int devfd, struct disklabel *dl) | |||
544 | { | |||
545 | struct gpt_partition gp[NGPTPARTITIONS128]; | |||
546 | struct gpt_header gh; | |||
547 | struct dos_partition dp[NDOSPART4]; | |||
548 | struct uuid efisys_uuid; | |||
549 | 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 }; | |||
550 | off_t off; | |||
551 | ssize_t len; | |||
552 | u_int64_t start; | |||
553 | int i; | |||
554 | uint32_t orig_csum, new_csum; | |||
555 | uint32_t ghsize, ghpartsize, ghpartnum, ghpartspersec; | |||
556 | u_int8_t *secbuf; | |||
557 | ||||
558 | /* Prepare EFI System UUID */ | |||
559 | uuid_dec_be(efisys_uuid_code, &efisys_uuid); | |||
560 | ||||
561 | if ((secbuf = malloc(dl->d_secsize)) == NULL((void *)0)) | |||
562 | err(1, NULL((void *)0)); | |||
563 | ||||
564 | /* Check that there is a protective MBR. */ | |||
565 | len = pread(devfd, secbuf, dl->d_secsize, 0); | |||
566 | if (len != dl->d_secsize) | |||
567 | err(4, "can't read mbr"); | |||
568 | memcpy(dp, &secbuf[DOSPARTOFF446], sizeof(dp)); | |||
569 | if (gpt_chk_mbr(dp, DL_GETDSIZE(dl)(((u_int64_t)(dl)->d_secperunith << 32) + (dl)->d_secperunit ))) { | |||
570 | free(secbuf); | |||
571 | return (-1); | |||
572 | } | |||
573 | ||||
574 | /* Check GPT Header. */ | |||
575 | off = dl->d_secsize; /* Read header from sector 1. */ | |||
576 | len = pread(devfd, secbuf, dl->d_secsize, off); | |||
577 | if (len != dl->d_secsize) | |||
578 | err(4, "can't pread gpt header"); | |||
579 | ||||
580 | memcpy(&gh, secbuf, sizeof(gh)); | |||
581 | free(secbuf); | |||
582 | ||||
583 | /* Check signature */ | |||
584 | if (letoh64(gh.gh_sig)((__uint64_t)(gh.gh_sig)) != GPTSIGNATURE0x5452415020494645LL) | |||
585 | return (-1); | |||
586 | ||||
587 | if (letoh32(gh.gh_rev)((__uint32_t)(gh.gh_rev)) != GPTREVISION0x10000) | |||
588 | return (-1); | |||
589 | ||||
590 | ghsize = letoh32(gh.gh_size)((__uint32_t)(gh.gh_size)); | |||
591 | if (ghsize < GPTMINHDRSIZE92 || ghsize > sizeof(struct gpt_header)) | |||
592 | return (-1); | |||
593 | ||||
594 | /* Check checksum */ | |||
595 | orig_csum = gh.gh_csum; | |||
596 | gh.gh_csum = 0; | |||
597 | new_csum = crc32((unsigned char *)&gh, ghsize); | |||
598 | gh.gh_csum = orig_csum; | |||
599 | if (letoh32(orig_csum)((__uint32_t)(orig_csum)) != new_csum) | |||
600 | return (-1); | |||
601 | ||||
602 | off = letoh64(gh.gh_part_lba)((__uint64_t)(gh.gh_part_lba)) * dl->d_secsize; | |||
603 | ghpartsize = letoh32(gh.gh_part_size)((__uint32_t)(gh.gh_part_size)); | |||
604 | ghpartspersec = dl->d_secsize / ghpartsize; | |||
605 | ghpartnum = letoh32(gh.gh_part_num)((__uint32_t)(gh.gh_part_num)); | |||
606 | if ((secbuf = malloc(dl->d_secsize)) == NULL((void *)0)) | |||
607 | err(1, NULL((void *)0)); | |||
608 | for (i = 0; i < (ghpartnum + ghpartspersec - 1) / ghpartspersec; i++) { | |||
609 | len = pread(devfd, secbuf, dl->d_secsize, off); | |||
610 | if (len != dl->d_secsize) { | |||
611 | free(secbuf); | |||
612 | return (-1); | |||
613 | } | |||
614 | memcpy(gp + i * ghpartspersec, secbuf, | |||
615 | ghpartspersec * sizeof(struct gpt_partition)); | |||
616 | off += dl->d_secsize; | |||
617 | } | |||
618 | free(secbuf); | |||
619 | new_csum = crc32((unsigned char *)&gp, ghpartnum * ghpartsize); | |||
620 | if (new_csum != letoh32(gh.gh_part_csum)((__uint32_t)(gh.gh_part_csum))) | |||
621 | return (-1); | |||
622 | ||||
623 | start = 0; | |||
624 | for (i = 0; i < ghpartnum && start == 0; i++) { | |||
625 | if (memcmp(&gp[i].gp_type, &efisys_uuid, | |||
626 | sizeof(struct uuid)) == 0) | |||
627 | start = letoh64(gp[i].gp_lba_start)((__uint64_t)(gp[i].gp_lba_start)); | |||
| ||||
628 | } | |||
629 | ||||
630 | if (start) { | |||
631 | for (i = 0; i < MAXPARTITIONS16; i++) { | |||
632 | if (DL_GETPSIZE(&dl->d_partitions[i])(((u_int64_t)(&dl->d_partitions[i])->p_sizeh << 32) + (&dl->d_partitions[i])->p_size) > 0 && | |||
633 | DL_GETPOFFSET(&dl->d_partitions[i])(((u_int64_t)(&dl->d_partitions[i])->p_offseth << 32) + (&dl->d_partitions[i])->p_offset) == start) | |||
634 | return ('a' + i); | |||
635 | } | |||
636 | } | |||
637 | ||||
638 | return (-1); | |||
639 | } | |||
640 | ||||
641 | /* | |||
642 | * Load the prototype boot sector (biosboot) into memory. | |||
643 | */ | |||
644 | static char * | |||
645 | loadproto(char *fname, long *size) | |||
646 | { | |||
647 | int fd; | |||
648 | size_t tdsize; /* text+data size */ | |||
649 | char *bp; | |||
650 | Elf_EhdrElf32_Ehdr eh; | |||
651 | Elf_WordElf32_Word phsize; | |||
652 | Elf_PhdrElf32_Phdr *ph; | |||
653 | ||||
654 | if ((fd = open(fname, O_RDONLY0x0000)) == -1) | |||
655 | err(1, "%s", fname); | |||
656 | ||||
657 | if (read(fd, &eh, sizeof(eh)) != sizeof(eh)) | |||
658 | errx(1, "%s: read failed", fname); | |||
659 | ||||
660 | if (!IS_ELF(eh)((eh).e_ident[0] == 0x7f && (eh).e_ident[1] == 'E' && (eh).e_ident[2] == 'L' && (eh).e_ident[3] == 'F')) | |||
661 | errx(1, "%s: bad magic: 0x%02x%02x%02x%02x", fname, | |||
662 | eh.e_ident[EI_MAG00], eh.e_ident[EI_MAG11], | |||
663 | eh.e_ident[EI_MAG22], eh.e_ident[EI_MAG33]); | |||
664 | ||||
665 | /* | |||
666 | * We have to include the exec header in the beginning of | |||
667 | * the buffer, and leave extra space at the end in case | |||
668 | * the actual write to disk wants to skip the header. | |||
669 | */ | |||
670 | ||||
671 | /* Program load header. */ | |||
672 | if (eh.e_phnum != 1) | |||
673 | errx(1, "%s: %u ELF load sections (only support 1)", | |||
674 | fname, eh.e_phnum); | |||
675 | ||||
676 | ph = reallocarray(NULL((void *)0), eh.e_phnum, sizeof(Elf_PhdrElf32_Phdr)); | |||
677 | if (ph == NULL((void *)0)) | |||
678 | err(1, NULL((void *)0)); | |||
679 | phsize = eh.e_phnum * sizeof(Elf_PhdrElf32_Phdr); | |||
680 | ||||
681 | if (pread(fd, ph, phsize, eh.e_phoff) != phsize) | |||
682 | errx(1, "%s: can't pread header", fname); | |||
683 | ||||
684 | tdsize = ph->p_filesz; | |||
685 | ||||
686 | /* | |||
687 | * Allocate extra space here because the caller may copy | |||
688 | * the boot block starting at the end of the exec header. | |||
689 | * This prevents reading beyond the end of the buffer. | |||
690 | */ | |||
691 | if ((bp = calloc(tdsize, 1)) == NULL((void *)0)) | |||
692 | err(1, NULL((void *)0)); | |||
693 | ||||
694 | /* Read the rest of the file. */ | |||
695 | if (pread(fd, bp, tdsize, ph->p_offset) != (ssize_t)tdsize) | |||
696 | errx(1, "%s: pread failed", fname); | |||
697 | ||||
698 | *size = tdsize; /* not aligned to DEV_BSIZE */ | |||
699 | ||||
700 | close(fd); | |||
701 | return bp; | |||
702 | } | |||
703 | ||||
704 | static void | |||
705 | devread(int fd, void *buf, daddr_t blk, size_t size, char *msg) | |||
706 | { | |||
707 | if (pread(fd, buf, size, dbtob((off_t)blk)(((off_t)blk) << 9)) != (ssize_t)size) | |||
708 | err(1, "%s: devread: pread", msg); | |||
709 | } | |||
710 | ||||
711 | /* | |||
712 | * Read information about /boot's inode, then put this and filesystem | |||
713 | * parameters from the superblock into pbr_symbols. | |||
714 | */ | |||
715 | static int | |||
716 | getbootparams(char *boot, int devfd, struct disklabel *dl) | |||
717 | { | |||
718 | int fd; | |||
719 | struct stat dsb, fsb; | |||
720 | struct statfs fssb; | |||
721 | struct partition *pp; | |||
722 | struct fs *fs; | |||
723 | char *sblock, *buf; | |||
724 | u_int blk, *ap; | |||
725 | int ndb; | |||
726 | int mib[3]; | |||
727 | size_t size; | |||
728 | dev_t dev; | |||
729 | int incr; | |||
730 | ||||
731 | /* | |||
732 | * Open 2nd-level boot program and record enough details about | |||
733 | * where it is on the filesystem represented by `devfd' | |||
734 | * (inode block, offset within that block, and various filesystem | |||
735 | * parameters essentially taken from the superblock) for biosboot | |||
736 | * to be able to load it later. | |||
737 | */ | |||
738 | ||||
739 | /* Make sure the (probably new) boot file is on disk. */ | |||
740 | sync(); sleep(1); | |||
741 | ||||
742 | if ((fd = open(boot, O_RDONLY0x0000)) == -1) | |||
743 | err(1, "open: %s", boot); | |||
744 | ||||
745 | if (fstatfs(fd, &fssb) == -1) | |||
746 | err(1, "statfs: %s", boot); | |||
747 | ||||
748 | if (strncmp(fssb.f_fstypename, "ffs", MFSNAMELEN16) && | |||
749 | strncmp(fssb.f_fstypename, "ufs", MFSNAMELEN16) ) | |||
750 | errx(1, "%s: not on an FFS filesystem", boot); | |||
751 | ||||
752 | #if 0 | |||
753 | if (read(fd, &eh, sizeof(eh)) != sizeof(eh)) | |||
754 | errx(1, "read: %s", boot); | |||
755 | ||||
756 | if (!IS_ELF(eh)((eh).e_ident[0] == 0x7f && (eh).e_ident[1] == 'E' && (eh).e_ident[2] == 'L' && (eh).e_ident[3] == 'F')) { | |||
757 | errx(1, "%s: bad magic: 0x%02x%02x%02x%02x", | |||
758 | boot, | |||
759 | eh.e_ident[EI_MAG00], eh.e_ident[EI_MAG11], | |||
760 | eh.e_ident[EI_MAG22], eh.e_ident[EI_MAG33]); | |||
761 | } | |||
762 | #endif | |||
763 | ||||
764 | if (fsync(fd) != 0) | |||
765 | err(1, "fsync: %s", boot); | |||
766 | ||||
767 | if (fstat(fd, &fsb) != 0) | |||
768 | err(1, "fstat: %s", boot); | |||
769 | ||||
770 | if (fstat(devfd, &dsb) != 0) | |||
771 | err(1, "fstat: %d", devfd); | |||
772 | ||||
773 | /* Check devices. */ | |||
774 | mib[0] = CTL_MACHDEP7; | |||
775 | mib[1] = CPU_CHR2BLK4; | |||
776 | mib[2] = dsb.st_rdev; | |||
777 | size = sizeof(dev); | |||
778 | if (sysctl(mib, 3, &dev, &size, NULL((void *)0), 0) >= 0) { | |||
779 | if (fsb.st_dev / MAXPARTITIONS16 != dev / MAXPARTITIONS16) | |||
780 | errx(1, "cross-device install"); | |||
781 | } | |||
782 | ||||
783 | pp = &dl->d_partitions[DISKPART(fsb.st_dev)(((unsigned)((fsb.st_dev) & 0xff) | (((fsb.st_dev) & 0xffff0000 ) >> 8)) % 16)]; | |||
784 | close(fd); | |||
785 | ||||
786 | if ((sblock = malloc(SBSIZE8192)) == NULL((void *)0)) | |||
787 | err(1, NULL((void *)0)); | |||
788 | ||||
789 | sbread(devfd, DL_SECTOBLK(dl, pp->p_offset)((pp->p_offset) * ((dl)->d_secsize / (1 << 9))), &fs, sblock); | |||
790 | ||||
791 | /* Read inode. */ | |||
792 | if ((buf = malloc(fs->fs_bsize)) == NULL((void *)0)) | |||
793 | err(1, NULL((void *)0)); | |||
794 | ||||
795 | 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 ); | |||
796 | ||||
797 | /* | |||
798 | * Have the inode. Figure out how many filesystem blocks (not disk | |||
799 | * sectors) there are for biosboot to load. | |||
800 | */ | |||
801 | devread(devfd, buf, DL_SECTOBLK(dl, pp->p_offset)((pp->p_offset) * ((dl)->d_secsize / (1 << 9))) + blk, | |||
802 | fs->fs_bsize, "inode"); | |||
803 | if (fs->fs_magic == FS_UFS2_MAGIC0x19540119) { | |||
804 | struct ufs2_dinode *ip2 = (struct ufs2_dinode *)(buf) + | |||
805 | ino_to_fsbo(fs, fsb.st_ino)((fsb.st_ino) % ((fs)->fs_inopb)); | |||
806 | ndb = howmany(ip2->di_size, fs->fs_bsize)(((ip2->di_size) + ((fs->fs_bsize) - 1)) / (fs->fs_bsize )); | |||
807 | ap = (u_int *)ip2->di_db; | |||
808 | incr = sizeof(u_int32_t); | |||
809 | } else { | |||
810 | struct ufs1_dinode *ip1 = (struct ufs1_dinode *)(buf) + | |||
811 | ino_to_fsbo(fs, fsb.st_ino)((fsb.st_ino) % ((fs)->fs_inopb)); | |||
812 | ndb = howmany(ip1->di_size, fs->fs_bsize)(((ip1->di_size) + ((fs->fs_bsize) - 1)) / (fs->fs_bsize )); | |||
813 | ap = (u_int *)ip1->di_db; | |||
814 | incr = 0; | |||
815 | } | |||
816 | ||||
817 | if (ndb <= 0) | |||
818 | errx(1, "No blocks to load"); | |||
819 | ||||
820 | /* | |||
821 | * Now set the values that will need to go into biosboot | |||
822 | * (the partition boot record, a.k.a. the PBR). | |||
823 | */ | |||
824 | sym_set_value(pbr_symbols, "_fs_bsize_p", (fs->fs_bsize / 16)); | |||
825 | sym_set_value(pbr_symbols, "_fs_bsize_s", (fs->fs_bsize / | |||
826 | dl->d_secsize)); | |||
827 | ||||
828 | /* | |||
829 | * fs_fsbtodb is the shift to convert fs_fsize to DEV_BSIZE. The | |||
830 | * ino_to_fsba() return value is the number of fs_fsize units. | |||
831 | * Calculate the shift to convert fs_fsize into physical sectors, | |||
832 | * which are added to p_offset to get the sector address BIOS | |||
833 | * will use. | |||
834 | * | |||
835 | * N.B.: ASSUMES fs_fsize is a power of 2 of d_secsize. | |||
836 | */ | |||
837 | sym_set_value(pbr_symbols, "_fsbtodb", | |||
838 | ffs(fs->fs_fsize / dl->d_secsize) - 1); | |||
839 | ||||
840 | sym_set_value(pbr_symbols, "_p_offset", pp->p_offset); | |||
841 | sym_set_value(pbr_symbols, "_inodeblk", | |||
842 | 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))))); | |||
843 | sym_set_value(pbr_symbols, "_inodedbl", | |||
844 | ((((char *)ap) - buf) + INODEOFF((0x07e0 -0x07c0) << 4))); | |||
845 | sym_set_value(pbr_symbols, "_nblocks", ndb); | |||
846 | sym_set_value(pbr_symbols, "_blkincr", incr); | |||
847 | ||||
848 | if (verbose) { | |||
849 | fprintf(stderr(&__sF[2]), "%s is %d blocks x %d bytes\n", | |||
850 | boot, ndb, fs->fs_bsize); | |||
851 | fprintf(stderr(&__sF[2]), "fs block shift %u; part offset %u; " | |||
852 | "inode block %lld, offset %u\n", | |||
853 | ffs(fs->fs_fsize / dl->d_secsize) - 1, | |||
854 | pp->p_offset, | |||
855 | 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)))), | |||
856 | (unsigned int)((((char *)ap) - buf) + INODEOFF((0x07e0 -0x07c0) << 4))); | |||
857 | fprintf(stderr(&__sF[2]), "expecting %d-bit fs blocks (incr %d)\n", | |||
858 | incr ? 64 : 32, incr); | |||
859 | } | |||
860 | ||||
861 | free (sblock); | |||
862 | free (buf); | |||
863 | ||||
864 | return 0; | |||
865 | } | |||
866 | ||||
867 | void | |||
868 | sym_set_value(struct sym_data *sym_list, char *sym, u_int32_t value) | |||
869 | { | |||
870 | struct sym_data *p; | |||
871 | ||||
872 | for (p = sym_list; p->sym_name != NULL((void *)0); p++) { | |||
873 | if (strcmp(p->sym_name, sym) == 0) | |||
874 | break; | |||
875 | } | |||
876 | ||||
877 | if (p->sym_name == NULL((void *)0)) | |||
878 | errx(1, "%s: no such symbol", sym); | |||
879 | ||||
880 | p->sym_value = value; | |||
881 | p->sym_set = 1; | |||
882 | } | |||
883 | ||||
884 | /* | |||
885 | * Write the parameters stored in sym_list into the in-memory copy of | |||
886 | * the prototype biosboot (proto), ready for it to be written to disk. | |||
887 | */ | |||
888 | void | |||
889 | pbr_set_symbols(char *fname, char *proto, struct sym_data *sym_list) | |||
890 | { | |||
891 | struct sym_data *sym; | |||
892 | struct nlist *nl; | |||
893 | char *vp; | |||
894 | u_int32_t *lp; | |||
895 | u_int16_t *wp; | |||
896 | u_int8_t *bp; | |||
897 | ||||
898 | for (sym = sym_list; sym->sym_name != NULL((void *)0); sym++) { | |||
899 | if (!sym->sym_set) | |||
900 | errx(1, "%s not set", sym->sym_name); | |||
901 | ||||
902 | /* Allocate space for 2; second is null-terminator for list. */ | |||
903 | nl = calloc(2, sizeof(struct nlist)); | |||
904 | if (nl == NULL((void *)0)) | |||
905 | err(1, NULL((void *)0)); | |||
906 | ||||
907 | nl->n_name = sym->sym_name; | |||
908 | ||||
909 | if (nlist_elf32(fname, nl) != 0) | |||
910 | errx(1, "%s: symbol %s not found", | |||
911 | fname, sym->sym_name); | |||
912 | ||||
913 | if (nl->n_type != (N_TEXT0x04)) | |||
914 | errx(1, "%s: %s: wrong type (%x)", | |||
915 | fname, sym->sym_name, nl->n_type); | |||
916 | ||||
917 | /* Get a pointer to where the symbol's value needs to go. */ | |||
918 | vp = proto + nl->n_value; | |||
919 | ||||
920 | switch (sym->sym_size) { | |||
921 | case 4: /* u_int32_t */ | |||
922 | lp = (u_int32_t *) vp; | |||
923 | *lp = sym->sym_value; | |||
924 | break; | |||
925 | case 2: /* u_int16_t */ | |||
926 | if (sym->sym_value >= 0x10000) /* out of range */ | |||
927 | errx(1, "%s: symbol out of range (%u)", | |||
928 | sym->sym_name, sym->sym_value); | |||
929 | wp = (u_int16_t *) vp; | |||
930 | *wp = (u_int16_t) sym->sym_value; | |||
931 | break; | |||
932 | case 1: /* u_int16_t */ | |||
933 | if (sym->sym_value >= 0x100) /* out of range */ | |||
934 | errx(1, "%s: symbol out of range (%u)", | |||
935 | sym->sym_name, sym->sym_value); | |||
936 | bp = (u_int8_t *) vp; | |||
937 | *bp = (u_int8_t) sym->sym_value; | |||
938 | break; | |||
939 | default: | |||
940 | errx(1, "%s: bad symbol size %d", | |||
941 | sym->sym_name, sym->sym_size); | |||
942 | /* NOTREACHED */ | |||
943 | } | |||
944 | ||||
945 | free(nl); | |||
946 | } | |||
947 | } | |||
948 | ||||
949 | static int | |||
950 | sbchk(struct fs *fs, daddr_t sbloc) | |||
951 | { | |||
952 | if (verbose) | |||
953 | fprintf(stderr(&__sF[2]), "looking for superblock at %lld\n", sbloc); | |||
954 | ||||
955 | if (fs->fs_magic != FS_UFS2_MAGIC0x19540119 && fs->fs_magic != FS_UFS1_MAGIC0x011954) { | |||
956 | if (verbose) | |||
957 | fprintf(stderr(&__sF[2]), "bad superblock magic 0x%x\n", | |||
958 | fs->fs_magic); | |||
959 | return (0); | |||
960 | } | |||
961 | ||||
962 | /* | |||
963 | * Looking for an FFS1 file system at SBLOCK_UFS2 will find the | |||
964 | * wrong superblock for file systems with 64k block size. | |||
965 | */ | |||
966 | if (fs->fs_magic == FS_UFS1_MAGIC0x011954 && sbloc == SBLOCK_UFS265536) { | |||
967 | if (verbose) | |||
968 | fprintf(stderr(&__sF[2]), "skipping ffs1 superblock at %lld\n", | |||
969 | sbloc); | |||
970 | return (0); | |||
971 | } | |||
972 | ||||
973 | if (fs->fs_bsize <= 0 || fs->fs_bsize < sizeof(struct fs) || | |||
974 | fs->fs_bsize > MAXBSIZE(64 * 1024)) { | |||
975 | if (verbose) | |||
976 | fprintf(stderr(&__sF[2]), "invalid superblock block size %d\n", | |||
977 | fs->fs_bsize); | |||
978 | return (0); | |||
979 | } | |||
980 | ||||
981 | if (fs->fs_sbsize <= 0 || fs->fs_sbsize > SBSIZE8192) { | |||
982 | if (verbose) | |||
983 | fprintf(stderr(&__sF[2]), "invalid superblock size %d\n", | |||
984 | fs->fs_sbsize); | |||
985 | return (0); | |||
986 | } | |||
987 | ||||
988 | if (fs->fs_inopb <= 0) { | |||
989 | if (verbose) | |||
990 | fprintf(stderr(&__sF[2]), "invalid superblock inodes/block %d\n", | |||
991 | fs->fs_inopb); | |||
992 | return (0); | |||
993 | } | |||
994 | ||||
995 | if (verbose) | |||
996 | fprintf(stderr(&__sF[2]), "found valid %s superblock\n", | |||
997 | fs->fs_magic == FS_UFS2_MAGIC0x19540119 ? "ffs2" : "ffs1"); | |||
998 | ||||
999 | return (1); | |||
1000 | } | |||
1001 | ||||
1002 | static void | |||
1003 | sbread(int fd, daddr_t poffset, struct fs **fs, char *sblock) | |||
1004 | { | |||
1005 | int i; | |||
1006 | daddr_t sboff; | |||
1007 | ||||
1008 | for (i = 0; sbtry[i] != -1; i++) { | |||
1009 | sboff = sbtry[i] / DEV_BSIZE(1 << 9); | |||
1010 | devread(fd, sblock, poffset + sboff, SBSIZE8192, "superblock"); | |||
1011 | *fs = (struct fs *)sblock; | |||
1012 | if (sbchk(*fs, sbtry[i])) | |||
1013 | break; | |||
1014 | } | |||
1015 | ||||
1016 | if (sbtry[i] == -1) | |||
1017 | errx(1, "couldn't find ffs superblock"); | |||
1018 | } |