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

« back to all changes in this revision

Viewing changes to grub-core/commands/menuentry.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
/* menuentry.c - menuentry command */
 
2
/*
 
3
 *  GRUB  --  GRand Unified Bootloader
 
4
 *  Copyright (C) 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/types.h>
 
21
#include <grub/misc.h>
 
22
#include <grub/err.h>
 
23
#include <grub/dl.h>
 
24
#include <grub/extcmd.h>
 
25
#include <grub/i18n.h>
 
26
#include <grub/normal.h>
 
27
 
 
28
static const struct grub_arg_option options[] =
 
29
  {
 
30
    {"class", 1, GRUB_ARG_OPTION_REPEATABLE,
 
31
     N_("Menu entry type."), "STRING", ARG_TYPE_STRING},
 
32
    {"users", 2, 0,
 
33
     N_("Users allowed to boot this entry."), "USERNAME", ARG_TYPE_STRING},
 
34
    {"hotkey", 3, 0,
 
35
     N_("Keyboard key for this entry."), "KEY", ARG_TYPE_STRING},
 
36
    {"source", 4, 0,
 
37
     N_("Menu entry definition as a string."), "STRING", ARG_TYPE_STRING},
 
38
    {0, 0, 0, 0, 0, 0}
 
39
  };
 
40
 
 
41
static struct
 
42
{
 
43
  char *name;
 
44
  int key;
 
45
} hotkey_aliases[] =
 
46
  {
 
47
    {"backspace", '\b'},
 
48
    {"tab", '\t'},
 
49
    {"delete", GRUB_TERM_KEY_DC},
 
50
    {"insert", GRUB_TERM_KEY_INSERT},
 
51
    {"f1", GRUB_TERM_KEY_F1},
 
52
    {"f2", GRUB_TERM_KEY_F2},
 
53
    {"f3", GRUB_TERM_KEY_F3},
 
54
    {"f4", GRUB_TERM_KEY_F4},
 
55
    {"f5", GRUB_TERM_KEY_F5},
 
56
    {"f6", GRUB_TERM_KEY_F6},
 
57
    {"f7", GRUB_TERM_KEY_F7},
 
58
    {"f8", GRUB_TERM_KEY_F8},
 
59
    {"f9", GRUB_TERM_KEY_F9},
 
60
    {"f10", GRUB_TERM_KEY_F10},
 
61
    {"f11", GRUB_TERM_KEY_F11},
 
62
    {"f12", GRUB_TERM_KEY_F12},
 
63
  };
 
64
 
 
65
/* Add a menu entry to the current menu context (as given by the environment
 
66
   variable data slot `menu').  As the configuration file is read, the script
 
67
   parser calls this when a menu entry is to be created.  */
 
68
grub_err_t
 
69
grub_normal_add_menu_entry (int argc, const char **args, char **classes,
 
70
                            const char *users, const char *hotkey,
 
71
                            const char *prefix, const char *sourcecode,
 
72
                            int submenu)
 
73
{
 
74
  int menu_hotkey = 0;
 
75
  char **menu_args = NULL;
 
76
  char *menu_users = NULL;
 
77
  char *menu_title = NULL;
 
78
  char *menu_sourcecode = NULL;
 
79
  struct grub_menu_entry_class *menu_classes = NULL;
 
80
 
 
81
  grub_menu_t menu;
 
82
  grub_menu_entry_t *last;
 
83
 
 
84
  menu = grub_env_get_menu ();
 
85
  if (! menu)
 
86
    return grub_error (GRUB_ERR_MENU, "no menu context");
 
87
 
 
88
  last = &menu->entry_list;
 
89
 
 
90
  menu_sourcecode = grub_xasprintf ("%s%s", prefix ?: "", sourcecode);
 
91
  if (! menu_sourcecode)
 
92
    return grub_errno;
 
93
 
 
94
  if (classes)
 
95
    {
 
96
      int i;
 
97
      for (i = 0; classes[i]; i++); /* count # of menuentry classes */
 
98
      menu_classes = grub_zalloc (sizeof (struct grub_menu_entry_class) * i);
 
99
      if (! menu_classes)
 
100
        goto fail;
 
101
 
 
102
      for (i = 0; classes[i]; i++)
 
103
        {
 
104
          menu_classes[i].name = grub_strdup (classes[i]);
 
105
          if (! menu_classes[i].name)
 
106
            goto fail;
 
107
          menu_classes[i].next = classes[i + 1] ? &menu_classes[i + 1] : NULL;
 
108
        }
 
109
    }
 
110
 
 
111
  if (users)
 
112
    {
 
113
      menu_users = grub_strdup (users);
 
114
      if (! menu_users)
 
115
        goto fail;
 
116
    }
 
117
 
 
118
  if (hotkey)
 
119
    {
 
120
      unsigned i;
 
121
      for (i = 0; i < ARRAY_SIZE (hotkey_aliases); i++)
 
122
        if (grub_strcmp (hotkey, hotkey_aliases[i].name) == 0)
 
123
          {
 
124
            menu_hotkey = hotkey_aliases[i].key;
 
125
            break;
 
126
          }
 
127
      if (i == ARRAY_SIZE (hotkey_aliases))
 
128
        menu_hotkey = hotkey[0];
 
129
    }
 
130
 
 
131
  if (! argc)
 
132
    {
 
133
      grub_error (GRUB_ERR_MENU, "menuentry is missing title");
 
134
      goto fail;
 
135
    }
 
136
 
 
137
  menu_title = grub_strdup (args[0]);
 
138
  if (! menu_title)
 
139
    goto fail;
 
140
 
 
141
  /* Save argc, args to pass as parameters to block arg later. */
 
142
  menu_args = grub_malloc (sizeof (char*) * (argc + 1));
 
143
  if (! menu_args)
 
144
    goto fail;
 
145
 
 
146
  {
 
147
    int i;
 
148
    for (i = 0; i < argc; i++)
 
149
      {
 
150
        menu_args[i] = grub_strdup (args[i]);
 
151
        if (! menu_args[i])
 
152
          goto fail;
 
153
      }
 
154
    menu_args[argc] = NULL;
 
155
  }
 
156
 
 
157
  /* Add the menu entry at the end of the list.  */
 
158
  while (*last)
 
159
    last = &(*last)->next;
 
160
 
 
161
  *last = grub_zalloc (sizeof (**last));
 
162
  if (! *last)
 
163
    goto fail;
 
164
 
 
165
  (*last)->title = menu_title;
 
166
  (*last)->hotkey = menu_hotkey;
 
167
  (*last)->classes = menu_classes;
 
168
  if (menu_users)
 
169
    (*last)->restricted = 1;
 
170
  (*last)->users = menu_users;
 
171
  (*last)->argc = argc;
 
172
  (*last)->args = menu_args;
 
173
  (*last)->sourcecode = menu_sourcecode;
 
174
  (*last)->submenu = submenu;
 
175
 
 
176
  menu->size++;
 
177
  return GRUB_ERR_NONE;
 
178
 
 
179
 fail:
 
180
 
 
181
  grub_free (menu_sourcecode);
 
182
  {
 
183
    int i;
 
184
    for (i = 0; menu_classes && menu_classes[i].name; i++)
 
185
      grub_free (menu_classes[i].name);
 
186
    grub_free (menu_classes);
 
187
  }
 
188
 
 
189
  {
 
190
    int i;
 
191
    for (i = 0; menu_args && menu_args[i]; i++)
 
192
      grub_free (menu_args[i]);
 
193
    grub_free (menu_args);
 
194
  }
 
195
 
 
196
  grub_free (menu_users);
 
197
  grub_free (menu_title);
 
198
  return grub_errno;
 
199
}
 
200
 
 
201
static char *
 
202
setparams_prefix (int argc, char **args)
 
203
{
 
204
  int i;
 
205
  int j;
 
206
  char *p;
 
207
  char *result;
 
208
  grub_size_t len = 10;
 
209
  static const char *escape_characters = "\"\\";
 
210
 
 
211
  auto char *strescpy (char *, const char *, const char *);
 
212
  char * strescpy (char *d, const char *s, const char *escapes)
 
213
  {
 
214
    while (*s)
 
215
      {
 
216
        if (grub_strchr (escapes, *s))
 
217
          *d++ = '\\';
 
218
        *d++ = *s++;
 
219
      }
 
220
    *d = '\0';
 
221
    return d;
 
222
  }
 
223
 
 
224
  /* Count resulting string length */
 
225
  for (i = 0; i < argc; i++)
 
226
    {
 
227
      len += 3; /* 3 = 1 space + 2 quotes */
 
228
      p = args[i];
 
229
      while (*p)
 
230
        len += grub_strchr (escape_characters, *p++) ? 2 : 1;
 
231
    }
 
232
 
 
233
  result = grub_malloc (len + 2);
 
234
  if (! result)
 
235
    return 0;
 
236
 
 
237
  grub_strcpy (result, "setparams");
 
238
  i = 9;
 
239
 
 
240
  for (j = 0; j < argc; j++)
 
241
    {
 
242
      result[i++] = ' ';
 
243
      result[i++] = '"';
 
244
      i = strescpy (result + i, args[j], escape_characters) - result;
 
245
      result[i++] = '"';
 
246
    }
 
247
  result[i++] = '\n';
 
248
  result[i] = '\0';
 
249
  return result;
 
250
}
 
251
 
 
252
static grub_err_t
 
253
grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args)
 
254
{
 
255
  char ch;
 
256
  char *src;
 
257
  char *prefix;
 
258
  unsigned len;
 
259
  grub_err_t r;
 
260
 
 
261
  if (! argc)
 
262
    return grub_error (GRUB_ERR_BAD_ARGUMENT, "missing arguments");
 
263
 
 
264
  if (ctxt->state[3].set && ctxt->script)
 
265
    return grub_error (GRUB_ERR_BAD_ARGUMENT, "multiple menuentry definitions");
 
266
 
 
267
  if (! ctxt->state[3].set && ! ctxt->script)
 
268
    return grub_error (GRUB_ERR_BAD_ARGUMENT, "no menuentry definition");
 
269
 
 
270
  if (! ctxt->script)
 
271
    return grub_normal_add_menu_entry (argc, (const char **) args,
 
272
                                       ctxt->state[0].args, ctxt->state[1].arg,
 
273
                                       ctxt->state[2].arg, 0,
 
274
                                       ctxt->state[3].arg,
 
275
                                       ctxt->extcmd->cmd->name[0] == 's');
 
276
 
 
277
  src = args[argc - 1];
 
278
  args[argc - 1] = NULL;
 
279
 
 
280
  len = grub_strlen(src);
 
281
  ch = src[len - 1];
 
282
  src[len - 1] = '\0';
 
283
 
 
284
  prefix = setparams_prefix (argc - 1, args);
 
285
  if (! prefix)
 
286
    return grub_errno;
 
287
 
 
288
  r = grub_normal_add_menu_entry (argc - 1, (const char **) args,
 
289
                                  ctxt->state[0].args, ctxt->state[1].arg,
 
290
                                  ctxt->state[2].arg, prefix, src + 1,
 
291
                                  ctxt->extcmd->cmd->name[0] == 's');
 
292
 
 
293
  src[len - 1] = ch;
 
294
  args[argc - 1] = src;
 
295
  grub_free (prefix);
 
296
  return r;
 
297
}
 
298
 
 
299
static grub_extcmd_t cmd, cmd_sub;
 
300
 
 
301
void
 
302
grub_menu_init (void)
 
303
{
 
304
  cmd = grub_register_extcmd ("menuentry", grub_cmd_menuentry,
 
305
                              GRUB_COMMAND_FLAG_BLOCKS
 
306
                              | GRUB_COMMAND_FLAG_EXTRACTOR,
 
307
                              N_("BLOCK"), N_("Define a menuentry."), options);
 
308
  cmd_sub = grub_register_extcmd ("submenu", grub_cmd_menuentry,
 
309
                                  GRUB_COMMAND_FLAG_BLOCKS
 
310
                                  | GRUB_COMMAND_FLAG_EXTRACTOR,
 
311
                                  N_("BLOCK"), N_("Define a submenu."),
 
312
                                  options);
 
313
}
 
314
 
 
315
void
 
316
grub_menu_fini (void)
 
317
{
 
318
  grub_unregister_extcmd (cmd);
 
319
  grub_unregister_extcmd (cmd_sub);
 
320
}