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