X-Git-Url: http://git.ozlabs.org/?p=petitboot;a=blobdiff_plain;f=discover%2Fgrub2%2Fblscfg.c;h=d4754aa363dfa0812d2feb9b7ced5be6e03b7aa9;hp=5dadd2c6e8efde1ccf2eaf37af2893f4825c1cef;hb=336f4eb17fb50526ea9fda82262356581e1b9ae0;hpb=f78714f16515783d79e636040cedccb3eb6611a3 diff --git a/discover/grub2/blscfg.c b/discover/grub2/blscfg.c index 5dadd2c..d4754aa 100644 --- a/discover/grub2/blscfg.c +++ b/discover/grub2/blscfg.c @@ -2,6 +2,7 @@ #define _GNU_SOURCE #include +#include #include #include #include @@ -15,11 +16,16 @@ #include "discover/parser-conf.h" #include "discover/parser.h" -#define BLS_DIR "/loader/entries" +static const char *const bls_dirs[] = { + "/loader/entries", + "/boot/loader/entries", + NULL +}; struct bls_state { struct discover_boot_option *opt; struct grub2_script *script; + unsigned int idx; const char *filename; const char *title; const char *version; @@ -29,71 +35,129 @@ struct bls_state { const char *dtb; }; +static char *field_append(struct bls_state *state, int type, char *buffer, + char *start, char *end) +{ + char *temp = talloc_strndup(state, start, end - start + 1); + const char *field = temp; + + if (type == GRUB2_WORD_VAR) { + field = script_env_get(state->script, temp); + if (!field) + return buffer; + } + + if (!buffer) + buffer = talloc_strdup(state->opt, field); + else + buffer = talloc_asprintf_append(buffer, "%s", field); + + return buffer; +} + +static char *expand_field(struct bls_state *state, char *value) +{ + char *buffer = NULL; + char *start = value; + char *end = value; + int type = GRUB2_WORD_TEXT; + + while (*value) { + if (*value == '$') { + if (start != end) { + buffer = field_append(state, type, buffer, + start, end); + if (!buffer) + return NULL; + } + + type = GRUB2_WORD_VAR; + start = value + 1; + } else if (type == GRUB2_WORD_VAR) { + if (!isalnum(*value) && *value != '_') { + buffer = field_append(state, type, buffer, + start, end); + type = GRUB2_WORD_TEXT; + start = value; + } + } + + end = value; + value++; + } + + if (start != end) { + buffer = field_append(state, type, buffer, + start, end); + if (!buffer) + return NULL; + } + + return buffer; +} + static void bls_process_pair(struct conf_context *conf, const char *name, char *value) { struct bls_state *state = conf->parser_info; struct discover_boot_option *opt = state->opt; struct boot_option *option = opt->option; - const char *boot_args; if (streq(name, "title")) { - state->title = talloc_strdup(state, value); + state->title = expand_field(state, value); return; } if (streq(name, "version")) { - state->version = talloc_strdup(state, value); + state->version = expand_field(state, value); return; } if (streq(name, "machine-id")) { - state->machine_id = talloc_strdup(state, value); + state->machine_id = expand_field(state, value); return; } if (streq(name, "linux")) { - state->image = talloc_strdup(state, value); + state->image = expand_field(state, value); return; } if (streq(name, "initrd")) { - state->initrd = talloc_strdup(state, value); + state->initrd = expand_field(state, value); return; } if (streq(name, "devicetree")) { - state->dtb = talloc_strdup(state, value); + state->dtb = expand_field(state, value); return; } if (streq(name, "options")) { - if (value[0] == '$') { - boot_args = script_env_get(state->script, value + 1); - if (!boot_args) - return; - - option->boot_args = talloc_strdup(opt, boot_args); - } else { - option->boot_args = talloc_strdup(opt, value); - } + option->boot_args = expand_field(state, value); return; } } -static bool option_is_default(struct grub2_script *script, +static bool option_is_default(struct bls_state *state, struct boot_option *option) { + unsigned int idx; const char *var; + char *end; - var = script_env_get(script, "default"); + var = script_env_get(state->script, "default"); if (!var) return false; if (!strcmp(var, option->id)) return true; - return !strcmp(var, option->name); + if (!strcmp(var, option->name)) + return true; + + idx = strtoul(var, &end, 10); + return end != var && *end == '\0' && idx == state->idx; } static void bls_finish(struct conf_context *conf) @@ -141,7 +205,13 @@ static void bls_finish(struct conf_context *conf) opt->dtb = create_grub2_resource(opt, conf->dc->device, root, state->dtb); - option->is_default = option_is_default(state->script, option); + char* args_sigfile_default = talloc_asprintf(opt, + "%s.cmdline.sig", state->image); + opt->args_sig_file = create_grub2_resource(opt, conf->dc->device, + root, args_sigfile_default); + talloc_free(args_sigfile_default); + + option->is_default = option_is_default(state, option); list_add_tail(&state->script->options, &opt->list); state->script->n_options++; @@ -176,13 +246,16 @@ int builtin_blscfg(struct grub2_script *script, int argc __attribute__((unused)), char *argv[] __attribute__((unused))) { + unsigned int current_idx = script->n_options; struct discover_context *dc = script->ctx; struct dirent **bls_entries; struct conf_context *conf; struct bls_state *state; char *buf, *filename; + const char * const *dir; const char *blsdir; int n, len, rc = -1; + struct stat statbuf; conf = talloc_zero(dc, struct conf_context); if (!conf) @@ -195,7 +268,17 @@ int builtin_blscfg(struct grub2_script *script, blsdir = script_env_get(script, "blsdir"); if (!blsdir) - blsdir = BLS_DIR; + for (dir = bls_dirs; *dir; dir++) + if (!parser_stat_path(dc, dc->device, *dir, &statbuf)) { + blsdir = *dir; + break; + } + + if (!blsdir) { + device_handler_status_dev_info(dc->handler, dc->device, + _("BLS directory wasn't found")); + goto err; + } n = parser_scandir(dc, blsdir, &bls_entries, bls_filter, bls_sort); if (n <= 0) @@ -217,6 +300,7 @@ int builtin_blscfg(struct grub2_script *script, state->script = script; state->filename = filename; + state->idx = current_idx++; conf->parser_info = state; rc = parser_request_file(dc, dc->device, filename, &buf, &len); @@ -234,7 +318,7 @@ int builtin_blscfg(struct grub2_script *script, if (n > 0) { device_handler_status_dev_info(dc->handler, dc->device, _("Scanning %s failed"), - BLS_DIR); + blsdir); do { free(bls_entries[n]); } while (n-- > 0);