/* $OpenBSD: powerpc64_installboot.c,v 1.8 2022/11/06 12:33:41 krw Exp $ */ /* * Copyright (c) 2011 Joel Sing * Copyright (c) 2010 Otto Moerbeek * Copyright (c) 2003 Tom Cosgrove * Copyright (c) 1997 Michael Shalayeff * Copyright (c) 1994 Paul Kranenburg * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Paul Kranenburg. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include /* DEV_BSIZE */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "installboot.h" static int create_filesystem(struct disklabel *, char); static void write_filesystem(struct disklabel *, char); static int findmbrfat(int, struct disklabel *); char duid[20]; void md_init(void) { stages = 1; stage1 = "/usr/mdec/boot"; } void md_loadboot(void) { } void md_prepareboot(int devfd, char *dev) { struct disklabel dl; int part; /* Get and check disklabel. */ if (ioctl(devfd, DIOCGDINFO, &dl) == -1) err(1, "disklabel: %s", dev); if (dl.d_magic != DISKMAGIC) errx(1, "bad disklabel magic=0x%08x", dl.d_magic); /* Warn on unknown disklabel types. */ if (dl.d_type == 0) warnx("disklabel type unknown"); part = findmbrfat(devfd, &dl); if (part != -1) { create_filesystem(&dl, (char)part); return; } } void md_installboot(int devfd, char *dev) { struct disklabel dl; int part; /* Get and check disklabel. */ if (ioctl(devfd, DIOCGDINFO, &dl) == -1) err(1, "disklabel: %s", dev); if (dl.d_magic != DISKMAGIC) errx(1, "bad disklabel magic=0x%08x", dl.d_magic); snprintf(duid, sizeof duid, "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx", dl.d_uid[0], dl.d_uid[1], dl.d_uid[2], dl.d_uid[3], dl.d_uid[4], dl.d_uid[5], dl.d_uid[6], dl.d_uid[7]); /* Warn on unknown disklabel types. */ if (dl.d_type == 0) warnx("disklabel type unknown"); part = findmbrfat(devfd, &dl); if (part != -1) { write_filesystem(&dl, (char)part); return; } } static int create_filesystem(struct disklabel *dl, char part) { static const char *newfsfmt = "/sbin/newfs -t msdos %s >/dev/null"; struct msdosfs_args args; char cmd[60]; int rslt; /* Mount . as msdos filesystem. */ memset(&args, 0, sizeof(args)); rslt = asprintf(&args.fspec, "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx.%c", dl->d_uid[0], dl->d_uid[1], dl->d_uid[2], dl->d_uid[3], dl->d_uid[4], dl->d_uid[5], dl->d_uid[6], dl->d_uid[7], part); if (rslt == -1) { warn("bad special device"); return rslt; } rslt = snprintf(cmd, sizeof(cmd), newfsfmt, args.fspec); if (rslt >= sizeof(cmd)) { warnx("can't build newfs command"); free(args.fspec); rslt = -1; return rslt; } if (verbose) fprintf(stderr, "%s %s\n", (nowrite ? "would newfs" : "newfsing"), args.fspec); if (!nowrite) { rslt = system(cmd); if (rslt == -1) { warn("system('%s') failed", cmd); free(args.fspec); return rslt; } } free(args.fspec); return 0; } static void write_filesystem(struct disklabel *dl, char part) { static const char *fsckfmt = "/sbin/fsck -t msdos %s >/dev/null"; struct msdosfs_args args; char cmd[60]; char dir[PATH_MAX]; char dst[PATH_MAX]; size_t mntlen; int rslt; /* Create directory for temporary mount point. */ strlcpy(dir, "/tmp/installboot.XXXXXXXXXX", sizeof(dst)); if (mkdtemp(dir) == NULL) err(1, "mkdtemp('%s') failed", dst); mntlen = strlen(dir); /* Mount . as msdos filesystem. */ memset(&args, 0, sizeof(args)); rslt = asprintf(&args.fspec, "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx.%c", dl->d_uid[0], dl->d_uid[1], dl->d_uid[2], dl->d_uid[3], dl->d_uid[4], dl->d_uid[5], dl->d_uid[6], dl->d_uid[7], part); if (rslt == -1) { warn("bad special device"); goto rmdir; } args.export_info.ex_root = -2; args.export_info.ex_flags = 0; args.flags = MSDOSFSMNT_LONGNAME; if (mount(MOUNT_MSDOS, dir, 0, &args) == -1) { /* Try fsck'ing it. */ rslt = snprintf(cmd, sizeof(cmd), fsckfmt, args.fspec); if (rslt >= sizeof(cmd)) { warnx("can't build fsck command"); rslt = -1; goto rmdir; } rslt = system(cmd); if (rslt == -1) { warn("system('%s') failed", cmd); goto rmdir; } if (mount(MOUNT_MSDOS, dir, 0, &args) == -1) { /* Try newfs'ing it. */ rslt = create_filesystem(dl, part); if (rslt == -1) goto rmdir; rslt = mount(MOUNT_MSDOS, dir, 0, &args); if (rslt == -1) { warn("unable to mount MSDOS partition"); goto rmdir; } } } /* * Copy /usr/mdec/boot to /mnt/boot. */ strlcpy(dst, dir, sizeof dst); if (strlcat(dst, "/boot", sizeof(dst)) >= sizeof(dst)) { rslt = -1; warn("unable to build /boot path"); goto umount; } if (verbose) fprintf(stderr, "%s %s to %s\n", (nowrite ? "would copy" : "copying"), stage1, dst); if (!nowrite) { rslt = filecopy(stage1, dst); if (rslt == -1) goto umount; } /* * Create grub.cfg */ strlcpy(dst, dir, sizeof dst); if (strlcat(dst, "/grub.cfg", sizeof(dst)) >= sizeof(dst)) { rslt = -1; warn("unable to build /grub.cfg path"); goto umount; } if (verbose) fprintf(stderr, "%s %s\n", (nowrite ? "would create" : "creating"), dst); if (!nowrite) { FILE *f; f = fopen(dst, "w+"); if (f == NULL) goto umount; fprintf(f, "menuentry \"OpenBSD\" {\n" "\tlinux /boot bootduid=%s\n" "\tinitrd /boot\n" "}\n", duid); fclose(f); } rslt = 0; umount: dir[mntlen] = '\0'; if (unmount(dir, MNT_FORCE) == -1) err(1, "unmount('%s') failed", dir); rmdir: free(args.fspec); dst[mntlen] = '\0'; if (rmdir(dir) == -1) err(1, "rmdir('%s') failed", dir); if (rslt == -1) exit(1); } int findmbrfat(int devfd, struct disklabel *dl) { struct dos_partition dp[NDOSPART]; ssize_t len; u_int64_t start = 0; int i; u_int8_t *secbuf; if ((secbuf = malloc(dl->d_secsize)) == NULL) err(1, NULL); /* Read MBR. */ len = pread(devfd, secbuf, dl->d_secsize, 0); if (len != dl->d_secsize) err(4, "can't read mbr"); memcpy(dp, &secbuf[DOSPARTOFF], sizeof(dp)); for (i = 0; i < NDOSPART; i++) { if (dp[i].dp_typ == DOSPTYP_UNUSED) continue; if (dp[i].dp_typ == DOSPTYP_FAT16L || dp[i].dp_typ == DOSPTYP_FAT32L || dp[i].dp_typ == DOSPTYP_FAT16B) start = letoh32(dp[i].dp_start); } free(secbuf); if (start) { for (i = 0; i < MAXPARTITIONS; i++) { if (DL_GETPSIZE(&dl->d_partitions[i]) > 0 && DL_GETPOFFSET(&dl->d_partitions[i]) == start) return ('a' + i); } } return (-1); }