1/* $OpenBSD: powerpc64_installboot.c,v 1.9 2023/04/26 18:04:21 kn Exp $ */ 2 3/* 4 * Copyright (c) 2011 Joel Sing <jsing@openbsd.org> 5 * Copyright (c) 2010 Otto Moerbeek <otto@openbsd.org> 6 * Copyright (c) 2003 Tom Cosgrove <tom.cosgrove@arches-consulting.com> 7 * Copyright (c) 1997 Michael Shalayeff 8 * Copyright (c) 1994 Paul Kranenburg 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by Paul Kranenburg. 22 * 4. The name of the author may not be used to endorse or promote products 23 * derived from this software without specific prior written permission 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 26 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 27 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 28 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 29 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 30 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 31 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 34 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 */ 36 37#include <sys/param.h> /* DEV_BSIZE */ 38#include <sys/disklabel.h> 39#include <sys/dkio.h> 40#include <sys/ioctl.h> 41#include <sys/mount.h> 42#include <sys/stat.h> 43 44#include <err.h> 45#include <errno.h> 46#include <fcntl.h> 47#include <stdlib.h> 48#include <stdio.h> 49#include <string.h> 50#include <unistd.h> 51#include <util.h> 52#include <endian.h> 53 54#include "installboot.h" 55 56static int create_filesystem(struct disklabel *, char); 57static void write_filesystem(struct disklabel *, char); 58static int findmbrfat(int, struct disklabel *); 59 60char duid[20]; 61 62void 63md_init(void) 64{ 65 stages = 1; 66 stage1 = "/usr/mdec/boot"; 67} 68 69void 70md_loadboot(void) 71{ 72} 73 74void 75md_prepareboot(int devfd, char *dev) 76{ 77 struct disklabel dl; 78 int part; 79 80 /* Get and check disklabel. */ 81 if (ioctl(devfd, DIOCGDINFO, &dl) == -1) 82 err(1, "disklabel: %s", dev); 83 if (dl.d_magic != DISKMAGIC) 84 errx(1, "bad disklabel magic=0x%08x", dl.d_magic); 85 86 /* Warn on unknown disklabel types. */ 87 if (dl.d_type == 0) 88 warnx("disklabel type unknown"); 89 90 part = findmbrfat(devfd, &dl); 91 if (part != -1) { 92 create_filesystem(&dl, (char)part); 93 return; 94 } 95} 96 97void 98md_installboot(int devfd, char *dev) 99{ 100 struct disklabel dl; 101 int part; 102 103 /* Get and check disklabel. */ 104 if (ioctl(devfd, DIOCGDINFO, &dl) == -1) 105 err(1, "disklabel: %s", dev); 106 if (dl.d_magic != DISKMAGIC) 107 errx(1, "bad disklabel magic=0x%08x", dl.d_magic); 108 109 snprintf(duid, sizeof duid, 110 "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx", 111 dl.d_uid[0], dl.d_uid[1], dl.d_uid[2], dl.d_uid[3], 112 dl.d_uid[4], dl.d_uid[5], dl.d_uid[6], dl.d_uid[7]); 113 114 /* Warn on unknown disklabel types. */ 115 if (dl.d_type == 0) 116 warnx("disklabel type unknown"); 117 118 part = findmbrfat(devfd, &dl); 119 if (part != -1) { 120 write_filesystem(&dl, (char)part); 121 return; 122 } 123} 124 125static int 126create_filesystem(struct disklabel *dl, char part) 127{ 128 static const char *newfsfmt = "/sbin/newfs -t msdos %s >/dev/null"; 129 struct msdosfs_args args; 130 char cmd[60]; 131 int rslt; 132 133 /* Newfs <duid>.<part> as msdos filesystem. */ 134 memset(&args, 0, sizeof(args)); 135 rslt = asprintf(&args.fspec, 136 "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx.%c", 137 dl->d_uid[0], dl->d_uid[1], dl->d_uid[2], dl->d_uid[3], 138 dl->d_uid[4], dl->d_uid[5], dl->d_uid[6], dl->d_uid[7], 139 part); 140 if (rslt == -1) { 141 warn("bad special device"); 142 return rslt; 143 } 144 145 rslt = snprintf(cmd, sizeof(cmd), newfsfmt, args.fspec); 146 if (rslt >= sizeof(cmd)) { 147 warnx("can't build newfs command"); 148 free(args.fspec); 149 rslt = -1; 150 return rslt; 151 } 152 153 if (verbose) 154 fprintf(stderr, "%s %s\n", 155 (nowrite ? "would newfs" : "newfsing"), args.fspec); 156 if (!nowrite) { 157 rslt = system(cmd); 158 if (rslt == -1) { 159 warn("system('%s') failed", cmd); 160 free(args.fspec); 161 return rslt; 162 } 163 } 164 165 free(args.fspec); 166 return 0; 167} 168 169static void 170write_filesystem(struct disklabel *dl, char part) 171{ 172 static const char *fsckfmt = "/sbin/fsck -t msdos %s >/dev/null"; 173 struct msdosfs_args args; 174 char cmd[60]; 175 char dir[PATH_MAX]; 176 char dst[PATH_MAX]; 177 size_t mntlen; 178 int rslt; 179 180 /* Create directory for temporary mount point. */ 181 strlcpy(dir, "/tmp/installboot.XXXXXXXXXX", sizeof(dst)); 182 if (mkdtemp(dir) == NULL) 183 err(1, "mkdtemp('%s') failed", dst); 184 mntlen = strlen(dir); 185 186 /* Mount <duid>.<part> as msdos filesystem. */ 187 memset(&args, 0, sizeof(args)); 188 rslt = asprintf(&args.fspec, 189 "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx.%c", 190 dl->d_uid[0], dl->d_uid[1], dl->d_uid[2], dl->d_uid[3], 191 dl->d_uid[4], dl->d_uid[5], dl->d_uid[6], dl->d_uid[7], 192 part); 193 if (rslt == -1) { 194 warn("bad special device"); 195 goto rmdir; 196 } 197 198 args.export_info.ex_root = -2; 199 args.export_info.ex_flags = 0; 200 args.flags = MSDOSFSMNT_LONGNAME; 201 202 if (mount(MOUNT_MSDOS, dir, 0, &args) == -1) { 203 /* Try fsck'ing it. */ 204 rslt = snprintf(cmd, sizeof(cmd), fsckfmt, args.fspec); 205 if (rslt >= sizeof(cmd)) { 206 warnx("can't build fsck command"); 207 rslt = -1; 208 goto rmdir; 209 } 210 rslt = system(cmd); 211 if (rslt == -1) { 212 warn("system('%s') failed", cmd); 213 goto rmdir; 214 } 215 if (mount(MOUNT_MSDOS, dir, 0, &args) == -1) { 216 /* Try newfs'ing it. */ 217 rslt = create_filesystem(dl, part); 218 if (rslt == -1) 219 goto rmdir; 220 rslt = mount(MOUNT_MSDOS, dir, 0, &args); 221 if (rslt == -1) { 222 warn("unable to mount MSDOS partition"); 223 goto rmdir; 224 } 225 } 226 } 227 228 /* 229 * Copy /usr/mdec/boot to /mnt/boot. 230 */ 231 strlcpy(dst, dir, sizeof dst); 232 if (strlcat(dst, "/boot", sizeof(dst)) >= sizeof(dst)) { 233 rslt = -1; 234 warn("unable to build /boot path"); 235 goto umount; 236 } 237 if (verbose) 238 fprintf(stderr, "%s %s to %s\n", 239 (nowrite ? "would copy" : "copying"), stage1, dst); 240 if (!nowrite) { 241 rslt = filecopy(stage1, dst); 242 if (rslt == -1) 243 goto umount; 244 } 245 246 /* 247 * Create grub.cfg 248 */ 249 strlcpy(dst, dir, sizeof dst); 250 if (strlcat(dst, "/grub.cfg", sizeof(dst)) >= sizeof(dst)) { 251 rslt = -1; 252 warn("unable to build /grub.cfg path"); 253 goto umount; 254 } 255 if (verbose) 256 fprintf(stderr, "%s %s\n", 257 (nowrite ? "would create" : "creating"), dst); 258 if (!nowrite) { 259 FILE *f; 260 261 f = fopen(dst, "w+"); 262 if (f == NULL) 263 goto umount; 264 fprintf(f, 265 "menuentry \"OpenBSD\" {\n" 266 "\tlinux /boot bootduid=%s\n" 267 "\tinitrd /boot\n" 268 "}\n", duid); 269 fclose(f); 270 } 271 272 rslt = 0; 273 274umount: 275 dir[mntlen] = '\0'; 276 if (unmount(dir, MNT_FORCE) == -1) 277 err(1, "unmount('%s') failed", dir); 278 279rmdir: 280 free(args.fspec); 281 dst[mntlen] = '\0'; 282 if (rmdir(dir) == -1) 283 err(1, "rmdir('%s') failed", dir); 284 285 if (rslt == -1) 286 exit(1); 287} 288 289int 290findmbrfat(int devfd, struct disklabel *dl) 291{ 292 struct dos_partition dp[NDOSPART]; 293 ssize_t len; 294 u_int64_t start = 0; 295 int i; 296 u_int8_t *secbuf; 297 298 if ((secbuf = malloc(dl->d_secsize)) == NULL) 299 err(1, NULL); 300 301 /* Read MBR. */ 302 len = pread(devfd, secbuf, dl->d_secsize, 0); 303 if (len != dl->d_secsize) 304 err(4, "can't read mbr"); 305 memcpy(dp, &secbuf[DOSPARTOFF], sizeof(dp)); 306 307 for (i = 0; i < NDOSPART; i++) { 308 if (dp[i].dp_typ == DOSPTYP_UNUSED) 309 continue; 310 if (dp[i].dp_typ == DOSPTYP_FAT16L || 311 dp[i].dp_typ == DOSPTYP_FAT32L || 312 dp[i].dp_typ == DOSPTYP_FAT16B) 313 start = letoh32(dp[i].dp_start); 314 } 315 316 free(secbuf); 317 318 if (start) { 319 for (i = 0; i < MAXPARTITIONS; i++) { 320 if (DL_GETPSIZE(&dl->d_partitions[i]) > 0 && 321 DL_GETPOFFSET(&dl->d_partitions[i]) == start) 322 return ('a' + i); 323 } 324 } 325 326 return (-1); 327} 328