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
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);
#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);
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);
+ }
+}
/* 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";
}
}
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);
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);
/*
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);
}
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);
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
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
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
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
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
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
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
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"
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
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
#include "bootstrap.h"
#include "dloader.h"
-static void dvar_free(dvar_t *lastp);
-
dvar_t dvbase;
dvar_t *dvlastp = &dvbase;
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)
{
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;
optinclude loader.conf
optinclude loader.conf.local
+optcd ${base}${default_kernel}
menu