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
47int errno;
48
49extern	char bootprog_name[], bootprog_rev[], bootprog_kernrev[];
50
51#define MAXDEVNAME 16
52
53static char    *current_fsmode;
54static char    *default_devname;
55static int      default_unit, default_partition;
56static char    *default_filename;
57
58char *sprint_bootsel(const char *);
59static void bootit(const char *, int, int);
60void usage(void);
61int main(int, char **);
62
63void	command_help(char *);
64void	command_ls(char *);
65void	command_quit(char *);
66void	command_boot(char *);
67void	command_mode(char *);
68void	command_dev(char *);
69
70const 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
81int
82parsebootfile(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
151char *
152sprint_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	}
169bad:
170	return ("(invalid)");
171}
172
173static void
174bootit(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
190static void
191print_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
221void
222usage(void)
223{
224	printf("dosboot [-u] [-c <commands>] [-i] [filename [-bootopts]]\n");
225}
226
227int
228main(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 */
290void
291command_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
303void
304command_ls(char *arg)
305{
306	char *help = default_filename;
307	default_filename = "/";
308	ls(arg);
309	default_filename = help;
310}
311
312/* ARGSUSED */
313void
314command_quit(char *arg)
315{
316	printf("Exiting... goodbye...\n");
317	_rtt();
318}
319
320void
321command_boot(char *arg)
322{
323	char *filename;
324	int howto;
325
326	if (parseboot(arg, &filename, &howto))
327		bootit(filename, howto, 1);
328}
329
330void
331command_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
341void
342command_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