e01c6f329a
being defined in <sys/diskmbr.h>. Instead give the symbols here a "PC98_" prefix. This way, both <sys/diskmbr.h> and <sys/diskpc98.h> can be included in the same C source file. The renaming is trivial. The only gotcha is that DOSBBSECTOR is also redefined from 0 to 1. This because DOSBBSECTOR was always used in conjunction with an addition of 1. The PC98_BBSECTOR symbol is defined as 1 and the expression is simplified. Note: it is not believed that ports are seriously impacted; or at all for that matter. Approved by: nyan@
320 lines
8.1 KiB
C
320 lines
8.1 KiB
C
/*
|
|
* 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);
|
|
}
|