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
32/*
33 * Copyright (c) 1999 Robert Nordier
34 * All rights reserved.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 * 1. Redistributions of source code must retain the above copyright
40 *    notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 *    notice, this list of conditions and the following disclaimer in the
43 *    documentation and/or other materials provided with the distribution.
44 *
45 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS``AS IS'' AND
46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
48 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
49 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
50 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
51 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
52 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
53 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
54 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
55 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
56 */
57
58#include <sys/cdefs.h>
59__FBSDID("$FreeBSD$");
60
61#include <sys/param.h>
62#include <sys/diskpc98.h>
63#include <sys/stat.h>
64
65#include <err.h>
66#include <errno.h>
67#include <fcntl.h>
68#include <libgeom.h>
69#include <paths.h>
70#include <stdio.h>
71#include <stdlib.h>
72#include <string.h>
73#include <unistd.h>
74
75#define	BOOTSIZE		0x2000
76#define	IPLSIZE			512		/* IPL size */
77#define	BOOTMENUSIZE		7168		/* Max HDD boot menu size */
78#define	BOOTMENUOFF		0x400
79
80u_char	boot0buf[BOOTSIZE];
81u_char	ipl[IPLSIZE];
82u_char	menu[BOOTMENUSIZE];
83
84static	int read_boot(const char *, u_char *);
85static	int write_boot(const char *, u_char *);
86static	char *mkrdev(const char *);
87static	void usage(void);
88
89/*
90 * Boot manager installation/configuration utility.
91 */
92int
93main(int argc, char *argv[])
94{
95	char	*endptr;
96	const	char *iplpath = "/boot/boot0", *menupath = "/boot/boot0.5";
97	char	*iplbakpath = NULL, *menubakpath = NULL;
98	char	*disk;
99	int	B_flag = 0;
100	int	c;
101	int	fd1;
102	int	n;
103	int	secsize = 512;
104	int	v_flag = 0, version;
105
106	while ((c = getopt(argc, argv, "BF:f:i:m:s:v:")) != -1) {
107		switch (c) {
108		case 'B':
109			B_flag = 1;
110			break;
111		case 'F':
112			menubakpath = optarg;
113			break;
114		case 'f':
115			iplbakpath = optarg;
116			break;
117		case 'i':
118			iplpath = optarg;
119			break;
120		case 'm':
121			menupath = optarg;
122			break;
123		case 's':
124			secsize = strtol(optarg, &endptr, 0);
125			if (errno || *optarg == '\0' || *endptr)
126				errx(1, "%s: Bad argument to -s option",
127				    optarg);
128			switch (secsize) {
129			case 256:
130			case 512:
131			case 1024:
132			case 2048:
133				break;
134			default:
135				errx(1, "%s: unsupported sector size", optarg);
136				break;
137			}
138			break;
139		case 'v':
140			v_flag = 1;
141			version = strtol(optarg, &endptr, 0);
142			if (errno || *optarg == '\0' || *endptr ||
143			    version < 0 || version > 255)
144				errx(1, "%s: Bad argument to -v option",
145				    optarg);
146			break;
147		default:
148			usage();
149			/* NOTREACHED */
150			break;
151		}
152	}
153	argc -= optind;
154	argv += optind;
155	if (argc != 1)
156		usage();
157	disk = mkrdev(*argv);
158
159	read_boot(disk, boot0buf);
160
161	if (iplbakpath != NULL) {
162		fd1 = open(iplbakpath, O_WRONLY | O_CREAT | O_TRUNC, 0666);
163		if (fd1 < 0)
164			err(1, "%s", iplbakpath);
165		n = write(fd1, boot0buf, IPLSIZE);
166		if (n == -1)
167			err(1, "%s", iplbakpath);
168		if (n != IPLSIZE)
169			errx(1, "%s: short write", iplbakpath);
170		close(fd1);
171	}
172
173	if (menubakpath != NULL) {
174		fd1 = open(menubakpath, O_WRONLY | O_CREAT | O_TRUNC, 0666);
175		if (fd1 < 0)
176			err(1, "%s", menubakpath);
177		n = write(fd1, boot0buf + BOOTMENUOFF, BOOTMENUSIZE);
178		if (n == -1)
179			err(1, "%s", menubakpath);
180		if (n != BOOTMENUSIZE)
181			errx(1, "%s: short write", menubakpath);
182		close(fd1);
183	}
184
185	if (B_flag) {
186		/* Read IPL (boot0). */
187		fd1 = open(iplpath, O_RDONLY);
188		if (fd1 < 0)
189			err(1, "%s", disk);
190		n = read(fd1, ipl, IPLSIZE);
191		if (n < 0)
192			err(1, "%s", iplpath);
193		if (n != IPLSIZE)
194			errx(1, "%s: invalid file", iplpath);
195		close(fd1);
196
197		/* Read HDD boot menu (boot0.5). */
198		fd1 = open(menupath, O_RDONLY);
199		if (fd1 < 0)
200			err(1, "%s", disk);
201		n = read(fd1, menu, BOOTMENUSIZE);
202		if (n < 0)
203			err(1, "%s", menupath);
204		if (n != BOOTMENUSIZE)
205			errx(1, "%s: invalid file", menupath);
206		close(fd1);
207
208		memcpy(boot0buf, ipl, IPLSIZE);
209		memcpy(boot0buf + BOOTMENUOFF, menu, BOOTMENUSIZE);
210	}
211
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 < PC98_NPARTS; 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