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