6 #include <types/types.h>
7 #include <talloc/talloc.h>
11 #include "discover/resource.h"
12 #include "discover/parser.h"
16 static int builtin_set(struct grub2_script *script,
17 void *data __attribute__((unused)),
18 int argc, char *argv[])
20 char *name, *value, *p;
26 p = strchr(argv[1], '=');
30 name = talloc_strndup(script, argv[1], p - argv[1]);
31 value = talloc_strdup(script, p+1);
33 for (i = 2; i < argc; i++)
34 value = talloc_asprintf_append(value, " %s", argv[i]);
36 script_env_set(script, name, value);
41 static int builtin_linux(struct grub2_script *script,
42 void *data __attribute__((unused)),
43 int argc, char *argv[])
45 struct discover_boot_option *opt = script->opt;
50 pb_log("grub2 syntax error: 'linux' statement outside "
56 pb_log("grub2 syntax error: no filename provided to "
61 root = script_env_get(script, "root");
63 opt->boot_image = create_grub2_resource(opt, script->ctx->device,
65 opt->option->boot_args = NULL;
68 opt->option->boot_args = talloc_strdup(opt, argv[2]);
70 for (i = 3; i < argc; i++)
71 opt->option->boot_args = talloc_asprintf_append(
72 opt->option->boot_args,
75 char* args_sigfile_default = talloc_asprintf(opt,
76 "%s.cmdline.sig", argv[1]);
77 opt->args_sig_file = create_grub2_resource(opt, script->ctx->device,
78 root, args_sigfile_default);
79 talloc_free(args_sigfile_default);
83 static int builtin_initrd(struct grub2_script *script,
84 void *data __attribute__((unused)),
85 int argc, char *argv[])
87 struct discover_boot_option *opt = script->opt;
91 pb_log("grub2 syntax error: 'initrd' statement outside "
97 pb_log("grub2 syntax error: no filename provided to "
98 "initrd statement\n");
102 root = script_env_get(script, "root");
103 opt->initrd = create_grub2_resource(opt, script->ctx->device,
109 static int builtin_search(struct grub2_script *script,
110 void *data __attribute__((unused)),
111 int argc, char *argv[])
113 const char *env_var, *spec;
118 for (i = 1; i < argc - 1; i++) {
119 if (!strncmp(argv[i], "--set=", strlen("--set="))) {
120 env_var = argv[i] + strlen("--set=");
128 spec = argv[argc - 1];
130 script_env_set(script, env_var, spec);
135 /* Note that GRUB does not follow symlinks in evaluating all file
136 * tests but -s, unlike below. However, it seems like a bad idea to
137 * emulate GRUB's behavior (e.g., it would take extra work), so we
138 * implement the behavior that coreutils' test binary has. */
139 static bool builtin_test_op_file(struct grub2_script *script, char op,
146 rc = parser_stat_path(script->ctx, script->ctx->device,
153 /* -s: return true if file exists and has non-zero size */
154 result = statbuf.st_size > 0;
157 /* -f: return true if file exists and is not a directory. This is
158 * different than the behavior of "test", but is what GRUB does
159 * (though note as above that we follow symlinks unlike GRUB). */
160 result = !S_ISDIR(statbuf.st_mode);
170 /* See comment at builtin_test_op_file for differences between how
171 * GRUB implements file tests versus Petitboot's GRUB parser. */
172 static bool builtin_test_op_dir(struct grub2_script *script, char op,
181 rc = parser_stat_path(script->ctx, script->ctx->device, dir, &statbuf);
186 return S_ISDIR(statbuf.st_mode);
189 static bool builtin_test_op(struct grub2_script *script,
190 int argc, char **argv, int *consumed)
201 if (!strcmp(op, "=") || !strcmp(op, "==")) {
203 return !strcmp(a1, a2);
206 if (!strcmp(op, "!=")) {
208 return strcmp(a1, a2);
211 if (!strcmp(op, "<")) {
213 return strcmp(a1, a2) < 0;
216 if (!strcmp(op, ">")) {
218 return strcmp(a1, a2) > 0;
228 if (!strcmp(op, "-z")) {
230 return strlen(a1) == 0;
233 if (!strcmp(op, "-n")) {
235 return strlen(a1) != 0;
238 if (!strcmp(op, "-s") || !strcmp(op, "-f")) {
240 return builtin_test_op_file(script, op[1], a1);
243 if (!strcmp(op, "-d")) {
245 return builtin_test_op_dir(script, op[1], a1);
251 return strlen(op) > 0;
254 static int builtin_test(struct grub2_script *script,
255 void *data __attribute__((unused)),
256 int argc, char *argv[])
261 if (!strcmp(argv[0], "[") && !strcmp(argv[argc - 1], "]"))
264 /* skip command name */
271 for (consumed = 0; argc > 0; argv += consumed, argc -= consumed) {
273 if (!strcmp(argv[0], "!")) {
279 if (!strcmp(argv[0], "-a")) {
286 if (!strcmp(argv[0], "-o")) {
293 rc = builtin_test_op(script, argc, argv, &consumed);
303 static int builtin_true(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_false(struct grub2_script *script __attribute__((unused)),
312 void *data __attribute__((unused)),
313 int argc __attribute__((unused)),
314 char *argv[] __attribute__((unused)))
319 static int builtin_nop(struct grub2_script *script __attribute__((unused)),
320 void *data __attribute__((unused)),
321 int argc __attribute__((unused)),
322 char *argv[] __attribute__((unused)))
327 extern int builtin_load_env(struct grub2_script *script,
328 void *data __attribute__((unused)),
329 int argc, char *argv[]);
330 int builtin_save_env(struct grub2_script *script,
331 void *data __attribute__((unused)),
332 int argc, char *argv[]);
333 int builtin_blscfg(struct grub2_script *script,
334 void *data __attribute__((unused)),
335 int argc __attribute__((unused)),
336 char *argv[] __attribute__((unused)));
356 .fn = builtin_initrd,
360 .fn = builtin_initrd,
364 .fn = builtin_search,
384 .fn = builtin_load_env,
388 .fn = builtin_save_env,
392 .fn = builtin_blscfg,
396 static const char *nops[] = {
397 "echo", "export", "insmod", "loadfont", "terminfo",
400 void register_builtins(struct grub2_script *script)
404 for (i = 0; i < ARRAY_SIZE(builtins); i++)
405 script_register_function(script, builtins[i].name,
406 builtins[i].fn, NULL);
408 for (i = 0; i < ARRAY_SIZE(nops); i++)
409 script_register_function(script, nops[i], builtin_nop, NULL);