]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/commands/menuentry.c
Add muli-languages support for Ventoy menu.
[Ventoy.git] / GRUB2 / MOD_SRC / grub-2.04 / grub-core / commands / menuentry.c
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 typedef const char * (*get_vmenu_title_pf)(const char *vMenu);
29 static get_vmenu_title_pf g_pfvmenu_title = NULL;
30
31
32 static const struct grub_arg_option options[] =
33 {
34 {"class", 1, GRUB_ARG_OPTION_REPEATABLE,
35 N_("Menu entry type."), N_("STRING"), ARG_TYPE_STRING},
36 {"users", 2, 0,
37 N_("List of users allowed to boot this entry."), N_("USERNAME[,USERNAME]"),
38 ARG_TYPE_STRING},
39 {"hotkey", 3, 0,
40 N_("Keyboard key to quickly boot this entry."), N_("KEYBOARD_KEY"), ARG_TYPE_STRING},
41 {"source", 4, 0,
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."),
49 0, ARG_TYPE_NONE},
50 {0, 0, 0, 0, 0, 0}
51 };
52
53 static struct
54 {
55 const char *name;
56 int key;
57 } hotkey_aliases[] =
58 {
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},
75 };
76
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. */
80 grub_err_t
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)
86 {
87 int menu_hotkey = 0;
88 char **menu_args = NULL;
89 char *menu_users = NULL;
90 char *menu_title = NULL;
91 char *menu_sourcecode = NULL;
92 char *menu_id = NULL;
93 const char *vmenu = NULL;
94 const char *vaddr = NULL;
95 struct grub_menu_entry_class *menu_classes = NULL;
96
97 grub_menu_t menu;
98 grub_menu_entry_t *last;
99
100 menu = grub_env_get_menu ();
101 if (! menu)
102 return grub_error (GRUB_ERR_MENU, "no menu context");
103
104 last = &menu->entry_list;
105
106 menu_sourcecode = grub_xasprintf ("%s%s", prefix ?: "", sourcecode);
107 if (! menu_sourcecode)
108 return grub_errno;
109
110 if (classes && classes[0])
111 {
112 int i;
113 for (i = 0; classes[i]; i++); /* count # of menuentry classes */
114 menu_classes = grub_zalloc (sizeof (struct grub_menu_entry_class)
115 * (i + 1));
116 if (! menu_classes)
117 goto fail;
118
119 for (i = 0; classes[i]; i++)
120 {
121 menu_classes[i].name = grub_strdup (classes[i]);
122 if (! menu_classes[i].name)
123 goto fail;
124 menu_classes[i].next = classes[i + 1] ? &menu_classes[i + 1] : NULL;
125 }
126 }
127
128 if (users)
129 {
130 menu_users = grub_strdup (users);
131 if (! menu_users)
132 goto fail;
133 }
134
135 if (hotkey)
136 {
137 unsigned i;
138 for (i = 0; i < ARRAY_SIZE (hotkey_aliases); i++)
139 if (grub_strcmp (hotkey, hotkey_aliases[i].name) == 0)
140 {
141 menu_hotkey = hotkey_aliases[i].key;
142 break;
143 }
144 if (i == ARRAY_SIZE (hotkey_aliases))
145 menu_hotkey = hotkey[0];
146 }
147
148 if (! argc)
149 {
150 grub_error (GRUB_ERR_MENU, "menuentry is missing title");
151 goto fail;
152 }
153
154 if (!g_pfvmenu_title) {
155 vaddr = grub_env_get("VTOY_VMENU_FUNC_ADDR");
156 if (vaddr)
157 g_pfvmenu_title = (get_vmenu_title_pf)(unsigned long)grub_strtoul(vaddr, NULL, 16);
158 }
159
160 if (g_pfvmenu_title && grub_strncmp(args[0], "@VTMENU_", 8) == 0)
161 vmenu = g_pfvmenu_title(args[0] + 1);
162
163 menu_title = grub_strdup (vmenu ? vmenu : args[0]);
164
165 if (! menu_title)
166 goto fail;
167
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);
171 if (! menu_id)
172 goto fail;
173 grub_dprintf ("menu", "menu_id:\"%s\"\n", menu_id);
174
175 /* Save argc, args to pass as parameters to block arg later. */
176 menu_args = grub_malloc (sizeof (char*) * (argc + 1));
177 if (! menu_args)
178 goto fail;
179
180 {
181 int i;
182 for (i = 0; i < argc; i++)
183 {
184 menu_args[i] = grub_strdup (args[i]);
185 if (! menu_args[i])
186 goto fail;
187 }
188 menu_args[argc] = NULL;
189 }
190
191 /* Add the menu entry at the end of the list. */
192 int ind=0;
193 while (*last)
194 {
195 ind++;
196 last = &(*last)->next;
197 }
198
199 *last = grub_zalloc (sizeof (**last));
200 if (! *last)
201 goto fail;
202
203 (*last)->title = menu_title;
204 (*last)->id = menu_id;
205 (*last)->hotkey = menu_hotkey;
206 (*last)->classes = menu_classes;
207 if (menu_users)
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;
214 (*last)->bls = bls;
215
216 menu->size++;
217 if (index)
218 *index = ind;
219 return GRUB_ERR_NONE;
220
221 fail:
222
223 grub_free (menu_sourcecode);
224 {
225 int i;
226 for (i = 0; menu_classes && menu_classes[i].name; i++)
227 grub_free (menu_classes[i].name);
228 grub_free (menu_classes);
229 }
230
231 {
232 int i;
233 for (i = 0; menu_args && menu_args[i]; i++)
234 grub_free (menu_args[i]);
235 grub_free (menu_args);
236 }
237
238 grub_free (menu_users);
239 grub_free (menu_title);
240 grub_free (menu_id);
241 return grub_errno;
242 }
243
244 static char *
245 setparams_prefix (int argc, char **args)
246 {
247 int i;
248 int j;
249 char *p;
250 char *result;
251 grub_size_t len = 10;
252
253 /* Count resulting string length */
254 for (i = 0; i < argc; i++)
255 {
256 len += 3; /* 3 = 1 space + 2 quotes */
257 p = args[i];
258 while (*p)
259 len += (*p++ == '\'' ? 3 : 1);
260 }
261
262 result = grub_malloc (len + 2);
263 if (! result)
264 return 0;
265
266 grub_strcpy (result, "setparams");
267 p = result + 9;
268
269 for (j = 0; j < argc; j++)
270 {
271 *p++ = ' ';
272 *p++ = '\'';
273 p = grub_strchrsub (p, args[j], '\'', "'\\''");
274 *p++ = '\'';
275 }
276 *p++ = '\n';
277 *p = '\0';
278 return result;
279 }
280
281 static grub_err_t
282 grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args)
283 {
284 char ch;
285 char *src;
286 char *prefix;
287 unsigned len;
288 grub_err_t r;
289 const char *users;
290
291 if (! argc)
292 return grub_error (GRUB_ERR_BAD_ARGUMENT, "missing arguments");
293
294 if (ctxt->state[3].set && ctxt->script)
295 return grub_error (GRUB_ERR_BAD_ARGUMENT, "multiple menuentry definitions");
296
297 if (! ctxt->state[3].set && ! ctxt->script)
298 return grub_error (GRUB_ERR_BAD_ARGUMENT, "no menuentry definition");
299
300 if (ctxt->state[1].set)
301 users = ctxt->state[1].arg;
302 else if (ctxt->state[5].set)
303 users = NULL;
304 else
305 users = "";
306
307 if (! ctxt->script)
308 return grub_normal_add_menu_entry (argc, (const char **) args,
309 (ctxt->state[0].set ? ctxt->state[0].args
310 : NULL),
311 ctxt->state[4].arg,
312 users,
313 ctxt->state[2].arg, 0,
314 ctxt->state[3].arg,
315 ctxt->extcmd->cmd->name[0] == 's',
316 NULL, NULL);
317
318 src = args[argc - 1];
319 args[argc - 1] = NULL;
320
321 len = grub_strlen(src);
322 ch = src[len - 1];
323 src[len - 1] = '\0';
324
325 prefix = setparams_prefix (argc - 1, args);
326 if (! prefix)
327 return grub_errno;
328
329 r = grub_normal_add_menu_entry (argc - 1, (const char **) args,
330 ctxt->state[0].args, ctxt->state[4].arg,
331 users,
332 ctxt->state[2].arg, prefix, src + 1,
333 ctxt->extcmd->cmd->name[0] == 's', NULL,
334 NULL);
335
336 src[len - 1] = ch;
337 args[argc - 1] = src;
338 grub_free (prefix);
339 return r;
340 }
341
342 static grub_extcmd_t cmd, cmd_sub;
343
344 void
345 grub_menu_init (void)
346 {
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."),
357 options);
358 }
359
360 void
361 grub_menu_fini (void)
362 {
363 grub_unregister_extcmd (cmd);
364 grub_unregister_extcmd (cmd_sub);
365 }