~darkmuggle-deactivatedaccount/ubuntu/quantal/grub2/fix-872244

« back to all changes in this revision

Viewing changes to grub-core/script/execute.c

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson, Colin Watson, Evan Broder, Mario Limonciello
  • Date: 2010-11-24 13:59:55 UTC
  • mfrom: (1.17.6 upstream) (17.6.15 experimental)
  • Revision ID: james.westby@ubuntu.com-20101124135955-r6ii5sepayr7jt53
Tags: 1.99~20101124-1ubuntu1
[ Colin Watson ]
* Resynchronise with Debian experimental.  Remaining changes:
  - Adjust for default Ubuntu boot options ("quiet splash").
  - Default to hiding the menu; holding down Shift at boot will show it.
  - Set a monochromatic theme for Ubuntu.
  - Apply Ubuntu GRUB Legacy changes to legacy update-grub script: title,
    recovery mode, quiet option, tweak how memtest86+ is displayed, and
    use UUIDs where appropriate.
  - Fix backslash-escaping in merge_debconf_into_conf.
  - Remove "GNU/Linux" from default distributor string.
  - Add crashkernel= options if kdump and makedumpfile are available.
  - If other operating systems are installed, then automatically unhide
    the menu.  Otherwise, if GRUB_HIDDEN_TIMEOUT is 0, then use keystatus
    if available to check whether Shift is pressed.  If it is, show the
    menu, otherwise boot immediately.  If keystatus is not available, then
    fall back to a short delay interruptible with Escape.
  - Allow Shift to interrupt 'sleep --interruptible'.
  - Don't display introductory message about line editing unless we're
    actually offering a shell prompt.  Don't clear the screen just before
    booting if we never drew the menu in the first place.
  - Remove some verbose messages printed before reading the configuration
    file.
  - Suppress progress messages as the kernel and initrd load for
    non-recovery kernel menu entries.
  - Change prepare_grub_to_access_device to handle filesystems
    loop-mounted on file images.
  - Ignore devices loop-mounted from files in 10_linux.
  - Show the boot menu if the previous boot failed, that is if it failed
    to get to the end of one of the normal runlevels.
  - Don't generate /boot/grub/device.map during grub-install or
    grub-mkconfig by default.
  - Adjust upgrade version checks for Ubuntu.
  - Don't display "GRUB loading" unless Shift is held down.
  - Adjust versions of grub-doc and grub-legacy-doc conflicts to tolerate
    our backport of the grub-doc split.
  - Fix LVM/RAID probing in the absence of /boot/grub/device.map.
  - Look for .mo files in /usr/share/locale-langpack as well, in
    preference.
  - Make sure GRUB_TIMEOUT isn't quoted unnecessarily.
  - Probe all devices in 'grub-probe --target=drive' if
    /boot/grub/device.map is missing.
  - Build-depend on qemu-kvm rather than qemu-system for grub-pc tests.
  - Use qemu rather than qemu-system-i386.
  - Program vesafb on BIOS systems rather than efifb.
  - Add a grub-rescue-efi-amd64 package containing a rescue CD-ROM image
    for EFI-AMD64.
  - On Wubi, don't ask for an install device, but just update wubildr
    using the diverted grub-install.
  - When embedding the core image in a post-MBR gap, check for and avoid
    sectors matching any of a list of known signatures.
  - Disable video_bochs and video_cirrus on PC BIOS systems, as probing
    PCI space seems to break on some systems.
* Downgrade "ACPI shutdown failed" error to a debug message, since it can
  cause spurious test failures.

[ Evan Broder ]
* Enable lua from grub-extras.
* Incorporate the bitop library into lua.
* Add enum_pci function to grub module in lua.
* Switch back to gfxpayload=keep by default, unless the video hardware
  is known to not support it.

[ Mario Limonciello ]
* Built part_msdos and vfat into bootx64.efi (LP: #677758)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
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
 
 
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
 
 
34
static unsigned long is_continue;
 
35
static unsigned long active_loops;
 
36
static unsigned long active_breaks;
 
37
static unsigned long function_return;
 
38
 
 
39
#define GRUB_SCRIPT_SCOPE_MALLOCED      1
 
40
#define GRUB_SCRIPT_SCOPE_ARGS_MALLOCED 2
 
41
 
 
42
/* Scope for grub script functions.  */
 
43
struct grub_script_scope
 
44
{
 
45
  unsigned flags;
 
46
  unsigned shifts;
 
47
  struct grub_script_argv argv;
 
48
};
 
49
static struct grub_script_scope *scope = 0;
 
50
 
 
51
/* Wildcard translator for GRUB script.  */
 
52
struct grub_script_wildcard_translator *grub_wildcard_translator;
 
53
 
 
54
static void
 
55
replace_scope (struct grub_script_scope *new_scope)
 
56
{
 
57
  if (scope)
 
58
    {
 
59
      scope->argv.argc += scope->shifts;
 
60
      scope->argv.args -= scope->shifts;
 
61
 
 
62
      if (scope->flags & GRUB_SCRIPT_SCOPE_ARGS_MALLOCED)
 
63
        grub_script_argv_free (&scope->argv);
 
64
 
 
65
      if (scope->flags & GRUB_SCRIPT_SCOPE_MALLOCED)
 
66
        grub_free (scope);
 
67
    }
 
68
  scope = new_scope;
 
69
}
 
70
 
 
71
grub_err_t
 
72
grub_script_break (grub_command_t cmd, int argc, char *argv[])
 
73
{
 
74
  char *p = 0;
 
75
  unsigned long count;
 
76
 
 
77
  if (argc == 0)
 
78
    count = 1;
 
79
 
 
80
  else if ((argc > 1) || (count = grub_strtoul (argv[0], &p, 10)) == 0 ||
 
81
           (*p != '\0'))
 
82
    return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad break");
 
83
 
 
84
  is_continue = grub_strcmp (cmd->name, "break") ? 1 : 0;
 
85
  active_breaks = grub_min (active_loops, count);
 
86
  return GRUB_ERR_NONE;
 
87
}
 
88
 
 
89
grub_err_t
 
90
grub_script_shift (grub_command_t cmd __attribute__((unused)),
 
91
                   int argc, char *argv[])
 
92
{
 
93
  char *p = 0;
 
94
  unsigned long n = 0;
 
95
 
 
96
  if (! scope)
 
97
    return GRUB_ERR_NONE;
 
98
 
 
99
  if (argc == 0)
 
100
    n = 1;
 
101
 
 
102
  else if (argc > 1)
 
103
    return GRUB_ERR_BAD_ARGUMENT;
 
104
 
 
105
  else
 
106
    {
 
107
      n = grub_strtoul (argv[0], &p, 10);
 
108
      if (*p != '\0')
 
109
        return GRUB_ERR_BAD_ARGUMENT;
 
110
    }
 
111
 
 
112
  if (n > scope->argv.argc)
 
113
    return GRUB_ERR_BAD_ARGUMENT;
 
114
 
 
115
  scope->shifts += n;
 
116
  scope->argv.argc -= n;
 
117
  scope->argv.args += n;
 
118
  return GRUB_ERR_NONE;
 
119
}
 
120
 
 
121
grub_err_t
 
122
grub_script_setparams (grub_command_t cmd __attribute__((unused)),
 
123
                       int argc, char **args)
 
124
{
 
125
  struct grub_script_scope *new_scope;
 
126
  struct grub_script_argv argv = { 0, 0, 0 };
 
127
 
 
128
  if (! scope)
 
129
    return GRUB_ERR_INVALID_COMMAND;
 
130
 
 
131
  new_scope = grub_malloc (sizeof (*new_scope));
 
132
  if (! new_scope)
 
133
    return grub_errno;
 
134
 
 
135
  if (grub_script_argv_make (&argv, argc, args))
 
136
    {
 
137
      grub_free (new_scope);
 
138
      return grub_errno;
 
139
    }
 
140
 
 
141
  new_scope->shifts = 0;
 
142
  new_scope->argv = argv;
 
143
  new_scope->flags = GRUB_SCRIPT_SCOPE_MALLOCED |
 
144
    GRUB_SCRIPT_SCOPE_ARGS_MALLOCED;
 
145
 
 
146
  replace_scope (new_scope);
 
147
  return GRUB_ERR_NONE;
 
148
}
 
149
 
 
150
grub_err_t
 
151
grub_script_return (grub_command_t cmd __attribute__((unused)),
 
152
                    int argc, char *argv[])
 
153
{
 
154
  char *p;
 
155
  unsigned long n;
 
156
 
 
157
  if (! scope || argc > 1)
 
158
    return grub_error (GRUB_ERR_BAD_ARGUMENT, "not in function scope");
 
159
 
 
160
  if (argc == 0)
 
161
    {
 
162
      function_return = 1;
 
163
      return grub_strtoul (grub_env_get ("?"), NULL, 10);
 
164
    }
 
165
 
 
166
  n = grub_strtoul (argv[0], &p, 10);
 
167
  if (*p != '\0')
 
168
    return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad argument");
 
169
 
 
170
  function_return = 1;
 
171
  return n ? grub_error (GRUB_ERR_TEST_FAILURE, "false") : GRUB_ERR_NONE;
 
172
}
 
173
 
 
174
static int
 
175
grub_env_special (const char *name)
 
176
{
 
177
  if (grub_isdigit (name[0]) ||
 
178
      grub_strcmp (name, "#") == 0 ||
 
179
      grub_strcmp (name, "*") == 0 ||
 
180
      grub_strcmp (name, "@") == 0)
 
181
    return 1;
 
182
  return 0;
 
183
}
 
184
 
 
185
static char **
 
186
grub_script_env_get (const char *name, grub_script_arg_type_t type)
 
187
{
 
188
  unsigned i;
 
189
  struct grub_script_argv result = { 0, 0, 0 };
 
190
 
 
191
  if (grub_script_argv_next (&result))
 
192
    goto fail;
 
193
 
 
194
  if (! grub_env_special (name))
 
195
    {
 
196
      char *v = grub_env_get (name);
 
197
      if (v && v[0])
 
198
        {
 
199
          if (type == GRUB_SCRIPT_ARG_TYPE_VAR)
 
200
            {
 
201
              if (grub_script_argv_split_append (&result, v))
 
202
                goto fail;
 
203
            }
 
204
          else
 
205
            if (grub_script_argv_append (&result, v))
 
206
              goto fail;
 
207
        }
 
208
    }
 
209
  else if (! scope)
 
210
    {
 
211
      if (grub_script_argv_append (&result, 0))
 
212
        goto fail;
 
213
    }
 
214
  else if (grub_strcmp (name, "#") == 0)
 
215
    {
 
216
      char buffer[ERRNO_DIGITS_MAX + 1];
 
217
      grub_snprintf (buffer, sizeof (buffer), "%u", scope->argv.argc);
 
218
      if (grub_script_argv_append (&result, buffer))
 
219
        goto fail;
 
220
    }
 
221
  else if (grub_strcmp (name, "*") == 0)
 
222
    {
 
223
      for (i = 0; i < scope->argv.argc; i++)
 
224
        if (type == GRUB_SCRIPT_ARG_TYPE_VAR)
 
225
          {
 
226
            if (i != 0 && grub_script_argv_next (&result))
 
227
              goto fail;
 
228
 
 
229
            if (grub_script_argv_split_append (&result, scope->argv.args[i]))
 
230
              goto fail;
 
231
          }
 
232
        else
 
233
          {
 
234
            if (i != 0 && grub_script_argv_append (&result, " "))
 
235
              goto fail;
 
236
 
 
237
            if (grub_script_argv_append (&result, scope->argv.args[i]))
 
238
              goto fail;
 
239
          }
 
240
    }
 
241
  else if (grub_strcmp (name, "@") == 0)
 
242
    {
 
243
      for (i = 0; i < scope->argv.argc; i++)
 
244
        {
 
245
          if (i != 0 && grub_script_argv_next (&result))
 
246
            goto fail;
 
247
 
 
248
          if (type == GRUB_SCRIPT_ARG_TYPE_VAR)
 
249
            {
 
250
              if (grub_script_argv_split_append (&result, scope->argv.args[i]))
 
251
                goto fail;
 
252
            }
 
253
          else
 
254
            if (grub_script_argv_append (&result, scope->argv.args[i]))
 
255
              goto fail;
 
256
        }
 
257
    }
 
258
  else
 
259
    {
 
260
      unsigned long num = grub_strtoul (name, 0, 10);
 
261
      if (num == 0)
 
262
        ; /* XXX no file name, for now.  */
 
263
 
 
264
      else if (num <= scope->argv.argc)
 
265
        {
 
266
          if (type == GRUB_SCRIPT_ARG_TYPE_VAR)
 
267
            {
 
268
              if (grub_script_argv_split_append (&result,
 
269
                                                 scope->argv.args[num - 1]))
 
270
                goto fail;
 
271
            }
 
272
          else
 
273
            if (grub_script_argv_append (&result, scope->argv.args[num - 1]))
 
274
              goto fail;
 
275
        }
 
276
    }
 
277
 
 
278
  return result.args;
 
279
 
 
280
 fail:
 
281
 
 
282
  grub_script_argv_free (&result);
 
283
  return 0;
 
284
}
 
285
 
 
286
static grub_err_t
 
287
grub_script_env_set (const char *name, const char *val)
 
288
{
 
289
  if (grub_env_special (name))
 
290
    return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad variable name");
 
291
 
 
292
  return grub_env_set (name, val);
 
293
}
 
294
 
 
295
/* Convert arguments in ARGLIST into ARGV form.  */
 
296
static int
 
297
grub_script_arglist_to_argv (struct grub_script_arglist *arglist,
 
298
                             struct grub_script_argv *argv)
 
299
{
 
300
  int i;
 
301
  char **values = 0;
 
302
  struct grub_script_arg *arg = 0;
 
303
  struct grub_script_argv result = { 0, 0, 0 };
 
304
 
 
305
  auto int append (char *s, int escape_type);
 
306
  int append (char *s, int escape_type)
 
307
  {
 
308
    int r;
 
309
    char *p = 0;
 
310
 
 
311
    if (! grub_wildcard_translator || escape_type == 0)
 
312
      return grub_script_argv_append (&result, s);
 
313
 
 
314
    if (escape_type > 0)
 
315
      p = grub_wildcard_translator->escape (s);
 
316
    else if (escape_type < 0)
 
317
      p = grub_wildcard_translator->unescape (s);
 
318
 
 
319
    if (! p)
 
320
      return 1;
 
321
 
 
322
    r = grub_script_argv_append (&result, p);
 
323
    grub_free (p);
 
324
    return r;
 
325
  }
 
326
 
 
327
  for (; arglist && arglist->arg; arglist = arglist->next)
 
328
    {
 
329
      if (grub_script_argv_next (&result))
 
330
        goto fail;
 
331
 
 
332
      arg = arglist->arg;
 
333
      while (arg)
 
334
        {
 
335
          switch (arg->type)
 
336
            {
 
337
            case GRUB_SCRIPT_ARG_TYPE_VAR:
 
338
            case GRUB_SCRIPT_ARG_TYPE_DQVAR:
 
339
              values = grub_script_env_get (arg->str, arg->type);
 
340
              for (i = 0; values && values[i]; i++)
 
341
                {
 
342
                  if (i != 0 && grub_script_argv_next (&result))
 
343
                    goto fail;
 
344
 
 
345
                  if (arg->type == GRUB_SCRIPT_ARG_TYPE_VAR)
 
346
                    {
 
347
                      if (grub_script_argv_append (&result, values[i]))
 
348
                        goto fail;
 
349
                    }
 
350
                  else
 
351
                    {
 
352
                      if (append (values[i], 1))
 
353
                        goto fail;
 
354
                    }
 
355
 
 
356
                  grub_free (values[i]);
 
357
                }
 
358
              grub_free (values);
 
359
              break;
 
360
 
 
361
            case GRUB_SCRIPT_ARG_TYPE_BLOCK:
 
362
              if (grub_script_argv_append (&result, "{") ||
 
363
                  grub_script_argv_append (&result, arg->str) ||
 
364
                  grub_script_argv_append (&result, "}"))
 
365
                goto fail;
 
366
              result.script = arg->script;
 
367
              break;
 
368
 
 
369
            case GRUB_SCRIPT_ARG_TYPE_TEXT:
 
370
              if (grub_strlen (arg->str) &&
 
371
                  grub_script_argv_append (&result, arg->str))
 
372
                goto fail;
 
373
              break;
 
374
 
 
375
            case GRUB_SCRIPT_ARG_TYPE_DQSTR:
 
376
            case GRUB_SCRIPT_ARG_TYPE_SQSTR:
 
377
              if (append (arg->str, 1))
 
378
                goto fail;
 
379
              break;
 
380
            }
 
381
          arg = arg->next;
 
382
        }
 
383
    }
 
384
 
 
385
  if (! result.args[result.argc - 1])
 
386
    result.argc--;
 
387
 
 
388
  /* Perform wildcard expansion.  */
 
389
 
 
390
  if (grub_wildcard_translator)
 
391
    {
 
392
      int j;
 
393
      int failed = 0;
 
394
      char **expansions = 0;
 
395
      struct grub_script_argv unexpanded = result;
 
396
 
 
397
      result.argc = 0;
 
398
      result.args = 0;
 
399
      for (i = 0; unexpanded.args[i]; i++)
 
400
        {
 
401
          if (grub_wildcard_translator->expand (unexpanded.args[i],
 
402
                                                &expansions))
 
403
            {
 
404
              grub_script_argv_free (&unexpanded);
 
405
              goto fail;
 
406
            }
 
407
 
 
408
          if (! expansions)
 
409
            {
 
410
              grub_script_argv_next (&result);
 
411
              append (unexpanded.args[i], -1);
 
412
            }
 
413
          else
 
414
            {
 
415
              for (j = 0; expansions[j]; j++)
 
416
                {
 
417
                  failed = (failed || grub_script_argv_next (&result) ||
 
418
                            append (expansions[j], -1));
 
419
                  grub_free (expansions[j]);
 
420
                }
 
421
              grub_free (expansions);
 
422
 
 
423
              if (failed)
 
424
                {
 
425
                  grub_script_argv_free (&unexpanded);
 
426
                  goto fail;
 
427
                }
 
428
            }
 
429
        }
 
430
      grub_script_argv_free (&unexpanded);
 
431
    }
 
432
 
 
433
  *argv = result;
 
434
  return 0;
 
435
 
 
436
 fail:
 
437
 
 
438
  grub_script_argv_free (&result);
 
439
  return 1;
 
440
}
 
441
 
 
442
static grub_err_t
 
443
grub_script_execute_cmd (struct grub_script_cmd *cmd)
 
444
{
 
445
  int ret;
 
446
  char errnobuf[ERRNO_DIGITS_MAX + 1];
 
447
 
 
448
  if (cmd == 0)
 
449
    return 0;
 
450
 
 
451
  ret = cmd->exec (cmd);
 
452
 
 
453
  grub_snprintf (errnobuf, sizeof (errnobuf), "%d", ret);
 
454
  grub_env_set ("?", errnobuf);
 
455
  return ret;
 
456
}
 
457
 
 
458
/* Execute a function call.  */
 
459
grub_err_t
 
460
grub_script_function_call (grub_script_function_t func, int argc, char **args)
 
461
{
 
462
  grub_err_t ret = 0;
 
463
  unsigned long loops = active_loops;
 
464
  struct grub_script_scope *old_scope;
 
465
  struct grub_script_scope new_scope;
 
466
 
 
467
  active_loops = 0;
 
468
  new_scope.flags = 0;
 
469
  new_scope.shifts = 0;
 
470
  new_scope.argv.argc = argc;
 
471
  new_scope.argv.args = args;
 
472
 
 
473
  old_scope = scope;
 
474
  scope = &new_scope;
 
475
 
 
476
  ret = grub_script_execute (func->func);
 
477
 
 
478
  function_return = 0;
 
479
  active_loops = loops;
 
480
  replace_scope (old_scope); /* free any scopes by setparams */
 
481
  return ret;
 
482
}
 
483
 
 
484
/* Execute a source script.  */
 
485
grub_err_t
 
486
grub_script_execute_sourcecode (const char *source, int argc, char **args)
 
487
{
 
488
  grub_err_t ret = 0;
 
489
  struct grub_script *parsed_script;
 
490
  struct grub_script_scope new_scope;
 
491
  struct grub_script_scope *old_scope;
 
492
 
 
493
  auto grub_err_t getline (char **line, int cont);
 
494
  grub_err_t getline (char **line, int cont __attribute__ ((unused)))
 
495
  {
 
496
    const char *p;
 
497
 
 
498
    if (! source)
 
499
      {
 
500
        *line = 0;
 
501
        return 0;
 
502
      }
 
503
 
 
504
    p = grub_strchr (source, '\n');
 
505
 
 
506
    if (p)
 
507
      *line = grub_strndup (source, p - source);
 
508
    else
 
509
      *line = grub_strdup (source);
 
510
    source = p ? p + 1 : 0;
 
511
    return 0;
 
512
  }
 
513
 
 
514
  new_scope.argv.argc = argc;
 
515
  new_scope.argv.args = args;
 
516
  new_scope.flags = 0;
 
517
 
 
518
  old_scope = scope;
 
519
  scope = &new_scope;
 
520
 
 
521
  while (source)
 
522
    {
 
523
      char *line;
 
524
 
 
525
      getline (&line, 0);
 
526
      parsed_script = grub_script_parse (line, getline);
 
527
      if (! parsed_script)
 
528
        {
 
529
          ret = grub_errno;
 
530
          break;
 
531
        }
 
532
 
 
533
      ret = grub_script_execute (parsed_script);
 
534
      grub_free (line);
 
535
    }
 
536
 
 
537
  scope = old_scope;
 
538
  return ret;
 
539
}
 
540
 
 
541
/* Execute a single command line.  */
 
542
grub_err_t
 
543
grub_script_execute_cmdline (struct grub_script_cmd *cmd)
 
544
{
 
545
  struct grub_script_cmdline *cmdline = (struct grub_script_cmdline *) cmd;
 
546
  grub_command_t grubcmd;
 
547
  grub_err_t ret = 0;
 
548
  grub_script_function_t func = 0;
 
549
  char errnobuf[18];
 
550
  char *cmdname;
 
551
  int argc;
 
552
  char **args;
 
553
  int invert;
 
554
  struct grub_script_argv argv = { 0, 0, 0 };
 
555
 
 
556
  /* Lookup the command.  */
 
557
  if (grub_script_arglist_to_argv (cmdline->arglist, &argv) || ! argv.args[0])
 
558
    return grub_errno;
 
559
 
 
560
  invert = 0;
 
561
  argc = argv.argc - 1;
 
562
  args = argv.args + 1;
 
563
  cmdname = argv.args[0];
 
564
  if (grub_strcmp (cmdname, "!") == 0)
 
565
    {
 
566
      if (argv.argc < 2 || ! argv.args[1])
 
567
        {
 
568
          grub_script_argv_free (&argv);
 
569
          return grub_error (GRUB_ERR_BAD_ARGUMENT, "missing arguments");
 
570
        }
 
571
 
 
572
      invert = 1;
 
573
      argc = argv.argc - 2;
 
574
      args = argv.args + 2;
 
575
      cmdname = argv.args[1];
 
576
    }
 
577
  grubcmd = grub_command_find (cmdname);
 
578
  if (! grubcmd)
 
579
    {
 
580
      grub_errno = GRUB_ERR_NONE;
 
581
 
 
582
      /* It's not a GRUB command, try all functions.  */
 
583
      func = grub_script_function_find (cmdname);
 
584
      if (! func)
 
585
        {
 
586
          /* As a last resort, try if it is an assignment.  */
 
587
          char *assign = grub_strdup (cmdname);
 
588
          char *eq = grub_strchr (assign, '=');
 
589
 
 
590
          if (eq)
 
591
            {
 
592
              /* This was set because the command was not found.  */
 
593
              grub_errno = GRUB_ERR_NONE;
 
594
 
 
595
              /* Create two strings and set the variable.  */
 
596
              *eq = '\0';
 
597
              eq++;
 
598
              grub_script_env_set (assign, eq);
 
599
            }
 
600
          grub_free (assign);
 
601
 
 
602
          grub_snprintf (errnobuf, sizeof (errnobuf), "%d", grub_errno);
 
603
          grub_script_env_set ("?", errnobuf);
 
604
 
 
605
          grub_script_argv_free (&argv);
 
606
          grub_print_error ();
 
607
 
 
608
          return 0;
 
609
        }
 
610
    }
 
611
 
 
612
  /* Execute the GRUB command or function.  */
 
613
  if (grubcmd)
 
614
    {
 
615
      if (grub_extractor_level && !(grubcmd->flags
 
616
                                    & GRUB_COMMAND_FLAG_EXTRACTOR))
 
617
        ret = grub_error (GRUB_ERR_EXTRACTOR,
 
618
                          "%s isn't allowed to execute in an extractor",
 
619
                          cmdname);
 
620
      else if ((grubcmd->flags & GRUB_COMMAND_FLAG_BLOCKS) &&
 
621
               (grubcmd->flags & GRUB_COMMAND_FLAG_EXTCMD))
 
622
        ret = grub_extcmd_dispatcher (grubcmd, argc, args, argv.script);
 
623
      else
 
624
        ret = (grubcmd->func) (grubcmd, argc, args);
 
625
    }
 
626
  else
 
627
    ret = grub_script_function_call (func, argc, args);
 
628
 
 
629
  if (invert)
 
630
    {
 
631
      if (ret == GRUB_ERR_TEST_FAILURE)
 
632
        grub_errno = ret = GRUB_ERR_NONE;
 
633
      else if (ret == GRUB_ERR_NONE)
 
634
        ret = grub_error (GRUB_ERR_TEST_FAILURE, "false");
 
635
      else
 
636
        {
 
637
          grub_print_error ();
 
638
          ret = GRUB_ERR_NONE;
 
639
        }
 
640
    }
 
641
 
 
642
  /* Free arguments.  */
 
643
  grub_script_argv_free (&argv);
 
644
 
 
645
  if (grub_errno == GRUB_ERR_TEST_FAILURE)
 
646
    grub_errno = GRUB_ERR_NONE;
 
647
 
 
648
  grub_print_error ();
 
649
 
 
650
  grub_snprintf (errnobuf, sizeof (errnobuf), "%d", ret);
 
651
  grub_env_set ("?", errnobuf);
 
652
 
 
653
  return ret;
 
654
}
 
655
 
 
656
/* Execute a block of one or more commands.  */
 
657
grub_err_t
 
658
grub_script_execute_cmdlist (struct grub_script_cmd *list)
 
659
{
 
660
  int ret = 0;
 
661
  struct grub_script_cmd *cmd;
 
662
 
 
663
  /* Loop over every command and execute it.  */
 
664
  for (cmd = list->next; cmd; cmd = cmd->next)
 
665
    {
 
666
      if (active_breaks)
 
667
        break;
 
668
 
 
669
      ret = grub_script_execute_cmd (cmd);
 
670
 
 
671
      if (function_return)
 
672
        break;
 
673
    }
 
674
 
 
675
  return ret;
 
676
}
 
677
 
 
678
/* Execute an if statement.  */
 
679
grub_err_t
 
680
grub_script_execute_cmdif (struct grub_script_cmd *cmd)
 
681
{
 
682
  int ret;
 
683
  char *result;
 
684
  struct grub_script_cmdif *cmdif = (struct grub_script_cmdif *) cmd;
 
685
 
 
686
  /* Check if the commands results in a true or a false.  The value is
 
687
     read from the env variable `?'.  */
 
688
  ret = grub_script_execute_cmd (cmdif->exec_to_evaluate);
 
689
  if (function_return)
 
690
    return ret;
 
691
 
 
692
  result = grub_env_get ("?");
 
693
  grub_errno = GRUB_ERR_NONE;
 
694
 
 
695
  /* Execute the `if' or the `else' part depending on the value of
 
696
     `?'.  */
 
697
  if (result && ! grub_strcmp (result, "0"))
 
698
    return grub_script_execute_cmd (cmdif->exec_on_true);
 
699
  else
 
700
    return grub_script_execute_cmd (cmdif->exec_on_false);
 
701
}
 
702
 
 
703
/* Execute a for statement.  */
 
704
grub_err_t
 
705
grub_script_execute_cmdfor (struct grub_script_cmd *cmd)
 
706
{
 
707
  unsigned i;
 
708
  grub_err_t result;
 
709
  struct grub_script_argv argv = { 0, 0, 0 };
 
710
  struct grub_script_cmdfor *cmdfor = (struct grub_script_cmdfor *) cmd;
 
711
 
 
712
  if (grub_script_arglist_to_argv (cmdfor->words, &argv))
 
713
    return grub_errno;
 
714
 
 
715
  active_loops++;
 
716
  result = 0;
 
717
  for (i = 0; i < argv.argc; i++)
 
718
    {
 
719
      if (is_continue && active_breaks == 1)
 
720
        active_breaks = 0;
 
721
 
 
722
      if (! active_breaks)
 
723
        {
 
724
          grub_script_env_set (cmdfor->name->str, argv.args[i]);
 
725
          result = grub_script_execute_cmd (cmdfor->list);
 
726
          if (function_return)
 
727
            break;
 
728
        }
 
729
    }
 
730
 
 
731
  if (active_breaks)
 
732
    active_breaks--;
 
733
 
 
734
  active_loops--;
 
735
  grub_script_argv_free (&argv);
 
736
  return result;
 
737
}
 
738
 
 
739
/* Execute a "while" or "until" command.  */
 
740
grub_err_t
 
741
grub_script_execute_cmdwhile (struct grub_script_cmd *cmd)
 
742
{
 
743
  int result;
 
744
  struct grub_script_cmdwhile *cmdwhile = (struct grub_script_cmdwhile *) cmd;
 
745
 
 
746
  active_loops++;
 
747
  do {
 
748
    result = grub_script_execute_cmd (cmdwhile->cond);
 
749
    if (function_return)
 
750
      break;
 
751
 
 
752
    if (cmdwhile->until ? !result : result)
 
753
      break;
 
754
 
 
755
    result = grub_script_execute_cmd (cmdwhile->list);
 
756
    if (function_return)
 
757
      break;
 
758
 
 
759
    if (active_breaks == 1 && is_continue)
 
760
      active_breaks = 0;
 
761
 
 
762
    if (active_breaks)
 
763
      break;
 
764
 
 
765
  } while (1); /* XXX Put a check for ^C here */
 
766
 
 
767
  if (active_breaks)
 
768
    active_breaks--;
 
769
 
 
770
  active_loops--;
 
771
  return result;
 
772
}
 
773
 
 
774
/* Execute any GRUB pre-parsed command or script.  */
 
775
grub_err_t
 
776
grub_script_execute (struct grub_script *script)
 
777
{
 
778
  if (script == 0)
 
779
    return 0;
 
780
 
 
781
  return grub_script_execute_cmd (script->cmd);
 
782
}
 
783