#include #include #include #include #include #include #include "grub2.h" static int builtin_set(struct grub2_script *script, void *data __attribute__((unused)), int argc, char *argv[]) { char *name, *value, *p; int i; if (argc < 2) return -1; p = strchr(argv[1], '='); if (!p) return -1; name = talloc_strndup(script, argv[1], p - argv[1]); value = talloc_strdup(script, p+1); for (i = 2; i < argc; i++) value = talloc_asprintf_append(value, " %s", argv[i]); script_env_set(script, name, value); return 0; } static int builtin_linux(struct grub2_script *script, void *data __attribute__((unused)), int argc, char *argv[]) { struct discover_boot_option *opt = script->opt; const char *root; int i; if (!opt) { pb_log("grub2 syntax error: 'linux' statement outside " "a menuentry.\n"); return -1; } if (argc < 2) { pb_log("grub2 syntax error: no filename provided to " "linux statement\n"); return -1; } root = script_env_get(script, "root"); opt->boot_image = create_grub2_resource(opt, script->ctx->device, root, argv[1]); opt->option->boot_args = NULL; if (argc > 2) opt->option->boot_args = talloc_strdup(opt, argv[2]); for (i = 3; i < argc; i++) opt->option->boot_args = talloc_asprintf_append( opt->option->boot_args, " %s", argv[i]); return 0; } static int builtin_initrd(struct grub2_script *script, void *data __attribute__((unused)), int argc, char *argv[]) { struct discover_boot_option *opt = script->opt; const char *root; if (!opt) { pb_log("grub2 syntax error: 'initrd' statement outside " "a menuentry.\n"); return -1; } if (argc < 2) { pb_log("grub2 syntax error: no filename provided to " "initrd statement\n"); return -1; } root = script_env_get(script, "root"); opt->initrd = create_grub2_resource(opt, script->ctx->device, root, argv[1]); return 0; } static int builtin_search(struct grub2_script *script, void *data __attribute__((unused)), int argc, char *argv[]) { const char *env_var, *spec; int i; env_var = NULL; for (i = 1; i < argc - 1; i++) { if (!strncmp(argv[i], "--set=", strlen("--set="))) { env_var = argv[i] + strlen("--set="); break; } } if (!env_var) return 0; spec = argv[argc - 1]; script_env_set(script, env_var, spec); return 0; } static bool builtin_test_op(int argc, char **argv, int *consumed) { char *op; if (argc >= 3) { const char *a1, *a2; a1 = argv[0]; op = argv[1]; a2 = argv[2]; if (!strcmp(op, "=") || !strcmp(op, "==")) { *consumed = 3; return !strcmp(a1, a2); } if (!strcmp(op, "!=")) { *consumed = 3; return strcmp(a1, a2); } if (!strcmp(op, "<")) { *consumed = 3; return strcmp(a1, a2) < 0; } if (!strcmp(op, ">")) { *consumed = 3; return strcmp(a1, a2) > 0; } } if (argc >= 2) { const char *a1; op = argv[0]; a1 = argv[1]; if (!strcmp(op, "-z")) { *consumed = 2; return strlen(a1) == 0; } if (!strcmp(op, "-n")) { *consumed = 2; return strlen(a1) != 0; } /* todo: implement file checks */ if (!strcmp(op, "-s") || !strcmp(op, "-f")) { *consumed = 2; return false; } } *consumed = 1; return strlen(op) > 0; } static int builtin_test(struct grub2_script *script __attribute__((unused)), void *data __attribute__((unused)), int argc, char *argv[]) { int consumed; bool not, rc; if (!strcmp(argv[0], "[") && !strcmp(argv[argc - 1], "]")) argc--; /* skip command name */ argc--; argv++; not = false; rc = false; for (consumed = 0; argc > 0; argv += consumed, argc -= consumed) { if (!strcmp(argv[0], "!")) { not = true; consumed = 1; continue; } if (!strcmp(argv[0], "-a")) { if (!rc) return 1; consumed = 1; continue; } if (!strcmp(argv[0], "-o")) { if (rc) return 0; consumed = 1; continue; } rc = builtin_test_op(argc, argv, &consumed); if (not) { rc = !rc; not = false; } } return rc ? 0 : 1; } static int builtin_nop(struct grub2_script *script __attribute__((unused)), void *data __attribute__((unused)), int argc __attribute__((unused)), char *argv[] __attribute__((unused))) { return 0; } static struct { const char *name; grub2_function fn; } builtins[] = { { .name = "set", .fn = builtin_set, }, { .name = "linux", .fn = builtin_linux, }, { .name = "initrd", .fn = builtin_initrd, }, { .name = "search", .fn = builtin_search, }, { .name = "[", .fn = builtin_test, }, { .name = "test", .fn = builtin_test, }, }; static const char *nops[] = { "echo", "export", "insmod", "loadfont", "terminfo", }; void register_builtins(struct grub2_script *script) { unsigned int i; for (i = 0; i < ARRAY_SIZE(builtins); i++) script_register_function(script, builtins[i].name, builtins[i].fn, NULL); for (i = 0; i < ARRAY_SIZE(nops); i++) script_register_function(script, nops[i], builtin_nop, NULL); }