10b654f60SRobert Nordier /* 20b654f60SRobert Nordier * Copyright (c) 1999 Robert Nordier 30b654f60SRobert Nordier * All rights reserved. 40b654f60SRobert Nordier * 50b654f60SRobert Nordier * Redistribution and use in source and binary forms, with or without 60b654f60SRobert Nordier * modification, are permitted provided that the following conditions 70b654f60SRobert Nordier * are met: 80b654f60SRobert Nordier * 1. Redistributions of source code must retain the above copyright 90b654f60SRobert Nordier * notice, this list of conditions and the following disclaimer. 100b654f60SRobert Nordier * 2. Redistributions in binary form must reproduce the above copyright 110b654f60SRobert Nordier * notice, this list of conditions and the following disclaimer in the 120b654f60SRobert Nordier * documentation and/or other materials provided with the distribution. 130b654f60SRobert Nordier * 140b654f60SRobert Nordier * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS``AS IS'' AND 150b654f60SRobert Nordier * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 160b654f60SRobert Nordier * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 170b654f60SRobert Nordier * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS 180b654f60SRobert Nordier * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 190b654f60SRobert Nordier * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 200b654f60SRobert Nordier * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 210b654f60SRobert Nordier * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 220b654f60SRobert Nordier * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 230b654f60SRobert Nordier * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 240b654f60SRobert Nordier * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 250b654f60SRobert Nordier */ 260b654f60SRobert Nordier 270b654f60SRobert Nordier #ifndef lint 280b654f60SRobert Nordier static const char rcsid[] = 2997d92980SPeter Wemm "$FreeBSD$"; 300b654f60SRobert Nordier #endif /* not lint */ 310b654f60SRobert Nordier 320b654f60SRobert Nordier #include <sys/param.h> 330b654f60SRobert Nordier #include <sys/disklabel.h> 340b654f60SRobert Nordier #include <sys/stat.h> 350b654f60SRobert Nordier 360b654f60SRobert Nordier #include <err.h> 370b654f60SRobert Nordier #include <errno.h> 380b654f60SRobert Nordier #include <fcntl.h> 390b654f60SRobert Nordier #include <paths.h> 400b654f60SRobert Nordier #include <stdio.h> 410b654f60SRobert Nordier #include <stdlib.h> 420b654f60SRobert Nordier #include <string.h> 430b654f60SRobert Nordier #include <unistd.h> 440b654f60SRobert Nordier 450b654f60SRobert Nordier #define MBRSIZE 512 /* master boot record size */ 460b654f60SRobert Nordier 47226ae6ffSJohn Baldwin #define OFF_VERSION 0x1b0 /* offset: version number */ 48ee6fb785SRobert Nordier #define OFF_DRIVE 0x1ba /* offset: setdrv drive */ 490b654f60SRobert Nordier #define OFF_FLAGS 0x1bb /* offset: option flags */ 500b654f60SRobert Nordier #define OFF_TICKS 0x1bc /* offset: clock ticks */ 510b654f60SRobert Nordier #define OFF_PTBL 0x1be /* offset: partition table */ 520b654f60SRobert Nordier #define OFF_MAGIC 0x1fe /* offset: magic number */ 530b654f60SRobert Nordier 540b654f60SRobert Nordier #define cv2(p) ((p)[0] | (p)[1] << 010) 550b654f60SRobert Nordier 560b654f60SRobert Nordier #define mk2(p, x) \ 570b654f60SRobert Nordier (p)[0] = (u_int8_t)(x), \ 580b654f60SRobert Nordier (p)[1] = (u_int8_t)((x) >> 010) 590b654f60SRobert Nordier 600b654f60SRobert Nordier static const struct { 610b654f60SRobert Nordier const char *tok; 620b654f60SRobert Nordier int def; 630b654f60SRobert Nordier } opttbl[] = { 640b654f60SRobert Nordier {"packet", 0}, 650b654f60SRobert Nordier {"update", 1}, 660b654f60SRobert Nordier {"setdrv", 0} 670b654f60SRobert Nordier }; 680b654f60SRobert Nordier static const int nopt = sizeof(opttbl) / sizeof(opttbl[0]); 690b654f60SRobert Nordier 700b654f60SRobert Nordier static const char fmt0[] = "# flag start chs type" 710b654f60SRobert Nordier " end chs offset size\n"; 720b654f60SRobert Nordier 730b654f60SRobert Nordier static const char fmt1[] = "%d 0x%02x %4u:%3u:%2u 0x%02x" 740b654f60SRobert Nordier " %4u:%3u:%2u %10u %10u\n"; 750b654f60SRobert Nordier 76c5dc421fSJohn Baldwin static int read_mbr(const char *, u_int8_t **, int); 77c5dc421fSJohn Baldwin static void write_mbr(const char *, int, u_int8_t *, int); 78c5dc421fSJohn Baldwin static void display_mbr(u_int8_t *); 79226ae6ffSJohn Baldwin static int boot0version(const u_int8_t *); 80d1306cd8SRobert Nordier static int boot0bs(const u_int8_t *); 810b654f60SRobert Nordier static void stropt(const char *, int *, int *); 820b654f60SRobert Nordier static char *mkrdev(const char *); 830b654f60SRobert Nordier static int argtoi(const char *, int, int, int); 840b654f60SRobert Nordier static void usage(void); 850b654f60SRobert Nordier 86d1306cd8SRobert Nordier /* 87d1306cd8SRobert Nordier * Boot manager installation/configuration utility. 88d1306cd8SRobert Nordier */ 890b654f60SRobert Nordier int 900b654f60SRobert Nordier main(int argc, char *argv[]) 910b654f60SRobert Nordier { 92c5dc421fSJohn Baldwin u_int8_t *mbr, *boot0; 93c5dc421fSJohn Baldwin int boot0_size, mbr_size; 940b654f60SRobert Nordier const char *bpath, *fpath, *disk; 950b654f60SRobert Nordier int B_flag, v_flag, o_flag; 965868a099SRobert Nordier int d_arg, m_arg, t_arg; 970b654f60SRobert Nordier int o_and, o_or; 98c5dc421fSJohn Baldwin int up, c; 990b654f60SRobert Nordier 1000b654f60SRobert Nordier bpath = "/boot/boot0"; 1010b654f60SRobert Nordier fpath = NULL; 1020b654f60SRobert Nordier B_flag = v_flag = o_flag = 0; 1035868a099SRobert Nordier d_arg = m_arg = t_arg = -1; 1040b654f60SRobert Nordier o_and = 0xff; 1050b654f60SRobert Nordier o_or = 0; 1065868a099SRobert Nordier while ((c = getopt(argc, argv, "Bvb:d:f:m:o:t:")) != -1) 1070b654f60SRobert Nordier switch (c) { 1080b654f60SRobert Nordier case 'B': 1090b654f60SRobert Nordier B_flag = 1; 1100b654f60SRobert Nordier break; 1110b654f60SRobert Nordier case 'v': 1120b654f60SRobert Nordier v_flag = 1; 1130b654f60SRobert Nordier break; 1140b654f60SRobert Nordier case 'b': 1150b654f60SRobert Nordier bpath = optarg; 1160b654f60SRobert Nordier break; 1170b654f60SRobert Nordier case 'd': 1180b654f60SRobert Nordier d_arg = argtoi(optarg, 0, 0xff, 'd'); 1190b654f60SRobert Nordier break; 1200b654f60SRobert Nordier case 'f': 1210b654f60SRobert Nordier fpath = optarg; 1220b654f60SRobert Nordier break; 1235868a099SRobert Nordier case 'm': 1245868a099SRobert Nordier m_arg = argtoi(optarg, 0, 0xf, 'm'); 1255868a099SRobert Nordier break; 1260b654f60SRobert Nordier case 'o': 1270b654f60SRobert Nordier stropt(optarg, &o_and, &o_or); 1280b654f60SRobert Nordier o_flag = 1; 1290b654f60SRobert Nordier break; 1300b654f60SRobert Nordier case 't': 1310b654f60SRobert Nordier t_arg = argtoi(optarg, 1, 0xffff, 't'); 1320b654f60SRobert Nordier break; 1330b654f60SRobert Nordier default: 1340b654f60SRobert Nordier usage(); 1350b654f60SRobert Nordier } 1360b654f60SRobert Nordier argc -= optind; 1370b654f60SRobert Nordier argv += optind; 1380b654f60SRobert Nordier if (argc != 1) 1390b654f60SRobert Nordier usage(); 1400b654f60SRobert Nordier disk = mkrdev(*argv); 1410fdf16a3SRobert Nordier up = B_flag || d_arg != -1 || m_arg != -1 || o_flag || t_arg != -1; 142c5dc421fSJohn Baldwin 143c5dc421fSJohn Baldwin /* open the disk and read in the existing mbr */ 144c5dc421fSJohn Baldwin mbr_size = read_mbr(disk, &mbr, !B_flag); 145c5dc421fSJohn Baldwin 146c5dc421fSJohn Baldwin /* save the existing MBR if we are asked to do so */ 147c5dc421fSJohn Baldwin if (fpath) 148c5dc421fSJohn Baldwin write_mbr(fpath, O_CREAT | O_TRUNC, mbr, mbr_size); 149c5dc421fSJohn Baldwin 150c5dc421fSJohn Baldwin /* 151c5dc421fSJohn Baldwin * If we are installing the boot loader, read it from disk and copy the 152c5dc421fSJohn Baldwin * slice table over from the existing MBR. If not, then point boot0 153c5dc421fSJohn Baldwin * back at the MBR we just read in. After this, boot0 is the data to 154c5dc421fSJohn Baldwin * write back to disk if we are going to do a write. 155c5dc421fSJohn Baldwin */ 1560b654f60SRobert Nordier if (B_flag) { 157c5dc421fSJohn Baldwin boot0_size = read_mbr(bpath, &boot0, 1); 158c5dc421fSJohn Baldwin memcpy(boot0 + OFF_PTBL, mbr + OFF_PTBL, 159c5dc421fSJohn Baldwin sizeof(struct dos_partition) * NDOSPART); 160c5dc421fSJohn Baldwin } else { 161c5dc421fSJohn Baldwin boot0 = mbr; 162c5dc421fSJohn Baldwin boot0_size = mbr_size; 1630b654f60SRobert Nordier } 164c5dc421fSJohn Baldwin 165c5dc421fSJohn Baldwin /* set the drive */ 166ee6fb785SRobert Nordier if (d_arg != -1) 167226ae6ffSJohn Baldwin boot0[OFF_DRIVE] = d_arg; 168c5dc421fSJohn Baldwin 169c5dc421fSJohn Baldwin /* set various flags */ 1705868a099SRobert Nordier if (m_arg != -1) { 171226ae6ffSJohn Baldwin boot0[OFF_FLAGS] &= 0xf0; 172226ae6ffSJohn Baldwin boot0[OFF_FLAGS] |= m_arg; 1735868a099SRobert Nordier } 1740b654f60SRobert Nordier if (o_flag) { 175226ae6ffSJohn Baldwin boot0[OFF_FLAGS] &= o_and; 176226ae6ffSJohn Baldwin boot0[OFF_FLAGS] |= o_or; 1770b654f60SRobert Nordier } 178c5dc421fSJohn Baldwin 179c5dc421fSJohn Baldwin /* set the timeout */ 1800b654f60SRobert Nordier if (t_arg != -1) 181226ae6ffSJohn Baldwin mk2(boot0 + OFF_TICKS, t_arg); 182c5dc421fSJohn Baldwin 183c5dc421fSJohn Baldwin /* write the MBR back to disk */ 184c5dc421fSJohn Baldwin if (up) 185c5dc421fSJohn Baldwin write_mbr(disk, 0, boot0, boot0_size); 186c5dc421fSJohn Baldwin 187c5dc421fSJohn Baldwin /* display the MBR */ 188c5dc421fSJohn Baldwin if (v_flag) 189c5dc421fSJohn Baldwin display_mbr(boot0); 190c5dc421fSJohn Baldwin 191c5dc421fSJohn Baldwin /* clean up */ 192c5dc421fSJohn Baldwin if (mbr != boot0) 193c5dc421fSJohn Baldwin free(boot0); 194c5dc421fSJohn Baldwin free(mbr); 195c5dc421fSJohn Baldwin 196c5dc421fSJohn Baldwin return 0; 197c5dc421fSJohn Baldwin } 198c5dc421fSJohn Baldwin 199c5dc421fSJohn Baldwin /* 200c5dc421fSJohn Baldwin * Read in the MBR of the disk. If it is boot0, then use the version to 201c5dc421fSJohn Baldwin * read in all of it if necessary. Use pointers to return a malloc'd 202c5dc421fSJohn Baldwin * buffer containing the MBR and then return its size. 203c5dc421fSJohn Baldwin */ 204c5dc421fSJohn Baldwin static int 205c5dc421fSJohn Baldwin read_mbr(const char *disk, u_int8_t **mbr, int check_version) 206c5dc421fSJohn Baldwin { 207c5dc421fSJohn Baldwin u_int8_t buf[MBRSIZE]; 208c5dc421fSJohn Baldwin int mbr_size, fd; 209c5dc421fSJohn Baldwin ssize_t n; 210c5dc421fSJohn Baldwin 211c5dc421fSJohn Baldwin if ((fd = open(disk, O_RDONLY)) == -1) 2120b654f60SRobert Nordier err(1, "%s", disk); 213c5dc421fSJohn Baldwin if ((n = read(fd, buf, MBRSIZE)) == -1) 214c5dc421fSJohn Baldwin err(1, "%s", disk); 215c5dc421fSJohn Baldwin if (n != MBRSIZE) 216c5dc421fSJohn Baldwin errx(1, "%s: short read", disk); 217c5dc421fSJohn Baldwin if (cv2(buf + OFF_MAGIC) != 0xaa55) 218c5dc421fSJohn Baldwin errx(1, "%s: bad magic", disk); 219c5dc421fSJohn Baldwin 220c5dc421fSJohn Baldwin if (!boot0bs(buf)) { 221c5dc421fSJohn Baldwin if (check_version) 222c5dc421fSJohn Baldwin errx(1, "%s: unknown or incompatible boot code", disk); 223c5dc421fSJohn Baldwin } else if (boot0version(buf) == 0x101) { 224c5dc421fSJohn Baldwin mbr_size = 1024; 225c5dc421fSJohn Baldwin if ((*mbr = malloc(mbr_size)) == NULL) 226c5dc421fSJohn Baldwin errx(1, "%s: unable to allocate read buffer", disk); 227c5dc421fSJohn Baldwin if (lseek(fd, 0, SEEK_SET) == -1 || 228c5dc421fSJohn Baldwin (n = read(fd, *mbr, mbr_size)) == -1) 229c5dc421fSJohn Baldwin err(1, "%s", disk); 230c5dc421fSJohn Baldwin if (n != mbr_size) 231c5dc421fSJohn Baldwin errx(1, "%s: short read", disk); 232c5dc421fSJohn Baldwin return (mbr_size); 2330b654f60SRobert Nordier } 234c5dc421fSJohn Baldwin *mbr = malloc(sizeof(buf)); 235c5dc421fSJohn Baldwin memcpy(*mbr, buf, sizeof(buf)); 236c5dc421fSJohn Baldwin 237c5dc421fSJohn Baldwin return sizeof(buf); 238c5dc421fSJohn Baldwin } 239c5dc421fSJohn Baldwin 240c5dc421fSJohn Baldwin /* 241c5dc421fSJohn Baldwin * Write out the mbr to the specified file. 242c5dc421fSJohn Baldwin */ 243c5dc421fSJohn Baldwin static void 244c5dc421fSJohn Baldwin write_mbr(const char *fname, int flags, u_int8_t *mbr, int mbr_size) 245c5dc421fSJohn Baldwin { 246c5dc421fSJohn Baldwin int fd; 247c5dc421fSJohn Baldwin ssize_t n; 248c5dc421fSJohn Baldwin 249c5dc421fSJohn Baldwin if ((fd = open(fname, O_WRONLY | flags, 0666)) == -1 || 250c5dc421fSJohn Baldwin (n = write(fd, mbr, mbr_size)) == -1 || close(fd)) 251c5dc421fSJohn Baldwin err(1, "%s", fname); 252c5dc421fSJohn Baldwin if (n != mbr_size) 253c5dc421fSJohn Baldwin errx(1, "%s: short write", fname); 254c5dc421fSJohn Baldwin } 255c5dc421fSJohn Baldwin 256c5dc421fSJohn Baldwin /* 257c5dc421fSJohn Baldwin * Outputs an informative dump of the data in the MBR to stdout. 258c5dc421fSJohn Baldwin */ 259c5dc421fSJohn Baldwin static void 260c5dc421fSJohn Baldwin display_mbr(u_int8_t *mbr) 261c5dc421fSJohn Baldwin { 262c5dc421fSJohn Baldwin struct dos_partition *part; 263c5dc421fSJohn Baldwin int i, version; 264c5dc421fSJohn Baldwin 265c5dc421fSJohn Baldwin part = (struct dos_partition *)(mbr + DOSPARTOFF); 2660b654f60SRobert Nordier printf(fmt0); 267c5dc421fSJohn Baldwin for (i = 0; i < NDOSPART; i++) 268c5dc421fSJohn Baldwin if (part[i].dp_typ) 269c5dc421fSJohn Baldwin printf(fmt1, 1 + i, part[i].dp_flag, 2700b654f60SRobert Nordier part[i].dp_scyl + ((part[i].dp_ssect & 0xc0) << 2), 271c5dc421fSJohn Baldwin part[i].dp_shd, part[i].dp_ssect & 0x3f, part[i].dp_typ, 2720b654f60SRobert Nordier part[i].dp_ecyl + ((part[i].dp_esect & 0xc0) << 2), 273c5dc421fSJohn Baldwin part[i].dp_ehd, part[i].dp_esect & 0x3f, part[i].dp_start, 2740b654f60SRobert Nordier part[i].dp_size); 2750b654f60SRobert Nordier printf("\n"); 276c5dc421fSJohn Baldwin version = boot0version(mbr); 277226ae6ffSJohn Baldwin printf("version=%d.%d drive=0x%x mask=0x%x ticks=%u\noptions=", 278c5dc421fSJohn Baldwin version >> 8, version & 0xff, mbr[OFF_DRIVE], 279c5dc421fSJohn Baldwin mbr[OFF_FLAGS] & 0xf, cv2(mbr + OFF_TICKS)); 2800b654f60SRobert Nordier for (i = 0; i < nopt; i++) { 2810b654f60SRobert Nordier if (i) 2820b654f60SRobert Nordier printf(","); 283c5dc421fSJohn Baldwin if (!(mbr[OFF_FLAGS] & 1 << (7 - i)) ^ opttbl[i].def) 2840b654f60SRobert Nordier printf("no"); 2850b654f60SRobert Nordier printf("%s", opttbl[i].tok); 2860b654f60SRobert Nordier } 287226ae6ffSJohn Baldwin printf("\n"); 2880b654f60SRobert Nordier } 2890b654f60SRobert Nordier 290d1306cd8SRobert Nordier /* 291226ae6ffSJohn Baldwin * Return the boot0 version with the minor revision in the low byte, and 292226ae6ffSJohn Baldwin * the major revision in the next higher byte. 293226ae6ffSJohn Baldwin */ 294226ae6ffSJohn Baldwin static int 295226ae6ffSJohn Baldwin boot0version(const u_int8_t *bs) 296226ae6ffSJohn Baldwin { 297226ae6ffSJohn Baldwin static u_int8_t idold[] = {0xfe, 0x45, 0xf2, 0xe9, 0x00, 0x8a}; 298226ae6ffSJohn Baldwin 299226ae6ffSJohn Baldwin /* Check for old version, and return 0x100 if found. */ 300226ae6ffSJohn Baldwin if (memcmp(bs + 0x1c, idold, sizeof(idold)) == 0) 301226ae6ffSJohn Baldwin return 0x100; 302226ae6ffSJohn Baldwin 303226ae6ffSJohn Baldwin /* We have a newer boot0, so extract the version number and return it. */ 304226ae6ffSJohn Baldwin return *(int *)(bs + OFF_VERSION) & 0xffff; 305226ae6ffSJohn Baldwin } 306226ae6ffSJohn Baldwin 307226ae6ffSJohn Baldwin /* 308d1306cd8SRobert Nordier * Decide if we have valid boot0 boot code by looking for 309d1306cd8SRobert Nordier * characteristic byte sequences at fixed offsets. 310d1306cd8SRobert Nordier */ 311d1306cd8SRobert Nordier static int 312d1306cd8SRobert Nordier boot0bs(const u_int8_t *bs) 313d1306cd8SRobert Nordier { 314226ae6ffSJohn Baldwin static u_int8_t id0[] = {0xfc, 0x31, 0xc0, 0x8e, 0xc0, 0x8e, 0xd8, 315226ae6ffSJohn Baldwin 0x8e, 0xd0, 0xbc, 0x00, 0x7c }; 316d1306cd8SRobert Nordier static u_int8_t id1[] = {'D', 'r', 'i', 'v', 'e', ' '}; 317d1306cd8SRobert Nordier static struct { 318d1306cd8SRobert Nordier unsigned off; 319d1306cd8SRobert Nordier unsigned len; 320d1306cd8SRobert Nordier u_int8_t *key; 321d1306cd8SRobert Nordier } ident[2] = { 322226ae6ffSJohn Baldwin {0x0, sizeof(id0), id0}, 323d1306cd8SRobert Nordier {0x1b2, sizeof(id1), id1} 324d1306cd8SRobert Nordier }; 325d1306cd8SRobert Nordier int i; 326d1306cd8SRobert Nordier 327d1306cd8SRobert Nordier for (i = 0; i < sizeof(ident) / sizeof(ident[0]); i++) 328c5dc421fSJohn Baldwin if (memcmp(bs + ident[i].off, ident[i].key, ident[i].len)) 329d1306cd8SRobert Nordier return 0; 330d1306cd8SRobert Nordier return 1; 331d1306cd8SRobert Nordier }; 332d1306cd8SRobert Nordier 333d1306cd8SRobert Nordier /* 334d1306cd8SRobert Nordier * Adjust "and" and "or" masks for a -o option argument. 335d1306cd8SRobert Nordier */ 3360b654f60SRobert Nordier static void 3370b654f60SRobert Nordier stropt(const char *arg, int *xa, int *xo) 3380b654f60SRobert Nordier { 3390b654f60SRobert Nordier const char *q; 3400b654f60SRobert Nordier char *s, *s1; 3410b654f60SRobert Nordier int inv, i, x; 3420b654f60SRobert Nordier 3430b654f60SRobert Nordier if (!(s = strdup(arg))) 3440b654f60SRobert Nordier err(1, NULL); 3450b654f60SRobert Nordier for (s1 = s; (q = strtok(s1, ",")); s1 = NULL) { 3460b654f60SRobert Nordier if ((inv = !strncmp(q, "no", 2))) 3470b654f60SRobert Nordier q += 2; 3480b654f60SRobert Nordier for (i = 0; i < nopt; i++) 3490b654f60SRobert Nordier if (!strcmp(q, opttbl[i].tok)) 3500b654f60SRobert Nordier break; 3510b654f60SRobert Nordier if (i == nopt) 3520b654f60SRobert Nordier errx(1, "%s: Unknown -o option", q); 3530b654f60SRobert Nordier if (opttbl[i].def) 3540b654f60SRobert Nordier inv ^= 1; 3550b654f60SRobert Nordier x = 1 << (7 - i); 3560b654f60SRobert Nordier if (inv) 3570b654f60SRobert Nordier *xa &= ~x; 3580b654f60SRobert Nordier else 3590b654f60SRobert Nordier *xo |= x; 3600b654f60SRobert Nordier } 3610b654f60SRobert Nordier free(s); 3620b654f60SRobert Nordier } 3630b654f60SRobert Nordier 364d1306cd8SRobert Nordier /* 365d1306cd8SRobert Nordier * Produce a device path for a "canonical" name, where appropriate. 366d1306cd8SRobert Nordier */ 3670b654f60SRobert Nordier static char * 3680b654f60SRobert Nordier mkrdev(const char *fname) 3690b654f60SRobert Nordier { 3700b654f60SRobert Nordier char buf[MAXPATHLEN]; 3710b654f60SRobert Nordier char *s; 3720b654f60SRobert Nordier 3730b654f60SRobert Nordier s = (char *)fname; 3740b654f60SRobert Nordier if (!strchr(fname, '/')) { 3750b654f60SRobert Nordier snprintf(buf, sizeof(buf), "%s%s", _PATH_DEV, fname); 3760b654f60SRobert Nordier if (!(s = strdup(buf))) 3770b654f60SRobert Nordier err(1, NULL); 3780b654f60SRobert Nordier } 3790b654f60SRobert Nordier return s; 3800b654f60SRobert Nordier } 3810b654f60SRobert Nordier 382d1306cd8SRobert Nordier /* 383d1306cd8SRobert Nordier * Convert and check an option argument. 384d1306cd8SRobert Nordier */ 3850b654f60SRobert Nordier static int 3860b654f60SRobert Nordier argtoi(const char *arg, int lo, int hi, int opt) 3870b654f60SRobert Nordier { 3880b654f60SRobert Nordier char *s; 3890b654f60SRobert Nordier long x; 3900b654f60SRobert Nordier 3910b654f60SRobert Nordier errno = 0; 3920b654f60SRobert Nordier x = strtol(arg, &s, 0); 3930b654f60SRobert Nordier if (errno || !*arg || *s || x < lo || x > hi) 3940b654f60SRobert Nordier errx(1, "%s: Bad argument to -%c option", arg, opt); 3950b654f60SRobert Nordier return x; 3960b654f60SRobert Nordier } 3970b654f60SRobert Nordier 398d1306cd8SRobert Nordier /* 399d1306cd8SRobert Nordier * Display usage information. 400d1306cd8SRobert Nordier */ 4010b654f60SRobert Nordier static void 4020b654f60SRobert Nordier usage(void) 4030b654f60SRobert Nordier { 4040b654f60SRobert Nordier fprintf(stderr, "%s\n%s\n", 4055868a099SRobert Nordier "usage: boot0cfg [-Bv] [-b boot0] [-d drive] [-f file] [-m mask]", 4065868a099SRobert Nordier " [-o options] [-t ticks] disk"); 4070b654f60SRobert Nordier exit(1); 4080b654f60SRobert Nordier } 409