execute.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  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.
  5. *
  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.
  10. *
  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.
  15. *
  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/>.
  18. */
  19. #include <grub/misc.h>
  20. #include <grub/mm.h>
  21. #include <grub/env.h>
  22. #include <grub/script_sh.h>
  23. #include <grub/command.h>
  24. #include <grub/menu.h>
  25. #include <grub/lib/arg.h>
  26. #include <grub/lib.h>
  27. /* Max digits for a char is 3 (0xFF is 255), similarly for an int it
  28. is sizeof (int) * 3, and one extra for a possible -ve sign. */
  29. #define ERRNO_DIGITS_MAX (sizeof (int) * 3 + 1)
  30. static grub_err_t
  31. grub_script_execute_cmd (struct grub_script_cmd *cmd)
  32. {
  33. int ret;
  34. char errnobuf[ERRNO_DIGITS_MAX + 1];
  35. if (cmd == 0)
  36. return 0;
  37. ret = cmd->exec (cmd);
  38. grub_snprintf (errnobuf, sizeof (errnobuf), "%d", ret);
  39. grub_env_set ("?", errnobuf);
  40. return ret;
  41. }
  42. #define ARG_ALLOCATION_UNIT (32 * sizeof (char))
  43. #define ARGV_ALLOCATION_UNIT (8 * sizeof (void*))
  44. /* Expand arguments in ARGLIST into multiple arguments. */
  45. char **
  46. grub_script_execute_arglist_to_argv (struct grub_script_arglist *arglist, int *count)
  47. {
  48. int i;
  49. int oom;
  50. int argc;
  51. int empty;
  52. char *ptr;
  53. char **argv;
  54. char *value;
  55. struct grub_script_arg *arg;
  56. auto void push (char *str);
  57. void push (char *str)
  58. {
  59. char **p;
  60. if (oom)
  61. return;
  62. p = grub_realloc (argv, ALIGN_UP (sizeof(char*) * (argc + 1), ARGV_ALLOCATION_UNIT));
  63. if (!p)
  64. oom = 1;
  65. else
  66. {
  67. p[argc++] = str;
  68. argv = p;
  69. }
  70. }
  71. auto char* append (const char *str, grub_size_t nchar);
  72. char* append (const char *str, grub_size_t nchar)
  73. {
  74. int len;
  75. int old;
  76. char *p;
  77. if (oom || !str)
  78. return 0;
  79. len = nchar ?: grub_strlen (str);
  80. old = argv[argc - 1] ? grub_strlen (argv[argc - 1]) : 0;
  81. p = grub_realloc (argv[argc - 1], ALIGN_UP(old + len + 1, ARG_ALLOCATION_UNIT));
  82. if (p)
  83. {
  84. grub_strncpy (p + old, str, len);
  85. p[old + len] = '\0';
  86. }
  87. else
  88. {
  89. oom = 1;
  90. grub_free (argv[argc - 1]);
  91. }
  92. argv[argc - 1] = p;
  93. return argv[argc - 1];
  94. }
  95. /* Move *STR to the begining of next word, but return current word. */
  96. auto char* move_to_next (char **str);
  97. char* move_to_next (char **str)
  98. {
  99. char *end;
  100. char *start;
  101. if (oom || !str || !*str)
  102. return 0;
  103. start = *str;
  104. while (*start && grub_isspace (*start)) start++;
  105. if (*start == '\0')
  106. return 0;
  107. end = start + 1;
  108. while (*end && !grub_isspace (*end)) end++;
  109. *str = end;
  110. return start;
  111. }
  112. oom = 0;
  113. argv = 0;
  114. argc = 0;
  115. push (0);
  116. for (; arglist; arglist = arglist->next)
  117. {
  118. empty = 1;
  119. arg = arglist->arg;
  120. while (arg)
  121. {
  122. switch (arg->type)
  123. {
  124. case GRUB_SCRIPT_ARG_TYPE_VAR:
  125. value = grub_env_get (arg->str);
  126. while (value && *value && (ptr = move_to_next(&value)))
  127. {
  128. empty = 0;
  129. append (ptr, value - ptr);
  130. if (*value) push(0);
  131. }
  132. break;
  133. case GRUB_SCRIPT_ARG_TYPE_TEXT:
  134. if (grub_strlen (arg->str) > 0)
  135. {
  136. empty = 0;
  137. append (arg->str, 0);
  138. }
  139. break;
  140. case GRUB_SCRIPT_ARG_TYPE_DQSTR:
  141. case GRUB_SCRIPT_ARG_TYPE_SQSTR:
  142. empty = 0;
  143. append (arg->str, 0);
  144. break;
  145. case GRUB_SCRIPT_ARG_TYPE_DQVAR:
  146. empty = 0;
  147. append (grub_env_get (arg->str), 0);
  148. break;
  149. }
  150. arg = arg->next;
  151. }
  152. if (!empty)
  153. push (0);
  154. }
  155. if (oom)
  156. {
  157. for (i = 0; i < argc; i++)
  158. grub_free (argv[i]);
  159. grub_free (argv);
  160. argv = 0;
  161. }
  162. if (argv)
  163. *count = argc - 1;
  164. return argv;
  165. }
  166. /* Execute a single command line. */
  167. grub_err_t
  168. grub_script_execute_cmdline (struct grub_script_cmd *cmd)
  169. {
  170. struct grub_script_cmdline *cmdline = (struct grub_script_cmdline *) cmd;
  171. char **args = 0;
  172. int i = 0;
  173. grub_command_t grubcmd;
  174. grub_err_t ret = 0;
  175. int argcount = 0;
  176. grub_script_function_t func = 0;
  177. char errnobuf[18];
  178. char *cmdname;
  179. /* Lookup the command. */
  180. args = grub_script_execute_arglist_to_argv (cmdline->arglist, &argcount);
  181. if (!args)
  182. return grub_errno;
  183. cmdname = args[0];
  184. grubcmd = grub_command_find (cmdname);
  185. if (! grubcmd)
  186. {
  187. grub_errno = GRUB_ERR_NONE;
  188. /* It's not a GRUB command, try all functions. */
  189. func = grub_script_function_find (cmdname);
  190. if (! func)
  191. {
  192. /* As a last resort, try if it is an assignment. */
  193. char *assign = grub_strdup (cmdname);
  194. char *eq = grub_strchr (assign, '=');
  195. if (eq)
  196. {
  197. /* This was set because the command was not found. */
  198. grub_errno = GRUB_ERR_NONE;
  199. /* Create two strings and set the variable. */
  200. *eq = '\0';
  201. eq++;
  202. grub_env_set (assign, eq);
  203. }
  204. grub_free (assign);
  205. grub_snprintf (errnobuf, sizeof (errnobuf), "%d", grub_errno);
  206. grub_env_set ("?", errnobuf);
  207. grub_print_error ();
  208. return 0;
  209. }
  210. }
  211. /* Execute the GRUB command or function. */
  212. if (grubcmd)
  213. ret = (grubcmd->func) (grubcmd, argcount - 1, args + 1);
  214. else
  215. ret = grub_script_function_call (func, argcount - 1, args + 1);
  216. /* Free arguments. */
  217. for (i = 0; i < argcount; i++)
  218. grub_free (args[i]);
  219. grub_free (args);
  220. if (grub_errno == GRUB_ERR_TEST_FAILURE)
  221. grub_errno = GRUB_ERR_NONE;
  222. grub_print_error ();
  223. grub_snprintf (errnobuf, sizeof (errnobuf), "%d", ret);
  224. grub_env_set ("?", errnobuf);
  225. return ret;
  226. }
  227. /* Execute a block of one or more commands. */
  228. grub_err_t
  229. grub_script_execute_cmdblock (struct grub_script_cmd *cmd)
  230. {
  231. int ret = 0;
  232. struct grub_script_cmdblock *cmdblock = (struct grub_script_cmdblock *) cmd;
  233. /* Loop over every command and execute it. */
  234. for (cmd = cmdblock->cmdlist; cmd; cmd = cmd->next)
  235. ret = grub_script_execute_cmd (cmd);
  236. return ret;
  237. }
  238. /* Execute an if statement. */
  239. grub_err_t
  240. grub_script_execute_cmdif (struct grub_script_cmd *cmd)
  241. {
  242. struct grub_script_cmdif *cmdif = (struct grub_script_cmdif *) cmd;
  243. char *result;
  244. /* Check if the commands results in a true or a false. The value is
  245. read from the env variable `?'. */
  246. grub_script_execute_cmd (cmdif->exec_to_evaluate);
  247. result = grub_env_get ("?");
  248. grub_errno = GRUB_ERR_NONE;
  249. /* Execute the `if' or the `else' part depending on the value of
  250. `?'. */
  251. if (result && ! grub_strcmp (result, "0"))
  252. return grub_script_execute_cmd (cmdif->exec_on_true);
  253. else
  254. return grub_script_execute_cmd (cmdif->exec_on_false);
  255. }
  256. /* Execute a for statement. */
  257. grub_err_t
  258. grub_script_execute_cmdfor (struct grub_script_cmd *cmd)
  259. {
  260. int i;
  261. int result;
  262. char **args;
  263. int argcount;
  264. struct grub_script_cmdfor *cmdfor = (struct grub_script_cmdfor *) cmd;
  265. args = grub_script_execute_arglist_to_argv (cmdfor->words, &argcount);
  266. if (!args)
  267. return grub_errno;
  268. result = 0;
  269. for (i = 0; i < argcount; i++)
  270. {
  271. grub_env_set (cmdfor->name->str, args[i]);
  272. result = grub_script_execute_cmd (cmdfor->list);
  273. grub_free (args[i]);
  274. }
  275. grub_free (args);
  276. return result;
  277. }
  278. /* Execute a "while" or "until" command. */
  279. grub_err_t
  280. grub_script_execute_cmdwhile (struct grub_script_cmd *cmd)
  281. {
  282. int cond;
  283. int result;
  284. struct grub_script_cmdwhile *cmdwhile = (struct grub_script_cmdwhile *) cmd;
  285. result = 0;
  286. do {
  287. cond = grub_script_execute_cmd (cmdwhile->cond);
  288. if (cmdwhile->until ? !cond : cond)
  289. break;
  290. result = grub_script_execute_cmd (cmdwhile->list);
  291. } while (1); /* XXX Put a check for ^C here */
  292. return result;
  293. }
  294. /* Execute the menu entry generate statement. */
  295. grub_err_t
  296. grub_script_execute_menuentry (struct grub_script_cmd *cmd)
  297. {
  298. struct grub_script_cmd_menuentry *cmd_menuentry;
  299. char **args = 0;
  300. int argcount = 0;
  301. int i = 0;
  302. cmd_menuentry = (struct grub_script_cmd_menuentry *) cmd;
  303. if (cmd_menuentry->arglist)
  304. {
  305. args = grub_script_execute_arglist_to_argv (cmd_menuentry->arglist, &argcount);
  306. if (!args)
  307. return grub_errno;
  308. }
  309. grub_menu_entry_add (argcount, (const char **) args,
  310. cmd_menuentry->sourcecode);
  311. /* Free arguments. */
  312. for (i = 0; i < argcount; i++)
  313. grub_free (args[i]);
  314. grub_free (args);
  315. return grub_errno;
  316. }
  317. /* Execute any GRUB pre-parsed command or script. */
  318. grub_err_t
  319. grub_script_execute (struct grub_script *script)
  320. {
  321. if (script == 0)
  322. return 0;
  323. return grub_script_execute_cmd (script->cmd);
  324. }