core: use GRUB_TERM_ definitions when handling term characters
[grub.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 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       if (c != GRUB_TERM_NO_KEY)
702         {
703           if (timeout >= 0)
704             {
705               grub_env_unset ("timeout");
706               grub_env_unset ("fallback");
707               clear_timeout ();
708             }
709
710           switch (c)
711             {
712             case GRUB_TERM_KEY_HOME:
713             case GRUB_TERM_CTRL | 'a':
714               current_entry = 0;
715               menu_set_chosen_entry (current_entry);
716               break;
717
718             case GRUB_TERM_KEY_END:
719             case GRUB_TERM_CTRL | 'e':
720               current_entry = menu->size - 1;
721               menu_set_chosen_entry (current_entry);
722               break;
723
724             case GRUB_TERM_KEY_UP:
725             case GRUB_TERM_CTRL | 'p':
726             case '^':
727               if (current_entry > 0)
728                 current_entry--;
729               menu_set_chosen_entry (current_entry);
730               break;
731
732             case GRUB_TERM_CTRL | 'n':
733             case GRUB_TERM_KEY_DOWN:
734             case 'v':
735               if (current_entry < menu->size - 1)
736                 current_entry++;
737               menu_set_chosen_entry (current_entry);
738               break;
739
740             case GRUB_TERM_CTRL | 'g':
741             case GRUB_TERM_KEY_PPAGE:
742               if (current_entry < GRUB_MENU_PAGE_SIZE)
743                 current_entry = 0;
744               else
745                 current_entry -= GRUB_MENU_PAGE_SIZE;
746               menu_set_chosen_entry (current_entry);
747               break;
748
749             case GRUB_TERM_CTRL | 'c':
750             case GRUB_TERM_KEY_NPAGE:
751               if (current_entry + GRUB_MENU_PAGE_SIZE < menu->size)
752                 current_entry += GRUB_MENU_PAGE_SIZE;
753               else
754                 current_entry = menu->size - 1;
755               menu_set_chosen_entry (current_entry);
756               break;
757
758             case '\n':
759             case '\r':
760             case GRUB_TERM_KEY_RIGHT:
761             case GRUB_TERM_CTRL | 'f':
762               menu_fini ();
763               *auto_boot = 0;
764               return current_entry;
765
766             case GRUB_TERM_ESC:
767               if (nested)
768                 {
769                   menu_fini ();
770                   return -1;
771                 }
772               break;
773
774             case 'c':
775               menu_fini ();
776               grub_cmdline_run (1, 0);
777               goto refresh;
778
779             case 'e':
780               menu_fini ();
781                 {
782                   grub_menu_entry_t e = grub_menu_get_entry (menu, current_entry);
783                   if (e)
784                     grub_menu_entry_run (e);
785                 }
786               goto refresh;
787
788             default:
789               {
790                 int entry;
791
792                 entry = get_entry_index_by_hotkey (menu, c);
793                 if (entry >= 0)
794                   {
795                     menu_fini ();
796                     *auto_boot = 0;
797                     return entry;
798                   }
799               }
800               break;
801             }
802         }
803     }
804
805   /* Never reach here.  */
806 }
807
808 /* Callback invoked immediately before a menu entry is executed.  */
809 static void
810 notify_booting (grub_menu_entry_t entry,
811                 void *userdata __attribute__((unused)))
812 {
813   grub_printf ("  ");
814   grub_printf_ (N_("Booting `%s'"), entry->title);
815   grub_printf ("\n\n");
816 }
817
818 /* Callback invoked when a default menu entry executed because of a timeout
819    has failed and an attempt will be made to execute the next fallback
820    entry, ENTRY.  */
821 static void
822 notify_fallback (grub_menu_entry_t entry,
823                  void *userdata __attribute__((unused)))
824 {
825   grub_printf ("\n   ");
826   grub_printf_ (N_("Falling back to `%s'"), entry->title);
827   grub_printf ("\n\n");
828   grub_millisleep (DEFAULT_ENTRY_ERROR_DELAY_MS);
829 }
830
831 /* Callback invoked when a menu entry has failed and there is no remaining
832    fallback entry to attempt.  */
833 static void
834 notify_execution_failure (void *userdata __attribute__((unused)))
835 {
836   if (grub_errno != GRUB_ERR_NONE)
837     {
838       grub_print_error ();
839       grub_errno = GRUB_ERR_NONE;
840     }
841   grub_printf ("\n  ");
842   grub_printf_ (N_("Failed to boot both default and fallback entries.\n"));
843   grub_wait_after_message ();
844 }
845
846 /* Callbacks used by the text menu to provide user feedback when menu entries
847    are executed.  */
848 static struct grub_menu_execute_callback execution_callback =
849 {
850   .notify_booting = notify_booting,
851   .notify_fallback = notify_fallback,
852   .notify_failure = notify_execution_failure
853 };
854
855 static grub_err_t
856 show_menu (grub_menu_t menu, int nested, int autobooted)
857 {
858   while (1)
859     {
860       int boot_entry;
861       grub_menu_entry_t e;
862       int auto_boot;
863
864       boot_entry = run_menu (menu, nested, &auto_boot);
865       if (boot_entry < 0)
866         break;
867
868       e = grub_menu_get_entry (menu, boot_entry);
869       if (! e)
870         continue; /* Menu is empty.  */
871
872       grub_cls ();
873
874       if (auto_boot)
875         grub_menu_execute_with_fallback (menu, e, autobooted,
876                                          &execution_callback, 0);
877       else
878         grub_menu_execute_entry (e, 0);
879       if (autobooted)
880         break;
881     }
882
883   return GRUB_ERR_NONE;
884 }
885
886 grub_err_t
887 grub_show_menu (grub_menu_t menu, int nested, int autoboot)
888 {
889   grub_err_t err1, err2;
890
891   while (1)
892     {
893       err1 = show_menu (menu, nested, autoboot);
894       autoboot = 0;
895       grub_print_error ();
896
897       if (grub_normal_exit_level)
898         break;
899
900       err2 = grub_auth_check_authentication (NULL);
901       if (err2)
902         {
903           grub_print_error ();
904           grub_errno = GRUB_ERR_NONE;
905           continue;
906         }
907
908       break;
909     }
910
911   return err1;
912 }