[9] | 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 | */
|
---|