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