execute.c 25 KB

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