6 #include <types/types.h>
7 #include <talloc/talloc.h>
10 #include "discover/parser.h"
14 static int builtin_set(struct grub2_script *script,
15 void *data __attribute__((unused)),
16 int argc, char *argv[])
18 char *name, *value, *p;
24 p = strchr(argv[1], '=');
28 name = talloc_strndup(script, argv[1], p - argv[1]);
29 value = talloc_strdup(script, p+1);
31 for (i = 2; i < argc; i++)
32 value = talloc_asprintf_append(value, " %s", argv[i]);
34 script_env_set(script, name, value);
39 static int builtin_linux(struct grub2_script *script,
40 void *data __attribute__((unused)),
41 int argc, char *argv[])
43 struct discover_boot_option *opt = script->opt;
48 pb_log("grub2 syntax error: 'linux' statement outside "
54 pb_log("grub2 syntax error: no filename provided to "
59 root = script_env_get(script, "root");
61 opt->boot_image = create_grub2_resource(opt, script->ctx->device,
63 opt->option->boot_args = NULL;
66 opt->option->boot_args = talloc_strdup(opt, argv[2]);
68 for (i = 3; i < argc; i++)
69 opt->option->boot_args = talloc_asprintf_append(
70 opt->option->boot_args,
75 static int builtin_initrd(struct grub2_script *script,
76 void *data __attribute__((unused)),
77 int argc, char *argv[])
79 struct discover_boot_option *opt = script->opt;
83 pb_log("grub2 syntax error: 'initrd' statement outside "
89 pb_log("grub2 syntax error: no filename provided to "
90 "initrd statement\n");
94 root = script_env_get(script, "root");
95 opt->initrd = create_grub2_resource(opt, script->ctx->device,
101 static int builtin_search(struct grub2_script *script,
102 void *data __attribute__((unused)),
103 int argc, char *argv[])
105 const char *env_var, *spec;
110 for (i = 1; i < argc - 1; i++) {
111 if (!strncmp(argv[i], "--set=", strlen("--set="))) {
112 env_var = argv[i] + strlen("--set=");
120 spec = argv[argc - 1];
122 script_env_set(script, env_var, spec);
127 /* Note that GRUB does not follow symlinks in evaluating all file
128 * tests but -s, unlike below. However, it seems like a bad idea to
129 * emulate GRUB's behavior (e.g., it would take extra work), so we
130 * implement the behavior that coreutils' test binary has. */
131 static bool builtin_test_op_file(struct grub2_script *script, char op,
138 rc = parser_stat_path(script->ctx, script->ctx->device,
145 /* -s: return true if file exists and has non-zero size */
146 result = statbuf.st_size > 0;
149 /* -f: return true if file exists and is not a directory. This is
150 * different than the behavior of "test", but is what GRUB does
151 * (though note as above that we follow symlinks unlike GRUB). */
152 result = !S_ISDIR(statbuf.st_mode);
162 /* See comment at builtin_test_op_file for differences between how
163 * GRUB implements file tests versus Petitboot's GRUB parser. */
164 static bool builtin_test_op_dir(struct grub2_script *script, char op,
173 rc = parser_stat_path(script->ctx, script->ctx->device, dir, &statbuf);
178 return S_ISDIR(statbuf.st_mode);
181 static bool builtin_test_op(struct grub2_script *script,
182 int argc, char **argv, int *consumed)
193 if (!strcmp(op, "=") || !strcmp(op, "==")) {
195 return !strcmp(a1, a2);
198 if (!strcmp(op, "!=")) {
200 return strcmp(a1, a2);
203 if (!strcmp(op, "<")) {
205 return strcmp(a1, a2) < 0;
208 if (!strcmp(op, ">")) {
210 return strcmp(a1, a2) > 0;
220 if (!strcmp(op, "-z")) {
222 return strlen(a1) == 0;
225 if (!strcmp(op, "-n")) {
227 return strlen(a1) != 0;
230 if (!strcmp(op, "-s") || !strcmp(op, "-f")) {
232 return builtin_test_op_file(script, op[1], a1);
235 if (!strcmp(op, "-d")) {
237 return builtin_test_op_dir(script, op[1], a1);
243 return strlen(op) > 0;
246 static int builtin_test(struct grub2_script *script,
247 void *data __attribute__((unused)),
248 int argc, char *argv[])
253 if (!strcmp(argv[0], "[") && !strcmp(argv[argc - 1], "]"))
256 /* skip command name */
263 for (consumed = 0; argc > 0; argv += consumed, argc -= consumed) {
265 if (!strcmp(argv[0], "!")) {
271 if (!strcmp(argv[0], "-a")) {
278 if (!strcmp(argv[0], "-o")) {
285 rc = builtin_test_op(script, argc, argv, &consumed);
295 static int builtin_true(struct grub2_script *script __attribute__((unused)),
296 void *data __attribute__((unused)),
297 int argc __attribute__((unused)),
298 char *argv[] __attribute__((unused)))
303 static int builtin_false(struct grub2_script *script __attribute__((unused)),
304 void *data __attribute__((unused)),
305 int argc __attribute__((unused)),
306 char *argv[] __attribute__((unused)))
311 static int builtin_nop(struct grub2_script *script __attribute__((unused)),
312 void *data __attribute__((unused)),
313 int argc __attribute__((unused)),
314 char *argv[] __attribute__((unused)))
319 extern int builtin_load_env(struct grub2_script *script,
320 void *data __attribute__((unused)),
321 int argc, char *argv[]);
322 int builtin_save_env(struct grub2_script *script,
323 void *data __attribute__((unused)),
324 int argc, char *argv[]);
345 .fn = builtin_initrd,
349 .fn = builtin_search,
369 .fn = builtin_load_env,
373 .fn = builtin_save_env,
377 static const char *nops[] = {
378 "echo", "export", "insmod", "loadfont", "terminfo",
381 void register_builtins(struct grub2_script *script)
385 for (i = 0; i < ARRAY_SIZE(builtins); i++)
386 script_register_function(script, builtins[i].name,
387 builtins[i].fn, NULL);
389 for (i = 0; i < ARRAY_SIZE(nops); i++)
390 script_register_function(script, nops[i], builtin_nop, NULL);