| 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 | } |