00001
00002
00003
00004
00005 char version[]= "2.20";
00006
00007 #define BIOS (!UNIX)
00008
00009 #define nil 0
00010 #define _POSIX_SOURCE 1
00011 #define _MINIX 1
00012 #include <stddef.h>
00013 #include <sys/types.h>
00014 #include <sys/stat.h>
00015 #include <stdlib.h>
00016 #include <stdio.h>
00017 #include <limits.h>
00018 #include <string.h>
00019 #include <errno.h>
00020 #include <ibm/partition.h>
00021 #include <ibm/bios.h>
00022 #include <minix/config.h>
00023 #include <minix/type.h>
00024 #include <minix/dmap.h>
00025 #include <minix/const.h>
00026 #include <minix/minlib.h>
00027 #include <minix/syslib.h>
00028 #if BIOS
00029 #include <kernel/const.h>
00030 #include <sys/video.h>
00031 #endif
00032 #if UNIX
00033 #include <stdio.h>
00034 #include <time.h>
00035 #include <unistd.h>
00036 #include <fcntl.h>
00037 #include <signal.h>
00038 #include <termios.h>
00039 #endif
00040 #include "rawfs.h"
00041 #undef EXTERN
00042 #define EXTERN
00043 #include "boot.h"
00044
00045 #define arraysize(a) (sizeof(a) / sizeof((a)[0]))
00046 #define arraylimit(a) ((a) + arraysize(a))
00047 #define between(a, c, z) ((unsigned) ((c) - (a)) <= ((z) - (a)))
00048
00049 int serial_line = -1;
00050
00051 u16_t vid_port;
00052 u32_t vid_mem_base;
00053 u32_t vid_mem_size;
00054
00055 int fsok= -1;
00056
00057 static int block_size;
00058
00059 #if BIOS
00060
00061
00062
00063
00064
00065 unsigned char boot_spec[24];
00066
00067 char *bios_err(int err)
00068
00069
00070
00071
00072 {
00073 static struct errlist {
00074 int err;
00075 char *what;
00076 } errlist[] = {
00077 #if !DOS
00078 { 0x00, "No error" },
00079 { 0x01, "Invalid command" },
00080 { 0x02, "Address mark not found" },
00081 { 0x03, "Disk write-protected" },
00082 { 0x04, "Sector not found" },
00083 { 0x05, "Reset failed" },
00084 { 0x06, "Floppy disk removed" },
00085 { 0x07, "Bad parameter table" },
00086 { 0x08, "DMA overrun" },
00087 { 0x09, "DMA crossed 64 KB boundary" },
00088 { 0x0A, "Bad sector flag" },
00089 { 0x0B, "Bad track flag" },
00090 { 0x0C, "Media type not found" },
00091 { 0x0D, "Invalid number of sectors on format" },
00092 { 0x0E, "Control data address mark detected" },
00093 { 0x0F, "DMA arbitration level out of range" },
00094 { 0x10, "Uncorrectable CRC or ECC data error" },
00095 { 0x11, "ECC corrected data error" },
00096 { 0x20, "Controller failed" },
00097 { 0x40, "Seek failed" },
00098 { 0x80, "Disk timed-out" },
00099 { 0xAA, "Drive not ready" },
00100 { 0xBB, "Undefined error" },
00101 { 0xCC, "Write fault" },
00102 { 0xE0, "Status register error" },
00103 { 0xFF, "Sense operation failed" }
00104 #else
00105 { 0x00, "No error" },
00106 { 0x01, "Function number invalid" },
00107 { 0x02, "File not found" },
00108 { 0x03, "Path not found" },
00109 { 0x04, "Too many open files" },
00110 { 0x05, "Access denied" },
00111 { 0x06, "Invalid handle" },
00112 { 0x0C, "Access code invalid" },
00113 #endif
00114 };
00115 struct errlist *errp;
00116
00117 for (errp= errlist; errp < arraylimit(errlist); errp++) {
00118 if (errp->err == err) return errp->what;
00119 }
00120 return "Unknown error";
00121 }
00122
00123
00124
00125
00126
00127
00128 int readsectors(u32_t bufaddr, u32_t sector, U8_t count)
00129 {
00130 #define CDSECTOR_SIZE 2048
00131 static char cdbuf[CDSECTOR_SIZE];
00132 static i32_t cdbuf_sec = -1;
00133 i32_t cdsec;
00134
00135 if(device != cddevice) {
00136 return biosreadsectors(bufaddr, sector, count);
00137 }
00138
00139 while(count > 0) {
00140 u32_t offset;
00141 #define FACTOR (CDSECTOR_SIZE/SECTOR_SIZE)
00142 cdsec = sector / FACTOR;
00143 offset = (sector % FACTOR) * SECTOR_SIZE;
00144 if(cdsec != cdbuf_sec) {
00145 int r;
00146 if((r=biosreadsectors(mon2abs(cdbuf), cdsec, 1)) != 0) {
00147 printf("error %d\n", r);
00148 return r;
00149 }
00150 cdbuf_sec = cdsec;
00151 }
00152 raw_copy(bufaddr, mon2abs(cdbuf) + offset, SECTOR_SIZE);
00153 bufaddr += SECTOR_SIZE;
00154 count--;
00155 sector++;
00156 }
00157
00158 return 0;
00159 }
00160
00161 char *unix_err(int err)
00162
00163 {
00164 switch (err) {
00165 case ENOENT: return "No such file or directory";
00166 case ENOTDIR: return "Not a directory";
00167 default: return "Unknown error";
00168 }
00169 }
00170
00171 void rwerr(char *rw, off_t sec, int err)
00172 {
00173 printf("\n%s error 0x%02x (%s) at sector %ld absolute\n",
00174 rw, err, bios_err(err), sec);
00175 }
00176
00177 void readerr(off_t sec, int err) { rwerr("Read", sec, err); }
00178 void writerr(off_t sec, int err) { rwerr("Write", sec, err); }
00179
00180 void readblock(off_t blk, char *buf, int block_size)
00181
00182 {
00183 int r;
00184 u32_t sec= lowsec + blk * RATIO(block_size);
00185
00186 if(!block_size) {
00187 printf("block_size 0\n");
00188 exit(1);
00189 }
00190
00191 if ((r= readsectors(mon2abs(buf), sec, 1 * RATIO(block_size))) != 0) {
00192 readerr(sec, r); exit(1);
00193 }
00194 }
00195
00196 #define istty (1)
00197 #define alarm(n) (0)
00198
00199 #endif
00200
00201 #if UNIX
00202
00203
00204 char boot_magic[] = { 0x31, 0xC0, 0x8E, 0xD8, 0xFA, 0x8E, 0xD0, 0xBC };
00205
00206 struct biosdev {
00207 char *name;
00208 int device;
00209 } bootdev;
00210
00211 struct termios termbuf;
00212 int istty;
00213
00214 void quit(int status)
00215 {
00216 if (istty) (void) tcsetattr(0, TCSANOW, &termbuf);
00217 exit(status);
00218 }
00219
00220 #define exit(s) quit(s)
00221
00222 void report(char *label)
00223
00224 {
00225 fprintf(stderr, "edparams: %s: %s\n", label, strerror(errno));
00226 }
00227
00228 void fatal(char *label)
00229 {
00230 report(label);
00231 exit(1);
00232 }
00233
00234 void *alloc(void *m, size_t n)
00235 {
00236 m= m == nil ? malloc(n) : realloc(m, n);
00237 if (m == nil) fatal("");
00238 return m;
00239 }
00240
00241 #define malloc(n) alloc(nil, n)
00242 #define realloc(m, n) alloc(m, n)
00243
00244 #define mon2abs(addr) ((void *) (addr))
00245
00246 int rwsectors(int rw, void *addr, u32_t sec, int nsec)
00247 {
00248 ssize_t r;
00249 size_t len= nsec * SECTOR_SIZE;
00250
00251 if (lseek(bootdev.device, sec * SECTOR_SIZE, SEEK_SET) == -1)
00252 return errno;
00253
00254 if (rw == 0) {
00255 r= read(bootdev.device, (char *) addr, len);
00256 } else {
00257 r= write(bootdev.device, (char *) addr, len);
00258 }
00259 if (r == -1) return errno;
00260 if (r != len) return EIO;
00261 return 0;
00262 }
00263
00264 #define readsectors(a, s, n) rwsectors(0, (a), (s), (n))
00265 #define writesectors(a, s, n) rwsectors(1, (a), (s), (n))
00266 #define readerr(sec, err) (errno= (err), report(bootdev.name))
00267 #define writerr(sec, err) (errno= (err), report(bootdev.name))
00268 #define putch(c) putchar(c)
00269 #define unix_err(err) strerror(err)
00270
00271 void readblock(off_t blk, char *buf, int block_size)
00272
00273 {
00274 if(!block_size) fatal("block_size 0");
00275 errno= EIO;
00276 if (lseek(bootdev.device, blk * block_size, SEEK_SET) == -1
00277 || read(bootdev.device, buf, block_size) != block_size)
00278 {
00279 fatal(bootdev.name);
00280 }
00281 }
00282
00283 sig_atomic_t trapsig;
00284
00285 void trap(int sig)
00286 {
00287 trapsig= sig;
00288 signal(sig, trap);
00289 }
00290
00291 int escape(void)
00292 {
00293 if (trapsig == SIGINT) {
00294 trapsig= 0;
00295 return 1;
00296 }
00297 return 0;
00298 }
00299
00300 static unsigned char unchar;
00301
00302 int getch(void)
00303 {
00304 unsigned char c;
00305
00306 fflush(stdout);
00307
00308 if (unchar != 0) {
00309 c= unchar;
00310 unchar= 0;
00311 return c;
00312 }
00313
00314 switch (read(0, &c, 1)) {
00315 case -1:
00316 if (errno != EINTR) fatal("");
00317 return(ESC);
00318 case 0:
00319 if (istty) putch('\n');
00320 exit(0);
00321 default:
00322 if (istty && c == termbuf.c_cc[VEOF]) {
00323 putch('\n');
00324 exit(0);
00325 }
00326 return c;
00327 }
00328 }
00329
00330 #define ungetch(c) ((void) (unchar = (c)))
00331
00332 #define get_tick() ((u32_t) time(nil))
00333 #define clear_screen() printf("[clear]")
00334 #define boot_device(device) printf("[boot %s]\n", device)
00335 #define ctty(line) printf("[ctty %s]\n", line)
00336 #define bootminix() (run_trailer() && printf("[boot]\n"))
00337 #define off() printf("[off]")
00338
00339 #endif
00340
00341 char *readline(void)
00342
00343 {
00344 char *line;
00345 size_t i, z;
00346 int c;
00347
00348 i= 0;
00349 z= 20;
00350 line= malloc(z * sizeof(char));
00351
00352 do {
00353 c= getch();
00354
00355 if (strchr("\b\177\25\30", c) != nil) {
00356
00357 do {
00358 if (i == 0) break;
00359 printf("\b \b");
00360 i--;
00361 } while (c == '\25' || c == '\30');
00362 } else
00363 if (c < ' ' && c != '\n') {
00364 putch('\7');
00365 } else {
00366 putch(c);
00367 line[i++]= c;
00368 if (i == z) {
00369 z*= 2;
00370 line= realloc(line, z * sizeof(char));
00371 }
00372 }
00373 } while (c != '\n');
00374 line[i]= 0;
00375 return line;
00376 }
00377
00378 int sugar(char *tok)
00379
00380 {
00381 return strchr("=(){};\n", tok[0]) != nil;
00382 }
00383
00384 char *onetoken(char **aline)
00385
00386 {
00387 char *line= *aline;
00388 size_t n;
00389 char *tok;
00390
00391
00392 while (*line == ' ' || (*line == '\n' && line[1] == '\n')) line++;
00393
00394 *aline= line;
00395
00396
00397 if ((unsigned) *line < ' ' && *line != '\n') return nil;
00398
00399 if (*line == '(') {
00400
00401 int depth= 0;
00402
00403 while ((unsigned) *line >= ' ') {
00404 if (*line == '(') depth++;
00405 if (*line++ == ')' && --depth == 0) break;
00406 }
00407 } else
00408 if (sugar(line)) {
00409
00410 line++;
00411 } else {
00412
00413 do line++; while ((unsigned) *line > ' ' && !sugar(line));
00414 }
00415 n= line - *aline;
00416 tok= malloc((n + 1) * sizeof(char));
00417 memcpy(tok, *aline, n);
00418 tok[n]= 0;
00419 if (tok[0] == '\n') tok[0]= ';';
00420
00421 *aline= line;
00422 return tok;
00423 }
00424
00425
00426
00427 typedef struct token {
00428 struct token *next;
00429 char *token;
00430 } token;
00431
00432 token **tokenize(token **acmds, char *line)
00433
00434
00435
00436
00437
00438
00439 {
00440 char *tok;
00441 token *newcmd;
00442
00443 while ((tok= onetoken(&line)) != nil) {
00444 newcmd= malloc(sizeof(*newcmd));
00445 newcmd->token= tok;
00446 newcmd->next= *acmds;
00447 *acmds= newcmd;
00448 acmds= &newcmd->next;
00449 }
00450 return acmds;
00451 }
00452
00453 token *cmds;
00454 int err;
00455
00456 char *poptoken(void)
00457
00458 {
00459 token *cmd= cmds;
00460 char *tok= cmd->token;
00461
00462 cmds= cmd->next;
00463 free(cmd);
00464
00465 return tok;
00466 }
00467
00468 void voidtoken(void)
00469
00470 {
00471 free(poptoken());
00472 }
00473
00474 void parse_code(char *code)
00475
00476
00477
00478 {
00479 if (cmds != nil && cmds->token[0] != ';') (void) tokenize(&cmds, ";");
00480 (void) tokenize(&cmds, code);
00481 }
00482
00483 int interrupt(void)
00484
00485 {
00486 if (escape()) {
00487 printf("[ESC]\n");
00488 err= 1;
00489 return 1;
00490 }
00491 return 0;
00492 }
00493
00494 #if BIOS
00495
00496 int activate;
00497
00498 struct biosdev {
00499 char name[8];
00500 int device, primary, secondary;
00501 } bootdev, tmpdev;
00502
00503 int get_master(char *master, struct part_entry **table, u32_t pos)
00504
00505 {
00506 int r, n;
00507 struct part_entry *pe, **pt;
00508
00509 if ((r= readsectors(mon2abs(master), pos, 1)) != 0) return r;
00510
00511 pe= (struct part_entry *) (master + PART_TABLE_OFF);
00512 for (pt= table; pt < table + NR_PARTITIONS; pt++) *pt= pe++;
00513
00514
00515 if (pos != 0) return 0;
00516
00517 n= NR_PARTITIONS;
00518 do {
00519 for (pt= table; pt < table + NR_PARTITIONS-1; pt++) {
00520 if (pt[0]->sysind == NO_PART
00521 || pt[0]->lowsec > pt[1]->lowsec) {
00522 pe= pt[0]; pt[0]= pt[1]; pt[1]= pe;
00523 }
00524 }
00525 } while (--n > 0);
00526 return 0;
00527 }
00528
00529 void initialize(void)
00530 {
00531 char master[SECTOR_SIZE];
00532 struct part_entry *table[NR_PARTITIONS];
00533 int r, p;
00534 u32_t masterpos;
00535 char *argp;
00536
00537
00538
00539
00540
00541 u32_t oldaddr= caddr;
00542 u32_t memend= mem[0].base + mem[0].size;
00543 u32_t newaddr= (memend - runsize) & ~0x0000FL;
00544 #if !DOS
00545 u32_t dma64k= (memend - 1) & ~0x0FFFFL;
00546
00547
00548
00549 if (newaddr + (daddr - caddr) < dma64k) {
00550 newaddr= (dma64k - runsize) & ~0x0000FL;
00551 }
00552 #endif
00553
00554
00555 if(cdbooted)
00556 cddevice = device;
00557 else
00558 cddevice = 0xff;
00559
00560
00561 caddr= newaddr;
00562
00563
00564 raw_copy(newaddr, oldaddr, runsize);
00565
00566
00567 relocate();
00568
00569 #if !DOS
00570
00571
00572
00573
00574
00575 if (mon_return = (mem[1].size > 512*1024L)) mem[0].size = newaddr;
00576 mem[0].base += 2048;
00577 mem[0].size -= 2048;
00578
00579
00580 bootdev.name[0]= 0;
00581 bootdev.device= device;
00582 bootdev.primary= -1;
00583 bootdev.secondary= -1;
00584
00585 if (device < 0x80) {
00586
00587 strcpy(bootdev.name, "fd0");
00588 bootdev.name[2] += bootdev.device;
00589 return;
00590 }
00591
00592
00593
00594
00595
00596
00597 raw_copy(mon2abs(&lowsec),
00598 vec2abs(&rem_part) + offsetof(struct part_entry, lowsec),
00599 sizeof(lowsec));
00600
00601 masterpos= 0;
00602
00603 for (;;) {
00604
00605 if ((r= get_master(master, table, masterpos)) != 0) {
00606 readerr(masterpos, r); exit(1);
00607 }
00608
00609
00610 if(device == cddevice) {
00611 p = 1;
00612 lowsec = table[p]->lowsec;
00613 bootdev.primary = p;
00614 break;
00615 }
00616
00617
00618 for (p= 0; p < NR_PARTITIONS; p++) {
00619 if (lowsec - table[p]->lowsec < table[p]->size) break;
00620 }
00621
00622 if (lowsec == table[p]->lowsec) {
00623 if (bootdev.primary < 0)
00624 bootdev.primary= p;
00625 else
00626 bootdev.secondary= p;
00627 break;
00628 }
00629
00630 if (p == NR_PARTITIONS || bootdev.primary >= 0
00631 || table[p]->sysind != MINIX_PART) {
00632
00633
00634
00635 bootdev.device= -1;
00636 return;
00637 }
00638
00639
00640 bootdev.primary= p;
00641 masterpos= table[p]->lowsec;
00642 }
00643
00644 if(device == cddevice) {
00645 strcpy(bootdev.name, CDNAME);
00646 } else {
00647 strcpy(bootdev.name, "d0p0");
00648 bootdev.name[1] += (device - 0x80);
00649 bootdev.name[3] += bootdev.primary;
00650 if (bootdev.secondary >= 0) {
00651 strcat(bootdev.name, "s0");
00652 bootdev.name[5] += bootdev.secondary;
00653 }
00654 }
00655
00656
00657 raw_copy(mon2abs(&vid_port), VDU_CRT_BASE_ADDR, sizeof(vid_port));
00658 if(vid_port == C_6845) {
00659 vid_mem_base = COLOR_BASE;
00660 vid_mem_size = COLOR_SIZE;
00661 } else {
00662 vid_mem_base = MONO_BASE;
00663 vid_mem_size = MONO_SIZE;
00664 }
00665
00666 if(get_video() >= 3)
00667 vid_mem_size = EGA_SIZE;
00668
00669 #else
00670
00671
00672
00673
00674 if (mem[1].size > 0) mem[0].size = newaddr + 0x80 - mem[0].base;
00675
00676
00677 argp= PSP + 0x81;
00678 argp[PSP[0x80]]= 0;
00679 while (between('\1', *argp, ' ')) argp++;
00680 vdisk= argp;
00681 while (!between('\0', *argp, ' ')) argp++;
00682 while (between('\1', *argp, ' ')) *argp++= 0;
00683 if (*vdisk == 0) {
00684 printf("\nUsage: boot <vdisk> [commands ...]\n");
00685 exit(1);
00686 }
00687 drun= *argp == 0 ? "main" : argp;
00688
00689 if ((r= dev_open()) != 0) {
00690 printf("\n%s: Error %02x (%s)\n", vdisk, r, bios_err(r));
00691 exit(1);
00692 }
00693
00694
00695 if ((r= get_master(master, table, 0)) != 0) {
00696 readerr(0, r); exit(1);
00697 }
00698
00699 strcpy(bootdev.name, "d0");
00700 bootdev.primary= -1;
00701 for (p= 0; p < NR_PARTITIONS; p++) {
00702 if (table[p]->bootind != 0 && table[p]->sysind == MINIX_PART) {
00703 bootdev.primary= p;
00704 strcat(bootdev.name, "p0");
00705 bootdev.name[3] += p;
00706 lowsec= table[p]->lowsec;
00707 break;
00708 }
00709 }
00710 #endif
00711 }
00712
00713 #endif
00714
00715
00716 enum resnames {
00717 R_NULL, R_BOOT, R_CTTY, R_DELAY, R_ECHO, R_EXIT, R_HELP,
00718 R_LS, R_MENU, R_OFF, R_SAVE, R_SET, R_TRAP, R_UNSET
00719 };
00720
00721 char resnames[][6] = {
00722 "", "boot", "ctty", "delay", "echo", "exit", "help",
00723 "ls", "menu", "off", "save", "set", "trap", "unset",
00724 };
00725
00726
00727 #define null (resnames[0])
00728
00729 int reserved(char *s)
00730
00731 {
00732 int r;
00733
00734 for (r= R_BOOT; r <= R_UNSET; r++) {
00735 if (strcmp(s, resnames[r]) == 0) return r;
00736 }
00737 return R_NULL;
00738 }
00739
00740 void sfree(char *s)
00741
00742 {
00743 if (s != nil && s != null) free(s);
00744 }
00745
00746 char *copystr(char *s)
00747
00748 {
00749 char *c;
00750
00751 if (*s == 0) return null;
00752 c= malloc((strlen(s) + 1) * sizeof(char));
00753 strcpy(c, s);
00754 return c;
00755 }
00756
00757 int is_default(environment *e)
00758 {
00759 return (e->flags & E_SPECIAL) && e->defval == nil;
00760 }
00761
00762 environment **searchenv(char *name)
00763 {
00764 environment **aenv= &env;
00765
00766 while (*aenv != nil && strcmp((*aenv)->name, name) != 0) {
00767 aenv= &(*aenv)->next;
00768 }
00769
00770 return aenv;
00771 }
00772
00773 #define b_getenv(name) (*searchenv(name))
00774
00775
00776 char *b_value(char *name)
00777
00778 {
00779 environment *e= b_getenv(name);
00780
00781 return e == nil || !(e->flags & E_VAR) ? nil : e->value;
00782 }
00783
00784 char *b_body(char *name)
00785
00786 {
00787 environment *e= b_getenv(name);
00788
00789 return e == nil || !(e->flags & E_FUNCTION) ? nil : e->value;
00790 }
00791
00792 int b_setenv(int flags, char *name, char *arg, char *value)
00793
00794
00795
00796 {
00797 environment **aenv, *e;
00798
00799 if (*(aenv= searchenv(name)) == nil) {
00800 if (reserved(name)) return E_RESERVED;
00801 e= malloc(sizeof(*e));
00802 e->name= copystr(name);
00803 e->flags= flags;
00804 e->defval= nil;
00805 e->next= nil;
00806 *aenv= e;
00807 } else {
00808 e= *aenv;
00809
00810
00811 if (e->flags & E_SPECIAL
00812 && (e->flags & E_FUNCTION) != (flags & E_FUNCTION)
00813 ) return e->flags;
00814
00815 e->flags= (e->flags & E_STICKY) | flags;
00816 if (is_default(e)) {
00817 e->defval= e->value;
00818 } else {
00819 sfree(e->value);
00820 }
00821 sfree(e->arg);
00822 }
00823 e->arg= copystr(arg);
00824 e->value= copystr(value);
00825
00826 return 0;
00827 }
00828
00829 int b_setvar(int flags, char *name, char *value)
00830
00831 {
00832 int r;
00833
00834 if((r=b_setenv(flags, name, null, value))) {
00835 return r;
00836 }
00837
00838 return r;
00839 }
00840
00841 void b_unset(char *name)
00842
00843
00844
00845 {
00846 environment **aenv, *e;
00847
00848 if ((e= *(aenv= searchenv(name))) == nil) return;
00849
00850 if (e->flags & E_SPECIAL) {
00851 if (e->defval != nil) {
00852 sfree(e->arg);
00853 e->arg= null;
00854 sfree(e->value);
00855 e->value= e->defval;
00856 e->defval= nil;
00857 }
00858 } else {
00859 sfree(e->name);
00860 sfree(e->arg);
00861 sfree(e->value);
00862 *aenv= e->next;
00863 free(e);
00864 }
00865 }
00866
00867 long a2l(char *a)
00868
00869 {
00870 int sign= 1;
00871 long n= 0;
00872
00873 if (*a == '-') { sign= -1; a++; }
00874
00875 while (between('0', *a, '9')) n= n * 10 + (*a++ - '0');
00876
00877 return sign * n;
00878 }
00879
00880 char *ul2a(u32_t n, unsigned b)
00881
00882 {
00883 static char num[(CHAR_BIT * sizeof(n) + 2) / 3 + 1];
00884 char *a= arraylimit(num) - 1;
00885 static char hex[16] = "0123456789ABCDEF";
00886
00887 do *--a = hex[(int) (n % b)]; while ((n/= b) > 0);
00888 return a;
00889 }
00890
00891 char *ul2a10(u32_t n)
00892
00893 {
00894 return ul2a(n, 10);
00895 }
00896
00897 unsigned a2x(char *a)
00898
00899 {
00900 unsigned n= 0;
00901 int c;
00902
00903 for (;;) {
00904 c= *a;
00905 if (between('0', c, '9')) c= c - '0' + 0x0;
00906 else
00907 if (between('A', c, 'F')) c= c - 'A' + 0xA;
00908 else
00909 if (between('a', c, 'f')) c= c - 'a' + 0xa;
00910 else
00911 break;
00912 n= (n<<4) | c;
00913 a++;
00914 }
00915 return n;
00916 }
00917
00918 void get_parameters(void)
00919 {
00920 char params[SECTOR_SIZE + 1];
00921 token **acmds;
00922 int r, bus, processor;
00923 memory *mp;
00924 static char bus_type[][4] = {
00925 "xt", "at", "mca"
00926 };
00927 static char vid_type[][4] = {
00928 "mda", "cga", "ega", "ega", "vga", "vga"
00929 };
00930 static char vid_chrome[][6] = {
00931 "mono", "color"
00932 };
00933
00934
00935 b_setvar(E_SPECIAL|E_VAR|E_DEV, "rootdev", "ram");
00936 b_setvar(E_SPECIAL|E_VAR|E_DEV, "ramimagedev", "bootdev");
00937 b_setvar(E_SPECIAL|E_VAR, "ramsize", "0");
00938 #define STRINGIT2(x) #x
00939 #define STRINGIT1(x) STRINGIT2(x)
00940 b_setvar(E_SPECIAL|E_VAR, "hz", STRINGIT1(DEFAULT_HZ));
00941 #if BIOS
00942 processor = getprocessor();
00943 if(processor == 1586) processor = 686;
00944 b_setvar(E_SPECIAL|E_VAR, "processor", ul2a10(processor));
00945 b_setvar(E_SPECIAL|E_VAR, "bus", bus_type[get_bus()]);
00946 b_setvar(E_SPECIAL|E_VAR, "video", vid_type[get_video()]);
00947 b_setvar(E_SPECIAL|E_VAR, "chrome", vid_chrome[get_video() & 1]);
00948 params[0]= 0;
00949 for (mp= mem; mp < arraylimit(mem); mp++) {
00950 if (mp->size == 0) continue;
00951 if (params[0] != 0) strcat(params, ",");
00952 strcat(params, ul2a(mp->base, 0x10));
00953 strcat(params, ":");
00954 strcat(params, ul2a(mp->size, 0x10));
00955 }
00956 b_setvar(E_SPECIAL|E_VAR, "memory", params);
00957
00958 #if DOS
00959 b_setvar(E_SPECIAL|E_VAR, "dosfile-d0", vdisk);
00960 #endif
00961
00962 #endif
00963 #if UNIX
00964 b_setvar(E_SPECIAL|E_VAR, "processor", "?");
00965 b_setvar(E_SPECIAL|E_VAR, "bus", "?");
00966 b_setvar(E_SPECIAL|E_VAR, "video", "?");
00967 b_setvar(E_SPECIAL|E_VAR, "chrome", "?");
00968 b_setvar(E_SPECIAL|E_VAR, "memory", "?");
00969 b_setvar(E_SPECIAL|E_VAR, "c0", "?");
00970 #endif
00971
00972
00973 b_setvar(E_SPECIAL|E_VAR, "image", "boot/image");
00974 b_setvar(E_SPECIAL|E_FUNCTION, "leader",
00975 "echo --- Welcome to MINIX 3. This is the boot monitor. ---\\n");
00976 b_setvar(E_SPECIAL|E_FUNCTION, "main", "menu");
00977 b_setvar(E_SPECIAL|E_FUNCTION, "trailer", "");
00978
00979
00980 b_setenv(E_RESERVED|E_FUNCTION, null, "=,Start MINIX", "boot");
00981
00982
00983 if ((r= readsectors(mon2abs(params), lowsec+PARAMSEC, 1)) != 0) {
00984 readerr(lowsec+PARAMSEC, r);
00985 exit(1);
00986 }
00987 params[SECTOR_SIZE]= 0;
00988 acmds= tokenize(&cmds, params);
00989
00990
00991 #if UNIX
00992 (void) tokenize(acmds, ":;");
00993 #elif DOS
00994 (void) tokenize(tokenize(acmds, ":;leader;"), drun);
00995 #else
00996 (void) tokenize(acmds, ":;leader;main");
00997 #endif
00998 }
00999
01000 char *addptr;
01001
01002 void addparm(char *n)
01003 {
01004 while (*n != 0 && *addptr != 0) *addptr++ = *n++;
01005 }
01006
01007 void save_parameters(void)
01008
01009 {
01010 environment *e;
01011 char params[SECTOR_SIZE + 1];
01012 int r;
01013
01014
01015 memset(params, '\n', SECTOR_SIZE);
01016
01017
01018 params[SECTOR_SIZE]= 0;
01019 addptr= params;
01020
01021 for (e= env; e != nil; e= e->next) {
01022 if (e->flags & E_RESERVED || is_default(e)) continue;
01023
01024 addparm(e->name);
01025 if (e->flags & E_FUNCTION) {
01026 addparm("(");
01027 addparm(e->arg);
01028 addparm(")");
01029 } else {
01030 addparm((e->flags & (E_DEV|E_SPECIAL)) != E_DEV
01031 ? "=" : "=d ");
01032 }
01033 addparm(e->value);
01034 if (*addptr == 0) {
01035 printf("The environment is too big\n");
01036 return;
01037 }
01038 *addptr++= '\n';
01039 }
01040
01041
01042 if ((r= writesectors(mon2abs(params), lowsec+PARAMSEC, 1)) != 0) {
01043 writerr(lowsec+PARAMSEC, r);
01044 printf("Can't save environment\n");
01045 }
01046 }
01047
01048 void show_env(void)
01049
01050 {
01051 environment *e;
01052 unsigned more= 0;
01053 int c;
01054
01055 for (e= env; e != nil; e= e->next) {
01056 if (e->flags & E_RESERVED) continue;
01057 if (!istty && is_default(e)) continue;
01058
01059 if (e->flags & E_FUNCTION) {
01060 printf("%s(%s) %s\n", e->name, e->arg, e->value);
01061 } else {
01062 printf(is_default(e) ? "%s = (%s)\n" : "%s = %s\n",
01063 e->name, e->value);
01064 }
01065
01066 if (e->next != nil && istty && ++more % 20 == 0) {
01067 printf("More? ");
01068 c= getch();
01069 if (c == ESC || c > ' ') {
01070 putch('\n');
01071 if (c > ' ') ungetch(c);
01072 break;
01073 }
01074 printf("\b\b\b\b\b\b");
01075 }
01076 }
01077 }
01078
01079 int numprefix(char *s, char **ps)
01080
01081
01082
01083 {
01084 char *n= s;
01085
01086 while (between('0', *n, '9')) n++;
01087
01088 if (n == s) return 0;
01089
01090 if (ps == nil) return *n == 0;
01091
01092 *ps= n;
01093 return 1;
01094 }
01095
01096 int numeric(char *s)
01097 {
01098 return numprefix(s, (char **) nil);
01099 }
01100
01101 #if BIOS
01102
01103
01104 #define DEV_FD0 0x0200
01105 static dev_t dev_cNd0[] = { 0x0300, 0x0800, 0x0A00, 0x0C00, 0x1000 };
01106 #define minor_p0s0 128
01107
01108 static int block_size;
01109
01110 dev_t name2dev(char *name)
01111
01112
01113
01114
01115
01116 {
01117 dev_t dev;
01118 ino_t ino;
01119 int drive;
01120 struct stat st;
01121 char *n, *s;
01122
01123
01124 if ((activate= (name[0] == '*'))) name++;
01125
01126
01127 if (strcmp(name, "bootdev") == 0) {
01128 if (bootdev.device == -1) {
01129 printf("The boot device could not be named\n");
01130 errno= 0;
01131 return -1;
01132 }
01133 name= bootdev.name;
01134 }
01135
01136
01137
01138
01139
01140 tmpdev.device= tmpdev.primary= tmpdev.secondary= -1;
01141 dev= -1;
01142 n= name;
01143 if (strncmp(n, "/dev/", 5) == 0) n+= 5;
01144
01145 if (strcmp(n, "ram") == 0 || strcmp(n, CDNAME) == 0) {
01146 dev= DEV_RAM;
01147 } else
01148 if (n[0] == 'f' && n[1] == 'd' && numeric(n+2)) {
01149
01150 tmpdev.device= a2l(n+2);
01151 dev= DEV_FD0 + tmpdev.device;
01152 } else
01153 if ((n[0] == 'h' || n[0] == 's') && n[1] == 'd' && numprefix(n+2, &s)
01154 && (*s == 0 || (between('a', *s, 'd') && s[1] == 0))
01155 ) {
01156
01157 dev= a2l(n+2);
01158 tmpdev.device= dev / (1 + NR_PARTITIONS);
01159 tmpdev.primary= (dev % (1 + NR_PARTITIONS)) - 1;
01160 if (*s != 0) {
01161
01162 tmpdev.secondary= *s - 'a';
01163 dev= minor_p0s0
01164 + (tmpdev.device * NR_PARTITIONS
01165 + tmpdev.primary) * NR_PARTITIONS
01166 + tmpdev.secondary;
01167 }
01168 tmpdev.device+= 0x80;
01169 dev+= n[0] == 'h' ? dev_cNd0[0] : dev_cNd0[2];
01170 } else {
01171
01172 int ctrlr= 0;
01173
01174 if (n[0] == 'c' && between('0', n[1], '4')) {
01175 ctrlr= (n[1] - '0');
01176 tmpdev.device= 0;
01177 n+= 2;
01178 }
01179 if (n[0] == 'd' && between('0', n[1], '7')) {
01180 tmpdev.device= (n[1] - '0');
01181 n+= 2;
01182 if (n[0] == 'p' && between('0', n[1], '3')) {
01183 tmpdev.primary= (n[1] - '0');
01184 n+= 2;
01185 if (n[0] == 's' && between('0', n[1], '3')) {
01186 tmpdev.secondary= (n[1] - '0');
01187 n+= 2;
01188 }
01189 }
01190 }
01191 if (*n == 0) {
01192 dev= dev_cNd0[ctrlr];
01193 if (tmpdev.secondary < 0) {
01194 dev += tmpdev.device * (NR_PARTITIONS+1)
01195 + (tmpdev.primary + 1);
01196 } else {
01197 dev += minor_p0s0
01198 + (tmpdev.device * NR_PARTITIONS
01199 + tmpdev.primary) * NR_PARTITIONS
01200 + tmpdev.secondary;
01201 }
01202 tmpdev.device+= 0x80;
01203 }
01204 }
01205
01206
01207 if (fsok == -1) fsok= r_super(&block_size) != 0;
01208 if (fsok) {
01209
01210 ino= r_lookup(r_lookup(ROOT_INO, "dev"), name);
01211
01212 if (ino != 0) {
01213
01214 r_stat(ino, &st);
01215 if (!S_ISBLK(st.st_mode)) {
01216 printf("%s is not a block device\n", name);
01217 errno= 0;
01218 return (dev_t) -1;
01219 }
01220 dev= st.st_rdev;
01221 }
01222 }
01223
01224 if (tmpdev.primary < 0) activate= 0;
01225
01226 if (dev == -1) {
01227 printf("Can't recognize '%s' as a device\n", name);
01228 errno= 0;
01229 }
01230 return dev;
01231 }
01232
01233 #if DEBUG
01234 static void apm_perror(char *label, u16_t ax)
01235 {
01236 unsigned ah;
01237 char *str;
01238
01239 ah= (ax >> 8);
01240 switch(ah)
01241 {
01242 case 0x01: str= "APM functionality disabled"; break;
01243 case 0x03: str= "interface not connected"; break;
01244 case 0x09: str= "unrecognized device ID"; break;
01245 case 0x0A: str= "parameter value out of range"; break;
01246 case 0x0B: str= "interface not engaged"; break;
01247 case 0x60: str= "unable to enter requested state"; break;
01248 case 0x86: str= "APM not present"; break;
01249 default: printf("%s: error 0x%02x\n", label, ah); return;
01250 }
01251 printf("%s: %s\n", label, str);
01252 }
01253
01254 #define apm_printf printf
01255 #else
01256 #define apm_perror(label, ax) ((void)0)
01257 #define apm_printf
01258 #endif
01259
01260 static void off(void)
01261 {
01262 bios_env_t be;
01263 unsigned al, ah;
01264
01265
01266
01267
01268
01269 be.ax= 0x5300;
01270 be.bx= 0;
01271 int15(&be);
01272 if (be.flags & FL_CARRY)
01273 {
01274 apm_perror("APM installation check failed", be.ax);
01275 return;
01276 }
01277 if (be.bx != (('P' << 8) | 'M'))
01278 {
01279 apm_printf("APM signature not found (got 0x%04x)\n", be.bx);
01280 return;
01281 }
01282
01283 ah= be.ax >> 8;
01284 if (ah > 9)
01285 ah= (ah >> 4)*10 + (ah & 0xf);
01286 al= be.ax & 0xff;
01287 if (al > 9)
01288 al= (al >> 4)*10 + (al & 0xf);
01289 apm_printf("APM version %u.%u%s%s%s%s%s\n",
01290 ah, al,
01291 (be.cx & 0x1) ? ", 16-bit PM" : "",
01292 (be.cx & 0x2) ? ", 32-bit PM" : "",
01293 (be.cx & 0x4) ? ", CPU-Idle" : "",
01294 (be.cx & 0x8) ? ", APM-disabled" : "",
01295 (be.cx & 0x10) ? ", APM-disengaged" : "");
01296
01297
01298 be.ax= 0x5301;
01299 be.bx= 0x0000;
01300 int15(&be);
01301 if (be.flags & FL_CARRY)
01302 {
01303 apm_perror("APM real mode connect failed", be.ax);
01304 return;
01305 }
01306
01307
01308 be.ax= 0x530e;
01309 be.bx= 0x0000;
01310 be.cx= 0x0102;
01311 int15(&be);
01312 if (be.flags & FL_CARRY)
01313 {
01314 apm_perror("Set driver version failed", be.ax);
01315 goto disco;
01316 }
01317
01318
01319
01320
01321 ah= be.ax >> 8;
01322 if (ah > 9)
01323 ah= (ah >> 4)*10 + (ah & 0xf);
01324 al= be.ax & 0xff;
01325 if (al > 9)
01326 al= (al >> 4)*10 + (al & 0xf);
01327 apm_printf("Got APM connection version %u.%u\n", ah, al);
01328
01329
01330 be.ax= 0x5308;
01331 be.bx= 0x0001;
01332 #if 0
01333
01334
01335
01336 be.bx= 0xffff;
01337 #endif
01338 be.cx= 0x0001;
01339 int15(&be);
01340 if (be.flags & FL_CARRY)
01341 {
01342 apm_perror("Enable power management failed", be.ax);
01343 goto disco;
01344 }
01345
01346
01347 be.ax= 0x5307;
01348 be.bx= 0x0001;
01349 be.cx= 0x0003;
01350 int15(&be);
01351 if (be.flags & FL_CARRY)
01352 {
01353 apm_perror("Set power state failed", be.ax);
01354 goto disco;
01355 }
01356
01357 apm_printf("Power off sequence successfully completed.\n\n");
01358 apm_printf("Ha, ha, just kidding!\n");
01359
01360 disco:
01361
01362 be.ax= 0x5304;
01363 be.bx= 0x0000;
01364 int15(&be);
01365 if (be.flags & FL_CARRY)
01366 {
01367 apm_perror("APM interface disconnect failed", be.ax);
01368 return;
01369 }
01370 }
01371
01372 #if !DOS
01373 #define B_NOSIG -1
01374
01375 int exec_bootstrap(void)
01376
01377
01378 {
01379 int r, n, dirty= 0;
01380 char master[SECTOR_SIZE];
01381 struct part_entry *table[NR_PARTITIONS], dummy, *active= &dummy;
01382 u32_t masterpos;
01383
01384 active->lowsec= 0;
01385
01386
01387 while (tmpdev.primary >= 0) {
01388 masterpos= active->lowsec;
01389
01390 if ((r= get_master(master, table, masterpos)) != 0) return r;
01391
01392 active= table[tmpdev.primary];
01393
01394
01395 if (active->sysind == NO_PART) return B_NOSIG;
01396
01397 tmpdev.primary= tmpdev.secondary;
01398 tmpdev.secondary= -1;
01399 }
01400
01401 if (activate && !active->bootind) {
01402 for (n= 0; n < NR_PARTITIONS; n++) table[n]->bootind= 0;
01403 active->bootind= ACTIVE_FLAG;
01404 dirty= 1;
01405 }
01406
01407
01408 if ((r= readsectors(BOOTPOS, active->lowsec, 1)) != 0) return r;
01409
01410
01411 if (get_word(BOOTPOS+SIGNATOFF) != SIGNATURE) return B_NOSIG;
01412
01413
01414 if (dirty && (r= writesectors(mon2abs(master), masterpos, 1)) != 0)
01415 return r;
01416
01417 bootstrap(device, active);
01418 }
01419
01420 void boot_device(char *devname)
01421
01422 {
01423 dev_t dev= name2dev(devname);
01424 int save_dev= device;
01425 int r;
01426 char *err;
01427
01428 if (tmpdev.device < 0) {
01429 if (dev != -1) printf("Can't boot from %s\n", devname);
01430 return;
01431 }
01432
01433
01434 device= tmpdev.device;
01435
01436 if ((r= dev_open()) == 0) r= exec_bootstrap();
01437
01438 err= r == B_NOSIG ? "Not bootable" : bios_err(r);
01439 printf("Can't boot %s: %s\n", devname, err);
01440
01441
01442 device= save_dev;
01443 (void) dev_open();
01444 }
01445
01446 void ctty(char *line)
01447 {
01448 if (line == nil) {
01449 serial_line = -1;
01450 } else if (between('0', line[0], '3') && line[1] == 0) {
01451 serial_line = line[0] - '0';
01452 } else {
01453 printf("Bad serial line number: %s\n", line);
01454 return;
01455 }
01456 serial_init(serial_line);
01457 }
01458
01459 #else
01460
01461 void boot_device(char *devname)
01462
01463 {
01464 printf("Can't boot devices under DOS\n");
01465 }
01466
01467 void ctty(char *line)
01468
01469 {
01470 printf("No serial line support under DOS\n");
01471 }
01472
01473 #endif
01474 #endif
01475
01476 void ls(char *dir)
01477
01478 {
01479 ino_t ino;
01480 struct stat st;
01481 char name[NAME_MAX+1];
01482
01483 if (fsok == -1) fsok= r_super(&block_size) != 0;
01484 if (!fsok) return;
01485
01486
01487 if ((ino= r_lookup(ROOT_INO, dir)) == 0 ||
01488 (r_stat(ino, &st), r_readdir(name)) == -1)
01489 {
01490 printf("ls: %s: %s\n", dir, unix_err(errno));
01491 return;
01492 }
01493 (void) r_readdir(name);
01494
01495 while ((ino= r_readdir(name)) != 0) printf("%s/%s\n", dir, name);
01496 }
01497
01498 u32_t milli_time(void)
01499 {
01500 return get_tick() * MSEC_PER_TICK;
01501 }
01502
01503 u32_t milli_since(u32_t base)
01504 {
01505 return (milli_time() + (TICKS_PER_DAY*MSEC_PER_TICK) - base)
01506 % (TICKS_PER_DAY*MSEC_PER_TICK);
01507 }
01508
01509 char *Thandler;
01510 u32_t Tbase, Tcount;
01511
01512 void unschedule(void)
01513
01514 {
01515 alarm(0);
01516
01517 if (Thandler != nil) {
01518 free(Thandler);
01519 Thandler= nil;
01520 }
01521 }
01522
01523 void schedule(long msec, char *cmd)
01524
01525 {
01526 unschedule();
01527 Thandler= cmd;
01528 Tbase= milli_time();
01529 Tcount= msec;
01530 alarm(1);
01531 }
01532
01533 int expired(void)
01534
01535 {
01536 return (Thandler != nil && milli_since(Tbase) >= Tcount);
01537 }
01538
01539 void delay(char *msec)
01540
01541 {
01542 u32_t base, count;
01543
01544 if ((count= a2l(msec)) == 0) return;
01545 base= milli_time();
01546
01547 alarm(1);
01548
01549 do {
01550 pause();
01551 } while (!interrupt() && !expired() && milli_since(base) < count);
01552 }
01553
01554 enum whatfun { NOFUN, SELECT, DEFFUN, USERFUN } menufun(environment *e)
01555 {
01556 if (!(e->flags & E_FUNCTION) || e->arg[0] == 0) return NOFUN;
01557 if (e->arg[1] != ',') return SELECT;
01558 return e->flags & E_RESERVED ? DEFFUN : USERFUN;
01559 }
01560
01561 void menu(void)
01562
01563
01564
01565
01566
01567 {
01568 int c, def= 1;
01569 char *choice= nil;
01570 environment *e;
01571
01572
01573 for (e= env; e != nil; e= e->next) if (menufun(e) == USERFUN) def= 0;
01574
01575 printf("\nHit a key as follows:\n\n");
01576
01577
01578 for (e= env; e != nil; e= e->next) {
01579 switch (menufun(e)) {
01580 case DEFFUN:
01581 if (!def) break;
01582
01583 case USERFUN:
01584 printf(" %c %s\n", e->arg[0], e->arg+2);
01585 break;
01586 case SELECT:
01587 printf(" %c Select %s kernel\n", e->arg[0],e->name);
01588 break;
01589 default:;
01590 }
01591 }
01592
01593
01594 do {
01595 c= getch();
01596 if (interrupt() || expired()) return;
01597
01598 unschedule();
01599
01600 for (e= env; e != nil; e= e->next) {
01601 switch (menufun(e)) {
01602 case DEFFUN:
01603 if (!def) break;
01604 case USERFUN:
01605 case SELECT:
01606 if (c == e->arg[0]) choice= e->value;
01607 }
01608 }
01609 } while (choice == nil);
01610
01611
01612 printf("%c\n", c);
01613 (void) tokenize(&cmds, choice);
01614 }
01615
01616 void help(void)
01617
01618 {
01619 struct help {
01620 char *thing;
01621 char *help;
01622 } *pi;
01623 static struct help info[] = {
01624 { nil, "Names:" },
01625 { "rootdev", "Root device" },
01626 { "ramimagedev", "Device to use as RAM disk image " },
01627 { "ramsize", "RAM disk size (if no image device) " },
01628 { "bootdev", "Special name for the boot device" },
01629 { "fd0, d0p2, c0d0p1s0", "Devices (as in /dev)" },
01630 { "image", "Name of the boot image to use" },
01631 { "main", "Startup function" },
01632 { "bootdelay", "Delay in msec after loading image" },
01633 { nil, "Commands:" },
01634 { "name = [device] value", "Set environment variable" },
01635 { "name() { ... }", "Define function" },
01636 { "name(key,text) { ... }",
01637 "A menu option like: minix(=,Start MINIX) {boot}" },
01638 { "name", "Call function" },
01639 { "boot [device]", "Boot Minix or another O.S." },
01640 { "ctty [line]", "Duplicate to serial line" },
01641 { "delay [msec]", "Delay (500 msec default)" },
01642 { "echo word ...", "Display the words" },
01643 { "ls [directory]", "List contents of directory" },
01644 { "menu", "Show menu and choose menu option" },
01645 { "save / set", "Save or show environment" },
01646 { "trap msec command", "Schedule command " },
01647 { "unset name ...", "Unset variable or set to default" },
01648 { "exit / off", "Exit the Monitor / Power off" },
01649 };
01650
01651 for (pi= info; pi < arraylimit(info); pi++) {
01652 if (pi->thing != nil) printf(" %-24s- ", pi->thing);
01653 printf("%s\n", pi->help);
01654 }
01655 }
01656
01657 void execute(void)
01658
01659 {
01660 token *second, *third, *fourth, *sep;
01661 char *name;
01662 int res;
01663 size_t n= 0;
01664
01665 if (err) {
01666
01667 while (cmds != nil) voidtoken();
01668 return;
01669 }
01670
01671 if (expired()) {
01672 parse_code(Thandler);
01673 unschedule();
01674 }
01675
01676
01677 for (sep= cmds; sep != nil && sep->token[0] != ';'; sep= sep->next) n++;
01678
01679 name= cmds->token;
01680 res= reserved(name);
01681 if ((second= cmds->next) != nil
01682 && (third= second->next) != nil)
01683 fourth= third->next;
01684
01685
01686 if (n == 0) {
01687 voidtoken();
01688 return;
01689 } else
01690
01691 if ((n == 3 || n == 4)
01692 && !sugar(name)
01693 && second->token[0] == '='
01694 && !sugar(third->token)
01695 && (n == 3 || (n == 4 && third->token[0] == 'd'
01696 && !sugar(fourth->token)
01697 ))) {
01698 char *value= third->token;
01699 int flags= E_VAR;
01700
01701 if (n == 4) { value= fourth->token; flags|= E_DEV; }
01702
01703 if ((flags= b_setvar(flags, name, value)) != 0) {
01704 printf("%s is a %s\n", name,
01705 flags & E_RESERVED ? "reserved word" :
01706 "special function");
01707 err= 1;
01708 }
01709 while (cmds != sep) voidtoken();
01710 return;
01711 } else
01712
01713 if (n >= 3
01714 && !sugar(name)
01715 && second->token[0] == '('
01716 ) {
01717 token *fun;
01718 int c, flags, depth;
01719 char *body;
01720 size_t len;
01721
01722 sep= fun= third;
01723 depth= 0;
01724 len= 1;
01725 while (sep != nil) {
01726 if ((c= sep->token[0]) == ';' && depth == 0) break;
01727 len+= strlen(sep->token) + 1;
01728 sep= sep->next;
01729 if (c == '{') depth++;
01730 if (c == '}' && --depth == 0) break;
01731 }
01732
01733 body= malloc(len * sizeof(char));
01734 *body= 0;
01735
01736 while (fun != sep) {
01737 strcat(body, fun->token);
01738 if (!sugar(fun->token)
01739 && !sugar(fun->next->token)
01740 ) strcat(body, " ");
01741 fun= fun->next;
01742 }
01743 second->token[strlen(second->token)-1]= 0;
01744
01745 if (depth != 0) {
01746 printf("Missing '}'\n");
01747 err= 1;
01748 } else
01749 if ((flags= b_setenv(E_FUNCTION, name,
01750 second->token+1, body)) != 0) {
01751 printf("%s is a %s\n", name,
01752 flags & E_RESERVED ? "reserved word" :
01753 "special variable");
01754 err= 1;
01755 }
01756 while (cmds != sep) voidtoken();
01757 free(body);
01758 return;
01759 } else
01760
01761 if (name[0] == '{') {
01762 token **acmds= &cmds->next;
01763 char *t;
01764 int depth= 1;
01765
01766
01767 depth= 1;
01768 while (*acmds != nil) {
01769 t= (*acmds)->token;
01770 if (t[0] == '{') depth++;
01771 if (t[0] == '}' && --depth == 0) { t[0]= ';'; break; }
01772 acmds= &(*acmds)->next;
01773 }
01774 voidtoken();
01775 return;
01776 } else
01777
01778 if (interrupt()) {
01779 return;
01780 } else
01781
01782 if (n >= 1 && (res == R_UNSET || res == R_ECHO)) {
01783 char *arg= poptoken(), *p;
01784
01785 for (;;) {
01786 free(arg);
01787 if (cmds == sep) break;
01788 arg= poptoken();
01789 if (res == R_UNSET) {
01790 b_unset(arg);
01791 } else {
01792 p= arg;
01793 while (*p != 0) {
01794 if (*p != '\\') {
01795 putch(*p);
01796 } else
01797 switch (*++p) {
01798 case 0:
01799 if (cmds == sep) return;
01800 continue;
01801 case 'n':
01802 putch('\n');
01803 break;
01804 case 'v':
01805 printf(version);
01806 break;
01807 case 'c':
01808 clear_screen();
01809 break;
01810 case 'w':
01811 for (;;) {
01812 if (interrupt())
01813 return;
01814 if (getch() == '\n')
01815 break;
01816 }
01817 break;
01818 default:
01819 putch(*p);
01820 }
01821 p++;
01822 }
01823 putch(cmds != sep ? ' ' : '\n');
01824 }
01825 }
01826 return;
01827 } else
01828
01829 if (n == 2 && res == R_BOOT && second->token[0] == '-') {
01830 static char optsvar[]= "bootopts";
01831 (void) b_setvar(E_VAR, optsvar, second->token);
01832 voidtoken();
01833 voidtoken();
01834 bootminix();
01835 b_unset(optsvar);
01836 return;
01837 } else
01838
01839 if (n == 2 && (res == R_BOOT || res == R_CTTY
01840 || res == R_DELAY || res == R_LS)
01841 ) {
01842 if (res == R_BOOT) boot_device(second->token);
01843 if (res == R_CTTY) ctty(second->token);
01844 if (res == R_DELAY) delay(second->token);
01845 if (res == R_LS) ls(second->token);
01846 voidtoken();
01847 voidtoken();
01848 return;
01849 } else
01850
01851 if (n == 3 && res == R_TRAP && numeric(second->token)) {
01852 long msec= a2l(second->token);
01853
01854 voidtoken();
01855 voidtoken();
01856 schedule(msec, poptoken());
01857 return;
01858 } else
01859
01860 if (n == 1) {
01861 char *body;
01862 int ok= 0;
01863
01864 name= poptoken();
01865
01866 switch (res) {
01867 case R_BOOT: bootminix(); ok= 1; break;
01868 case R_DELAY: delay("500"); ok= 1; break;
01869 case R_LS: ls(null); ok= 1; break;
01870 case R_MENU: menu(); ok= 1; break;
01871 case R_SAVE: save_parameters(); ok= 1;break;
01872 case R_SET: show_env(); ok= 1; break;
01873 case R_HELP: help(); ok= 1; break;
01874 case R_EXIT: exit(0);
01875 case R_OFF: off(); ok= 1; break;
01876 case R_CTTY: ctty(nil); ok= 1; break;
01877 }
01878
01879
01880 if (strcmp(name, ":") == 0) ok= 1;
01881
01882
01883 if (!ok && (body= b_body(name)) != nil) {
01884 (void) tokenize(&cmds, body);
01885 ok= 1;
01886 }
01887 if (!ok) printf("%s: unknown function", name);
01888 free(name);
01889 if (ok) return;
01890 } else {
01891
01892 printf("Can't parse:");
01893 while (cmds != sep) {
01894 printf(" %s", cmds->token); voidtoken();
01895 }
01896 }
01897
01898
01899 printf("\nTry 'help'\n");
01900 err= 1;
01901 }
01902
01903 int run_trailer(void)
01904
01905
01906
01907 {
01908 token *save_cmds= cmds;
01909
01910 cmds= nil;
01911 (void) tokenize(&cmds, "trailer");
01912 while (cmds != nil) execute();
01913 cmds= save_cmds;
01914 return !err;
01915 }
01916
01917 void monitor(void)
01918
01919 {
01920 char *line;
01921
01922 unschedule();
01923 err= 0;
01924
01925 if (istty) printf("%s>", bootdev.name);
01926 line= readline();
01927 (void) tokenize(&cmds, line);
01928 free(line);
01929 (void) escape();
01930 }
01931
01932 #if BIOS
01933
01934 void boot(void)
01935
01936 {
01937
01938 initialize();
01939
01940
01941 get_parameters();
01942
01943 while (1) {
01944
01945
01946 while (cmds != nil) execute();
01947
01948
01949 monitor();
01950 }
01951 }
01952 #endif
01953
01954 #if UNIX
01955
01956 void main(int argc, char **argv)
01957
01958 {
01959 int i;
01960 char bootcode[SECTOR_SIZE];
01961 struct termios rawterm;
01962
01963 istty= (argc <= 2 && tcgetattr(0, &termbuf) == 0);
01964
01965 if (argc < 2) {
01966 fprintf(stderr, "Usage: edparams device [command ...]\n");
01967 exit(1);
01968 }
01969
01970
01971 for (i= 2; i < argc; i++) {
01972 char *p;
01973
01974 for (p= argv[i]; *p != 0; p++) {
01975 if ((unsigned) *p < ' ' && *p != '\n') *p= ' ';
01976 }
01977 }
01978
01979 bootdev.name= argv[1];
01980 if (strncmp(bootdev.name, "/dev/", 5) == 0) bootdev.name+= 5;
01981 if ((bootdev.device= open(argv[1], O_RDWR, 0666)) < 0)
01982 fatal(bootdev.name);
01983
01984
01985 if (readsectors(mon2abs(bootcode), lowsec, 1) != 0) {
01986 fprintf(stderr, "edparams: %s: not a bootable Minix device\n",
01987 bootdev.name);
01988 exit(1);
01989 }
01990
01991
01992 if (istty) printf("Boot parameters editor.\n");
01993
01994 signal(SIGINT, trap);
01995 signal(SIGALRM, trap);
01996
01997 if (istty) {
01998 rawterm= termbuf;
01999 rawterm.c_lflag&= ~(ICANON|ECHO|IEXTEN);
02000 rawterm.c_cc[VINTR]= ESC;
02001 if (tcsetattr(0, TCSANOW, &rawterm) < 0) fatal("");
02002 }
02003
02004
02005 get_parameters();
02006
02007 i= 2;
02008 for (;;) {
02009
02010 while (cmds != nil || i < argc) {
02011 if (cmds == nil) {
02012
02013 parse_code(argv[i++]);
02014 }
02015 execute();
02016
02017
02018 if (err && !istty) exit(1);
02019 }
02020
02021
02022 if (argc > 2) break;
02023
02024
02025 monitor();
02026 }
02027 exit(0);
02028 }
02029 #endif
02030
02031
02032
02033
02034