]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/grub-2.04/grub-core/normal/menu.c
Add German language (#57)
[Ventoy.git] / GRUB2 / grub-2.04 / grub-core / normal / menu.c
1 /* menu.c - General supporting functionality for menus. */
2 /*
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2003,2004,2005,2006,2007,2008,2009,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/normal.h>
21 #include <grub/misc.h>
22 #include <grub/loader.h>
23 #include <grub/mm.h>
24 #include <grub/time.h>
25 #include <grub/env.h>
26 #include <grub/menu_viewer.h>
27 #include <grub/command.h>
28 #include <grub/parser.h>
29 #include <grub/auth.h>
30 #include <grub/i18n.h>
31 #include <grub/term.h>
32 #include <grub/script_sh.h>
33 #include <grub/gfxterm.h>
34 #include <grub/dl.h>
35 #include <grub/env.h>
36
37 int g_ventoy_menu_refresh = 0;
38 int g_ventoy_memdisk_mode = 0;
39 int g_ventoy_iso_raw = 0;
40 int g_ventoy_iso_uefi_drv = 0;
41 int g_ventoy_last_entry = 0;
42
43 /* Time to delay after displaying an error message about a default/fallback
44 entry failing to boot. */
45 #define DEFAULT_ENTRY_ERROR_DELAY_MS 2500
46
47 grub_err_t (*grub_gfxmenu_try_hook) (int entry, grub_menu_t menu,
48 int nested) = NULL;
49
50 enum timeout_style {
51 TIMEOUT_STYLE_MENU,
52 TIMEOUT_STYLE_COUNTDOWN,
53 TIMEOUT_STYLE_HIDDEN
54 };
55
56 struct timeout_style_name {
57 const char *name;
58 enum timeout_style style;
59 } timeout_style_names[] = {
60 {"menu", TIMEOUT_STYLE_MENU},
61 {"countdown", TIMEOUT_STYLE_COUNTDOWN},
62 {"hidden", TIMEOUT_STYLE_HIDDEN},
63 {NULL, 0}
64 };
65
66 /* Wait until the user pushes any key so that the user
67 can see what happened. */
68 void
69 grub_wait_after_message (void)
70 {
71 grub_uint64_t endtime;
72 grub_xputs ("\n");
73 grub_printf_ (N_("Press any key to continue..."));
74 grub_refresh ();
75
76 endtime = grub_get_time_ms () + 10000;
77
78 while (grub_get_time_ms () < endtime
79 && grub_getkey_noblock () == GRUB_TERM_NO_KEY);
80
81 grub_xputs ("\n");
82 }
83
84 /* Get a menu entry by its index in the entry list. */
85 grub_menu_entry_t
86 grub_menu_get_entry (grub_menu_t menu, int no)
87 {
88 grub_menu_entry_t e;
89
90 for (e = menu->entry_list; e && no > 0; e = e->next, no--)
91 ;
92
93 return e;
94 }
95
96 /* Get the index of a menu entry associated with a given hotkey, or -1. */
97 static int
98 get_entry_index_by_hotkey (grub_menu_t menu, int hotkey)
99 {
100 grub_menu_entry_t entry;
101 int i;
102
103 for (i = 0, entry = menu->entry_list; i < menu->size;
104 i++, entry = entry->next)
105 if (entry->hotkey == hotkey)
106 return i;
107
108 return -1;
109 }
110
111 /* Return the timeout style. If the variable "timeout_style" is not set or
112 invalid, default to TIMEOUT_STYLE_MENU. */
113 static enum timeout_style
114 get_timeout_style (void)
115 {
116 const char *val;
117 struct timeout_style_name *style_name;
118
119 val = grub_env_get ("timeout_style");
120 if (!val)
121 return TIMEOUT_STYLE_MENU;
122
123 for (style_name = timeout_style_names; style_name->name; style_name++)
124 if (grub_strcmp (style_name->name, val) == 0)
125 return style_name->style;
126
127 return TIMEOUT_STYLE_MENU;
128 }
129
130 /* Return the current timeout. If the variable "timeout" is not set or
131 invalid, return -1. */
132 int
133 grub_menu_get_timeout (void)
134 {
135 const char *val;
136 int timeout;
137
138 val = grub_env_get ("timeout");
139 if (! val)
140 return -1;
141
142 grub_error_push ();
143
144 timeout = (int) grub_strtoul (val, 0, 0);
145
146 /* If the value is invalid, unset the variable. */
147 if (grub_errno != GRUB_ERR_NONE)
148 {
149 grub_env_unset ("timeout");
150 grub_errno = GRUB_ERR_NONE;
151 timeout = -1;
152 }
153
154 grub_error_pop ();
155
156 return timeout;
157 }
158
159 /* Set current timeout in the variable "timeout". */
160 void
161 grub_menu_set_timeout (int timeout)
162 {
163 /* Ignore TIMEOUT if it is zero, because it will be unset really soon. */
164 if (timeout > 0)
165 {
166 char buf[16];
167
168 grub_snprintf (buf, sizeof (buf), "%d", timeout);
169 grub_env_set ("timeout", buf);
170 }
171 }
172
173 /* Get the first entry number from the value of the environment variable NAME,
174 which is a space-separated list of non-negative integers. The entry number
175 which is returned is stripped from the value of NAME. If no entry number
176 can be found, -1 is returned. */
177 static int
178 get_and_remove_first_entry_number (const char *name)
179 {
180 const char *val;
181 char *tail;
182 int entry;
183
184 val = grub_env_get (name);
185 if (! val)
186 return -1;
187
188 grub_error_push ();
189
190 entry = (int) grub_strtoul (val, &tail, 0);
191
192 if (grub_errno == GRUB_ERR_NONE)
193 {
194 /* Skip whitespace to find the next digit. */
195 while (*tail && grub_isspace (*tail))
196 tail++;
197 grub_env_set (name, tail);
198 }
199 else
200 {
201 grub_env_unset (name);
202 grub_errno = GRUB_ERR_NONE;
203 entry = -1;
204 }
205
206 grub_error_pop ();
207
208 return entry;
209 }
210
211 /* Run a menu entry. */
212 static void
213 grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot)
214 {
215 grub_err_t err = GRUB_ERR_NONE;
216 int errs_before;
217 grub_menu_t menu = NULL;
218 char *optr, *buf, *oldchosen = NULL, *olddefault = NULL;
219 const char *ptr, *chosen, *def;
220 grub_size_t sz = 0;
221
222 if (entry->restricted)
223 err = grub_auth_check_authentication (entry->users);
224
225 if (err)
226 {
227 grub_print_error ();
228 grub_errno = GRUB_ERR_NONE;
229 return;
230 }
231
232 errs_before = grub_err_printed_errors;
233
234 chosen = grub_env_get ("chosen");
235 def = grub_env_get ("default");
236
237 if (entry->submenu)
238 {
239 grub_env_context_open ();
240 menu = grub_zalloc (sizeof (*menu));
241 if (! menu)
242 return;
243 grub_env_set_menu (menu);
244 if (auto_boot)
245 grub_env_set ("timeout", "0");
246 }
247
248 for (ptr = entry->id; *ptr; ptr++)
249 sz += (*ptr == '>') ? 2 : 1;
250 if (chosen)
251 {
252 oldchosen = grub_strdup (chosen);
253 if (!oldchosen)
254 grub_print_error ();
255 }
256 if (def)
257 {
258 olddefault = grub_strdup (def);
259 if (!olddefault)
260 grub_print_error ();
261 }
262 sz++;
263 if (chosen)
264 sz += grub_strlen (chosen);
265 sz++;
266 buf = grub_malloc (sz);
267 if (!buf)
268 grub_print_error ();
269 else
270 {
271 optr = buf;
272 if (chosen)
273 {
274 optr = grub_stpcpy (optr, chosen);
275 *optr++ = '>';
276 }
277 for (ptr = entry->id; *ptr; ptr++)
278 {
279 if (*ptr == '>')
280 *optr++ = '>';
281 *optr++ = *ptr;
282 }
283 *optr = 0;
284 grub_env_set ("chosen", buf);
285 grub_env_export ("chosen");
286 grub_free (buf);
287 }
288
289 for (ptr = def; ptr && *ptr; ptr++)
290 {
291 if (ptr[0] == '>' && ptr[1] == '>')
292 {
293 ptr++;
294 continue;
295 }
296 if (ptr[0] == '>')
297 break;
298 }
299
300 if (ptr && ptr[0] && ptr[1])
301 grub_env_set ("default", ptr + 1);
302 else
303 grub_env_unset ("default");
304
305 grub_script_execute_new_scope (entry->sourcecode, entry->argc, entry->args);
306
307 if (errs_before != grub_err_printed_errors)
308 grub_wait_after_message ();
309
310 errs_before = grub_err_printed_errors;
311
312 if (grub_errno == GRUB_ERR_NONE && grub_loader_is_loaded ())
313 /* Implicit execution of boot, only if something is loaded. */
314 grub_command_execute ("boot", 0, 0);
315
316 if (errs_before != grub_err_printed_errors)
317 grub_wait_after_message ();
318
319 if (entry->submenu)
320 {
321 if (menu && menu->size)
322 {
323 grub_show_menu (menu, 1, auto_boot);
324 grub_normal_free_menu (menu);
325 }
326 grub_env_context_close ();
327 }
328 if (oldchosen)
329 grub_env_set ("chosen", oldchosen);
330 else
331 grub_env_unset ("chosen");
332 if (olddefault)
333 grub_env_set ("default", olddefault);
334 else
335 grub_env_unset ("default");
336 grub_env_unset ("timeout");
337 }
338
339 /* Execute ENTRY from the menu MENU, falling back to entries specified
340 in the environment variable "fallback" if it fails. CALLBACK is a
341 pointer to a struct of function pointers which are used to allow the
342 caller provide feedback to the user. */
343 static void
344 grub_menu_execute_with_fallback (grub_menu_t menu,
345 grub_menu_entry_t entry,
346 int autobooted,
347 grub_menu_execute_callback_t callback,
348 void *callback_data)
349 {
350 int fallback_entry;
351
352 callback->notify_booting (entry, callback_data);
353
354 grub_menu_execute_entry (entry, 1);
355
356 /* Deal with fallback entries. */
357 while ((fallback_entry = get_and_remove_first_entry_number ("fallback"))
358 >= 0)
359 {
360 grub_print_error ();
361 grub_errno = GRUB_ERR_NONE;
362
363 entry = grub_menu_get_entry (menu, fallback_entry);
364 callback->notify_fallback (entry, callback_data);
365 grub_menu_execute_entry (entry, 1);
366 /* If the function call to execute the entry returns at all, then this is
367 taken to indicate a boot failure. For menu entries that do something
368 other than actually boot an operating system, this could assume
369 incorrectly that something failed. */
370 }
371
372 if (!autobooted)
373 callback->notify_failure (callback_data);
374 }
375
376 static struct grub_menu_viewer *viewers;
377
378 static void
379 menu_set_chosen_entry (int entry)
380 {
381 struct grub_menu_viewer *cur;
382 for (cur = viewers; cur; cur = cur->next)
383 cur->set_chosen_entry (entry, cur->data);
384 }
385
386 static void
387 menu_print_timeout (int timeout)
388 {
389 struct grub_menu_viewer *cur;
390 for (cur = viewers; cur; cur = cur->next)
391 cur->print_timeout (timeout, cur->data);
392 }
393
394 static void
395 menu_fini (void)
396 {
397 struct grub_menu_viewer *cur, *next;
398 for (cur = viewers; cur; cur = next)
399 {
400 next = cur->next;
401 cur->fini (cur->data);
402 grub_free (cur);
403 }
404 viewers = NULL;
405 }
406
407 static void
408 menu_init (int entry, grub_menu_t menu, int nested)
409 {
410 struct grub_term_output *term;
411 int gfxmenu = 0;
412
413 FOR_ACTIVE_TERM_OUTPUTS(term)
414 if (term->fullscreen)
415 {
416 if (grub_env_get ("theme"))
417 {
418 if (!grub_gfxmenu_try_hook)
419 {
420 grub_dl_load ("gfxmenu");
421 grub_print_error ();
422 }
423 if (grub_gfxmenu_try_hook)
424 {
425 grub_err_t err;
426 err = grub_gfxmenu_try_hook (entry, menu, nested);
427 if(!err)
428 {
429 gfxmenu = 1;
430 break;
431 }
432 }
433 else
434 grub_error (GRUB_ERR_BAD_MODULE,
435 N_("module `%s' isn't loaded"),
436 "gfxmenu");
437 grub_print_error ();
438 grub_wait_after_message ();
439 }
440 grub_errno = GRUB_ERR_NONE;
441 term->fullscreen ();
442 break;
443 }
444
445 FOR_ACTIVE_TERM_OUTPUTS(term)
446 {
447 grub_err_t err;
448
449 if (grub_strcmp (term->name, "gfxterm") == 0 && gfxmenu)
450 continue;
451
452 err = grub_menu_try_text (term, entry, menu, nested);
453 if(!err)
454 continue;
455 grub_print_error ();
456 grub_errno = GRUB_ERR_NONE;
457 }
458 }
459
460 static void
461 clear_timeout (void)
462 {
463 struct grub_menu_viewer *cur;
464 for (cur = viewers; cur; cur = cur->next)
465 cur->clear_timeout (cur->data);
466 }
467
468 void
469 grub_menu_register_viewer (struct grub_menu_viewer *viewer)
470 {
471 viewer->next = viewers;
472 viewers = viewer;
473 }
474
475 static int
476 menuentry_eq (const char *id, const char *spec)
477 {
478 const char *ptr1, *ptr2;
479 ptr1 = id;
480 ptr2 = spec;
481 while (1)
482 {
483 if (*ptr2 == '>' && ptr2[1] != '>' && *ptr1 == 0)
484 return 1;
485 if (*ptr2 == '>' && ptr2[1] != '>')
486 return 0;
487 if (*ptr2 == '>')
488 ptr2++;
489 if (*ptr1 != *ptr2)
490 return 0;
491 if (*ptr1 == 0)
492 return 1;
493 ptr1++;
494 ptr2++;
495 }
496 }
497
498
499 /* Get the entry number from the variable NAME. */
500 static int
501 get_entry_number (grub_menu_t menu, const char *name)
502 {
503 const char *val;
504 int entry;
505
506 val = grub_env_get (name);
507 if (! val)
508 return -1;
509
510 grub_error_push ();
511
512 entry = (int) grub_strtoul (val, 0, 0);
513
514 if (grub_errno == GRUB_ERR_BAD_NUMBER)
515 {
516 /* See if the variable matches the title of a menu entry. */
517 grub_menu_entry_t e = menu->entry_list;
518 int i;
519
520 grub_errno = GRUB_ERR_NONE;
521
522 for (i = 0; e; i++)
523 {
524 if (menuentry_eq (e->title, val)
525 || menuentry_eq (e->id, val))
526 {
527 entry = i;
528 break;
529 }
530 e = e->next;
531 }
532
533 if (! e)
534 entry = -1;
535 }
536
537 if (grub_errno != GRUB_ERR_NONE)
538 {
539 grub_errno = GRUB_ERR_NONE;
540 entry = -1;
541 }
542
543 grub_error_pop ();
544
545 return entry;
546 }
547
548 /* Check whether a second has elapsed since the last tick. If so, adjust
549 the timer and return 1; otherwise, return 0. */
550 static int
551 has_second_elapsed (grub_uint64_t *saved_time)
552 {
553 grub_uint64_t current_time;
554
555 current_time = grub_get_time_ms ();
556 if (current_time - *saved_time >= 1000)
557 {
558 *saved_time = current_time;
559 return 1;
560 }
561 else
562 return 0;
563 }
564
565 static void
566 print_countdown (struct grub_term_coordinate *pos, int n)
567 {
568 grub_term_restore_pos (pos);
569 /* NOTE: Do not remove the trailing space characters.
570 They are required to clear the line. */
571 grub_printf ("%d ", n);
572 grub_refresh ();
573 }
574
575 #define GRUB_MENU_PAGE_SIZE 10
576
577 /* Show the menu and handle menu entry selection. Returns the menu entry
578 index that should be executed or -1 if no entry should be executed (e.g.,
579 Esc pressed to exit a sub-menu or switching menu viewers).
580 If the return value is not -1, then *AUTO_BOOT is nonzero iff the menu
581 entry to be executed is a result of an automatic default selection because
582 of the timeout. */
583 static int
584 run_menu (grub_menu_t menu, int nested, int *auto_boot)
585 {
586 const char *cmdstr;
587 grub_uint64_t saved_time;
588 int default_entry,current_entry;
589 int timeout;
590 enum timeout_style timeout_style;
591
592 default_entry = get_entry_number (menu, "default");
593
594 if (g_ventoy_last_entry >= 0 && g_ventoy_last_entry < menu->size) {
595 default_entry = g_ventoy_last_entry;
596 }
597 /* If DEFAULT_ENTRY is not within the menu entries, fall back to
598 the first entry. */
599 else if (default_entry < 0 || default_entry >= menu->size)
600 default_entry = 0;
601
602 timeout = grub_menu_get_timeout ();
603 if (timeout < 0)
604 /* If there is no timeout, the "countdown" and "hidden" styles result in
605 the system doing nothing and providing no or very little indication
606 why. Technically this is what the user asked for, but it's not very
607 useful and likely to be a source of confusion, so we disallow this. */
608 grub_env_unset ("timeout_style");
609
610 timeout_style = get_timeout_style ();
611
612 if (timeout_style == TIMEOUT_STYLE_COUNTDOWN
613 || timeout_style == TIMEOUT_STYLE_HIDDEN)
614 {
615 static struct grub_term_coordinate *pos;
616 int entry = -1;
617
618 if (timeout_style == TIMEOUT_STYLE_COUNTDOWN && timeout)
619 {
620 pos = grub_term_save_pos ();
621 print_countdown (pos, timeout);
622 }
623
624 /* Enter interruptible sleep until Escape or a menu hotkey is pressed,
625 or the timeout expires. */
626 saved_time = grub_get_time_ms ();
627 while (1)
628 {
629 int key;
630
631 key = grub_getkey_noblock ();
632 if (key != GRUB_TERM_NO_KEY)
633 {
634 entry = get_entry_index_by_hotkey (menu, key);
635 if (entry >= 0)
636 break;
637 }
638 if (key == GRUB_TERM_ESC)
639 {
640 timeout = -1;
641 break;
642 }
643
644 if (timeout > 0 && has_second_elapsed (&saved_time))
645 {
646 timeout--;
647 if (timeout_style == TIMEOUT_STYLE_COUNTDOWN)
648 print_countdown (pos, timeout);
649 }
650
651 if (timeout == 0)
652 /* We will fall through to auto-booting the default entry. */
653 break;
654 }
655
656 grub_env_unset ("timeout");
657 grub_env_unset ("timeout_style");
658 if (entry >= 0)
659 {
660 *auto_boot = 0;
661 return entry;
662 }
663 }
664
665 /* If timeout is 0, drawing is pointless (and ugly). */
666 if (timeout == 0)
667 {
668 *auto_boot = 1;
669 return default_entry;
670 }
671
672 current_entry = default_entry;
673
674 refresh:
675 menu_init (current_entry, menu, nested);
676
677 /* Initialize the time. */
678 saved_time = grub_get_time_ms ();
679
680 timeout = grub_menu_get_timeout ();
681
682 if (timeout > 0)
683 menu_print_timeout (timeout);
684 else
685 clear_timeout ();
686
687 while (1)
688 {
689 int c;
690 timeout = grub_menu_get_timeout ();
691
692 if (grub_normal_exit_level)
693 return -1;
694
695 if (timeout > 0 && has_second_elapsed (&saved_time))
696 {
697 timeout--;
698 grub_menu_set_timeout (timeout);
699 menu_print_timeout (timeout);
700 }
701
702 if (timeout == 0)
703 {
704 grub_env_unset ("timeout");
705 *auto_boot = 1;
706 menu_fini ();
707 return default_entry;
708 }
709
710 c = grub_getkey_noblock ();
711
712 /* Negative values are returned on error. */
713 if ((c != GRUB_TERM_NO_KEY) && (c > 0))
714 {
715 if (timeout >= 0)
716 {
717 grub_env_unset ("timeout");
718 grub_env_unset ("fallback");
719 clear_timeout ();
720 }
721
722 switch (c)
723 {
724 case GRUB_TERM_KEY_HOME:
725 case GRUB_TERM_CTRL | 'a':
726 current_entry = 0;
727 menu_set_chosen_entry (current_entry);
728 break;
729
730 case GRUB_TERM_KEY_END:
731 case GRUB_TERM_CTRL | 'e':
732 current_entry = menu->size - 1;
733 menu_set_chosen_entry (current_entry);
734 break;
735
736 case GRUB_TERM_KEY_UP:
737 case GRUB_TERM_CTRL | 'p':
738 case '^':
739 if (current_entry > 0)
740 current_entry--;
741 menu_set_chosen_entry (current_entry);
742 break;
743
744 case GRUB_TERM_CTRL | 'n':
745 case GRUB_TERM_KEY_DOWN:
746 case 'v':
747 if (current_entry < menu->size - 1)
748 current_entry++;
749 menu_set_chosen_entry (current_entry);
750 break;
751
752 case GRUB_TERM_CTRL | 'g':
753 case GRUB_TERM_KEY_PPAGE:
754 if (current_entry < GRUB_MENU_PAGE_SIZE)
755 current_entry = 0;
756 else
757 current_entry -= GRUB_MENU_PAGE_SIZE;
758 menu_set_chosen_entry (current_entry);
759 break;
760
761 case GRUB_TERM_CTRL | 'c':
762 case GRUB_TERM_KEY_NPAGE:
763 if (current_entry + GRUB_MENU_PAGE_SIZE < menu->size)
764 current_entry += GRUB_MENU_PAGE_SIZE;
765 else
766 current_entry = menu->size - 1;
767 menu_set_chosen_entry (current_entry);
768 break;
769
770 case '\n':
771 case '\r':
772 // case GRUB_TERM_KEY_RIGHT:
773 case GRUB_TERM_CTRL | 'f':
774 menu_fini ();
775 *auto_boot = 0;
776 return current_entry;
777
778 case GRUB_TERM_ESC:
779 if (nested)
780 {
781 menu_fini ();
782 return -1;
783 }
784 break;
785
786 case 'c':
787 menu_fini ();
788 grub_cmdline_run (1, 0);
789 goto refresh;
790
791 case 'e':
792 menu_fini ();
793 {
794 grub_menu_entry_t e = grub_menu_get_entry (menu, current_entry);
795 if (e)
796 grub_menu_entry_run (e);
797 }
798 goto refresh;
799
800 case GRUB_TERM_KEY_F2:
801 cmdstr = grub_env_get("VTOY_F2_CMD");
802 if (cmdstr)
803 {
804 menu_fini ();
805 grub_script_execute_sourcecode(cmdstr);
806 goto refresh;
807 }
808 break;
809 case GRUB_TERM_KEY_F3:
810 cmdstr = grub_env_get("VTOY_F3_CMD");
811 if (cmdstr)
812 {
813 menu_fini ();
814 grub_script_execute_sourcecode(cmdstr);
815 goto refresh;
816 }
817 break;
818 case GRUB_TERM_KEY_F4:
819 cmdstr = grub_env_get("VTOY_F4_CMD");
820 if (cmdstr)
821 {
822 menu_fini ();
823 grub_script_execute_sourcecode(cmdstr);
824 goto refresh;
825 }
826 break;
827 case GRUB_TERM_KEY_F5:
828 cmdstr = grub_env_get("VTOY_F5_CMD");
829 if (cmdstr)
830 {
831 menu_fini ();
832 grub_script_execute_sourcecode(cmdstr);
833 goto refresh;
834 }
835 break;
836 case GRUB_TERM_KEY_F6:
837 cmdstr = grub_env_get("VTOY_F6_CMD");
838 if (cmdstr)
839 {
840 menu_fini ();
841 grub_script_execute_sourcecode(cmdstr);
842 goto refresh;
843 }
844 break;
845 case GRUB_TERM_KEY_F7:
846 cmdstr = grub_env_get("VTOY_F7_CMD");
847 if (cmdstr)
848 {
849 menu_fini ();
850 grub_script_execute_sourcecode(cmdstr);
851 goto refresh;
852 }
853 break;
854 case GRUB_TERM_KEY_F1:
855 menu_fini ();
856 g_ventoy_memdisk_mode = 1 - g_ventoy_memdisk_mode;
857 g_ventoy_menu_refresh = 1;
858 goto refresh;
859
860 case (GRUB_TERM_CTRL | 'i'):
861 menu_fini ();
862 g_ventoy_iso_raw = 1 - g_ventoy_iso_raw;
863 g_ventoy_menu_refresh = 1;
864 goto refresh;
865
866 case (GRUB_TERM_CTRL | 'u'):
867 menu_fini ();
868 g_ventoy_iso_uefi_drv = 1 - g_ventoy_iso_uefi_drv;
869 g_ventoy_menu_refresh = 1;
870 goto refresh;
871
872 default:
873 {
874 int entry;
875
876 entry = get_entry_index_by_hotkey (menu, c);
877 if (entry >= 0)
878 {
879 menu_fini ();
880 *auto_boot = 0;
881 return entry;
882 }
883 }
884 break;
885 }
886 }
887 }
888
889 /* Never reach here. */
890 }
891
892 /* Callback invoked immediately before a menu entry is executed. */
893 static void
894 notify_booting (grub_menu_entry_t entry,
895 void *userdata __attribute__((unused)))
896 {
897 grub_printf (" ");
898 grub_printf_ (N_("Booting `%s'"), entry->title);
899 grub_printf ("\n\n");
900 }
901
902 /* Callback invoked when a default menu entry executed because of a timeout
903 has failed and an attempt will be made to execute the next fallback
904 entry, ENTRY. */
905 static void
906 notify_fallback (grub_menu_entry_t entry,
907 void *userdata __attribute__((unused)))
908 {
909 grub_printf ("\n ");
910 grub_printf_ (N_("Falling back to `%s'"), entry->title);
911 grub_printf ("\n\n");
912 grub_millisleep (DEFAULT_ENTRY_ERROR_DELAY_MS);
913 }
914
915 /* Callback invoked when a menu entry has failed and there is no remaining
916 fallback entry to attempt. */
917 static void
918 notify_execution_failure (void *userdata __attribute__((unused)))
919 {
920 if (grub_errno != GRUB_ERR_NONE)
921 {
922 grub_print_error ();
923 grub_errno = GRUB_ERR_NONE;
924 }
925 grub_printf ("\n ");
926 grub_printf_ (N_("Failed to boot both default and fallback entries.\n"));
927 grub_wait_after_message ();
928 }
929
930 /* Callbacks used by the text menu to provide user feedback when menu entries
931 are executed. */
932 static struct grub_menu_execute_callback execution_callback =
933 {
934 .notify_booting = notify_booting,
935 .notify_fallback = notify_fallback,
936 .notify_failure = notify_execution_failure
937 };
938
939 static grub_err_t
940 show_menu (grub_menu_t menu, int nested, int autobooted)
941 {
942 while (1)
943 {
944 int boot_entry;
945 grub_menu_entry_t e;
946 int auto_boot;
947
948 boot_entry = run_menu (menu, nested, &auto_boot);
949 if (boot_entry < 0)
950 break;
951
952 g_ventoy_last_entry = boot_entry;
953
954 e = grub_menu_get_entry (menu, boot_entry);
955 if (! e)
956 continue; /* Menu is empty. */
957
958 grub_cls ();
959
960 if (auto_boot)
961 grub_menu_execute_with_fallback (menu, e, autobooted,
962 &execution_callback, 0);
963 else
964 grub_menu_execute_entry (e, 0);
965 if (autobooted)
966 break;
967 }
968
969 return GRUB_ERR_NONE;
970 }
971
972 grub_err_t
973 grub_show_menu (grub_menu_t menu, int nested, int autoboot)
974 {
975 grub_err_t err1, err2;
976
977 while (1)
978 {
979 err1 = show_menu (menu, nested, autoboot);
980 autoboot = 0;
981 grub_print_error ();
982
983 if (grub_normal_exit_level)
984 break;
985
986 err2 = grub_auth_check_authentication (NULL);
987 if (err2)
988 {
989 grub_print_error ();
990 grub_errno = GRUB_ERR_NONE;
991 continue;
992 }
993
994 break;
995 }
996
997 return err1;
998 }