]> git.ozlabs.org Git - petitboot/blobdiff - discover/grub2/script.c
discover/grub2: Allow to separate the --id argument using a space char
[petitboot] / discover / grub2 / script.c
index 36f73b21abfc4a0992a5a8a5540382d6102581c1..8a9d91dac987c36680283f8b9c95cfdf6ac15fb5 100644 (file)
@@ -103,7 +103,7 @@ static bool is_delim(char c)
 }
 
 static bool option_is_default(struct grub2_script *script,
-               struct discover_boot_option *opt, const char *id)
+                             struct discover_boot_option *opt, const char *id)
 {
        unsigned int default_idx;
        const char *var;
@@ -117,12 +117,10 @@ static bool option_is_default(struct grub2_script *script,
        if (end != var && *end == '\0')
                return default_idx == script->n_options;
 
-       /* if we don't have an explicit id for this option, fall back to
-        * the name */
-       if (!id)
-               id = opt->option->name;
+       if (id && !strcmp(id, var))
+               return true;
 
-       return !strcmp(id, var);
+       return !strcmp(opt->option->name, var);
 }
 
 static void append_text_to_current_arg(struct grub2_argv *argv,
@@ -227,7 +225,7 @@ static void process_expansions(struct grub2_script *script,
        }
 
        /* we may have allocated an extra argv element but not populated it */
-       if (!argv->argv[argv->argc - 1])
+       if (argv->argv && !argv->argv[argv->argc - 1])
                argv->argc--;
 }
 
@@ -341,9 +339,16 @@ int statement_menuentry_execute(struct grub2_script *script,
         * implementation to get --id= working.
         */
        for (i = 1; i < st->argv->argc; ++i) {
-               if (strncmp("--id=", st->argv->argv[i], 5) == 0) {
-                       id = st->argv->argv[i] + 5;
-                       break;
+               if (strncmp("--id", st->argv->argv[i], strlen("--id")) == 0) {
+                       if (strlen(st->argv->argv[i]) > strlen("--id=")) {
+                               id = st->argv->argv[i] + strlen("--id=");
+                               break;
+                       }
+
+                       if (i + 1 < st->argv->argc) {
+                               id = st->argv->argv[i + 1];
+                               break;
+                       }
                }
        }
        if (st->argv->argc > 0)
@@ -364,7 +369,7 @@ int statement_menuentry_execute(struct grub2_script *script,
 
        opt->option->is_default = option_is_default(script, opt, id);
 
-       discover_context_add_boot_option(script->ctx, opt);
+       list_add_tail(&script->options, &opt->list);
        script->n_options++;
        script->opt = NULL;
 
@@ -379,8 +384,8 @@ static int function_invoke(struct grub2_script *script,
        int i;
 
        /* set positional parameters */
-       for (i = 0; i < argc; i++) {
-               name = talloc_asprintf(script, "$%d", i);
+       for (i = 1; i < argc; i++) {
+               name = talloc_asprintf(script, "%d", i);
                script_env_set(script, name, argv[i]);
        }
 
@@ -463,11 +468,46 @@ void script_register_function(struct grub2_script *script,
        list_add(&script->symtab, &entry->list);
 }
 
+static void set_fallback_default(struct grub2_script *script)
+{
+       struct discover_boot_option *opt, *first = NULL;
+       bool have_default = false;
+
+       list_for_each_entry(&script->options, opt, list) {
+               if (!first)
+                       first = opt;
+               have_default = have_default || opt->option->is_default;
+       }
+
+       if (!have_default && first) {
+               const char *env = script_env_get(script, "default");
+
+               pb_log("grub: no explicit default (env default=%s), "
+                               "falling back to first option (%s)\n",
+                               env ?: "unset", first->option->name);
+
+               first->option->is_default = true;
+       }
+}
 
 void script_execute(struct grub2_script *script)
 {
+       struct discover_boot_option *opt, *tmp;
+
+       if (!script)
+               return;
+
        init_env(script);
        statements_execute(script, script->statements);
+
+       set_fallback_default(script);
+
+       list_for_each_entry_safe(&script->options, opt, tmp, list)
+               discover_context_add_boot_option(script->ctx, opt);
+
+       /* Our option list will be invalid, as we've added all options to the
+        * discover context */
+       list_init(&script->options);
 }
 
 struct grub2_script *create_script(struct grub2_parser *parser,
@@ -480,6 +520,7 @@ struct grub2_script *create_script(struct grub2_parser *parser,
        script->ctx = ctx;
 
        list_init(&script->symtab);
+       list_init(&script->options);
        register_builtins(script);
 
        return script;