xref: /netbsd-src/sys/arch/i386/stand/dosboot/main.c (revision fdecd6a253f999ae92b139670d9e15cc9df4497c)
1 /*	$NetBSD: main.c,v 1.3 1997/06/13 13:24:10 drochner 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 void ls  __P((char *));
47 extern int getopt __P((int, char **, const char *));
48 
49 int             errno;
50 static char    *consdev;
51 
52 extern char     version[];
53 
54 #define MAXDEVNAME 16
55 
56 static char    *current_fsmode;
57 static char    *default_devname;
58 static int      default_unit, default_partition;
59 static char    *default_filename;
60 
61 int
62 parsebootfile(fname, fsmode, devname, unit, partition, file)
63 	const char     *fname;
64 	char          **fsmode;
65 	char          **devname;/* out */
66 	unsigned int   *unit, *partition;	/* out */
67 	const char    **file;	/* out */
68 {
69 	const char     *col, *help;
70 
71 	*fsmode = current_fsmode;
72 	*devname = default_devname;
73 	*unit = default_unit;
74 	*partition = default_partition;
75 	*file = default_filename;
76 
77 	if (!fname)
78 		return (0);
79 
80 	if ((col = strchr(fname, ':'))) {	/* device given */
81 		static char     savedevname[MAXDEVNAME + 1];
82 		int             devlen;
83 		unsigned int    u = 0, p = 0;
84 		int             i = 0;
85 
86 		devlen = col - fname;
87 		if (devlen > MAXDEVNAME)
88 			return (EINVAL);
89 
90 #define isvalidname(c) ((c) >= 'a' && (c) <= 'z')
91 		if (!isvalidname(fname[i]))
92 			return (EINVAL);
93 		do {
94 			savedevname[i] = fname[i];
95 			i++;
96 		} while (isvalidname(fname[i]));
97 		savedevname[i] = '\0';
98 
99 #define isnum(c) ((c) >= '0' && (c) <= '9')
100 		if (i < devlen) {
101 			if (!isnum(fname[i]))
102 				return (EUNIT);
103 			do {
104 				u *= 10;
105 				u += fname[i++] - '0';
106 			} while (isnum(fname[i]));
107 		}
108 #define isvalidpart(c) ((c) >= 'a' && (c) <= 'z')
109 		if (i < devlen) {
110 			if (!isvalidpart(fname[i]))
111 				return (EPART);
112 			p = fname[i++] - 'a';
113 		}
114 		if (i != devlen)
115 			return (ENXIO);
116 
117 		*devname = savedevname;
118 		*unit = u;
119 		*partition = p;
120 		help = col + 1;
121 	} else
122 		help = fname;
123 
124 	if (*help)
125 		*file = help;
126 
127 	return (0);
128 }
129 
130 static void
131 print_bootsel(filename)
132 	char           *filename;
133 {
134 	char           *fsname;
135 	char           *devname;
136 	int             unit, partition;
137 	const char     *file;
138 
139 	if (!parsebootfile(filename, &fsname, &devname, &unit,
140 	    &partition, &file)) {
141 		if (!strcmp(fsname, "dos"))
142 			printf("booting %s\n", file);
143 		else if (!strcmp(fsname, "ufs"))
144 			printf("booting %s%d%c:%s\n", devname, unit,
145 			       'a' + partition, file);
146 	}
147 }
148 
149 static void
150 bootit(filename, howto, tell)
151 	const char     *filename;
152 	int             howto, tell;
153 {
154 	if (tell)
155 		print_bootsel(filename);
156 
157 	if (exec_netbsd(filename, 0, howto, 0, consdev) < 0)
158 		printf("boot: %s\n", strerror(errno));
159 	else
160 		printf("boot returned\n");
161 }
162 
163 static void
164 helpme()
165 {
166 	printf("commands are:\n"
167 	       "boot [xdNx:][filename] [-adrs]\n"
168 	       "     (ex. \"sd0a:netbsd.old -s\"\n"
169 	       "ls [path]\n"
170 	       "mode ufs|dos\n"
171 	       "help|?\n"
172 	       "quit\n");
173 }
174 
175 /*
176  * chops the head from the arguments and returns the arguments if any,
177  * or possibly an empty string.
178  */
179 static char    *
180 gettrailer(arg)
181 	char           *arg;
182 {
183 	char           *options;
184 
185 	if ((options = strchr(arg, ' ')) == NULL)
186 		options = "";
187 	else
188 		*options++ = '\0';
189 	/* trim leading blanks */
190 	while (*options && *options == ' ')
191 		options++;
192 
193 	return (options);
194 }
195 
196 static int
197 parseopts(opts, howto)
198 	char           *opts;
199 	int            *howto;
200 {
201 	int             tmpopt = 0;
202 
203 	opts++;			/* skip - */
204 	while (*opts && *opts != ' ') {
205 		tmpopt |= netbsd_opt(*opts);
206 		if (tmpopt == -1) {
207 			printf("-%c: unknown flag\n", *opts);
208 			helpme();
209 			return (0);
210 		}
211 		opts++;
212 	}
213 	*howto = tmpopt;
214 	return (1);
215 }
216 
217 static int
218 parseboot(arg, filename, howto)
219 	char           *arg;
220 	char          **filename;
221 	int            *howto;
222 {
223 	char           *opts = NULL;
224 
225 	*filename = 0;
226 	*howto = 0;
227 
228 	/* if there were no arguments */
229 	if (!*arg)
230 		return (1);
231 
232 	/* format is... */
233 	/* [[xxNx:]filename] [-adrs] */
234 
235 	/* check for just args */
236 	if (arg[0] == '-') {
237 		opts = arg;
238 	} else {		/* at least a file name */
239 		*filename = arg;
240 
241 		opts = gettrailer(arg);
242 		if (!*opts)
243 			opts = NULL;
244 		else if (*opts != '-') {
245 			printf("invalid arguments\n");
246 			helpme();
247 			return (0);
248 		}
249 	}
250 	/* at this point, we have dealt with filenames. */
251 
252 	/* now, deal with options */
253 	if (opts) {
254 		if (!parseopts(opts, howto))
255 			return (0);
256 	}
257 	return (1);
258 }
259 
260 static void
261 parsemode(arg, mode)
262 	char           *arg;
263 	char          **mode;
264 {
265 	if (!strcmp("dos", arg))
266 		*mode = "dos";
267 	else if (!strcmp("ufs", arg))
268 		*mode = "ufs";
269 	else
270 		printf("invalid mode\n");
271 }
272 
273 static void
274 docommand(arg)
275 	char           *arg;
276 {
277 	char           *options;
278 
279 	options = gettrailer(arg);
280 
281 	if ((strcmp("help", arg) == 0) ||
282 	    (strcmp("?", arg) == 0)) {
283 		helpme();
284 		return;
285 	}
286 	if (strcmp("ls", arg) == 0) {
287 		char           *help = default_filename;
288 		if (strcmp(current_fsmode, "ufs")) {
289 			printf("UFS only\n");
290 			return;
291 		}
292 		default_filename = "/";
293 		ls(options);
294 		default_filename = help;
295 		return;
296 	}
297 	if (strcmp("quit", arg) == 0) {
298 		printf("Exiting... goodbye...\n");
299 		exit(0);
300 	}
301 	if (strcmp("boot", arg) == 0) {
302 		char           *filename;
303 		int             howto;
304 		if (parseboot(options, &filename, &howto))
305 			bootit(filename, howto, 1);
306 		return;
307 	}
308 	if (strcmp("mode", arg) == 0) {
309 		parsemode(options, &current_fsmode);
310 		return;
311 	}
312 	printf("unknown command\n");
313 	helpme();
314 }
315 
316 void
317 bootmenu()
318 {
319 	printf("\ntype \"?\" or \"help\" for help.\n");
320 	for (;;) {
321 		char            input[80];
322 
323 		input[0] = '\0';
324 		printf("> ");
325 		gets(input);
326 
327 		docommand(input);
328 	}
329 }
330 
331 static void
332 print_banner(void)
333 {
334 	printf("\n"
335 	       ">> NetBSD BOOT: %d/%d k [%s]\n",
336 	       getbasemem(),
337 	       getextmem(),
338 	       version);
339 }
340 
341 void
342 usage()
343 {
344 	printf("dosboot [-u] [-c <commands>] [-i] [filename [-bootopts]]\n");
345 }
346 
347 int
348 main(argc, argv)
349 	int             argc;
350 	char          **argv;
351 {
352 	int             ch;
353 	int             interactive = 0;
354 	int             howto;
355 	extern char    *optarg;
356 	extern int      optind;
357 
358 	consdev = initio(CONSDEV_PC);
359 	gateA20();
360 
361 	print_banner();
362 
363 	current_fsmode = "dos";
364 	default_devname = "hd";
365 	default_unit = 0;
366 	default_partition = 0;
367 	default_filename = "netbsd";
368 
369 	while ((ch = getopt(argc, argv, "c:iu")) != -1) {
370 		switch (ch) {
371 		case 'c':
372 			docommand(optarg);
373 			return (1);
374 			break;
375 		case 'i':
376 			interactive = 1;
377 			break;
378 		case 'u':
379 			current_fsmode = "ufs";
380 			break;
381 		default:
382 			usage();
383 			return (1);
384 		}
385 	}
386 
387 	if (interactive)
388 		bootmenu();
389 
390 	argc -= optind;
391 	argv += optind;
392 
393 	if (argc > 2) {
394 		usage();
395 		return (1);
396 	}
397 	howto = 0;
398 	if (argc > 1 && !parseopts(argv[1], &howto))
399 		return (1);
400 
401 	bootit((argc > 0 ? argv[0] : "netbsd"), howto, 1);
402 	return (1);
403 }
404