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