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