1 | /* boot.c - Load and start Minix. Author: Kees J. Bot
|
---|
2 | * 27 Dec 1991
|
---|
3 | */
|
---|
4 |
|
---|
5 | char version[]= "2.20";
|
---|
6 |
|
---|
7 | #define BIOS (!UNIX) /* Either uses BIOS or UNIX syscalls. */
|
---|
8 |
|
---|
9 | #define nil 0
|
---|
10 | #define _POSIX_SOURCE 1
|
---|
11 | #define _MINIX 1
|
---|
12 | #include <stddef.h>
|
---|
13 | #include <sys/types.h>
|
---|
14 | #include <sys/stat.h>
|
---|
15 | #include <stdlib.h>
|
---|
16 | #include <stdio.h>
|
---|
17 | #include <limits.h>
|
---|
18 | #include <string.h>
|
---|
19 | #include <errno.h>
|
---|
20 | #include <ibm/partition.h>
|
---|
21 | #include <minix/config.h>
|
---|
22 | #include <minix/type.h>
|
---|
23 | #include <minix/com.h>
|
---|
24 | #include <minix/dmap.h>
|
---|
25 | #include <minix/const.h>
|
---|
26 | #include <minix/minlib.h>
|
---|
27 | #include <minix/syslib.h>
|
---|
28 | #if BIOS
|
---|
29 | #include <kernel/const.h>
|
---|
30 | #include <kernel/type.h>
|
---|
31 | #endif
|
---|
32 | #if UNIX
|
---|
33 | #include <stdio.h>
|
---|
34 | #include <time.h>
|
---|
35 | #include <unistd.h>
|
---|
36 | #include <fcntl.h>
|
---|
37 | #include <signal.h>
|
---|
38 | #include <termios.h>
|
---|
39 | #endif
|
---|
40 | #include "rawfs.h"
|
---|
41 | #undef EXTERN
|
---|
42 | #define EXTERN /* Empty */
|
---|
43 | #include "boot.h"
|
---|
44 |
|
---|
45 | #define arraysize(a) (sizeof(a) / sizeof((a)[0]))
|
---|
46 | #define arraylimit(a) ((a) + arraysize(a))
|
---|
47 | #define between(a, c, z) ((unsigned) ((c) - (a)) <= ((z) - (a)))
|
---|
48 |
|
---|
49 | int fsok= -1; /* File system state. Initially unknown. */
|
---|
50 |
|
---|
51 | static int block_size;
|
---|
52 |
|
---|
53 | #if BIOS
|
---|
54 |
|
---|
55 | /* this data is reserved for BIOS int 0x13 to put the 'specification packet'
|
---|
56 | * in. It has a structure of course, but we don't define a struct because
|
---|
57 | * of compiler padding. We fiddle out the bytes ourselves later.
|
---|
58 | */
|
---|
59 | unsigned char boot_spec[24];
|
---|
60 |
|
---|
61 | char *bios_err(int err)
|
---|
62 | /* Translate BIOS error code to a readable string. (This is a rare trait
|
---|
63 | * known as error checking and reporting. Take a good look at it, you won't
|
---|
64 | * see it often.)
|
---|
65 | */
|
---|
66 | {
|
---|
67 | static struct errlist {
|
---|
68 | int err;
|
---|
69 | char *what;
|
---|
70 | } errlist[] = {
|
---|
71 | #if !DOS
|
---|
72 | { 0x00, "No error" },
|
---|
73 | { 0x01, "Invalid command" },
|
---|
74 | { 0x02, "Address mark not found" },
|
---|
75 | { 0x03, "Disk write-protected" },
|
---|
76 | { 0x04, "Sector not found" },
|
---|
77 | { 0x05, "Reset failed" },
|
---|
78 | { 0x06, "Floppy disk removed" },
|
---|
79 | { 0x07, "Bad parameter table" },
|
---|
80 | { 0x08, "DMA overrun" },
|
---|
81 | { 0x09, "DMA crossed 64 KB boundary" },
|
---|
82 | { 0x0A, "Bad sector flag" },
|
---|
83 | { 0x0B, "Bad track flag" },
|
---|
84 | { 0x0C, "Media type not found" },
|
---|
85 | { 0x0D, "Invalid number of sectors on format" },
|
---|
86 | { 0x0E, "Control data address mark detected" },
|
---|
87 | { 0x0F, "DMA arbitration level out of range" },
|
---|
88 | { 0x10, "Uncorrectable CRC or ECC data error" },
|
---|
89 | { 0x11, "ECC corrected data error" },
|
---|
90 | { 0x20, "Controller failed" },
|
---|
91 | { 0x40, "Seek failed" },
|
---|
92 | { 0x80, "Disk timed-out" },
|
---|
93 | { 0xAA, "Drive not ready" },
|
---|
94 | { 0xBB, "Undefined error" },
|
---|
95 | { 0xCC, "Write fault" },
|
---|
96 | { 0xE0, "Status register error" },
|
---|
97 | { 0xFF, "Sense operation failed" }
|
---|
98 | #else /* DOS */
|
---|
99 | { 0x00, "No error" },
|
---|
100 | { 0x01, "Function number invalid" },
|
---|
101 | { 0x02, "File not found" },
|
---|
102 | { 0x03, "Path not found" },
|
---|
103 | { 0x04, "Too many open files" },
|
---|
104 | { 0x05, "Access denied" },
|
---|
105 | { 0x06, "Invalid handle" },
|
---|
106 | { 0x0C, "Access code invalid" },
|
---|
107 | #endif /* DOS */
|
---|
108 | };
|
---|
109 | struct errlist *errp;
|
---|
110 |
|
---|
111 | for (errp= errlist; errp < arraylimit(errlist); errp++) {
|
---|
112 | if (errp->err == err) return errp->what;
|
---|
113 | }
|
---|
114 | return "Unknown error";
|
---|
115 | }
|
---|
116 |
|
---|
117 | char *unix_err(int err)
|
---|
118 | /* Translate the few errors rawfs can give. */
|
---|
119 | {
|
---|
120 | switch (err) {
|
---|
121 | case ENOENT: return "No such file or directory";
|
---|
122 | case ENOTDIR: return "Not a directory";
|
---|
123 | default: return "Unknown error";
|
---|
124 | }
|
---|
125 | }
|
---|
126 |
|
---|
127 | void rwerr(char *rw, off_t sec, int err)
|
---|
128 | {
|
---|
129 | printf("\n%s error 0x%02x (%s) at sector %ld absolute\n",
|
---|
130 | rw, err, bios_err(err), sec);
|
---|
131 | }
|
---|
132 |
|
---|
133 | void readerr(off_t sec, int err) { rwerr("Read", sec, err); }
|
---|
134 | void writerr(off_t sec, int err) { rwerr("Write", sec, err); }
|
---|
135 |
|
---|
136 | void readblock(off_t blk, char *buf, int block_size)
|
---|
137 | /* Read blocks for the rawfs package. */
|
---|
138 | {
|
---|
139 | int r;
|
---|
140 | u32_t sec= lowsec + blk * RATIO(block_size);
|
---|
141 |
|
---|
142 | if(!block_size) {
|
---|
143 | printf("block_size 0\n");
|
---|
144 | exit(1);
|
---|
145 | }
|
---|
146 |
|
---|
147 | if ((r= readsectors(mon2abs(buf), sec, 1 * RATIO(block_size))) != 0) {
|
---|
148 | readerr(sec, r); exit(1);
|
---|
149 | }
|
---|
150 | }
|
---|
151 |
|
---|
152 | #define istty (1)
|
---|
153 | #define alarm(n) (0)
|
---|
154 |
|
---|
155 | #endif /* BIOS */
|
---|
156 |
|
---|
157 | #if UNIX
|
---|
158 |
|
---|
159 | /* The Minix boot block must start with these bytes: */
|
---|
160 | char boot_magic[] = { 0x31, 0xC0, 0x8E, 0xD8, 0xFA, 0x8E, 0xD0, 0xBC };
|
---|
161 |
|
---|
162 | struct biosdev {
|
---|
163 | char *name; /* Name of device. */
|
---|
164 | int device; /* Device to edit parameters. */
|
---|
165 | } bootdev;
|
---|
166 |
|
---|
167 | struct termios termbuf;
|
---|
168 | int istty;
|
---|
169 |
|
---|
170 | void quit(int status)
|
---|
171 | {
|
---|
172 | if (istty) (void) tcsetattr(0, TCSANOW, &termbuf);
|
---|
173 | exit(status);
|
---|
174 | }
|
---|
175 |
|
---|
176 | #define exit(s) quit(s)
|
---|
177 |
|
---|
178 | void report(char *label)
|
---|
179 | /* edparams: label: No such file or directory */
|
---|
180 | {
|
---|
181 | fprintf(stderr, "edparams: %s: %s\n", label, strerror(errno));
|
---|
182 | }
|
---|
183 |
|
---|
184 | void fatal(char *label)
|
---|
185 | {
|
---|
186 | report(label);
|
---|
187 | exit(1);
|
---|
188 | }
|
---|
189 |
|
---|
190 | void *alloc(void *m, size_t n)
|
---|
191 | {
|
---|
192 | m= m == nil ? malloc(n) : realloc(m, n);
|
---|
193 | if (m == nil) fatal("");
|
---|
194 | return m;
|
---|
195 | }
|
---|
196 |
|
---|
197 | #define malloc(n) alloc(nil, n)
|
---|
198 | #define realloc(m, n) alloc(m, n)
|
---|
199 |
|
---|
200 | #define mon2abs(addr) ((void *) (addr))
|
---|
201 |
|
---|
202 | int rwsectors(int rw, void *addr, u32_t sec, int nsec)
|
---|
203 | {
|
---|
204 | ssize_t r;
|
---|
205 | size_t len= nsec * SECTOR_SIZE;
|
---|
206 |
|
---|
207 | if (lseek(bootdev.device, sec * SECTOR_SIZE, SEEK_SET) == -1)
|
---|
208 | return errno;
|
---|
209 |
|
---|
210 | if (rw == 0) {
|
---|
211 | r= read(bootdev.device, (char *) addr, len);
|
---|
212 | } else {
|
---|
213 | r= write(bootdev.device, (char *) addr, len);
|
---|
214 | }
|
---|
215 | if (r == -1) return errno;
|
---|
216 | if (r != len) return EIO;
|
---|
217 | return 0;
|
---|
218 | }
|
---|
219 |
|
---|
220 | #define readsectors(a, s, n) rwsectors(0, (a), (s), (n))
|
---|
221 | #define writesectors(a, s, n) rwsectors(1, (a), (s), (n))
|
---|
222 | #define readerr(sec, err) (errno= (err), report(bootdev.name))
|
---|
223 | #define writerr(sec, err) (errno= (err), report(bootdev.name))
|
---|
224 | #define putch(c) putchar(c)
|
---|
225 | #define unix_err(err) strerror(err)
|
---|
226 |
|
---|
227 | void readblock(off_t blk, char *buf, int block_size)
|
---|
228 | /* Read blocks for the rawfs package. */
|
---|
229 | {
|
---|
230 | if(!block_size) fatal("block_size 0");
|
---|
231 | errno= EIO;
|
---|
232 | if (lseek(bootdev.device, blk * block_size, SEEK_SET) == -1
|
---|
233 | || read(bootdev.device, buf, block_size) != block_size)
|
---|
234 | {
|
---|
235 | fatal(bootdev.name);
|
---|
236 | }
|
---|
237 | }
|
---|
238 |
|
---|
239 | sig_atomic_t trapsig;
|
---|
240 |
|
---|
241 | void trap(int sig)
|
---|
242 | {
|
---|
243 | trapsig= sig;
|
---|
244 | signal(sig, trap);
|
---|
245 | }
|
---|
246 |
|
---|
247 | int escape(void)
|
---|
248 | {
|
---|
249 | if (trapsig == SIGINT) {
|
---|
250 | trapsig= 0;
|
---|
251 | return 1;
|
---|
252 | }
|
---|
253 | return 0;
|
---|
254 | }
|
---|
255 |
|
---|
256 | static unsigned char unchar;
|
---|
257 |
|
---|
258 | int getch(void)
|
---|
259 | {
|
---|
260 | unsigned char c;
|
---|
261 |
|
---|
262 | fflush(stdout);
|
---|
263 |
|
---|
264 | if (unchar != 0) {
|
---|
265 | c= unchar;
|
---|
266 | unchar= 0;
|
---|
267 | return c;
|
---|
268 | }
|
---|
269 |
|
---|
270 | switch (read(0, &c, 1)) {
|
---|
271 | case -1:
|
---|
272 | if (errno != EINTR) fatal("");
|
---|
273 | return(ESC);
|
---|
274 | case 0:
|
---|
275 | if (istty) putch('\n');
|
---|
276 | exit(0);
|
---|
277 | default:
|
---|
278 | if (istty && c == termbuf.c_cc[VEOF]) {
|
---|
279 | putch('\n');
|
---|
280 | exit(0);
|
---|
281 | }
|
---|
282 | return c;
|
---|
283 | }
|
---|
284 | }
|
---|
285 |
|
---|
286 | #define ungetch(c) ((void) (unchar = (c)))
|
---|
287 |
|
---|
288 | #define get_tick() ((u32_t) time(nil))
|
---|
289 | #define clear_screen() printf("[clear]")
|
---|
290 | #define boot_device(device) printf("[boot %s]\n", device)
|
---|
291 | #define ctty(line) printf("[ctty %s]\n", line)
|
---|
292 | #define bootminix() (run_trailer() && printf("[boot]\n"))
|
---|
293 | #define off() printf("[off]")
|
---|
294 |
|
---|
295 | #endif /* UNIX */
|
---|
296 |
|
---|
297 | char *readline(void)
|
---|
298 | /* Read a line including a newline with echoing. */
|
---|
299 | {
|
---|
300 | char *line;
|
---|
301 | size_t i, z;
|
---|
302 | int c;
|
---|
303 |
|
---|
304 | i= 0;
|
---|
305 | z= 20;
|
---|
306 | line= malloc(z * sizeof(char));
|
---|
307 |
|
---|
308 | do {
|
---|
309 | c= getch();
|
---|
310 |
|
---|
311 | if (strchr("\b\177\25\30", c) != nil) {
|
---|
312 | /* Backspace, DEL, ctrl-U, or ctrl-X. */
|
---|
313 | do {
|
---|
314 | if (i == 0) break;
|
---|
315 | printf("\b \b");
|
---|
316 | i--;
|
---|
317 | } while (c == '\25' || c == '\30');
|
---|
318 | } else
|
---|
319 | if (c < ' ' && c != '\n') {
|
---|
320 | putch('\7');
|
---|
321 | } else {
|
---|
322 | putch(c);
|
---|
323 | line[i++]= c;
|
---|
324 | if (i == z) {
|
---|
325 | z*= 2;
|
---|
326 | line= realloc(line, z * sizeof(char));
|
---|
327 | }
|
---|
328 | }
|
---|
329 | } while (c != '\n');
|
---|
330 | line[i]= 0;
|
---|
331 | return line;
|
---|
332 | }
|
---|
333 |
|
---|
334 | int sugar(char *tok)
|
---|
335 | /* Recognize special tokens. */
|
---|
336 | {
|
---|
337 | return strchr("=(){};\n", tok[0]) != nil;
|
---|
338 | }
|
---|
339 |
|
---|
340 | char *onetoken(char **aline)
|
---|
341 | /* Returns a string with one token for tokenize. */
|
---|
342 | {
|
---|
343 | char *line= *aline;
|
---|
344 | size_t n;
|
---|
345 | char *tok;
|
---|
346 |
|
---|
347 | /* Skip spaces and runs of newlines. */
|
---|
348 | while (*line == ' ' || (*line == '\n' && line[1] == '\n')) line++;
|
---|
349 |
|
---|
350 | *aline= line;
|
---|
351 |
|
---|
352 | /* Don't do odd junk (nor the terminating 0!). */
|
---|
353 | if ((unsigned) *line < ' ' && *line != '\n') return nil;
|
---|
354 |
|
---|
355 | if (*line == '(') {
|
---|
356 | /* Function argument, anything goes but () must match. */
|
---|
357 | int depth= 0;
|
---|
358 |
|
---|
359 | while ((unsigned) *line >= ' ') {
|
---|
360 | if (*line == '(') depth++;
|
---|
361 | if (*line++ == ')' && --depth == 0) break;
|
---|
362 | }
|
---|
363 | } else
|
---|
364 | if (sugar(line)) {
|
---|
365 | /* Single character token. */
|
---|
366 | line++;
|
---|
367 | } else {
|
---|
368 | /* Multicharacter token. */
|
---|
369 | do line++; while ((unsigned) *line > ' ' && !sugar(line));
|
---|
370 | }
|
---|
371 | n= line - *aline;
|
---|
372 | tok= malloc((n + 1) * sizeof(char));
|
---|
373 | memcpy(tok, *aline, n);
|
---|
374 | tok[n]= 0;
|
---|
375 | if (tok[0] == '\n') tok[0]= ';'; /* ';' same as '\n' */
|
---|
376 |
|
---|
377 | *aline= line;
|
---|
378 | return tok;
|
---|
379 | }
|
---|
380 |
|
---|
381 | /* Typed commands form strings of tokens. */
|
---|
382 |
|
---|
383 | typedef struct token {
|
---|
384 | struct token *next; /* Next in a command chain. */
|
---|
385 | char *token;
|
---|
386 | } token;
|
---|
387 |
|
---|
388 | token **tokenize(token **acmds, char *line)
|
---|
389 | /* Takes a line apart to form tokens. The tokens are inserted into a command
|
---|
390 | * chain at *acmds. Tokenize returns a reference to where another line could
|
---|
391 | * be added. Tokenize looks at spaces as token separators, and recognizes only
|
---|
392 | * ';', '=', '{', '}', and '\n' as single character tokens. One token is
|
---|
393 | * formed from '(' and ')' with anything in between as long as more () match.
|
---|
394 | */
|
---|
395 | {
|
---|
396 | char *tok;
|
---|
397 | token *newcmd;
|
---|
398 |
|
---|
399 | while ((tok= onetoken(&line)) != nil) {
|
---|
400 | newcmd= malloc(sizeof(*newcmd));
|
---|
401 | newcmd->token= tok;
|
---|
402 | newcmd->next= *acmds;
|
---|
403 | *acmds= newcmd;
|
---|
404 | acmds= &newcmd->next;
|
---|
405 | }
|
---|
406 | return acmds;
|
---|
407 | }
|
---|
408 |
|
---|
409 | token *cmds; /* String of commands to execute. */
|
---|
410 | int err; /* Set on an error. */
|
---|
411 |
|
---|
412 | char *poptoken(void)
|
---|
413 | /* Pop one token off the command chain. */
|
---|
414 | {
|
---|
415 | token *cmd= cmds;
|
---|
416 | char *tok= cmd->token;
|
---|
417 |
|
---|
418 | cmds= cmd->next;
|
---|
419 | free(cmd);
|
---|
420 |
|
---|
421 | return tok;
|
---|
422 | }
|
---|
423 |
|
---|
424 | void voidtoken(void)
|
---|
425 | /* Remove one token from the command chain. */
|
---|
426 | {
|
---|
427 | free(poptoken());
|
---|
428 | }
|
---|
429 |
|
---|
430 | void parse_code(char *code)
|
---|
431 | /* Tokenize a string of monitor code, making sure there is a delimiter. It is
|
---|
432 | * to be executed next. (Prepended to the current input.)
|
---|
433 | */
|
---|
434 | {
|
---|
435 | if (cmds != nil && cmds->token[0] != ';') (void) tokenize(&cmds, ";");
|
---|
436 | (void) tokenize(&cmds, code);
|
---|
437 | }
|
---|
438 |
|
---|
439 | int interrupt(void)
|
---|
440 | /* Clean up after an ESC has been typed. */
|
---|
441 | {
|
---|
442 | if (escape()) {
|
---|
443 | printf("[ESC]\n");
|
---|
444 | err= 1;
|
---|
445 | return 1;
|
---|
446 | }
|
---|
447 | return 0;
|
---|
448 | }
|
---|
449 |
|
---|
450 | #if BIOS
|
---|
451 |
|
---|
452 | int activate;
|
---|
453 |
|
---|
454 | struct biosdev {
|
---|
455 | char name[8];
|
---|
456 | int device, primary, secondary;
|
---|
457 | } bootdev, tmpdev;
|
---|
458 |
|
---|
459 | int get_master(char *master, struct part_entry **table, u32_t pos)
|
---|
460 | /* Read a master boot sector and its partition table. */
|
---|
461 | {
|
---|
462 | int r, n;
|
---|
463 | struct part_entry *pe, **pt;
|
---|
464 |
|
---|
465 | if ((r= readsectors(mon2abs(master), pos, 1)) != 0) return r;
|
---|
466 |
|
---|
467 | pe= (struct part_entry *) (master + PART_TABLE_OFF);
|
---|
468 | for (pt= table; pt < table + NR_PARTITIONS; pt++) *pt= pe++;
|
---|
469 |
|
---|
470 | /* DOS has the misguided idea that partition tables must be sorted. */
|
---|
471 | if (pos != 0) return 0; /* But only the primary. */
|
---|
472 |
|
---|
473 | n= NR_PARTITIONS;
|
---|
474 | do {
|
---|
475 | for (pt= table; pt < table + NR_PARTITIONS-1; pt++) {
|
---|
476 | if (pt[0]->sysind == NO_PART
|
---|
477 | || pt[0]->lowsec > pt[1]->lowsec) {
|
---|
478 | pe= pt[0]; pt[0]= pt[1]; pt[1]= pe;
|
---|
479 | }
|
---|
480 | }
|
---|
481 | } while (--n > 0);
|
---|
482 | return 0;
|
---|
483 | }
|
---|
484 |
|
---|
485 | void initialize(void)
|
---|
486 | {
|
---|
487 | char master[SECTOR_SIZE];
|
---|
488 | struct part_entry *table[NR_PARTITIONS];
|
---|
489 | int r, p;
|
---|
490 | u32_t masterpos;
|
---|
491 | char *argp;
|
---|
492 |
|
---|
493 | /* Copy the boot program to the far end of low memory, this must be
|
---|
494 | * done to get out of the way of Minix, and to put the data area
|
---|
495 | * cleanly inside a 64K chunk if using BIOS I/O (no DMA problems).
|
---|
496 | */
|
---|
497 | u32_t oldaddr= caddr;
|
---|
498 | u32_t memend= mem[0].base + mem[0].size;
|
---|
499 | u32_t newaddr= (memend - runsize) & ~0x0000FL;
|
---|
500 | #if !DOS
|
---|
501 | u32_t dma64k= (memend - 1) & ~0x0FFFFL;
|
---|
502 |
|
---|
503 |
|
---|
504 | /* Check if data segment crosses a 64K boundary. */
|
---|
505 | if (newaddr + (daddr - caddr) < dma64k) {
|
---|
506 | newaddr= (dma64k - runsize) & ~0x0000FL;
|
---|
507 | }
|
---|
508 | #endif
|
---|
509 |
|
---|
510 | /* Set the new caddr for relocate. */
|
---|
511 | caddr= newaddr;
|
---|
512 |
|
---|
513 | /* Copy code and data. */
|
---|
514 | raw_copy(newaddr, oldaddr, runsize);
|
---|
515 |
|
---|
516 | /* Make the copy running. */
|
---|
517 | relocate();
|
---|
518 |
|
---|
519 | #if !DOS
|
---|
520 |
|
---|
521 | /* Take the monitor out of the memory map if we have memory to spare,
|
---|
522 | * and also keep the BIOS data area safe (1.5K), plus a bit extra for
|
---|
523 | * where we may have to put a.out headers for older kernels.
|
---|
524 | */
|
---|
525 | if (mon_return = (mem[1].size > 512*1024L)) mem[0].size = newaddr;
|
---|
526 | mem[0].base += 2048;
|
---|
527 | mem[0].size -= 2048;
|
---|
528 |
|
---|
529 | /* Find out what the boot device and partition was. */
|
---|
530 | bootdev.name[0]= 0;
|
---|
531 | bootdev.device= device;
|
---|
532 | bootdev.primary= -1;
|
---|
533 | bootdev.secondary= -1;
|
---|
534 |
|
---|
535 | if (device < 0x80) {
|
---|
536 | /* Floppy. */
|
---|
537 | strcpy(bootdev.name, "fd0");
|
---|
538 | bootdev.name[2] += bootdev.device;
|
---|
539 | return;
|
---|
540 | }
|
---|
541 |
|
---|
542 | /* Disk: Get the partition table from the very first sector, and
|
---|
543 | * determine the partition we booted from using the information from
|
---|
544 | * the booted partition entry as passed on by the bootstrap (rem_part).
|
---|
545 | * All we need from it is the partition offset.
|
---|
546 | */
|
---|
547 | raw_copy(mon2abs(&lowsec),
|
---|
548 | vec2abs(&rem_part) + offsetof(struct part_entry, lowsec),
|
---|
549 | sizeof(lowsec));
|
---|
550 |
|
---|
551 | masterpos= 0; /* Master bootsector position. */
|
---|
552 |
|
---|
553 | for (;;) {
|
---|
554 | /* Extract the partition table from the master boot sector. */
|
---|
555 | if ((r= get_master(master, table, masterpos)) != 0) {
|
---|
556 | readerr(masterpos, r); exit(1);
|
---|
557 | }
|
---|
558 |
|
---|
559 | /* See if you can find "lowsec" back. */
|
---|
560 | for (p= 0; p < NR_PARTITIONS; p++) {
|
---|
561 | if (lowsec - table[p]->lowsec < table[p]->size) break;
|
---|
562 | }
|
---|
563 |
|
---|
564 | if (lowsec == table[p]->lowsec) { /* Found! */
|
---|
565 | if (bootdev.primary < 0)
|
---|
566 | bootdev.primary= p;
|
---|
567 | else
|
---|
568 | bootdev.secondary= p;
|
---|
569 | break;
|
---|
570 | }
|
---|
571 |
|
---|
572 | if (p == NR_PARTITIONS || bootdev.primary >= 0
|
---|
573 | || table[p]->sysind != MINIX_PART) {
|
---|
574 | /* The boot partition cannot be named, this only means
|
---|
575 | * that "bootdev" doesn't work.
|
---|
576 | */
|
---|
577 | bootdev.device= -1;
|
---|
578 | return;
|
---|
579 | }
|
---|
580 |
|
---|
581 | /* See if the primary partition is subpartitioned. */
|
---|
582 | bootdev.primary= p;
|
---|
583 | masterpos= table[p]->lowsec;
|
---|
584 | }
|
---|
585 | strcpy(bootdev.name, "d0p0");
|
---|
586 | bootdev.name[1] += (device - 0x80);
|
---|
587 | bootdev.name[3] += bootdev.primary;
|
---|
588 | if (bootdev.secondary >= 0) {
|
---|
589 | strcat(bootdev.name, "s0");
|
---|
590 | bootdev.name[5] += bootdev.secondary;
|
---|
591 | }
|
---|
592 |
|
---|
593 | #else /* DOS */
|
---|
594 | /* Take the monitor out of the memory map if we have memory to spare,
|
---|
595 | * note that only half our PSP is needed at the new place, the first
|
---|
596 | * half is to be kept in its place.
|
---|
597 | */
|
---|
598 | if (mem[1].size > 0) mem[0].size = newaddr + 0x80 - mem[0].base;
|
---|
599 |
|
---|
600 | /* Parse the command line. */
|
---|
601 | argp= PSP + 0x81;
|
---|
602 | argp[PSP[0x80]]= 0;
|
---|
603 | while (between('\1', *argp, ' ')) argp++;
|
---|
604 | vdisk= argp;
|
---|
605 | while (!between('\0', *argp, ' ')) argp++;
|
---|
606 | while (between('\1', *argp, ' ')) *argp++= 0;
|
---|
607 | if (*vdisk == 0) {
|
---|
608 | printf("\nUsage: boot <vdisk> [commands ...]\n");
|
---|
609 | exit(1);
|
---|
610 | }
|
---|
611 | drun= *argp == 0 ? "main" : argp;
|
---|
612 |
|
---|
613 | if ((r= dev_open()) != 0) {
|
---|
614 | printf("\n%s: Error %02x (%s)\n", vdisk, r, bios_err(r));
|
---|
615 | exit(1);
|
---|
616 | }
|
---|
617 |
|
---|
618 | /* Find the active partition on the virtual disk. */
|
---|
619 | if ((r= get_master(master, table, 0)) != 0) {
|
---|
620 | readerr(0, r); exit(1);
|
---|
621 | }
|
---|
622 |
|
---|
623 | strcpy(bootdev.name, "d0");
|
---|
624 | bootdev.primary= -1;
|
---|
625 | for (p= 0; p < NR_PARTITIONS; p++) {
|
---|
626 | if (table[p]->bootind != 0 && table[p]->sysind == MINIX_PART) {
|
---|
627 | bootdev.primary= p;
|
---|
628 | strcat(bootdev.name, "p0");
|
---|
629 | bootdev.name[3] += p;
|
---|
630 | lowsec= table[p]->lowsec;
|
---|
631 | break;
|
---|
632 | }
|
---|
633 | }
|
---|
634 | #endif /* DOS */
|
---|
635 | }
|
---|
636 |
|
---|
637 | #endif /* BIOS */
|
---|
638 |
|
---|
639 | /* Reserved names: */
|
---|
640 | enum resnames {
|
---|
641 | R_NULL, R_BOOT, R_CTTY, R_DELAY, R_ECHO, R_EXIT, R_HELP,
|
---|
642 | R_LS, R_MENU, R_OFF, R_SAVE, R_SET, R_TRAP, R_UNSET
|
---|
643 | };
|
---|
644 |
|
---|
645 | char resnames[][6] = {
|
---|
646 | "", "boot", "ctty", "delay", "echo", "exit", "help",
|
---|
647 | "ls", "menu", "off", "save", "set", "trap", "unset",
|
---|
648 | };
|
---|
649 |
|
---|
650 | /* Using this for all null strings saves a lot of memory. */
|
---|
651 | #define null (resnames[0])
|
---|
652 |
|
---|
653 | int reserved(char *s)
|
---|
654 | /* Recognize reserved strings. */
|
---|
655 | {
|
---|
656 | int r;
|
---|
657 |
|
---|
658 | for (r= R_BOOT; r <= R_UNSET; r++) {
|
---|
659 | if (strcmp(s, resnames[r]) == 0) return r;
|
---|
660 | }
|
---|
661 | return R_NULL;
|
---|
662 | }
|
---|
663 |
|
---|
664 | void sfree(char *s)
|
---|
665 | /* Free a non-null string. */
|
---|
666 | {
|
---|
667 | if (s != nil && s != null) free(s);
|
---|
668 | }
|
---|
669 |
|
---|
670 | char *copystr(char *s)
|
---|
671 | /* Copy a non-null string using malloc. */
|
---|
672 | {
|
---|
673 | char *c;
|
---|
674 |
|
---|
675 | if (*s == 0) return null;
|
---|
676 | c= malloc((strlen(s) + 1) * sizeof(char));
|
---|
677 | strcpy(c, s);
|
---|
678 | return c;
|
---|
679 | }
|
---|
680 |
|
---|
681 | int is_default(environment *e)
|
---|
682 | {
|
---|
683 | return (e->flags & E_SPECIAL) && e->defval == nil;
|
---|
684 | }
|
---|
685 |
|
---|
686 | environment **searchenv(char *name)
|
---|
687 | {
|
---|
688 | environment **aenv= &env;
|
---|
689 |
|
---|
690 | while (*aenv != nil && strcmp((*aenv)->name, name) != 0) {
|
---|
691 | aenv= &(*aenv)->next;
|
---|
692 | }
|
---|
693 |
|
---|
694 | return aenv;
|
---|
695 | }
|
---|
696 |
|
---|
697 | #define b_getenv(name) (*searchenv(name))
|
---|
698 | /* Return the environment *structure* belonging to name, or nil if not found. */
|
---|
699 |
|
---|
700 | char *b_value(char *name)
|
---|
701 | /* The value of a variable. */
|
---|
702 | {
|
---|
703 | environment *e= b_getenv(name);
|
---|
704 |
|
---|
705 | return e == nil || !(e->flags & E_VAR) ? nil : e->value;
|
---|
706 | }
|
---|
707 |
|
---|
708 | char *b_body(char *name)
|
---|
709 | /* The value of a function. */
|
---|
710 | {
|
---|
711 | environment *e= b_getenv(name);
|
---|
712 |
|
---|
713 | return e == nil || !(e->flags & E_FUNCTION) ? nil : e->value;
|
---|
714 | }
|
---|
715 |
|
---|
716 | int b_setenv(int flags, char *name, char *arg, char *value)
|
---|
717 | /* Change the value of an environment variable. Returns the flags of the
|
---|
718 | * variable if you are not allowed to change it, 0 otherwise.
|
---|
719 | */
|
---|
720 | {
|
---|
721 | environment **aenv, *e;
|
---|
722 |
|
---|
723 | if (*(aenv= searchenv(name)) == nil) {
|
---|
724 | if (reserved(name)) return E_RESERVED;
|
---|
725 | e= malloc(sizeof(*e));
|
---|
726 | e->name= copystr(name);
|
---|
727 | e->flags= flags;
|
---|
728 | e->defval= nil;
|
---|
729 | e->next= nil;
|
---|
730 | *aenv= e;
|
---|
731 | } else {
|
---|
732 | e= *aenv;
|
---|
733 |
|
---|
734 | /* Don't change special variables to functions or vv. */
|
---|
735 | if (e->flags & E_SPECIAL
|
---|
736 | && (e->flags & E_FUNCTION) != (flags & E_FUNCTION)
|
---|
737 | ) return e->flags;
|
---|
738 |
|
---|
739 | e->flags= (e->flags & E_STICKY) | flags;
|
---|
740 | if (is_default(e)) {
|
---|
741 | e->defval= e->value;
|
---|
742 | } else {
|
---|
743 | sfree(e->value);
|
---|
744 | }
|
---|
745 | sfree(e->arg);
|
---|
746 | }
|
---|
747 | e->arg= copystr(arg);
|
---|
748 | e->value= copystr(value);
|
---|
749 |
|
---|
750 | return 0;
|
---|
751 | }
|
---|
752 |
|
---|
753 | int b_setvar(int flags, char *name, char *value)
|
---|
754 | /* Set variable or simple function. */
|
---|
755 | {
|
---|
756 | int r;
|
---|
757 |
|
---|
758 | if((r=b_setenv(flags, name, null, value))) {
|
---|
759 | return r;
|
---|
760 | }
|
---|
761 |
|
---|
762 | return r;
|
---|
763 | }
|
---|
764 |
|
---|
765 | void b_unset(char *name)
|
---|
766 | /* Remove a variable from the environment. A special variable is reset to
|
---|
767 | * its default value.
|
---|
768 | */
|
---|
769 | {
|
---|
770 | environment **aenv, *e;
|
---|
771 |
|
---|
772 | if ((e= *(aenv= searchenv(name))) == nil) return;
|
---|
773 |
|
---|
774 | if (e->flags & E_SPECIAL) {
|
---|
775 | if (e->defval != nil) {
|
---|
776 | sfree(e->arg);
|
---|
777 | e->arg= null;
|
---|
778 | sfree(e->value);
|
---|
779 | e->value= e->defval;
|
---|
780 | e->defval= nil;
|
---|
781 | }
|
---|
782 | } else {
|
---|
783 | sfree(e->name);
|
---|
784 | sfree(e->arg);
|
---|
785 | sfree(e->value);
|
---|
786 | *aenv= e->next;
|
---|
787 | free(e);
|
---|
788 | }
|
---|
789 | }
|
---|
790 |
|
---|
791 | long a2l(char *a)
|
---|
792 | /* Cheap atol(). */
|
---|
793 | {
|
---|
794 | int sign= 1;
|
---|
795 | long n= 0;
|
---|
796 |
|
---|
797 | if (*a == '-') { sign= -1; a++; }
|
---|
798 |
|
---|
799 | while (between('0', *a, '9')) n= n * 10 + (*a++ - '0');
|
---|
800 |
|
---|
801 | return sign * n;
|
---|
802 | }
|
---|
803 |
|
---|
804 | char *ul2a(u32_t n, unsigned b)
|
---|
805 | /* Transform a long number to ascii at base b, (b >= 8). */
|
---|
806 | {
|
---|
807 | static char num[(CHAR_BIT * sizeof(n) + 2) / 3 + 1];
|
---|
808 | char *a= arraylimit(num) - 1;
|
---|
809 | static char hex[16] = "0123456789ABCDEF";
|
---|
810 |
|
---|
811 | do *--a = hex[(int) (n % b)]; while ((n/= b) > 0);
|
---|
812 | return a;
|
---|
813 | }
|
---|
814 |
|
---|
815 | char *ul2a10(u32_t n)
|
---|
816 | /* Transform a long number to ascii at base 10. */
|
---|
817 | {
|
---|
818 | return ul2a(n, 10);
|
---|
819 | }
|
---|
820 |
|
---|
821 | unsigned a2x(char *a)
|
---|
822 | /* Ascii to hex. */
|
---|
823 | {
|
---|
824 | unsigned n= 0;
|
---|
825 | int c;
|
---|
826 |
|
---|
827 | for (;;) {
|
---|
828 | c= *a;
|
---|
829 | if (between('0', c, '9')) c= c - '0' + 0x0;
|
---|
830 | else
|
---|
831 | if (between('A', c, 'F')) c= c - 'A' + 0xA;
|
---|
832 | else
|
---|
833 | if (between('a', c, 'f')) c= c - 'a' + 0xa;
|
---|
834 | else
|
---|
835 | break;
|
---|
836 | n= (n<<4) | c;
|
---|
837 | a++;
|
---|
838 | }
|
---|
839 | return n;
|
---|
840 | }
|
---|
841 |
|
---|
842 | void get_parameters(void)
|
---|
843 | {
|
---|
844 | char params[SECTOR_SIZE + 1];
|
---|
845 | token **acmds;
|
---|
846 | int r, bus, processor;
|
---|
847 | memory *mp;
|
---|
848 | static char bus_type[][4] = {
|
---|
849 | "xt", "at", "mca"
|
---|
850 | };
|
---|
851 | static char vid_type[][4] = {
|
---|
852 | "mda", "cga", "ega", "ega", "vga", "vga"
|
---|
853 | };
|
---|
854 | static char vid_chrome[][6] = {
|
---|
855 | "mono", "color"
|
---|
856 | };
|
---|
857 |
|
---|
858 | /* Variables that Minix needs: */
|
---|
859 | b_setvar(E_SPECIAL|E_VAR|E_DEV, "rootdev", "ram");
|
---|
860 | b_setvar(E_SPECIAL|E_VAR|E_DEV, "ramimagedev", "bootdev");
|
---|
861 | b_setvar(E_SPECIAL|E_VAR, "ramsize", "0");
|
---|
862 | #if BIOS
|
---|
863 | processor = getprocessor();
|
---|
864 | if(processor == 1586) processor = 686;
|
---|
865 | b_setvar(E_SPECIAL|E_VAR, "processor", ul2a10(processor));
|
---|
866 | b_setvar(E_SPECIAL|E_VAR, "bus", bus_type[get_bus()]);
|
---|
867 | b_setvar(E_SPECIAL|E_VAR, "video", vid_type[get_video()]);
|
---|
868 | b_setvar(E_SPECIAL|E_VAR, "chrome", vid_chrome[get_video() & 1]);
|
---|
869 | params[0]= 0;
|
---|
870 | for (mp= mem; mp < arraylimit(mem); mp++) {
|
---|
871 | if (mp->size == 0) continue;
|
---|
872 | if (params[0] != 0) strcat(params, ",");
|
---|
873 | strcat(params, ul2a(mp->base, 0x10));
|
---|
874 | strcat(params, ":");
|
---|
875 | strcat(params, ul2a(mp->size, 0x10));
|
---|
876 | }
|
---|
877 | b_setvar(E_SPECIAL|E_VAR, "memory", params);
|
---|
878 |
|
---|
879 | #if DOS
|
---|
880 | b_setvar(E_SPECIAL|E_VAR, "dosfile-d0", vdisk);
|
---|
881 | #endif
|
---|
882 |
|
---|
883 | #endif
|
---|
884 | #if UNIX
|
---|
885 | b_setvar(E_SPECIAL|E_VAR, "processor", "?");
|
---|
886 | b_setvar(E_SPECIAL|E_VAR, "bus", "?");
|
---|
887 | b_setvar(E_SPECIAL|E_VAR, "video", "?");
|
---|
888 | b_setvar(E_SPECIAL|E_VAR, "chrome", "?");
|
---|
889 | b_setvar(E_SPECIAL|E_VAR, "memory", "?");
|
---|
890 | b_setvar(E_SPECIAL|E_VAR, "c0", "?");
|
---|
891 | #endif
|
---|
892 |
|
---|
893 | /* Variables boot needs: */
|
---|
894 | b_setvar(E_SPECIAL|E_VAR, "image", "boot/image");
|
---|
895 | b_setvar(E_SPECIAL|E_FUNCTION, "leader",
|
---|
896 | "echo --- Welcome to MINIX 3. This is the boot monitor. ---\\n");
|
---|
897 | b_setvar(E_SPECIAL|E_FUNCTION, "main", "menu");
|
---|
898 | b_setvar(E_SPECIAL|E_FUNCTION, "trailer", "");
|
---|
899 |
|
---|
900 | /* Default hidden menu function: */
|
---|
901 | b_setenv(E_RESERVED|E_FUNCTION, null, "=,Start MINIX", "boot");
|
---|
902 |
|
---|
903 | /* Tokenize bootparams sector. */
|
---|
904 | if ((r= readsectors(mon2abs(params), lowsec+PARAMSEC, 1)) != 0) {
|
---|
905 | readerr(lowsec+PARAMSEC, r);
|
---|
906 | exit(1);
|
---|
907 | }
|
---|
908 | params[SECTOR_SIZE]= 0;
|
---|
909 | acmds= tokenize(&cmds, params);
|
---|
910 |
|
---|
911 | /* Stuff the default action into the command chain. */
|
---|
912 | #if UNIX
|
---|
913 | (void) tokenize(acmds, ":;");
|
---|
914 | #elif DOS
|
---|
915 | (void) tokenize(tokenize(acmds, ":;leader;"), drun);
|
---|
916 | #else /* BIOS */
|
---|
917 | (void) tokenize(acmds, ":;leader;main");
|
---|
918 | #endif
|
---|
919 | }
|
---|
920 |
|
---|
921 | char *addptr;
|
---|
922 |
|
---|
923 | void addparm(char *n)
|
---|
924 | {
|
---|
925 | while (*n != 0 && *addptr != 0) *addptr++ = *n++;
|
---|
926 | }
|
---|
927 |
|
---|
928 | void save_parameters(void)
|
---|
929 | /* Save nondefault environment variables to the bootparams sector. */
|
---|
930 | {
|
---|
931 | environment *e;
|
---|
932 | char params[SECTOR_SIZE + 1];
|
---|
933 | int r;
|
---|
934 |
|
---|
935 | /* Default filling: */
|
---|
936 | memset(params, '\n', SECTOR_SIZE);
|
---|
937 |
|
---|
938 | /* Don't touch the 0! */
|
---|
939 | params[SECTOR_SIZE]= 0;
|
---|
940 | addptr= params;
|
---|
941 |
|
---|
942 | for (e= env; e != nil; e= e->next) {
|
---|
943 | if (e->flags & E_RESERVED || is_default(e)) continue;
|
---|
944 |
|
---|
945 | addparm(e->name);
|
---|
946 | if (e->flags & E_FUNCTION) {
|
---|
947 | addparm("(");
|
---|
948 | addparm(e->arg);
|
---|
949 | addparm(")");
|
---|
950 | } else {
|
---|
951 | addparm((e->flags & (E_DEV|E_SPECIAL)) != E_DEV
|
---|
952 | ? "=" : "=d ");
|
---|
953 | }
|
---|
954 | addparm(e->value);
|
---|
955 | if (*addptr == 0) {
|
---|
956 | printf("The environment is too big\n");
|
---|
957 | return;
|
---|
958 | }
|
---|
959 | *addptr++= '\n';
|
---|
960 | }
|
---|
961 |
|
---|
962 | /* Save the parameters on disk. */
|
---|
963 | if ((r= writesectors(mon2abs(params), lowsec+PARAMSEC, 1)) != 0) {
|
---|
964 | writerr(lowsec+PARAMSEC, r);
|
---|
965 | printf("Can't save environment\n");
|
---|
966 | }
|
---|
967 | }
|
---|
968 |
|
---|
969 | void show_env(void)
|
---|
970 | /* Show the environment settings. */
|
---|
971 | {
|
---|
972 | environment *e;
|
---|
973 | unsigned more= 0;
|
---|
974 | int c;
|
---|
975 |
|
---|
976 | for (e= env; e != nil; e= e->next) {
|
---|
977 | if (e->flags & E_RESERVED) continue;
|
---|
978 | if (!istty && is_default(e)) continue;
|
---|
979 |
|
---|
980 | if (e->flags & E_FUNCTION) {
|
---|
981 | printf("%s(%s) %s\n", e->name, e->arg, e->value);
|
---|
982 | } else {
|
---|
983 | printf(is_default(e) ? "%s = (%s)\n" : "%s = %s\n",
|
---|
984 | e->name, e->value);
|
---|
985 | }
|
---|
986 |
|
---|
987 | if (e->next != nil && istty && ++more % 20 == 0) {
|
---|
988 | printf("More? ");
|
---|
989 | c= getch();
|
---|
990 | if (c == ESC || c > ' ') {
|
---|
991 | putch('\n');
|
---|
992 | if (c > ' ') ungetch(c);
|
---|
993 | break;
|
---|
994 | }
|
---|
995 | printf("\b\b\b\b\b\b");
|
---|
996 | }
|
---|
997 | }
|
---|
998 | }
|
---|
999 |
|
---|
1000 | int numprefix(char *s, char **ps)
|
---|
1001 | /* True iff s is a string of digits. *ps will be set to the first nondigit
|
---|
1002 | * if non-nil, otherwise the string should end.
|
---|
1003 | */
|
---|
1004 | {
|
---|
1005 | char *n= s;
|
---|
1006 |
|
---|
1007 | while (between('0', *n, '9')) n++;
|
---|
1008 |
|
---|
1009 | if (n == s) return 0;
|
---|
1010 |
|
---|
1011 | if (ps == nil) return *n == 0;
|
---|
1012 |
|
---|
1013 | *ps= n;
|
---|
1014 | return 1;
|
---|
1015 | }
|
---|
1016 |
|
---|
1017 | int numeric(char *s)
|
---|
1018 | {
|
---|
1019 | return numprefix(s, (char **) nil);
|
---|
1020 | }
|
---|
1021 |
|
---|
1022 | #if BIOS
|
---|
1023 |
|
---|
1024 | /* Device numbers of standard MINIX devices. */
|
---|
1025 | #define DEV_FD0 0x0200
|
---|
1026 | static dev_t dev_cNd0[] = { 0x0300, 0x0800, 0x0A00, 0x0C00, 0x1000 };
|
---|
1027 | #define minor_p0s0 128
|
---|
1028 |
|
---|
1029 | static int block_size;
|
---|
1030 |
|
---|
1031 | dev_t name2dev(char *name)
|
---|
1032 | /* Translate, say, /dev/c0d0p2 to a device number. If the name can't be
|
---|
1033 | * found on the boot device, then do some guesswork. The global structure
|
---|
1034 | * "tmpdev" will be filled in based on the name, so that "boot d1p0" knows
|
---|
1035 | * what device to boot without interpreting device numbers.
|
---|
1036 | */
|
---|
1037 | {
|
---|
1038 | dev_t dev;
|
---|
1039 | ino_t ino;
|
---|
1040 | int drive;
|
---|
1041 | struct stat st;
|
---|
1042 | char *n, *s;
|
---|
1043 |
|
---|
1044 | /* "boot *d0p2" means: make partition 2 active before you boot it. */
|
---|
1045 | if ((activate= (name[0] == '*'))) name++;
|
---|
1046 |
|
---|
1047 | /* The special name "bootdev" must be translated to the boot device. */
|
---|
1048 | if (strcmp(name, "bootdev") == 0) {
|
---|
1049 | if (bootdev.device == -1) {
|
---|
1050 | printf("The boot device could not be named\n");
|
---|
1051 | errno= 0;
|
---|
1052 | return -1;
|
---|
1053 | }
|
---|
1054 | name= bootdev.name;
|
---|
1055 | }
|
---|
1056 |
|
---|
1057 | /* If our boot device doesn't have a file system, or we want to know
|
---|
1058 | * what a name means for the BIOS, then we need to interpret the
|
---|
1059 | * device name ourselves: "fd" = floppy, "c0d0" = hard disk, etc.
|
---|
1060 | */
|
---|
1061 | tmpdev.device= tmpdev.primary= tmpdev.secondary= -1;
|
---|
1062 | dev= -1;
|
---|
1063 | n= name;
|
---|
1064 | if (strncmp(n, "/dev/", 5) == 0) n+= 5;
|
---|
1065 |
|
---|
1066 | if (strcmp(n, "ram") == 0) {
|
---|
1067 | dev= DEV_RAM;
|
---|
1068 | } else
|
---|
1069 | if (strcmp(n, "boot") == 0) {
|
---|
1070 | dev= DEV_BOOT;
|
---|
1071 | } else
|
---|
1072 | if (n[0] == 'f' && n[1] == 'd' && numeric(n+2)) {
|
---|
1073 | /* Floppy. */
|
---|
1074 | tmpdev.device= a2l(n+2);
|
---|
1075 | dev= DEV_FD0 + tmpdev.device;
|
---|
1076 | } else
|
---|
1077 | if ((n[0] == 'h' || n[0] == 's') && n[1] == 'd' && numprefix(n+2, &s)
|
---|
1078 | && (*s == 0 || (between('a', *s, 'd') && s[1] == 0))
|
---|
1079 | ) {
|
---|
1080 | /* Old style hard disk (backwards compatibility.) */
|
---|
1081 | dev= a2l(n+2);
|
---|
1082 | tmpdev.device= dev / (1 + NR_PARTITIONS);
|
---|
1083 | tmpdev.primary= (dev % (1 + NR_PARTITIONS)) - 1;
|
---|
1084 | if (*s != 0) {
|
---|
1085 | /* Subpartition. */
|
---|
1086 | tmpdev.secondary= *s - 'a';
|
---|
1087 | dev= minor_p0s0
|
---|
1088 | + (tmpdev.device * NR_PARTITIONS
|
---|
1089 | + tmpdev.primary) * NR_PARTITIONS
|
---|
1090 | + tmpdev.secondary;
|
---|
1091 | }
|
---|
1092 | tmpdev.device+= 0x80;
|
---|
1093 | dev+= n[0] == 'h' ? dev_cNd0[0] : dev_cNd0[2];
|
---|
1094 | } else {
|
---|
1095 | /* Hard disk. */
|
---|
1096 | int ctrlr= 0;
|
---|
1097 |
|
---|
1098 | if (n[0] == 'c' && between('0', n[1], '4')) {
|
---|
1099 | ctrlr= (n[1] - '0');
|
---|
1100 | tmpdev.device= 0;
|
---|
1101 | n+= 2;
|
---|
1102 | }
|
---|
1103 | if (n[0] == 'd' && between('0', n[1], '7')) {
|
---|
1104 | tmpdev.device= (n[1] - '0');
|
---|
1105 | n+= 2;
|
---|
1106 | if (n[0] == 'p' && between('0', n[1], '3')) {
|
---|
1107 | tmpdev.primary= (n[1] - '0');
|
---|
1108 | n+= 2;
|
---|
1109 | if (n[0] == 's' && between('0', n[1], '3')) {
|
---|
1110 | tmpdev.secondary= (n[1] - '0');
|
---|
1111 | n+= 2;
|
---|
1112 | }
|
---|
1113 | }
|
---|
1114 | }
|
---|
1115 | if (*n == 0) {
|
---|
1116 | dev= dev_cNd0[ctrlr];
|
---|
1117 | if (tmpdev.secondary < 0) {
|
---|
1118 | dev += tmpdev.device * (NR_PARTITIONS+1)
|
---|
1119 | + (tmpdev.primary + 1);
|
---|
1120 | } else {
|
---|
1121 | dev += minor_p0s0
|
---|
1122 | + (tmpdev.device * NR_PARTITIONS
|
---|
1123 | + tmpdev.primary) * NR_PARTITIONS
|
---|
1124 | + tmpdev.secondary;
|
---|
1125 | }
|
---|
1126 | tmpdev.device+= 0x80;
|
---|
1127 | }
|
---|
1128 | }
|
---|
1129 |
|
---|
1130 | /* Look the name up on the boot device for the UNIX device number. */
|
---|
1131 | if (fsok == -1) fsok= r_super(&block_size) != 0;
|
---|
1132 | if (fsok) {
|
---|
1133 | /* The current working directory is "/dev". */
|
---|
1134 | ino= r_lookup(r_lookup(ROOT_INO, "dev"), name);
|
---|
1135 |
|
---|
1136 | if (ino != 0) {
|
---|
1137 | /* Name has been found, extract the device number. */
|
---|
1138 | r_stat(ino, &st);
|
---|
1139 | if (!S_ISBLK(st.st_mode)) {
|
---|
1140 | printf("%s is not a block device\n", name);
|
---|
1141 | errno= 0;
|
---|
1142 | return (dev_t) -1;
|
---|
1143 | }
|
---|
1144 | dev= st.st_rdev;
|
---|
1145 | }
|
---|
1146 | }
|
---|
1147 |
|
---|
1148 | if (tmpdev.primary < 0) activate= 0; /* Careful now! */
|
---|
1149 |
|
---|
1150 | if (dev == -1) {
|
---|
1151 | printf("Can't recognize '%s' as a device\n", name);
|
---|
1152 | errno= 0;
|
---|
1153 | }
|
---|
1154 | return dev;
|
---|
1155 | }
|
---|
1156 |
|
---|
1157 | #if DEBUG
|
---|
1158 | static void apm_perror(char *label, u16_t ax)
|
---|
1159 | {
|
---|
1160 | unsigned ah;
|
---|
1161 | char *str;
|
---|
1162 |
|
---|
1163 | ah= (ax >> 8);
|
---|
1164 | switch(ah)
|
---|
1165 | {
|
---|
1166 | case 0x01: str= "APM functionality disabled"; break;
|
---|
1167 | case 0x03: str= "interface not connected"; break;
|
---|
1168 | case 0x09: str= "unrecognized device ID"; break;
|
---|
1169 | case 0x0A: str= "parameter value out of range"; break;
|
---|
1170 | case 0x0B: str= "interface not engaged"; break;
|
---|
1171 | case 0x60: str= "unable to enter requested state"; break;
|
---|
1172 | case 0x86: str= "APM not present"; break;
|
---|
1173 | default: printf("%s: error 0x%02x\n", label, ah); return;
|
---|
1174 | }
|
---|
1175 | printf("%s: %s\n", label, str);
|
---|
1176 | }
|
---|
1177 |
|
---|
1178 | #define apm_printf printf
|
---|
1179 | #else
|
---|
1180 | #define apm_perror(label, ax) ((void)0)
|
---|
1181 | #define apm_printf
|
---|
1182 | #endif
|
---|
1183 |
|
---|
1184 | static void off(void)
|
---|
1185 | {
|
---|
1186 | bios_env_t be;
|
---|
1187 | unsigned al, ah;
|
---|
1188 |
|
---|
1189 | /* Try to switch off the system. Print diagnostic information
|
---|
1190 | * that can be useful if the operation fails.
|
---|
1191 | */
|
---|
1192 |
|
---|
1193 | be.ax= 0x5300; /* APM, Installation check */
|
---|
1194 | be.bx= 0; /* Device, APM BIOS */
|
---|
1195 | int15(&be);
|
---|
1196 | if (be.flags & FL_CARRY)
|
---|
1197 | {
|
---|
1198 | apm_perror("APM installation check failed", be.ax);
|
---|
1199 | return;
|
---|
1200 | }
|
---|
1201 | if (be.bx != (('P' << 8) | 'M'))
|
---|
1202 | {
|
---|
1203 | apm_printf("APM signature not found (got 0x%04x)\n", be.bx);
|
---|
1204 | return;
|
---|
1205 | }
|
---|
1206 |
|
---|
1207 | ah= be.ax >> 8;
|
---|
1208 | if (ah > 9)
|
---|
1209 | ah= (ah >> 4)*10 + (ah & 0xf);
|
---|
1210 | al= be.ax & 0xff;
|
---|
1211 | if (al > 9)
|
---|
1212 | al= (al >> 4)*10 + (al & 0xf);
|
---|
1213 | apm_printf("APM version %u.%u%s%s%s%s%s\n",
|
---|
1214 | ah, al,
|
---|
1215 | (be.cx & 0x1) ? ", 16-bit PM" : "",
|
---|
1216 | (be.cx & 0x2) ? ", 32-bit PM" : "",
|
---|
1217 | (be.cx & 0x4) ? ", CPU-Idle" : "",
|
---|
1218 | (be.cx & 0x8) ? ", APM-disabled" : "",
|
---|
1219 | (be.cx & 0x10) ? ", APM-disengaged" : "");
|
---|
1220 |
|
---|
1221 | /* Connect */
|
---|
1222 | be.ax= 0x5301; /* APM, Real mode interface connect */
|
---|
1223 | be.bx= 0x0000; /* APM BIOS */
|
---|
1224 | int15(&be);
|
---|
1225 | if (be.flags & FL_CARRY)
|
---|
1226 | {
|
---|
1227 | apm_perror("APM real mode connect failed", be.ax);
|
---|
1228 | return;
|
---|
1229 | }
|
---|
1230 |
|
---|
1231 | /* Ask for a seat upgrade */
|
---|
1232 | be.ax= 0x530e; /* APM, Driver Version */
|
---|
1233 | be.bx= 0x0000; /* BIOS */
|
---|
1234 | be.cx= 0x0102; /* version 1.2 */
|
---|
1235 | int15(&be);
|
---|
1236 | if (be.flags & FL_CARRY)
|
---|
1237 | {
|
---|
1238 | apm_perror("Set driver version failed", be.ax);
|
---|
1239 | goto disco;
|
---|
1240 | }
|
---|
1241 |
|
---|
1242 | /* Is this version really worth reporting. Well, if the system
|
---|
1243 | * does switch off, you won't see it anyway.
|
---|
1244 | */
|
---|
1245 | ah= be.ax >> 8;
|
---|
1246 | if (ah > 9)
|
---|
1247 | ah= (ah >> 4)*10 + (ah & 0xf);
|
---|
1248 | al= be.ax & 0xff;
|
---|
1249 | if (al > 9)
|
---|
1250 | al= (al >> 4)*10 + (al & 0xf);
|
---|
1251 | apm_printf("Got APM connection version %u.%u\n", ah, al);
|
---|
1252 |
|
---|
1253 | /* Enable */
|
---|
1254 | be.ax= 0x5308; /* APM, Enable/disable power management */
|
---|
1255 | be.bx= 0x0001; /* All device managed by APM BIOS */
|
---|
1256 | #if 0
|
---|
1257 | /* For old APM 1.0 systems, we need 0xffff. Assume that those
|
---|
1258 | * systems do not exist.
|
---|
1259 | */
|
---|
1260 | be.bx= 0xffff; /* All device managed by APM BIOS (compat) */
|
---|
1261 | #endif
|
---|
1262 | be.cx= 0x0001; /* Enable power management */
|
---|
1263 | int15(&be);
|
---|
1264 | if (be.flags & FL_CARRY)
|
---|
1265 | {
|
---|
1266 | apm_perror("Enable power management failed", be.ax);
|
---|
1267 | goto disco;
|
---|
1268 | }
|
---|
1269 |
|
---|
1270 | /* Off */
|
---|
1271 | be.ax= 0x5307; /* APM, Set Power State */
|
---|
1272 | be.bx= 0x0001; /* All devices managed by APM */
|
---|
1273 | be.cx= 0x0003; /* Off */
|
---|
1274 | int15(&be);
|
---|
1275 | if (be.flags & FL_CARRY)
|
---|
1276 | {
|
---|
1277 | apm_perror("Set power state failed", be.ax);
|
---|
1278 | goto disco;
|
---|
1279 | }
|
---|
1280 |
|
---|
1281 | apm_printf("Power off sequence successfully completed.\n\n");
|
---|
1282 | apm_printf("Ha, ha, just kidding!\n");
|
---|
1283 |
|
---|
1284 | disco:
|
---|
1285 | /* Disconnect */
|
---|
1286 | be.ax= 0x5304; /* APM, interface disconnect */
|
---|
1287 | be.bx= 0x0000; /* APM BIOS */
|
---|
1288 | int15(&be);
|
---|
1289 | if (be.flags & FL_CARRY)
|
---|
1290 | {
|
---|
1291 | apm_perror("APM interface disconnect failed", be.ax);
|
---|
1292 | return;
|
---|
1293 | }
|
---|
1294 | }
|
---|
1295 |
|
---|
1296 | #if !DOS
|
---|
1297 | #define B_NOSIG -1 /* "No signature" error code. */
|
---|
1298 |
|
---|
1299 | int exec_bootstrap(void)
|
---|
1300 | /* Load boot sector from the disk or floppy described by tmpdev and execute it.
|
---|
1301 | */
|
---|
1302 | {
|
---|
1303 | int r, n, dirty= 0;
|
---|
1304 | char master[SECTOR_SIZE];
|
---|
1305 | struct part_entry *table[NR_PARTITIONS], dummy, *active= &dummy;
|
---|
1306 | u32_t masterpos;
|
---|
1307 |
|
---|
1308 | active->lowsec= 0;
|
---|
1309 |
|
---|
1310 | /* Select a partition table entry. */
|
---|
1311 | while (tmpdev.primary >= 0) {
|
---|
1312 | masterpos= active->lowsec;
|
---|
1313 |
|
---|
1314 | if ((r= get_master(master, table, masterpos)) != 0) return r;
|
---|
1315 |
|
---|
1316 | active= table[tmpdev.primary];
|
---|
1317 |
|
---|
1318 | /* How does one check a partition table entry? */
|
---|
1319 | if (active->sysind == NO_PART) return B_NOSIG;
|
---|
1320 |
|
---|
1321 | tmpdev.primary= tmpdev.secondary;
|
---|
1322 | tmpdev.secondary= -1;
|
---|
1323 | }
|
---|
1324 |
|
---|
1325 | if (activate && !active->bootind) {
|
---|
1326 | for (n= 0; n < NR_PARTITIONS; n++) table[n]->bootind= 0;
|
---|
1327 | active->bootind= ACTIVE_FLAG;
|
---|
1328 | dirty= 1;
|
---|
1329 | }
|
---|
1330 |
|
---|
1331 | /* Read the boot sector. */
|
---|
1332 | if ((r= readsectors(BOOTPOS, active->lowsec, 1)) != 0) return r;
|
---|
1333 |
|
---|
1334 | /* Check signature word. */
|
---|
1335 | if (get_word(BOOTPOS+SIGNATOFF) != SIGNATURE) return B_NOSIG;
|
---|
1336 |
|
---|
1337 | /* Write the partition table if a member must be made active. */
|
---|
1338 | if (dirty && (r= writesectors(mon2abs(master), masterpos, 1)) != 0)
|
---|
1339 | return r;
|
---|
1340 |
|
---|
1341 | bootstrap(device, active);
|
---|
1342 | }
|
---|
1343 |
|
---|
1344 | void boot_device(char *devname)
|
---|
1345 | /* Boot the device named by devname. */
|
---|
1346 | {
|
---|
1347 | dev_t dev= name2dev(devname);
|
---|
1348 | int save_dev= device;
|
---|
1349 | int r;
|
---|
1350 | char *err;
|
---|
1351 |
|
---|
1352 | if (tmpdev.device < 0) {
|
---|
1353 | if (dev != -1) printf("Can't boot from %s\n", devname);
|
---|
1354 | return;
|
---|
1355 | }
|
---|
1356 |
|
---|
1357 | /* Change current device and try to load and execute its bootstrap. */
|
---|
1358 | device= tmpdev.device;
|
---|
1359 |
|
---|
1360 | if ((r= dev_open()) == 0) r= exec_bootstrap();
|
---|
1361 |
|
---|
1362 | err= r == B_NOSIG ? "Not bootable" : bios_err(r);
|
---|
1363 | printf("Can't boot %s: %s\n", devname, err);
|
---|
1364 |
|
---|
1365 | /* Restore boot device setting. */
|
---|
1366 | device= save_dev;
|
---|
1367 | (void) dev_open();
|
---|
1368 | }
|
---|
1369 |
|
---|
1370 | void ctty(char *line)
|
---|
1371 | {
|
---|
1372 | if (between('0', line[0], '3') && line[1] == 0) {
|
---|
1373 | serial_init(line[0] - '0');
|
---|
1374 | } else {
|
---|
1375 | printf("Bad serial line number: %s\n", line);
|
---|
1376 | }
|
---|
1377 | }
|
---|
1378 |
|
---|
1379 | #else /* DOS */
|
---|
1380 |
|
---|
1381 | void boot_device(char *devname)
|
---|
1382 | /* No booting of other devices under DOS. */
|
---|
1383 | {
|
---|
1384 | printf("Can't boot devices under DOS\n");
|
---|
1385 | }
|
---|
1386 |
|
---|
1387 | void ctty(char *line)
|
---|
1388 | /* Don't know how to handle serial lines under DOS. */
|
---|
1389 | {
|
---|
1390 | printf("No serial line support under DOS\n");
|
---|
1391 | }
|
---|
1392 |
|
---|
1393 | #endif /* DOS */
|
---|
1394 | #endif /* BIOS */
|
---|
1395 |
|
---|
1396 | void ls(char *dir)
|
---|
1397 | /* List the contents of a directory. */
|
---|
1398 | {
|
---|
1399 | ino_t ino;
|
---|
1400 | struct stat st;
|
---|
1401 | char name[NAME_MAX+1];
|
---|
1402 |
|
---|
1403 | if (fsok == -1) fsok= r_super(&block_size) != 0;
|
---|
1404 | if (!fsok) return;
|
---|
1405 |
|
---|
1406 | /* (,) construct because r_stat returns void */
|
---|
1407 | if ((ino= r_lookup(ROOT_INO, dir)) == 0 ||
|
---|
1408 | (r_stat(ino, &st), r_readdir(name)) == -1)
|
---|
1409 | {
|
---|
1410 | printf("ls: %s: %s\n", dir, unix_err(errno));
|
---|
1411 | return;
|
---|
1412 | }
|
---|
1413 | (void) r_readdir(name); /* Skip ".." too. */
|
---|
1414 |
|
---|
1415 | while ((ino= r_readdir(name)) != 0) printf("%s/%s\n", dir, name);
|
---|
1416 | }
|
---|
1417 |
|
---|
1418 | u32_t milli_time(void)
|
---|
1419 | {
|
---|
1420 | return get_tick() * MSEC_PER_TICK;
|
---|
1421 | }
|
---|
1422 |
|
---|
1423 | u32_t milli_since(u32_t base)
|
---|
1424 | {
|
---|
1425 | return (milli_time() + (TICKS_PER_DAY*MSEC_PER_TICK) - base)
|
---|
1426 | % (TICKS_PER_DAY*MSEC_PER_TICK);
|
---|
1427 | }
|
---|
1428 |
|
---|
1429 | char *Thandler;
|
---|
1430 | u32_t Tbase, Tcount;
|
---|
1431 |
|
---|
1432 | void unschedule(void)
|
---|
1433 | /* Invalidate a waiting command. */
|
---|
1434 | {
|
---|
1435 | alarm(0);
|
---|
1436 |
|
---|
1437 | if (Thandler != nil) {
|
---|
1438 | free(Thandler);
|
---|
1439 | Thandler= nil;
|
---|
1440 | }
|
---|
1441 | }
|
---|
1442 |
|
---|
1443 | void schedule(long msec, char *cmd)
|
---|
1444 | /* Schedule command at a certain time from now. */
|
---|
1445 | {
|
---|
1446 | unschedule();
|
---|
1447 | Thandler= cmd;
|
---|
1448 | Tbase= milli_time();
|
---|
1449 | Tcount= msec;
|
---|
1450 | alarm(1);
|
---|
1451 | }
|
---|
1452 |
|
---|
1453 | int expired(void)
|
---|
1454 | /* Check if the timer expired for getch(). */
|
---|
1455 | {
|
---|
1456 | return (Thandler != nil && milli_since(Tbase) >= Tcount);
|
---|
1457 | }
|
---|
1458 |
|
---|
1459 | void delay(char *msec)
|
---|
1460 | /* Delay for a given time. */
|
---|
1461 | {
|
---|
1462 | u32_t base, count;
|
---|
1463 |
|
---|
1464 | if ((count= a2l(msec)) == 0) return;
|
---|
1465 | base= milli_time();
|
---|
1466 |
|
---|
1467 | alarm(1);
|
---|
1468 |
|
---|
1469 | do {
|
---|
1470 | pause();
|
---|
1471 | } while (!interrupt() && !expired() && milli_since(base) < count);
|
---|
1472 | }
|
---|
1473 |
|
---|
1474 | enum whatfun { NOFUN, SELECT, DEFFUN, USERFUN } menufun(environment *e)
|
---|
1475 | {
|
---|
1476 | if (!(e->flags & E_FUNCTION) || e->arg[0] == 0) return NOFUN;
|
---|
1477 | if (e->arg[1] != ',') return SELECT;
|
---|
1478 | return e->flags & E_RESERVED ? DEFFUN : USERFUN;
|
---|
1479 | }
|
---|
1480 |
|
---|
1481 | void menu(void)
|
---|
1482 | /* By default: Show a simple menu.
|
---|
1483 | * Multiple kernels/images: Show extra selection options.
|
---|
1484 | * User defined function: Kill the defaults and show these.
|
---|
1485 | * Wait for a keypress and execute the given function.
|
---|
1486 | */
|
---|
1487 | {
|
---|
1488 | int c, def= 1;
|
---|
1489 | char *choice= nil;
|
---|
1490 | environment *e;
|
---|
1491 |
|
---|
1492 | /* Just a default menu? */
|
---|
1493 | for (e= env; e != nil; e= e->next) if (menufun(e) == USERFUN) def= 0;
|
---|
1494 |
|
---|
1495 | printf("\nHit a key as follows:\n\n");
|
---|
1496 |
|
---|
1497 | /* Show the choices. */
|
---|
1498 | for (e= env; e != nil; e= e->next) {
|
---|
1499 | switch (menufun(e)) {
|
---|
1500 | case DEFFUN:
|
---|
1501 | if (!def) break;
|
---|
1502 | /*FALL THROUGH*/
|
---|
1503 | case USERFUN:
|
---|
1504 | printf(" %c %s\n", e->arg[0], e->arg+2);
|
---|
1505 | break;
|
---|
1506 | case SELECT:
|
---|
1507 | printf(" %c Select %s kernel\n", e->arg[0],e->name);
|
---|
1508 | break;
|
---|
1509 | default:;
|
---|
1510 | }
|
---|
1511 | }
|
---|
1512 |
|
---|
1513 | /* Wait for a keypress. */
|
---|
1514 | do {
|
---|
1515 | c= getch();
|
---|
1516 | if (interrupt() || expired()) return;
|
---|
1517 |
|
---|
1518 | unschedule();
|
---|
1519 |
|
---|
1520 | for (e= env; e != nil; e= e->next) {
|
---|
1521 | switch (menufun(e)) {
|
---|
1522 | case DEFFUN:
|
---|
1523 | if (!def) break;
|
---|
1524 | case USERFUN:
|
---|
1525 | case SELECT:
|
---|
1526 | if (c == e->arg[0]) choice= e->value;
|
---|
1527 | }
|
---|
1528 | }
|
---|
1529 | } while (choice == nil);
|
---|
1530 |
|
---|
1531 | /* Execute the chosen function. */
|
---|
1532 | printf("%c\n", c);
|
---|
1533 | (void) tokenize(&cmds, choice);
|
---|
1534 | }
|
---|
1535 |
|
---|
1536 | void help(void)
|
---|
1537 | /* Not everyone is a rocket scientist. */
|
---|
1538 | {
|
---|
1539 | struct help {
|
---|
1540 | char *thing;
|
---|
1541 | char *help;
|
---|
1542 | } *pi;
|
---|
1543 | static struct help info[] = {
|
---|
1544 | { nil, "Names:" },
|
---|
1545 | { "rootdev", "Root device" },
|
---|
1546 | { "ramimagedev", "Device to use as RAM disk image " },
|
---|
1547 | { "ramsize", "RAM disk size (if no image device) " },
|
---|
1548 | { "bootdev", "Special name for the boot device" },
|
---|
1549 | { "fd0, d0p2, c0d0p1s0", "Devices (as in /dev)" },
|
---|
1550 | { "image", "Name of the boot image to use" },
|
---|
1551 | { "main", "Startup function" },
|
---|
1552 | { "bootdelay", "Delay in msec after loading image" },
|
---|
1553 | { nil, "Commands:" },
|
---|
1554 | { "name = [device] value", "Set environment variable" },
|
---|
1555 | { "name() { ... }", "Define function" },
|
---|
1556 | { "name(key,text) { ... }",
|
---|
1557 | "A menu option like: minix(=,Start MINIX) {boot}" },
|
---|
1558 | { "name", "Call function" },
|
---|
1559 | { "boot [device]", "Boot Minix or another O.S." },
|
---|
1560 | { "ctty [line]", "Duplicate to serial line" },
|
---|
1561 | { "delay [msec]", "Delay (500 msec default)" },
|
---|
1562 | { "echo word ...", "Display the words" },
|
---|
1563 | { "ls [directory]", "List contents of directory" },
|
---|
1564 | { "menu", "Show menu and choose menu option" },
|
---|
1565 | { "save / set", "Save or show environment" },
|
---|
1566 | { "trap msec command", "Schedule command " },
|
---|
1567 | { "unset name ...", "Unset variable or set to default" },
|
---|
1568 | { "exit / off", "Exit the Monitor / Power off" },
|
---|
1569 | };
|
---|
1570 |
|
---|
1571 | for (pi= info; pi < arraylimit(info); pi++) {
|
---|
1572 | if (pi->thing != nil) printf(" %-24s- ", pi->thing);
|
---|
1573 | printf("%s\n", pi->help);
|
---|
1574 | }
|
---|
1575 | }
|
---|
1576 |
|
---|
1577 | void execute(void)
|
---|
1578 | /* Get one command from the command chain and execute it. */
|
---|
1579 | {
|
---|
1580 | token *second, *third, *fourth, *sep;
|
---|
1581 | char *name;
|
---|
1582 | int res;
|
---|
1583 | size_t n= 0;
|
---|
1584 |
|
---|
1585 | if (err) {
|
---|
1586 | /* An error occured, stop interpreting. */
|
---|
1587 | while (cmds != nil) voidtoken();
|
---|
1588 | return;
|
---|
1589 | }
|
---|
1590 |
|
---|
1591 | if (expired()) { /* Timer expired? */
|
---|
1592 | parse_code(Thandler);
|
---|
1593 | unschedule();
|
---|
1594 | }
|
---|
1595 |
|
---|
1596 | /* There must be a separator lurking somewhere. */
|
---|
1597 | for (sep= cmds; sep != nil && sep->token[0] != ';'; sep= sep->next) n++;
|
---|
1598 |
|
---|
1599 | name= cmds->token;
|
---|
1600 | res= reserved(name);
|
---|
1601 | if ((second= cmds->next) != nil
|
---|
1602 | && (third= second->next) != nil)
|
---|
1603 | fourth= third->next;
|
---|
1604 |
|
---|
1605 | /* Null command? */
|
---|
1606 | if (n == 0) {
|
---|
1607 | voidtoken();
|
---|
1608 | return;
|
---|
1609 | } else
|
---|
1610 | /* name = [device] value? */
|
---|
1611 | if ((n == 3 || n == 4)
|
---|
1612 | && !sugar(name)
|
---|
1613 | && second->token[0] == '='
|
---|
1614 | && !sugar(third->token)
|
---|
1615 | && (n == 3 || (n == 4 && third->token[0] == 'd'
|
---|
1616 | && !sugar(fourth->token)
|
---|
1617 | ))) {
|
---|
1618 | char *value= third->token;
|
---|
1619 | int flags= E_VAR;
|
---|
1620 |
|
---|
1621 | if (n == 4) { value= fourth->token; flags|= E_DEV; }
|
---|
1622 |
|
---|
1623 | if ((flags= b_setvar(flags, name, value)) != 0) {
|
---|
1624 | printf("%s is a %s\n", name,
|
---|
1625 | flags & E_RESERVED ? "reserved word" :
|
---|
1626 | "special function");
|
---|
1627 | err= 1;
|
---|
1628 | }
|
---|
1629 | while (cmds != sep) voidtoken();
|
---|
1630 | return;
|
---|
1631 | } else
|
---|
1632 | /* name '(arg)' ... ? */
|
---|
1633 | if (n >= 3
|
---|
1634 | && !sugar(name)
|
---|
1635 | && second->token[0] == '('
|
---|
1636 | ) {
|
---|
1637 | token *fun;
|
---|
1638 | int c, flags, depth;
|
---|
1639 | char *body;
|
---|
1640 | size_t len;
|
---|
1641 |
|
---|
1642 | sep= fun= third;
|
---|
1643 | depth= 0;
|
---|
1644 | len= 1;
|
---|
1645 | while (sep != nil) {
|
---|
1646 | if ((c= sep->token[0]) == ';' && depth == 0) break;
|
---|
1647 | len+= strlen(sep->token) + 1;
|
---|
1648 | sep= sep->next;
|
---|
1649 | if (c == '{') depth++;
|
---|
1650 | if (c == '}' && --depth == 0) break;
|
---|
1651 | }
|
---|
1652 |
|
---|
1653 | body= malloc(len * sizeof(char));
|
---|
1654 | *body= 0;
|
---|
1655 |
|
---|
1656 | while (fun != sep) {
|
---|
1657 | strcat(body, fun->token);
|
---|
1658 | if (!sugar(fun->token)
|
---|
1659 | && !sugar(fun->next->token)
|
---|
1660 | ) strcat(body, " ");
|
---|
1661 | fun= fun->next;
|
---|
1662 | }
|
---|
1663 | second->token[strlen(second->token)-1]= 0;
|
---|
1664 |
|
---|
1665 | if (depth != 0) {
|
---|
1666 | printf("Missing '}'\n");
|
---|
1667 | err= 1;
|
---|
1668 | } else
|
---|
1669 | if ((flags= b_setenv(E_FUNCTION, name,
|
---|
1670 | second->token+1, body)) != 0) {
|
---|
1671 | printf("%s is a %s\n", name,
|
---|
1672 | flags & E_RESERVED ? "reserved word" :
|
---|
1673 | "special variable");
|
---|
1674 | err= 1;
|
---|
1675 | }
|
---|
1676 | while (cmds != sep) voidtoken();
|
---|
1677 | free(body);
|
---|
1678 | return;
|
---|
1679 | } else
|
---|
1680 | /* Grouping? */
|
---|
1681 | if (name[0] == '{') {
|
---|
1682 | token **acmds= &cmds->next;
|
---|
1683 | char *t;
|
---|
1684 | int depth= 1;
|
---|
1685 |
|
---|
1686 | /* Find and remove matching '}' */
|
---|
1687 | depth= 1;
|
---|
1688 | while (*acmds != nil) {
|
---|
1689 | t= (*acmds)->token;
|
---|
1690 | if (t[0] == '{') depth++;
|
---|
1691 | if (t[0] == '}' && --depth == 0) { t[0]= ';'; break; }
|
---|
1692 | acmds= &(*acmds)->next;
|
---|
1693 | }
|
---|
1694 | voidtoken();
|
---|
1695 | return;
|
---|
1696 | } else
|
---|
1697 | /* Command coming up, check if ESC typed. */
|
---|
1698 | if (interrupt()) {
|
---|
1699 | return;
|
---|
1700 | } else
|
---|
1701 | /* unset name ..., echo word ...? */
|
---|
1702 | if (n >= 1 && (res == R_UNSET || res == R_ECHO)) {
|
---|
1703 | char *arg= poptoken(), *p;
|
---|
1704 |
|
---|
1705 | for (;;) {
|
---|
1706 | free(arg);
|
---|
1707 | if (cmds == sep) break;
|
---|
1708 | arg= poptoken();
|
---|
1709 | if (res == R_UNSET) { /* unset arg */
|
---|
1710 | b_unset(arg);
|
---|
1711 | } else { /* echo arg */
|
---|
1712 | p= arg;
|
---|
1713 | while (*p != 0) {
|
---|
1714 | if (*p != '\\') {
|
---|
1715 | putch(*p);
|
---|
1716 | } else
|
---|
1717 | switch (*++p) {
|
---|
1718 | case 0:
|
---|
1719 | if (cmds == sep) return;
|
---|
1720 | continue;
|
---|
1721 | case 'n':
|
---|
1722 | putch('\n');
|
---|
1723 | break;
|
---|
1724 | case 'v':
|
---|
1725 | printf(version);
|
---|
1726 | break;
|
---|
1727 | case 'c':
|
---|
1728 | clear_screen();
|
---|
1729 | break;
|
---|
1730 | case 'w':
|
---|
1731 | for (;;) {
|
---|
1732 | if (interrupt())
|
---|
1733 | return;
|
---|
1734 | if (getch() == '\n')
|
---|
1735 | break;
|
---|
1736 | }
|
---|
1737 | break;
|
---|
1738 | default:
|
---|
1739 | putch(*p);
|
---|
1740 | }
|
---|
1741 | p++;
|
---|
1742 | }
|
---|
1743 | putch(cmds != sep ? ' ' : '\n');
|
---|
1744 | }
|
---|
1745 | }
|
---|
1746 | return;
|
---|
1747 | } else
|
---|
1748 | /* boot -opts? */
|
---|
1749 | if (n == 2 && res == R_BOOT && second->token[0] == '-') {
|
---|
1750 | static char optsvar[]= "bootopts";
|
---|
1751 | (void) b_setvar(E_VAR, optsvar, second->token);
|
---|
1752 | voidtoken();
|
---|
1753 | voidtoken();
|
---|
1754 | bootminix();
|
---|
1755 | b_unset(optsvar);
|
---|
1756 | return;
|
---|
1757 | } else
|
---|
1758 | /* boot device, ls dir, delay msec? */
|
---|
1759 | if (n == 2 && (res == R_BOOT || res == R_CTTY
|
---|
1760 | || res == R_DELAY || res == R_LS)
|
---|
1761 | ) {
|
---|
1762 | if (res == R_BOOT) boot_device(second->token);
|
---|
1763 | if (res == R_CTTY) ctty(second->token);
|
---|
1764 | if (res == R_DELAY) delay(second->token);
|
---|
1765 | if (res == R_LS) ls(second->token);
|
---|
1766 | voidtoken();
|
---|
1767 | voidtoken();
|
---|
1768 | return;
|
---|
1769 | } else
|
---|
1770 | /* trap msec command? */
|
---|
1771 | if (n == 3 && res == R_TRAP && numeric(second->token)) {
|
---|
1772 | long msec= a2l(second->token);
|
---|
1773 |
|
---|
1774 | voidtoken();
|
---|
1775 | voidtoken();
|
---|
1776 | schedule(msec, poptoken());
|
---|
1777 | return;
|
---|
1778 | } else
|
---|
1779 | /* Simple command. */
|
---|
1780 | if (n == 1) {
|
---|
1781 | char *body;
|
---|
1782 | int ok= 0;
|
---|
1783 |
|
---|
1784 | name= poptoken();
|
---|
1785 |
|
---|
1786 | switch (res) {
|
---|
1787 | case R_BOOT: bootminix(); ok= 1; break;
|
---|
1788 | case R_DELAY: delay("500"); ok= 1; break;
|
---|
1789 | case R_LS: ls(null); ok= 1; break;
|
---|
1790 | case R_MENU: menu(); ok= 1; break;
|
---|
1791 | case R_SAVE: save_parameters(); ok= 1;break;
|
---|
1792 | case R_SET: show_env(); ok= 1; break;
|
---|
1793 | case R_HELP: help(); ok= 1; break;
|
---|
1794 | case R_EXIT: exit(0);
|
---|
1795 | case R_OFF: off(); ok= 1; break;
|
---|
1796 | }
|
---|
1797 |
|
---|
1798 | /* Command to check bootparams: */
|
---|
1799 | if (strcmp(name, ":") == 0) ok= 1;
|
---|
1800 |
|
---|
1801 | /* User defined function. */
|
---|
1802 | if (!ok && (body= b_body(name)) != nil) {
|
---|
1803 | (void) tokenize(&cmds, body);
|
---|
1804 | ok= 1;
|
---|
1805 | }
|
---|
1806 | if (!ok) printf("%s: unknown function", name);
|
---|
1807 | free(name);
|
---|
1808 | if (ok) return;
|
---|
1809 | } else {
|
---|
1810 | /* Syntax error. */
|
---|
1811 | printf("Can't parse:");
|
---|
1812 | while (cmds != sep) {
|
---|
1813 | printf(" %s", cmds->token); voidtoken();
|
---|
1814 | }
|
---|
1815 | }
|
---|
1816 |
|
---|
1817 | /* Getting here means that the command is not understood. */
|
---|
1818 | printf("\nTry 'help'\n");
|
---|
1819 | err= 1;
|
---|
1820 | }
|
---|
1821 |
|
---|
1822 | int run_trailer(void)
|
---|
1823 | /* Run the trailer function between loading Minix and handing control to it.
|
---|
1824 | * Return true iff there was no error.
|
---|
1825 | */
|
---|
1826 | {
|
---|
1827 | token *save_cmds= cmds;
|
---|
1828 |
|
---|
1829 | cmds= nil;
|
---|
1830 | (void) tokenize(&cmds, "trailer");
|
---|
1831 | while (cmds != nil) execute();
|
---|
1832 | cmds= save_cmds;
|
---|
1833 | return !err;
|
---|
1834 | }
|
---|
1835 |
|
---|
1836 | void monitor(void)
|
---|
1837 | /* Read a line and tokenize it. */
|
---|
1838 | {
|
---|
1839 | char *line;
|
---|
1840 |
|
---|
1841 | unschedule(); /* Kill a trap. */
|
---|
1842 | err= 0; /* Clear error state. */
|
---|
1843 |
|
---|
1844 | if (istty) printf("%s>", bootdev.name);
|
---|
1845 | line= readline();
|
---|
1846 | (void) tokenize(&cmds, line);
|
---|
1847 | free(line);
|
---|
1848 | (void) escape(); /* Forget if ESC typed. */
|
---|
1849 | }
|
---|
1850 |
|
---|
1851 | #if BIOS
|
---|
1852 |
|
---|
1853 | unsigned char cdspec[25];
|
---|
1854 | void bootcdinfo(u32_t, int *, int drive);
|
---|
1855 |
|
---|
1856 | void boot(void)
|
---|
1857 | /* Load Minix and start it, among other things. */
|
---|
1858 | {
|
---|
1859 |
|
---|
1860 | /* Initialize tables. */
|
---|
1861 | initialize();
|
---|
1862 |
|
---|
1863 | /* Get environment variables from the parameter sector. */
|
---|
1864 | get_parameters();
|
---|
1865 |
|
---|
1866 | while (1) {
|
---|
1867 | /* While there are commands, execute them! */
|
---|
1868 |
|
---|
1869 | while (cmds != nil) execute();
|
---|
1870 |
|
---|
1871 | /* The "monitor" is just a "read one command" thing. */
|
---|
1872 | monitor();
|
---|
1873 | }
|
---|
1874 | }
|
---|
1875 | #endif /* BIOS */
|
---|
1876 |
|
---|
1877 | #if UNIX
|
---|
1878 |
|
---|
1879 | void main(int argc, char **argv)
|
---|
1880 | /* Do not load or start anything, just edit parameters. */
|
---|
1881 | {
|
---|
1882 | int i;
|
---|
1883 | char bootcode[SECTOR_SIZE];
|
---|
1884 | struct termios rawterm;
|
---|
1885 |
|
---|
1886 | istty= (argc <= 2 && tcgetattr(0, &termbuf) == 0);
|
---|
1887 |
|
---|
1888 | if (argc < 2) {
|
---|
1889 | fprintf(stderr, "Usage: edparams device [command ...]\n");
|
---|
1890 | exit(1);
|
---|
1891 | }
|
---|
1892 |
|
---|
1893 | /* Go over the arguments, changing control characters to spaces. */
|
---|
1894 | for (i= 2; i < argc; i++) {
|
---|
1895 | char *p;
|
---|
1896 |
|
---|
1897 | for (p= argv[i]; *p != 0; p++) {
|
---|
1898 | if ((unsigned) *p < ' ' && *p != '\n') *p= ' ';
|
---|
1899 | }
|
---|
1900 | }
|
---|
1901 |
|
---|
1902 | bootdev.name= argv[1];
|
---|
1903 | if (strncmp(bootdev.name, "/dev/", 5) == 0) bootdev.name+= 5;
|
---|
1904 | if ((bootdev.device= open(argv[1], O_RDWR, 0666)) < 0)
|
---|
1905 | fatal(bootdev.name);
|
---|
1906 |
|
---|
1907 | /* Check if it is a bootable Minix device. */
|
---|
1908 | if (readsectors(mon2abs(bootcode), lowsec, 1) != 0
|
---|
1909 | || memcmp(bootcode, boot_magic, sizeof(boot_magic)) != 0) {
|
---|
1910 | fprintf(stderr, "edparams: %s: not a bootable Minix device\n",
|
---|
1911 | bootdev.name);
|
---|
1912 | exit(1);
|
---|
1913 | }
|
---|
1914 |
|
---|
1915 | /* Print greeting message. */
|
---|
1916 | if (istty) printf("Boot parameters editor.\n");
|
---|
1917 |
|
---|
1918 | signal(SIGINT, trap);
|
---|
1919 | signal(SIGALRM, trap);
|
---|
1920 |
|
---|
1921 | if (istty) {
|
---|
1922 | rawterm= termbuf;
|
---|
1923 | rawterm.c_lflag&= ~(ICANON|ECHO|IEXTEN);
|
---|
1924 | rawterm.c_cc[VINTR]= ESC;
|
---|
1925 | if (tcsetattr(0, TCSANOW, &rawterm) < 0) fatal("");
|
---|
1926 | }
|
---|
1927 |
|
---|
1928 | /* Get environment variables from the parameter sector. */
|
---|
1929 | get_parameters();
|
---|
1930 |
|
---|
1931 | i= 2;
|
---|
1932 | for (;;) {
|
---|
1933 | /* While there are commands, execute them! */
|
---|
1934 | while (cmds != nil || i < argc) {
|
---|
1935 | if (cmds == nil) {
|
---|
1936 | /* A command line command. */
|
---|
1937 | parse_code(argv[i++]);
|
---|
1938 | }
|
---|
1939 | execute();
|
---|
1940 |
|
---|
1941 | /* Bail out on errors if not interactive. */
|
---|
1942 | if (err && !istty) exit(1);
|
---|
1943 | }
|
---|
1944 |
|
---|
1945 | /* Commands on the command line? */
|
---|
1946 | if (argc > 2) break;
|
---|
1947 |
|
---|
1948 | /* The "monitor" is just a "read one command" thing. */
|
---|
1949 | monitor();
|
---|
1950 | }
|
---|
1951 | exit(0);
|
---|
1952 | }
|
---|
1953 | #endif /* UNIX */
|
---|
1954 |
|
---|
1955 | /*
|
---|
1956 | * $PchId: boot.c,v 1.14 2002/02/27 19:46:14 philip Exp $
|
---|
1957 | */
|
---|