main.c revision 1.2 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