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