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