tpm2_key_protector: Enable build for powerpc_ieee1275
[grub.git] / grub-core / script / execute.c
blob14ff09094f0d3b10b458e7d1df33b6b852d3933f
1 /* execute.c -- Execute a GRUB script. */
2 /*
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2005,2007,2008,2009,2010 Free Software Foundation, Inc.
6 * GRUB is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * GRUB is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
20 #include <grub/misc.h>
21 #include <grub/mm.h>
22 #include <grub/env.h>
23 #include <grub/script_sh.h>
24 #include <grub/command.h>
25 #include <grub/menu.h>
26 #include <grub/lib/arg.h>
27 #include <grub/normal.h>
28 #include <grub/extcmd.h>
29 #include <grub/i18n.h>
30 #include <grub/verify.h>
32 /* Max digits for a char is 3 (0xFF is 255), similarly for an int it
33 is sizeof (int) * 3, and one extra for a possible -ve sign. */
34 #define ERRNO_DIGITS_MAX (sizeof (int) * 3 + 1)
36 static unsigned long is_continue;
37 static unsigned long active_loops;
38 static unsigned long active_breaks;
39 static unsigned long function_return;
41 #define GRUB_SCRIPT_SCOPE_MALLOCED 1
42 #define GRUB_SCRIPT_SCOPE_ARGS_MALLOCED 2
44 /* Scope for grub script functions. */
45 struct grub_script_scope
47 unsigned flags;
48 unsigned shifts;
49 struct grub_script_argv argv;
51 static struct grub_script_scope *scope = 0;
53 /* Wildcard translator for GRUB script. */
54 struct grub_script_wildcard_translator *grub_wildcard_translator;
56 static char*
57 wildcard_escape (const char *s)
59 int i;
60 int len;
61 char ch;
62 char *p;
64 len = grub_strlen (s);
65 p = grub_malloc (len * 2 + 1);
66 if (! p)
67 return NULL;
69 i = 0;
70 while ((ch = *s++))
72 if (ch == '*' || ch == '\\' || ch == '?')
73 p[i++] = '\\';
74 p[i++] = ch;
76 p[i] = '\0';
77 return p;
80 static char*
81 wildcard_unescape (const char *s)
83 int i;
84 int len;
85 char ch;
86 char *p;
88 len = grub_strlen (s);
89 p = grub_malloc (len + 1);
90 if (! p)
91 return NULL;
93 i = 0;
94 while ((ch = *s++))
96 if (ch == '\\')
97 p[i++] = *s++;
98 else
99 p[i++] = ch;
101 p[i] = '\0';
102 return p;
105 static void
106 replace_scope (struct grub_script_scope *new_scope)
108 if (scope)
110 scope->argv.argc += scope->shifts;
111 scope->argv.args -= scope->shifts;
113 if (scope->flags & GRUB_SCRIPT_SCOPE_ARGS_MALLOCED)
114 grub_script_argv_free (&scope->argv);
116 if (scope->flags & GRUB_SCRIPT_SCOPE_MALLOCED)
117 grub_free (scope);
119 scope = new_scope;
122 grub_err_t
123 grub_script_break (grub_command_t cmd, int argc, char *argv[])
125 const char *p = NULL;
126 unsigned long count;
128 if (argc == 0)
129 count = 1;
130 else if (argc > 1)
131 return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
132 else
134 count = grub_strtoul (argv[0], &p, 10);
135 if (grub_errno)
136 return grub_errno;
137 if (*p != '\0')
138 return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("unrecognized number"));
139 if (count == 0)
140 /* TRANSLATORS: 0 is a quantifier. "break" (similar to bash)
141 can be used e.g. to break 3 loops at once.
142 But asking it to break 0 loops makes no sense. */
143 return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("can't break 0 loops"));
146 is_continue = grub_strcmp (cmd->name, "break") ? 1 : 0;
147 active_breaks = count;
148 if (active_breaks > active_loops)
149 active_breaks = active_loops;
150 return GRUB_ERR_NONE;
153 grub_err_t
154 grub_script_shift (grub_command_t cmd __attribute__((unused)),
155 int argc, char *argv[])
157 const char *p = NULL;
158 unsigned long n = 0;
160 if (! scope)
161 return GRUB_ERR_NONE;
163 if (argc == 0)
164 n = 1;
166 else if (argc > 1)
167 return GRUB_ERR_BAD_ARGUMENT;
169 else
171 n = grub_strtoul (argv[0], &p, 10);
172 if (*p != '\0')
173 return GRUB_ERR_BAD_ARGUMENT;
176 if (n > scope->argv.argc)
177 return GRUB_ERR_BAD_ARGUMENT;
179 scope->shifts += n;
180 scope->argv.argc -= n;
181 scope->argv.args += n;
182 return GRUB_ERR_NONE;
185 grub_err_t
186 grub_script_setparams (grub_command_t cmd __attribute__((unused)),
187 int argc, char **args)
189 struct grub_script_scope *new_scope;
190 struct grub_script_argv argv = { 0, 0, 0 };
192 if (! scope)
193 return GRUB_ERR_INVALID_COMMAND;
195 new_scope = grub_malloc (sizeof (*new_scope));
196 if (! new_scope)
197 return grub_errno;
199 if (grub_script_argv_make (&argv, argc, args))
201 grub_free (new_scope);
202 return grub_errno;
205 new_scope->shifts = 0;
206 new_scope->argv = argv;
207 new_scope->flags = GRUB_SCRIPT_SCOPE_MALLOCED |
208 GRUB_SCRIPT_SCOPE_ARGS_MALLOCED;
210 replace_scope (new_scope);
211 return GRUB_ERR_NONE;
214 grub_err_t
215 grub_script_return (grub_command_t cmd __attribute__((unused)),
216 int argc, char *argv[])
218 const char *p = NULL;
219 unsigned long n;
221 if (! scope || argc > 1)
222 return grub_error (GRUB_ERR_BAD_ARGUMENT,
223 /* TRANSLATORS: It's about not being
224 inside a function. "return" can be used only
225 in a function and this error occurs if it's used
226 anywhere else. */
227 N_("not in function body"));
229 if (argc == 0)
231 const char *t;
232 function_return = 1;
233 t = grub_env_get ("?");
234 if (!t)
235 return GRUB_ERR_NONE;
236 return grub_strtoul (t, NULL, 10);
239 n = grub_strtoul (argv[0], &p, 10);
240 if (grub_errno)
241 return grub_errno;
242 if (*p != '\0')
243 return grub_error (GRUB_ERR_BAD_ARGUMENT,
244 N_("unrecognized number"));
246 function_return = 1;
247 return n ? grub_error (n, N_("false")) : GRUB_ERR_NONE;
250 static int
251 grub_env_special (const char *name)
253 if (grub_isdigit (name[0]) ||
254 grub_strcmp (name, "#") == 0 ||
255 grub_strcmp (name, "*") == 0 ||
256 grub_strcmp (name, "@") == 0)
257 return 1;
258 return 0;
261 static char **
262 grub_script_env_get (const char *name, grub_script_arg_type_t type)
264 unsigned i;
265 struct grub_script_argv result = { 0, 0, 0 };
267 if (grub_script_argv_next (&result))
268 goto fail;
270 if (! grub_env_special (name))
272 const char *v = grub_env_get (name);
273 if (v && v[0])
275 if (type == GRUB_SCRIPT_ARG_TYPE_VAR)
277 if (grub_script_argv_split_append (&result, v))
278 goto fail;
280 else
281 if (grub_script_argv_append (&result, v, grub_strlen (v)))
282 goto fail;
285 else if (! scope)
287 if (grub_script_argv_append (&result, 0, 0))
288 goto fail;
290 else if (grub_strcmp (name, "#") == 0)
292 char buffer[ERRNO_DIGITS_MAX + 1];
293 grub_snprintf (buffer, sizeof (buffer), "%u", scope->argv.argc);
294 if (grub_script_argv_append (&result, buffer, grub_strlen (buffer)))
295 goto fail;
297 else if (grub_strcmp (name, "*") == 0)
299 for (i = 0; i < scope->argv.argc; i++)
300 if (type == GRUB_SCRIPT_ARG_TYPE_VAR)
302 if (i != 0 && grub_script_argv_next (&result))
303 goto fail;
305 if (grub_script_argv_split_append (&result, scope->argv.args[i]))
306 goto fail;
308 else
310 if (i != 0 && grub_script_argv_append (&result, " ", 1))
311 goto fail;
313 if (grub_script_argv_append (&result, scope->argv.args[i],
314 grub_strlen (scope->argv.args[i])))
315 goto fail;
318 else if (grub_strcmp (name, "@") == 0)
320 for (i = 0; i < scope->argv.argc; i++)
322 if (i != 0 && grub_script_argv_next (&result))
323 goto fail;
325 if (type == GRUB_SCRIPT_ARG_TYPE_VAR)
327 if (grub_script_argv_split_append (&result, scope->argv.args[i]))
328 goto fail;
330 else
331 if (grub_script_argv_append (&result, scope->argv.args[i],
332 grub_strlen (scope->argv.args[i])))
333 goto fail;
336 else
338 unsigned long num = grub_strtoul (name, 0, 10);
339 if (num == 0)
340 ; /* XXX no file name, for now. */
342 else if (num <= scope->argv.argc)
344 if (type == GRUB_SCRIPT_ARG_TYPE_VAR)
346 if (grub_script_argv_split_append (&result,
347 scope->argv.args[num - 1]))
348 goto fail;
350 else
351 if (grub_script_argv_append (&result, scope->argv.args[num - 1],
352 grub_strlen (scope->argv.args[num - 1])
354 goto fail;
358 return result.args;
360 fail:
362 grub_script_argv_free (&result);
363 return 0;
366 static grub_err_t
367 grub_script_env_set (const char *name, const char *val)
369 if (grub_env_special (name))
370 return grub_error (GRUB_ERR_BAD_ARGUMENT,
371 N_("invalid variable name `%s'"), name);
373 return grub_env_set (name, val);
376 struct gettext_context
378 char **allowed_strings;
379 grub_size_t nallowed_strings;
380 grub_size_t additional_len;
383 static int
384 parse_string (const char *str,
385 int (*hook) (const char *var, grub_size_t varlen,
386 char **ptr, struct gettext_context *ctx),
387 struct gettext_context *ctx,
388 char *put)
390 const char *ptr;
391 int escaped = 0;
392 const char *optr;
394 for (ptr = str; ptr && *ptr; )
395 switch (*ptr)
397 case '\\':
398 escaped = !escaped;
399 if (!escaped && put)
400 *(put++) = '\\';
401 ptr++;
402 break;
403 case '$':
404 if (escaped)
406 escaped = 0;
407 if (put)
408 *(put++) = *ptr;
409 ptr++;
410 break;
413 ptr++;
414 switch (*ptr)
416 case '{':
418 optr = ptr + 1;
419 ptr = grub_strchr (optr, '}');
420 if (!ptr)
421 break;
422 if (hook (optr, ptr - optr, &put, ctx))
423 return 1;
424 ptr++;
425 break;
427 case '0' ... '9':
428 optr = ptr;
429 while (*ptr >= '0' && *ptr <= '9')
430 ptr++;
431 if (hook (optr, ptr - optr, &put, ctx))
432 return 1;
433 break;
434 case 'a' ... 'z':
435 case 'A' ... 'Z':
436 case '_':
437 optr = ptr;
438 while ((*ptr >= '0' && *ptr <= '9')
439 || (*ptr >= 'a' && *ptr <= 'z')
440 || (*ptr >= 'A' && *ptr <= 'Z')
441 || *ptr == '_')
442 ptr++;
443 if (hook (optr, ptr - optr, &put, ctx))
444 return 1;
445 break;
446 case '?':
447 case '#':
448 if (hook (ptr, 1, &put, ctx))
449 return 1;
450 ptr++;
451 break;
452 default:
453 if (put)
454 *(put++) = '$';
456 break;
457 default:
458 if (escaped && put)
459 *(put++) = '\\';
460 escaped = 0;
461 if (put)
462 *(put++) = *ptr;
463 ptr++;
464 break;
466 if (put)
467 *(put++) = 0;
468 return 0;
471 static int
472 gettext_putvar (const char *str, grub_size_t len,
473 char **ptr, struct gettext_context *ctx)
475 const char *var;
476 grub_size_t i;
478 for (i = 0; i < ctx->nallowed_strings; i++)
479 if (grub_strncmp (ctx->allowed_strings[i], str, len) == 0
480 && ctx->allowed_strings[i][len] == 0)
482 break;
484 if (i == ctx->nallowed_strings)
485 return 0;
487 /* Enough for any number. */
488 if (len == 1 && str[0] == '#' && scope != NULL)
490 grub_snprintf (*ptr, 30, "%u", scope->argv.argc);
491 *ptr += grub_strlen (*ptr);
492 return 0;
494 var = grub_env_get (ctx->allowed_strings[i]);
495 if (var)
496 *ptr = grub_stpcpy (*ptr, var);
497 return 0;
500 static int
501 gettext_save_allow (const char *str, grub_size_t len,
502 char **ptr __attribute__ ((unused)),
503 struct gettext_context *ctx)
505 ctx->allowed_strings[ctx->nallowed_strings++] = grub_strndup (str, len);
506 if (!ctx->allowed_strings[ctx->nallowed_strings - 1])
507 return 1;
508 return 0;
511 static int
512 gettext_getlen (const char *str, grub_size_t len,
513 char **ptr __attribute__ ((unused)),
514 struct gettext_context *ctx)
516 const char *var;
517 grub_size_t i;
519 for (i = 0; i < ctx->nallowed_strings; i++)
520 if (grub_strncmp (ctx->allowed_strings[i], str, len) == 0
521 && ctx->allowed_strings[i][len] == 0)
522 break;
523 if (i == ctx->nallowed_strings)
524 return 0;
526 /* Enough for any number. */
527 if (len == 1 && str[0] == '#')
529 ctx->additional_len += 30;
530 return 0;
532 var = grub_env_get (ctx->allowed_strings[i]);
533 if (var)
534 ctx->additional_len += grub_strlen (var);
535 return 0;
538 static int
539 gettext_append (struct grub_script_argv *result, const char *orig_str)
541 const char *template;
542 char *res = 0;
543 struct gettext_context ctx = {
544 .allowed_strings = 0,
545 .nallowed_strings = 0,
546 .additional_len = 1
548 int rval = 1;
549 const char *iptr;
551 grub_size_t dollar_cnt = 0;
553 for (iptr = orig_str; *iptr; iptr++)
554 if (*iptr == '$')
555 dollar_cnt++;
556 ctx.allowed_strings = grub_calloc (dollar_cnt, sizeof (ctx.allowed_strings[0]));
558 if (parse_string (orig_str, gettext_save_allow, &ctx, 0))
559 goto fail;
561 template = _(orig_str);
563 if (parse_string (template, gettext_getlen, &ctx, 0))
564 goto fail;
566 res = grub_malloc (grub_strlen (template) + ctx.additional_len);
567 if (!res)
568 goto fail;
570 if (parse_string (template, gettext_putvar, &ctx, res))
571 goto fail;
573 char *escaped = 0;
574 escaped = wildcard_escape (res);
575 if (grub_script_argv_append (result, escaped, grub_strlen (escaped)))
577 grub_free (escaped);
578 goto fail;
580 grub_free (escaped);
582 rval = 0;
583 fail:
584 grub_free (res);
586 grub_size_t i;
587 for (i = 0; i < ctx.nallowed_strings; i++)
588 grub_free (ctx.allowed_strings[i]);
590 grub_free (ctx.allowed_strings);
591 return rval;
594 static int
595 append (struct grub_script_argv *result,
596 const char *s, int escape_type)
598 int r;
599 char *p = 0;
601 if (escape_type == 0)
602 return grub_script_argv_append (result, s, grub_strlen (s));
604 if (escape_type > 0)
605 p = wildcard_escape (s);
606 else if (escape_type < 0)
607 p = wildcard_unescape (s);
609 if (! p)
610 return 1;
612 r = grub_script_argv_append (result, p, grub_strlen (p));
613 grub_free (p);
614 return r;
617 /* Convert arguments in ARGLIST into ARGV form. */
618 static int
619 grub_script_arglist_to_argv (struct grub_script_arglist *arglist,
620 struct grub_script_argv *argv)
622 int i;
623 char **values = 0;
624 struct grub_script_arg *arg = 0;
625 struct grub_script_argv result = { 0, 0, 0 };
627 if (arglist == NULL)
628 return 1;
630 for (; arglist && arglist->arg; arglist = arglist->next)
632 if (grub_script_argv_next (&result))
633 goto fail;
635 arg = arglist->arg;
636 while (arg)
638 switch (arg->type)
640 case GRUB_SCRIPT_ARG_TYPE_VAR:
641 case GRUB_SCRIPT_ARG_TYPE_DQVAR:
643 int need_cleanup = 0;
645 values = grub_script_env_get (arg->str, arg->type);
646 for (i = 0; values && values[i]; i++)
648 if (!need_cleanup)
650 if (i != 0 && grub_script_argv_next (&result))
652 need_cleanup = 1;
653 goto cleanup;
656 if (arg->type == GRUB_SCRIPT_ARG_TYPE_VAR)
658 int len;
659 char ch;
660 char *p;
661 char *op;
662 const char *s = values[i];
664 len = grub_strlen (values[i]);
665 /* \? -> \\\? */
666 /* \* -> \\\* */
667 /* \ -> \\ */
668 p = grub_malloc (len * 2 + 1);
669 if (! p)
671 need_cleanup = 1;
672 goto cleanup;
675 op = p;
676 while ((ch = *s++))
678 if (ch == '\\')
680 *op++ = '\\';
681 if (*s == '?' || *s == '*')
682 *op++ = '\\';
684 *op++ = ch;
686 *op = '\0';
688 need_cleanup = grub_script_argv_append (&result, p, op - p);
689 grub_free (p);
690 /* Fall through to cleanup */
692 else
694 need_cleanup = append (&result, values[i], 1);
695 /* Fall through to cleanup */
699 cleanup:
700 grub_free (values[i]);
702 grub_free (values);
704 if (need_cleanup)
705 goto fail;
707 break;
710 case GRUB_SCRIPT_ARG_TYPE_BLOCK:
712 char *p;
713 if (grub_script_argv_append (&result, "{", 1))
714 goto fail;
715 p = wildcard_escape (arg->str);
716 if (!p)
717 goto fail;
718 if (grub_script_argv_append (&result, p,
719 grub_strlen (p)))
721 grub_free (p);
722 goto fail;
724 grub_free (p);
725 if (grub_script_argv_append (&result, "}", 1))
726 goto fail;
728 result.script = arg->script;
729 break;
731 case GRUB_SCRIPT_ARG_TYPE_TEXT:
732 if (arg->str[0] &&
733 grub_script_argv_append (&result, arg->str,
734 grub_strlen (arg->str)))
735 goto fail;
736 break;
738 case GRUB_SCRIPT_ARG_TYPE_GETTEXT:
740 if (gettext_append (&result, arg->str))
741 goto fail;
743 break;
745 case GRUB_SCRIPT_ARG_TYPE_DQSTR:
746 case GRUB_SCRIPT_ARG_TYPE_SQSTR:
747 if (append (&result, arg->str, 1))
748 goto fail;
749 break;
751 arg = arg->next;
755 if (! result.args[result.argc - 1])
756 result.argc--;
758 /* Perform wildcard expansion. */
760 int j;
761 int failed = 0;
762 struct grub_script_argv unexpanded = result;
764 result.argc = 0;
765 result.args = 0;
766 for (i = 0; unexpanded.args[i]; i++)
768 char **expansions = 0;
769 if (grub_wildcard_translator
770 && grub_wildcard_translator->expand (unexpanded.args[i],
771 &expansions))
773 grub_script_argv_free (&unexpanded);
774 goto fail;
777 if (! expansions)
779 grub_script_argv_next (&result);
780 append (&result, unexpanded.args[i], -1);
782 else
784 for (j = 0; expansions[j]; j++)
786 failed = (failed || grub_script_argv_next (&result) ||
787 append (&result, expansions[j], 0));
788 grub_free (expansions[j]);
790 grub_free (expansions);
792 if (failed)
794 grub_script_argv_free (&unexpanded);
795 goto fail;
799 grub_script_argv_free (&unexpanded);
801 *argv = result;
802 return 0;
804 fail:
806 grub_script_argv_free (&result);
807 return 1;
810 static grub_err_t
811 grub_script_execute_cmd (struct grub_script_cmd *cmd)
813 int ret;
814 char errnobuf[ERRNO_DIGITS_MAX + 1];
816 if (cmd == 0)
817 return 0;
819 ret = cmd->exec (cmd);
821 grub_snprintf (errnobuf, sizeof (errnobuf), "%d", ret);
822 grub_env_set ("?", errnobuf);
823 return ret;
826 /* Execute a function call. */
827 grub_err_t
828 grub_script_function_call (grub_script_function_t func, int argc, char **args)
830 grub_err_t ret = 0;
831 unsigned long loops = active_loops;
832 struct grub_script_scope *old_scope;
833 struct grub_script_scope new_scope;
835 active_loops = 0;
836 new_scope.flags = 0;
837 new_scope.shifts = 0;
838 new_scope.argv.argc = argc;
839 new_scope.argv.args = args;
841 old_scope = scope;
842 scope = &new_scope;
844 func->executing++;
845 ret = grub_script_execute (func->func);
846 func->executing--;
848 function_return = 0;
849 active_loops = loops;
850 replace_scope (old_scope); /* free any scopes by setparams */
851 return ret;
854 /* Helper for grub_script_execute_sourcecode. */
855 static grub_err_t
856 grub_script_execute_sourcecode_getline (char **line,
857 int cont __attribute__ ((unused)),
858 void *data)
860 const char **source = data;
861 const char *p;
863 if (! *source)
865 *line = 0;
866 return 0;
869 p = grub_strchr (*source, '\n');
871 if (p)
872 *line = grub_strndup (*source, p - *source);
873 else
874 *line = grub_strdup (*source);
875 *source = p ? p + 1 : 0;
876 return 0;
879 /* Execute a source script. */
880 grub_err_t
881 grub_script_execute_sourcecode (const char *source)
883 grub_err_t ret = 0;
884 struct grub_script *parsed_script;
886 while (source)
888 char *line;
890 grub_script_execute_sourcecode_getline (&line, 0, &source);
891 parsed_script = grub_script_parse
892 (line, grub_script_execute_sourcecode_getline, &source);
893 if (! parsed_script)
895 ret = grub_errno;
896 grub_free (line);
897 break;
900 ret = grub_script_execute (parsed_script);
901 grub_script_free (parsed_script);
902 grub_free (line);
905 return ret;
908 /* Execute a source script in new scope. */
909 grub_err_t
910 grub_script_execute_new_scope (const char *source, int argc, char **args)
912 grub_err_t ret = 0;
913 struct grub_script_scope new_scope;
914 struct grub_script_scope *old_scope;
916 new_scope.argv.argc = argc;
917 new_scope.argv.args = args;
918 new_scope.flags = 0;
920 old_scope = scope;
921 scope = &new_scope;
923 ret = grub_script_execute_sourcecode (source);
925 scope = old_scope;
926 return ret;
929 /* Execute a single command line. */
930 grub_err_t
931 grub_script_execute_cmdline (struct grub_script_cmd *cmd)
933 struct grub_script_cmdline *cmdline = (struct grub_script_cmdline *) cmd;
934 grub_command_t grubcmd;
935 grub_err_t ret = 0;
936 grub_script_function_t func = 0;
937 char errnobuf[18];
938 char *cmdname, *cmdstring;
939 int argc, offset = 0, cmdlen = 0;
940 unsigned int i;
941 char **args;
942 int invert;
943 struct grub_script_argv argv = { 0, 0, 0 };
945 /* Lookup the command. */
946 if (grub_script_arglist_to_argv (cmdline->arglist, &argv) || ! argv.args || ! argv.args[0])
947 return grub_errno;
949 for (i = 0; i < argv.argc; i++)
951 cmdlen += grub_strlen (argv.args[i]) + 1;
954 cmdstring = grub_malloc (cmdlen);
955 if (!cmdstring)
957 return grub_error (GRUB_ERR_OUT_OF_MEMORY,
958 N_("cannot allocate command buffer"));
961 for (i = 0; i < argv.argc; i++)
963 offset += grub_snprintf (cmdstring + offset, cmdlen - offset, "%s ",
964 argv.args[i]);
966 cmdstring[cmdlen - 1] = '\0';
967 grub_verify_string (cmdstring, GRUB_VERIFY_COMMAND);
968 grub_free (cmdstring);
969 invert = 0;
970 argc = argv.argc - 1;
971 args = argv.args + 1;
972 cmdname = argv.args[0];
973 if (grub_strcmp (cmdname, "!") == 0)
975 if (argv.argc < 2 || ! argv.args[1])
977 grub_script_argv_free (&argv);
978 return grub_error (GRUB_ERR_BAD_ARGUMENT,
979 N_("no command is specified"));
982 invert = 1;
983 argc = argv.argc - 2;
984 args = argv.args + 2;
985 cmdname = argv.args[1];
987 grubcmd = grub_command_find (cmdname);
988 if (! grubcmd)
990 grub_errno = GRUB_ERR_NONE;
992 /* It's not a GRUB command, try all functions. */
993 func = grub_script_function_find (cmdname);
994 if (! func)
996 /* As a last resort, try if it is an assignment. */
997 char *assign = grub_strdup (cmdname);
998 char *eq = grub_strchr (assign, '=');
1000 if (eq)
1002 /* This was set because the command was not found. */
1003 grub_errno = GRUB_ERR_NONE;
1005 /* Create two strings and set the variable. */
1006 *eq = '\0';
1007 eq++;
1008 grub_script_env_set (assign, eq);
1010 grub_free (assign);
1012 grub_snprintf (errnobuf, sizeof (errnobuf), "%d", grub_errno);
1013 grub_script_env_set ("?", errnobuf);
1015 grub_script_argv_free (&argv);
1016 grub_print_error ();
1018 return 0;
1022 /* Execute the GRUB command or function. */
1023 if (grubcmd)
1025 if (grub_extractor_level && !(grubcmd->flags
1026 & GRUB_COMMAND_FLAG_EXTRACTOR))
1027 ret = grub_error (GRUB_ERR_EXTRACTOR,
1028 "%s isn't allowed to execute in an extractor",
1029 cmdname);
1030 else if ((grubcmd->flags & GRUB_COMMAND_FLAG_BLOCKS) &&
1031 (grubcmd->flags & GRUB_COMMAND_FLAG_EXTCMD))
1032 ret = grub_extcmd_dispatcher (grubcmd, argc, args, argv.script);
1033 else
1034 ret = (grubcmd->func) (grubcmd, argc, args);
1036 else
1037 ret = grub_script_function_call (func, argc, args);
1039 if (invert)
1041 if (ret == GRUB_ERR_TEST_FAILURE)
1042 grub_errno = ret = GRUB_ERR_NONE;
1043 else if (ret == GRUB_ERR_NONE)
1044 ret = grub_error (GRUB_ERR_TEST_FAILURE, N_("false"));
1045 else
1047 grub_print_error ();
1048 ret = GRUB_ERR_NONE;
1052 /* Free arguments. */
1053 grub_script_argv_free (&argv);
1055 if (grub_errno == GRUB_ERR_TEST_FAILURE)
1056 grub_errno = GRUB_ERR_NONE;
1058 grub_print_error ();
1060 grub_snprintf (errnobuf, sizeof (errnobuf), "%d", ret);
1061 grub_env_set ("?", errnobuf);
1063 return ret;
1066 /* Execute a block of one or more commands. */
1067 grub_err_t
1068 grub_script_execute_cmdlist (struct grub_script_cmd *list)
1070 int ret = 0;
1071 struct grub_script_cmd *cmd;
1073 /* Loop over every command and execute it. */
1074 for (cmd = list->next; cmd; cmd = cmd->next)
1076 if (active_breaks)
1077 break;
1079 ret = grub_script_execute_cmd (cmd);
1081 if (function_return)
1082 break;
1085 return ret;
1088 /* Execute an if statement. */
1089 grub_err_t
1090 grub_script_execute_cmdif (struct grub_script_cmd *cmd)
1092 int ret;
1093 const char *result;
1094 struct grub_script_cmdif *cmdif = (struct grub_script_cmdif *) cmd;
1096 /* Check if the commands results in a true or a false. The value is
1097 read from the env variable `?'. */
1098 ret = grub_script_execute_cmd (cmdif->exec_to_evaluate);
1099 if (function_return)
1100 return ret;
1102 result = grub_env_get ("?");
1103 grub_errno = GRUB_ERR_NONE;
1105 /* Execute the `if' or the `else' part depending on the value of
1106 `?'. */
1107 if (result && ! grub_strcmp (result, "0"))
1108 return grub_script_execute_cmd (cmdif->exec_on_true);
1109 else
1110 return grub_script_execute_cmd (cmdif->exec_on_false);
1113 /* Execute a for statement. */
1114 grub_err_t
1115 grub_script_execute_cmdfor (struct grub_script_cmd *cmd)
1117 unsigned i;
1118 grub_err_t result;
1119 struct grub_script_argv argv = { 0, 0, 0 };
1120 struct grub_script_cmdfor *cmdfor = (struct grub_script_cmdfor *) cmd;
1122 if (grub_script_arglist_to_argv (cmdfor->words, &argv))
1123 return grub_errno;
1125 active_loops++;
1126 result = 0;
1127 for (i = 0; i < argv.argc; i++)
1129 if (is_continue && active_breaks == 1)
1130 active_breaks = 0;
1132 if (! active_breaks)
1134 grub_script_env_set (cmdfor->name->str, argv.args[i]);
1135 result = grub_script_execute_cmd (cmdfor->list);
1136 if (function_return)
1137 break;
1141 if (active_breaks)
1142 active_breaks--;
1144 active_loops--;
1145 grub_script_argv_free (&argv);
1146 return result;
1149 /* Execute a "while" or "until" command. */
1150 grub_err_t
1151 grub_script_execute_cmdwhile (struct grub_script_cmd *cmd)
1153 int result;
1154 struct grub_script_cmdwhile *cmdwhile = (struct grub_script_cmdwhile *) cmd;
1156 active_loops++;
1157 do {
1158 result = grub_script_execute_cmd (cmdwhile->cond);
1159 if (function_return)
1160 break;
1162 if (cmdwhile->until ? !result : result)
1163 break;
1165 result = grub_script_execute_cmd (cmdwhile->list);
1166 if (function_return)
1167 break;
1169 if (active_breaks == 1 && is_continue)
1170 active_breaks = 0;
1172 if (active_breaks)
1173 break;
1175 } while (1); /* XXX Put a check for ^C here */
1177 if (active_breaks)
1178 active_breaks--;
1180 active_loops--;
1181 return result;
1184 /* Execute any GRUB pre-parsed command or script. */
1185 grub_err_t
1186 grub_script_execute (struct grub_script *script)
1188 if (script == 0)
1189 return 0;
1191 return grub_script_execute_cmd (script->cmd);