boot98cfg.c revision 174764
1133759Srwatson/*
2133759Srwatson * Copyright (c) KATO Takenori, 2000.
3133759Srwatson *
4133759Srwatson * All rights reserved.  Unpublished rights reserved under the copyright
5133759Srwatson * laws of Japan.
6133759Srwatson *
7133759Srwatson * Redistribution and use in source and binary forms, with or without
8133759Srwatson * modification, are permitted provided that the following conditions
9133759Srwatson * are met:
10133759Srwatson *
11133759Srwatson * 1. Redistributions of source code must retain the above copyright
12133759Srwatson *    notice, this list of conditions and the following disclaimer as
13133759Srwatson *    the first lines of this file unmodified.
14133759Srwatson * 2. Redistributions in binary form must reproduce the above copyright
15133759Srwatson *    notice, this list of conditions and the following disclaimer in the
16133759Srwatson *    documentation and/or other materials provided with the distribution.
17133759Srwatson * 3. The name of the author may not be used to endorse or promote products
18133759Srwatson *    derived from this software without specific prior written permission.
19133759Srwatson *
20133759Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21133759Srwatson * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22133759Srwatson * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23133759Srwatson * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24133759Srwatson * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25133759Srwatson * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26133759Srwatson * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27133759Srwatson * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28133759Srwatson * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29133759Srwatson * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30133770Srwatson */
31133759Srwatson
32133770Srwatson/*
33133770Srwatson * Copyright (c) 1999 Robert Nordier
34133770Srwatson * All rights reserved.
35133770Srwatson *
36133759Srwatson * Redistribution and use in source and binary forms, with or without
37133759Srwatson * modification, are permitted provided that the following conditions
38133759Srwatson * are met:
39133759Srwatson * 1. Redistributions of source code must retain the above copyright
40133759Srwatson *    notice, this list of conditions and the following disclaimer.
41133759Srwatson * 2. Redistributions in binary form must reproduce the above copyright
42133759Srwatson *    notice, this list of conditions and the following disclaimer in the
43133759Srwatson *    documentation and/or other materials provided with the distribution.
44133759Srwatson *
45133759Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS``AS IS'' AND
46133759Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47214631Sjhb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
48133759Srwatson * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
49133759Srwatson * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
50133759Srwatson * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
51133759Srwatson * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
52142722Sobrien * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
53133759Srwatson * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
54133759Srwatson * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
55133759Srwatson * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
56142722Sobrien */
57133759Srwatson
58133759Srwatson#include <sys/cdefs.h>
59133759Srwatson__FBSDID("$FreeBSD: head/usr.sbin/boot98cfg/boot98cfg.c 174764 2007-12-19 03:31:44Z imp $");
60133759Srwatson
61133759Srwatson#include <sys/param.h>
62133759Srwatson#include <sys/diskpc98.h>
63133759Srwatson#include <sys/stat.h>
64133759Srwatson
65133759Srwatson#include <err.h>
66133759Srwatson#include <errno.h>
67133759Srwatson#include <fcntl.h>
68133759Srwatson#include <libgeom.h>
69133759Srwatson#include <paths.h>
70133759Srwatson#include <stdio.h>
71142722Sobrien#include <stdlib.h>
72133759Srwatson#include <string.h>
73133759Srwatson#include <unistd.h>
74133759Srwatson
75133759Srwatson#define	BOOTSIZE		0x2000
76133759Srwatson#define	IPLSIZE			512		/* IPL size */
77142722Sobrien#define	BOOTMENUSIZE		7168		/* Max HDD boot menu size */
78142722Sobrien#define	BOOTMENUOFF		0x400
79133759Srwatson
80133759Srwatsonu_char	boot0buf[BOOTSIZE];
81133759Srwatsonu_char	ipl[IPLSIZE];
82133759Srwatsonu_char	menu[BOOTMENUSIZE];
83133759Srwatson
84133759Srwatsonstatic	int read_boot(const char *, u_char *);
85133759Srwatsonstatic	int write_boot(const char *, u_char *);
86133759Srwatsonstatic	char *mkrdev(const char *);
87133759Srwatsonstatic	void usage(void);
88133759Srwatson
89133759Srwatson/*
90142722Sobrien * Boot manager installation/configuration utility.
91142722Sobrien */
92133759Srwatsonint
93133759Srwatsonmain(int argc, char *argv[])
94133759Srwatson{
95133759Srwatson	char	*endptr;
96133759Srwatson	const	char *iplpath = "/boot/boot0", *menupath = "/boot/boot0.5";
97133759Srwatson	char	*iplbakpath = NULL, *menubakpath = NULL;
98133759Srwatson	char	*disk;
99133759Srwatson	int	B_flag = 0;
100133759Srwatson	int	c;
101133759Srwatson	int	fd1;
102133759Srwatson	int	n;
103133759Srwatson	int	secsize = 512;
104133759Srwatson	int	v_flag = 0, version;
105133759Srwatson
106133759Srwatson	while ((c = getopt(argc, argv, "BF:f:i:m:s:v:")) != -1) {
107133759Srwatson		switch (c) {
108133759Srwatson		case 'B':
109133759Srwatson			B_flag = 1;
110133759Srwatson			break;
111133759Srwatson		case 'F':
112133759Srwatson			menubakpath = optarg;
113133759Srwatson			break;
114142722Sobrien		case 'f':
115142722Sobrien			iplbakpath = optarg;
116142722Sobrien			break;
117142722Sobrien		case 'i':
118142722Sobrien			iplpath = optarg;
119142722Sobrien			break;
120142765Spjd		case 'm':
121142722Sobrien			menupath = optarg;
122142722Sobrien			break;
123142722Sobrien		case 's':
124142722Sobrien			secsize = strtol(optarg, &endptr, 0);
125142722Sobrien			if (errno || *optarg == '\0' || *endptr)
126142722Sobrien				errx(1, "%s: Bad argument to -s option",
127142722Sobrien				    optarg);
128142722Sobrien			switch (secsize) {
129142722Sobrien			case 256:
130142722Sobrien			case 512:
131142722Sobrien			case 1024:
132142722Sobrien			case 2048:
133142722Sobrien				break;
134142722Sobrien			default:
135133759Srwatson				errx(1, "%s: unsupported sector size", optarg);
136133759Srwatson				break;
137133759Srwatson			}
138133759Srwatson			break;
139133759Srwatson		case 'v':
140133759Srwatson			v_flag = 1;
141133759Srwatson			version = strtol(optarg, &endptr, 0);
142133759Srwatson			if (errno || *optarg == '\0' || *endptr ||
143133759Srwatson			    version < 0 || version > 255)
144133759Srwatson				errx(1, "%s: Bad argument to -v option",
145133759Srwatson				    optarg);
146133759Srwatson			break;
147133759Srwatson		default:
148133759Srwatson			usage();
149142722Sobrien			/* NOTREACHED */
150142722Sobrien			break;
151133759Srwatson		}
152133759Srwatson	}
153133759Srwatson	argc -= optind;
154142722Sobrien	argv += optind;
155133759Srwatson	if (argc != 1)
156133759Srwatson		usage();
157133759Srwatson	disk = mkrdev(*argv);
158133759Srwatson
159133759Srwatson	read_boot(disk, boot0buf);
160133759Srwatson
161133759Srwatson	if (iplbakpath != NULL) {
162133759Srwatson		fd1 = open(iplbakpath, O_WRONLY | O_CREAT | O_TRUNC, 0666);
163133759Srwatson		if (fd1 < 0)
164133759Srwatson			err(1, "%s", iplbakpath);
165133759Srwatson		n = write(fd1, boot0buf, IPLSIZE);
166133759Srwatson		if (n == -1)
167133759Srwatson			err(1, "%s", iplbakpath);
168133759Srwatson		if (n != IPLSIZE)
169133759Srwatson			errx(1, "%s: short write", iplbakpath);
170133759Srwatson		close(fd1);
171133759Srwatson	}
172133759Srwatson
173133759Srwatson	if (menubakpath != NULL) {
174133759Srwatson		fd1 = open(menubakpath, O_WRONLY | O_CREAT | O_TRUNC, 0666);
175133759Srwatson		if (fd1 < 0)
176133759Srwatson			err(1, "%s", menubakpath);
177133759Srwatson		n = write(fd1, boot0buf + BOOTMENUOFF, BOOTMENUSIZE);
178133759Srwatson		if (n == -1)
179133759Srwatson			err(1, "%s", menubakpath);
180133759Srwatson		if (n != BOOTMENUSIZE)
181133759Srwatson			errx(1, "%s: short write", menubakpath);
182133759Srwatson		close(fd1);
183133759Srwatson	}
184133759Srwatson
185133759Srwatson	if (B_flag) {
186133759Srwatson		/* Read IPL (boot0). */
187133759Srwatson		fd1 = open(iplpath, O_RDONLY);
188133759Srwatson		if (fd1 < 0)
189133759Srwatson			err(1, "%s", disk);
190133759Srwatson		n = read(fd1, ipl, IPLSIZE);
191133759Srwatson		if (n < 0)
192133759Srwatson			err(1, "%s", iplpath);
193133759Srwatson		if (n != IPLSIZE)
194133759Srwatson			errx(1, "%s: invalid file", iplpath);
195133759Srwatson		close(fd1);
196133759Srwatson
197133759Srwatson		/* Read HDD boot menu (boot0.5). */
198133759Srwatson		fd1 = open(menupath, O_RDONLY);
199133759Srwatson		if (fd1 < 0)
200133759Srwatson			err(1, "%s", disk);
201133759Srwatson		n = read(fd1, menu, BOOTMENUSIZE);
202133759Srwatson		if (n < 0)
203133759Srwatson			err(1, "%s", menupath);
204133759Srwatson		if (n != BOOTMENUSIZE)
205133759Srwatson			errx(1, "%s: invalid file", menupath);
206174898Srwatson		close(fd1);
207133759Srwatson
208133759Srwatson		memcpy(boot0buf, ipl, IPLSIZE);
209133759Srwatson		memcpy(boot0buf + BOOTMENUOFF, menu, BOOTMENUSIZE);
210133759Srwatson	}
211133759Srwatson
212	/* Set version number field. */
213	if (v_flag)
214		*(boot0buf + secsize - 4) = (u_char)version;
215
216	if (B_flag || v_flag)
217		write_boot(disk, boot0buf);
218
219	return 0;
220}
221
222static int
223read_boot(const char *disk, u_char *boot)
224{
225	int fd, n;
226
227	/* Read IPL, partition table and HDD boot menu. */
228	fd = open(disk, O_RDONLY);
229	if (fd < 0)
230		err(1, "%s", disk);
231	n = read(fd, boot, BOOTSIZE);
232	if (n != BOOTSIZE)
233		errx(1, "%s: short read", disk);
234	close(fd);
235
236	return 0;
237}
238
239static int
240write_boot(const char *disk, u_char *boot)
241{
242	int fd, n, i;
243	char buf[MAXPATHLEN];
244	const char *q;
245	struct gctl_req *grq;
246
247	fd = open(disk, O_WRONLY, 0666);
248	if (fd != -1) {
249		if ((n = write(fd, boot, BOOTSIZE)) < 0)
250			err(1, "%s", disk);
251		if (n != BOOTSIZE)
252			errx(1, "%s: short write", disk);
253		close(fd);
254		return 0;
255	}
256
257	grq = gctl_get_handle();
258	gctl_ro_param(grq, "verb", -1, "write PC98");
259	gctl_ro_param(grq, "class", -1, "PC98");
260	q = strrchr(disk, '/');
261	if (q == NULL)
262		q = disk;
263	else
264		q++;
265	gctl_ro_param(grq, "geom", -1, q);
266	gctl_ro_param(grq, "data", BOOTSIZE, boot);
267	q = gctl_issue(grq);
268	if (q == NULL)
269		return 0;
270
271	warnx("%s: %s", disk, q);
272	gctl_free(grq);
273
274	for (i = 0; i < NDOSPART; i++) {
275		snprintf(buf, sizeof(buf), "%ss%d", disk, i + 1);
276		fd = open(buf, O_RDONLY);
277		if (fd < 0)
278			continue;
279		n = ioctl(fd, DIOCSPC98, boot);
280		if (n != 0)
281			err(1, "%s: ioctl DIOCSPC98", disk);
282		close(fd);
283		return 0;
284	}
285
286	err(1, "%s", disk);
287}
288
289/*
290 * Produce a device path for a "canonical" name, where appropriate.
291 */
292static char *
293mkrdev(const char *fname)
294{
295    char buf[MAXPATHLEN];
296    char *s;
297
298    if (!strchr(fname, '/')) {
299	snprintf(buf, sizeof(buf), "%s%s", _PATH_DEV, fname);
300        s = strdup(buf);
301    } else
302        s = strdup(fname);
303
304    if (s == NULL)
305        errx(1, "No more memory");
306    return s;
307}
308
309/*
310 * Display usage information.
311 */
312static void
313usage(void)
314{
315	fprintf(stderr,
316	    "boot98cfg [-B][-i boot0][-m boot0.5][-s secsize][-v version]\n"
317	    "          [-f ipl.bak][-F menu.bak] disk\n");
318	exit(1);
319}
320