xref: /netbsd-src/sys/arch/i386/stand/dosboot/main.c (revision d0fed6c87ddc40a8bffa6f99e7433ddfc864dd83)
1 /*	$NetBSD: main.c,v 1.2 1997/03/22 09:06:20 thorpej Exp $	 */
2 
3 /*
4  * Copyright (c) 1996, 1997
5  * 	Matthias Drochner.  All rights reserved.
6  * Copyright (c) 1996, 1997
7  * 	Perry E. Metzger.  All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
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. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgements:
19  *	This product includes software developed for the NetBSD Project
20  *	by Matthias Drochner.
21  *	This product includes software developed for the NetBSD Project
22  *	by Perry E. Metzger.
23  * 4. The names of the authors may not be used to endorse or promote products
24  *    derived from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
27  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
28  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
29  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
30  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
31  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36  */
37 
38 
39 #include <sys/reboot.h>
40 
41 #include <lib/libkern/libkern.h>
42 #include <lib/libsa/stand.h>
43 
44 #include <libi386.h>
45 
46 extern char    *strerror __P((int));	/* XXX missing in stand.h */
47 
48 extern void ls  __P((char *));
49 extern int getopt __P((int, char **, const char *));
50 
51 int             errno;
52 static char    *consdev;
53 
54 extern char     version[];
55 
56 #define MAXDEVNAME 16
57 
58 static char    *current_fsmode;
59 static char    *default_devname;
60 static int      default_unit, default_partition;
61 static char    *default_filename;
62 
63 int
64 parsebootfile(fname, fsmode, devname, unit, partition, file)
65 	const char     *fname;
66 	char          **fsmode;
67 	char          **devname;/* out */
68 	unsigned int   *unit, *partition;	/* out */
69 	const char    **file;	/* out */
70 {
71 	const char     *col, *help;
72 
73 	*fsmode = current_fsmode;
74 	*devname = default_devname;
75 	*unit = default_unit;
76 	*partition = default_partition;
77 	*file = default_filename;
78 
79 	if (!fname)
80 		return (0);
81 
82 	if ((col = strchr(fname, ':'))) {	/* device given */
83 		static char     savedevname[MAXDEVNAME + 1];
84 		int             devlen;
85 		unsigned int    u = 0, p = 0;
86 		int             i = 0;
87 
88 		devlen = col - fname;
89 		if (devlen > MAXDEVNAME)
90 			return (EINVAL);
91 
92 #define isvalidname(c) ((c) >= 'a' && (c) <= 'z')
93 		if (!isvalidname(fname[i]))
94 			return (EINVAL);
95 		do {
96 			savedevname[i] = fname[i];
97 			i++;
98 		} while (isvalidname(fname[i]));
99 		savedevname[i] = '\0';
100 
101 #define isnum(c) ((c) >= '0' && (c) <= '9')
102 		if (i < devlen) {
103 			if (!isnum(fname[i]))
104 				return (EUNIT);
105 			do {
106 				u *= 10;
107 				u += fname[i++] - '0';
108 			} while (isnum(fname[i]));
109 		}
110 #define isvalidpart(c) ((c) >= 'a' && (c) <= 'z')
111 		if (i < devlen) {
112 			if (!isvalidpart(fname[i]))
113 				return (EPART);
114 			p = fname[i++] - 'a';
115 		}
116 		if (i != devlen)
117 			return (ENXIO);
118 
119 		*devname = savedevname;
120 		*unit = u;
121 		*partition = p;
122 		help = col + 1;
123 	} else
124 		help = fname;
125 
126 	if (*help)
127 		*file = help;
128 
129 	return (0);
130 }
131 
132 static void
133 print_bootsel(filename)
134 	char           *filename;
135 {
136 	char           *fsname;
137 	char           *devname;
138 	int             unit, partition;
139 	const char     *file;
140 
141 	if (!parsebootfile(filename, &fsname, &devname, &unit,
142 	    &partition, &file)) {
143 		if (!strcmp(fsname, "dos"))
144 			printf("booting %s\n", file);
145 		else if (!strcmp(fsname, "ufs"))
146 			printf("booting %s%d%c:%s\n", devname, unit,
147 			       'a' + partition, file);
148 	}
149 }
150 
151 static void
152 bootit(filename, howto, tell)
153 	const char     *filename;
154 	int             howto, tell;
155 {
156 	if (tell)
157 		print_bootsel(filename);
158 
159 	if (exec_netbsd(filename, 0, howto, 0, consdev) < 0)
160 		printf("boot: %s\n", strerror(errno));
161 	else
162 		printf("boot returned\n");
163 }
164 
165 static void
166 helpme()
167 {
168 	printf("commands are:\n"
169 	       "boot [xdNx:][filename] [-adrs]\n"
170 	       "     (ex. \"sd0a:netbsd.old -s\"\n"
171 	       "ls [path]\n"
172 	       "mode ufs|dos\n"
173 	       "help|?\n"
174 	       "quit\n");
175 }
176 
177 /*
178  * chops the head from the arguments and returns the arguments if any,
179  * or possibly an empty string.
180  */
181 static char    *
182 gettrailer(arg)
183 	char           *arg;
184 {
185 	char           *options;
186 
187 	if ((options = strchr(arg, ' ')) == NULL)
188 		options = "";
189 	else
190 		*options++ = '\0';
191 	/* trim leading blanks */
192 	while (*options && *options == ' ')
193 		options++;
194 
195 	return (options);
196 }
197 
198 static int
199 parseopts(opts, howto)
200 	char           *opts;
201 	int            *howto;
202 {
203 	int             tmpopt = 0;
204 
205 	opts++;			/* skip - */
206 	while (*opts && *opts != ' ') {
207 		tmpopt |= netbsd_opt(*opts);
208 		if (tmpopt == -1) {
209 			printf("-%c: unknown flag\n", *opts);
210 			helpme();
211 			return (0);
212 		}
213 		opts++;
214 	}
215 	*howto = tmpopt;
216 	return (1);
217 }
218 
219 static int
220 parseboot(arg, filename, howto)
221 	char           *arg;
222 	char          **filename;
223 	int            *howto;
224 {
225 	char           *opts = NULL;
226 
227 	*filename = 0;
228 	*howto = 0;
229 
230 	/* if there were no arguments */
231 	if (!*arg)
232 		return (1);
233 
234 	/* format is... */
235 	/* [[xxNx:]filename] [-adrs] */
236 
237 	/* check for just args */
238 	if (arg[0] == '-') {
239 		opts = arg;
240 	} else {		/* at least a file name */
241 		*filename = arg;
242 
243 		opts = gettrailer(arg);
244 		if (!*opts)
245 			opts = NULL;
246 		else if (*opts != '-') {
247 			printf("invalid arguments\n");
248 			helpme();
249 			return (0);
250 		}
251 	}
252 	/* at this point, we have dealt with filenames. */
253 
254 	/* now, deal with options */
255 	if (opts) {
256 		if (!parseopts(opts, howto))
257 			return (0);
258 	}
259 	return (1);
260 }
261 
262 static void
263 parsemode(arg, mode)
264 	char           *arg;
265 	char          **mode;
266 {
267 	if (!strcmp("dos", arg))
268 		*mode = "dos";
269 	else if (!strcmp("ufs", arg))
270 		*mode = "ufs";
271 	else
272 		printf("invalid mode\n");
273 }
274 
275 static void
276 docommand(arg)
277 	char           *arg;
278 {
279 	char           *options;
280 
281 	options = gettrailer(arg);
282 
283 	if ((strcmp("help", arg) == 0) ||
284 	    (strcmp("?", arg) == 0)) {
285 		helpme();
286 		return;
287 	}
288 	if (strcmp("ls", arg) == 0) {
289 		char           *help = default_filename;
290 		if (strcmp(current_fsmode, "ufs")) {
291 			printf("UFS only\n");
292 			return;
293 		}
294 		default_filename = "/";
295 		ls(options);
296 		default_filename = help;
297 		return;
298 	}
299 	if (strcmp("quit", arg) == 0) {
300 		printf("Exiting... goodbye...\n");
301 		exit(0);
302 	}
303 	if (strcmp("boot", arg) == 0) {
304 		char           *filename;
305 		int             howto;
306 		if (parseboot(options, &filename, &howto))
307 			bootit(filename, howto, 1);
308 		return;
309 	}
310 	if (strcmp("mode", arg) == 0) {
311 		parsemode(options, &current_fsmode);
312 		return;
313 	}
314 	printf("unknown command\n");
315 	helpme();
316 }
317 
318 void
319 bootmenu()
320 {
321 	printf("\ntype \"?\" or \"help\" for help.\n");
322 	for (;;) {
323 		char            input[80];
324 
325 		input[0] = '\0';
326 		printf("> ");
327 		gets(input);
328 
329 		docommand(input);
330 	}
331 }
332 
333 static void
334 print_banner(void)
335 {
336 	printf("\n"
337 	       ">> NetBSD BOOT: %d/%d k [%s]\n",
338 	       getbasemem(),
339 	       getextmem(),
340 	       version);
341 }
342 
343 void
344 usage()
345 {
346 	printf("dosboot [-u] [-c <commands>] [-i] [filename [-bootopts]]\n");
347 }
348 
349 int
350 main(argc, argv)
351 	int             argc;
352 	char          **argv;
353 {
354 	int             ch;
355 	int             interactive = 0;
356 	int             howto;
357 	extern char    *optarg;
358 	extern int      optind;
359 
360 	consdev = initio(CONSDEV_PC);
361 	gateA20();
362 
363 	print_banner();
364 
365 	current_fsmode = "dos";
366 	default_devname = "hd";
367 	default_unit = 0;
368 	default_partition = 0;
369 	default_filename = "netbsd";
370 
371 	while ((ch = getopt(argc, argv, "c:iu")) != -1) {
372 		switch (ch) {
373 		case 'c':
374 			docommand(optarg);
375 			return (1);
376 			break;
377 		case 'i':
378 			interactive = 1;
379 			break;
380 		case 'u':
381 			current_fsmode = "ufs";
382 			break;
383 		default:
384 			usage();
385 			return (1);
386 		}
387 	}
388 
389 	if (interactive)
390 		bootmenu();
391 
392 	argc -= optind;
393 	argv += optind;
394 
395 	if (argc > 2) {
396 		usage();
397 		return (1);
398 	}
399 	howto = 0;
400 	if (argc > 1 && !parseopts(argv[1], &howto))
401 		return (1);
402 
403 	bootit((argc > 0 ? argv[0] : "netbsd"), howto, 1);
404 	return (1);
405 }
406