X-Git-Url: http://git.ozlabs.org/?a=blobdiff_plain;f=discover%2Fgrub2%2Fscript.c;h=fce4f0afde487f8fc623ccc2ab519bf2d4ecee0e;hb=5c6c8ea8ca66fe70563143cb226852a10b1a98fb;hp=067b0c9440857f48b0ce4c0ad84c3e3e559484ac;hpb=1247b4bbbbf102c0cc54f6b3a927e249a9368ba4;p=petitboot diff --git a/discover/grub2/script.c b/discover/grub2/script.c index 067b0c9..fce4f0a 100644 --- a/discover/grub2/script.c +++ b/discover/grub2/script.c @@ -1,62 +1,72 @@ #include -#include #include #include #include "grub2.h" +#define to_stmt_simple(stmt) \ + container_of(stmt, struct grub2_statement_simple, st) +#define to_stmt_if(stmt) \ + container_of(stmt, struct grub2_statement_if, st) +#define to_stmt_menuentry(stmt) \ + container_of(stmt, struct grub2_statement_menuentry, st) + struct env_entry { const char *name; const char *value; struct list_item list; }; -static const char *env_lookup(struct grub2_script *script, - const char *name, int name_len) +const char *script_env_get(struct grub2_script *script, const char *name) { struct env_entry *entry; - const char *str; - - str = talloc_strndup(script, name, name_len); - printf("%s: %s\n", __func__, str); list_for_each_entry(&script->environment, entry, list) - if (!strncmp(entry->name, name, name_len)) + if (!strcmp(entry->name, name)) return entry->value; return NULL; } -static bool expand_word(struct grub2_script *script, struct grub2_word *word) +void script_env_set(struct grub2_script *script, + const char *name, const char *value) { - const char *val, *src; - char *dest = NULL; - regmatch_t match; - int n; + struct env_entry *e, *entry = NULL; + + list_for_each_entry(&script->environment, e, list) { + if (!strcmp(e->name, name)) { + entry = e; + break; + } + } - src = word->text; + if (!entry) { + entry = talloc(script, struct env_entry); + entry->name = name; + list_add(&script->environment, &entry->list); + } + + entry->value = value; +} - n = regexec(&script->var_re, src, 1, &match, 0); - if (n == 0) - return false; +static bool expand_var(struct grub2_script *script, struct grub2_word *word) +{ + const char *val; - val = env_lookup(script, src + match.rm_so, - match.rm_eo - match.rm_so); - if (val) + val = script_env_get(script, word->var.name); + if (!val) val = ""; - dest = talloc_strndup(script, src, match.rm_so); - dest = talloc_asprintf_append(dest, "%s%s", val, src + match.rm_eo); + word->type = GRUB2_WORD_TEXT; + word->text = talloc_strdup(script, val); - word->text = dest; return true; } -/* iterate through the words in an argv, looking for expansions. If a - * word is marked with expand == true, then we process any variable - * substitutions. +/* iterate through the words in an argv_list, looking for GRUB2_WORD_VAR + * expansions. * * Once that's done, we may (if split == true) have to split the word to create * new argv items @@ -64,45 +74,157 @@ static bool expand_word(struct grub2_script *script, struct grub2_word *word) static void process_expansions(struct grub2_script *script, struct grub2_argv *argv) { - struct grub2_word *word; + struct grub2_word *top_word, *word; + int i; - list_for_each_entry(&argv->words, word, argv_list) { - if (!word->expand) - continue; + argv->argc = 0; - expand_word(script, word); + list_for_each_entry(&argv->words, top_word, argv_list) { + argv->argc++; + + /* expand vars and squash the list of words into the top struct. + * todo: splitting + */ + for (word = top_word; word; word = word->next) { + if (word->type == GRUB2_WORD_VAR) + expand_var(script, word); + + if (word == top_word) + continue; + + top_word->text = talloc_asprintf_append(top_word->text, + "%s", word->text); + } + top_word->next = NULL; } + + argv->argv = talloc_array(script, char *, argv->argc); + i = 0; + + list_for_each_entry(&argv->words, word, argv_list) + argv->argv[i++] = word->text; } -static int script_destroy(void *p) +int statements_execute(struct grub2_script *script, + struct grub2_statements *stmts) { - struct grub2_script *script = p; - regfree(&script->var_re); - return 0; + struct grub2_statement *stmt; + int rc = 0; + + list_for_each_entry(&stmts->list, stmt, list) { + if (stmt->exec) + rc = stmt->exec(script, stmt); + } + return rc; } -struct grub2_script *create_script(void *ctx) +int statement_simple_execute(struct grub2_script *script, + struct grub2_statement *statement) { - struct grub2_script *script; + struct grub2_statement_simple *st = to_stmt_simple(statement); + struct grub2_command *cmd; int rc; - script = talloc(ctx, struct grub2_script); + if (!st->argv) + return 0; + + process_expansions(script, st->argv); - rc = regcomp(&script->var_re, - "\\$\\{?([[:alpha:]][_[:alnum:]]*|[0-9]|[\\?@\\*#])\\}?", - REG_EXTENDED); - if (rc) { - char err[200]; - regerror(rc, &script->var_re, err, sizeof(err)); - fprintf(stderr, "RE error %d: %s\n", rc, err); - talloc_free(script); - return NULL; + if (!st->argv->argc) + return 0; + cmd = script_lookup_command(script, st->argv->argv[0]); + if (!cmd) { + fprintf(stderr, "undefined command '%s'\n", st->argv->argv[0]); + return 0; } - talloc_set_destructor(script, script_destroy); + + rc = cmd->exec(script, st->argv->argc, st->argv->argv); + + return rc; +} + +int statement_if_execute(struct grub2_script *script, + struct grub2_statement *statement) +{ + struct grub2_statement_if *st = to_stmt_if(statement); + struct grub2_statements *case_stmts; + int rc; + + rc = st->condition->exec(script, st->condition); + + if (rc == 0) + case_stmts = st->true_case; + else + case_stmts = st->false_case; + + if (case_stmts) + statements_execute(script, case_stmts); + else + rc = 0; + + return rc; +} + +int statement_menuentry_execute(struct grub2_script *script, + struct grub2_statement *statement) +{ + struct grub2_statement_menuentry *st = to_stmt_menuentry(statement); + + process_expansions(script, st->argv); + statements_execute(script, st->statements); + + return 0; +} + +static void init_env(struct grub2_script *script) +{ + struct env_entry *env; list_init(&script->environment); + env = talloc(script, struct env_entry); + env->name = talloc_strdup(env, "prefix"); + env->value = talloc_strdup(env, "/"); + + list_add(&script->environment, &env->list); +} + +struct grub2_command *script_lookup_command(struct grub2_script *script, + const char *name) +{ + struct grub2_command *command; + + list_for_each_entry(&script->commands, command, list) { + if (!strcmp(command->name, name)) + return command; + } + + return NULL; +} + +void script_register_command(struct grub2_script *script, + struct grub2_command *command) +{ + list_add(&script->commands, &command->list); +} + + +void script_execute(struct grub2_script *script) +{ + statements_execute(script, script->statements); +} + +struct grub2_script *create_script(void *ctx) +{ + struct grub2_script *script; + + script = talloc(ctx, struct grub2_script); + + init_env(script); + list_init(&script->commands); + register_builtins(script); + return script; }