1 /* menuentry.c - menuentry command */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2010 Free Software Foundation, Inc.
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.
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.
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/>.
20 #include <grub/types.h>
21 #include <grub/misc.h>
24 #include <grub/extcmd.h>
25 #include <grub/i18n.h>
26 #include <grub/normal.h>
28 static const struct grub_arg_option options
[] =
30 {"class", 1, GRUB_ARG_OPTION_REPEATABLE
,
31 N_("Menu entry type."), N_("STRING"), ARG_TYPE_STRING
},
33 N_("List of users allowed to boot this entry."), N_("USERNAME[,USERNAME]"),
36 N_("Keyboard key to quickly boot this entry."), N_("KEYBOARD_KEY"), ARG_TYPE_STRING
},
38 N_("Use STRING as menu entry body."), N_("STRING"), ARG_TYPE_STRING
},
39 {"id", 0, 0, N_("Menu entry identifier."), N_("STRING"), ARG_TYPE_STRING
},
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
42 boot a given menu entry. With --unrestricted (this option)
43 anyone can boot it. */
44 {"unrestricted", 0, 0, N_("This entry can be booted by any user."),
55 {"backspace", GRUB_TERM_BACKSPACE
},
56 {"tab", GRUB_TERM_TAB
},
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
},
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. */
77 grub_normal_add_menu_entry (int argc
, const char **args
,
78 char **classes
, const char *id
,
79 const char *users
, const char *hotkey
,
80 const char *prefix
, const char *sourcecode
,
81 int submenu
, int *index
, struct bls_entry
*bls
)
84 char **menu_args
= NULL
;
85 char *menu_users
= NULL
;
86 char *menu_title
= NULL
;
87 char *menu_sourcecode
= NULL
;
89 struct grub_menu_entry_class
*menu_classes
= NULL
;
92 grub_menu_entry_t
*last
;
94 menu
= grub_env_get_menu ();
96 return grub_error (GRUB_ERR_MENU
, "no menu context");
98 last
= &menu
->entry_list
;
100 menu_sourcecode
= grub_xasprintf ("%s%s", prefix
?: "", sourcecode
);
101 if (! menu_sourcecode
)
104 if (classes
&& classes
[0])
107 for (i
= 0; classes
[i
]; i
++); /* count # of menuentry classes */
108 menu_classes
= grub_zalloc (sizeof (struct grub_menu_entry_class
)
113 for (i
= 0; classes
[i
]; i
++)
115 menu_classes
[i
].name
= grub_strdup (classes
[i
]);
116 if (! menu_classes
[i
].name
)
118 menu_classes
[i
].next
= classes
[i
+ 1] ? &menu_classes
[i
+ 1] : NULL
;
124 menu_users
= grub_strdup (users
);
132 for (i
= 0; i
< ARRAY_SIZE (hotkey_aliases
); i
++)
133 if (grub_strcmp (hotkey
, hotkey_aliases
[i
].name
) == 0)
135 menu_hotkey
= hotkey_aliases
[i
].key
;
138 if (i
== ARRAY_SIZE (hotkey_aliases
))
139 menu_hotkey
= hotkey
[0];
144 grub_error (GRUB_ERR_MENU
, "menuentry is missing title");
148 menu_title
= grub_strdup (args
[0]);
152 grub_dprintf ("menu", "id:\"%s\"\n", id
);
153 grub_dprintf ("menu", "title:\"%s\"\n", menu_title
);
154 menu_id
= grub_strdup (id
? : menu_title
);
157 grub_dprintf ("menu", "menu_id:\"%s\"\n", menu_id
);
159 /* Save argc, args to pass as parameters to block arg later. */
160 menu_args
= grub_malloc (sizeof (char*) * (argc
+ 1));
166 for (i
= 0; i
< argc
; i
++)
168 menu_args
[i
] = grub_strdup (args
[i
]);
172 menu_args
[argc
] = NULL
;
175 /* Add the menu entry at the end of the list. */
180 last
= &(*last
)->next
;
183 *last
= grub_zalloc (sizeof (**last
));
187 (*last
)->title
= menu_title
;
188 (*last
)->id
= menu_id
;
189 (*last
)->hotkey
= menu_hotkey
;
190 (*last
)->classes
= menu_classes
;
192 (*last
)->restricted
= 1;
193 (*last
)->users
= menu_users
;
194 (*last
)->argc
= argc
;
195 (*last
)->args
= menu_args
;
196 (*last
)->sourcecode
= menu_sourcecode
;
197 (*last
)->submenu
= submenu
;
203 return GRUB_ERR_NONE
;
207 grub_free (menu_sourcecode
);
210 for (i
= 0; menu_classes
&& menu_classes
[i
].name
; i
++)
211 grub_free (menu_classes
[i
].name
);
212 grub_free (menu_classes
);
217 for (i
= 0; menu_args
&& menu_args
[i
]; i
++)
218 grub_free (menu_args
[i
]);
219 grub_free (menu_args
);
222 grub_free (menu_users
);
223 grub_free (menu_title
);
229 setparams_prefix (int argc
, char **args
)
235 grub_size_t len
= 10;
237 /* Count resulting string length */
238 for (i
= 0; i
< argc
; i
++)
240 len
+= 3; /* 3 = 1 space + 2 quotes */
243 len
+= (*p
++ == '\'' ? 3 : 1);
246 result
= grub_malloc (len
+ 2);
250 grub_strcpy (result
, "setparams");
253 for (j
= 0; j
< argc
; j
++)
257 p
= grub_strchrsub (p
, args
[j
], '\'', "'\\''");
266 grub_cmd_menuentry (grub_extcmd_context_t ctxt
, int argc
, char **args
)
276 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "missing arguments");
278 if (ctxt
->state
[3].set
&& ctxt
->script
)
279 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "multiple menuentry definitions");
281 if (! ctxt
->state
[3].set
&& ! ctxt
->script
)
282 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "no menuentry definition");
284 if (ctxt
->state
[1].set
)
285 users
= ctxt
->state
[1].arg
;
286 else if (ctxt
->state
[5].set
)
292 return grub_normal_add_menu_entry (argc
, (const char **) args
,
293 (ctxt
->state
[0].set
? ctxt
->state
[0].args
297 ctxt
->state
[2].arg
, 0,
299 ctxt
->extcmd
->cmd
->name
[0] == 's',
302 src
= args
[argc
- 1];
303 args
[argc
- 1] = NULL
;
305 len
= grub_strlen(src
);
309 prefix
= setparams_prefix (argc
- 1, args
);
313 r
= grub_normal_add_menu_entry (argc
- 1, (const char **) args
,
314 ctxt
->state
[0].args
, ctxt
->state
[4].arg
,
316 ctxt
->state
[2].arg
, prefix
, src
+ 1,
317 ctxt
->extcmd
->cmd
->name
[0] == 's', NULL
,
321 args
[argc
- 1] = src
;
326 static grub_extcmd_t cmd
, cmd_sub
;
329 grub_menu_init (void)
331 cmd
= grub_register_extcmd ("menuentry", grub_cmd_menuentry
,
332 GRUB_COMMAND_FLAG_BLOCKS
333 | GRUB_COMMAND_ACCEPT_DASH
334 | GRUB_COMMAND_FLAG_EXTRACTOR
,
335 N_("BLOCK"), N_("Define a menu entry."), options
);
336 cmd_sub
= grub_register_extcmd ("submenu", grub_cmd_menuentry
,
337 GRUB_COMMAND_FLAG_BLOCKS
338 | GRUB_COMMAND_ACCEPT_DASH
339 | GRUB_COMMAND_FLAG_EXTRACTOR
,
340 N_("BLOCK"), N_("Define a submenu."),
345 grub_menu_fini (void)
347 grub_unregister_extcmd (cmd
);
348 grub_unregister_extcmd (cmd_sub
);