boot98cfg.c revision 148049
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: head/usr.sbin/boot98cfg/boot98cfg.c 148049 2005-07-15 14:37:40Z nyan $");
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>
6864126Skato#include <paths.h>
6964126Skato#include <stdio.h>
7064126Skato#include <stdlib.h>
7164126Skato#include <string.h>
7264126Skato#include <unistd.h>
7364126Skato
74110678Snyan#define	BOOTSIZE		0x2000
7564126Skato#define	IPLSIZE			512		/* IPL size */
7664126Skato#define	BOOTMENUSIZE		7168		/* Max HDD boot menu size */
7764126Skato#define	BOOTMENUOFF		0x400
7864126Skato
79110678Snyanu_char	boot0buf[BOOTSIZE];
80110678Snyanu_char	ipl[IPLSIZE];
81110678Snyanu_char	menu[BOOTMENUSIZE];
8264126Skato
83148049Snyanstatic	int read_boot(const char *, u_char *);
84148049Snyanstatic	int write_boot(const char *, u_char *);
85148049Snyanstatic	char *mkrdev(char *);
86148049Snyanstatic	void usage(void);
87148049Snyan
8864126Skato/*
89148049Snyan * Boot manager installation/configuration utility.
9064126Skato */
9164126Skatoint
9264126Skatomain(int argc, char *argv[])
9364126Skato{
9464126Skato	char	*endptr;
9578715Sdd	const	char *iplpath = "/boot/boot0", *menupath = "/boot/boot0.5";
9664126Skato	char	*iplbakpath = NULL, *menubakpath = NULL;
9764126Skato	char	*disk;
9864126Skato	int	B_flag = 0;
9964126Skato	int	c;
100110678Snyan	int	fd1;
10164126Skato	int	n;
10264126Skato	int	secsize = 512;
10364126Skato	int	v_flag = 0, version;
10464126Skato
10564126Skato	while ((c = getopt(argc, argv, "BF:f:i:m:s:v:")) != -1) {
10664126Skato		switch (c) {
10764126Skato		case 'B':
10864126Skato			B_flag = 1;
10964126Skato			break;
11064126Skato		case 'F':
11164126Skato			menubakpath = optarg;
11264126Skato			break;
11364126Skato		case 'f':
11464126Skato			iplbakpath = optarg;
11564126Skato			break;
11664126Skato		case 'i':
11764126Skato			iplpath = optarg;
11864126Skato			break;
11964126Skato		case 'm':
12064126Skato			menupath = optarg;
12164126Skato			break;
12264126Skato		case 's':
12364126Skato			secsize = strtol(optarg, &endptr, 0);
124126652Snyan			if (errno || *optarg == '\0' || *endptr)
12564126Skato				errx(1, "%s: Bad argument to -s option",
12664126Skato				    optarg);
12764126Skato			switch (secsize) {
12864126Skato			case 256:
12964126Skato			case 512:
13064126Skato			case 1024:
13164126Skato			case 2048:
13264126Skato				break;
13364126Skato			default:
13464126Skato				errx(1, "%s: unsupported sector size", optarg);
13564126Skato				break;
13664126Skato			}
13764126Skato			break;
13864126Skato		case 'v':
13964126Skato			v_flag = 1;
14064126Skato			version = strtol(optarg, &endptr, 0);
141126652Snyan			if (errno || *optarg == '\0' || *endptr ||
14264126Skato			    version < 0 || version > 255)
14364126Skato				errx(1, "%s: Bad argument to -s option",
14464126Skato				    optarg);
14564126Skato			break;
14664126Skato		default:
14764126Skato			usage();
14864126Skato			/* NOTREACHED */
14964126Skato			break;
15064126Skato		}
15164126Skato	}
15264126Skato	argc -= optind;
15364126Skato	argv += optind;
15464126Skato	if (argc != 1)
15564126Skato		usage();
15664126Skato	disk = mkrdev(*argv);
15764126Skato
158110678Snyan	read_boot(disk, boot0buf);
15964126Skato
16064126Skato	if (iplbakpath != NULL) {
16164126Skato		fd1 = open(iplbakpath, O_WRONLY | O_CREAT | O_TRUNC, 0666);
16264126Skato		if (fd1 < 0)
16364126Skato			err(1, "%s", iplbakpath);
16464126Skato		n = write(fd1, boot0buf, IPLSIZE);
16564126Skato		if (n == -1)
16664126Skato			err(1, "%s", iplbakpath);
16764126Skato		if (n != IPLSIZE)
16864126Skato			errx(1, "%s: short write", iplbakpath);
16964126Skato		close(fd1);
17064126Skato	}
17164126Skato
17264126Skato	if (menubakpath != NULL) {
17364126Skato		fd1 = open(menubakpath, O_WRONLY | O_CREAT | O_TRUNC, 0666);
17464126Skato		if (fd1 < 0)
17564126Skato			err(1, "%s", menubakpath);
17664126Skato		n = write(fd1, boot0buf + BOOTMENUOFF, BOOTMENUSIZE);
17764126Skato		if (n == -1)
17864126Skato			err(1, "%s", menubakpath);
17964126Skato		if (n != BOOTMENUSIZE)
18064126Skato			errx(1, "%s: short write", menubakpath);
18164126Skato		close(fd1);
18264126Skato	}
18364126Skato
18464126Skato	if (B_flag) {
18564126Skato		/* Read IPL (boot0). */
18664126Skato		fd1 = open(iplpath, O_RDONLY);
18764126Skato		if (fd1 < 0)
18864126Skato			err(1, "%s", disk);
18964126Skato		n = read(fd1, ipl, IPLSIZE);
19064126Skato		if (n < 0)
19164126Skato			err(1, "%s", iplpath);
19264126Skato		if (n != IPLSIZE)
19364126Skato			errx(1, "%s: invalid file", iplpath);
19464126Skato		close(fd1);
19564126Skato
19664126Skato		/* Read HDD boot menu (boot0.5). */
19764126Skato		fd1 = open(menupath, O_RDONLY);
19864126Skato		if (fd1 < 0)
19964126Skato			err(1, "%s", disk);
20064126Skato		n = read(fd1, menu, BOOTMENUSIZE);
20164126Skato		if (n < 0)
20264126Skato			err(1, "%s", menupath);
20364126Skato		if (n != BOOTMENUSIZE)
20464126Skato			errx(1, "%s: invalid file", menupath);
20564126Skato		close(fd1);
20664126Skato
20764126Skato		memcpy(boot0buf, ipl, IPLSIZE);
20864126Skato		memcpy(boot0buf + BOOTMENUOFF, menu, BOOTMENUSIZE);
20964126Skato	}
21064126Skato
21164126Skato	/* Set version number field. */
21264126Skato	if (v_flag)
21364126Skato		*(boot0buf + secsize - 4) = (u_char)version;
21464126Skato
215110678Snyan	if (B_flag || v_flag)
216110678Snyan		write_boot(disk, boot0buf);
217110678Snyan
21864126Skato	return 0;
21964126Skato}
220148049Snyan
221148049Snyanstatic int
222148049Snyanread_boot(const char *disk, u_char *boot)
223148049Snyan{
224148049Snyan	int fd, n;
225148049Snyan
226148049Snyan	/* Read IPL, partition table and HDD boot menu. */
227148049Snyan	fd = open(disk, O_RDONLY);
228148049Snyan	if (fd < 0)
229148049Snyan		err(1, "%s", disk);
230148049Snyan	n = read(fd, boot, BOOTSIZE);
231148049Snyan	if (n != BOOTSIZE)
232148049Snyan		errx(1, "%s: short read", disk);
233148049Snyan	close(fd);
234148049Snyan
235148049Snyan	return 0;
236148049Snyan}
237148049Snyan
238148049Snyanstatic int
239148049Snyanwrite_boot(const char *disk, u_char *boot)
240148049Snyan{
241148049Snyan	int fd, n, i;
242148049Snyan	char buf[MAXPATHLEN];
243148049Snyan
244148049Snyan	fd = open(disk, O_RDWR);
245148049Snyan	if (fd != -1) {
246148049Snyan		if (lseek(fd, 0, SEEK_SET) == -1)
247148049Snyan			err(1, "%s", disk);
248148049Snyan		if ((n = write(fd, boot, BOOTSIZE)) < 0)
249148049Snyan			err(1, "%s", disk);
250148049Snyan		if (n != BOOTSIZE)
251148049Snyan			errx(1, "%s: short write", disk);
252148049Snyan		close(fd);
253148049Snyan		return 0;
254148049Snyan	}
255148049Snyan
256148049Snyan	for (i = 0; i < NDOSPART; i++) {
257148049Snyan		snprintf(buf, sizeof(buf), "%ss%d", disk, i + 1);
258148049Snyan		fd = open(buf, O_RDONLY);
259148049Snyan		if (fd < 0)
260148049Snyan			continue;
261148049Snyan		n = ioctl(fd, DIOCSPC98, boot);
262148049Snyan		if (n != 0)
263148049Snyan			err(1, "%s: ioctl DIOCSPC98", disk);
264148049Snyan		close(fd);
265148049Snyan		return 0;
266148049Snyan	}
267148049Snyan
268148049Snyan	err(1, "%s", disk);
269148049Snyan}
270148049Snyan
271148049Snyan/*
272148049Snyan * Produce a device path for a "canonical" name, where appropriate.
273148049Snyan */
274148049Snyanstatic char *
275148049Snyanmkrdev(char *fname)
276148049Snyan{
277148049Snyan    char buf[MAXPATHLEN];
278148049Snyan    struct stat sb;
279148049Snyan    char *s;
280148049Snyan
281148049Snyan    s = (char *)fname;
282148049Snyan    if (!strchr(fname, '/')) {
283148049Snyan        snprintf(buf, sizeof(buf), "%sr%s", _PATH_DEV, fname);
284148049Snyan        if (stat(buf, &sb))
285148049Snyan            snprintf(buf, sizeof(buf), "%s%s", _PATH_DEV, fname);
286148049Snyan        if (!(s = strdup(buf)))
287148049Snyan            err(1, NULL);
288148049Snyan    }
289148049Snyan    return s;
290148049Snyan}
291148049Snyan
292148049Snyan/*
293148049Snyan * Display usage information.
294148049Snyan */
295148049Snyanstatic void
296148049Snyanusage(void)
297148049Snyan{
298148049Snyan	fprintf(stderr,
299148049Snyan	    "boot98cfg [-B][-i boot0][-m boot0.5][-s secsize][-v version]\n"
300148049Snyan	    "          [-f ipl.bak][-F menu.bak] disk\n");
301148049Snyan	exit(1);
302148049Snyan}
303