xref: /netbsd-src/sys/arch/i386/stand/dosboot/main.c (revision 4b896b232495b7a9b8b94a1cf1e21873296d53b8)
1 /*	$NetBSD: main.c,v 1.19 2003/08/31 22:40:13 fvdl 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 #include <lib/libsa/ufs.h>
44 
45 #include <libi386.h>
46 
47 #ifdef SUPPORT_LYNX
48 extern int exec_lynx __P((const char*, int));
49 #endif
50 
51 int errno;
52 
53 extern	char bootprog_name[], bootprog_rev[], bootprog_date[],
54 	bootprog_maker[];
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 char *sprint_bootsel __P((const char *));
64 static void bootit __P((const char *, int, int));
65 void usage __P((void));
66 int main __P((int, char **));
67 int parsebootfile __P((const char *, char**, char**, unsigned int*,
68 			      unsigned int*, const char**));
69 
70 void	command_help __P((char *));
71 void	command_ls __P((char *));
72 void	command_quit __P((char *));
73 void	command_boot __P((char *));
74 void	command_mode __P((char *));
75 void	command_dev __P((char *));
76 
77 const struct bootblk_command commands[] = {
78 	{ "help",	command_help },
79 	{ "?",		command_help },
80 	{ "ls",		command_ls },
81 	{ "quit",	command_quit },
82 	{ "boot",	command_boot },
83 	{ "mode",	command_mode },
84 	{ "dev",	command_dev },
85 	{ NULL,		NULL },
86 };
87 
88 int
89 parsebootfile(fname, fsmode, devname, unit, partition, file)
90 	const char     *fname;
91 	char          **fsmode; /* out */
92 	char          **devname; /* out */
93 	unsigned int   *unit, *partition; /* out */
94 	const char    **file; /* out */
95 {
96 	const char     *col, *help;
97 
98 	*fsmode = current_fsmode;
99 	*devname = default_devname;
100 	*unit = default_unit;
101 	*partition = default_partition;
102 	*file = default_filename;
103 
104 	if (fname == NULL)
105 		return (0);
106 
107 	if (strcmp(current_fsmode, "dos") && (col = strchr(fname, ':'))) {
108 		/* no DOS, device given */
109 		static char     savedevname[MAXDEVNAME + 1];
110 		int             devlen;
111 		unsigned int    u = 0, p = 0;
112 		int             i = 0;
113 
114 		devlen = col - fname;
115 		if (devlen > MAXDEVNAME)
116 			return (EINVAL);
117 
118 #define isvalidname(c) ((c) >= 'a' && (c) <= 'z')
119 		if (!isvalidname(fname[i]))
120 			return (EINVAL);
121 		do {
122 			savedevname[i] = fname[i];
123 			i++;
124 		} while (isvalidname(fname[i]));
125 		savedevname[i] = '\0';
126 
127 #define isnum(c) ((c) >= '0' && (c) <= '9')
128 		if (i < devlen) {
129 			if (!isnum(fname[i]))
130 				return (EUNIT);
131 			do {
132 				u *= 10;
133 				u += fname[i++] - '0';
134 			} while (isnum(fname[i]));
135 		}
136 
137 #define isvalidpart(c) ((c) >= 'a' && (c) <= 'z')
138 		if (i < devlen) {
139 			if (!isvalidpart(fname[i]))
140 				return (EPART);
141 			p = fname[i++] - 'a';
142 		}
143 		if (i != devlen)
144 			return (ENXIO);
145 
146 		*devname = savedevname;
147 		*unit = u;
148 		*partition = p;
149 		help = col + 1;
150 	} else
151 		help = fname;
152 
153 	if (*help)
154 		*file = help;
155 
156 	return (0);
157 }
158 
159 char *
160 sprint_bootsel(filename)
161 	const char *filename;
162 {
163 	char *fsname, *devname;
164 	int unit, partition;
165 	const char *file;
166 	static char buf[80];
167 
168 	if (parsebootfile(filename, &fsname, &devname, &unit,
169 			  &partition, &file) == 0) {
170 		if (!strcmp(fsname, "dos"))
171 			sprintf(buf, "dos:%s", file);
172 		else if (!strcmp(fsname, "ufs"))
173 			sprintf(buf, "%s%d%c:%s", devname, unit,
174 				'a' + partition, file);
175 		else goto bad;
176 		return (buf);
177 	}
178 bad:
179 	return ("(invalid)");
180 }
181 
182 static void
183 bootit(filename, howto, tell)
184 	const char     *filename;
185 	int             howto, tell;
186 {
187 	if (tell) {
188 		printf("booting %s", sprint_bootsel(filename));
189 		if (howto)
190 			printf(" (howto 0x%x)", howto);
191 		printf("\n");
192 	}
193 #ifdef SUPPORT_LYNX
194 	if(exec_netbsd(filename, 0, howto) < 0)
195 		printf("boot netbsd: %s: %s\n", sprint_bootsel(filename),
196 		       strerror(errno));
197 	else {
198 		printf("boot netbsd returned\n");
199 		return;
200 	}
201 	if (exec_lynx(filename, 0) < 0)
202 		printf("boot lynx: %s: %s\n", sprint_bootsel(filename),
203 		       strerror(errno));
204 	else
205 		printf("boot lynx returned\n");
206 #else
207 	if (exec_netbsd(filename, 0, howto) < 0)
208 		printf("boot: %s: %s\n", sprint_bootsel(filename),
209 		       strerror(errno));
210 	else
211 		printf("boot returned\n");
212 #endif
213 }
214 
215 static void
216 print_banner(void)
217 {
218 	int extmem = getextmem();
219 	char *s = "";
220 
221 #ifdef XMS
222 	u_long xmsmem;
223 	if (getextmem1() == 0 && (xmsmem = checkxms()) != 0) {
224 		/*
225 		 * With "CONSERVATIVE_MEMDETECT", extmem is 0 because
226 		 *  getextmem() is getextmem1(). Without, the "smart"
227 		 *  methods could fail to report all memory as well.
228 		 * xmsmem is a few kB less than the actual size, but
229 		 *  better than nothing.
230 		 */
231 		if ((int)xmsmem > extmem)
232 			extmem = xmsmem;
233 		s = "(xms) ";
234 	}
235 #endif
236 
237 	printf("\n");
238 	printf(">> %s, Revision %s\n", bootprog_name, bootprog_rev);
239 	printf(">> (%s, %s)\n", bootprog_maker, bootprog_date);
240 	printf(">> Memory: %d/%d %sk\n", getbasemem(), extmem, s);
241 }
242 
243 void
244 usage()
245 {
246 	printf("dosboot [-u] [-c <commands>] [-i] [filename [-bootopts]]\n");
247 }
248 
249 int
250 main(argc, argv)
251 	int             argc;
252 	char          **argv;
253 {
254 	int             ch;
255 	int             interactive = 0;
256 	int             howto;
257 	extern char    *optarg;
258 	extern int      optind;
259 
260 #ifdef	SUPPORT_SERIAL
261 	initio(SUPPORT_SERIAL);
262 #else
263 	initio(CONSDEV_PC);
264 #endif
265 	gateA20();
266 
267 	print_banner();
268 
269 	current_fsmode = "dos";
270 	default_devname = "hd";
271 	default_unit = 0;
272 	default_partition = 0;
273 	default_filename = "netbsd";
274 
275 	while ((ch = getopt(argc, argv, "c:iu")) != -1) {
276 		switch (ch) {
277 		case 'c':
278 			docommand(optarg);
279 			return (1);
280 			break;
281 		case 'i':
282 			interactive = 1;
283 			break;
284 		case 'u':
285 			current_fsmode = "ufs";
286 			break;
287 		default:
288 			usage();
289 			return (1);
290 		}
291 	}
292 
293 	if (interactive) {
294 		printf("type \"?\" or \"help\" for help.\n");
295 		bootmenu();
296 	}
297 
298 	argc -= optind;
299 	argv += optind;
300 
301 	if (argc > 2) {
302 		usage();
303 		return (1);
304 	}
305 	howto = 0;
306 	if (argc > 1 && !parseopts(argv[1], &howto))
307 		return (1);
308 
309 	bootit((argc > 0 ? argv[0] : "netbsd"), howto, 1);
310 	return (1);
311 }
312 
313 /* ARGSUSED */
314 void
315 command_help(arg)
316 	char *arg;
317 {
318 	printf("commands are:\n"
319 	       "boot [xdNx:][filename] [-acdqsv]\n"
320 	       "     (ex. \"sd0a:netbsd.old -s\"\n"
321 	       "ls [path]\n"
322 	       "mode ufs|dos\n"
323 	       "dev xd[N[x]]:\n"
324 	       "help|?\n"
325 	       "quit\n");
326 }
327 
328 void
329 command_ls(arg)
330 	char *arg;
331 {
332 	char *help = default_filename;
333 	if (strcmp(current_fsmode, "ufs")) {
334 		printf("UFS only\n");
335 		return;
336 	}
337 	default_filename = "/";
338 	ufs_ls(arg);
339 	default_filename = help;
340 }
341 
342 /* ARGSUSED */
343 void
344 command_quit(arg)
345 	char *arg;
346 {
347 	printf("Exiting... goodbye...\n");
348 	exit(0);
349 }
350 
351 void
352 command_boot(arg)
353 	char *arg;
354 {
355 	char *filename;
356 	int howto;
357 
358 	if (parseboot(arg, &filename, &howto))
359 		bootit(filename, howto, 1);
360 }
361 
362 void
363 command_mode(arg)
364 	char *arg;
365 {
366 	if (!strcmp("dos", arg))
367 		current_fsmode = "dos";
368 	else if (!strcmp("ufs", arg))
369 		current_fsmode = "ufs";
370 	else
371 		printf("invalid mode\n");
372 }
373 
374 void
375 command_dev(arg)
376 	char *arg;
377 {
378 	static char savedevname[MAXDEVNAME + 1];
379 	char *fsname, *devname;
380 	const char *file; /* dummy */
381 
382 	if (!strcmp(current_fsmode, "dos")) {
383 		printf("not available in DOS mode\n");
384 		return;
385 	}
386 
387 	if (*arg == '\0') {
388 		printf("%s%d%c:\n", default_devname, default_unit,
389 		       'a' + default_partition);
390 		return;
391 	}
392 
393 	if (!strchr(arg, ':') ||
394 	    parsebootfile(arg, &fsname, &devname, &default_unit,
395 			  &default_partition, &file)) {
396 		command_help(NULL);
397 		return;
398 	}
399 
400 	/* put to own static storage */
401 	strncpy(savedevname, devname, MAXDEVNAME + 1);
402 	default_devname = savedevname;
403 }
404