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