boot - Add a ton of features to the boot loader & adjust default menu
authorMatthew Dillon <dillon@apollo.backplane.com>
Sun, 24 Oct 2010 02:03:51 +0000 (19:03 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Sun, 24 Oct 2010 02:16:29 +0000 (19:16 -0700)
* Add conditionals ifset ifexists else elseifexists and endif

* Conditionalize dloader.menu to only present menu options for which
  the related kernels are present in /boot.

* Set the default kernel to one of:

  kernel, kernel.GENERIC, kernel.GENERIC_SMP, kernel.X86_64_GENERIC,
  or kernel.X86_64_GENERIC_SMP.  The first one in the list found becomes
  the default.

* If ${default_kernel}_SMP is available supply a menu option to change
  the default to that kernel, aka UP->SMP

* If kernel.X86_64_GENERIC[_SMP] is available and the current default is
  not the same supply menu options to change the default to the 64-bit
  UP or SMP kernel.

  Note however that for this to work the related boot kernel directory
  had better have a loader.conf.local in it that points the root mount
  to a 64-bit root 'cause 64-bit kernels can't run 32 bit binaries yet.

* Adjust the menu item execution code to copy the items before executing
  them, allowing recursive menu execution.  The recursive menu feature
  is a bit of a hack right now however.

* NOTE: the optcd for people ESCaping into the boot prompt was moved
  to dloader.rc, when updating you may have to manually reinstall that
  file to get the functionality.

sys/boot/common/bootstrap.h
sys/boot/common/commands.c
sys/boot/common/do_dloader.c
sys/boot/dloader/cmds.c
sys/boot/dloader/dloader.h
sys/boot/dloader/dloader.menu
sys/boot/dloader/subs.c
sys/boot/pc32/loader/dloader.rc

index 5187c0d..8153551 100644 (file)
@@ -50,6 +50,7 @@ struct devdesc
 typedef int    (bootblk_cmd_t)(int argc, char *argv[]);
 extern char    *command_errmsg;        
 extern char    command_errbuf[];       /* XXX blah, length */
+extern int     CurrentCondition;
 #define CMD_OK         0
 #define CMD_ERROR      1
 
@@ -265,11 +266,17 @@ struct bootblk_command
     const char         *c_name;
     const char         *c_desc;
     bootblk_cmd_t      *c_fn;
+    int                        c_cond;
 };
 
 #define COMMAND_SET(tag, key, desc, func)                              \
     static bootblk_cmd_t func;                                         \
-    static struct bootblk_command _cmd_ ## tag = { key, desc, func };  \
+    static struct bootblk_command _cmd_ ## tag = { key, desc, func, 0 };\
+    DATA_SET(Xcommand_set, _cmd_ ## tag)
+
+#define COMMAND_SET_COND(tag, key, desc, func)                         \
+    static bootblk_cmd_t func;                                         \
+    static struct bootblk_command _cmd_ ## tag = { key, desc, func, 1 };\
     DATA_SET(Xcommand_set, _cmd_ ## tag)
 
 SET_DECLARE(Xcommand_set, struct bootblk_command);
index 2cac41f..1ecb50b 100644 (file)
@@ -33,7 +33,8 @@
 #include "bootstrap.h"
 
 char           *command_errmsg;
-char           command_errbuf[256];    /* XXX should have procedural interface for setting, size limit? */
+char           command_errbuf[256];
+int            CurrentCondition = 1;
 
 static int page_file(char *filename);
 
@@ -496,3 +497,141 @@ command_lsdev(int argc, char *argv[])
     return(CMD_OK);
 }
 
+/*
+ * CONDITIONALS
+ */
+COMMAND_SET_COND(ifexists, "ifexists", "conditional f/d present",
+                command_ifexists);
+
+struct cond {
+    char    inherit;
+    char    current;
+};
+
+static struct cond CondStack[32];
+static int CondIndex;
+
+static int
+command_ifexists(int argc, char *argv[])
+{
+       if (CondIndex + 1 == sizeof(CondStack)/sizeof(CondStack[0])) {
+               sprintf(command_errbuf, "if stack too deep");
+               return(-1);
+       } else if (argc != 2) {
+               sprintf(command_errbuf, "ifexists requires one argument");
+               return(-1);
+       } else {
+               struct stat sb;
+               struct cond *cond = &CondStack[CondIndex++];
+
+               cond->inherit = CurrentCondition;
+
+               if (rel_stat(argv[1], &sb)) {
+                       cond->current = 0;
+               } else {
+                       cond->current = 1;
+               }
+               CurrentCondition = (cond->inherit && cond->current);
+               return(CMD_OK);
+       }
+}
+
+COMMAND_SET_COND(ifset, "ifset", "conditional kenv present", command_ifset);
+
+static int
+command_ifset(int argc, char *argv[])
+{
+       if (CondIndex + 1 == sizeof(CondStack)/sizeof(CondStack[0])) {
+               sprintf(command_errbuf, "if stack too deep");
+               return(-1);
+       } else if (argc != 2) {
+               sprintf(command_errbuf, "ifexists requires one argument");
+               return(-1);
+       } else {
+               struct cond *cond = &CondStack[CondIndex++];
+
+               cond->inherit = CurrentCondition;
+
+               if (getenv(argv[1])) {
+                       cond->current = 1;
+               } else {
+                       cond->current = 0;
+               }
+               CurrentCondition = (cond->inherit && cond->current);
+               return(CMD_OK);
+       }
+}
+
+COMMAND_SET_COND(elseifexists, "elseifexists", "conditional f/d present",
+                command_elseifexists);
+
+static int
+command_elseifexists(int argc, char *argv[])
+{
+       if (CondIndex == 0) {
+               sprintf(command_errbuf, "elseifexists without if");
+               return(-1);
+       } else if (argc != 2) {
+               sprintf(command_errbuf, "ifexists requires one argument");
+               return(-1);
+       } else {
+               struct stat sb;
+               struct cond *cond = &CondStack[CondIndex - 1];
+
+               if (cond->inherit == 0) {
+                       CurrentCondition = 0;   /* already ran / can't run */
+               } else if (cond->current) {
+                       cond->inherit = 0;      /* can't run any more */
+                       cond->current = 0;
+                       CurrentCondition = 0;
+               } else {
+                       if (rel_stat(argv[1], &sb)) {
+                               cond->current = 0;
+                       } else {
+                               cond->current = 1;
+                       }
+                       CurrentCondition = (cond->inherit && cond->current);
+               }
+               return(CMD_OK);
+       }
+}
+
+COMMAND_SET_COND(else, "else", "cond if/else/endif", command_else);
+
+static int
+command_else(int argc, char *argv[])
+{
+       struct cond *cond;
+
+       if (CondIndex) {
+               cond = &CondStack[CondIndex - 1];
+               cond->current = !cond->current;
+               CurrentCondition = (cond->inherit && cond->current);
+               return(CMD_OK);
+       } else {
+               sprintf(command_errbuf, "else without if");
+               return(-1);
+       }
+}
+
+COMMAND_SET_COND(endif, "endif", "cond if/else/endif", command_endif);
+
+static int
+command_endif(int argc, char *argv[])
+{
+       struct cond *cond;
+
+       if (CondIndex) {
+               --CondIndex;
+               if (CondIndex) {
+                       cond = &CondStack[CondIndex - 1];
+                       CurrentCondition = (cond->inherit && cond->current);
+               } else {
+                       CurrentCondition = 1;
+               }
+               return(CMD_OK);
+       } else {
+               sprintf(command_errbuf, "endif without if");
+               return(-1);
+       }
+}
index b589b11..213c7fa 100644 (file)
@@ -67,11 +67,16 @@ perform(int argc, char *argv[])
 
     /* search the command set for the command */
     SET_FOREACH(cmdp, Xcommand_set) {
-       if (((*cmdp)->c_name != NULL) && !strcmp(av0, (*cmdp)->c_name))
+       if (((*cmdp)->c_name != NULL) && !strcmp(av0, (*cmdp)->c_name)) {
            cmd = (*cmdp)->c_fn;
+           break;
+       }
     }
     if (cmd != NULL) {
-       result = (cmd)(argc, argv);
+       if ((*cmdp)->c_cond || CurrentCondition != 0)
+               result = (cmd)(argc, argv);
+       else
+               result = CMD_OK;
     } else {
        command_errmsg = "unknown command";
     }
index e29bfc5..24f091a 100644 (file)
@@ -411,9 +411,6 @@ command_menu(int ac, char **av)
                        }
                        if (c == 0x1b) {
                                setenv("autoboot_delay", "NO", 1);
-                               argv[0] = "optcd";
-                               argv[1] = "kernel";
-                               (void)perform(2, argv);
                                return(CMD_OK);
                        }
                        res = menu_execute(c);
@@ -577,11 +574,11 @@ static int
 menu_execute(int c)
 {
        dvar_t dvar;
+       dvar_t dvar_exec = NULL;
+       dvar_t *dvar_execp = &dvar_exec;
        char namebuf[32];
        int res;
 
-       printf("\n");
-
        snprintf(namebuf, sizeof(namebuf), "item_%c_0", c);
 
        /*
@@ -592,16 +589,37 @@ menu_execute(int c)
 
        snprintf(namebuf, sizeof(namebuf), "item_%c", c);
        res = CMD_OK;
+       printf("\n");
+
+       /*
+        * Copy the items to execute (the act of execution may modify our
+        * local variables so we need to copy).
+        */
        for (dvar = dvar_first(); dvar; dvar = dvar_next(dvar)) {
                if (strncmp(dvar->name, namebuf, 6) == 0) {
-                       res = perform(dvar->count, dvar->data);
-                       if (res != CMD_OK) {
-                               printf("%s: %s\n",
-                                       dvar->data[0], command_errmsg);
-                               setenv("autoboot_delay", "NO", 1);
-                               break;
-                       }
+                       *dvar_execp = dvar_copy(dvar);
+                       dvar_execp = &(*dvar_execp)->next;
                }
        }
+
+       /*
+        * Execute items
+        */
+       for (dvar = dvar_exec; dvar; dvar = dvar->next) {
+               res = perform(dvar->count, dvar->data);
+               if (res != CMD_OK) {
+                       printf("%s: %s\n",
+                               dvar->data[0], command_errmsg);
+                       setenv("autoboot_delay", "NO", 1);
+                       break;
+               }
+       }
+
+       /*
+        * Free items
+        */
+       while (dvar_exec)
+               dvar_free(&dvar_exec);
+
        return(res);
 }
index ea2d981..e76f2ad 100644 (file)
@@ -49,4 +49,7 @@ void dvar_set(const char *name, char **data, int count);
 void dvar_unset(const char *name);
 dvar_t dvar_first(void);
 dvar_t dvar_next(dvar_t var);
+dvar_t dvar_copy(dvar_t var);
+void dvar_free(dvar_t *lastp);
+
 int perform(int ac, char **av);
index 09af224..bb93753 100644 (file)
@@ -28,8 +28,27 @@ acpi_load="YES"
 ahci_load="YES"
 ehci_load="YES"
 
-menuitem 1 "Boot DragonFly [default]"
-menuadd optcd kernel
+# Default boot /boot/kernel/ is the user-installed kernel and
+# is always checked first.  Otherwise fallback to generic kernels.
+#
+ifset default_kernel
+    # already selected a kernel
+elseifexists kernel
+    set default_kernel=kernel
+elseifexists kernel.GENERIC
+    set default_kernel=kernel.GENERIC
+elseifexists kernel.GENERIC_SMP
+    set default_kernel=kernel.GENERIC_SMP
+elseifexists kernel.X86_64_GENERIC
+    set default_kernel=kernel.X86_64_GENERIC
+elseifexists kernel.X86_64_GENERIC_SMP
+    set default_kernel=kernel.X86_64_GENERIC_SMP
+else
+    set default_kernel=kernel
+endif
+
+menuitem 1 "Boot DragonFly [${default_kernel}]"
+menuadd cd ${base}${default_kernel}
 menuadd optinclude loader.conf
 menuadd optinclude loader.conf.local
 menuadd lunsetif acpi_load hint.acpi.0.disabled
@@ -39,7 +58,7 @@ menuadd loadall
 menuadd boot
 
 menuitem 2 "Boot DragonFly in Safe Mode"
-menuadd optcd kernel
+menuadd cd ${base}${default_kernel}
 menuadd optinclude loader.conf
 menuadd optinclude loader.conf.local
 menuadd set hint.acpi.0.disabled=1
@@ -58,7 +77,7 @@ menuadd boot
 menuadd set autoboot_delay=NO
 
 menuitem 3 "Boot DragonFly without AHCI driver"
-menuadd optcd kernel
+menuadd cd ${base}${default_kernel}
 menuadd optinclude loader.conf
 menuadd optinclude loader.conf.local
 menuadd set hint.ahci.disabled=YES
@@ -70,7 +89,7 @@ menuadd boot
 menuadd set autoboot_delay=NO
 
 menuitem 4 "Boot DragonFly without ACPI driver"
-menuadd cd ${base}kernel
+menuadd cd ${base}${default_kernel}
 menuadd optinclude loader.conf
 menuadd optinclude loader.conf.local
 menuadd set hint.acpi.0.disabled=1
@@ -83,9 +102,10 @@ menuadd boot
 menuadd set autoboot_delay=NO
 
 menuitem 9 "Escape to loader prompt (also ESC)"
-menuadd optcd kernel
+menuadd optcd ${base}${default_kernel}
 menuadd set autoboot_delay=NO
 
+ifexists kernel.alt
 menuitem a "Boot Backup kernel kernel.alt"
 menuadd cd ${base}kernel.alt
 menuadd optinclude loader.conf
@@ -96,7 +116,9 @@ menuadd lunsetif ahci_load hint.ahci.disabled
 menuadd loadall
 menuadd boot
 menuadd set autoboot_delay=NO
+endif
 
+ifexists kernel.bak
 menuitem b "Boot Backup kernel kernel.bak"
 menuadd cd ${base}kernel.bak
 menuadd optinclude loader.conf
@@ -107,7 +129,9 @@ menuadd lunsetif ahci_load hint.ahci.disabled
 menuadd loadall
 menuadd boot
 menuadd set autoboot_delay=NO
+endif
 
+ifexists kernel.old
 menuitem o "Boot DragonFly using kernel.old"
 menuadd cd ${base}kernel.old
 menuadd optinclude loader.conf
@@ -118,9 +142,10 @@ menuadd lunsetif ahci_load hint.ahci.disabled
 menuadd loadall
 menuadd boot
 menuadd set autoboot_delay=NO
+endif
 
 menuitem s "Boot DragonFly in single user mode"
-menuadd optcd kernel
+menuadd cd ${base}${default_kernel}
 menuadd optinclude loader.conf
 menuadd optinclude loader.conf.local
 menuadd set boot_single="YES"
@@ -132,7 +157,7 @@ menuadd boot
 menuadd set autoboot_delay=NO
 
 menuitem v "Boot DragonFly with verbose logging"
-menuadd optcd kernel
+menuadd cd ${base}${default_kernel}
 menuadd optinclude loader.conf
 menuadd optinclude loader.conf.local
 menuadd set boot_verbose=YES
@@ -143,5 +168,29 @@ menuadd loadall
 menuadd boot
 menuadd set autoboot_delay=NO
 
+ifexists ${default_kernel}_SMP
+menuitem m "Select SMP kernel"
+menuadd set default_kernel=${default_kernel}_SMP
+menuadd include ${base}defaults/dloader.menu
+menuadd optinclude ${base}dloader.menu
+menuadd menu
+endif
+
+ifexists ${base}kernel.X86_64_GENERIC
+menuitem x "Select 64-bit UP kernel"
+menuadd set default_kernel=kernel.X86_64_GENERIC
+menuadd include ${base}defaults/dloader.menu
+menuadd optinclude ${base}dloader.menu
+menuadd menu
+endif
+
+ifexists ${base}kernel.X86_64_GENERIC_SMP
+menuitem y "Select 64-bit SMP kernel"
+menuadd set default_kernel=kernel.X86_64_GENERIC_SMP
+menuadd include ${base}defaults/dloader.menu
+menuadd optinclude ${base}dloader.menu
+menuadd menu
+endif
+
 menuitem R "Reboot"
 menuadd reboot
index 1bbe4f5..2857f7a 100644 (file)
@@ -37,8 +37,6 @@
 #include "bootstrap.h"
 #include "dloader.h"
 
-static void dvar_free(dvar_t *lastp);
-
 dvar_t dvbase;
 dvar_t *dvlastp = &dvbase;
 
@@ -83,6 +81,24 @@ dvar_set(const char *name, char **data, int count)
                var->data[count] = strdup(data[count]);
 }
 
+dvar_t
+dvar_copy(dvar_t ovar)
+{
+       dvar_t var;
+       int count;
+
+       var = malloc(sizeof(*var));
+       bzero(var, sizeof(*var));
+       count = ovar->count;
+
+       var->count = count;
+       var->data = malloc(sizeof(char *) * (count + 1));
+       var->data[count] = NULL;
+       while (--count >= 0)
+               var->data[count] = strdup(ovar->data[count]);
+       return (var);
+}
+
 void
 dvar_unset(const char *name)
 {
@@ -123,7 +139,19 @@ dvar_next(dvar_t var)
        return(var->next);
 }
 
-static void
+dvar_t *
+dvar_firstp(void)
+{
+       return(&dvbase);
+}
+
+dvar_t *
+dvar_nextp(dvar_t var)
+{
+       return(&var->next);
+}
+
+void
 dvar_free(dvar_t *lastp)
 {
        dvar_t dvar = *lastp;
index 74044d3..3c2fd40 100644 (file)
@@ -11,4 +11,5 @@ optinclude dloader.menu
 optinclude loader.conf
 optinclude loader.conf.local
 
+optcd ${base}${default_kernel}
 menu