/* * Copyright (c) KATO Takenori, 2000. * * All rights reserved. Unpublished rights reserved under the copyright * laws of Japan. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer as * the first lines of this file unmodified. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Copyright (c) 1999 Robert Nordier * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #define BOOTSIZE 0x2000 #define IPLSIZE 512 /* IPL size */ #define BOOTMENUSIZE 7168 /* Max HDD boot menu size */ #define BOOTMENUOFF 0x400 u_char boot0buf[BOOTSIZE]; u_char ipl[IPLSIZE]; u_char menu[BOOTMENUSIZE]; static int read_boot(const char *, u_char *); static int write_boot(const char *, u_char *); static char *mkrdev(const char *); static void usage(void); /* * Boot manager installation/configuration utility. */ int main(int argc, char *argv[]) { char *endptr; const char *iplpath = "/boot/boot0", *menupath = "/boot/boot0.5"; char *iplbakpath = NULL, *menubakpath = NULL; char *disk; int B_flag = 0; int c; int fd1; int n; int secsize = 512; int v_flag = 0, version; while ((c = getopt(argc, argv, "BF:f:i:m:s:v:")) != -1) { switch (c) { case 'B': B_flag = 1; break; case 'F': menubakpath = optarg; break; case 'f': iplbakpath = optarg; break; case 'i': iplpath = optarg; break; case 'm': menupath = optarg; break; case 's': secsize = strtol(optarg, &endptr, 0); if (errno || *optarg == '\0' || *endptr) errx(1, "%s: Bad argument to -s option", optarg); switch (secsize) { case 256: case 512: case 1024: case 2048: break; default: errx(1, "%s: unsupported sector size", optarg); break; } break; case 'v': v_flag = 1; version = strtol(optarg, &endptr, 0); if (errno || *optarg == '\0' || *endptr || version < 0 || version > 255) errx(1, "%s: Bad argument to -v option", optarg); break; default: usage(); /* NOTREACHED */ break; } } argc -= optind; argv += optind; if (argc != 1) usage(); disk = mkrdev(*argv); read_boot(disk, boot0buf); if (iplbakpath != NULL) { fd1 = open(iplbakpath, O_WRONLY | O_CREAT | O_TRUNC, 0666); if (fd1 < 0) err(1, "%s", iplbakpath); n = write(fd1, boot0buf, IPLSIZE); if (n == -1) err(1, "%s", iplbakpath); if (n != IPLSIZE) errx(1, "%s: short write", iplbakpath); close(fd1); } if (menubakpath != NULL) { fd1 = open(menubakpath, O_WRONLY | O_CREAT | O_TRUNC, 0666); if (fd1 < 0) err(1, "%s", menubakpath); n = write(fd1, boot0buf + BOOTMENUOFF, BOOTMENUSIZE); if (n == -1) err(1, "%s", menubakpath); if (n != BOOTMENUSIZE) errx(1, "%s: short write", menubakpath); close(fd1); } if (B_flag) { /* Read IPL (boot0). */ fd1 = open(iplpath, O_RDONLY); if (fd1 < 0) err(1, "%s", disk); n = read(fd1, ipl, IPLSIZE); if (n < 0) err(1, "%s", iplpath); if (n != IPLSIZE) errx(1, "%s: invalid file", iplpath); close(fd1); /* Read HDD boot menu (boot0.5). */ fd1 = open(menupath, O_RDONLY); if (fd1 < 0) err(1, "%s", disk); n = read(fd1, menu, BOOTMENUSIZE); if (n < 0) err(1, "%s", menupath); if (n != BOOTMENUSIZE) errx(1, "%s: invalid file", menupath); close(fd1); memcpy(boot0buf, ipl, IPLSIZE); memcpy(boot0buf + BOOTMENUOFF, menu, BOOTMENUSIZE); } /* Set version number field. */ if (v_flag) *(boot0buf + secsize - 4) = (u_char)version; if (B_flag || v_flag) write_boot(disk, boot0buf); return 0; } static int read_boot(const char *disk, u_char *boot) { int fd, n; /* Read IPL, partition table and HDD boot menu. */ fd = open(disk, O_RDONLY); if (fd < 0) err(1, "%s", disk); n = read(fd, boot, BOOTSIZE); if (n != BOOTSIZE) errx(1, "%s: short read", disk); close(fd); return 0; } static int write_boot(const char *disk, u_char *boot) { int fd, n, i; char buf[MAXPATHLEN]; const char *q; struct gctl_req *grq; fd = open(disk, O_WRONLY, 0666); if (fd != -1) { if ((n = write(fd, boot, BOOTSIZE)) < 0) err(1, "%s", disk); if (n != BOOTSIZE) errx(1, "%s: short write", disk); close(fd); return 0; } grq = gctl_get_handle(); gctl_ro_param(grq, "verb", -1, "write PC98"); gctl_ro_param(grq, "class", -1, "PC98"); q = strrchr(disk, '/'); if (q == NULL) q = disk; else q++; gctl_ro_param(grq, "geom", -1, q); gctl_ro_param(grq, "data", BOOTSIZE, boot); q = gctl_issue(grq); if (q == NULL) return 0; warnx("%s: %s", disk, q); gctl_free(grq); for (i = 0; i < PC98_NPARTS; i++) { snprintf(buf, sizeof(buf), "%ss%d", disk, i + 1); fd = open(buf, O_RDONLY); if (fd < 0) continue; n = ioctl(fd, DIOCSPC98, boot); if (n != 0) err(1, "%s: ioctl DIOCSPC98", disk); close(fd); return 0; } err(1, "%s", disk); } /* * Produce a device path for a "canonical" name, where appropriate. */ static char * mkrdev(const char *fname) { char buf[MAXPATHLEN]; char *s; if (!strchr(fname, '/')) { snprintf(buf, sizeof(buf), "%s%s", _PATH_DEV, fname); s = strdup(buf); } else s = strdup(fname); if (s == NULL) errx(1, "No more memory"); return s; } /* * Display usage information. */ static void usage(void) { fprintf(stderr, "boot98cfg [-B][-i boot0][-m boot0.5][-s secsize][-v version]\n" " [-f ipl.bak][-F menu.bak] disk\n"); exit(1); }