1 /* $NetBSD: main.c,v 1.2 1997/03/22 09:06:20 thorpej 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 char *strerror __P((int)); /* XXX missing in stand.h */ 47 48 extern void ls __P((char *)); 49 extern int getopt __P((int, char **, const char *)); 50 51 int errno; 52 static char *consdev; 53 54 extern char version[]; 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 int 64 parsebootfile(fname, fsmode, devname, unit, partition, file) 65 const char *fname; 66 char **fsmode; 67 char **devname;/* out */ 68 unsigned int *unit, *partition; /* out */ 69 const char **file; /* out */ 70 { 71 const char *col, *help; 72 73 *fsmode = current_fsmode; 74 *devname = default_devname; 75 *unit = default_unit; 76 *partition = default_partition; 77 *file = default_filename; 78 79 if (!fname) 80 return (0); 81 82 if ((col = strchr(fname, ':'))) { /* device given */ 83 static char savedevname[MAXDEVNAME + 1]; 84 int devlen; 85 unsigned int u = 0, p = 0; 86 int i = 0; 87 88 devlen = col - fname; 89 if (devlen > MAXDEVNAME) 90 return (EINVAL); 91 92 #define isvalidname(c) ((c) >= 'a' && (c) <= 'z') 93 if (!isvalidname(fname[i])) 94 return (EINVAL); 95 do { 96 savedevname[i] = fname[i]; 97 i++; 98 } while (isvalidname(fname[i])); 99 savedevname[i] = '\0'; 100 101 #define isnum(c) ((c) >= '0' && (c) <= '9') 102 if (i < devlen) { 103 if (!isnum(fname[i])) 104 return (EUNIT); 105 do { 106 u *= 10; 107 u += fname[i++] - '0'; 108 } while (isnum(fname[i])); 109 } 110 #define isvalidpart(c) ((c) >= 'a' && (c) <= 'z') 111 if (i < devlen) { 112 if (!isvalidpart(fname[i])) 113 return (EPART); 114 p = fname[i++] - 'a'; 115 } 116 if (i != devlen) 117 return (ENXIO); 118 119 *devname = savedevname; 120 *unit = u; 121 *partition = p; 122 help = col + 1; 123 } else 124 help = fname; 125 126 if (*help) 127 *file = help; 128 129 return (0); 130 } 131 132 static void 133 print_bootsel(filename) 134 char *filename; 135 { 136 char *fsname; 137 char *devname; 138 int unit, partition; 139 const char *file; 140 141 if (!parsebootfile(filename, &fsname, &devname, &unit, 142 &partition, &file)) { 143 if (!strcmp(fsname, "dos")) 144 printf("booting %s\n", file); 145 else if (!strcmp(fsname, "ufs")) 146 printf("booting %s%d%c:%s\n", devname, unit, 147 'a' + partition, file); 148 } 149 } 150 151 static void 152 bootit(filename, howto, tell) 153 const char *filename; 154 int howto, tell; 155 { 156 if (tell) 157 print_bootsel(filename); 158 159 if (exec_netbsd(filename, 0, howto, 0, consdev) < 0) 160 printf("boot: %s\n", strerror(errno)); 161 else 162 printf("boot returned\n"); 163 } 164 165 static void 166 helpme() 167 { 168 printf("commands are:\n" 169 "boot [xdNx:][filename] [-adrs]\n" 170 " (ex. \"sd0a:netbsd.old -s\"\n" 171 "ls [path]\n" 172 "mode ufs|dos\n" 173 "help|?\n" 174 "quit\n"); 175 } 176 177 /* 178 * chops the head from the arguments and returns the arguments if any, 179 * or possibly an empty string. 180 */ 181 static char * 182 gettrailer(arg) 183 char *arg; 184 { 185 char *options; 186 187 if ((options = strchr(arg, ' ')) == NULL) 188 options = ""; 189 else 190 *options++ = '\0'; 191 /* trim leading blanks */ 192 while (*options && *options == ' ') 193 options++; 194 195 return (options); 196 } 197 198 static int 199 parseopts(opts, howto) 200 char *opts; 201 int *howto; 202 { 203 int tmpopt = 0; 204 205 opts++; /* skip - */ 206 while (*opts && *opts != ' ') { 207 tmpopt |= netbsd_opt(*opts); 208 if (tmpopt == -1) { 209 printf("-%c: unknown flag\n", *opts); 210 helpme(); 211 return (0); 212 } 213 opts++; 214 } 215 *howto = tmpopt; 216 return (1); 217 } 218 219 static int 220 parseboot(arg, filename, howto) 221 char *arg; 222 char **filename; 223 int *howto; 224 { 225 char *opts = NULL; 226 227 *filename = 0; 228 *howto = 0; 229 230 /* if there were no arguments */ 231 if (!*arg) 232 return (1); 233 234 /* format is... */ 235 /* [[xxNx:]filename] [-adrs] */ 236 237 /* check for just args */ 238 if (arg[0] == '-') { 239 opts = arg; 240 } else { /* at least a file name */ 241 *filename = arg; 242 243 opts = gettrailer(arg); 244 if (!*opts) 245 opts = NULL; 246 else if (*opts != '-') { 247 printf("invalid arguments\n"); 248 helpme(); 249 return (0); 250 } 251 } 252 /* at this point, we have dealt with filenames. */ 253 254 /* now, deal with options */ 255 if (opts) { 256 if (!parseopts(opts, howto)) 257 return (0); 258 } 259 return (1); 260 } 261 262 static void 263 parsemode(arg, mode) 264 char *arg; 265 char **mode; 266 { 267 if (!strcmp("dos", arg)) 268 *mode = "dos"; 269 else if (!strcmp("ufs", arg)) 270 *mode = "ufs"; 271 else 272 printf("invalid mode\n"); 273 } 274 275 static void 276 docommand(arg) 277 char *arg; 278 { 279 char *options; 280 281 options = gettrailer(arg); 282 283 if ((strcmp("help", arg) == 0) || 284 (strcmp("?", arg) == 0)) { 285 helpme(); 286 return; 287 } 288 if (strcmp("ls", arg) == 0) { 289 char *help = default_filename; 290 if (strcmp(current_fsmode, "ufs")) { 291 printf("UFS only\n"); 292 return; 293 } 294 default_filename = "/"; 295 ls(options); 296 default_filename = help; 297 return; 298 } 299 if (strcmp("quit", arg) == 0) { 300 printf("Exiting... goodbye...\n"); 301 exit(0); 302 } 303 if (strcmp("boot", arg) == 0) { 304 char *filename; 305 int howto; 306 if (parseboot(options, &filename, &howto)) 307 bootit(filename, howto, 1); 308 return; 309 } 310 if (strcmp("mode", arg) == 0) { 311 parsemode(options, ¤t_fsmode); 312 return; 313 } 314 printf("unknown command\n"); 315 helpme(); 316 } 317 318 void 319 bootmenu() 320 { 321 printf("\ntype \"?\" or \"help\" for help.\n"); 322 for (;;) { 323 char input[80]; 324 325 input[0] = '\0'; 326 printf("> "); 327 gets(input); 328 329 docommand(input); 330 } 331 } 332 333 static void 334 print_banner(void) 335 { 336 printf("\n" 337 ">> NetBSD BOOT: %d/%d k [%s]\n", 338 getbasemem(), 339 getextmem(), 340 version); 341 } 342 343 void 344 usage() 345 { 346 printf("dosboot [-u] [-c <commands>] [-i] [filename [-bootopts]]\n"); 347 } 348 349 int 350 main(argc, argv) 351 int argc; 352 char **argv; 353 { 354 int ch; 355 int interactive = 0; 356 int howto; 357 extern char *optarg; 358 extern int optind; 359 360 consdev = initio(CONSDEV_PC); 361 gateA20(); 362 363 print_banner(); 364 365 current_fsmode = "dos"; 366 default_devname = "hd"; 367 default_unit = 0; 368 default_partition = 0; 369 default_filename = "netbsd"; 370 371 while ((ch = getopt(argc, argv, "c:iu")) != -1) { 372 switch (ch) { 373 case 'c': 374 docommand(optarg); 375 return (1); 376 break; 377 case 'i': 378 interactive = 1; 379 break; 380 case 'u': 381 current_fsmode = "ufs"; 382 break; 383 default: 384 usage(); 385 return (1); 386 } 387 } 388 389 if (interactive) 390 bootmenu(); 391 392 argc -= optind; 393 argv += optind; 394 395 if (argc > 2) { 396 usage(); 397 return (1); 398 } 399 howto = 0; 400 if (argc > 1 && !parseopts(argv[1], &howto)) 401 return (1); 402 403 bootit((argc > 0 ? argv[0] : "netbsd"), howto, 1); 404 return (1); 405 } 406