Home | History | Annotate | Line # | Download | only in dosboot
main.c revision 1.5
      1 /*	$NetBSD: main.c,v 1.5 1997/07/29 16:01:45 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 
     44 #include <libi386.h>
     45 
     46 extern void ls  __P((char *));
     47 extern int getopt __P((int, char **, const char *));
     48 
     49 int             errno;
     50 static char    *consdev;
     51 
     52 extern	char bootprog_name[], bootprog_rev[], bootprog_date[],
     53 	bootprog_maker[];
     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 int
     63 parsebootfile(fname, fsmode, devname, unit, partition, file)
     64 	const char     *fname;
     65 	char          **fsmode;
     66 	char          **devname;/* out */
     67 	unsigned int   *unit, *partition;	/* out */
     68 	const char    **file;	/* out */
     69 {
     70 	const char     *col, *help;
     71 
     72 	*fsmode = current_fsmode;
     73 	*devname = default_devname;
     74 	*unit = default_unit;
     75 	*partition = default_partition;
     76 	*file = default_filename;
     77 
     78 	if (!fname)
     79 		return (0);
     80 
     81 	if ((col = strchr(fname, ':'))) {	/* device given */
     82 		static char     savedevname[MAXDEVNAME + 1];
     83 		int             devlen;
     84 		unsigned int    u = 0, p = 0;
     85 		int             i = 0;
     86 
     87 		devlen = col - fname;
     88 		if (devlen > MAXDEVNAME)
     89 			return (EINVAL);
     90 
     91 #define isvalidname(c) ((c) >= 'a' && (c) <= 'z')
     92 		if (!isvalidname(fname[i]))
     93 			return (EINVAL);
     94 		do {
     95 			savedevname[i] = fname[i];
     96 			i++;
     97 		} while (isvalidname(fname[i]));
     98 		savedevname[i] = '\0';
     99 
    100 #define isnum(c) ((c) >= '0' && (c) <= '9')
    101 		if (i < devlen) {
    102 			if (!isnum(fname[i]))
    103 				return (EUNIT);
    104 			do {
    105 				u *= 10;
    106 				u += fname[i++] - '0';
    107 			} while (isnum(fname[i]));
    108 		}
    109 #define isvalidpart(c) ((c) >= 'a' && (c) <= 'z')
    110 		if (i < devlen) {
    111 			if (!isvalidpart(fname[i]))
    112 				return (EPART);
    113 			p = fname[i++] - 'a';
    114 		}
    115 		if (i != devlen)
    116 			return (ENXIO);
    117 
    118 		*devname = savedevname;
    119 		*unit = u;
    120 		*partition = p;
    121 		help = col + 1;
    122 	} else
    123 		help = fname;
    124 
    125 	if (*help)
    126 		*file = help;
    127 
    128 	return (0);
    129 }
    130 
    131 static void
    132 print_bootsel(filename)
    133 	char           *filename;
    134 {
    135 	char           *fsname;
    136 	char           *devname;
    137 	int             unit, partition;
    138 	const char     *file;
    139 
    140 	if (!parsebootfile(filename, &fsname, &devname, &unit,
    141 	    &partition, &file)) {
    142 		if (!strcmp(fsname, "dos"))
    143 			printf("booting %s\n", file);
    144 		else if (!strcmp(fsname, "ufs"))
    145 			printf("booting %s%d%c:%s\n", devname, unit,
    146 			       'a' + partition, file);
    147 	}
    148 }
    149 
    150 static void
    151 bootit(filename, howto, tell)
    152 	const char     *filename;
    153 	int             howto, tell;
    154 {
    155 	if (tell)
    156 		print_bootsel(filename);
    157 
    158 	if (exec_netbsd(filename, 0, howto, 0, consdev) < 0)
    159 		printf("boot: %s\n", strerror(errno));
    160 	else
    161 		printf("boot returned\n");
    162 }
    163 
    164 static void
    165 helpme()
    166 {
    167 	printf("commands are:\n"
    168 	       "boot [xdNx:][filename] [-adrs]\n"
    169 	       "     (ex. \"sd0a:netbsd.old -s\"\n"
    170 	       "ls [path]\n"
    171 	       "mode ufs|dos\n"
    172 	       "help|?\n"
    173 	       "quit\n");
    174 }
    175 
    176 /*
    177  * chops the head from the arguments and returns the arguments if any,
    178  * or possibly an empty string.
    179  */
    180 static char    *
    181 gettrailer(arg)
    182 	char           *arg;
    183 {
    184 	char           *options;
    185 
    186 	if ((options = strchr(arg, ' ')) == NULL)
    187 		options = "";
    188 	else
    189 		*options++ = '\0';
    190 	/* trim leading blanks */
    191 	while (*options && *options == ' ')
    192 		options++;
    193 
    194 	return (options);
    195 }
    196 
    197 static int
    198 parseopts(opts, howto)
    199 	char           *opts;
    200 	int            *howto;
    201 {
    202 	int             tmpopt = 0;
    203 
    204 	opts++;			/* skip - */
    205 	while (*opts && *opts != ' ') {
    206 		tmpopt |= netbsd_opt(*opts);
    207 		if (tmpopt == -1) {
    208 			printf("-%c: unknown flag\n", *opts);
    209 			helpme();
    210 			return (0);
    211 		}
    212 		opts++;
    213 	}
    214 	*howto = tmpopt;
    215 	return (1);
    216 }
    217 
    218 static int
    219 parseboot(arg, filename, howto)
    220 	char           *arg;
    221 	char          **filename;
    222 	int            *howto;
    223 {
    224 	char           *opts = NULL;
    225 
    226 	*filename = 0;
    227 	*howto = 0;
    228 
    229 	/* if there were no arguments */
    230 	if (!*arg)
    231 		return (1);
    232 
    233 	/* format is... */
    234 	/* [[xxNx:]filename] [-adrs] */
    235 
    236 	/* check for just args */
    237 	if (arg[0] == '-') {
    238 		opts = arg;
    239 	} else {		/* at least a file name */
    240 		*filename = arg;
    241 
    242 		opts = gettrailer(arg);
    243 		if (!*opts)
    244 			opts = NULL;
    245 		else if (*opts != '-') {
    246 			printf("invalid arguments\n");
    247 			helpme();
    248 			return (0);
    249 		}
    250 	}
    251 	/* at this point, we have dealt with filenames. */
    252 
    253 	/* now, deal with options */
    254 	if (opts) {
    255 		if (!parseopts(opts, howto))
    256 			return (0);
    257 	}
    258 	return (1);
    259 }
    260 
    261 static void
    262 parsemode(arg, mode)
    263 	char           *arg;
    264 	char          **mode;
    265 {
    266 	if (!strcmp("dos", arg))
    267 		*mode = "dos";
    268 	else if (!strcmp("ufs", arg))
    269 		*mode = "ufs";
    270 	else
    271 		printf("invalid mode\n");
    272 }
    273 
    274 static void
    275 docommand(arg)
    276 	char           *arg;
    277 {
    278 	char           *options;
    279 
    280 	options = gettrailer(arg);
    281 
    282 	if ((strcmp("help", arg) == 0) ||
    283 	    (strcmp("?", arg) == 0)) {
    284 		helpme();
    285 		return;
    286 	}
    287 	if (strcmp("ls", arg) == 0) {
    288 		char           *help = default_filename;
    289 		if (strcmp(current_fsmode, "ufs")) {
    290 			printf("UFS only\n");
    291 			return;
    292 		}
    293 		default_filename = "/";
    294 		ls(options);
    295 		default_filename = help;
    296 		return;
    297 	}
    298 	if (strcmp("quit", arg) == 0) {
    299 		printf("Exiting... goodbye...\n");
    300 		exit(0);
    301 	}
    302 	if (strcmp("boot", arg) == 0) {
    303 		char           *filename;
    304 		int             howto;
    305 		if (parseboot(options, &filename, &howto))
    306 			bootit(filename, howto, 1);
    307 		return;
    308 	}
    309 	if (strcmp("mode", arg) == 0) {
    310 		parsemode(options, &current_fsmode);
    311 		return;
    312 	}
    313 	printf("unknown command\n");
    314 	helpme();
    315 }
    316 
    317 void
    318 bootmenu()
    319 {
    320 	printf("\ntype \"?\" or \"help\" for help.\n");
    321 	for (;;) {
    322 		char            input[80];
    323 
    324 		input[0] = '\0';
    325 		printf("> ");
    326 		gets(input);
    327 
    328 		docommand(input);
    329 	}
    330 }
    331 
    332 static void
    333 print_banner(void)
    334 {
    335 	int extmem = getextmem();
    336 	char *s = "";
    337 
    338 #ifdef XMS
    339 	if (extmem == 0) {
    340 		if ((extmem = checkxms()) != 0)
    341 			s = "(xms) ";
    342 	}
    343 #endif
    344 
    345 	printf("\n");
    346 	printf(">> %s, Revision %s\n", bootprog_name, bootprog_rev);
    347 	printf(">> (%s, %s)\n", bootprog_maker, bootprog_date);
    348 	printf(">> Memory: %d/%d %sk\n", getbasemem(), extmem, s);
    349 }
    350 
    351 void
    352 usage()
    353 {
    354 	printf("dosboot [-u] [-c <commands>] [-i] [filename [-bootopts]]\n");
    355 }
    356 
    357 int
    358 main(argc, argv)
    359 	int             argc;
    360 	char          **argv;
    361 {
    362 	int             ch;
    363 	int             interactive = 0;
    364 	int             howto;
    365 	extern char    *optarg;
    366 	extern int      optind;
    367 
    368 	consdev = initio(CONSDEV_PC);
    369 	gateA20();
    370 
    371 	print_banner();
    372 
    373 	current_fsmode = "dos";
    374 	default_devname = "hd";
    375 	default_unit = 0;
    376 	default_partition = 0;
    377 	default_filename = "netbsd";
    378 
    379 	while ((ch = getopt(argc, argv, "c:iu")) != -1) {
    380 		switch (ch) {
    381 		case 'c':
    382 			docommand(optarg);
    383 			return (1);
    384 			break;
    385 		case 'i':
    386 			interactive = 1;
    387 			break;
    388 		case 'u':
    389 			current_fsmode = "ufs";
    390 			break;
    391 		default:
    392 			usage();
    393 			return (1);
    394 		}
    395 	}
    396 
    397 	if (interactive)
    398 		bootmenu();
    399 
    400 	argc -= optind;
    401 	argv += optind;
    402 
    403 	if (argc > 2) {
    404 		usage();
    405 		return (1);
    406 	}
    407 	howto = 0;
    408 	if (argc > 1 && !parseopts(argv[1], &howto))
    409 		return (1);
    410 
    411 	bootit((argc > 0 ? argv[0] : "netbsd"), howto, 1);
    412 	return (1);
    413 }
    414