164126Skato/*
264126Skato * Copyright (c) KATO Takenori, 2000.
364126Skato *
464126Skato * All rights reserved.  Unpublished rights reserved under the copyright
564126Skato * laws of Japan.
664126Skato *
764126Skato * Redistribution and use in source and binary forms, with or without
864126Skato * modification, are permitted provided that the following conditions
964126Skato * are met:
1064126Skato *
1164126Skato * 1. Redistributions of source code must retain the above copyright
1264126Skato *    notice, this list of conditions and the following disclaimer as
1364126Skato *    the first lines of this file unmodified.
1464126Skato * 2. Redistributions in binary form must reproduce the above copyright
1564126Skato *    notice, this list of conditions and the following disclaimer in the
1664126Skato *    documentation and/or other materials provided with the distribution.
1764126Skato * 3. The name of the author may not be used to endorse or promote products
1864126Skato *    derived from this software without specific prior written permission.
1964126Skato *
2064126Skato * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2164126Skato * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2264126Skato * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2364126Skato * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2464126Skato * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2564126Skato * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2664126Skato * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2764126Skato * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2864126Skato * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2964126Skato * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3064126Skato */
3164126Skato
3264126Skato/*
3364126Skato * Copyright (c) 1999 Robert Nordier
3464126Skato * All rights reserved.
3564126Skato *
3664126Skato * Redistribution and use in source and binary forms, with or without
3764126Skato * modification, are permitted provided that the following conditions
3864126Skato * are met:
3964126Skato * 1. Redistributions of source code must retain the above copyright
4064126Skato *    notice, this list of conditions and the following disclaimer.
4164126Skato * 2. Redistributions in binary form must reproduce the above copyright
4264126Skato *    notice, this list of conditions and the following disclaimer in the
4364126Skato *    documentation and/or other materials provided with the distribution.
4464126Skato *
4564126Skato * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS``AS IS'' AND
4664126Skato * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4764126Skato * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
4864126Skato * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
4964126Skato * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
5064126Skato * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
5164126Skato * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
5264126Skato * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
5364126Skato * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
5464126Skato * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
5564126Skato * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5664126Skato */
5764126Skato
58148049Snyan#include <sys/cdefs.h>
59148049Snyan__FBSDID("$FreeBSD$");
60148049Snyan
6164126Skato#include <sys/param.h>
62148049Snyan#include <sys/diskpc98.h>
6364126Skato#include <sys/stat.h>
6464126Skato
6564126Skato#include <err.h>
6664126Skato#include <errno.h>
6764126Skato#include <fcntl.h>
68148064Snyan#include <libgeom.h>
6964126Skato#include <paths.h>
7064126Skato#include <stdio.h>
7164126Skato#include <stdlib.h>
7264126Skato#include <string.h>
7364126Skato#include <unistd.h>
7464126Skato
75110678Snyan#define	BOOTSIZE		0x2000
7664126Skato#define	IPLSIZE			512		/* IPL size */
7764126Skato#define	BOOTMENUSIZE		7168		/* Max HDD boot menu size */
7864126Skato#define	BOOTMENUOFF		0x400
7964126Skato
80110678Snyanu_char	boot0buf[BOOTSIZE];
81110678Snyanu_char	ipl[IPLSIZE];
82110678Snyanu_char	menu[BOOTMENUSIZE];
8364126Skato
84148049Snyanstatic	int read_boot(const char *, u_char *);
85148049Snyanstatic	int write_boot(const char *, u_char *);
86148064Snyanstatic	char *mkrdev(const char *);
87148049Snyanstatic	void usage(void);
88148049Snyan
8964126Skato/*
90148049Snyan * Boot manager installation/configuration utility.
9164126Skato */
9264126Skatoint
9364126Skatomain(int argc, char *argv[])
9464126Skato{
9564126Skato	char	*endptr;
9678715Sdd	const	char *iplpath = "/boot/boot0", *menupath = "/boot/boot0.5";
9764126Skato	char	*iplbakpath = NULL, *menubakpath = NULL;
9864126Skato	char	*disk;
9964126Skato	int	B_flag = 0;
10064126Skato	int	c;
101110678Snyan	int	fd1;
10264126Skato	int	n;
10364126Skato	int	secsize = 512;
10464126Skato	int	v_flag = 0, version;
10564126Skato
10664126Skato	while ((c = getopt(argc, argv, "BF:f:i:m:s:v:")) != -1) {
10764126Skato		switch (c) {
10864126Skato		case 'B':
10964126Skato			B_flag = 1;
11064126Skato			break;
11164126Skato		case 'F':
11264126Skato			menubakpath = optarg;
11364126Skato			break;
11464126Skato		case 'f':
11564126Skato			iplbakpath = optarg;
11664126Skato			break;
11764126Skato		case 'i':
11864126Skato			iplpath = optarg;
11964126Skato			break;
12064126Skato		case 'm':
12164126Skato			menupath = optarg;
12264126Skato			break;
12364126Skato		case 's':
12464126Skato			secsize = strtol(optarg, &endptr, 0);
125126652Snyan			if (errno || *optarg == '\0' || *endptr)
12664126Skato				errx(1, "%s: Bad argument to -s option",
12764126Skato				    optarg);
12864126Skato			switch (secsize) {
12964126Skato			case 256:
13064126Skato			case 512:
13164126Skato			case 1024:
13264126Skato			case 2048:
13364126Skato				break;
13464126Skato			default:
13564126Skato				errx(1, "%s: unsupported sector size", optarg);
13664126Skato				break;
13764126Skato			}
13864126Skato			break;
13964126Skato		case 'v':
14064126Skato			v_flag = 1;
14164126Skato			version = strtol(optarg, &endptr, 0);
142126652Snyan			if (errno || *optarg == '\0' || *endptr ||
14364126Skato			    version < 0 || version > 255)
144174764Simp				errx(1, "%s: Bad argument to -v option",
14564126Skato				    optarg);
14664126Skato			break;
14764126Skato		default:
14864126Skato			usage();
14964126Skato			/* NOTREACHED */
15064126Skato			break;
15164126Skato		}
15264126Skato	}
15364126Skato	argc -= optind;
15464126Skato	argv += optind;
15564126Skato	if (argc != 1)
15664126Skato		usage();
15764126Skato	disk = mkrdev(*argv);
15864126Skato
159110678Snyan	read_boot(disk, boot0buf);
16064126Skato
16164126Skato	if (iplbakpath != NULL) {
16264126Skato		fd1 = open(iplbakpath, O_WRONLY | O_CREAT | O_TRUNC, 0666);
16364126Skato		if (fd1 < 0)
16464126Skato			err(1, "%s", iplbakpath);
16564126Skato		n = write(fd1, boot0buf, IPLSIZE);
16664126Skato		if (n == -1)
16764126Skato			err(1, "%s", iplbakpath);
16864126Skato		if (n != IPLSIZE)
16964126Skato			errx(1, "%s: short write", iplbakpath);
17064126Skato		close(fd1);
17164126Skato	}
17264126Skato
17364126Skato	if (menubakpath != NULL) {
17464126Skato		fd1 = open(menubakpath, O_WRONLY | O_CREAT | O_TRUNC, 0666);
17564126Skato		if (fd1 < 0)
17664126Skato			err(1, "%s", menubakpath);
17764126Skato		n = write(fd1, boot0buf + BOOTMENUOFF, BOOTMENUSIZE);
17864126Skato		if (n == -1)
17964126Skato			err(1, "%s", menubakpath);
18064126Skato		if (n != BOOTMENUSIZE)
18164126Skato			errx(1, "%s: short write", menubakpath);
18264126Skato		close(fd1);
18364126Skato	}
18464126Skato
18564126Skato	if (B_flag) {
18664126Skato		/* Read IPL (boot0). */
18764126Skato		fd1 = open(iplpath, O_RDONLY);
18864126Skato		if (fd1 < 0)
18964126Skato			err(1, "%s", disk);
19064126Skato		n = read(fd1, ipl, IPLSIZE);
19164126Skato		if (n < 0)
19264126Skato			err(1, "%s", iplpath);
19364126Skato		if (n != IPLSIZE)
19464126Skato			errx(1, "%s: invalid file", iplpath);
19564126Skato		close(fd1);
19664126Skato
19764126Skato		/* Read HDD boot menu (boot0.5). */
19864126Skato		fd1 = open(menupath, O_RDONLY);
19964126Skato		if (fd1 < 0)
20064126Skato			err(1, "%s", disk);
20164126Skato		n = read(fd1, menu, BOOTMENUSIZE);
20264126Skato		if (n < 0)
20364126Skato			err(1, "%s", menupath);
20464126Skato		if (n != BOOTMENUSIZE)
20564126Skato			errx(1, "%s: invalid file", menupath);
20664126Skato		close(fd1);
20764126Skato
20864126Skato		memcpy(boot0buf, ipl, IPLSIZE);
20964126Skato		memcpy(boot0buf + BOOTMENUOFF, menu, BOOTMENUSIZE);
21064126Skato	}
21164126Skato
21264126Skato	/* Set version number field. */
21364126Skato	if (v_flag)
21464126Skato		*(boot0buf + secsize - 4) = (u_char)version;
21564126Skato
216110678Snyan	if (B_flag || v_flag)
217110678Snyan		write_boot(disk, boot0buf);
218110678Snyan
21964126Skato	return 0;
22064126Skato}
221148049Snyan
222148049Snyanstatic int
223148049Snyanread_boot(const char *disk, u_char *boot)
224148049Snyan{
225148049Snyan	int fd, n;
226148049Snyan
227148049Snyan	/* Read IPL, partition table and HDD boot menu. */
228148049Snyan	fd = open(disk, O_RDONLY);
229148049Snyan	if (fd < 0)
230148049Snyan		err(1, "%s", disk);
231148049Snyan	n = read(fd, boot, BOOTSIZE);
232148049Snyan	if (n != BOOTSIZE)
233148049Snyan		errx(1, "%s: short read", disk);
234148049Snyan	close(fd);
235148049Snyan
236148049Snyan	return 0;
237148049Snyan}
238148049Snyan
239148049Snyanstatic int
240148049Snyanwrite_boot(const char *disk, u_char *boot)
241148049Snyan{
242148049Snyan	int fd, n, i;
243148049Snyan	char buf[MAXPATHLEN];
244148064Snyan	const char *q;
245148064Snyan	struct gctl_req *grq;
246148049Snyan
247148064Snyan	fd = open(disk, O_WRONLY, 0666);
248148049Snyan	if (fd != -1) {
249148049Snyan		if ((n = write(fd, boot, BOOTSIZE)) < 0)
250148049Snyan			err(1, "%s", disk);
251148049Snyan		if (n != BOOTSIZE)
252148049Snyan			errx(1, "%s: short write", disk);
253148049Snyan		close(fd);
254148049Snyan		return 0;
255148049Snyan	}
256148049Snyan
257148064Snyan	grq = gctl_get_handle();
258148064Snyan	gctl_ro_param(grq, "verb", -1, "write PC98");
259148064Snyan	gctl_ro_param(grq, "class", -1, "PC98");
260148064Snyan	q = strrchr(disk, '/');
261148064Snyan	if (q == NULL)
262148064Snyan		q = disk;
263148064Snyan	else
264148064Snyan		q++;
265148064Snyan	gctl_ro_param(grq, "geom", -1, q);
266148064Snyan	gctl_ro_param(grq, "data", BOOTSIZE, boot);
267148064Snyan	q = gctl_issue(grq);
268148064Snyan	if (q == NULL)
269148064Snyan		return 0;
270148064Snyan
271148064Snyan	warnx("%s: %s", disk, q);
272148064Snyan	gctl_free(grq);
273148064Snyan
274254015Smarcel	for (i = 0; i < PC98_NPARTS; i++) {
275148049Snyan		snprintf(buf, sizeof(buf), "%ss%d", disk, i + 1);
276148049Snyan		fd = open(buf, O_RDONLY);
277148049Snyan		if (fd < 0)
278148049Snyan			continue;
279148049Snyan		n = ioctl(fd, DIOCSPC98, boot);
280148049Snyan		if (n != 0)
281148049Snyan			err(1, "%s: ioctl DIOCSPC98", disk);
282148049Snyan		close(fd);
283148049Snyan		return 0;
284148049Snyan	}
285148049Snyan
286148049Snyan	err(1, "%s", disk);
287148049Snyan}
288148049Snyan
289148049Snyan/*
290148049Snyan * Produce a device path for a "canonical" name, where appropriate.
291148049Snyan */
292148049Snyanstatic char *
293148064Snyanmkrdev(const char *fname)
294148049Snyan{
295148049Snyan    char buf[MAXPATHLEN];
296148049Snyan    char *s;
297148049Snyan
298148049Snyan    if (!strchr(fname, '/')) {
299148064Snyan	snprintf(buf, sizeof(buf), "%s%s", _PATH_DEV, fname);
300148064Snyan        s = strdup(buf);
301148064Snyan    } else
302148064Snyan        s = strdup(fname);
303148064Snyan
304148064Snyan    if (s == NULL)
305148064Snyan        errx(1, "No more memory");
306148049Snyan    return s;
307148049Snyan}
308148049Snyan
309148049Snyan/*
310148049Snyan * Display usage information.
311148049Snyan */
312148049Snyanstatic void
313148049Snyanusage(void)
314148049Snyan{
315148049Snyan	fprintf(stderr,
316148049Snyan	    "boot98cfg [-B][-i boot0][-m boot0.5][-s secsize][-v version]\n"
317148049Snyan	    "          [-f ipl.bak][-F menu.bak] disk\n");
318148049Snyan	exit(1);
319148049Snyan}
320