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

« 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, Robert Millan, Updated translations
  • Date: 2010-11-22 12:24:56 UTC
  • mfrom: (1.26.4 upstream) (17.3.36 sid)
  • mto: (17.3.43 sid)
  • mto: This revision was merged to the branch mainline in revision 89.
  • Revision ID: james.westby@ubuntu.com-20101122122456-y82z3sfb7k4zfdcc
Tags: 1.99~20101122-1
[ Colin Watson ]
* New Bazaar snapshot.  Too many changes to list in full, but some of the
  more user-visible ones are as follows:
  - GRUB script:
    + Function parameters, "break", "continue", "shift", "setparams",
      "return", and "!".
    + "export" command supports multiple variable names.
    + Multi-line quoted strings support.
    + Wildcard expansion.
  - sendkey support.
  - USB hotunplugging and USB serial support.
  - Rename CD-ROM to cd on BIOS.
  - Add new --boot-directory option to grub-install, grub-reboot, and
    grub-set-default; the old --root-directory option is still accepted
    but was often confusing.
  - Basic btrfs detection/UUID support (but no file reading yet).
  - bash-completion for utilities.
  - If a device is listed in device.map, always assume that it is
    BIOS-visible rather than using extra layers such as LVM or RAID.
  - Add grub-mknetdir script (closes: #550658).
  - Remove deprecated "root" command.
  - Handle RAID devices containing virtio components.
  - GRUB Legacy configuration file support (via grub-menulst2cfg).
  - Keyboard layout support (via grub-mklayout and grub-kbdcomp).
  - Check generated grub.cfg for syntax errors before saving.
  - Pause execution for at most ten seconds if any errors are displayed,
    so that the user has a chance to see them.
  - Support submenus.
  - Write embedding zone using Reed-Solomon, so that it's robust against
    being partially overwritten (closes: #550702, #591416, #593347).
  - GRUB_DISABLE_LINUX_RECOVERY and GRUB_DISABLE_NETBSD_RECOVERY merged
    into a single GRUB_DISABLE_RECOVERY variable.
  - Fix loader memory allocation failure (closes: #551627).
  - Don't call savedefault on recovery entries (closes: #589325).
  - Support triple-indirect blocks on ext2 (closes: #543924).
  - Recognise DDF1 fake RAID (closes: #603354).

[ Robert Millan ]
* Use dpkg architecture wildcards.

[ Updated translations ]
* Slovenian (Vanja Cvelbar).  Closes: #604003
* Dzongkha (dawa pemo via Tenzin Dendup).  Closes: #604102

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
}