Indentation fix, cleanup.
[AROS.git] / arch / all-pc / boot / grub2-aros / grub-core / script / execute.c
blobbb70ebf175dc619f6a7c0de05a71eabb017b2b34
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>
31 /* Max digits for a char is 3 (0xFF is 255), similarly for an int it
32 is sizeof (int) * 3, and one extra for a possible -ve sign. */
33 #define ERRNO_DIGITS_MAX (sizeof (int) * 3 + 1)
35 static unsigned long is_continue;
36 static unsigned long active_loops;
37 static unsigned long active_breaks;
38 static unsigned long function_return;
40 #define GRUB_SCRIPT_SCOPE_MALLOCED 1
41 #define GRUB_SCRIPT_SCOPE_ARGS_MALLOCED 2
43 /* Scope for grub script functions. */
44 struct grub_script_scope
46 unsigned flags;
47 unsigned shifts;
48 struct grub_script_argv argv;
50 static struct grub_script_scope *scope = 0;
52 /* Wildcard translator for GRUB script. */
53 struct grub_script_wildcard_translator *grub_wildcard_translator;
55 static char*
56 wildcard_escape (const char *s)
58 int i;
59 int len;
60 char ch;
61 char *p;
63 len = grub_strlen (s);
64 p = grub_malloc (len * 2 + 1);
65 if (! p)
66 return NULL;
68 i = 0;
69 while ((ch = *s++))
71 if (ch == '*' || ch == '\\' || ch == '?')
72 p[i++] = '\\';
73 p[i++] = ch;
75 p[i] = '\0';
76 return p;
79 static char*
80 wildcard_unescape (const char *s)
82 int i;
83 int len;
84 char ch;
85 char *p;
87 len = grub_strlen (s);
88 p = grub_malloc (len + 1);
89 if (! p)
90 return NULL;
92 i = 0;
93 while ((ch = *s++))
95 if (ch == '\\')
96 p[i++] = *s++;
97 else
98 p[i++] = ch;
100 p[i] = '\0';
101 return p;
104 static void
105 replace_scope (struct grub_script_scope *new_scope)
107 if (scope)
109 scope->argv.argc += scope->shifts;
110 scope->argv.args -= scope->shifts;
112 if (scope->flags & GRUB_SCRIPT_SCOPE_ARGS_MALLOCED)
113 grub_script_argv_free (&scope->argv);
115 if (scope->flags & GRUB_SCRIPT_SCOPE_MALLOCED)
116 grub_free (scope);
118 scope = new_scope;
121 grub_err_t
122 grub_script_break (grub_command_t cmd, int argc, char *argv[])
124 char *p = 0;
125 unsigned long count;
127 if (argc == 0)
128 count = 1;
129 else if (argc > 1)
130 return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
131 else
133 count = grub_strtoul (argv[0], &p, 10);
134 if (grub_errno)
135 return grub_errno;
136 if (*p != '\0')
137 return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("unrecognized number"));
138 if (count == 0)
139 /* TRANSLATORS: 0 is a quantifier. "break" (similar to bash)
140 can be used e.g. to break 3 loops at once.
141 But asking it to break 0 loops makes no sense. */
142 return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("can't break 0 loops"));
145 is_continue = grub_strcmp (cmd->name, "break") ? 1 : 0;
146 active_breaks = count;
147 if (active_breaks > active_loops)
148 active_breaks = active_loops;
149 return GRUB_ERR_NONE;
152 grub_err_t
153 grub_script_shift (grub_command_t cmd __attribute__((unused)),
154 int argc, char *argv[])
156 char *p = 0;
157 unsigned long n = 0;
159 if (! scope)
160 return GRUB_ERR_NONE;
162 if (argc == 0)
163 n = 1;
165 else if (argc > 1)
166 return GRUB_ERR_BAD_ARGUMENT;
168 else
170 n = grub_strtoul (argv[0], &p, 10);
171 if (*p != '\0')
172 return GRUB_ERR_BAD_ARGUMENT;
175 if (n > scope->argv.argc)
176 return GRUB_ERR_BAD_ARGUMENT;
178 scope->shifts += n;
179 scope->argv.argc -= n;
180 scope->argv.args += n;
181 return GRUB_ERR_NONE;
184 grub_err_t
185 grub_script_setparams (grub_command_t cmd __attribute__((unused)),
186 int argc, char **args)
188 struct grub_script_scope *new_scope;
189 struct grub_script_argv argv = { 0, 0, 0 };
191 if (! scope)
192 return GRUB_ERR_INVALID_COMMAND;
194 new_scope = grub_malloc (sizeof (*new_scope));
195 if (! new_scope)
196 return grub_errno;
198 if (grub_script_argv_make (&argv, argc, args))
200 grub_free (new_scope);
201 return grub_errno;
204 new_scope->shifts = 0;
205 new_scope->argv = argv;
206 new_scope->flags = GRUB_SCRIPT_SCOPE_MALLOCED |
207 GRUB_SCRIPT_SCOPE_ARGS_MALLOCED;
209 replace_scope (new_scope);
210 return GRUB_ERR_NONE;
213 grub_err_t
214 grub_script_return (grub_command_t cmd __attribute__((unused)),
215 int argc, char *argv[])
217 char *p;
218 unsigned long n;
220 if (! scope || argc > 1)
221 return grub_error (GRUB_ERR_BAD_ARGUMENT,
222 /* TRANSLATORS: It's about not being
223 inside a function. "return" can be used only
224 in a function and this error occurs if it's used
225 anywhere else. */
226 N_("not in function body"));
228 if (argc == 0)
230 const char *t;
231 function_return = 1;
232 t = grub_env_get ("?");
233 if (!t)
234 return GRUB_ERR_NONE;
235 return grub_strtoul (t, NULL, 10);
238 n = grub_strtoul (argv[0], &p, 10);
239 if (grub_errno)
240 return grub_errno;
241 if (*p != '\0')
242 return grub_error (GRUB_ERR_BAD_ARGUMENT,
243 N_("unrecognized number"));
245 function_return = 1;
246 return n ? grub_error (n, N_("false")) : GRUB_ERR_NONE;
249 static int
250 grub_env_special (const char *name)
252 if (grub_isdigit (name[0]) ||
253 grub_strcmp (name, "#") == 0 ||
254 grub_strcmp (name, "*") == 0 ||
255 grub_strcmp (name, "@") == 0)
256 return 1;
257 return 0;
260 static char **
261 grub_script_env_get (const char *name, grub_script_arg_type_t type)
263 unsigned i;
264 struct grub_script_argv result = { 0, 0, 0 };
266 if (grub_script_argv_next (&result))
267 goto fail;
269 if (! grub_env_special (name))
271 const char *v = grub_env_get (name);
272 if (v && v[0])
274 if (type == GRUB_SCRIPT_ARG_TYPE_VAR)
276 if (grub_script_argv_split_append (&result, v))
277 goto fail;
279 else
280 if (grub_script_argv_append (&result, v, grub_strlen (v)))
281 goto fail;
284 else if (! scope)
286 if (grub_script_argv_append (&result, 0, 0))
287 goto fail;
289 else if (grub_strcmp (name, "#") == 0)
291 char buffer[ERRNO_DIGITS_MAX + 1];
292 grub_snprintf (buffer, sizeof (buffer), "%u", scope->argv.argc);
293 if (grub_script_argv_append (&result, buffer, grub_strlen (buffer)))
294 goto fail;
296 else if (grub_strcmp (name, "*") == 0)
298 for (i = 0; i < scope->argv.argc; i++)
299 if (type == GRUB_SCRIPT_ARG_TYPE_VAR)
301 if (i != 0 && grub_script_argv_next (&result))
302 goto fail;
304 if (grub_script_argv_split_append (&result, scope->argv.args[i]))
305 goto fail;
307 else
309 if (i != 0 && grub_script_argv_append (&result, " ", 1))
310 goto fail;
312 if (grub_script_argv_append (&result, scope->argv.args[i],
313 grub_strlen (scope->argv.args[i])))
314 goto fail;
317 else if (grub_strcmp (name, "@") == 0)
319 for (i = 0; i < scope->argv.argc; i++)
321 if (i != 0 && grub_script_argv_next (&result))
322 goto fail;
324 if (type == GRUB_SCRIPT_ARG_TYPE_VAR)
326 if (grub_script_argv_split_append (&result, scope->argv.args[i]))
327 goto fail;
329 else
330 if (grub_script_argv_append (&result, scope->argv.args[i],
331 grub_strlen (scope->argv.args[i])))
332 goto fail;
335 else
337 unsigned long num = grub_strtoul (name, 0, 10);
338 if (num == 0)
339 ; /* XXX no file name, for now. */
341 else if (num <= scope->argv.argc)
343 if (type == GRUB_SCRIPT_ARG_TYPE_VAR)
345 if (grub_script_argv_split_append (&result,
346 scope->argv.args[num - 1]))
347 goto fail;
349 else
350 if (grub_script_argv_append (&result, scope->argv.args[num - 1],
351 grub_strlen (scope->argv.args[num - 1])
353 goto fail;
357 return result.args;
359 fail:
361 grub_script_argv_free (&result);
362 return 0;
365 static grub_err_t
366 grub_script_env_set (const char *name, const char *val)
368 if (grub_env_special (name))
369 return grub_error (GRUB_ERR_BAD_ARGUMENT,
370 N_("invalid variable name `%s'"), name);
372 return grub_env_set (name, val);
375 struct gettext_context
377 char **allowed_strings;
378 grub_size_t nallowed_strings;
379 grub_size_t additional_len;
382 static int
383 parse_string (const char *str,
384 int (*hook) (const char *var, grub_size_t varlen,
385 char **ptr, struct gettext_context *ctx),
386 struct gettext_context *ctx,
387 char *put)
389 const char *ptr;
390 int escaped = 0;
391 const char *optr;
393 for (ptr = str; ptr && *ptr; )
394 switch (*ptr)
396 case '\\':
397 escaped = !escaped;
398 if (!escaped && put)
399 *(put++) = '\\';
400 ptr++;
401 break;
402 case '$':
403 if (escaped)
405 escaped = 0;
406 if (put)
407 *(put++) = *ptr;
408 ptr++;
409 break;
412 ptr++;
413 switch (*ptr)
415 case '{':
417 optr = ptr + 1;
418 ptr = grub_strchr (optr, '}');
419 if (!ptr)
420 break;
421 if (hook (optr, ptr - optr, &put, ctx))
422 return 1;
423 ptr++;
424 break;
426 case '0' ... '9':
427 optr = ptr;
428 while (*ptr >= '0' && *ptr <= '9')
429 ptr++;
430 if (hook (optr, ptr - optr, &put, ctx))
431 return 1;
432 break;
433 case 'a' ... 'z':
434 case 'A' ... 'Z':
435 case '_':
436 optr = ptr;
437 while ((*ptr >= '0' && *ptr <= '9')
438 || (*ptr >= 'a' && *ptr <= 'z')
439 || (*ptr >= 'A' && *ptr <= 'Z')
440 || *ptr == '_')
441 ptr++;
442 if (hook (optr, ptr - optr, &put, ctx))
443 return 1;
444 break;
445 case '?':
446 case '#':
447 if (hook (ptr, 1, &put, ctx))
448 return 1;
449 ptr++;
450 break;
451 default:
452 if (put)
453 *(put++) = '$';
455 break;
456 default:
457 if (escaped && put)
458 *(put++) = '\\';
459 escaped = 0;
460 if (put)
461 *(put++) = *ptr;
462 ptr++;
463 break;
465 if (put)
466 *(put++) = 0;
467 return 0;
470 static int
471 gettext_putvar (const char *str, grub_size_t len,
472 char **ptr, struct gettext_context *ctx)
474 const char *var;
475 grub_size_t i;
477 for (i = 0; i < ctx->nallowed_strings; i++)
478 if (grub_strncmp (ctx->allowed_strings[i], str, len) == 0
479 && ctx->allowed_strings[i][len] == 0)
481 break;
483 if (i == ctx->nallowed_strings)
484 return 0;
486 /* Enough for any number. */
487 if (len == 1 && str[0] == '#')
489 grub_snprintf (*ptr, 30, "%u", scope->argv.argc);
490 *ptr += grub_strlen (*ptr);
491 return 0;
493 var = grub_env_get (ctx->allowed_strings[i]);
494 if (var)
495 *ptr = grub_stpcpy (*ptr, var);
496 return 0;
499 static int
500 gettext_save_allow (const char *str, grub_size_t len,
501 char **ptr __attribute__ ((unused)),
502 struct gettext_context *ctx)
504 ctx->allowed_strings[ctx->nallowed_strings++] = grub_strndup (str, len);
505 if (!ctx->allowed_strings[ctx->nallowed_strings - 1])
506 return 1;
507 return 0;
510 static int
511 gettext_getlen (const char *str, grub_size_t len,
512 char **ptr __attribute__ ((unused)),
513 struct gettext_context *ctx)
515 const char *var;
516 grub_size_t i;
518 for (i = 0; i < ctx->nallowed_strings; i++)
519 if (grub_strncmp (ctx->allowed_strings[i], str, len) == 0
520 && ctx->allowed_strings[i][len] == 0)
521 break;
522 if (i == ctx->nallowed_strings)
523 return 0;
525 /* Enough for any number. */
526 if (len == 1 && str[0] == '#')
528 ctx->additional_len += 30;
529 return 0;
531 var = grub_env_get (ctx->allowed_strings[i]);
532 if (var)
533 ctx->additional_len += grub_strlen (var);
534 return 0;
537 static int
538 gettext_append (struct grub_script_argv *result, const char *orig_str)
540 const char *template;
541 char *res = 0;
542 struct gettext_context ctx = {
543 .allowed_strings = 0,
544 .nallowed_strings = 0,
545 .additional_len = 1
547 int rval = 1;
548 const char *iptr;
550 grub_size_t dollar_cnt = 0;
552 for (iptr = orig_str; *iptr; iptr++)
553 if (*iptr == '$')
554 dollar_cnt++;
555 ctx.allowed_strings = grub_malloc (sizeof (ctx.allowed_strings[0]) * dollar_cnt);
557 if (parse_string (orig_str, gettext_save_allow, &ctx, 0))
558 goto fail;
560 template = _(orig_str);
562 if (parse_string (template, gettext_getlen, &ctx, 0))
563 goto fail;
565 res = grub_malloc (grub_strlen (template) + ctx.additional_len);
566 if (!res)
567 goto fail;
569 if (parse_string (template, gettext_putvar, &ctx, res))
570 goto fail;
572 char *escaped = 0;
573 escaped = wildcard_escape (res);
574 if (grub_script_argv_append (result, escaped, grub_strlen (escaped)))
576 grub_free (escaped);
577 goto fail;
579 grub_free (escaped);
581 rval = 0;
582 fail:
583 grub_free (res);
585 grub_size_t i;
586 for (i = 0; i < ctx.nallowed_strings; i++)
587 grub_free (ctx.allowed_strings[i]);
589 grub_free (ctx.allowed_strings);
590 return rval;
593 static int
594 append (struct grub_script_argv *result,
595 const char *s, int escape_type)
597 int r;
598 char *p = 0;
600 if (escape_type == 0)
601 return grub_script_argv_append (result, s, grub_strlen (s));
603 if (escape_type > 0)
604 p = wildcard_escape (s);
605 else if (escape_type < 0)
606 p = wildcard_unescape (s);
608 if (! p)
609 return 1;
611 r = grub_script_argv_append (result, p, grub_strlen (p));
612 grub_free (p);
613 return r;
616 /* Convert arguments in ARGLIST into ARGV form. */
617 static int
618 grub_script_arglist_to_argv (struct grub_script_arglist *arglist,
619 struct grub_script_argv *argv)
621 int i;
622 char **values = 0;
623 struct grub_script_arg *arg = 0;
624 struct grub_script_argv result = { 0, 0, 0 };
626 for (; arglist && arglist->arg; arglist = arglist->next)
628 if (grub_script_argv_next (&result))
629 goto fail;
631 arg = arglist->arg;
632 while (arg)
634 switch (arg->type)
636 case GRUB_SCRIPT_ARG_TYPE_VAR:
637 case GRUB_SCRIPT_ARG_TYPE_DQVAR:
639 int need_cleanup = 0;
641 values = grub_script_env_get (arg->str, arg->type);
642 for (i = 0; values && values[i]; i++)
644 if (!need_cleanup)
646 if (i != 0 && grub_script_argv_next (&result))
648 need_cleanup = 1;
649 goto cleanup;
652 if (arg->type == GRUB_SCRIPT_ARG_TYPE_VAR)
654 int len;
655 char ch;
656 char *p;
657 char *op;
658 const char *s = values[i];
660 len = grub_strlen (values[i]);
661 /* \? -> \\\? */
662 /* \* -> \\\* */
663 /* \ -> \\ */
664 p = grub_malloc (len * 2 + 1);
665 if (! p)
667 need_cleanup = 1;
668 goto cleanup;
671 op = p;
672 while ((ch = *s++))
674 if (ch == '\\')
676 *op++ = '\\';
677 if (*s == '?' || *s == '*')
678 *op++ = '\\';
680 *op++ = ch;
682 *op = '\0';
684 if (grub_script_argv_append (&result, p, op - p))
686 grub_free (p);
687 need_cleanup = 1;
688 /* Fall through to cleanup */
691 else
693 if (append (&result, values[i], 1))
694 need_cleanup = 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 ret = grub_script_execute (func->func);
846 function_return = 0;
847 active_loops = loops;
848 replace_scope (old_scope); /* free any scopes by setparams */
849 return ret;
852 /* Helper for grub_script_execute_sourcecode. */
853 static grub_err_t
854 grub_script_execute_sourcecode_getline (char **line,
855 int cont __attribute__ ((unused)),
856 void *data)
858 const char **source = data;
859 const char *p;
861 if (! *source)
863 *line = 0;
864 return 0;
867 p = grub_strchr (*source, '\n');
869 if (p)
870 *line = grub_strndup (*source, p - *source);
871 else
872 *line = grub_strdup (*source);
873 *source = p ? p + 1 : 0;
874 return 0;
877 /* Execute a source script. */
878 grub_err_t
879 grub_script_execute_sourcecode (const char *source)
881 grub_err_t ret = 0;
882 struct grub_script *parsed_script;
884 while (source)
886 char *line;
888 grub_script_execute_sourcecode_getline (&line, 0, &source);
889 parsed_script = grub_script_parse
890 (line, grub_script_execute_sourcecode_getline, &source);
891 if (! parsed_script)
893 ret = grub_errno;
894 grub_free (line);
895 break;
898 ret = grub_script_execute (parsed_script);
899 grub_script_free (parsed_script);
900 grub_free (line);
903 return ret;
906 /* Execute a source script in new scope. */
907 grub_err_t
908 grub_script_execute_new_scope (const char *source, int argc, char **args)
910 grub_err_t ret = 0;
911 struct grub_script_scope new_scope;
912 struct grub_script_scope *old_scope;
914 new_scope.argv.argc = argc;
915 new_scope.argv.args = args;
916 new_scope.flags = 0;
918 old_scope = scope;
919 scope = &new_scope;
921 ret = grub_script_execute_sourcecode (source);
923 scope = old_scope;
924 return ret;
927 /* Execute a single command line. */
928 grub_err_t
929 grub_script_execute_cmdline (struct grub_script_cmd *cmd)
931 struct grub_script_cmdline *cmdline = (struct grub_script_cmdline *) cmd;
932 grub_command_t grubcmd;
933 grub_err_t ret = 0;
934 grub_script_function_t func = 0;
935 char errnobuf[18];
936 char *cmdname;
937 int argc;
938 char **args;
939 int invert;
940 struct grub_script_argv argv = { 0, 0, 0 };
942 /* Lookup the command. */
943 if (grub_script_arglist_to_argv (cmdline->arglist, &argv) || ! argv.args[0])
944 return grub_errno;
946 invert = 0;
947 argc = argv.argc - 1;
948 args = argv.args + 1;
949 cmdname = argv.args[0];
950 if (grub_strcmp (cmdname, "!") == 0)
952 if (argv.argc < 2 || ! argv.args[1])
954 grub_script_argv_free (&argv);
955 return grub_error (GRUB_ERR_BAD_ARGUMENT,
956 N_("no command is specified"));
959 invert = 1;
960 argc = argv.argc - 2;
961 args = argv.args + 2;
962 cmdname = argv.args[1];
964 grubcmd = grub_command_find (cmdname);
965 if (! grubcmd)
967 grub_errno = GRUB_ERR_NONE;
969 /* It's not a GRUB command, try all functions. */
970 func = grub_script_function_find (cmdname);
971 if (! func)
973 /* As a last resort, try if it is an assignment. */
974 char *assign = grub_strdup (cmdname);
975 char *eq = grub_strchr (assign, '=');
977 if (eq)
979 /* This was set because the command was not found. */
980 grub_errno = GRUB_ERR_NONE;
982 /* Create two strings and set the variable. */
983 *eq = '\0';
984 eq++;
985 grub_script_env_set (assign, eq);
987 grub_free (assign);
989 grub_snprintf (errnobuf, sizeof (errnobuf), "%d", grub_errno);
990 grub_script_env_set ("?", errnobuf);
992 grub_script_argv_free (&argv);
993 grub_print_error ();
995 return 0;
999 /* Execute the GRUB command or function. */
1000 if (grubcmd)
1002 if (grub_extractor_level && !(grubcmd->flags
1003 & GRUB_COMMAND_FLAG_EXTRACTOR))
1004 ret = grub_error (GRUB_ERR_EXTRACTOR,
1005 "%s isn't allowed to execute in an extractor",
1006 cmdname);
1007 else if ((grubcmd->flags & GRUB_COMMAND_FLAG_BLOCKS) &&
1008 (grubcmd->flags & GRUB_COMMAND_FLAG_EXTCMD))
1009 ret = grub_extcmd_dispatcher (grubcmd, argc, args, argv.script);
1010 else
1011 ret = (grubcmd->func) (grubcmd, argc, args);
1013 else
1014 ret = grub_script_function_call (func, argc, args);
1016 if (invert)
1018 if (ret == GRUB_ERR_TEST_FAILURE)
1019 grub_errno = ret = GRUB_ERR_NONE;
1020 else if (ret == GRUB_ERR_NONE)
1021 ret = grub_error (GRUB_ERR_TEST_FAILURE, N_("false"));
1022 else
1024 grub_print_error ();
1025 ret = GRUB_ERR_NONE;
1029 /* Free arguments. */
1030 grub_script_argv_free (&argv);
1032 if (grub_errno == GRUB_ERR_TEST_FAILURE)
1033 grub_errno = GRUB_ERR_NONE;
1035 grub_print_error ();
1037 grub_snprintf (errnobuf, sizeof (errnobuf), "%d", ret);
1038 grub_env_set ("?", errnobuf);
1040 return ret;
1043 /* Execute a block of one or more commands. */
1044 grub_err_t
1045 grub_script_execute_cmdlist (struct grub_script_cmd *list)
1047 int ret = 0;
1048 struct grub_script_cmd *cmd;
1050 /* Loop over every command and execute it. */
1051 for (cmd = list->next; cmd; cmd = cmd->next)
1053 if (active_breaks)
1054 break;
1056 ret = grub_script_execute_cmd (cmd);
1058 if (function_return)
1059 break;
1062 return ret;
1065 /* Execute an if statement. */
1066 grub_err_t
1067 grub_script_execute_cmdif (struct grub_script_cmd *cmd)
1069 int ret;
1070 const char *result;
1071 struct grub_script_cmdif *cmdif = (struct grub_script_cmdif *) cmd;
1073 /* Check if the commands results in a true or a false. The value is
1074 read from the env variable `?'. */
1075 ret = grub_script_execute_cmd (cmdif->exec_to_evaluate);
1076 if (function_return)
1077 return ret;
1079 result = grub_env_get ("?");
1080 grub_errno = GRUB_ERR_NONE;
1082 /* Execute the `if' or the `else' part depending on the value of
1083 `?'. */
1084 if (result && ! grub_strcmp (result, "0"))
1085 return grub_script_execute_cmd (cmdif->exec_on_true);
1086 else
1087 return grub_script_execute_cmd (cmdif->exec_on_false);
1090 /* Execute a for statement. */
1091 grub_err_t
1092 grub_script_execute_cmdfor (struct grub_script_cmd *cmd)
1094 unsigned i;
1095 grub_err_t result;
1096 struct grub_script_argv argv = { 0, 0, 0 };
1097 struct grub_script_cmdfor *cmdfor = (struct grub_script_cmdfor *) cmd;
1099 if (grub_script_arglist_to_argv (cmdfor->words, &argv))
1100 return grub_errno;
1102 active_loops++;
1103 result = 0;
1104 for (i = 0; i < argv.argc; i++)
1106 if (is_continue && active_breaks == 1)
1107 active_breaks = 0;
1109 if (! active_breaks)
1111 grub_script_env_set (cmdfor->name->str, argv.args[i]);
1112 result = grub_script_execute_cmd (cmdfor->list);
1113 if (function_return)
1114 break;
1118 if (active_breaks)
1119 active_breaks--;
1121 active_loops--;
1122 grub_script_argv_free (&argv);
1123 return result;
1126 /* Execute a "while" or "until" command. */
1127 grub_err_t
1128 grub_script_execute_cmdwhile (struct grub_script_cmd *cmd)
1130 int result;
1131 struct grub_script_cmdwhile *cmdwhile = (struct grub_script_cmdwhile *) cmd;
1133 active_loops++;
1134 do {
1135 result = grub_script_execute_cmd (cmdwhile->cond);
1136 if (function_return)
1137 break;
1139 if (cmdwhile->until ? !result : result)
1140 break;
1142 result = grub_script_execute_cmd (cmdwhile->list);
1143 if (function_return)
1144 break;
1146 if (active_breaks == 1 && is_continue)
1147 active_breaks = 0;
1149 if (active_breaks)
1150 break;
1152 } while (1); /* XXX Put a check for ^C here */
1154 if (active_breaks)
1155 active_breaks--;
1157 active_loops--;
1158 return result;
1161 /* Execute any GRUB pre-parsed command or script. */
1162 grub_err_t
1163 grub_script_execute (struct grub_script *script)
1165 if (script == 0)
1166 return 0;
1168 return grub_script_execute_cmd (script->cmd);