diff options
Diffstat (limited to 'usr.sbin/boot98cfg/boot98cfg.c')
-rw-r--r-- | usr.sbin/boot98cfg/boot98cfg.c | 319 |
1 files changed, 319 insertions, 0 deletions
diff --git a/usr.sbin/boot98cfg/boot98cfg.c b/usr.sbin/boot98cfg/boot98cfg.c new file mode 100644 index 0000000..0ed1b17 --- /dev/null +++ b/usr.sbin/boot98cfg/boot98cfg.c @@ -0,0 +1,319 @@ +/* + * 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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/diskpc98.h> +#include <sys/stat.h> + +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <libgeom.h> +#include <paths.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#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); +} |