C 23
Boot.c Guest on 24th October 2020 05:25:02 PM
  1. /*      boot 2.5.0 - Load and start Minix.              Author: Kees J. Bot
  2.  *                                                              27 Dec 1991
  3.  *
  4.  * Copyright 1996 Kees J. Bot, All rights reserved.
  5.  * This package may be freely used and modified except that changes that
  6.  * do not increase the functionality or that are incompatible with the
  7.  * original may not be released to the public without permission from the
  8.  * author.  Use of so called "C beautifiers" is explicitly prohibited.
  9.  */
  10.  
  11. char version[]=         "2.5";
  12.  
  13. #define nil 0
  14. #define _POSIX_SOURCE   1
  15. #define _MINIX          1
  16. #include <stddef.h>
  17. #include <sys/types.h>
  18. #include <sys/stat.h>
  19. #include <stdlib.h>
  20. #include <limits.h>
  21. #include <string.h>
  22. #include <errno.h>
  23. #include <a.out.h>
  24. #include <minix/config.h>
  25. #include <minix/const.h>
  26. #include <minix/type.h>
  27. #include <minix/minlib.h>
  28. #include <kernel/const.h>
  29. #include <kernel/type.h>
  30. #include <ibm/partition.h>
  31. #include "rawfs.h"
  32. #undef EXTERN
  33. #define EXTERN  /* Empty */
  34. #include "boot.h"
  35.  
  36. #define arraysize(a)            (sizeof(a) / sizeof((a)[0]))
  37. #define arraylimit(a)           ((a) + arraysize(a))
  38. #define between(a, c, z)        ((unsigned) ((c) - (a)) <= ((z) - (a)))
  39.  
  40. void printk(char *fmt, ...);
  41. #define printf  printk
  42.  
  43. char *bios_err(int err)
  44. /* Translate BIOS error code to a readable string.  (This is a rare trait
  45.  * known as error checking and reporting.  Take a good look at it, you won't
  46.  * see it often.)
  47.  */
  48. {
  49.         static struct errlist {
  50.                 short   err;
  51.                 char    *what;
  52.         } errlist[] = {
  53. #if !DOS
  54.                 { 0x00, "No error" },
  55.                 { 0x01, "Invalid command" },
  56.                 { 0x02, "Address mark not found" },
  57.                 { 0x03, "Disk write-protected" },
  58.                 { 0x04, "Sector not found" },
  59.                 { 0x05, "Reset failed" },
  60.                 { 0x06, "Floppy disk removed" },
  61.                 { 0x07, "Bad parameter table" },
  62.                 { 0x08, "DMA overrun" },
  63.                 { 0x09, "DMA crossed 64 KB boundary" },
  64.                 { 0x0A, "Bad sector flag" },
  65.                 { 0x0B, "Bad track flag" },
  66.                 { 0x0C, "Media type not found" },
  67.                 { 0x0D, "Invalid number of sectors on format" },
  68.                 { 0x0E, "Control data address mark detected" },
  69.                 { 0x0F, "DMA arbitration level out of range" },
  70.                 { 0x10, "Uncorrectable CRC or ECC data error" },
  71.                 { 0x11, "ECC corrected data error" },
  72.                 { 0x20, "Controller failed" },
  73.                 { 0x40, "Seek failed" },
  74.                 { 0x80, "Disk timed-out" },
  75.                 { 0xAA, "Drive not ready" },
  76.                 { 0xBB, "Undefined error" },
  77.                 { 0xCC, "Write fault" },
  78.                 { 0xE0, "Status register error" },
  79.                 { 0xFF, "Sense operation failed" }
  80. #else /* DOS */
  81.                 { 0x00, "No error" },
  82.                 { 0x01, "Function number invalid" },
  83.                 { 0x02, "File not found" },
  84.                 { 0x03, "Path not found" },
  85.                 { 0x04, "Too many open files" },
  86.                 { 0x05, "I/O error" },
  87.                 { 0x06, "Invalid handle" },
  88.                 { 0x0C, "Access code invalid" },
  89. #endif /* DOS */
  90.         };
  91.         struct errlist *errp;
  92.  
  93.         for (errp= errlist; errp < arraylimit(errlist); errp++) {
  94.                 if (errp->err == err) return errp->what;
  95.         }
  96.         return "Unknown error";
  97. }
  98.  
  99. char *unix_err(int err)
  100. /* Translate the few errors rawfs can give. */
  101. {
  102.         switch (err) {
  103.         case ENOENT:    return "No such file or directory";
  104.         case ENOTDIR:   return "Not a directory";
  105.         default:        return "Unknown error";
  106.         }
  107. }
  108.  
  109. void rwerr(char *rw, off_t sec, int err)
  110. {
  111.         printf("\n%s error 0x%02x (%s) at sector %ld absolute\n",
  112.                 rw, err, bios_err(err), sec);
  113. }
  114.  
  115. void readerr(off_t sec, int err)        { rwerr("Read", sec, err); }
  116. void writerr(off_t sec, int err)        { rwerr("Write", sec, err); }
  117.  
  118. /* Readblock support for rawfs.c */
  119.  
  120. #define CACHE_SIZE      32      /* More than enough. */
  121.  
  122. struct cache_entry {
  123.         u32_t   block;
  124.         u32_t   addr;
  125. } cache[CACHE_SIZE];
  126.  
  127. #if !DOS
  128. int cache_live= 0;
  129.  
  130. void init_cache(void)
  131. /* Initialize the block cache. */
  132. {
  133.         struct cache_entry *pc;
  134.         u32_t addr= FREEPOS;
  135.  
  136.         for (pc= cache; pc < arraylimit(cache); pc++) {
  137.                 pc->block= -1;
  138.                 pc->addr= addr;
  139.                 addr+= BLOCK_SIZE;
  140.         }
  141.  
  142.         cache_live= 1;  /* Turn it on. */
  143. }
  144.  
  145. void invalidate_cache(void)
  146. /* The cache can't be used when Minix is loaded. */
  147. {
  148.         cache_live= 0;
  149. }
  150.  
  151. #else /* DOS */
  152. /* We can't fool around with random memory under DOS. */
  153. #define cache_live 0
  154. void init_cache(void) {}
  155. void invalidate_cache(void) {}
  156. #endif /* DOS */
  157.  
  158. void readblock(off_t blk, char *buf)
  159. /* Read blocks for the rawfs package with caching.  Wins 2 seconds. */
  160. {
  161.         int r= 0;
  162.         u32_t sec= lowsec + blk * RATIO;
  163.  
  164.         if (!cache_live) {
  165.                 /* Cache invalidated, load block directly in place. */
  166.                 r= readsectors(mon2abs(buf), sec, 1 * RATIO);
  167.         } else {
  168.                 /* Search through the cache from 0 up.  Move the one found
  169.                  * to the front of the cache, then optionally read a block.
  170.                  */
  171.                 struct cache_entry *pc, lifo, tmp;
  172.  
  173.                 for (pc= cache; pc < arraylimit(cache); pc++) {
  174.                         tmp= *pc;
  175.                         *pc= lifo;
  176.                         lifo= tmp;
  177.                         if (lifo.block == blk) break;
  178.                 }
  179.                 cache[0]= lifo;
  180.  
  181.                 if (cache[0].block != blk) {
  182.                         r= readsectors(cache[0].addr, sec, 1 * RATIO);
  183.                         cache[0].block= blk;
  184.                 }
  185.                 raw_copy(mon2abs(buf), cache[0].addr, BLOCK_SIZE);
  186.         }
  187.         if (r != 0) { readerr(sec, r); exit(1); }
  188. }
  189.  
  190. char *readline(void)
  191. /* Read a line including a newline with echoing. */
  192. {
  193.         char *line;
  194.         size_t i, z;
  195.         int c;
  196.  
  197.         i= 0;
  198.         z= 20;
  199.         line= malloc(z * sizeof(char));
  200.  
  201.         do {
  202.                 c= getchar();
  203.  
  204.                 if (strchr("\b\177\25\30", c) != nil) {
  205.                         /* Backspace, DEL, ctrl-U, or ctrl-X. */
  206.                         do {
  207.                                 if (i == 0) break;
  208.                                 printf("\b \b");
  209.                                 i--;
  210.                         } while (c == '\25' || c == '\30');
  211.                 } else
  212.                 if (c < ' ' && c != '\n') {
  213.                         putchar('\7');
  214.                 } else {
  215.                         putchar(c);
  216.                         line[i++]= c;
  217.                         if (i == z) {
  218.                                 z*= 2;
  219.                                 line= realloc(line, z * sizeof(char));
  220.                         }
  221.                 }
  222.         } while (c != '\n');
  223.         line[i]= 0;
  224.         return line;
  225. }
  226.  
  227. int sugar(char *tok)
  228. /* Recognize special tokens. */
  229. {
  230.         return strchr("=(){};\n", tok[0]) != nil;
  231. }
  232.  
  233. char *onetoken(char **aline, int arg)
  234. /* Returns a string with one token for tokenize.  Arg is true when reading
  235.  * between ( and ).
  236.  */
  237. {
  238.         char *line= *aline;
  239.         size_t n;
  240.         char *tok;
  241.  
  242.         /* Skip spaces and runs of newlines. */
  243.         while (*line == ' ' || (*line == '\n' && line[1] == '\n')) line++;
  244.  
  245.         *aline= line;
  246.  
  247.         /* Don't do odd junk (nor the terminating 0!). */
  248.         if ((unsigned) *line < ' ' && *line != '\n') return nil;
  249.  
  250.         if (arg) {
  251.                 /* Function argument, anything goes except ). */
  252.                 int depth= 0;
  253.  
  254.                 while ((unsigned) *line >= ' ') {
  255.                         if (*line == '(') depth++;
  256.                         if (*line == ')' && --depth < 0) break;
  257.                         line++;
  258.                 }
  259.                 while (line > *aline && line[-1] == ' ') line--;
  260.         } else
  261.         if (sugar(line)) {
  262.                 /* Single character token. */
  263.                 line++;
  264.         } else {
  265.                 /* Multicharacter token. */
  266.                 do line++; while ((unsigned) *line > ' ' && !sugar(line));
  267.         }
  268.         n= line - *aline;
  269.         tok= malloc((n + 1) * sizeof(char));
  270.         memcpy(tok, *aline, n);
  271.         tok[n]= 0;
  272.         if (tok[0] == '\n') tok[0]= ';';        /* ';' same as '\n' */
  273.  
  274.         *aline= line;
  275.         return tok;
  276. }
  277.  
  278. /* Typed commands form strings of tokens. */
  279.  
  280. typedef struct token {
  281.         struct token    *next;  /* Next in a command chain. */
  282.         char            *token;
  283. } token;
  284.  
  285. token **tokenize(token **acmds, char *line, int *fundef)
  286. /* Takes a line apart to form tokens.  The tokens are inserted into a command
  287.  * chain at *acmds.  Tokenize returns a reference to where another line could
  288.  * be added.  The fundef variable holds the state tokenize is in when decoding
  289.  * a multiline function definition.  It is nonzero when more must be read.
  290.  * Tokenize looks at spaces as token separators, and recognizes only
  291.  * ';', '=', '(', ')' '{', '}', and '\n' as single character tokens.
  292.  */
  293. {
  294.         int fd= *fundef;
  295.         char *tok;
  296.         token *newcmd;
  297.         static char funsugar[]= { '(', 0, ')', '{', '}' };
  298.  
  299.         while ((tok= onetoken(&line, fd == 1)) != nil) {
  300.                 if (fd == 1) {
  301.                         fd++;   /* Function argument. */
  302.                 } else
  303.                 if (funsugar[fd] == tok[0]) {
  304.                         /* Recognize next token as part of a function def. */
  305.                         fd= tok[0] == '}' ? 0 : fd + 1;
  306.                 } else
  307.                 if (fd != 0) {
  308.                         if (tok[0] == ';' && fd == 3) {
  309.                                 /* Kill separator between ')' and '{'. */
  310.                                 free(tok);
  311.                                 continue;
  312.                         }
  313.                         /* Syntax error unless between '{' and '}'. */
  314.                         if (fd != 4) fd= 0;
  315.                 }
  316.                 newcmd= malloc(sizeof(*newcmd));
  317.                 newcmd->token= tok;
  318.                 newcmd->next= *acmds;
  319.                 *acmds= newcmd;
  320.                 acmds= &newcmd->next;
  321.         }
  322.         *fundef= fd;
  323.         return acmds;
  324. }
  325.  
  326. token *cmds;            /* String of commands to execute. */
  327. int err;                /* Set on an error. */
  328.  
  329. char *poptoken(void)
  330. /* Pop one token off the command chain. */
  331. {
  332.         token *cmd= cmds;
  333.         char *tok= cmd->token;
  334.  
  335.         cmds= cmd->next;
  336.         free(cmd);
  337.  
  338.         return tok;
  339. }
  340.  
  341. void voidtoken(void)
  342. /* Remove one token from the command chain. */
  343. {
  344.         free(poptoken());
  345. }
  346.  
  347. void interrupt(void)
  348. /* Clean up after an ESC has been typed. */
  349. {
  350.         printf("[ESC]\n");
  351.         while (peekchar() == ESC) (void) getchar();
  352.         err= 1;
  353. }
  354.  
  355. int activate;
  356.  
  357. struct biosdev {
  358.         char name[6];
  359.         int device, primary, secondary;
  360. } bootdev, tmpdev;
  361.  
  362. struct part_entry boot_part;
  363. char dskpars[DSKPARSIZE]=       /* 360K floppy disk parameters (for now). */
  364.         { 0xDF, 0x02, 25, 2,  9, 0x2A, 0xFF, 0x50, 0xF6, 15, 8 };
  365.  
  366. void migrate(void)
  367. /* Copy the boot program to the far end of memory, this must be done asap to
  368.  * put the data area cleanly inside a 64K chunk (no DMA problems).
  369.  */
  370. {
  371.         u32_t oldaddr= caddr;
  372.         u32_t memsize= get_memsize() * 1024L;
  373.         u32_t newaddr= memsize - runsize;
  374. #if !DOS
  375.         u32_t dma64k= (memsize - 1) & ~0xFFFFL;
  376.         vector dskbase;
  377.  
  378.         /* Check if data segment crosses a 64k boundary. */
  379.         if (newaddr + (daddr - caddr) < dma64k) newaddr= dma64k - runsize;
  380.  
  381.         /* Get some variables into my address space before they get mashed. */
  382.         if (device < 0x80) {
  383.                 /* Floppy disk parameters. */
  384.                 raw_copy(mon2abs(&dskbase), DSKBASE * sizeof(vector),
  385.                                                         sizeof(vector));
  386.                 raw_copy(mon2abs(dskpars), vec2abs(&dskbase),
  387.                                                         DSKPARSIZE);
  388.         } else {
  389.                 /* Hard disk partition table entry into boot_part. */
  390.                 raw_copy(mon2abs(&boot_part), vec2abs(&rem_part),
  391.                                                         sizeof(boot_part));
  392.         }
  393. #endif /* !DOS */
  394.  
  395.         /* Set the new caddr for relocate. */
  396.         caddr= newaddr;
  397.  
  398.         /* Copy code and data. */
  399.         raw_copy(newaddr, oldaddr, runsize);
  400.  
  401.         relocate();     /* Make the copy running. */
  402.  
  403. #if !DOS
  404.         /* Set the parameters for the boot device using global variables
  405.          * device and dskpars.  (This particular call should not fail.)
  406.          */
  407.         (void) dev_geometry();
  408. #endif /* !DOS */
  409. }
  410.  
  411. int get_master(char *master, struct part_entry **table, u32_t pos)
  412. /* Read a master boot sector and its partition table. */
  413. {
  414.         int r, n;
  415.         struct part_entry *pe, **pt;
  416.  
  417.         if ((r= readsectors(mon2abs(master), pos, 1)) != 0) return r;
  418.  
  419.         pe= (struct part_entry *) (master + PART_TABLE_OFF);
  420.         for (pt= table; pt < table + NR_PARTITIONS; pt++) *pt= pe++;
  421.  
  422.         /* DOS has the misguided idea that partition tables must be sorted. */
  423.         if (pos != 0) return 0;         /* But only the primary. */
  424.  
  425.         n= NR_PARTITIONS;
  426.         do {
  427.                 for (pt= table; pt < table + NR_PARTITIONS-1; pt++) {
  428.                         if (pt[0]->sysind == NO_PART
  429.                                 || (pt[0]->lowsec > pt[1]->lowsec
  430.                                                 && pt[1]->sysind != NO_PART)) {
  431.                                 pe= pt[0]; pt[0]= pt[1]; pt[1]= pe;
  432.                         }
  433.                 }
  434.         } while (--n > 0);
  435.         return 0;
  436. }
  437.  
  438. void initialize(void)
  439. {
  440.         char master[SECTOR_SIZE];
  441.         struct part_entry *table[NR_PARTITIONS];
  442.         int r, p;
  443.         u32_t masterpos;
  444.         static char sub[]= "a";
  445.  
  446. #if !DOS
  447.         /* Find out what the boot device and partition was. */
  448.         bootdev.name[0]= 0;
  449.         bootdev.device= device;
  450.         bootdev.primary= -1;
  451.         bootdev.secondary= -1;
  452.  
  453.         if (device < 0x80) {
  454.                 /* Floppy. */
  455.                 strcpy(bootdev.name, "fd");
  456.                 strcat(bootdev.name, u2a(bootdev.device));
  457.                 return;
  458.         }
  459.  
  460.         /* Get the partition table from the very first sector, and determine
  461.          * the partition we booted from.  Migrate() was so nice to put the
  462.          * partition table entry of the booted partition in boot_part.
  463.          */
  464.  
  465.         /* The only thing really needed from the booted partition: */
  466.         lowsec= boot_part.lowsec;
  467.  
  468.         masterpos= 0;   /* Master bootsector position. */
  469.  
  470.         for (;;) {
  471.                 /* Extract the partition table from the master boot sector. */
  472.                 if ((r= get_master(master, table, masterpos)) != 0) {
  473.                         readerr(masterpos, r); exit(1);
  474.                 }
  475.  
  476.                 /* See if you can find "lowsec" back. */
  477.                 for (p= 0; p < NR_PARTITIONS; p++) {
  478.                         if (lowsec - table[p]->lowsec < table[p]->size) break;
  479.                 }
  480.  
  481.                 if (lowsec == table[p]->lowsec) {       /* Found! */
  482.                         if (bootdev.primary < 0)
  483.                                 bootdev.primary= p;
  484.                         else
  485.                                 bootdev.secondary= p;
  486.                         break;
  487.                 }
  488.  
  489.                 if (p == NR_PARTITIONS || bootdev.primary >= 0) {
  490.                         /* The boot partition cannot be named, this only means
  491.                          * that "bootdev" doesn't work.
  492.                          */
  493.                         bootdev.device= -1;
  494.                         return;
  495.                 }
  496.  
  497.                 /* See if the primary partition is subpartitioned. */
  498.                 bootdev.primary= p;
  499.                 masterpos= table[p]->lowsec;
  500.         }
  501.         strcpy(bootdev.name, "hd");
  502.         strcat(bootdev.name, u2a((device - 0x80) * (1 + NR_PARTITIONS)
  503.                                                 + 1 + bootdev.primary));
  504.         sub[0]= 'a' + bootdev.secondary;
  505.         if (bootdev.secondary >= 0) strcat(bootdev.name, sub);
  506.  
  507. #else /* DOS */
  508.         /* Initialize under DOS: Open virtual disk to boot Minix from, grab
  509.          * extended memory, etc.
  510.          */
  511.         char *argp, *vdisk;
  512.  
  513.         /* Parse the command line. */
  514.         argp= PSP + 0x81;
  515.         argp[PSP[0x80]]= 0;
  516.         while (between('\1', *argp, ' ')) argp++;
  517.         vdisk= argp;
  518.         while (!between('\0', *argp, ' ')) argp++;
  519.         while (between('\1', *argp, ' ')) *argp++= 0;
  520.         if (*argp != 0 || *vdisk == 0) {
  521.                 printf("\nUsage: boot <vdisk>\n");
  522.                 exit(1);
  523.         }
  524.  
  525.         if ((r= dos_open(vdisk)) != 0) {
  526.                 printf("\n%s: Error %02x (%s)\n", vdisk, r, bios_err(r));
  527.                 exit(1);
  528.         }
  529.  
  530.         /* Find the active partition on the virtual disk. */
  531.         if ((r= get_master(master, table, 0)) != 0) {
  532.                 readerr(0, r); exit(1);
  533.         }
  534.  
  535.         strcpy(bootdev.name, "dosd0");
  536.         bootdev.primary= -1;
  537.         for (p= 0; p < NR_PARTITIONS; p++) {
  538.                 if (table[p]->bootind != 0 && table[p]->sysind == MINIX_PART) {
  539.                         bootdev.primary= p;
  540.                         bootdev.name[4]= '1' + p;
  541.                         lowsec= table[p]->lowsec;
  542.                         break;
  543.                 }
  544.         }
  545. #endif /* DOS */
  546. }
  547.  
  548. char null[]= "";        /* This kludge saves lots of memory. */
  549.  
  550. void sfree(char *s)
  551. /* Free a non-null string. */
  552. {
  553.         if (s != nil && s != null) free(s);
  554. }
  555.  
  556. char *copystr(char *s)
  557. /* Copy a non-null string using malloc. */
  558. {
  559.         char *c;
  560.  
  561.         if (*s == 0) return null;
  562.         c= malloc((strlen(s) + 1) * sizeof(char));
  563.         strcpy(c, s);
  564.         return c;
  565. }
  566.  
  567. int is_default(environment *e)
  568. {
  569.         return (e->flags & E_SPECIAL) && e->defval == nil;
  570. }
  571.  
  572. environment **searchenv(char *name)
  573. {
  574.         environment **aenv= &env;
  575.  
  576.         while (*aenv != nil && strcmp((*aenv)->name, name) != 0) {
  577.                 aenv= &(*aenv)->next;
  578.         }
  579.  
  580.         return aenv;
  581. }
  582.  
  583. #define b_getenv(name)  (*searchenv(name))
  584. /* Return the environment *structure* belonging to name, or nil if not found. */
  585.  
  586. char *b_value(char *name)
  587. /* The value of a variable. */
  588. {
  589.         environment *e= b_getenv(name);
  590.  
  591.         return e == nil || !(e->flags & E_VAR) ? nil : e->value;
  592. }
  593.  
  594. char *b_body(char *name)
  595. /* The value of a function. */
  596. {
  597.         environment *e= b_getenv(name);
  598.  
  599.         return e == nil || !(e->flags & E_FUNCTION) ? nil : e->value;
  600. }
  601.  
  602. int b_setenv(int flags, char *name, char *arg, char *value)
  603. /* Change the value of an environment variable.  Returns the flags of the
  604.  * variable if you are not allowed to change it, 0 otherwise.
  605.  */
  606. {
  607.         environment **aenv, *e;
  608.  
  609.         if (*(aenv= searchenv(name)) == nil) {
  610.                 e= malloc(sizeof(*e));
  611.                 e->name= copystr(name);
  612.                 e->flags= flags;
  613.                 e->defval= nil;
  614.                 e->next= nil;
  615.                 *aenv= e;
  616.         } else {
  617.                 e= *aenv;
  618.  
  619.                 /* Don't touch reserved names and don't change special
  620.                  * variables to functions or vv.
  621.                  */
  622.                 if (e->flags & E_RESERVED || (e->flags & E_SPECIAL
  623.                         && (e->flags & E_FUNCTION) != (flags & E_FUNCTION)
  624.                 )) return e->flags;
  625.  
  626.                 e->flags= (e->flags & E_STICKY) | flags;
  627.                 if (is_default(e)) {
  628.                         e->defval= e->value;
  629.                 } else {
  630.                         sfree(e->value);
  631.                 }
  632.                 sfree(e->arg);
  633.         }
  634.         e->arg= copystr(arg);
  635.         e->value= copystr(value);
  636.         return 0;
  637. }
  638.  
  639. int b_setvar(int flags, char *name, char *value)
  640. /* Set variable or simple function. */
  641. {
  642.         return b_setenv(flags, name, null, value);
  643. }
  644.  
  645. void b_unset(char *name)
  646. /* Remove a variable from the environment.  A special variable is reset to
  647.  * its default value.
  648.  */
  649. {
  650.         environment **aenv, *e;
  651.  
  652.         if ((e= *(aenv= searchenv(name))) == nil) return;
  653.  
  654.         if (e->flags & E_SPECIAL) {
  655.                 if (e->defval != nil) {
  656.                         sfree(e->arg);
  657.                         e->arg= null;
  658.                         sfree(e->value);
  659.                         e->value= e->defval;
  660.                         e->defval= nil;
  661.                 }
  662.         } else {
  663.                 sfree(e->name);
  664.                 sfree(e->arg);
  665.                 sfree(e->value);
  666.                 *aenv= e->next;
  667.                 free(e);
  668.         }
  669. }
  670.  
  671. long a2l(char *a)
  672. /* Cheap atol(). */
  673. {
  674.         int sign= 1;
  675.         long n= 0;
  676.  
  677.         if (*a == '-') { sign= -1; a++; }
  678.  
  679.         while (between('0', *a, '9')) n= n * 10 + (*a++ - '0');
  680.  
  681.         return sign * n;
  682. }
  683.  
  684. char *ul2a(u32_t n)
  685. /* Transform a long number to ascii digits. */
  686. {
  687.         static char num[3 * sizeof(n)];
  688.         char *a= arraylimit(num) - 1;
  689.  
  690.         do *--a = (n % 10) + '0'; while ((n/= 10) > 0);
  691.         return a;
  692. }
  693.  
  694. char *u2a(U16_t n)
  695. /* Transform a short number to ascii digits. */
  696. {
  697.         return ul2a(n);
  698. }
  699.  
  700. unsigned a2x(char *a)
  701. /* Ascii to hex. */
  702. {
  703.         unsigned n= 0;
  704.         int c;
  705.  
  706.         for (;;) {
  707.                 c= *a;
  708.                 if (between('0', c, '9')) c= c - '0' + 0x0;
  709.                 else
  710.                 if (between('A', c, 'F')) c= c - 'A' + 0xA;
  711.                 else
  712.                 if (between('a', c, 'f')) c= c - 'a' + 0xa;
  713.                 else
  714.                         break;
  715.                 n= (n<<4) | c;
  716.                 a++;
  717.         }
  718.         return n;
  719. }
  720.  
  721. void get_parameters(void)
  722. {
  723.         char params[SECTOR_SIZE + 1];
  724.         token **acmds;
  725.         int r, fundef= 0;
  726.         static char bus_type[][4] = {
  727.                 "xt", "at", "mca"
  728.         };
  729.         static char vid_type[][4] = {
  730.                 "mda", "cga", "ega", "ega", "vga", "vga"
  731.         };
  732.         static char vid_chrome[][6] = {
  733.                 "mono", "color"
  734.         };
  735.  
  736.         /* Variables that Minix needs: */
  737.         b_setvar(E_SPECIAL|E_VAR|E_DEV, "rootdev", "ram");
  738.         b_setvar(E_SPECIAL|E_VAR|E_DEV, "ramimagedev", "bootdev");
  739.         b_setvar(E_SPECIAL|E_VAR, "ramsize", "0");
  740.         b_setvar(E_SPECIAL|E_VAR, "processor", u2a(getprocessor()));
  741.         b_setvar(E_SPECIAL|E_VAR, "bus", bus_type[get_bus()]);
  742.         b_setvar(E_SPECIAL|E_VAR, "memsize", u2a(get_memsize()));
  743.         b_setvar(E_SPECIAL|E_VAR, "emssize", ul2a(get_ext_memsize()));
  744.         b_setvar(E_SPECIAL|E_VAR, "video", vid_type[get_video()]);
  745.         b_setvar(E_SPECIAL|E_VAR, "chrome", vid_chrome[get_video() & 1]);
  746.  
  747.         /* Variables boot needs: */
  748.         b_setvar(E_SPECIAL|E_VAR, "image", "minix");
  749.         b_setvar(E_SPECIAL|E_FUNCTION, "main", "menu");
  750.  
  751.         /* Default menu function: */
  752.         b_setenv(E_RESERVED|E_FUNCTION, "\1", "=,Start Minix", "boot");
  753.  
  754.         /* Reserved names: */
  755.         b_setvar(E_RESERVED, "boot", null);
  756.         b_setvar(E_RESERVED, "menu", null);
  757.         b_setvar(E_RESERVED, "set", null);
  758.         b_setvar(E_RESERVED, "unset", null);
  759.         b_setvar(E_RESERVED, "save", null);
  760.         b_setvar(E_RESERVED, "ls", null);
  761.         b_setvar(E_RESERVED, "echo", null);
  762.         b_setvar(E_RESERVED, "trap", null);
  763.         b_setvar(E_RESERVED, "help", null);
  764.         b_setvar(E_RESERVED, "exit", null);
  765.  
  766.         /* Tokenize bootparams sector. */
  767.         if ((r= readsectors(mon2abs(params), lowsec+PARAMSEC, 1)) != 0) {
  768.                 readerr(lowsec+PARAMSEC, r);
  769.                 exit(1);
  770.         }
  771.         params[SECTOR_SIZE]= 0;
  772.         acmds= tokenize(&cmds, params, &fundef);
  773.  
  774.         /* Stuff the default action into the command chain. */
  775.         (void) tokenize(acmds, ":;main", &fundef);
  776. }
  777.  
  778. void remote_code(void)
  779. /* A rebooting Minix returns a bit of code for the monitor. */
  780. {
  781.         if (reboot_code != 0) {
  782.                 char code[SECTOR_SIZE + 2];
  783.                 int fundef= 0;
  784.  
  785.                 raw_copy(mon2abs(code), reboot_code, SECTOR_SIZE);
  786.                 code[SECTOR_SIZE]= 0;
  787.                 strcat(code, ";");
  788.                 (void) tokenize(&cmds, code, &fundef);
  789.                 reboot_code= 0;
  790.         }
  791. }
  792.  
  793. char *addptr;
  794.  
  795. void addparm(char *n)
  796. {
  797.         while (*n != 0 && *addptr != 0) *addptr++ = *n++;
  798. }
  799.  
  800. void save_parameters(void)
  801. /* Save nondefault environment variables to the bootparams sector. */
  802. {
  803.         environment *e;
  804.         char params[SECTOR_SIZE + 1];
  805.         int r;
  806.  
  807.         /* Default filling: */
  808.         memset(params, '\n', SECTOR_SIZE);
  809.  
  810.         /* Don't touch the 0! */
  811.         params[SECTOR_SIZE]= 0;
  812.         addptr= params;
  813.  
  814.         for (e= env; e != nil; e= e->next) {
  815.                 if (e->flags & E_RESERVED || is_default(e)) continue;
  816.  
  817.                 addparm(e->name);
  818.                 if (e->flags & E_FUNCTION) {
  819.                         addparm("(");
  820.                         addparm(e->arg);
  821.                         addparm("){");
  822.                 } else {
  823.                         addparm((e->flags & (E_DEV|E_SPECIAL)) != E_DEV
  824.                                                         ? "=" : "=d ");
  825.                 }
  826.                 addparm(e->value);
  827.                 if (e->flags & E_FUNCTION) addparm("}");
  828.                 if (*addptr == 0) {
  829.                         printf("The environment is too big\n");
  830.                         return;
  831.                 }
  832.                 *addptr++= '\n';
  833.         }
  834.  
  835.         /* Save the parameters on disk. */
  836.         if ((r= writesectors(mon2abs(params), lowsec+PARAMSEC, 1)) != 0) {
  837.                 writerr(lowsec+PARAMSEC, r);
  838.                 printf("Can't save environment\n");
  839.         }
  840. }
  841.  
  842. void show_env(void)
  843. /* Show the environment settings. */
  844. {
  845.         environment *e;
  846.  
  847.         for (e= env; e != nil; e= e->next) {
  848.                 if (e->flags & E_RESERVED) continue;
  849.  
  850.                 if (e->flags & E_FUNCTION) {
  851.                         printf("%s(%s) {%s}\n", e->name, e->arg, e->value);
  852.                 } else {
  853.                         printf(is_default(e) ? "%s = (%s)\n" : "%s = %s\n",
  854.                                 e->name, e->value);
  855.                 }
  856.         }
  857. }
  858.  
  859. int numprefix(char *s, char **ps)
  860. /* True iff s is a string of digits.  *ps will be set to the first nondigit
  861.  * if non-nil, otherwise the string should end.
  862.  */
  863. {
  864.         char *n= s;
  865.  
  866.         while (between('0', *n, '9')) n++;
  867.  
  868.         if (n == s) return 0;
  869.  
  870.         if (ps == nil) return *n == 0;
  871.  
  872.         *ps= n;
  873.         return 1;
  874. }
  875.  
  876. int numeric(char *s)
  877. {
  878.         return numprefix(s, (char **) nil);
  879. }
  880.  
  881. /* Device numbers of standard Minix devices. */
  882. #define DEV_RAM         0x0100
  883. #define DEV_FD0         0x0200
  884. #define DEV_HD0         0x0300
  885. #define DEV_SD0         0x0A00
  886. #define minor_1a           128
  887.  
  888. dev_t name2dev(char *name)
  889. /* Translate, say, /dev/hd3 to a device number.  If the name can't be
  890.  * found on the boot device, then do some guesswork.  The global structure
  891.  * "tmpdev" will be filled in based on the name, so that "boot hd6" knows
  892.  * what device to boot without interpreting device numbers.
  893.  */
  894. {
  895.         dev_t dev;
  896.         ino_t ino;
  897.         int drive;
  898.         struct stat st;
  899.         char *n, *s;
  900.  
  901.         /* "boot *hd3" means: make partition 3 active before you boot it. */
  902.         if ((activate= (name[0] == '*'))) name++;
  903.  
  904.         /* The special name "bootdev" must be translated to the boot device. */
  905.         if (strcmp(name, "bootdev") == 0) {
  906.                 if (bootdev.device == -1) {
  907.                         printf("The boot device could not be named\n");
  908.                         errno= 0;
  909.                         return -1;
  910.                 }
  911.                 name= bootdev.name;
  912.         }
  913.  
  914.         /* If our boot device doesn't have a file system, or we want to know
  915.          * what a name means for the BIOS, then we need to interpret the
  916.          * device name ourselves: "fd" = floppy, "hd" = hard disk, etc.
  917.          */
  918.         tmpdev.device= tmpdev.primary= tmpdev.secondary= -1;
  919.         dev= -1;
  920.         n= name;
  921.         if (strncmp(n, "/dev/", 5) == 0) n+= 5;
  922.  
  923.         if (strcmp(n, "ram") == 0) {
  924.                 dev= DEV_RAM;
  925.         } else
  926.         if (n[0] == 'f' && n[1] == 'd' && numeric(n+2)) {
  927.                 /* Floppy. */
  928.                 tmpdev.device= a2l(n+2);
  929.                 dev= DEV_FD0 + tmpdev.device;
  930.         } else
  931.         if ((n[0] == 'h' || n[0] == 's') && n[1] == 'd' && numprefix(n+2, &s)
  932.                 && (*s == 0 || (between('a', *s, 'd') && s[1] == 0))
  933.         ) {
  934.                 /* Hard disk. */
  935.                 dev= a2l(n+2);
  936.                 tmpdev.device= dev / (1 + NR_PARTITIONS);
  937.                 tmpdev.primary= (dev % (1 + NR_PARTITIONS)) - 1;
  938.                 if (*s != 0) {
  939.                         /* Subpartition. */
  940.                         tmpdev.secondary= *s - 'a';
  941.                         dev= minor_1a
  942.                                 + (tmpdev.device * NR_PARTITIONS
  943.                                         + tmpdev.primary) * NR_PARTITIONS
  944.                                 + tmpdev.secondary;
  945.                 }
  946.                 tmpdev.device+= 0x80;
  947.                 dev+= n[0] == 'h' ? DEV_HD0 : DEV_SD0;
  948.         }
  949.  
  950.         /* Look the name up on the boot device for the UNIX device number. */
  951.         if (fsok) {
  952.                 /* The current working directory is "/dev". */
  953.                 ino= r_lookup(r_lookup(ROOT_INO, "dev"), name);
  954.  
  955.                 if (ino != 0) {
  956.                         /* Name has been found, extract the device number. */
  957.                         r_stat(ino, &st);
  958.                         if (!S_ISBLK(st.st_mode)) {
  959.                                 printf("%s is not a block device\n", name);
  960.                                 errno= 0;
  961.                                 return (dev_t) -1;
  962.                         }
  963.                         dev= st.st_rdev;
  964.                 }
  965.         }
  966.  
  967.         if (tmpdev.primary < 0) activate= 0;    /* Careful now! */
  968.  
  969.         if (dev == -1) {
  970.                 printf("Can't recognize '%s' as a device\n", name);
  971.                 errno= 0;
  972.         }
  973.         return dev;
  974. }
  975.  
  976. #if !DOS
  977. #define B_NODEV         -1
  978. #define B_NOSIG         -2
  979.  
  980. int exec_bootstrap(dev_t dev)
  981. /* Load boot sector from the disk or floppy described by tmpdev and execute it.
  982.  * The floppy parameters may not be right for the floppy we want to read, but
  983.  * reading sector 0 seems to be no problem.
  984.  */
  985. {
  986.         int r, n, dirty= 0;
  987.         char master[SECTOR_SIZE];
  988.         struct part_entry *table[NR_PARTITIONS], dummy, *active= &dummy;
  989.         u32_t masterpos;
  990.  
  991.         device= tmpdev.device;
  992.         if (!dev_geometry()) return B_NODEV;
  993.  
  994.         active->lowsec= 0;
  995.  
  996.         /* Select a partition table entry. */
  997.         while (tmpdev.primary >= 0) {
  998.                 masterpos= active->lowsec;
  999.  
  1000.                 if ((r= get_master(master, table, masterpos)) != 0) return r;
  1001.  
  1002.                 active= table[tmpdev.primary];
  1003.  
  1004.                 /* How does one check a partition table entry? */
  1005.                 if (active->sysind == NO_PART) return B_NOSIG;
  1006.  
  1007.                 tmpdev.primary= tmpdev.secondary;
  1008.                 tmpdev.secondary= -1;
  1009.         }
  1010.  
  1011.         if (activate && !active->bootind) {
  1012.                 for (n= 0; n < NR_PARTITIONS; n++) table[n]->bootind= 0;
  1013.                 active->bootind= ACTIVE_FLAG;
  1014.                 dirty= 1;
  1015.         }
  1016.  
  1017.         /* Read the boot sector. */
  1018.         if ((r= readsectors(BOOTPOS, active->lowsec, 1)) != 0) return r;
  1019.  
  1020.         /* Check signature word. */
  1021.         if (get_word(BOOTPOS+SIGNATOFF) != SIGNATURE) return B_NOSIG;
  1022.  
  1023.         /* Write the partition table if a member must be made active. */
  1024.         if (dirty && (r= writesectors(mon2abs(master), masterpos, 1)) != 0)
  1025.                 return r;
  1026.  
  1027.         bootstrap(device, active);
  1028. }
  1029.  
  1030. void boot_device(char *devname)
  1031. /* Boot the device named by devname. */
  1032. {
  1033.         dev_t dev= name2dev(devname);
  1034.         int save_dev= device;
  1035.         int r;
  1036.  
  1037.         if (tmpdev.device < 0) {
  1038.                 if (dev != -1) printf("Can't boot from %s\n", devname);
  1039.                 return;
  1040.         }
  1041.  
  1042.         switch (r= exec_bootstrap(dev)) {
  1043.         case B_NODEV:
  1044.                 printf("%s: device not present\n", devname);
  1045.                 break;
  1046.         case B_NOSIG:
  1047.                 printf("%s is not bootable\n", devname);
  1048.                 break;
  1049.         default:
  1050.                 printf("Can't boot %s: %s\n", devname, bios_err(r));
  1051.         }
  1052.  
  1053.         /* Restore boot device setting. */
  1054.         device= save_dev;
  1055.         (void) dev_geometry();
  1056. }
  1057.  
  1058. #else /* DOS */
  1059.  
  1060. void boot_device(char *devname)
  1061. /* No booting of other devices under DOS */
  1062. {
  1063.         printf("Can't boot devices under MS-DOS\n");
  1064. }
  1065. #endif /* DOS */
  1066.  
  1067. void ls(char *dir)
  1068. /* List the contents of a directory. */
  1069. {
  1070.         ino_t ino;
  1071.         struct stat st;
  1072.         char name[NAME_MAX+1];
  1073.  
  1074.         if (!fsok) return;
  1075.  
  1076.         if ((ino= r_lookup(ROOT_INO, dir)) == 0
  1077.                 || (r_stat(ino, &st), r_readdir(name)) == -1
  1078.         ) {
  1079.                 printf("ls: %s: %s\n", dir, unix_err(errno));
  1080.                 return;
  1081.         }
  1082.         (void) r_readdir(name); /* Skip ".." too. */
  1083.  
  1084.         while ((ino= r_readdir(name)) != 0) printf("%s/%s\n", dir, name);
  1085. }
  1086.  
  1087. u32_t milli_time(void)
  1088. {
  1089.         return get_tick() * MSEC_PER_TICK;
  1090. }
  1091.  
  1092. u32_t milli_since(u32_t base)
  1093. {
  1094.         return (milli_time() + (TICKS_PER_DAY*MSEC_PER_TICK) - base)
  1095.                         % (TICKS_PER_DAY*MSEC_PER_TICK);
  1096. }
  1097.  
  1098. char *Thandler;
  1099. u32_t Tbase, Tcount;
  1100.  
  1101. void unschedule(void)
  1102. /* Invalidate a waiting command. */
  1103. {
  1104.         if (Thandler != nil) {
  1105.                 free(Thandler);
  1106.                 Thandler= nil;
  1107.         }
  1108. }
  1109.  
  1110. void schedule(long msec, char *cmd)
  1111. /* Schedule command at a certain time from now. */
  1112. {
  1113.         unschedule();
  1114.         Thandler= cmd;
  1115.         Tbase= milli_time();
  1116.         Tcount= msec;
  1117. }
  1118.  
  1119. int expired(void)
  1120. /* Check if the timer expired.  If so prepend the scheduled command to
  1121.  * the command chain and return 1.
  1122.  */
  1123. {
  1124.         int fundef= 0;
  1125.  
  1126.         if (Thandler == nil || milli_since(Tbase) < Tcount) return 0;
  1127.  
  1128.         (void) tokenize(tokenize(&cmds, Thandler, &fundef), ";", &fundef);
  1129.         unschedule();
  1130.         return 1;
  1131. }
  1132.  
  1133. int delay(char *msec)
  1134. /* Delay for a given time.  Returns true iff delay was not interrupted.
  1135.  * Make sure no time functions are used if msec == 0, because get_tick()
  1136.  * may do funny things on the original IBM PC (not the XT!).
  1137.  * If msec happens to be the string "swap" then wait till the user hits
  1138.  * return after changing diskettes.
  1139.  */
  1140. {
  1141.         int swap= 0;
  1142.         u32_t base, count;
  1143.  
  1144.         if (strcmp(msec, "swap") == 0) {
  1145.                 swap= 1;
  1146.                 count= 0;
  1147.                 printf("\nInsert the root diskette then hit RETURN\n");
  1148.         } else
  1149.         if ((count= a2l(msec)) > 0) {
  1150.                 base= milli_time();
  1151.         }
  1152.  
  1153.         do {
  1154.                 switch (peekchar()) {
  1155.                 case -1:        break;
  1156.                 case ESC:       interrupt(); return 0;
  1157.                 case '\n':      swap= 0;
  1158.                 default:        (void) getchar();
  1159.                 }
  1160.         } while (!expired()
  1161.                 && (swap || (count > 0 && milli_since(base) < count))
  1162.         );
  1163.         return 1;
  1164. }
  1165.  
  1166. enum whatfun { NOFUN, SELECT, DEFFUN, USERFUN } menufun(environment *e)
  1167. {
  1168.         if (!(e->flags & E_FUNCTION) || e->arg[0] == 0) return NOFUN;
  1169.         if (e->arg[1] != ',') return SELECT;
  1170.         return e->flags & E_RESERVED ? DEFFUN : USERFUN;
  1171. }
  1172.  
  1173. void menu(void)
  1174. /* By default:  Show a simple menu.
  1175.  * Multiple kernels/images:  Show extra selection options.
  1176.  * User defined function:  Kill the defaults and show these.
  1177.  * Wait for a keypress and execute the given function.
  1178.  */
  1179. {
  1180.         int fundef= 0, c, def= 1;
  1181.         char *choice= nil;
  1182.         environment *e;
  1183.  
  1184.         /* Just a default menu? */
  1185.         for (e= env; e != nil; e= e->next) if (menufun(e) == USERFUN) def= 0;
  1186.  
  1187.         printf("\nHit a key as follows:\n\n");
  1188.  
  1189.         /* Show the choices. */
  1190.         for (e= env; e != nil; e= e->next) {
  1191.                 switch (menufun(e)) {
  1192.                 case DEFFUN:
  1193.                         if (!def) break;
  1194.                         /*FALL THROUGH*/
  1195.                 case USERFUN:
  1196.                         printf("    %c  %s\n", e->arg[0], e->arg+2);
  1197.                         break;
  1198.                 case SELECT:
  1199.                         printf("    %c  Select %s kernel\n", e->arg[0],e->name);
  1200.                 }
  1201.         }
  1202.  
  1203.         /* Wait for a keypress. */
  1204.         do {
  1205.                 while (peekchar() == -1) if (expired()) return;
  1206.  
  1207.                 unschedule();
  1208.  
  1209.                 if ((c= getchar()) == ESC) { interrupt(); return; }
  1210.  
  1211.                 for (e= env; e != nil; e= e->next) {
  1212.                         switch (menufun(e)) {
  1213.                         case DEFFUN:
  1214.                                 if (!def) break;
  1215.                         case USERFUN:
  1216.                         case SELECT:
  1217.                                 if (c == e->arg[0]) choice= e->value;
  1218.                         }
  1219.                 }
  1220.         } while (choice == nil);
  1221.  
  1222.         /* Execute the chosen function. */
  1223.         printf("%c\n", c);
  1224.         (void) tokenize(&cmds, choice, &fundef);
  1225. }
  1226.  
  1227. void help(void)
  1228. /* Not everyone is a rocket scientist. */
  1229. {
  1230.         struct help {
  1231.                 char    *thing;
  1232.                 char    *help;
  1233.         } *pi;
  1234.         static struct help info[] = {
  1235.                 { nil,  "Names:" },
  1236.                 { "rootdev",            "Root device" },
  1237.                 { "ramimagedev",        "RAM disk image if root is RAM" },
  1238.                 { "ramsize",            "RAM disk size if root is not RAM" },
  1239.                 { "bootdev",            "Special name for the boot device" },
  1240.                 { "fd0, hd3, hd2a",     "Devices (as in /dev)" },
  1241.                 { "image",              "Name of the kernel image" },
  1242.                 { "main",               "Startup function" },
  1243.                 { nil,  "Commands:" },
  1244.                 { "name = [device] value",  "Set environment variable" },
  1245.                 { "name() { ... }",         "Define function" },
  1246.                 { "name(key,text) { ... }",
  1247.                         "A menu function like: minix(=,Start Minix) {boot}" },
  1248.                 { "name",               "Call function" },
  1249.                 { "boot [device]",      "Boot Minix or another O.S." },
  1250.                 { "delay [msec]",       "Delay (500 msec default)" },
  1251.                 { "echo word ...",      "Print the words" },
  1252.                 { "ls [directory]",     "List contents of directory" },
  1253.                 { "menu",               "Choose a menu function" },
  1254.                 { "save",               "Save environment" },
  1255.                 { "set",                "Show environment" },
  1256.                 { "trap msec command",  "Schedule command" },
  1257.                 { "unset name ...",     "Unset variable or set to default" },
  1258.                 { "exit",               "Exit the Monitor" },
  1259.         };
  1260.  
  1261.         for (pi= info; pi < arraylimit(info); pi++) {
  1262.                 if (pi->thing != nil) printf("    %-24s- ", pi->thing);
  1263.                 printf("%s\n", pi->help);
  1264.         }
  1265. }
  1266.  
  1267. void execute(void)
  1268. /* Get one command from the command chain and execute it. */
  1269. {
  1270.         token *second, *third, *fourth, *fifth, *sep;
  1271.         char *name= cmds->token;
  1272.         size_t n= 0;
  1273.  
  1274.         /* There must be a separator lurking somewhere. */
  1275.         for (sep= cmds; sep != nil && sep->token[0] != ';'; sep= sep->next) n++;
  1276.  
  1277.         if ((second= cmds->next) != nil
  1278.                 && (third= second->next) != nil
  1279.                 && (fourth= third->next) != nil)
  1280.                         fifth= fourth->next;
  1281.  
  1282.                 /* Null command? */
  1283.         if (n == 0) {
  1284.                 voidtoken();
  1285.                 return;
  1286.         } else
  1287.                 /* name = [device] value? */
  1288.         if ((n == 3 || n == 4)
  1289.                 && !sugar(name)
  1290.                 && second->token[0] == '='
  1291.                 && !sugar(third->token)
  1292.                 && (n == 3 || (n == 4 && third->token[0] == 'd'
  1293.                                         && !sugar(fourth->token)
  1294.         ))) {
  1295.                 char *value= third->token;
  1296.                 int flags= E_VAR;
  1297.  
  1298.                 if (n == 4) { value= fourth->token; flags|= E_DEV; }
  1299.  
  1300.                 if ((flags= b_setvar(flags, name, value)) != 0) {
  1301.                         printf("%s is a %s\n", name,
  1302.                                 flags & E_RESERVED ? "reserved word" :
  1303.                                                 "special function");
  1304.                         err= 1;
  1305.                 }
  1306.                 while (cmds != sep) voidtoken();
  1307.                 return;
  1308.         } else
  1309.                 /* name '(' arg ')' '{' ... '}'? */
  1310.         if (n >= 5
  1311.                 && !sugar(name)
  1312.                 && second->token[0] == '('
  1313.                 && fourth->token[0] == ')'
  1314.                 && fifth->token[0] == '{'
  1315.         ) {
  1316.                 token *fun= fifth->next;
  1317.                 int ok= 1, flags;
  1318.                 char *body;
  1319.                 size_t len= 1;
  1320.  
  1321.                 sep= fun;
  1322.                 while (sep != nil && sep->token[0] != '}') {
  1323.                         len+= strlen(sep->token) + 1;
  1324.                         sep= sep->next;
  1325.                 }
  1326.                 if (sep == nil || (sep= sep->next) == nil
  1327.                         || sep->token[0] != ';'
  1328.                 ) ok= 0;
  1329.  
  1330.                 if (ok) {
  1331.                         body= malloc(len * sizeof(char));
  1332.                         *body= 0;
  1333.  
  1334.                         while (fun->token[0] != '}') {
  1335.                                 strcat(body, fun->token);
  1336.                                 if (!sugar(fun->token)
  1337.                                         && !sugar(fun->next->token)
  1338.                                 ) strcat(body, " ");
  1339.                                 fun= fun->next;
  1340.                         }
  1341.  
  1342.                         if ((flags= b_setenv(E_FUNCTION, name,
  1343.                                                 third->token, body)) != 0) {
  1344.                                 printf("%s is a %s\n", name,
  1345.                                         flags & E_RESERVED ? "reserved word" :
  1346.                                                         "special variable");
  1347.                                 err= 1;
  1348.                         }
  1349.                         while (cmds != sep) voidtoken();
  1350.                         free(body);
  1351.                         return;
  1352.                 }
  1353.         } else
  1354.                 /* Command coming up, check if ESC typed. */
  1355.         if (peekchar() == ESC) {
  1356.                 interrupt();
  1357.                 return;
  1358.         } else
  1359.                 /* unset name ..., echo word ...? */
  1360.         if (n >= 1 && (
  1361.                 strcmp(name, "unset") == 0
  1362.                 || strcmp(name, "echo") == 0
  1363.         )) {
  1364.                 int cmd= name[0];
  1365.                 char *arg= poptoken();
  1366.  
  1367.                 for (;;) {
  1368.                         free(arg);
  1369.                         if (cmds == sep) break;
  1370.                         arg= poptoken();
  1371.                         if (cmd == 'u') {
  1372.                                 b_unset(arg);
  1373.                         } else {
  1374.                                 printf("%s", arg);
  1375.                                 if (cmds != sep) putchar(' ');
  1376.                         }
  1377.                 }
  1378.                 if (cmd == 'e') putchar('\n');
  1379.                 return;
  1380.         } else
  1381.                 /* boot -opts? */
  1382.         if (n == 2 && strcmp(name, "boot") == 0 && second->token[0] == '-') {
  1383.                 static char optsvar[]= "bootopts";
  1384.                 (void) b_setvar(E_VAR, optsvar, second->token);
  1385.                 bootminix();
  1386.                 b_unset(optsvar);
  1387.                 voidtoken();
  1388.                 voidtoken();
  1389.                 return;
  1390.         } else
  1391.                 /* boot device, ls dir, delay msec? */
  1392.         if (n == 2 && (
  1393.                 strcmp(name, "boot") == 0
  1394.                 || strcmp(name, "delay") == 0
  1395.                 || strcmp(name, "ls") == 0
  1396.         )) {
  1397.                 if (name[0] == 'b') boot_device(second->token);
  1398.                 if (name[0] == 'd') (void) delay(second->token);
  1399.                 if (name[0] == 'l') ls(second->token);
  1400.                 voidtoken();
  1401.                 voidtoken();
  1402.                 return;
  1403.         } else
  1404.                 /* trap msec command? */
  1405.         if (n == 3 && strcmp(name, "trap") == 0 && numeric(second->token)) {
  1406.                 long msec= a2l(second->token);
  1407.  
  1408.                 voidtoken();
  1409.                 voidtoken();
  1410.                 schedule(msec, poptoken());
  1411.                 return;
  1412.         } else
  1413.                 /* Simple command. */
  1414.         if (n == 1) {
  1415.                 char *cmd= poptoken();
  1416.                 char *body;
  1417.                 int fundef= 0;
  1418.                 int ok= 0;
  1419.  
  1420.                 if (strcmp(cmd, "boot") == 0) { bootminix(); ok= 1; }
  1421.                 if (strcmp(cmd, "delay") == 0) { (void) delay("500"); ok= 1; }
  1422.                 if (strcmp(cmd, "ls") == 0) { ls(null); ok= 1; }
  1423.                 if (strcmp(cmd, "menu") == 0) { menu(); ok= 1; }
  1424.                 if (strcmp(cmd, "save") == 0) { save_parameters(); ok= 1; }
  1425.                 if (strcmp(cmd, "set") == 0) { show_env(); ok= 1; }
  1426.                 if (strcmp(cmd, "help") == 0) { help(); ok= 1; }
  1427.                 if (strcmp(cmd, "exit") == 0) { exit(0); }
  1428.  
  1429.                 /* Command to check bootparams: */
  1430.                 if (strcmp(cmd, ":") == 0) ok= 1;
  1431.  
  1432.                 /* User defined function. */
  1433.                 if (!ok && (body= b_body(cmd)) != nil) {
  1434.                         (void) tokenize(&cmds, body, &fundef);
  1435.                         ok= 1;
  1436.                 }
  1437.                 if (!ok) printf("%s: unknown function", cmd);
  1438.                 free(cmd);
  1439.                 if (ok) return;
  1440.         } else {
  1441.                 /* Syntax error. */
  1442.                 printf("Can't parse:");
  1443.                 while (cmds != sep) {
  1444.                         printf(" %s", cmds->token); voidtoken();
  1445.                 }
  1446.         }
  1447.  
  1448.         /* Getting here means that the command is not understood. */
  1449.         printf("\nTry 'help'\n");
  1450.         err= 1;
  1451. }
  1452.  
  1453. void monitor(void)
  1454. /* Read one or more lines and tokenize them. */
  1455. {
  1456.         char *line;
  1457.         int fundef= 0;
  1458.         token **acmds= &cmds;
  1459.  
  1460.         unschedule();   /* Kill a trap. */
  1461.  
  1462.         do {
  1463.                 printf("%s%c", bootdev.name, fundef == 0 ? '>' : '+');
  1464.                 line= readline();
  1465.                 acmds= tokenize(acmds, line, &fundef);
  1466.                 free(line);
  1467.         } while (fundef != 0);
  1468. }
  1469.  
  1470. void boot(void)
  1471. /* Load Minix and start it, among other things. */
  1472. {
  1473.         /* Print greeting message.  The copyright message is not yet displayed,
  1474.          * because this boot program need not necessarily start Minix.
  1475.          */
  1476.         reset_video(get_video() & 1 ? COLOR_MODE : MONO_MODE);
  1477.  
  1478.         printf("\nMinix boot monitor %s\n", version);
  1479.         printf("\nPress ESC to enter the monitor\n");
  1480.  
  1481.         /* Initialize tables under DOS. */
  1482.         if (DOS) initialize();
  1483.  
  1484.         /* Relocate program to the end of memory. */
  1485.         migrate();
  1486.  
  1487.         /* Initialize tables under the BIOS. */
  1488.         if (!DOS) initialize();
  1489.  
  1490.         /* Block cache. */
  1491.         init_cache();
  1492.  
  1493.         /* Get environment variables from the parameter sector. */
  1494.         get_parameters();
  1495.  
  1496.         /* Read and check the superblock. */
  1497.         fsok= r_super() != 0;
  1498.  
  1499.         while (1) {
  1500.                 /* While there are commands, execute them! */
  1501.                 while (cmds != nil) {
  1502.                         execute();
  1503.                         if (err) {
  1504.                                 /* An error, stop interpreting. */
  1505.                                 while (cmds != nil) voidtoken();
  1506.                                 err= 0;
  1507.                                 break;
  1508.                         }
  1509.                         (void) expired();
  1510.                         remote_code();
  1511.                 }
  1512.                 /* The "monitor" is just a "read one command" thing. */
  1513.                 monitor();
  1514.         }
  1515. }

Paste is for source code and general debugging text.

Login or Register to edit, delete and keep track of your pastes and more.

Raw Paste

Login or Register to edit or fork this paste. It's free.