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