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 typedef const char * (*get_vmenu_title_pf
)(const char *vMenu
);
29 static get_vmenu_title_pf g_pfvmenu_title
= NULL
;
32 static const struct grub_arg_option options
[] =
34 {"class", 1, GRUB_ARG_OPTION_REPEATABLE
,
35 N_("Menu entry type."), N_("STRING"), ARG_TYPE_STRING
},
37 N_("List of users allowed to boot this entry."), N_("USERNAME[,USERNAME]"),
40 N_("Keyboard key to quickly boot this entry."), N_("KEYBOARD_KEY"), ARG_TYPE_STRING
},
42 N_("Use STRING as menu entry body."), N_("STRING"), ARG_TYPE_STRING
},
43 {"id", 0, 0, N_("Menu entry identifier."), N_("STRING"), ARG_TYPE_STRING
},
44 /* TRANSLATORS: menu entry can either be bootable by anyone or only by
45 handful of users. By default when security is active only superusers can
46 boot a given menu entry. With --unrestricted (this option)
47 anyone can boot it. */
48 {"unrestricted", 0, 0, N_("This entry can be booted by any user."),
59 {"backspace", GRUB_TERM_BACKSPACE
},
60 {"tab", GRUB_TERM_TAB
},
61 {"delete", GRUB_TERM_KEY_DC
},
62 {"insert", GRUB_TERM_KEY_INSERT
},
63 {"f1", GRUB_TERM_KEY_F1
},
64 {"f2", GRUB_TERM_KEY_F2
},
65 {"f3", GRUB_TERM_KEY_F3
},
66 {"f4", GRUB_TERM_KEY_F4
},
67 {"f5", GRUB_TERM_KEY_F5
},
68 {"f6", GRUB_TERM_KEY_F6
},
69 {"f7", GRUB_TERM_KEY_F7
},
70 {"f8", GRUB_TERM_KEY_F8
},
71 {"f9", GRUB_TERM_KEY_F9
},
72 {"f10", GRUB_TERM_KEY_F10
},
73 {"f11", GRUB_TERM_KEY_F11
},
74 {"f12", GRUB_TERM_KEY_F12
},
77 /* Add a menu entry to the current menu context (as given by the environment
78 variable data slot `menu'). As the configuration file is read, the script
79 parser calls this when a menu entry is to be created. */
81 grub_normal_add_menu_entry (int argc
, const char **args
,
82 char **classes
, const char *id
,
83 const char *users
, const char *hotkey
,
84 const char *prefix
, const char *sourcecode
,
85 int submenu
, int *index
, struct bls_entry
*bls
)
88 char **menu_args
= NULL
;
89 char *menu_users
= NULL
;
90 char *menu_title
= NULL
;
91 char *menu_sourcecode
= NULL
;
93 const char *vmenu
= NULL
;
94 const char *vaddr
= NULL
;
95 struct grub_menu_entry_class
*menu_classes
= NULL
;
98 grub_menu_entry_t
*last
;
100 menu
= grub_env_get_menu ();
102 return grub_error (GRUB_ERR_MENU
, "no menu context");
104 last
= &menu
->entry_list
;
106 menu_sourcecode
= grub_xasprintf ("%s%s", prefix
?: "", sourcecode
);
107 if (! menu_sourcecode
)
110 if (classes
&& classes
[0])
113 for (i
= 0; classes
[i
]; i
++); /* count # of menuentry classes */
114 menu_classes
= grub_zalloc (sizeof (struct grub_menu_entry_class
)
119 for (i
= 0; classes
[i
]; i
++)
121 menu_classes
[i
].name
= grub_strdup (classes
[i
]);
122 if (! menu_classes
[i
].name
)
124 menu_classes
[i
].next
= classes
[i
+ 1] ? &menu_classes
[i
+ 1] : NULL
;
130 menu_users
= grub_strdup (users
);
138 for (i
= 0; i
< ARRAY_SIZE (hotkey_aliases
); i
++)
139 if (grub_strcmp (hotkey
, hotkey_aliases
[i
].name
) == 0)
141 menu_hotkey
= hotkey_aliases
[i
].key
;
144 if (i
== ARRAY_SIZE (hotkey_aliases
))
145 menu_hotkey
= hotkey
[0];
150 grub_error (GRUB_ERR_MENU
, "menuentry is missing title");
154 if (!g_pfvmenu_title
) {
155 vaddr
= grub_env_get("VTOY_VMENU_FUNC_ADDR");
157 g_pfvmenu_title
= (get_vmenu_title_pf
)(unsigned long)grub_strtoul(vaddr
, NULL
, 16);
160 if (g_pfvmenu_title
&& grub_strncmp(args
[0], "@VTMENU_", 8) == 0)
161 vmenu
= g_pfvmenu_title(args
[0] + 1);
163 menu_title
= grub_strdup (vmenu
? vmenu
: args
[0]);
168 grub_dprintf ("menu", "id:\"%s\"\n", id
);
169 grub_dprintf ("menu", "title:\"%s\"\n", menu_title
);
170 menu_id
= grub_strdup (id
? : menu_title
);
173 grub_dprintf ("menu", "menu_id:\"%s\"\n", menu_id
);
175 /* Save argc, args to pass as parameters to block arg later. */
176 menu_args
= grub_malloc (sizeof (char*) * (argc
+ 1));
182 for (i
= 0; i
< argc
; i
++)
184 menu_args
[i
] = grub_strdup (args
[i
]);
188 menu_args
[argc
] = NULL
;
191 /* Add the menu entry at the end of the list. */
196 last
= &(*last
)->next
;
199 *last
= grub_zalloc (sizeof (**last
));
203 (*last
)->title
= menu_title
;
204 (*last
)->id
= menu_id
;
205 (*last
)->hotkey
= menu_hotkey
;
206 (*last
)->classes
= menu_classes
;
208 (*last
)->restricted
= 1;
209 (*last
)->users
= menu_users
;
210 (*last
)->argc
= argc
;
211 (*last
)->args
= menu_args
;
212 (*last
)->sourcecode
= menu_sourcecode
;
213 (*last
)->submenu
= submenu
;
219 return GRUB_ERR_NONE
;
223 grub_free (menu_sourcecode
);
226 for (i
= 0; menu_classes
&& menu_classes
[i
].name
; i
++)
227 grub_free (menu_classes
[i
].name
);
228 grub_free (menu_classes
);
233 for (i
= 0; menu_args
&& menu_args
[i
]; i
++)
234 grub_free (menu_args
[i
]);
235 grub_free (menu_args
);
238 grub_free (menu_users
);
239 grub_free (menu_title
);
245 setparams_prefix (int argc
, char **args
)
251 grub_size_t len
= 10;
253 /* Count resulting string length */
254 for (i
= 0; i
< argc
; i
++)
256 len
+= 3; /* 3 = 1 space + 2 quotes */
259 len
+= (*p
++ == '\'' ? 3 : 1);
262 result
= grub_malloc (len
+ 2);
266 grub_strcpy (result
, "setparams");
269 for (j
= 0; j
< argc
; j
++)
273 p
= grub_strchrsub (p
, args
[j
], '\'', "'\\''");
282 grub_cmd_menuentry (grub_extcmd_context_t ctxt
, int argc
, char **args
)
292 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "missing arguments");
294 if (ctxt
->state
[3].set
&& ctxt
->script
)
295 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "multiple menuentry definitions");
297 if (! ctxt
->state
[3].set
&& ! ctxt
->script
)
298 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "no menuentry definition");
300 if (ctxt
->state
[1].set
)
301 users
= ctxt
->state
[1].arg
;
302 else if (ctxt
->state
[5].set
)
308 return grub_normal_add_menu_entry (argc
, (const char **) args
,
309 (ctxt
->state
[0].set
? ctxt
->state
[0].args
313 ctxt
->state
[2].arg
, 0,
315 ctxt
->extcmd
->cmd
->name
[0] == 's',
318 src
= args
[argc
- 1];
319 args
[argc
- 1] = NULL
;
321 len
= grub_strlen(src
);
325 prefix
= setparams_prefix (argc
- 1, args
);
329 r
= grub_normal_add_menu_entry (argc
- 1, (const char **) args
,
330 ctxt
->state
[0].args
, ctxt
->state
[4].arg
,
332 ctxt
->state
[2].arg
, prefix
, src
+ 1,
333 ctxt
->extcmd
->cmd
->name
[0] == 's', NULL
,
337 args
[argc
- 1] = src
;
342 static grub_extcmd_t cmd
, cmd_sub
;
345 grub_menu_init (void)
347 cmd
= grub_register_extcmd ("menuentry", grub_cmd_menuentry
,
348 GRUB_COMMAND_FLAG_BLOCKS
349 | GRUB_COMMAND_ACCEPT_DASH
350 | GRUB_COMMAND_FLAG_EXTRACTOR
,
351 N_("BLOCK"), N_("Define a menu entry."), options
);
352 cmd_sub
= grub_register_extcmd ("submenu", grub_cmd_menuentry
,
353 GRUB_COMMAND_FLAG_BLOCKS
354 | GRUB_COMMAND_ACCEPT_DASH
355 | GRUB_COMMAND_FLAG_EXTRACTOR
,
356 N_("BLOCK"), N_("Define a submenu."),
361 grub_menu_fini (void)
363 grub_unregister_extcmd (cmd
);
364 grub_unregister_extcmd (cmd_sub
);