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