boot98cfg.c revision 110678
1/* 2 * Copyright (c) KATO Takenori, 2000. 3 * 4 * All rights reserved. Unpublished rights reserved under the copyright 5 * laws of Japan. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer as 13 * the first lines of this file unmodified. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. The name of the author may not be used to endorse or promote products 18 * derived from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 * 31 * $FreeBSD: head/usr.sbin/boot98cfg/boot98cfg.c 110678 2003-02-11 07:29:14Z nyan $ 32 */ 33 34/* 35 * Copyright (c) 1999 Robert Nordier 36 * All rights reserved. 37 * 38 * Redistribution and use in source and binary forms, with or without 39 * modification, are permitted provided that the following conditions 40 * are met: 41 * 1. Redistributions of source code must retain the above copyright 42 * notice, this list of conditions and the following disclaimer. 43 * 2. Redistributions in binary form must reproduce the above copyright 44 * notice, this list of conditions and the following disclaimer in the 45 * documentation and/or other materials provided with the distribution. 46 * 47 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS``AS IS'' AND 48 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 50 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS 51 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 52 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 53 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 54 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 55 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 56 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 57 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 58 */ 59 60#include <sys/param.h> 61#include <sys/stat.h> 62#include <sys/diskpc98.h> 63 64#include <err.h> 65#include <errno.h> 66#include <fcntl.h> 67#include <paths.h> 68#include <stdio.h> 69#include <stdlib.h> 70#include <string.h> 71#include <unistd.h> 72 73#define BOOTSIZE 0x2000 74#define IPLSIZE 512 /* IPL size */ 75#define BOOTMENUSIZE 7168 /* Max HDD boot menu size */ 76#define BOOTMENUOFF 0x400 77 78static char *mkrdev(char *); 79static void usage(void); 80static int read_boot(const char *, u_char *); 81static int write_boot(const char *, u_char *); 82 83u_char boot0buf[BOOTSIZE]; 84u_char ipl[IPLSIZE]; 85u_char menu[BOOTMENUSIZE]; 86 87/* 88 * Produce a device path for a "canonical" name, where appropriate. 89 */ 90static char * 91mkrdev(char *fname) 92{ 93 char buf[MAXPATHLEN]; 94 struct stat sb; 95 char *s; 96 97 s = (char *)fname; 98 if (!strchr(fname, '/')) { 99 snprintf(buf, sizeof(buf), "%sr%s", _PATH_DEV, fname); 100 if (stat(buf, &sb)) 101 snprintf(buf, sizeof(buf), "%s%s", _PATH_DEV, fname); 102 if (!(s = strdup(buf))) 103 err(1, NULL); 104 } 105 return s; 106} 107 108static void 109usage(void) 110{ 111 fprintf(stderr, 112 "boot98cfg [-B][-i boot0][-m boot0.5][-s secsize][-v version]\n" 113 " [-f ipl.bak][-F menu.bak] disk\n"); 114 exit(1); 115} 116 117static int 118read_boot(const char *disk, u_char *boot) 119{ 120 int fd, n; 121 122 /* Read IPL, partition table and HDD boot menu. */ 123 fd = open(disk, O_RDONLY); 124 if (fd < 0) 125 err(1, "%s", disk); 126 n = read(fd, boot, BOOTSIZE); 127 if (n != BOOTSIZE) 128 errx(1, "%s: short read", disk); 129 close(fd); 130 131 return 0; 132} 133 134static int 135write_boot(const char *disk, u_char *boot) 136{ 137 int fd, n, i; 138 char buf[MAXPATHLEN]; 139 140 fd = open(disk, O_RDWR); 141 if (fd != -1) { 142 if (lseek(fd, 0, SEEK_SET) == -1) 143 err(1, "%s", disk); 144 if ((n = write(fd, boot, BOOTSIZE)) < 0) 145 err(1, "%s", disk); 146 if (n != BOOTSIZE) 147 errx(1, "%s: short write", disk); 148 close(fd); 149 return 0; 150 } 151 152 for (i = 0; i < NDOSPART; i++) { 153 snprintf(buf, sizeof(buf), "%ss%d", disk, i + 1); 154 fd = open(buf, O_RDONLY); 155 if (fd < 0) 156 continue; 157 n = ioctl(fd, DIOCGPC98, boot); 158 if (n != 0) 159 err(1, "%s: ioctl DIOCGPC98", disk); 160 close(fd); 161 return 0; 162 } 163 164 err(1, "%s", disk); 165} 166 167int 168main(int argc, char *argv[]) 169{ 170 char *endptr; 171 const char *iplpath = "/boot/boot0", *menupath = "/boot/boot0.5"; 172 char *iplbakpath = NULL, *menubakpath = NULL; 173 char *disk; 174 int B_flag = 0; 175 int c; 176 int fd1; 177 int n; 178 int secsize = 512; 179 int v_flag = 0, version; 180 181 while ((c = getopt(argc, argv, "BF:f:i:m:s:v:")) != -1) { 182 switch (c) { 183 case 'B': 184 B_flag = 1; 185 break; 186 case 'F': 187 menubakpath = optarg; 188 break; 189 case 'f': 190 iplbakpath = optarg; 191 break; 192 case 'i': 193 iplpath = optarg; 194 break; 195 case 'm': 196 menupath = optarg; 197 break; 198 case 's': 199 secsize = strtol(optarg, &endptr, 0); 200 if (errno || *optarg == NULL || *endptr) 201 errx(1, "%s: Bad argument to -s option", 202 optarg); 203 switch (secsize) { 204 case 256: 205 case 512: 206 case 1024: 207 case 2048: 208 break; 209 default: 210 errx(1, "%s: unsupported sector size", optarg); 211 break; 212 } 213 break; 214 case 'v': 215 v_flag = 1; 216 version = strtol(optarg, &endptr, 0); 217 if (errno || *optarg == NULL || *endptr || 218 version < 0 || version > 255) 219 errx(1, "%s: Bad argument to -s option", 220 optarg); 221 break; 222 default: 223 usage(); 224 /* NOTREACHED */ 225 break; 226 } 227 } 228 argc -= optind; 229 argv += optind; 230 if (argc != 1) 231 usage(); 232 disk = mkrdev(*argv); 233 234 read_boot(disk, boot0buf); 235 236 if (iplbakpath != NULL) { 237 fd1 = open(iplbakpath, O_WRONLY | O_CREAT | O_TRUNC, 0666); 238 if (fd1 < 0) 239 err(1, "%s", iplbakpath); 240 n = write(fd1, boot0buf, IPLSIZE); 241 if (n == -1) 242 err(1, "%s", iplbakpath); 243 if (n != IPLSIZE) 244 errx(1, "%s: short write", iplbakpath); 245 close(fd1); 246 } 247 248 if (menubakpath != NULL) { 249 fd1 = open(menubakpath, O_WRONLY | O_CREAT | O_TRUNC, 0666); 250 if (fd1 < 0) 251 err(1, "%s", menubakpath); 252 n = write(fd1, boot0buf + BOOTMENUOFF, BOOTMENUSIZE); 253 if (n == -1) 254 err(1, "%s", menubakpath); 255 if (n != BOOTMENUSIZE) 256 errx(1, "%s: short write", menubakpath); 257 close(fd1); 258 } 259 260 if (B_flag) { 261 /* Read IPL (boot0). */ 262 fd1 = open(iplpath, O_RDONLY); 263 if (fd1 < 0) 264 err(1, "%s", disk); 265 n = read(fd1, ipl, IPLSIZE); 266 if (n < 0) 267 err(1, "%s", iplpath); 268 if (n != IPLSIZE) 269 errx(1, "%s: invalid file", iplpath); 270 close(fd1); 271 272 /* Read HDD boot menu (boot0.5). */ 273 fd1 = open(menupath, O_RDONLY); 274 if (fd1 < 0) 275 err(1, "%s", disk); 276 n = read(fd1, menu, BOOTMENUSIZE); 277 if (n < 0) 278 err(1, "%s", menupath); 279 if (n != BOOTMENUSIZE) 280 errx(1, "%s: invalid file", menupath); 281 close(fd1); 282 283 memcpy(boot0buf, ipl, IPLSIZE); 284 memcpy(boot0buf + BOOTMENUOFF, menu, BOOTMENUSIZE); 285 } 286 287 /* Set version number field. */ 288 if (v_flag) 289 *(boot0buf + secsize - 4) = (u_char)version; 290 291 if (B_flag || v_flag) 292 write_boot(disk, boot0buf); 293 294 return 0; 295} 296