xref: /trueos/usr.sbin/boot98cfg/boot98cfg.c (revision 9394ef331eb7d0ba7f22583970cc84b62ad9f19a)
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 
80 u_char	boot0buf[BOOTSIZE];
81 u_char	ipl[IPLSIZE];
82 u_char	menu[BOOTMENUSIZE];
83 
84 static	int read_boot(const char *, u_char *);
85 static	int write_boot(const char *, u_char *);
86 static	char *mkrdev(const char *);
87 static	void usage(void);
88 
89 /*
90  * Boot manager installation/configuration utility.
91  */
92 int
main(int argc,char * argv[])93 main(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 
222 static int
read_boot(const char * disk,u_char * boot)223 read_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 
239 static int
write_boot(const char * disk,u_char * boot)240 write_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  */
292 static char *
mkrdev(const char * fname)293 mkrdev(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  */
312 static void
usage(void)313 usage(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