]> git.ozlabs.org Git - petitboot/blob - discover/grub2/script.c
b6d3221c36effed793300a63af86d34a44475dfa
[petitboot] / discover / grub2 / script.c
1
2 #include <sys/types.h>
3 #include <regex.h>
4 #include <string.h>
5
6 #include <talloc/talloc.h>
7
8 #include "grub2.h"
9
10 #define to_stmt_simple(stmt) \
11         container_of(stmt, struct grub2_statement_simple, st)
12 #define to_stmt_if(stmt) \
13         container_of(stmt, struct grub2_statement_if, st)
14
15 struct env_entry {
16         const char              *name;
17         const char              *value;
18         struct list_item        list;
19 };
20
21 static const char *env_lookup(struct grub2_script *script,
22                 const char *name, int name_len)
23 {
24         struct env_entry *entry;
25         const char *str;
26
27         str = talloc_strndup(script, name, name_len);
28         printf("%s: %s\n", __func__, str);
29
30         list_for_each_entry(&script->environment, entry, list)
31                 if (!strncmp(entry->name, name, name_len))
32                         return entry->value;
33
34         return NULL;
35 }
36
37 static bool expand_word(struct grub2_script *script, struct grub2_word *word)
38 {
39         const char *val, *src;
40         char *dest = NULL;
41         regmatch_t match;
42         int n;
43
44         src = word->text;
45
46         n = regexec(&script->var_re, src, 1, &match, 0);
47         printf("%s %s: %d\n", __func__, word->text, n);
48         if (n != 0)
49                 return false;
50
51         val = env_lookup(script, src + match.rm_so,
52                                  match.rm_eo - match.rm_so);
53         if (!val)
54                 val = "";
55
56         dest = talloc_strndup(script, src, match.rm_so);
57         dest = talloc_asprintf_append(dest, "%s%s", val, src + match.rm_eo);
58
59         word->text = dest;
60         return true;
61 }
62
63 /* iterate through the words in an argv, looking for expansions. If a
64  * word is marked with expand == true, then we process any variable
65  * substitutions.
66  *
67  * Once that's done, we may (if split == true) have to split the word to create
68  * new argv items
69  */
70 static void process_expansions(struct grub2_script *script,
71                 struct grub2_argv *argv)
72 {
73         struct grub2_word *word;
74
75         list_for_each_entry(&argv->words, word, argv_list) {
76                 if (!word->expand)
77                         continue;
78
79                 expand_word(script, word);
80         }
81 }
82
83 int statements_execute(struct grub2_script *script,
84                 struct grub2_statements *stmts)
85 {
86         struct grub2_statement *stmt;
87         int rc = 0;
88
89         list_for_each_entry(&stmts->list, stmt, list) {
90                 if (stmt->exec)
91                         rc = stmt->exec(script, stmt);
92                 printf("%s(%p)\n", __func__, stmt);
93         }
94         return rc;
95 }
96
97 int statement_simple_execute(struct grub2_script *script,
98                 struct grub2_statement *statement)
99 {
100         struct grub2_statement_simple *st = to_stmt_simple(statement);
101
102         if (!st->argv)
103                 return 0;
104
105         process_expansions(script, st->argv);
106
107         return 0;
108 }
109
110 int statement_if_execute(struct grub2_script *script,
111                 struct grub2_statement *statement)
112 {
113         struct grub2_statement_if *st = to_stmt_if(statement);
114         struct grub2_statements *case_stmts;
115         int rc;
116
117         rc = st->condition->exec(script, st->condition);
118
119         if (rc == 0)
120                 case_stmts = st->true_case;
121         else
122                 case_stmts = st->false_case;
123
124         if (case_stmts)
125                 statements_execute(script, case_stmts);
126         else
127                 rc = 0;
128
129         return rc;
130 }
131
132
133 void script_execute(struct grub2_script *script)
134 {
135         statements_execute(script, script->statements);
136 }
137
138 static int script_destroy(void *p)
139 {
140         struct grub2_script *script = p;
141         regfree(&script->var_re);
142         return 0;
143 }
144
145 struct grub2_script *create_script(void *ctx)
146 {
147         struct grub2_script *script;
148         int rc;
149
150         script = talloc(ctx, struct grub2_script);
151
152         rc = regcomp(&script->var_re,
153                 "\\$\\{?([[:alpha:]][_[:alnum:]]*|[0-9]|[\\?@\\*#])\\}?",
154                         REG_EXTENDED);
155         if (rc) {
156                 char err[200];
157                 regerror(rc, &script->var_re, err, sizeof(err));
158                 fprintf(stderr, "RE error %d: %s\n", rc, err);
159                 talloc_free(script);
160                 return NULL;
161
162         }
163         talloc_set_destructor(script, script_destroy);
164
165         list_init(&script->environment);
166
167         return script;
168 }
169