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."),
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
,
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 menu_id
= grub_strdup (id
? : menu_title
);
156 /* Save argc, args to pass as parameters to block arg later. */
157 menu_args
= grub_malloc (sizeof (char*) * (argc
+ 1));
163 for (i
= 0; i
< argc
; i
++)
165 menu_args
[i
] = grub_strdup (args
[i
]);
169 menu_args
[argc
] = NULL
;
172 /* Add the menu entry at the end of the list. */
174 last
= &(*last
)->next
;
176 *last
= grub_zalloc (sizeof (**last
));
180 (*last
)->title
= menu_title
;
181 (*last
)->id
= menu_id
;
182 (*last
)->hotkey
= menu_hotkey
;
183 (*last
)->classes
= menu_classes
;
185 (*last
)->restricted
= 1;
186 (*last
)->users
= menu_users
;
187 (*last
)->argc
= argc
;
188 (*last
)->args
= menu_args
;
189 (*last
)->sourcecode
= menu_sourcecode
;
190 (*last
)->submenu
= submenu
;
193 return GRUB_ERR_NONE
;
197 grub_free (menu_sourcecode
);
200 for (i
= 0; menu_classes
&& menu_classes
[i
].name
; i
++)
201 grub_free (menu_classes
[i
].name
);
202 grub_free (menu_classes
);
207 for (i
= 0; menu_args
&& menu_args
[i
]; i
++)
208 grub_free (menu_args
[i
]);
209 grub_free (menu_args
);
212 grub_free (menu_users
);
213 grub_free (menu_title
);
219 setparams_prefix (int argc
, char **args
)
225 grub_size_t len
= 10;
227 /* Count resulting string length */
228 for (i
= 0; i
< argc
; i
++)
230 len
+= 3; /* 3 = 1 space + 2 quotes */
233 len
+= (*p
++ == '\'' ? 3 : 1);
236 result
= grub_malloc (len
+ 2);
240 grub_strcpy (result
, "setparams");
243 for (j
= 0; j
< argc
; j
++)
247 p
= grub_strchrsub (p
, args
[j
], '\'', "'\\''");
256 grub_cmd_menuentry (grub_extcmd_context_t ctxt
, int argc
, char **args
)
266 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "missing arguments");
268 if (ctxt
->state
[3].set
&& ctxt
->script
)
269 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "multiple menuentry definitions");
271 if (! ctxt
->state
[3].set
&& ! ctxt
->script
)
272 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "no menuentry definition");
274 if (ctxt
->state
[1].set
)
275 users
= ctxt
->state
[1].arg
;
276 else if (ctxt
->state
[5].set
)
282 return grub_normal_add_menu_entry (argc
, (const char **) args
,
283 (ctxt
->state
[0].set
? ctxt
->state
[0].args
287 ctxt
->state
[2].arg
, 0,
289 ctxt
->extcmd
->cmd
->name
[0] == 's');
291 src
= args
[argc
- 1];
292 args
[argc
- 1] = NULL
;
294 len
= grub_strlen(src
);
298 prefix
= setparams_prefix (argc
- 1, args
);
302 r
= grub_normal_add_menu_entry (argc
- 1, (const char **) args
,
303 ctxt
->state
[0].args
, ctxt
->state
[4].arg
,
305 ctxt
->state
[2].arg
, prefix
, src
+ 1,
306 ctxt
->extcmd
->cmd
->name
[0] == 's');
309 args
[argc
- 1] = src
;
314 static grub_extcmd_t cmd
, cmd_sub
;
317 grub_menu_init (void)
319 cmd
= grub_register_extcmd ("menuentry", grub_cmd_menuentry
,
320 GRUB_COMMAND_FLAG_BLOCKS
321 | GRUB_COMMAND_ACCEPT_DASH
322 | GRUB_COMMAND_FLAG_EXTRACTOR
,
323 N_("BLOCK"), N_("Define a menu entry."), options
);
324 cmd_sub
= grub_register_extcmd ("submenu", grub_cmd_menuentry
,
325 GRUB_COMMAND_FLAG_BLOCKS
326 | GRUB_COMMAND_ACCEPT_DASH
327 | GRUB_COMMAND_FLAG_EXTRACTOR
,
328 N_("BLOCK"), N_("Define a submenu."),
333 grub_menu_fini (void)
335 grub_unregister_extcmd (cmd
);
336 grub_unregister_extcmd (cmd_sub
);