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