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