boot0cfg.c revision 44197
1/* 2 * Copyright (c) 1999 Robert Nordier 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS 18 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 19 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 20 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 21 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 23 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 24 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#ifndef lint 28static const char rcsid[] = 29"$Id: $"; 30#endif /* not lint */ 31 32#include <sys/param.h> 33#include <sys/disklabel.h> 34#include <sys/stat.h> 35 36#include <err.h> 37#include <errno.h> 38#include <fcntl.h> 39#include <paths.h> 40#include <stdio.h> 41#include <stdlib.h> 42#include <string.h> 43#include <unistd.h> 44 45#define MBRSIZE 512 /* master boot record size */ 46 47#define OFF_FLAGS 0x1bb /* offset: option flags */ 48#define OFF_TICKS 0x1bc /* offset: clock ticks */ 49#define OFF_PTBL 0x1be /* offset: partition table */ 50#define OFF_MAGIC 0x1fe /* offset: magic number */ 51 52#define cv2(p) ((p)[0] | (p)[1] << 010) 53 54#define mk2(p, x) \ 55 (p)[0] = (u_int8_t)(x), \ 56 (p)[1] = (u_int8_t)((x) >> 010) 57 58static const struct { 59 const char *tok; 60 int def; 61} opttbl[] = { 62 {"packet", 0}, 63 {"update", 1}, 64 {"setdrv", 0} 65}; 66static const int nopt = sizeof(opttbl) / sizeof(opttbl[0]); 67 68static const char fmt0[] = "# flag start chs type" 69 " end chs offset size\n"; 70 71static const char fmt1[] = "%d 0x%02x %4u:%3u:%2u 0x%02x" 72 " %4u:%3u:%2u %10u %10u\n"; 73 74static void stropt(const char *, int *, int *); 75static char *mkrdev(const char *); 76static int argtoi(const char *, int, int, int); 77static void usage(void); 78 79int 80main(int argc, char *argv[]) 81{ 82 u_int8_t buf[MBRSIZE]; 83 struct dos_partition part[4]; 84 const char *bpath, *fpath, *disk; 85 ssize_t n; 86 int B_flag, v_flag, o_flag; 87 int d_arg, t_arg; 88 int o_and, o_or; 89 int fd, fd1, up, c, i; 90 91 bpath = "/boot/boot0"; 92 fpath = NULL; 93 B_flag = v_flag = o_flag = 0; 94 d_arg = t_arg = -1; 95 o_and = 0xff; 96 o_or = 0; 97 while ((c = getopt(argc, argv, "Bvb:d:f:o:t:")) != -1) 98 switch (c) { 99 case 'B': 100 B_flag = 1; 101 break; 102 case 'v': 103 v_flag = 1; 104 break; 105 case 'b': 106 bpath = optarg; 107 break; 108 case 'd': 109 d_arg = argtoi(optarg, 0, 0xff, 'd'); 110 break; 111 case 'f': 112 fpath = optarg; 113 break; 114 case 'o': 115 stropt(optarg, &o_and, &o_or); 116 o_flag = 1; 117 break; 118 case 't': 119 t_arg = argtoi(optarg, 1, 0xffff, 't'); 120 break; 121 default: 122 usage(); 123 } 124 argc -= optind; 125 argv += optind; 126 if (argc != 1) 127 usage(); 128 disk = mkrdev(*argv); 129 up = B_flag || d_arg || o_flag || t_arg; 130 if ((fd = open(disk, up ? O_RDWR : O_RDONLY)) == -1) 131 err(1, "%s", disk); 132 if ((n = read(fd, buf, MBRSIZE)) == -1) 133 err(1, "%s", disk); 134 if (n != MBRSIZE) 135 errx(1, "%s: short read", disk); 136 if (cv2(buf + OFF_MAGIC) != 0xaa55) 137 errx(1, "%s: bad magic", disk); 138 if (fpath) { 139 if ((fd1 = open(fpath, O_WRONLY | O_CREAT | O_TRUNC, 140 0666)) == -1 || 141 (n = write(fd1, buf, MBRSIZE)) == -1 || close(fd1)) 142 err(1, "%s", fpath); 143 if (n != MBRSIZE) 144 errx(1, "%s: short write", fpath); 145 } 146 memcpy(part, buf + OFF_PTBL, sizeof(part)); 147 if (B_flag) { 148 if ((fd1 = open(bpath, O_RDONLY)) == -1 || 149 (n = read(fd1, buf, MBRSIZE)) == -1 || close(fd1)) 150 err(1, "%s", bpath); 151 if (n != MBRSIZE) 152 errx(1, "%s: short read", bpath); 153 if (cv2(buf + OFF_MAGIC) != 0xaa55) 154 errx(1, "%s: bad magic", bpath); 155 memcpy(buf + OFF_PTBL, part, sizeof(part)); 156 } 157 if (o_flag) { 158 buf[OFF_FLAGS] &= o_and; 159 buf[OFF_FLAGS] |= o_or; 160 } 161 if (t_arg != -1) 162 mk2(buf + OFF_TICKS, t_arg); 163 if (up) { 164 if (lseek(fd, 0, SEEK_SET) == -1 || 165 (n = write(fd, buf, MBRSIZE)) == -1 || close(fd)) 166 err(1, "%s", disk); 167 if (n != MBRSIZE) 168 errx(1, "%s: short write", disk); 169 } 170 if (v_flag) { 171 printf(fmt0); 172 for (i = 0; i < 4; i++) 173 if (part[i].dp_typ) { 174 printf(fmt1, 175 1 + i, 176 part[i].dp_flag, 177 part[i].dp_scyl + ((part[i].dp_ssect & 0xc0) << 2), 178 part[i].dp_shd, 179 part[i].dp_ssect & 0x3f, 180 part[i].dp_typ, 181 part[i].dp_ecyl + ((part[i].dp_esect & 0xc0) << 2), 182 part[i].dp_ehd, 183 part[i].dp_esect & 0x3f, 184 part[i].dp_start, 185 part[i].dp_size); 186 } 187 printf("\n"); 188 printf("drive=0x0 options="); 189 for (i = 0; i < nopt; i++) { 190 if (i) 191 printf(","); 192 if (!(buf[OFF_FLAGS] & 1 << (7 - i)) ^ opttbl[i].def) 193 printf("no"); 194 printf("%s", opttbl[i].tok); 195 } 196 printf(" ticks=%u\n", cv2(buf + OFF_TICKS)); 197 } 198 return 0; 199} 200 201static void 202stropt(const char *arg, int *xa, int *xo) 203{ 204 const char *q; 205 char *s, *s1; 206 int inv, i, x; 207 208 if (!(s = strdup(arg))) 209 err(1, NULL); 210 for (s1 = s; (q = strtok(s1, ",")); s1 = NULL) { 211 if ((inv = !strncmp(q, "no", 2))) 212 q += 2; 213 for (i = 0; i < nopt; i++) 214 if (!strcmp(q, opttbl[i].tok)) 215 break; 216 if (i == nopt) 217 errx(1, "%s: Unknown -o option", q); 218 if (opttbl[i].def) 219 inv ^= 1; 220 x = 1 << (7 - i); 221 if (inv) 222 *xa &= ~x; 223 else 224 *xo |= x; 225 } 226 free(s); 227} 228 229static char * 230mkrdev(const char *fname) 231{ 232 char buf[MAXPATHLEN]; 233 struct stat sb; 234 char *s; 235 236 s = (char *) fname; 237 if (!strchr(fname, '/')) { 238 snprintf(buf, sizeof(buf), "%sr%s", _PATH_DEV, fname); 239 if (stat(buf, &sb)) 240 snprintf(buf, sizeof(buf), "%s%s", _PATH_DEV, fname); 241 if (!(s = strdup(buf))) 242 err(1, NULL); 243 } 244 return s; 245} 246 247static int 248argtoi(const char *arg, int lo, int hi, int opt) 249{ 250 char *s; 251 long x; 252 253 errno = 0; 254 x = strtol(arg, &s, 0); 255 if (errno || !*arg || *s || x < lo || x > hi) 256 errx(1, "%s: Bad argument to -%c option", arg, opt); 257 return x; 258} 259 260static void 261usage(void) 262{ 263 fprintf(stderr, "%s\n%s\n", 264 "usage: boot0cfg [-Bv] [-b boot0] [-d drive] [-f file] [-o options]", 265 " [-t ticks] disk"); 266 exit(1); 267} 268