boot98cfg.c revision 114535
1/*
2 * Copyright (c) KATO Takenori, 2000.
3 *
4 * All rights reserved.  Unpublished rights reserved under the copyright
5 * laws of Japan.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer as
13 *    the first lines of this file unmodified.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. The name of the author may not be used to endorse or promote products
18 *    derived from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 *
31 * $FreeBSD: head/usr.sbin/boot98cfg/boot98cfg.c 114535 2003-05-02 14:55:42Z nyan $
32 */
33
34/*
35 * Copyright (c) 1999 Robert Nordier
36 * All rights reserved.
37 *
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
40 * are met:
41 * 1. Redistributions of source code must retain the above copyright
42 *    notice, this list of conditions and the following disclaimer.
43 * 2. Redistributions in binary form must reproduce the above copyright
44 *    notice, this list of conditions and the following disclaimer in the
45 *    documentation and/or other materials provided with the distribution.
46 *
47 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS``AS IS'' AND
48 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
50 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
51 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
52 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
53 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
54 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
55 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
56 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
57 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
58 */
59
60#include <sys/param.h>
61#include <sys/stat.h>
62#include <sys/diskpc98.h>
63
64#include <err.h>
65#include <errno.h>
66#include <fcntl.h>
67#include <paths.h>
68#include <stdio.h>
69#include <stdlib.h>
70#include <string.h>
71#include <unistd.h>
72
73#define	BOOTSIZE		0x2000
74#define	IPLSIZE			512		/* IPL size */
75#define	BOOTMENUSIZE		7168		/* Max HDD boot menu size */
76#define	BOOTMENUOFF		0x400
77
78static	char *mkrdev(char *);
79static	void usage(void);
80static	int read_boot(const char *, u_char *);
81static	int write_boot(const char *, u_char *);
82
83u_char	boot0buf[BOOTSIZE];
84u_char	ipl[IPLSIZE];
85u_char	menu[BOOTMENUSIZE];
86
87/*
88 * Produce a device path for a "canonical" name, where appropriate.
89 */
90static char *
91mkrdev(char *fname)
92{
93    char buf[MAXPATHLEN];
94    struct stat sb;
95    char *s;
96
97    s = (char *)fname;
98    if (!strchr(fname, '/')) {
99        snprintf(buf, sizeof(buf), "%sr%s", _PATH_DEV, fname);
100        if (stat(buf, &sb))
101            snprintf(buf, sizeof(buf), "%s%s", _PATH_DEV, fname);
102        if (!(s = strdup(buf)))
103            err(1, NULL);
104    }
105    return s;
106}
107
108static void
109usage(void)
110{
111	fprintf(stderr,
112	    "boot98cfg [-B][-i boot0][-m boot0.5][-s secsize][-v version]\n"
113	    "          [-f ipl.bak][-F menu.bak] disk\n");
114	exit(1);
115}
116
117static int
118read_boot(const char *disk, u_char *boot)
119{
120	int fd, n;
121
122	/* Read IPL, partition table and HDD boot menu. */
123	fd = open(disk, O_RDONLY);
124	if (fd < 0)
125		err(1, "%s", disk);
126	n = read(fd, boot, BOOTSIZE);
127	if (n != BOOTSIZE)
128		errx(1, "%s: short read", disk);
129	close(fd);
130
131	return 0;
132}
133
134static int
135write_boot(const char *disk, u_char *boot)
136{
137	int fd, n, i;
138	char buf[MAXPATHLEN];
139
140	fd = open(disk, O_RDWR);
141	if (fd != -1) {
142		if (lseek(fd, 0, SEEK_SET) == -1)
143			err(1, "%s", disk);
144		if ((n = write(fd, boot, BOOTSIZE)) < 0)
145			err(1, "%s", disk);
146		if (n != BOOTSIZE)
147			errx(1, "%s: short write", disk);
148		close(fd);
149		return 0;
150	}
151
152	for (i = 0; i < NDOSPART; i++) {
153		snprintf(buf, sizeof(buf), "%ss%d", disk, i + 1);
154		fd = open(buf, O_RDONLY);
155		if (fd < 0)
156			continue;
157		n = ioctl(fd, DIOCSPC98, boot);
158		if (n != 0)
159			err(1, "%s: ioctl DIOCSPC98", disk);
160		close(fd);
161		return 0;
162	}
163
164	err(1, "%s", disk);
165}
166
167int
168main(int argc, char *argv[])
169{
170	char	*endptr;
171	const	char *iplpath = "/boot/boot0", *menupath = "/boot/boot0.5";
172	char	*iplbakpath = NULL, *menubakpath = NULL;
173	char	*disk;
174	int	B_flag = 0;
175	int	c;
176	int	fd1;
177	int	n;
178	int	secsize = 512;
179	int	v_flag = 0, version;
180
181	while ((c = getopt(argc, argv, "BF:f:i:m:s:v:")) != -1) {
182		switch (c) {
183		case 'B':
184			B_flag = 1;
185			break;
186		case 'F':
187			menubakpath = optarg;
188			break;
189		case 'f':
190			iplbakpath = optarg;
191			break;
192		case 'i':
193			iplpath = optarg;
194			break;
195		case 'm':
196			menupath = optarg;
197			break;
198		case 's':
199			secsize = strtol(optarg, &endptr, 0);
200			if (errno || *optarg == NULL || *endptr)
201				errx(1, "%s: Bad argument to -s option",
202				    optarg);
203			switch (secsize) {
204			case 256:
205			case 512:
206			case 1024:
207			case 2048:
208				break;
209			default:
210				errx(1, "%s: unsupported sector size", optarg);
211				break;
212			}
213			break;
214		case 'v':
215			v_flag = 1;
216			version = strtol(optarg, &endptr, 0);
217			if (errno || *optarg == NULL || *endptr ||
218			    version < 0 || version > 255)
219				errx(1, "%s: Bad argument to -s option",
220				    optarg);
221			break;
222		default:
223			usage();
224			/* NOTREACHED */
225			break;
226		}
227	}
228	argc -= optind;
229	argv += optind;
230	if (argc != 1)
231		usage();
232	disk = mkrdev(*argv);
233
234	read_boot(disk, boot0buf);
235
236	if (iplbakpath != NULL) {
237		fd1 = open(iplbakpath, O_WRONLY | O_CREAT | O_TRUNC, 0666);
238		if (fd1 < 0)
239			err(1, "%s", iplbakpath);
240		n = write(fd1, boot0buf, IPLSIZE);
241		if (n == -1)
242			err(1, "%s", iplbakpath);
243		if (n != IPLSIZE)
244			errx(1, "%s: short write", iplbakpath);
245		close(fd1);
246	}
247
248	if (menubakpath != NULL) {
249		fd1 = open(menubakpath, O_WRONLY | O_CREAT | O_TRUNC, 0666);
250		if (fd1 < 0)
251			err(1, "%s", menubakpath);
252		n = write(fd1, boot0buf + BOOTMENUOFF, BOOTMENUSIZE);
253		if (n == -1)
254			err(1, "%s", menubakpath);
255		if (n != BOOTMENUSIZE)
256			errx(1, "%s: short write", menubakpath);
257		close(fd1);
258	}
259
260	if (B_flag) {
261		/* Read IPL (boot0). */
262		fd1 = open(iplpath, O_RDONLY);
263		if (fd1 < 0)
264			err(1, "%s", disk);
265		n = read(fd1, ipl, IPLSIZE);
266		if (n < 0)
267			err(1, "%s", iplpath);
268		if (n != IPLSIZE)
269			errx(1, "%s: invalid file", iplpath);
270		close(fd1);
271
272		/* Read HDD boot menu (boot0.5). */
273		fd1 = open(menupath, O_RDONLY);
274		if (fd1 < 0)
275			err(1, "%s", disk);
276		n = read(fd1, menu, BOOTMENUSIZE);
277		if (n < 0)
278			err(1, "%s", menupath);
279		if (n != BOOTMENUSIZE)
280			errx(1, "%s: invalid file", menupath);
281		close(fd1);
282
283		memcpy(boot0buf, ipl, IPLSIZE);
284		memcpy(boot0buf + BOOTMENUOFF, menu, BOOTMENUSIZE);
285	}
286
287	/* Set version number field. */
288	if (v_flag)
289		*(boot0buf + secsize - 4) = (u_char)version;
290
291	if (B_flag || v_flag)
292		write_boot(disk, boot0buf);
293
294	return 0;
295}
296