1 /* $OpenBSD: octeon_installboot.c,v 1.11 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 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 void 61 md_init(void) 62 { 63 stages = 1; 64 stage1 = "/usr/mdec/boot"; 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 /* Warn on unknown disklabel types. */ 108 if (dl.d_type == 0) 109 warnx("disklabel type unknown"); 110 111 part = findmbrfat(devfd, &dl); 112 if (part != -1) { 113 write_filesystem(&dl, (char)part); 114 return; 115 } 116 } 117 118 static int 119 create_filesystem(struct disklabel *dl, char part) 120 { 121 static const char *newfsfmt = "/sbin/newfs -t msdos %s >/dev/null"; 122 struct msdosfs_args args; 123 char cmd[60]; 124 int rslt; 125 126 /* Newfs <duid>.<part> as msdos filesystem. */ 127 memset(&args, 0, sizeof(args)); 128 rslt = asprintf(&args.fspec, 129 "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx.%c", 130 dl->d_uid[0], dl->d_uid[1], dl->d_uid[2], dl->d_uid[3], 131 dl->d_uid[4], dl->d_uid[5], dl->d_uid[6], dl->d_uid[7], 132 part); 133 if (rslt == -1) { 134 warn("bad special device"); 135 return rslt; 136 } 137 138 rslt = snprintf(cmd, sizeof(cmd), newfsfmt, args.fspec); 139 if (rslt >= sizeof(cmd)) { 140 warnx("can't build newfs command"); 141 free(args.fspec); 142 rslt = -1; 143 return rslt; 144 } 145 146 if (verbose) 147 fprintf(stderr, "%s %s\n", 148 (nowrite ? "would newfs" : "newfsing"), args.fspec); 149 if (!nowrite) { 150 rslt = system(cmd); 151 if (rslt == -1) { 152 warn("system('%s') failed", cmd); 153 free(args.fspec); 154 return rslt; 155 } 156 } 157 158 free(args.fspec); 159 return 0; 160 } 161 162 static void 163 write_filesystem(struct disklabel *dl, char part) 164 { 165 static char *fsckfmt = "/sbin/fsck -t msdos %s >/dev/null"; 166 struct msdosfs_args args; 167 char cmd[60]; 168 char dst[PATH_MAX]; 169 size_t mntlen; 170 int rslt; 171 172 /* Create directory for temporary mount point. */ 173 strlcpy(dst, "/tmp/installboot.XXXXXXXXXX", sizeof(dst)); 174 if (mkdtemp(dst) == NULL) 175 err(1, "mkdtemp('%s') failed", dst); 176 mntlen = strlen(dst); 177 178 /* Mount <duid>.<part> as msdos filesystem. */ 179 memset(&args, 0, sizeof(args)); 180 rslt = asprintf(&args.fspec, 181 "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx.%c", 182 dl->d_uid[0], dl->d_uid[1], dl->d_uid[2], dl->d_uid[3], 183 dl->d_uid[4], dl->d_uid[5], dl->d_uid[6], dl->d_uid[7], 184 part); 185 if (rslt == -1) { 186 warn("bad special device"); 187 goto rmdir; 188 } 189 190 args.export_info.ex_root = -2; 191 args.export_info.ex_flags = 0; 192 args.flags = MSDOSFSMNT_LONGNAME; 193 194 if (mount(MOUNT_MSDOS, dst, 0, &args) == -1) { 195 /* Try fsck'ing it. */ 196 rslt = snprintf(cmd, sizeof(cmd), fsckfmt, args.fspec); 197 if (rslt >= sizeof(cmd)) { 198 warnx("can't build fsck command"); 199 rslt = -1; 200 goto rmdir; 201 } 202 rslt = system(cmd); 203 if (rslt == -1) { 204 warn("system('%s') failed", cmd); 205 goto rmdir; 206 } 207 if (mount(MOUNT_MSDOS, dst, 0, &args) == -1) { 208 /* Try newfs'ing it. */ 209 rslt = create_filesystem(dl, part); 210 if (rslt == -1) 211 goto rmdir; 212 rslt = mount(MOUNT_MSDOS, dst, 0, &args); 213 if (rslt == -1) { 214 warn("unable to mount MSDOS partition"); 215 goto rmdir; 216 } 217 } 218 } 219 220 /* 221 * Copy /usr/mdec/boot to /mnt/boot. 222 */ 223 if (strlcat(dst, "/boot", sizeof(dst)) >= sizeof(dst)) { 224 rslt = -1; 225 warn("unable to build /boot path"); 226 goto umount; 227 } 228 if (verbose) 229 fprintf(stderr, "%s %s to %s\n", 230 (nowrite ? "would copy" : "copying"), stage1, dst); 231 if (!nowrite) { 232 rslt = filecopy(stage1, dst); 233 if (rslt == -1) 234 goto umount; 235 } 236 237 rslt = 0; 238 239 umount: 240 dst[mntlen] = '\0'; 241 if (unmount(dst, MNT_FORCE) == -1) 242 err(1, "unmount('%s') failed", dst); 243 244 rmdir: 245 free(args.fspec); 246 dst[mntlen] = '\0'; 247 if (rmdir(dst) == -1) 248 err(1, "rmdir('%s') failed", dst); 249 250 if (rslt == -1) 251 exit(1); 252 } 253 254 int 255 findmbrfat(int devfd, struct disklabel *dl) 256 { 257 struct dos_partition dp[NDOSPART]; 258 ssize_t len; 259 u_int64_t start = 0; 260 int i; 261 u_int8_t *secbuf; 262 263 if ((secbuf = malloc(dl->d_secsize)) == NULL) 264 err(1, NULL); 265 266 /* Read MBR. */ 267 len = pread(devfd, secbuf, dl->d_secsize, 0); 268 if (len != dl->d_secsize) 269 err(4, "can't read mbr"); 270 memcpy(dp, &secbuf[DOSPARTOFF], sizeof(dp)); 271 272 for (i = 0; i < NDOSPART; i++) { 273 if (dp[i].dp_typ == DOSPTYP_UNUSED) 274 continue; 275 if (dp[i].dp_typ == DOSPTYP_FAT16L || 276 dp[i].dp_typ == DOSPTYP_FAT32L || 277 dp[i].dp_typ == DOSPTYP_FAT16B) 278 start = letoh32(dp[i].dp_start); 279 } 280 281 free(secbuf); 282 283 if (start) { 284 for (i = 0; i < MAXPARTITIONS; i++) { 285 if (DL_GETPSIZE(&dl->d_partitions[i]) > 0 && 286 DL_GETPOFFSET(&dl->d_partitions[i]) == start) 287 return ('a' + i); 288 } 289 } 290 291 return (-1); 292 } 293