~hamo/ubuntu/precise/grub2/grub2.hi_res

« back to all changes in this revision

Viewing changes to grub-core/lib/arg.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
/* arg.c - argument parser */
 
2
/*
 
3
 *  GRUB  --  GRand Unified Bootloader
 
4
 *  Copyright (C) 2003,2004,2005,2007,2008  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/err.h>
 
23
#include <grub/term.h>
 
24
#include <grub/extcmd.h>
 
25
#include <grub/i18n.h>
 
26
 
 
27
/* Built-in parser for default options.  */
 
28
#define SHORT_ARG_HELP  -100
 
29
#define SHORT_ARG_USAGE -101
 
30
 
 
31
static const struct grub_arg_option help_options[] =
 
32
  {
 
33
    {"help", SHORT_ARG_HELP, 0,
 
34
     N_("Display this help and exit."), 0, ARG_TYPE_NONE},
 
35
    {"usage", SHORT_ARG_USAGE, 0,
 
36
     N_("Display the usage of this command and exit."), 0, ARG_TYPE_NONE},
 
37
    {0, 0, 0, 0, 0, 0}
 
38
  };
 
39
 
 
40
static struct grub_arg_option *
 
41
find_short (const struct grub_arg_option *options, char c)
 
42
{
 
43
  struct grub_arg_option *found = 0;
 
44
  auto struct grub_arg_option *fnd_short (const struct grub_arg_option *opt);
 
45
 
 
46
  struct grub_arg_option *fnd_short (const struct grub_arg_option *opt)
 
47
    {
 
48
      while (opt->doc)
 
49
        {
 
50
          if (opt->shortarg == c)
 
51
            return (struct grub_arg_option *) opt;
 
52
          opt++;
 
53
        }
 
54
      return 0;
 
55
    }
 
56
 
 
57
  if (options)
 
58
    found = fnd_short (options);
 
59
 
 
60
  if (! found)
 
61
    {
 
62
      switch (c)
 
63
        {
 
64
        case 'h':
 
65
          found = (struct grub_arg_option *) help_options;
 
66
          break;
 
67
 
 
68
        case 'u':
 
69
          found = (struct grub_arg_option *) (help_options + 1);
 
70
          break;
 
71
 
 
72
        default:
 
73
          break;
 
74
        }
 
75
    }
 
76
 
 
77
  return found;
 
78
}
 
79
 
 
80
static struct grub_arg_option *
 
81
find_long (const struct grub_arg_option *options, const char *s, int len)
 
82
{
 
83
  struct grub_arg_option *found = 0;
 
84
  auto struct grub_arg_option *fnd_long (const struct grub_arg_option *opt);
 
85
 
 
86
  struct grub_arg_option *fnd_long (const struct grub_arg_option *opt)
 
87
    {
 
88
      while (opt->doc)
 
89
        {
 
90
          if (opt->longarg && ! grub_strncmp (opt->longarg, s, len) &&
 
91
              opt->longarg[len] == '\0')
 
92
            return (struct grub_arg_option *) opt;
 
93
          opt++;
 
94
        }
 
95
      return 0;
 
96
    }
 
97
 
 
98
  if (options)
 
99
    found = fnd_long (options);
 
100
 
 
101
  if (! found)
 
102
    found = fnd_long (help_options);
 
103
 
 
104
  return found;
 
105
}
 
106
 
 
107
static void
 
108
show_usage (grub_extcmd_t cmd)
 
109
{
 
110
  grub_printf ("%s %s %s\n", _("Usage:"), cmd->cmd->name, _(cmd->cmd->summary));
 
111
}
 
112
 
 
113
void
 
114
grub_arg_show_help (grub_extcmd_t cmd)
 
115
{
 
116
  auto void showargs (const struct grub_arg_option *opt);
 
117
  int h_is_used = 0;
 
118
  int u_is_used = 0;
 
119
 
 
120
  auto void showargs (const struct grub_arg_option *opt)
 
121
    {
 
122
      for (; opt->doc; opt++)
 
123
        {
 
124
          int spacing = 20;
 
125
 
 
126
          if (opt->shortarg && grub_isgraph (opt->shortarg))
 
127
            grub_printf ("-%c%c ", opt->shortarg, opt->longarg ? ',':' ');
 
128
          else if (opt->shortarg == SHORT_ARG_HELP && ! h_is_used)
 
129
            grub_printf ("-h, ");
 
130
          else if (opt->shortarg == SHORT_ARG_USAGE && ! u_is_used)
 
131
            grub_printf ("-u, ");
 
132
          else
 
133
            grub_printf ("    ");
 
134
 
 
135
          if (opt->longarg)
 
136
            {
 
137
              grub_printf ("--%s", opt->longarg);
 
138
              spacing -= grub_strlen (opt->longarg) + 2;
 
139
 
 
140
              if (opt->arg)
 
141
                {
 
142
                  grub_printf ("=%s", opt->arg);
 
143
                  spacing -= grub_strlen (opt->arg) + 1;
 
144
                }
 
145
            }
 
146
 
 
147
          if (spacing < 0)
 
148
            spacing = 3;
 
149
 
 
150
          while (spacing--)
 
151
            grub_xputs (" ");
 
152
 
 
153
          grub_printf ("%s\n", _(opt->doc));
 
154
 
 
155
          switch (opt->shortarg)
 
156
            {
 
157
            case 'h':
 
158
              h_is_used = 1;
 
159
              break;
 
160
 
 
161
            case 'u':
 
162
              u_is_used = 1;
 
163
              break;
 
164
 
 
165
            default:
 
166
              break;
 
167
            }
 
168
        }
 
169
    }
 
170
 
 
171
  show_usage (cmd);
 
172
  grub_printf ("%s\n\n", _(cmd->cmd->description));
 
173
  if (cmd->options)
 
174
    showargs (cmd->options);
 
175
  showargs (help_options);
 
176
#if 0
 
177
  grub_printf ("\nReport bugs to <%s>.\n", PACKAGE_BUGREPORT);
 
178
#endif
 
179
}
 
180
 
 
181
 
 
182
static int
 
183
parse_option (grub_extcmd_t cmd, int key, char *arg, struct grub_arg_list *usr)
 
184
{
 
185
  switch (key)
 
186
    {
 
187
    case SHORT_ARG_HELP:
 
188
      grub_arg_show_help (cmd);
 
189
      return -1;
 
190
 
 
191
    case SHORT_ARG_USAGE:
 
192
      show_usage (cmd);
 
193
      return -1;
 
194
 
 
195
    default:
 
196
      {
 
197
        int found = -1;
 
198
        int i = 0;
 
199
        const struct grub_arg_option *opt = cmd->options;
 
200
 
 
201
        while (opt->doc)
 
202
          {
 
203
            if (opt->shortarg && key == opt->shortarg)
 
204
              {
 
205
                found = i;
 
206
                break;
 
207
              }
 
208
            opt++;
 
209
            i++;
 
210
          }
 
211
 
 
212
        if (found == -1)
 
213
          return -1;
 
214
 
 
215
        if (opt->flags & GRUB_ARG_OPTION_REPEATABLE)
 
216
          {
 
217
            usr[found].args[usr[found].set++] = arg;
 
218
            usr[found].args[usr[found].set] = NULL;
 
219
          }
 
220
        else
 
221
          {
 
222
            usr[found].set = 1;
 
223
            usr[found].arg = arg;
 
224
          }
 
225
      }
 
226
    }
 
227
 
 
228
  return 0;
 
229
}
 
230
 
 
231
int
 
232
grub_arg_parse (grub_extcmd_t cmd, int argc, char **argv,
 
233
                struct grub_arg_list *usr, char ***args, int *argnum)
 
234
{
 
235
  int curarg;
 
236
  int arglen;
 
237
  char **argl = 0;
 
238
  int num = 0;
 
239
  auto grub_err_t add_arg (char *s);
 
240
 
 
241
  grub_err_t add_arg (char *s)
 
242
    {
 
243
      char **p = argl;
 
244
      argl = grub_realloc (argl, (++num + 1) * sizeof (char *));
 
245
      if (! argl)
 
246
        {
 
247
          grub_free (p);
 
248
          return grub_errno;
 
249
        }
 
250
      argl[num - 1] = s;
 
251
      argl[num] = NULL;
 
252
      return 0;
 
253
    }
 
254
 
 
255
 
 
256
  for (curarg = 0; curarg < argc; curarg++)
 
257
    {
 
258
      char *arg = argv[curarg];
 
259
      struct grub_arg_option *opt;
 
260
      char *option = 0;
 
261
 
 
262
      /* No option is used.  */
 
263
      if ((num && (cmd->cmd->flags & GRUB_COMMAND_OPTIONS_AT_START))
 
264
          || arg[0] != '-' || grub_strlen (arg) == 1)
 
265
        {
 
266
          if (add_arg (arg) != 0)
 
267
            goto fail;
 
268
 
 
269
          continue;
 
270
        }
 
271
 
 
272
      /* One or more short options.  */
 
273
      if (arg[1] != '-')
 
274
        {
 
275
          char *curshort;
 
276
 
 
277
          if (cmd->cmd->flags & GRUB_COMMAND_ACCEPT_DASH)
 
278
            {
 
279
              for (curshort = arg + 1; *curshort; curshort++)
 
280
                if (!find_short (cmd->options, *curshort))
 
281
                  break;
 
282
            
 
283
              if (*curshort)
 
284
                {
 
285
                  if (add_arg (arg) != 0)
 
286
                    goto fail;
 
287
                  continue;
 
288
                }
 
289
            }
 
290
 
 
291
          curshort = arg + 1;
 
292
 
 
293
          while (1)
 
294
            {
 
295
              opt = find_short (cmd->options, *curshort);
 
296
 
 
297
              if (! opt)
 
298
                {
 
299
                  grub_error (GRUB_ERR_BAD_ARGUMENT,
 
300
                              "unknown argument `-%c'", *curshort);
 
301
                  goto fail;
 
302
                }
 
303
 
 
304
              curshort++;
 
305
 
 
306
              /* Parse all arguments here except the last one because
 
307
                 it can have an argument value.  */
 
308
              if (*curshort)
 
309
                {
 
310
                  if (parse_option (cmd, opt->shortarg, 0, usr) || grub_errno)
 
311
                    goto fail;
 
312
                }
 
313
              else
 
314
                {
 
315
                  if (opt->type != ARG_TYPE_NONE)
 
316
                    {
 
317
                      if (curarg + 1 < argc)
 
318
                        {
 
319
                          char *nextarg = argv[curarg + 1];
 
320
                          if (!(opt->flags & GRUB_ARG_OPTION_OPTIONAL)
 
321
                              || (grub_strlen (nextarg) < 2 || nextarg[0] != '-'))
 
322
                            option = argv[++curarg];
 
323
                        }
 
324
                    }
 
325
                  break;
 
326
                }
 
327
            }
 
328
 
 
329
        }
 
330
      else /* The argument starts with "--".  */
 
331
        {
 
332
          /* If the argument "--" is used just pass the other
 
333
             arguments.  */
 
334
          if (grub_strlen (arg) == 2)
 
335
            {
 
336
              for (curarg++; curarg < argc; curarg++)
 
337
                if (add_arg (argv[curarg]) != 0)
 
338
                  goto fail;
 
339
              break;
 
340
            }
 
341
 
 
342
          option = grub_strchr (arg, '=');
 
343
          if (option)
 
344
            {
 
345
              arglen = option - arg - 2;
 
346
              option++;
 
347
            }
 
348
          else
 
349
            arglen = grub_strlen (arg) - 2;
 
350
 
 
351
          opt = find_long (cmd->options, arg + 2, arglen);
 
352
 
 
353
          if (!option && argv[curarg + 1] && argv[curarg + 1][0] != '-'
 
354
              && opt->type != ARG_TYPE_NONE)
 
355
            option = argv[++curarg];
 
356
 
 
357
          if (!opt && (cmd->cmd->flags & GRUB_COMMAND_ACCEPT_DASH))
 
358
            {
 
359
              if (add_arg (arg) != 0)
 
360
                goto fail;
 
361
              continue;
 
362
            }
 
363
 
 
364
          if (! opt)
 
365
            {
 
366
              grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown argument `%s'", arg);
 
367
              goto fail;
 
368
            }
 
369
        }
 
370
 
 
371
      if (! (opt->type == ARG_TYPE_NONE
 
372
             || (! option && (opt->flags & GRUB_ARG_OPTION_OPTIONAL))))
 
373
        {
 
374
          if (! option)
 
375
            {
 
376
              grub_error (GRUB_ERR_BAD_ARGUMENT,
 
377
                          "missing mandatory option for `%s'", opt->longarg);
 
378
              goto fail;
 
379
            }
 
380
 
 
381
          switch (opt->type)
 
382
            {
 
383
            case ARG_TYPE_NONE:
 
384
              /* This will never happen.  */
 
385
              break;
 
386
 
 
387
            case ARG_TYPE_STRING:
 
388
                  /* No need to do anything.  */
 
389
              break;
 
390
 
 
391
            case ARG_TYPE_INT:
 
392
              {
 
393
                char *tail;
 
394
 
 
395
                grub_strtoull (option, &tail, 0);
 
396
                if (tail == 0 || tail == option || *tail != '\0' || grub_errno)
 
397
                  {
 
398
                    grub_error (GRUB_ERR_BAD_ARGUMENT,
 
399
                                "the argument `%s' requires an integer",
 
400
                                arg);
 
401
 
 
402
                    goto fail;
 
403
                  }
 
404
                break;
 
405
              }
 
406
 
 
407
            case ARG_TYPE_DEVICE:
 
408
            case ARG_TYPE_DIR:
 
409
            case ARG_TYPE_FILE:
 
410
            case ARG_TYPE_PATHNAME:
 
411
              /* XXX: Not implemented.  */
 
412
              break;
 
413
            }
 
414
          if (parse_option (cmd, opt->shortarg, option, usr) || grub_errno)
 
415
            goto fail;
 
416
        }
 
417
      else
 
418
        {
 
419
          if (option)
 
420
            {
 
421
              grub_error (GRUB_ERR_BAD_ARGUMENT,
 
422
                          "a value was assigned to the argument `%s' while it "
 
423
                          "doesn't require an argument", arg);
 
424
              goto fail;
 
425
            }
 
426
 
 
427
          if (parse_option (cmd, opt->shortarg, 0, usr) || grub_errno)
 
428
            goto fail;
 
429
        }
 
430
    }
 
431
 
 
432
  *args = argl;
 
433
  *argnum = num;
 
434
  return 1;
 
435
 
 
436
 fail:
 
437
  return 0;
 
438
}
 
439
 
 
440
struct grub_arg_list*
 
441
grub_arg_list_alloc(grub_extcmd_t extcmd, int argc,
 
442
                    char **argv __attribute__((unused)))
 
443
{
 
444
  int i;
 
445
  char **args;
 
446
  unsigned argcnt;
 
447
  struct grub_arg_list *list;
 
448
  const struct grub_arg_option *options;
 
449
 
 
450
  options = extcmd->options;
 
451
  if (! options)
 
452
    return 0;
 
453
 
 
454
  argcnt = 0;
 
455
  for (i = 0; options[i].doc; i++)
 
456
    {
 
457
      if (options[i].flags & GRUB_ARG_OPTION_REPEATABLE)
 
458
        argcnt += (argc + 1) / 2 + 1; /* max possible for any option */
 
459
    }
 
460
 
 
461
  list = grub_zalloc (sizeof (*list) * i + sizeof (char*) * argcnt);
 
462
  if (! list)
 
463
    return 0;
 
464
 
 
465
  args = (char**) (list + i);
 
466
  for (i = 0; options[i].doc; i++)
 
467
    {
 
468
      list[i].set = 0;
 
469
      list[i].arg = 0;
 
470
 
 
471
      if (options[i].flags & GRUB_ARG_OPTION_REPEATABLE)
 
472
        {
 
473
          list[i].args = args;
 
474
          args += argc / 2 + 1;
 
475
        }
 
476
    }
 
477
  return list;
 
478
}