Fix hang/crash when requesting ZPOOL with incorrect backing device
[grub2/phcoder.git] / script / sh / execute.c
blobe0b7b2ebf806a2ab916cf5c3fd8d72412009dc44
1 /* execute.c -- Execute a GRUB script. */
2 /*
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2005,2007,2008,2009 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>
29 static grub_err_t
30 grub_script_execute_cmd (struct grub_script_cmd *cmd)
32 if (cmd == 0)
33 return 0;
35 return cmd->exec (cmd);
38 /* Parse ARG and return the textual representation. Add strings are
39 concatenated and all values of the variables are filled in. */
40 char *
41 grub_script_execute_argument_to_string (struct grub_script_arg *arg)
43 int size = 0;
44 char *val;
45 char *chararg;
46 struct grub_script_arg *argi;
48 /* First determine the size of the argument. */
49 for (argi = arg; argi; argi = argi->next)
51 if (argi->type == 1)
53 val = grub_env_get (argi->str);
54 if (val)
55 size += grub_strlen (val);
57 else
58 size += grub_strlen (argi->str);
61 /* Create the argument. */
62 chararg = grub_malloc (size + 1);
63 if (! chararg)
64 return 0;
66 *chararg = '\0';
67 /* First determine the size of the argument. */
68 for (argi = arg; argi; argi = argi->next)
70 if (argi->type == 1)
72 val = grub_env_get (argi->str);
73 if (val)
74 grub_strcat (chararg, val);
76 else
77 grub_strcat (chararg, argi->str);
80 return chararg;
83 /* Execute a single command line. */
84 grub_err_t
85 grub_script_execute_cmdline (struct grub_script_cmd *cmd)
87 struct grub_script_cmdline *cmdline = (struct grub_script_cmdline *) cmd;
88 struct grub_script_arglist *arglist;
89 char **args = 0;
90 int i = 0;
91 grub_command_t grubcmd;
92 grub_err_t ret = 0;
93 int argcount = 0;
94 grub_script_function_t func = 0;
95 char errnobuf[6];
96 char *cmdname;
98 /* Lookup the command. */
99 cmdname = grub_script_execute_argument_to_string (cmdline->arglist->arg);
100 grubcmd = grub_command_find (cmdname);
101 if (! grubcmd)
103 /* Ignore errors. */
104 grub_errno = GRUB_ERR_NONE;
106 /* It's not a GRUB command, try all functions. */
107 func = grub_script_function_find (cmdname);
108 if (! func)
110 /* As a last resort, try if it is an assignment. */
111 char *assign = grub_strdup (cmdname);
112 char *eq = grub_strchr (assign, '=');
114 if (eq)
116 /* Create two strings and set the variable. */
117 *eq = '\0';
118 eq++;
119 grub_env_set (assign, eq);
121 /* This was set because the command was not found. */
122 grub_errno = GRUB_ERR_NONE;
124 grub_free (assign);
125 return 0;
128 grub_free (cmdname);
130 if (cmdline->arglist->next)
132 argcount = cmdline->arglist->argcount - 1;
134 /* Create argv from the arguments. */
135 args = grub_malloc (sizeof (char *) * argcount);
136 for (arglist = cmdline->arglist->next; arglist; arglist = arglist->next)
138 char *str;
139 str = grub_script_execute_argument_to_string (arglist->arg);
140 args[i++] = str;
144 /* Execute the GRUB command or function. */
145 if (grubcmd)
146 ret = (grubcmd->func) (grubcmd, argcount, args);
147 else
148 ret = grub_script_function_call (func, argcount, args);
150 /* Free arguments. */
151 for (i = 0; i < argcount; i++)
152 grub_free (args[i]);
153 grub_free (args);
155 grub_sprintf (errnobuf, "%d", ret);
156 grub_env_set ("?", errnobuf);
158 return ret;
161 /* Execute a block of one or more commands. */
162 grub_err_t
163 grub_script_execute_cmdblock (struct grub_script_cmd *cmd)
165 struct grub_script_cmdblock *cmdblock = (struct grub_script_cmdblock *) cmd;
167 /* Loop over every command and execute it. */
168 for (cmd = cmdblock->cmdlist; cmd; cmd = cmd->next)
169 grub_script_execute_cmd (cmd);
171 return 0;
174 /* Execute an if statement. */
175 grub_err_t
176 grub_script_execute_cmdif (struct grub_script_cmd *cmd)
178 struct grub_script_cmdif *cmdif = (struct grub_script_cmdif *) cmd;
179 char *result;
181 /* Check if the commands results in a true or a false. The value is
182 read from the env variable `?'. */
183 grub_script_execute_cmd (cmdif->exec_to_evaluate);
184 result = grub_env_get ("?");
186 grub_errno = GRUB_ERR_NONE;
188 /* Execute the `if' or the `else' part depending on the value of
189 `?'. */
190 if (result && ! grub_strcmp (result, "0"))
191 return grub_script_execute_cmd (cmdif->exec_on_true);
192 else
193 return grub_script_execute_cmd (cmdif->exec_on_false);
196 /* Execute the menu entry generate statement. */
197 grub_err_t
198 grub_script_execute_menuentry (struct grub_script_cmd *cmd)
200 struct grub_script_cmd_menuentry *cmd_menuentry;
201 struct grub_script_arglist *arglist;
202 char **args = 0;
203 int argcount = 0;
204 int i = 0;
206 cmd_menuentry = (struct grub_script_cmd_menuentry *) cmd;
208 if (cmd_menuentry->arglist)
210 argcount = cmd_menuentry->arglist->argcount;
212 /* Create argv from the arguments. */
213 args = grub_malloc (sizeof (char *) * argcount);
215 if (! args)
217 return grub_errno;
220 for (arglist = cmd_menuentry->arglist; arglist; arglist = arglist->next)
222 char *str;
223 str = grub_script_execute_argument_to_string (arglist->arg);
224 args[i++] = str;
228 grub_normal_add_menu_entry (argcount, (const char **) args,
229 cmd_menuentry->sourcecode);
231 /* Free arguments. */
232 for (i = 0; i < argcount; i++)
233 grub_free (args[i]);
234 grub_free (args);
236 return grub_errno;
241 /* Execute any GRUB pre-parsed command or script. */
242 grub_err_t
243 grub_script_execute (struct grub_script *script)
245 if (script == 0)
246 return 0;
248 return grub_script_execute_cmd (script->cmd);