Home | History | Annotate | Line # | Download | only in dosboot
      1 /*	$NetBSD: main.c,v 1.34 2024/09/11 20:15:36 andvar 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 
    195 	clear_pc_screen();
    196 
    197 	printf("\n"
    198 	       ">> %s, Revision %s (from NetBSD %s)\n"
    199 	       ">> Memory: %d/%d k\n",
    200 	       bootprog_name, bootprog_rev, bootprog_kernrev,
    201 	       getbasemem(), extmem);
    202 }
    203 
    204 void
    205 usage(void)
    206 {
    207 	printf("dosboot [-u] [-c <commands>] [-i] [filename [-bootopts]]\n");
    208 }
    209 
    210 int
    211 main(int argc, char **argv)
    212 {
    213 	int             ch;
    214 	int             interactive = 0;
    215 	int             howto;
    216 	extern char    *optarg;
    217 	extern int      optind;
    218 
    219 #ifdef	SUPPORT_SERIAL
    220 	initio(SUPPORT_SERIAL);
    221 #else
    222 	initio(CONSDEV_PC);
    223 #endif
    224 	gateA20();
    225 
    226 	print_banner();
    227 
    228 	current_fsmode = "dos";
    229 	default_devname = "hd";
    230 	default_unit = 0;
    231 	default_partition = 0;
    232 	default_filename = "netbsd";
    233 
    234 	while ((ch = getopt(argc, argv, "c:iu")) != -1) {
    235 		switch (ch) {
    236 		case 'c':
    237 			docommand(optarg);
    238 			return (1);
    239 			break;
    240 		case 'i':
    241 			interactive = 1;
    242 			break;
    243 		case 'u':
    244 			current_fsmode = "ufs";
    245 			break;
    246 		default:
    247 			usage();
    248 			return (1);
    249 		}
    250 	}
    251 
    252 	if (interactive) {
    253 		printf("type \"?\" or \"help\" for help.\n");
    254 		bootmenu();
    255 	}
    256 
    257 	argc -= optind;
    258 	argv += optind;
    259 
    260 	if (argc > 2) {
    261 		usage();
    262 		return (1);
    263 	}
    264 	howto = 0;
    265 	if (argc > 1 && !parseopts(argv[1], &howto))
    266 		return (1);
    267 
    268 	bootit((argc > 0 ? argv[0] : "netbsd"), howto, 1);
    269 	return (1);
    270 }
    271 
    272 /* ARGSUSED */
    273 void
    274 command_help(char *arg)
    275 {
    276 	printf("commands are:\n"
    277 	       "boot [xdNx:][filename] [-acdqsv]\n"
    278 	       "     (ex. \"sd0a:netbsd.old -s\"\n"
    279 	       "ls [path]\n"
    280 	       "mode ufs|dos\n"
    281 	       "dev xd[N[x]]:\n"
    282 	       "help|?\n"
    283 	       "quit\n");
    284 }
    285 
    286 void
    287 command_ls(char *arg)
    288 {
    289 	char *help = default_filename;
    290 	default_filename = "/";
    291 	ls(arg);
    292 	default_filename = help;
    293 }
    294 
    295 /* ARGSUSED */
    296 void
    297 command_quit(char *arg)
    298 {
    299 	printf("Exiting... goodbye...\n");
    300 	_rtt();
    301 }
    302 
    303 void
    304 command_boot(char *arg)
    305 {
    306 	char *filename;
    307 	int howto;
    308 
    309 	if (parseboot(arg, &filename, &howto))
    310 		bootit(filename, howto, 1);
    311 }
    312 
    313 void
    314 command_mode(char *arg)
    315 {
    316 	if (!strcmp("dos", arg))
    317 		current_fsmode = "dos";
    318 	else if (!strcmp("ufs", arg))
    319 		current_fsmode = "ufs";
    320 	else
    321 		printf("invalid mode\n");
    322 }
    323 
    324 void
    325 command_dev(char *arg)
    326 {
    327 	static char savedevname[MAXDEVNAME + 1];
    328 	char *fsname, *devname;
    329 	const char *file; /* dummy */
    330 
    331 	if (!strcmp(current_fsmode, "dos")) {
    332 		printf("not available in DOS mode\n");
    333 		return;
    334 	}
    335 
    336 	if (*arg == '\0') {
    337 		printf("%s%d%c:\n", default_devname, default_unit,
    338 		       'a' + default_partition);
    339 		return;
    340 	}
    341 
    342 	if (!strchr(arg, ':') ||
    343 	    parsebootfile(arg, &fsname, &devname, &default_unit,
    344 			  &default_partition, &file)) {
    345 		command_help(NULL);
    346 		return;
    347 	}
    348 
    349 	/* put to own static storage */
    350 	strncpy(savedevname, devname, MAXDEVNAME + 1);
    351 	default_devname = savedevname;
    352 }
    353