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