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