execute.c 26 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193
  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/normal.h>
  27. #include <grub/extcmd.h>
  28. #include <grub/i18n.h>
  29. #include <grub/verify.h>
  30. /* Max digits for a char is 3 (0xFF is 255), similarly for an int it
  31. is sizeof (int) * 3, and one extra for a possible -ve sign. */
  32. #define ERRNO_DIGITS_MAX (sizeof (int) * 3 + 1)
  33. static unsigned long is_continue;
  34. static unsigned long active_loops;
  35. static unsigned long active_breaks;
  36. static unsigned long function_return;
  37. #define GRUB_SCRIPT_SCOPE_MALLOCED 1
  38. #define GRUB_SCRIPT_SCOPE_ARGS_MALLOCED 2
  39. /* Scope for grub script functions. */
  40. struct grub_script_scope
  41. {
  42. unsigned flags;
  43. unsigned shifts;
  44. struct grub_script_argv argv;
  45. };
  46. static struct grub_script_scope *scope = 0;
  47. /* Wildcard translator for GRUB script. */
  48. struct grub_script_wildcard_translator *grub_wildcard_translator;
  49. static char*
  50. wildcard_escape (const char *s)
  51. {
  52. int i;
  53. int len;
  54. char ch;
  55. char *p;
  56. len = grub_strlen (s);
  57. p = grub_malloc (len * 2 + 1);
  58. if (! p)
  59. return NULL;
  60. i = 0;
  61. while ((ch = *s++))
  62. {
  63. if (ch == '*' || ch == '\\' || ch == '?')
  64. p[i++] = '\\';
  65. p[i++] = ch;
  66. }
  67. p[i] = '\0';
  68. return p;
  69. }
  70. static char*
  71. wildcard_unescape (const char *s)
  72. {
  73. int i;
  74. int len;
  75. char ch;
  76. char *p;
  77. len = grub_strlen (s);
  78. p = grub_malloc (len + 1);
  79. if (! p)
  80. return NULL;
  81. i = 0;
  82. while ((ch = *s++))
  83. {
  84. if (ch == '\\')
  85. p[i++] = *s++;
  86. else
  87. p[i++] = ch;
  88. }
  89. p[i] = '\0';
  90. return p;
  91. }
  92. static void
  93. replace_scope (struct grub_script_scope *new_scope)
  94. {
  95. if (scope)
  96. {
  97. scope->argv.argc += scope->shifts;
  98. scope->argv.args -= scope->shifts;
  99. if (scope->flags & GRUB_SCRIPT_SCOPE_ARGS_MALLOCED)
  100. grub_script_argv_free (&scope->argv);
  101. if (scope->flags & GRUB_SCRIPT_SCOPE_MALLOCED)
  102. grub_free (scope);
  103. }
  104. scope = new_scope;
  105. }
  106. grub_err_t
  107. grub_script_break (grub_command_t cmd, int argc, char *argv[])
  108. {
  109. const char *p = NULL;
  110. unsigned long count;
  111. if (argc == 0)
  112. count = 1;
  113. else if (argc > 1)
  114. return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
  115. else
  116. {
  117. count = grub_strtoul (argv[0], &p, 10);
  118. if (grub_errno)
  119. return grub_errno;
  120. if (*p != '\0')
  121. return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("unrecognized number"));
  122. if (count == 0)
  123. /* TRANSLATORS: 0 is a quantifier. "break" (similar to bash)
  124. can be used e.g. to break 3 loops at once.
  125. But asking it to break 0 loops makes no sense. */
  126. return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("can't break 0 loops"));
  127. }
  128. is_continue = grub_strcmp (cmd->name, "break") ? 1 : 0;
  129. active_breaks = count;
  130. if (active_breaks > active_loops)
  131. active_breaks = active_loops;
  132. return GRUB_ERR_NONE;
  133. }
  134. grub_err_t
  135. grub_script_shift (grub_command_t cmd __attribute__((unused)),
  136. int argc, char *argv[])
  137. {
  138. const char *p = NULL;
  139. unsigned long n = 0;
  140. if (! scope)
  141. return GRUB_ERR_NONE;
  142. if (argc == 0)
  143. n = 1;
  144. else if (argc > 1)
  145. return GRUB_ERR_BAD_ARGUMENT;
  146. else
  147. {
  148. n = grub_strtoul (argv[0], &p, 10);
  149. if (*p != '\0')
  150. return GRUB_ERR_BAD_ARGUMENT;
  151. }
  152. if (n > scope->argv.argc)
  153. return GRUB_ERR_BAD_ARGUMENT;
  154. scope->shifts += n;
  155. scope->argv.argc -= n;
  156. scope->argv.args += n;
  157. return GRUB_ERR_NONE;
  158. }
  159. grub_err_t
  160. grub_script_setparams (grub_command_t cmd __attribute__((unused)),
  161. int argc, char **args)
  162. {
  163. struct grub_script_scope *new_scope;
  164. struct grub_script_argv argv = { 0, 0, 0 };
  165. if (! scope)
  166. return GRUB_ERR_INVALID_COMMAND;
  167. new_scope = grub_malloc (sizeof (*new_scope));
  168. if (! new_scope)
  169. return grub_errno;
  170. if (grub_script_argv_make (&argv, argc, args))
  171. {
  172. grub_free (new_scope);
  173. return grub_errno;
  174. }
  175. new_scope->shifts = 0;
  176. new_scope->argv = argv;
  177. new_scope->flags = GRUB_SCRIPT_SCOPE_MALLOCED |
  178. GRUB_SCRIPT_SCOPE_ARGS_MALLOCED;
  179. replace_scope (new_scope);
  180. return GRUB_ERR_NONE;
  181. }
  182. grub_err_t
  183. grub_script_return (grub_command_t cmd __attribute__((unused)),
  184. int argc, char *argv[])
  185. {
  186. const char *p = NULL;
  187. unsigned long n;
  188. if (! scope || argc > 1)
  189. return grub_error (GRUB_ERR_BAD_ARGUMENT,
  190. /* TRANSLATORS: It's about not being
  191. inside a function. "return" can be used only
  192. in a function and this error occurs if it's used
  193. anywhere else. */
  194. N_("not in function body"));
  195. if (argc == 0)
  196. {
  197. const char *t;
  198. function_return = 1;
  199. t = grub_env_get ("?");
  200. if (!t)
  201. return GRUB_ERR_NONE;
  202. return grub_strtoul (t, NULL, 10);
  203. }
  204. n = grub_strtoul (argv[0], &p, 10);
  205. if (grub_errno)
  206. return grub_errno;
  207. if (*p != '\0')
  208. return grub_error (GRUB_ERR_BAD_ARGUMENT,
  209. N_("unrecognized number"));
  210. function_return = 1;
  211. return n ? grub_error (n, N_("false")) : GRUB_ERR_NONE;
  212. }
  213. static int
  214. grub_env_special (const char *name)
  215. {
  216. if (grub_isdigit (name[0]) ||
  217. grub_strcmp (name, "#") == 0 ||
  218. grub_strcmp (name, "*") == 0 ||
  219. grub_strcmp (name, "@") == 0)
  220. return 1;
  221. return 0;
  222. }
  223. static char **
  224. grub_script_env_get (const char *name, grub_script_arg_type_t type)
  225. {
  226. unsigned i;
  227. struct grub_script_argv result = { 0, 0, 0 };
  228. if (grub_script_argv_next (&result))
  229. goto fail;
  230. if (! grub_env_special (name))
  231. {
  232. const char *v = grub_env_get (name);
  233. if (v && v[0])
  234. {
  235. if (type == GRUB_SCRIPT_ARG_TYPE_VAR)
  236. {
  237. if (grub_script_argv_split_append (&result, v))
  238. goto fail;
  239. }
  240. else
  241. if (grub_script_argv_append (&result, v, grub_strlen (v)))
  242. goto fail;
  243. }
  244. }
  245. else if (! scope)
  246. {
  247. if (grub_script_argv_append (&result, 0, 0))
  248. goto fail;
  249. }
  250. else if (grub_strcmp (name, "#") == 0)
  251. {
  252. char buffer[ERRNO_DIGITS_MAX + 1];
  253. grub_snprintf (buffer, sizeof (buffer), "%u", scope->argv.argc);
  254. if (grub_script_argv_append (&result, buffer, grub_strlen (buffer)))
  255. goto fail;
  256. }
  257. else if (grub_strcmp (name, "*") == 0)
  258. {
  259. for (i = 0; i < scope->argv.argc; i++)
  260. if (type == GRUB_SCRIPT_ARG_TYPE_VAR)
  261. {
  262. if (i != 0 && grub_script_argv_next (&result))
  263. goto fail;
  264. if (grub_script_argv_split_append (&result, scope->argv.args[i]))
  265. goto fail;
  266. }
  267. else
  268. {
  269. if (i != 0 && grub_script_argv_append (&result, " ", 1))
  270. goto fail;
  271. if (grub_script_argv_append (&result, scope->argv.args[i],
  272. grub_strlen (scope->argv.args[i])))
  273. goto fail;
  274. }
  275. }
  276. else if (grub_strcmp (name, "@") == 0)
  277. {
  278. for (i = 0; i < scope->argv.argc; i++)
  279. {
  280. if (i != 0 && grub_script_argv_next (&result))
  281. goto fail;
  282. if (type == GRUB_SCRIPT_ARG_TYPE_VAR)
  283. {
  284. if (grub_script_argv_split_append (&result, scope->argv.args[i]))
  285. goto fail;
  286. }
  287. else
  288. if (grub_script_argv_append (&result, scope->argv.args[i],
  289. grub_strlen (scope->argv.args[i])))
  290. goto fail;
  291. }
  292. }
  293. else
  294. {
  295. unsigned long num = grub_strtoul (name, 0, 10);
  296. if (num == 0)
  297. ; /* XXX no file name, for now. */
  298. else if (num <= scope->argv.argc)
  299. {
  300. if (type == GRUB_SCRIPT_ARG_TYPE_VAR)
  301. {
  302. if (grub_script_argv_split_append (&result,
  303. scope->argv.args[num - 1]))
  304. goto fail;
  305. }
  306. else
  307. if (grub_script_argv_append (&result, scope->argv.args[num - 1],
  308. grub_strlen (scope->argv.args[num - 1])
  309. ))
  310. goto fail;
  311. }
  312. }
  313. return result.args;
  314. fail:
  315. grub_script_argv_free (&result);
  316. return 0;
  317. }
  318. static grub_err_t
  319. grub_script_env_set (const char *name, const char *val)
  320. {
  321. if (grub_env_special (name))
  322. return grub_error (GRUB_ERR_BAD_ARGUMENT,
  323. N_("invalid variable name `%s'"), name);
  324. return grub_env_set (name, val);
  325. }
  326. struct gettext_context
  327. {
  328. char **allowed_strings;
  329. grub_size_t nallowed_strings;
  330. grub_size_t additional_len;
  331. };
  332. static int
  333. parse_string (const char *str,
  334. int (*hook) (const char *var, grub_size_t varlen,
  335. char **ptr, struct gettext_context *ctx),
  336. struct gettext_context *ctx,
  337. char *put)
  338. {
  339. const char *ptr;
  340. int escaped = 0;
  341. const char *optr;
  342. for (ptr = str; ptr && *ptr; )
  343. switch (*ptr)
  344. {
  345. case '\\':
  346. escaped = !escaped;
  347. if (!escaped && put)
  348. *(put++) = '\\';
  349. ptr++;
  350. break;
  351. case '$':
  352. if (escaped)
  353. {
  354. escaped = 0;
  355. if (put)
  356. *(put++) = *ptr;
  357. ptr++;
  358. break;
  359. }
  360. ptr++;
  361. switch (*ptr)
  362. {
  363. case '{':
  364. {
  365. optr = ptr + 1;
  366. ptr = grub_strchr (optr, '}');
  367. if (!ptr)
  368. break;
  369. if (hook (optr, ptr - optr, &put, ctx))
  370. return 1;
  371. ptr++;
  372. break;
  373. }
  374. case '0' ... '9':
  375. optr = ptr;
  376. while (*ptr >= '0' && *ptr <= '9')
  377. ptr++;
  378. if (hook (optr, ptr - optr, &put, ctx))
  379. return 1;
  380. break;
  381. case 'a' ... 'z':
  382. case 'A' ... 'Z':
  383. case '_':
  384. optr = ptr;
  385. while ((*ptr >= '0' && *ptr <= '9')
  386. || (*ptr >= 'a' && *ptr <= 'z')
  387. || (*ptr >= 'A' && *ptr <= 'Z')
  388. || *ptr == '_')
  389. ptr++;
  390. if (hook (optr, ptr - optr, &put, ctx))
  391. return 1;
  392. break;
  393. case '?':
  394. case '#':
  395. if (hook (ptr, 1, &put, ctx))
  396. return 1;
  397. ptr++;
  398. break;
  399. default:
  400. if (put)
  401. *(put++) = '$';
  402. }
  403. break;
  404. default:
  405. if (escaped && put)
  406. *(put++) = '\\';
  407. escaped = 0;
  408. if (put)
  409. *(put++) = *ptr;
  410. ptr++;
  411. break;
  412. }
  413. if (put)
  414. *(put++) = 0;
  415. return 0;
  416. }
  417. static int
  418. gettext_putvar (const char *str, grub_size_t len,
  419. char **ptr, struct gettext_context *ctx)
  420. {
  421. const char *var;
  422. grub_size_t i;
  423. for (i = 0; i < ctx->nallowed_strings; i++)
  424. if (grub_strncmp (ctx->allowed_strings[i], str, len) == 0
  425. && ctx->allowed_strings[i][len] == 0)
  426. {
  427. break;
  428. }
  429. if (i == ctx->nallowed_strings)
  430. return 0;
  431. /* Enough for any number. */
  432. if (len == 1 && str[0] == '#' && scope != NULL)
  433. {
  434. grub_snprintf (*ptr, 30, "%u", scope->argv.argc);
  435. *ptr += grub_strlen (*ptr);
  436. return 0;
  437. }
  438. var = grub_env_get (ctx->allowed_strings[i]);
  439. if (var)
  440. *ptr = grub_stpcpy (*ptr, var);
  441. return 0;
  442. }
  443. static int
  444. gettext_save_allow (const char *str, grub_size_t len,
  445. char **ptr __attribute__ ((unused)),
  446. struct gettext_context *ctx)
  447. {
  448. ctx->allowed_strings[ctx->nallowed_strings++] = grub_strndup (str, len);
  449. if (!ctx->allowed_strings[ctx->nallowed_strings - 1])
  450. return 1;
  451. return 0;
  452. }
  453. static int
  454. gettext_getlen (const char *str, grub_size_t len,
  455. char **ptr __attribute__ ((unused)),
  456. struct gettext_context *ctx)
  457. {
  458. const char *var;
  459. grub_size_t i;
  460. for (i = 0; i < ctx->nallowed_strings; i++)
  461. if (grub_strncmp (ctx->allowed_strings[i], str, len) == 0
  462. && ctx->allowed_strings[i][len] == 0)
  463. break;
  464. if (i == ctx->nallowed_strings)
  465. return 0;
  466. /* Enough for any number. */
  467. if (len == 1 && str[0] == '#')
  468. {
  469. ctx->additional_len += 30;
  470. return 0;
  471. }
  472. var = grub_env_get (ctx->allowed_strings[i]);
  473. if (var)
  474. ctx->additional_len += grub_strlen (var);
  475. return 0;
  476. }
  477. static int
  478. gettext_append (struct grub_script_argv *result, const char *orig_str)
  479. {
  480. const char *template;
  481. char *res = 0;
  482. struct gettext_context ctx = {
  483. .allowed_strings = 0,
  484. .nallowed_strings = 0,
  485. .additional_len = 1
  486. };
  487. int rval = 1;
  488. const char *iptr;
  489. grub_size_t dollar_cnt = 0;
  490. for (iptr = orig_str; *iptr; iptr++)
  491. if (*iptr == '$')
  492. dollar_cnt++;
  493. ctx.allowed_strings = grub_calloc (dollar_cnt, sizeof (ctx.allowed_strings[0]));
  494. if (parse_string (orig_str, gettext_save_allow, &ctx, 0))
  495. goto fail;
  496. template = _(orig_str);
  497. if (parse_string (template, gettext_getlen, &ctx, 0))
  498. goto fail;
  499. res = grub_malloc (grub_strlen (template) + ctx.additional_len);
  500. if (!res)
  501. goto fail;
  502. if (parse_string (template, gettext_putvar, &ctx, res))
  503. goto fail;
  504. char *escaped = 0;
  505. escaped = wildcard_escape (res);
  506. if (grub_script_argv_append (result, escaped, grub_strlen (escaped)))
  507. {
  508. grub_free (escaped);
  509. goto fail;
  510. }
  511. grub_free (escaped);
  512. rval = 0;
  513. fail:
  514. grub_free (res);
  515. {
  516. grub_size_t i;
  517. for (i = 0; i < ctx.nallowed_strings; i++)
  518. grub_free (ctx.allowed_strings[i]);
  519. }
  520. grub_free (ctx.allowed_strings);
  521. return rval;
  522. }
  523. static int
  524. append (struct grub_script_argv *result,
  525. const char *s, int escape_type)
  526. {
  527. int r;
  528. char *p = 0;
  529. if (escape_type == 0)
  530. return grub_script_argv_append (result, s, grub_strlen (s));
  531. if (escape_type > 0)
  532. p = wildcard_escape (s);
  533. else if (escape_type < 0)
  534. p = wildcard_unescape (s);
  535. if (! p)
  536. return 1;
  537. r = grub_script_argv_append (result, p, grub_strlen (p));
  538. grub_free (p);
  539. return r;
  540. }
  541. /* Convert arguments in ARGLIST into ARGV form. */
  542. static int
  543. grub_script_arglist_to_argv (struct grub_script_arglist *arglist,
  544. struct grub_script_argv *argv)
  545. {
  546. int i;
  547. char **values = 0;
  548. struct grub_script_arg *arg = 0;
  549. struct grub_script_argv result = { 0, 0, 0 };
  550. if (arglist == NULL)
  551. return 1;
  552. for (; arglist && arglist->arg; arglist = arglist->next)
  553. {
  554. if (grub_script_argv_next (&result))
  555. goto fail;
  556. arg = arglist->arg;
  557. while (arg)
  558. {
  559. switch (arg->type)
  560. {
  561. case GRUB_SCRIPT_ARG_TYPE_VAR:
  562. case GRUB_SCRIPT_ARG_TYPE_DQVAR:
  563. {
  564. int need_cleanup = 0;
  565. values = grub_script_env_get (arg->str, arg->type);
  566. for (i = 0; values && values[i]; i++)
  567. {
  568. if (!need_cleanup)
  569. {
  570. if (i != 0 && grub_script_argv_next (&result))
  571. {
  572. need_cleanup = 1;
  573. goto cleanup;
  574. }
  575. if (arg->type == GRUB_SCRIPT_ARG_TYPE_VAR)
  576. {
  577. int len;
  578. char ch;
  579. char *p;
  580. char *op;
  581. const char *s = values[i];
  582. len = grub_strlen (values[i]);
  583. /* \? -> \\\? */
  584. /* \* -> \\\* */
  585. /* \ -> \\ */
  586. p = grub_malloc (len * 2 + 1);
  587. if (! p)
  588. {
  589. need_cleanup = 1;
  590. goto cleanup;
  591. }
  592. op = p;
  593. while ((ch = *s++))
  594. {
  595. if (ch == '\\')
  596. {
  597. *op++ = '\\';
  598. if (*s == '?' || *s == '*')
  599. *op++ = '\\';
  600. }
  601. *op++ = ch;
  602. }
  603. *op = '\0';
  604. need_cleanup = grub_script_argv_append (&result, p, op - p);
  605. grub_free (p);
  606. /* Fall through to cleanup */
  607. }
  608. else
  609. {
  610. need_cleanup = append (&result, values[i], 1);
  611. /* Fall through to cleanup */
  612. }
  613. }
  614. cleanup:
  615. grub_free (values[i]);
  616. }
  617. grub_free (values);
  618. if (need_cleanup)
  619. goto fail;
  620. break;
  621. }
  622. case GRUB_SCRIPT_ARG_TYPE_BLOCK:
  623. {
  624. char *p;
  625. if (grub_script_argv_append (&result, "{", 1))
  626. goto fail;
  627. p = wildcard_escape (arg->str);
  628. if (!p)
  629. goto fail;
  630. if (grub_script_argv_append (&result, p,
  631. grub_strlen (p)))
  632. {
  633. grub_free (p);
  634. goto fail;
  635. }
  636. grub_free (p);
  637. if (grub_script_argv_append (&result, "}", 1))
  638. goto fail;
  639. }
  640. result.script = arg->script;
  641. break;
  642. case GRUB_SCRIPT_ARG_TYPE_TEXT:
  643. if (arg->str[0] &&
  644. grub_script_argv_append (&result, arg->str,
  645. grub_strlen (arg->str)))
  646. goto fail;
  647. break;
  648. case GRUB_SCRIPT_ARG_TYPE_GETTEXT:
  649. {
  650. if (gettext_append (&result, arg->str))
  651. goto fail;
  652. }
  653. break;
  654. case GRUB_SCRIPT_ARG_TYPE_DQSTR:
  655. case GRUB_SCRIPT_ARG_TYPE_SQSTR:
  656. if (append (&result, arg->str, 1))
  657. goto fail;
  658. break;
  659. }
  660. arg = arg->next;
  661. }
  662. }
  663. if (! result.args[result.argc - 1])
  664. result.argc--;
  665. /* Perform wildcard expansion. */
  666. int j;
  667. int failed = 0;
  668. struct grub_script_argv unexpanded = result;
  669. result.argc = 0;
  670. result.args = 0;
  671. for (i = 0; unexpanded.args[i]; i++)
  672. {
  673. char **expansions = 0;
  674. if (grub_wildcard_translator
  675. && grub_wildcard_translator->expand (unexpanded.args[i],
  676. &expansions))
  677. {
  678. grub_script_argv_free (&unexpanded);
  679. goto fail;
  680. }
  681. if (! expansions)
  682. {
  683. grub_script_argv_next (&result);
  684. append (&result, unexpanded.args[i], -1);
  685. }
  686. else
  687. {
  688. for (j = 0; expansions[j]; j++)
  689. {
  690. failed = (failed || grub_script_argv_next (&result) ||
  691. append (&result, expansions[j], 0));
  692. grub_free (expansions[j]);
  693. }
  694. grub_free (expansions);
  695. if (failed)
  696. {
  697. grub_script_argv_free (&unexpanded);
  698. goto fail;
  699. }
  700. }
  701. }
  702. grub_script_argv_free (&unexpanded);
  703. *argv = result;
  704. return 0;
  705. fail:
  706. grub_script_argv_free (&result);
  707. return 1;
  708. }
  709. static grub_err_t
  710. grub_script_execute_cmd (struct grub_script_cmd *cmd)
  711. {
  712. int ret;
  713. char errnobuf[ERRNO_DIGITS_MAX + 1];
  714. if (cmd == 0)
  715. return 0;
  716. ret = cmd->exec (cmd);
  717. grub_snprintf (errnobuf, sizeof (errnobuf), "%d", ret);
  718. grub_env_set ("?", errnobuf);
  719. return ret;
  720. }
  721. /* Execute a function call. */
  722. grub_err_t
  723. grub_script_function_call (grub_script_function_t func, int argc, char **args)
  724. {
  725. grub_err_t ret = 0;
  726. unsigned long loops = active_loops;
  727. struct grub_script_scope *old_scope;
  728. struct grub_script_scope new_scope;
  729. active_loops = 0;
  730. new_scope.flags = 0;
  731. new_scope.shifts = 0;
  732. new_scope.argv.argc = argc;
  733. new_scope.argv.args = args;
  734. old_scope = scope;
  735. scope = &new_scope;
  736. func->executing++;
  737. ret = grub_script_execute (func->func);
  738. func->executing--;
  739. function_return = 0;
  740. active_loops = loops;
  741. replace_scope (old_scope); /* free any scopes by setparams */
  742. return ret;
  743. }
  744. /* Helper for grub_script_execute_sourcecode. */
  745. static grub_err_t
  746. grub_script_execute_sourcecode_getline (char **line,
  747. int cont __attribute__ ((unused)),
  748. void *data)
  749. {
  750. const char **source = data;
  751. const char *p;
  752. if (! *source)
  753. {
  754. *line = 0;
  755. return 0;
  756. }
  757. p = grub_strchr (*source, '\n');
  758. if (p)
  759. *line = grub_strndup (*source, p - *source);
  760. else
  761. *line = grub_strdup (*source);
  762. *source = p ? p + 1 : 0;
  763. return 0;
  764. }
  765. /* Execute a source script. */
  766. grub_err_t
  767. grub_script_execute_sourcecode (const char *source)
  768. {
  769. grub_err_t ret = 0;
  770. struct grub_script *parsed_script;
  771. while (source)
  772. {
  773. char *line;
  774. grub_script_execute_sourcecode_getline (&line, 0, &source);
  775. parsed_script = grub_script_parse
  776. (line, grub_script_execute_sourcecode_getline, &source);
  777. if (! parsed_script)
  778. {
  779. ret = grub_errno;
  780. grub_free (line);
  781. break;
  782. }
  783. ret = grub_script_execute (parsed_script);
  784. grub_script_free (parsed_script);
  785. grub_free (line);
  786. }
  787. return ret;
  788. }
  789. /* Execute a source script in new scope. */
  790. grub_err_t
  791. grub_script_execute_new_scope (const char *source, int argc, char **args)
  792. {
  793. grub_err_t ret = 0;
  794. struct grub_script_scope new_scope;
  795. struct grub_script_scope *old_scope;
  796. new_scope.argv.argc = argc;
  797. new_scope.argv.args = args;
  798. new_scope.flags = 0;
  799. old_scope = scope;
  800. scope = &new_scope;
  801. ret = grub_script_execute_sourcecode (source);
  802. scope = old_scope;
  803. return ret;
  804. }
  805. /* Execute a single command line. */
  806. grub_err_t
  807. grub_script_execute_cmdline (struct grub_script_cmd *cmd)
  808. {
  809. struct grub_script_cmdline *cmdline = (struct grub_script_cmdline *) cmd;
  810. grub_command_t grubcmd;
  811. grub_err_t ret = 0;
  812. grub_script_function_t func = 0;
  813. char errnobuf[18];
  814. char *cmdname, *cmdstring;
  815. int argc, offset = 0, cmdlen = 0;
  816. unsigned int i;
  817. char **args;
  818. int invert;
  819. struct grub_script_argv argv = { 0, 0, 0 };
  820. /* Lookup the command. */
  821. if (grub_script_arglist_to_argv (cmdline->arglist, &argv) || ! argv.args || ! argv.args[0])
  822. return grub_errno;
  823. for (i = 0; i < argv.argc; i++)
  824. {
  825. cmdlen += grub_strlen (argv.args[i]) + 1;
  826. }
  827. cmdstring = grub_malloc (cmdlen);
  828. if (!cmdstring)
  829. {
  830. return grub_error (GRUB_ERR_OUT_OF_MEMORY,
  831. N_("cannot allocate command buffer"));
  832. }
  833. for (i = 0; i < argv.argc; i++)
  834. {
  835. offset += grub_snprintf (cmdstring + offset, cmdlen - offset, "%s ",
  836. argv.args[i]);
  837. }
  838. cmdstring[cmdlen - 1] = '\0';
  839. grub_verify_string (cmdstring, GRUB_VERIFY_COMMAND);
  840. grub_free (cmdstring);
  841. invert = 0;
  842. argc = argv.argc - 1;
  843. args = argv.args + 1;
  844. cmdname = argv.args[0];
  845. if (grub_strcmp (cmdname, "!") == 0)
  846. {
  847. if (argv.argc < 2 || ! argv.args[1])
  848. {
  849. grub_script_argv_free (&argv);
  850. return grub_error (GRUB_ERR_BAD_ARGUMENT,
  851. N_("no command is specified"));
  852. }
  853. invert = 1;
  854. argc = argv.argc - 2;
  855. args = argv.args + 2;
  856. cmdname = argv.args[1];
  857. }
  858. grubcmd = grub_command_find (cmdname);
  859. if (! grubcmd)
  860. {
  861. grub_errno = GRUB_ERR_NONE;
  862. /* It's not a GRUB command, try all functions. */
  863. func = grub_script_function_find (cmdname);
  864. if (! func)
  865. {
  866. /* As a last resort, try if it is an assignment. */
  867. char *assign = grub_strdup (cmdname);
  868. char *eq = grub_strchr (assign, '=');
  869. if (eq)
  870. {
  871. /* This was set because the command was not found. */
  872. grub_errno = GRUB_ERR_NONE;
  873. /* Create two strings and set the variable. */
  874. *eq = '\0';
  875. eq++;
  876. grub_script_env_set (assign, eq);
  877. }
  878. grub_free (assign);
  879. grub_snprintf (errnobuf, sizeof (errnobuf), "%d", grub_errno);
  880. grub_script_env_set ("?", errnobuf);
  881. grub_script_argv_free (&argv);
  882. grub_print_error ();
  883. return 0;
  884. }
  885. }
  886. /* Execute the GRUB command or function. */
  887. if (grubcmd)
  888. {
  889. if (grub_extractor_level && !(grubcmd->flags
  890. & GRUB_COMMAND_FLAG_EXTRACTOR))
  891. ret = grub_error (GRUB_ERR_EXTRACTOR,
  892. "%s isn't allowed to execute in an extractor",
  893. cmdname);
  894. else if ((grubcmd->flags & GRUB_COMMAND_FLAG_BLOCKS) &&
  895. (grubcmd->flags & GRUB_COMMAND_FLAG_EXTCMD))
  896. ret = grub_extcmd_dispatcher (grubcmd, argc, args, argv.script);
  897. else
  898. ret = (grubcmd->func) (grubcmd, argc, args);
  899. }
  900. else
  901. ret = grub_script_function_call (func, argc, args);
  902. if (invert)
  903. {
  904. if (ret == GRUB_ERR_TEST_FAILURE)
  905. grub_errno = ret = GRUB_ERR_NONE;
  906. else if (ret == GRUB_ERR_NONE)
  907. ret = grub_error (GRUB_ERR_TEST_FAILURE, N_("false"));
  908. else
  909. {
  910. grub_print_error ();
  911. ret = GRUB_ERR_NONE;
  912. }
  913. }
  914. /* Free arguments. */
  915. grub_script_argv_free (&argv);
  916. if (grub_errno == GRUB_ERR_TEST_FAILURE)
  917. grub_errno = GRUB_ERR_NONE;
  918. grub_print_error ();
  919. grub_snprintf (errnobuf, sizeof (errnobuf), "%d", ret);
  920. grub_env_set ("?", errnobuf);
  921. return ret;
  922. }
  923. /* Execute a block of one or more commands. */
  924. grub_err_t
  925. grub_script_execute_cmdlist (struct grub_script_cmd *list)
  926. {
  927. int ret = 0;
  928. struct grub_script_cmd *cmd;
  929. /* Loop over every command and execute it. */
  930. for (cmd = list->next; cmd; cmd = cmd->next)
  931. {
  932. if (active_breaks)
  933. break;
  934. ret = grub_script_execute_cmd (cmd);
  935. if (function_return)
  936. break;
  937. }
  938. return ret;
  939. }
  940. /* Execute an if statement. */
  941. grub_err_t
  942. grub_script_execute_cmdif (struct grub_script_cmd *cmd)
  943. {
  944. int ret;
  945. const char *result;
  946. struct grub_script_cmdif *cmdif = (struct grub_script_cmdif *) cmd;
  947. /* Check if the commands results in a true or a false. The value is
  948. read from the env variable `?'. */
  949. ret = grub_script_execute_cmd (cmdif->exec_to_evaluate);
  950. if (function_return)
  951. return ret;
  952. result = grub_env_get ("?");
  953. grub_errno = GRUB_ERR_NONE;
  954. /* Execute the `if' or the `else' part depending on the value of
  955. `?'. */
  956. if (result && ! grub_strcmp (result, "0"))
  957. return grub_script_execute_cmd (cmdif->exec_on_true);
  958. else
  959. return grub_script_execute_cmd (cmdif->exec_on_false);
  960. }
  961. /* Execute a for statement. */
  962. grub_err_t
  963. grub_script_execute_cmdfor (struct grub_script_cmd *cmd)
  964. {
  965. unsigned i;
  966. grub_err_t result;
  967. struct grub_script_argv argv = { 0, 0, 0 };
  968. struct grub_script_cmdfor *cmdfor = (struct grub_script_cmdfor *) cmd;
  969. if (grub_script_arglist_to_argv (cmdfor->words, &argv))
  970. return grub_errno;
  971. active_loops++;
  972. result = 0;
  973. for (i = 0; i < argv.argc; i++)
  974. {
  975. if (is_continue && active_breaks == 1)
  976. active_breaks = 0;
  977. if (! active_breaks)
  978. {
  979. grub_script_env_set (cmdfor->name->str, argv.args[i]);
  980. result = grub_script_execute_cmd (cmdfor->list);
  981. if (function_return)
  982. break;
  983. }
  984. }
  985. if (active_breaks)
  986. active_breaks--;
  987. active_loops--;
  988. grub_script_argv_free (&argv);
  989. return result;
  990. }
  991. /* Execute a "while" or "until" command. */
  992. grub_err_t
  993. grub_script_execute_cmdwhile (struct grub_script_cmd *cmd)
  994. {
  995. int result;
  996. struct grub_script_cmdwhile *cmdwhile = (struct grub_script_cmdwhile *) cmd;
  997. active_loops++;
  998. do {
  999. result = grub_script_execute_cmd (cmdwhile->cond);
  1000. if (function_return)
  1001. break;
  1002. if (cmdwhile->until ? !result : result)
  1003. break;
  1004. result = grub_script_execute_cmd (cmdwhile->list);
  1005. if (function_return)
  1006. break;
  1007. if (active_breaks == 1 && is_continue)
  1008. active_breaks = 0;
  1009. if (active_breaks)
  1010. break;
  1011. } while (1); /* XXX Put a check for ^C here */
  1012. if (active_breaks)
  1013. active_breaks--;
  1014. active_loops--;
  1015. return result;
  1016. }
  1017. /* Execute any GRUB pre-parsed command or script. */
  1018. grub_err_t
  1019. grub_script_execute (struct grub_script *script)
  1020. {
  1021. if (script == 0)
  1022. return 0;
  1023. return grub_script_execute_cmd (script->cmd);
  1024. }