]> git.proxmox.com Git - grub2.git/blob - grub-core/normal/menu.c
Add configure option to reduce visual clutter at boot time
[grub2.git] / 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 mods = 0;
619 grub_term_input_t term;
620 int key;
621
622 if (grub_term_poll_usb)
623 grub_term_poll_usb (0);
624
625 FOR_ACTIVE_TERM_INPUTS(term)
626 {
627 if (term->getkeystatus)
628 mods |= term->getkeystatus (term);
629 }
630
631 if (mods >= 0 &&
632 (mods & (GRUB_TERM_STATUS_LSHIFT
633 | GRUB_TERM_STATUS_RSHIFT)) != 0)
634 {
635 timeout = -1;
636 break;
637 }
638
639 key = grub_getkey_noblock ();
640 if (key != GRUB_TERM_NO_KEY)
641 {
642 entry = get_entry_index_by_hotkey (menu, key);
643 if (entry >= 0)
644 break;
645 }
646 if (key == GRUB_TERM_ESC)
647 {
648 timeout = -1;
649 break;
650 }
651
652 if (timeout > 0 && has_second_elapsed (&saved_time))
653 {
654 timeout--;
655 if (timeout_style == TIMEOUT_STYLE_COUNTDOWN)
656 print_countdown (pos, timeout);
657 }
658
659 if (timeout == 0)
660 /* We will fall through to auto-booting the default entry. */
661 break;
662 }
663
664 grub_env_unset ("timeout");
665 grub_env_unset ("timeout_style");
666 if (entry >= 0)
667 {
668 *auto_boot = 0;
669 return entry;
670 }
671 }
672
673 /* If timeout is 0, drawing is pointless (and ugly). */
674 if (timeout == 0)
675 {
676 *auto_boot = 1;
677 return default_entry;
678 }
679
680 current_entry = default_entry;
681
682 refresh:
683 menu_init (current_entry, menu, nested);
684
685 /* Initialize the time. */
686 saved_time = grub_get_time_ms ();
687
688 timeout = grub_menu_get_timeout ();
689
690 if (timeout > 0)
691 menu_print_timeout (timeout);
692 else
693 clear_timeout ();
694
695 while (1)
696 {
697 int c;
698 timeout = grub_menu_get_timeout ();
699
700 if (grub_normal_exit_level)
701 return -1;
702
703 if (timeout > 0 && has_second_elapsed (&saved_time))
704 {
705 timeout--;
706 grub_menu_set_timeout (timeout);
707 menu_print_timeout (timeout);
708 }
709
710 if (timeout == 0)
711 {
712 grub_env_unset ("timeout");
713 *auto_boot = 1;
714 menu_fini ();
715 return default_entry;
716 }
717
718 c = grub_getkey_noblock ();
719
720 if (c != GRUB_TERM_NO_KEY)
721 {
722 if (timeout >= 0)
723 {
724 grub_env_unset ("timeout");
725 grub_env_unset ("fallback");
726 clear_timeout ();
727 }
728
729 switch (c)
730 {
731 case GRUB_TERM_KEY_HOME:
732 case GRUB_TERM_CTRL | 'a':
733 current_entry = 0;
734 menu_set_chosen_entry (current_entry);
735 break;
736
737 case GRUB_TERM_KEY_END:
738 case GRUB_TERM_CTRL | 'e':
739 current_entry = menu->size - 1;
740 menu_set_chosen_entry (current_entry);
741 break;
742
743 case GRUB_TERM_KEY_UP:
744 case GRUB_TERM_CTRL | 'p':
745 case '^':
746 if (current_entry > 0)
747 current_entry--;
748 menu_set_chosen_entry (current_entry);
749 break;
750
751 case GRUB_TERM_CTRL | 'n':
752 case GRUB_TERM_KEY_DOWN:
753 case 'v':
754 if (current_entry < menu->size - 1)
755 current_entry++;
756 menu_set_chosen_entry (current_entry);
757 break;
758
759 case GRUB_TERM_CTRL | 'g':
760 case GRUB_TERM_KEY_PPAGE:
761 if (current_entry < GRUB_MENU_PAGE_SIZE)
762 current_entry = 0;
763 else
764 current_entry -= GRUB_MENU_PAGE_SIZE;
765 menu_set_chosen_entry (current_entry);
766 break;
767
768 case GRUB_TERM_CTRL | 'c':
769 case GRUB_TERM_KEY_NPAGE:
770 if (current_entry + GRUB_MENU_PAGE_SIZE < menu->size)
771 current_entry += GRUB_MENU_PAGE_SIZE;
772 else
773 current_entry = menu->size - 1;
774 menu_set_chosen_entry (current_entry);
775 break;
776
777 case '\n':
778 case '\r':
779 case GRUB_TERM_KEY_RIGHT:
780 case GRUB_TERM_CTRL | 'f':
781 menu_fini ();
782 *auto_boot = 0;
783 return current_entry;
784
785 case '\e':
786 if (nested)
787 {
788 menu_fini ();
789 return -1;
790 }
791 break;
792
793 case 'c':
794 menu_fini ();
795 grub_cmdline_run (1);
796 goto refresh;
797
798 case 'e':
799 menu_fini ();
800 {
801 grub_menu_entry_t e = grub_menu_get_entry (menu, current_entry);
802 if (e)
803 grub_menu_entry_run (e);
804 }
805 goto refresh;
806
807 default:
808 {
809 int entry;
810
811 entry = get_entry_index_by_hotkey (menu, c);
812 if (entry >= 0)
813 {
814 menu_fini ();
815 *auto_boot = 0;
816 return entry;
817 }
818 }
819 break;
820 }
821 }
822 }
823
824 /* Never reach here. */
825 }
826
827 /* Callback invoked immediately before a menu entry is executed. */
828 static void
829 notify_booting (grub_menu_entry_t entry
830 #ifdef QUIET_BOOT
831 __attribute__((unused))
832 #endif
833 ,
834 void *userdata __attribute__((unused)))
835 {
836 #ifndef QUIET_BOOT
837 grub_printf (" ");
838 grub_printf_ (N_("Booting `%s'"), entry->title);
839 grub_printf ("\n\n");
840 #endif
841 }
842
843 /* Callback invoked when a default menu entry executed because of a timeout
844 has failed and an attempt will be made to execute the next fallback
845 entry, ENTRY. */
846 static void
847 notify_fallback (grub_menu_entry_t entry,
848 void *userdata __attribute__((unused)))
849 {
850 grub_printf ("\n ");
851 grub_printf_ (N_("Falling back to `%s'"), entry->title);
852 grub_printf ("\n\n");
853 grub_millisleep (DEFAULT_ENTRY_ERROR_DELAY_MS);
854 }
855
856 /* Callback invoked when a menu entry has failed and there is no remaining
857 fallback entry to attempt. */
858 static void
859 notify_execution_failure (void *userdata __attribute__((unused)))
860 {
861 if (grub_errno != GRUB_ERR_NONE)
862 {
863 grub_print_error ();
864 grub_errno = GRUB_ERR_NONE;
865 }
866 grub_printf ("\n ");
867 grub_printf_ (N_("Failed to boot both default and fallback entries.\n"));
868 grub_wait_after_message ();
869 }
870
871 /* Callbacks used by the text menu to provide user feedback when menu entries
872 are executed. */
873 static struct grub_menu_execute_callback execution_callback =
874 {
875 .notify_booting = notify_booting,
876 .notify_fallback = notify_fallback,
877 .notify_failure = notify_execution_failure
878 };
879
880 static grub_err_t
881 show_menu (grub_menu_t menu, int nested, int autobooted)
882 {
883 while (1)
884 {
885 int boot_entry;
886 grub_menu_entry_t e;
887 int auto_boot;
888 #ifdef QUIET_BOOT
889 int initial_timeout = grub_menu_get_timeout ();
890 #endif
891
892 boot_entry = run_menu (menu, nested, &auto_boot);
893 if (boot_entry < 0)
894 break;
895
896 e = grub_menu_get_entry (menu, boot_entry);
897 if (! e)
898 continue; /* Menu is empty. */
899
900 #ifdef QUIET_BOOT
901 /* Only clear the screen if we drew the menu in the first place. */
902 if (initial_timeout != 0)
903 #endif
904 grub_cls ();
905
906 if (auto_boot)
907 grub_menu_execute_with_fallback (menu, e, autobooted,
908 &execution_callback, 0);
909 else
910 grub_menu_execute_entry (e, 0);
911 if (autobooted)
912 break;
913 }
914
915 return GRUB_ERR_NONE;
916 }
917
918 grub_err_t
919 grub_show_menu (grub_menu_t menu, int nested, int autoboot)
920 {
921 grub_err_t err1, err2;
922
923 while (1)
924 {
925 err1 = show_menu (menu, nested, autoboot);
926 autoboot = 0;
927 grub_print_error ();
928
929 if (grub_normal_exit_level)
930 break;
931
932 err2 = grub_auth_check_authentication (NULL);
933 if (err2)
934 {
935 grub_print_error ();
936 grub_errno = GRUB_ERR_NONE;
937 continue;
938 }
939
940 break;
941 }
942
943 return err1;
944 }