1 /* $OpenBSD: powerpc64_installboot.c,v 1.3 2021/07/20 14:51:56 kettenis 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 56 static int create_filesystem(struct disklabel *, char); 57 static void write_filesystem(struct disklabel *, char); 58 static int findmbrfat(int, struct disklabel *); 59 60 char duid[20]; 61 62 void 63 md_init(void) 64 { 65 } 66 67 void 68 md_loadboot(void) 69 { 70 } 71 72 void 73 md_prepareboot(int devfd, char *dev) 74 { 75 struct disklabel dl; 76 int part; 77 78 /* Get and check disklabel. */ 79 if (ioctl(devfd, DIOCGDINFO, &dl) == -1) 80 err(1, "disklabel: %s", dev); 81 if (dl.d_magic != DISKMAGIC) 82 errx(1, "bad disklabel magic=0x%08x", dl.d_magic); 83 84 /* Warn on unknown disklabel types. */ 85 if (dl.d_type == 0) 86 warnx("disklabel type unknown"); 87 88 part = findmbrfat(devfd, &dl); 89 if (part != -1) { 90 create_filesystem(&dl, (char)part); 91 return; 92 } 93 } 94 95 void 96 md_installboot(int devfd, char *dev) 97 { 98 struct disklabel dl; 99 int part; 100 101 /* Get and check disklabel. */ 102 if (ioctl(devfd, DIOCGDINFO, &dl) == -1) 103 err(1, "disklabel: %s", dev); 104 if (dl.d_magic != DISKMAGIC) 105 errx(1, "bad disklabel magic=0x%08x", dl.d_magic); 106 107 snprintf(duid, sizeof duid, 108 "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx", 109 dl.d_uid[0], dl.d_uid[1], dl.d_uid[2], dl.d_uid[3], 110 dl.d_uid[4], dl.d_uid[5], dl.d_uid[6], dl.d_uid[7]); 111 112 /* Warn on unknown disklabel types. */ 113 if (dl.d_type == 0) 114 warnx("disklabel type unknown"); 115 116 part = findmbrfat(devfd, &dl); 117 if (part != -1) { 118 write_filesystem(&dl, (char)part); 119 return; 120 } 121 } 122 123 static int 124 create_filesystem(struct disklabel *dl, char part) 125 { 126 static char *newfsfmt ="/sbin/newfs_msdos %s >/dev/null"; 127 struct msdosfs_args args; 128 char cmd[60]; 129 int rslt; 130 131 /* Mount <duid>.<part> as msdos filesystem. */ 132 memset(&args, 0, sizeof(args)); 133 rslt = asprintf(&args.fspec, 134 "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx.%c", 135 dl->d_uid[0], dl->d_uid[1], dl->d_uid[2], dl->d_uid[3], 136 dl->d_uid[4], dl->d_uid[5], dl->d_uid[6], dl->d_uid[7], 137 part); 138 if (rslt == -1) { 139 warn("bad special device"); 140 return rslt; 141 } 142 143 rslt = snprintf(cmd, sizeof(cmd), newfsfmt, args.fspec); 144 if (rslt >= sizeof(cmd)) { 145 warnx("can't build newfs command"); 146 rslt = -1; 147 return rslt; 148 } 149 150 if (verbose) 151 fprintf(stderr, "%s %s\n", 152 (nowrite ? "would newfs" : "newfsing"), args.fspec); 153 if (!nowrite) { 154 rslt = system(cmd); 155 if (rslt == -1) { 156 warn("system('%s') failed", cmd); 157 return rslt; 158 } 159 } 160 161 return 0; 162 } 163 164 static void 165 write_filesystem(struct disklabel *dl, char part) 166 { 167 static char *fsckfmt = "/sbin/fsck_msdos %s >/dev/null"; 168 struct msdosfs_args args; 169 char cmd[60]; 170 char dir[PATH_MAX]; 171 char dst[PATH_MAX]; 172 char *src; 173 size_t mntlen, srclen; 174 int rslt; 175 176 src = NULL; 177 178 /* Create directory for temporary mount point. */ 179 strlcpy(dir, "/tmp/installboot.XXXXXXXXXX", sizeof(dst)); 180 if (mkdtemp(dir) == NULL) 181 err(1, "mkdtemp('%s') failed", dst); 182 mntlen = strlen(dir); 183 184 /* Mount <duid>.<part> as msdos filesystem. */ 185 memset(&args, 0, sizeof(args)); 186 rslt = asprintf(&args.fspec, 187 "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx.%c", 188 dl->d_uid[0], dl->d_uid[1], dl->d_uid[2], dl->d_uid[3], 189 dl->d_uid[4], dl->d_uid[5], dl->d_uid[6], dl->d_uid[7], 190 part); 191 if (rslt == -1) { 192 warn("bad special device"); 193 goto rmdir; 194 } 195 196 args.export_info.ex_root = -2; 197 args.export_info.ex_flags = 0; 198 args.flags = MSDOSFSMNT_LONGNAME; 199 200 if (mount(MOUNT_MSDOS, dir, 0, &args) == -1) { 201 /* Try fsck'ing it. */ 202 rslt = snprintf(cmd, sizeof(cmd), fsckfmt, args.fspec); 203 if (rslt >= sizeof(cmd)) { 204 warnx("can't build fsck command"); 205 rslt = -1; 206 goto rmdir; 207 } 208 rslt = system(cmd); 209 if (rslt == -1) { 210 warn("system('%s') failed", cmd); 211 goto rmdir; 212 } 213 if (mount(MOUNT_MSDOS, dir, 0, &args) == -1) { 214 /* Try newfs'ing it. */ 215 rslt = create_filesystem(dl, part); 216 if (rslt == -1) 217 goto rmdir; 218 rslt = mount(MOUNT_MSDOS, dir, 0, &args); 219 if (rslt == -1) { 220 warn("unable to mount MSDOS partition"); 221 goto rmdir; 222 } 223 } 224 } 225 226 /* 227 * Copy /usr/mdec/boot to /mnt/boot. 228 */ 229 strlcpy(dst, dir, sizeof dst); 230 if (strlcat(dst, "/boot", sizeof(dst)) >= sizeof(dst)) { 231 rslt = -1; 232 warn("unable to build /boot path"); 233 goto umount; 234 } 235 src = fileprefix(root, "/usr/mdec/boot"); 236 if (src == NULL) { 237 rslt = -1; 238 goto umount; 239 } 240 srclen = strlen(src); 241 if (verbose) 242 fprintf(stderr, "%s %s to %s\n", 243 (nowrite ? "would copy" : "copying"), src, dst); 244 if (!nowrite) { 245 rslt = filecopy(src, dst); 246 if (rslt == -1) 247 goto umount; 248 } 249 250 /* 251 * Create grub.cfg 252 */ 253 strlcpy(dst, dir, sizeof dst); 254 if (strlcat(dst, "/grub.cfg", sizeof(dst)) >= sizeof(dst)) { 255 rslt = -1; 256 warn("unable to build /grub.cfg path"); 257 goto umount; 258 } 259 if (verbose) 260 fprintf(stderr, "%s %s\n", 261 (nowrite ? "would create" : "creating"), dst); 262 if (!nowrite) { 263 FILE *f; 264 265 f = fopen(dst, "w+"); 266 if (f == NULL) 267 goto umount; 268 fprintf(f, 269 "menuentry \"OpenBSD\" {\n" 270 "\tlinux /boot bootduid=%s\n" 271 "\tinitrd /boot\n" 272 "}\n", duid); 273 fclose(f); 274 } 275 276 rslt = 0; 277 278 umount: 279 dir[mntlen] = '\0'; 280 if (unmount(dir, MNT_FORCE) == -1) 281 err(1, "unmount('%s') failed", dir); 282 283 rmdir: 284 free(args.fspec); 285 dst[mntlen] = '\0'; 286 if (rmdir(dir) == -1) 287 err(1, "rmdir('%s') failed", dir); 288 289 free(src); 290 291 if (rslt == -1) 292 exit(1); 293 } 294 295 int 296 findmbrfat(int devfd, struct disklabel *dl) 297 { 298 struct dos_partition dp[NDOSPART]; 299 ssize_t len; 300 u_int64_t start = 0; 301 int i; 302 u_int8_t *secbuf; 303 304 if ((secbuf = malloc(dl->d_secsize)) == NULL) 305 err(1, NULL); 306 307 /* Read MBR. */ 308 len = pread(devfd, secbuf, dl->d_secsize, 0); 309 if (len != dl->d_secsize) 310 err(4, "can't read mbr"); 311 memcpy(dp, &secbuf[DOSPARTOFF], sizeof(dp)); 312 313 for (i = 0; i < NDOSPART; i++) { 314 if (dp[i].dp_typ == DOSPTYP_UNUSED) 315 continue; 316 if (dp[i].dp_typ == DOSPTYP_FAT16L || 317 dp[i].dp_typ == DOSPTYP_FAT32L || 318 dp[i].dp_typ == DOSPTYP_FAT16B) 319 start = letoh32(dp[i].dp_start); 320 } 321 322 free(secbuf); 323 324 if (start) { 325 for (i = 0; i < MAXPARTITIONS; i++) { 326 if (DL_GETPSIZE(&dl->d_partitions[i]) > 0 && 327 DL_GETPOFFSET(&dl->d_partitions[i]) == start) 328 return ('a' + i); 329 } 330 } 331 332 return (-1); 333 } 334