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