]> git.proxmox.com Git - grub2.git/blame - grub-core/commands/menuentry.c
* grub-core/commands/menuentry.c: Fix typo in TRANSLATORS comments
[grub2.git] / grub-core / commands / menuentry.c
CommitLineData
627c30f7
BC
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
639cc5ab
BC
28static const struct grub_arg_option options[] =
29 {
30 {"class", 1, GRUB_ARG_OPTION_REPEATABLE,
10f0117b 31 N_("Menu entry type."), N_("STRING"), ARG_TYPE_STRING},
639cc5ab 32 {"users", 2, 0,
9c4b5c13
VS
33 N_("List of users allowed to boot this entry."), N_("USERNAME[,USERNAME]"),
34 ARG_TYPE_STRING},
639cc5ab 35 {"hotkey", 3, 0,
b525fd83 36 N_("Keyboard key to quickly boot this entry."), N_("KEYBOARD_KEY"), ARG_TYPE_STRING},
80f5b97c 37 {"source", 4, 0,
9c4b5c13 38 N_("Use STRING as menu entry body."), N_("STRING"), ARG_TYPE_STRING},
90eeab76 39 {"id", 0, 0, N_("Menu entry identifier."), N_("STRING"), ARG_TYPE_STRING},
11858300
VS
40 /* TRANSLATORS: menu entry can either be bootable by anyone or only by
41 handful of users. By default when security is active only superusers can
4e9b2819 42 boot a given menu entry. With --unrestricted (this option)
11858300 43 anyone can boot it. */
dc478aea
VS
44 {"unrestricted", 0, 0, N_("This entry can be booted by any user."),
45 0, ARG_TYPE_NONE},
639cc5ab
BC
46 {0, 0, 0, 0, 0, 0}
47 };
48
49static struct
50{
bf3a3857 51 const char *name;
639cc5ab
BC
52 int key;
53} hotkey_aliases[] =
54 {
55 {"backspace", '\b'},
56 {"tab", '\t'},
1a9130dd
CPE
57 {"delete", GRUB_TERM_KEY_DC},
58 {"insert", GRUB_TERM_KEY_INSERT},
59 {"f1", GRUB_TERM_KEY_F1},
60 {"f2", GRUB_TERM_KEY_F2},
61 {"f3", GRUB_TERM_KEY_F3},
62 {"f4", GRUB_TERM_KEY_F4},
63 {"f5", GRUB_TERM_KEY_F5},
64 {"f6", GRUB_TERM_KEY_F6},
65 {"f7", GRUB_TERM_KEY_F7},
66 {"f8", GRUB_TERM_KEY_F8},
67 {"f9", GRUB_TERM_KEY_F9},
68 {"f10", GRUB_TERM_KEY_F10},
69 {"f11", GRUB_TERM_KEY_F11},
70 {"f12", GRUB_TERM_KEY_F12},
639cc5ab
BC
71 };
72
73/* Add a menu entry to the current menu context (as given by the environment
74 variable data slot `menu'). As the configuration file is read, the script
75 parser calls this when a menu entry is to be created. */
bd960307 76grub_err_t
d9bef9bc
VS
77grub_normal_add_menu_entry (int argc, const char **args,
78 char **classes, const char *id,
bd960307 79 const char *users, const char *hotkey,
fc55cc4c
VS
80 const char *prefix, const char *sourcecode,
81 int submenu)
639cc5ab 82{
639cc5ab 83 int menu_hotkey = 0;
1767f709 84 char **menu_args = NULL;
639cc5ab
BC
85 char *menu_users = NULL;
86 char *menu_title = NULL;
87 char *menu_sourcecode = NULL;
d9bef9bc 88 char *menu_id = NULL;
639cc5ab
BC
89 struct grub_menu_entry_class *menu_classes = NULL;
90
91 grub_menu_t menu;
92 grub_menu_entry_t *last;
93
94 menu = grub_env_get_menu ();
95 if (! menu)
96 return grub_error (GRUB_ERR_MENU, "no menu context");
97
98 last = &menu->entry_list;
99
e89f9ec5 100 menu_sourcecode = grub_xasprintf ("%s%s", prefix ?: "", sourcecode);
639cc5ab
BC
101 if (! menu_sourcecode)
102 return grub_errno;
103
d4de6b01 104 if (classes && classes[0])
639cc5ab 105 {
fc55cc4c 106 int i;
639cc5ab 107 for (i = 0; classes[i]; i++); /* count # of menuentry classes */
d83ff9f9
VS
108 menu_classes = grub_zalloc (sizeof (struct grub_menu_entry_class)
109 * (i + 1));
639cc5ab
BC
110 if (! menu_classes)
111 goto fail;
112
113 for (i = 0; classes[i]; i++)
114 {
115 menu_classes[i].name = grub_strdup (classes[i]);
116 if (! menu_classes[i].name)
117 goto fail;
118 menu_classes[i].next = classes[i + 1] ? &menu_classes[i + 1] : NULL;
119 }
120 }
121
122 if (users)
123 {
124 menu_users = grub_strdup (users);
125 if (! menu_users)
126 goto fail;
127 }
128
129 if (hotkey)
130 {
fc55cc4c 131 unsigned i;
639cc5ab
BC
132 for (i = 0; i < ARRAY_SIZE (hotkey_aliases); i++)
133 if (grub_strcmp (hotkey, hotkey_aliases[i].name) == 0)
134 {
135 menu_hotkey = hotkey_aliases[i].key;
136 break;
137 }
78780e70
BC
138 if (i == ARRAY_SIZE (hotkey_aliases))
139 menu_hotkey = hotkey[0];
639cc5ab
BC
140 }
141
142 if (! argc)
143 {
144 grub_error (GRUB_ERR_MENU, "menuentry is missing title");
145 goto fail;
146 }
147
148 menu_title = grub_strdup (args[0]);
149 if (! menu_title)
150 goto fail;
151
d9bef9bc
VS
152 menu_id = grub_strdup (id ? : menu_title);
153 if (! menu_id)
154 goto fail;
155
1767f709
BC
156 /* Save argc, args to pass as parameters to block arg later. */
157 menu_args = grub_malloc (sizeof (char*) * (argc + 1));
158 if (! menu_args)
159 goto fail;
160
fc55cc4c
VS
161 {
162 int i;
163 for (i = 0; i < argc; i++)
164 {
165 menu_args[i] = grub_strdup (args[i]);
166 if (! menu_args[i])
167 goto fail;
168 }
169 menu_args[argc] = NULL;
170 }
639cc5ab
BC
171
172 /* Add the menu entry at the end of the list. */
173 while (*last)
174 last = &(*last)->next;
175
176 *last = grub_zalloc (sizeof (**last));
177 if (! *last)
178 goto fail;
179
180 (*last)->title = menu_title;
d9bef9bc 181 (*last)->id = menu_id;
639cc5ab
BC
182 (*last)->hotkey = menu_hotkey;
183 (*last)->classes = menu_classes;
184 if (menu_users)
185 (*last)->restricted = 1;
186 (*last)->users = menu_users;
1767f709
BC
187 (*last)->argc = argc;
188 (*last)->args = menu_args;
639cc5ab 189 (*last)->sourcecode = menu_sourcecode;
fc55cc4c 190 (*last)->submenu = submenu;
639cc5ab
BC
191
192 menu->size++;
193 return GRUB_ERR_NONE;
194
195 fail:
196
197 grub_free (menu_sourcecode);
fc55cc4c
VS
198 {
199 int i;
200 for (i = 0; menu_classes && menu_classes[i].name; i++)
201 grub_free (menu_classes[i].name);
202 grub_free (menu_classes);
203 }
1767f709 204
fc55cc4c
VS
205 {
206 int i;
207 for (i = 0; menu_args && menu_args[i]; i++)
208 grub_free (menu_args[i]);
209 grub_free (menu_args);
210 }
1767f709 211
639cc5ab
BC
212 grub_free (menu_users);
213 grub_free (menu_title);
d9bef9bc 214 grub_free (menu_id);
639cc5ab
BC
215 return grub_errno;
216}
217
e89f9ec5
BC
218static char *
219setparams_prefix (int argc, char **args)
220{
221 int i;
222 int j;
223 char *p;
224 char *result;
225 grub_size_t len = 10;
e89f9ec5
BC
226
227 /* Count resulting string length */
228 for (i = 0; i < argc; i++)
229 {
230 len += 3; /* 3 = 1 space + 2 quotes */
231 p = args[i];
232 while (*p)
9acdcbf3 233 len += (*p++ == '\'' ? 3 : 1);
e89f9ec5
BC
234 }
235
236 result = grub_malloc (len + 2);
237 if (! result)
238 return 0;
239
240 grub_strcpy (result, "setparams");
f866fe80 241 p = result + 9;
e89f9ec5
BC
242
243 for (j = 0; j < argc; j++)
244 {
f866fe80
BC
245 *p++ = ' ';
246 *p++ = '\'';
5b080620 247 p = grub_strchrsub (p, args[j], '\'', "'\\''");
f866fe80 248 *p++ = '\'';
e89f9ec5 249 }
f866fe80
BC
250 *p++ = '\n';
251 *p = '\0';
e89f9ec5
BC
252 return result;
253}
254
627c30f7
BC
255static grub_err_t
256grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args)
257{
639cc5ab 258 char ch;
627c30f7 259 char *src;
e89f9ec5 260 char *prefix;
b1490686 261 unsigned len;
627c30f7 262 grub_err_t r;
dc478aea 263 const char *users;
627c30f7 264
80f5b97c
BC
265 if (! argc)
266 return grub_error (GRUB_ERR_BAD_ARGUMENT, "missing arguments");
267
268 if (ctxt->state[3].set && ctxt->script)
269 return grub_error (GRUB_ERR_BAD_ARGUMENT, "multiple menuentry definitions");
270
271 if (! ctxt->state[3].set && ! ctxt->script)
272 return grub_error (GRUB_ERR_BAD_ARGUMENT, "no menuentry definition");
273
dc478aea
VS
274 if (ctxt->state[1].set)
275 users = ctxt->state[1].arg;
276 else if (ctxt->state[5].set)
277 users = NULL;
278 else
279 users = "";
280
80f5b97c 281 if (! ctxt->script)
bd960307 282 return grub_normal_add_menu_entry (argc, (const char **) args,
d4de6b01 283 (ctxt->state[0].set ? ctxt->state[0].args
d9bef9bc
VS
284 : NULL),
285 ctxt->state[4].arg,
dc478aea 286 users,
bd960307 287 ctxt->state[2].arg, 0,
fc55cc4c
VS
288 ctxt->state[3].arg,
289 ctxt->extcmd->cmd->name[0] == 's');
627c30f7
BC
290
291 src = args[argc - 1];
639cc5ab
BC
292 args[argc - 1] = NULL;
293
b1490686 294 len = grub_strlen(src);
639cc5ab 295 ch = src[len - 1];
b1490686 296 src[len - 1] = '\0';
627c30f7 297
e89f9ec5
BC
298 prefix = setparams_prefix (argc - 1, args);
299 if (! prefix)
300 return grub_errno;
301
bd960307 302 r = grub_normal_add_menu_entry (argc - 1, (const char **) args,
d9bef9bc 303 ctxt->state[0].args, ctxt->state[4].arg,
dc478aea 304 users,
fc55cc4c
VS
305 ctxt->state[2].arg, prefix, src + 1,
306 ctxt->extcmd->cmd->name[0] == 's');
627c30f7 307
639cc5ab 308 src[len - 1] = ch;
627c30f7 309 args[argc - 1] = src;
e89f9ec5 310 grub_free (prefix);
627c30f7
BC
311 return r;
312}
313
fc55cc4c 314static grub_extcmd_t cmd, cmd_sub;
627c30f7 315
9284756e
BC
316void
317grub_menu_init (void)
627c30f7
BC
318{
319 cmd = grub_register_extcmd ("menuentry", grub_cmd_menuentry,
7756d444 320 GRUB_COMMAND_FLAG_BLOCKS
d9bef9bc 321 | GRUB_COMMAND_ACCEPT_DASH
a38b701c 322 | GRUB_COMMAND_FLAG_EXTRACTOR,
67093bc0 323 N_("BLOCK"), N_("Define a menu entry."), options);
fc55cc4c
VS
324 cmd_sub = grub_register_extcmd ("submenu", grub_cmd_menuentry,
325 GRUB_COMMAND_FLAG_BLOCKS
d9bef9bc 326 | GRUB_COMMAND_ACCEPT_DASH
fc55cc4c
VS
327 | GRUB_COMMAND_FLAG_EXTRACTOR,
328 N_("BLOCK"), N_("Define a submenu."),
329 options);
627c30f7
BC
330}
331
9284756e
BC
332void
333grub_menu_fini (void)
627c30f7
BC
334{
335 grub_unregister_extcmd (cmd);
fc55cc4c 336 grub_unregister_extcmd (cmd_sub);
627c30f7 337}