~hamo/ubuntu/precise/grub2/grub2.hi_res

« back to all changes in this revision

Viewing changes to grub-core/normal/menu.c

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson, Colin Watson, Evan Broder, Mario Limonciello
  • Date: 2010-11-24 13:59:55 UTC
  • mfrom: (1.17.6 upstream) (17.6.15 experimental)
  • Revision ID: james.westby@ubuntu.com-20101124135955-r6ii5sepayr7jt53
Tags: 1.99~20101124-1ubuntu1
[ Colin Watson ]
* Resynchronise with Debian experimental.  Remaining changes:
  - Adjust for default Ubuntu boot options ("quiet splash").
  - Default to hiding the menu; holding down Shift at boot will show it.
  - Set a monochromatic theme for Ubuntu.
  - Apply Ubuntu GRUB Legacy changes to legacy update-grub script: title,
    recovery mode, quiet option, tweak how memtest86+ is displayed, and
    use UUIDs where appropriate.
  - Fix backslash-escaping in merge_debconf_into_conf.
  - Remove "GNU/Linux" from default distributor string.
  - Add crashkernel= options if kdump and makedumpfile are available.
  - If other operating systems are installed, then automatically unhide
    the menu.  Otherwise, if GRUB_HIDDEN_TIMEOUT is 0, then use keystatus
    if available to check whether Shift is pressed.  If it is, show the
    menu, otherwise boot immediately.  If keystatus is not available, then
    fall back to a short delay interruptible with Escape.
  - Allow Shift to interrupt 'sleep --interruptible'.
  - Don't display introductory message about line editing unless we're
    actually offering a shell prompt.  Don't clear the screen just before
    booting if we never drew the menu in the first place.
  - Remove some verbose messages printed before reading the configuration
    file.
  - Suppress progress messages as the kernel and initrd load for
    non-recovery kernel menu entries.
  - Change prepare_grub_to_access_device to handle filesystems
    loop-mounted on file images.
  - Ignore devices loop-mounted from files in 10_linux.
  - Show the boot menu if the previous boot failed, that is if it failed
    to get to the end of one of the normal runlevels.
  - Don't generate /boot/grub/device.map during grub-install or
    grub-mkconfig by default.
  - Adjust upgrade version checks for Ubuntu.
  - Don't display "GRUB loading" unless Shift is held down.
  - Adjust versions of grub-doc and grub-legacy-doc conflicts to tolerate
    our backport of the grub-doc split.
  - Fix LVM/RAID probing in the absence of /boot/grub/device.map.
  - Look for .mo files in /usr/share/locale-langpack as well, in
    preference.
  - Make sure GRUB_TIMEOUT isn't quoted unnecessarily.
  - Probe all devices in 'grub-probe --target=drive' if
    /boot/grub/device.map is missing.
  - Build-depend on qemu-kvm rather than qemu-system for grub-pc tests.
  - Use qemu rather than qemu-system-i386.
  - Program vesafb on BIOS systems rather than efifb.
  - Add a grub-rescue-efi-amd64 package containing a rescue CD-ROM image
    for EFI-AMD64.
  - On Wubi, don't ask for an install device, but just update wubildr
    using the diverted grub-install.
  - When embedding the core image in a post-MBR gap, check for and avoid
    sectors matching any of a list of known signatures.
  - Disable video_bochs and video_cirrus on PC BIOS systems, as probing
    PCI space seems to break on some systems.
* Downgrade "ACPI shutdown failed" error to a debug message, since it can
  cause spurious test failures.

[ Evan Broder ]
* Enable lua from grub-extras.
* Incorporate the bitop library into lua.
* Add enum_pci function to grub module in lua.
* Switch back to gfxpayload=keep by default, unless the video hardware
  is known to not support it.

[ Mario Limonciello ]
* Built part_msdos and vfat into bootx64.efi (LP: #677758)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
34
/* Time to delay after displaying an error message about a default/fallback
 
35
   entry failing to boot.  */
 
36
#define DEFAULT_ENTRY_ERROR_DELAY_MS  2500
 
37
 
 
38
grub_err_t (*grub_gfxmenu_try_hook) (int entry, grub_menu_t menu,
 
39
                                     int nested) = NULL;
 
40
 
 
41
/* Wait until the user pushes any key so that the user
 
42
   can see what happened.  */
 
43
void
 
44
grub_wait_after_message (void)
 
45
{
 
46
  grub_uint64_t endtime;
 
47
  grub_xputs ("\n");
 
48
  grub_printf_ (N_("Press any key to continue..."));
 
49
  grub_refresh ();
 
50
 
 
51
  endtime = grub_get_time_ms () + 10000;
 
52
 
 
53
  while (grub_get_time_ms () < endtime)
 
54
    if (grub_checkkey () >= 0)
 
55
      {
 
56
        grub_getkey ();
 
57
        break;
 
58
      }
 
59
 
 
60
  grub_xputs ("\n");
 
61
}
 
62
 
 
63
/* Get a menu entry by its index in the entry list.  */
 
64
grub_menu_entry_t
 
65
grub_menu_get_entry (grub_menu_t menu, int no)
 
66
{
 
67
  grub_menu_entry_t e;
 
68
 
 
69
  for (e = menu->entry_list; e && no > 0; e = e->next, no--)
 
70
    ;
 
71
 
 
72
  return e;
 
73
}
 
74
 
 
75
/* Return the current timeout. If the variable "timeout" is not set or
 
76
   invalid, return -1.  */
 
77
int
 
78
grub_menu_get_timeout (void)
 
79
{
 
80
  char *val;
 
81
  int timeout;
 
82
 
 
83
  val = grub_env_get ("timeout");
 
84
  if (! val)
 
85
    return -1;
 
86
 
 
87
  grub_error_push ();
 
88
 
 
89
  timeout = (int) grub_strtoul (val, 0, 0);
 
90
 
 
91
  /* If the value is invalid, unset the variable.  */
 
92
  if (grub_errno != GRUB_ERR_NONE)
 
93
    {
 
94
      grub_env_unset ("timeout");
 
95
      grub_errno = GRUB_ERR_NONE;
 
96
      timeout = -1;
 
97
    }
 
98
 
 
99
  grub_error_pop ();
 
100
 
 
101
  return timeout;
 
102
}
 
103
 
 
104
/* Set current timeout in the variable "timeout".  */
 
105
void
 
106
grub_menu_set_timeout (int timeout)
 
107
{
 
108
  /* Ignore TIMEOUT if it is zero, because it will be unset really soon.  */
 
109
  if (timeout > 0)
 
110
    {
 
111
      char buf[16];
 
112
 
 
113
      grub_snprintf (buf, sizeof (buf), "%d", timeout);
 
114
      grub_env_set ("timeout", buf);
 
115
    }
 
116
}
 
117
 
 
118
/* Get the first entry number from the value of the environment variable NAME,
 
119
   which is a space-separated list of non-negative integers.  The entry number
 
120
   which is returned is stripped from the value of NAME.  If no entry number
 
121
   can be found, -1 is returned.  */
 
122
static int
 
123
get_and_remove_first_entry_number (const char *name)
 
124
{
 
125
  char *val;
 
126
  char *tail;
 
127
  int entry;
 
128
 
 
129
  val = grub_env_get (name);
 
130
  if (! val)
 
131
    return -1;
 
132
 
 
133
  grub_error_push ();
 
134
 
 
135
  entry = (int) grub_strtoul (val, &tail, 0);
 
136
 
 
137
  if (grub_errno == GRUB_ERR_NONE)
 
138
    {
 
139
      /* Skip whitespace to find the next digit.  */
 
140
      while (*tail && grub_isspace (*tail))
 
141
        tail++;
 
142
      grub_env_set (name, tail);
 
143
    }
 
144
  else
 
145
    {
 
146
      grub_env_unset (name);
 
147
      grub_errno = GRUB_ERR_NONE;
 
148
      entry = -1;
 
149
    }
 
150
 
 
151
  grub_error_pop ();
 
152
 
 
153
  return entry;
 
154
}
 
155
 
 
156
/* Run a menu entry.  */
 
157
void
 
158
grub_menu_execute_entry(grub_menu_entry_t entry)
 
159
{
 
160
  grub_err_t err = GRUB_ERR_NONE;
 
161
  int errs_before;
 
162
  grub_menu_t menu;
 
163
 
 
164
  if (entry->restricted)
 
165
    err = grub_auth_check_authentication (entry->users);
 
166
 
 
167
  if (err)
 
168
    {
 
169
      grub_print_error ();
 
170
      grub_errno = GRUB_ERR_NONE;
 
171
      return;
 
172
    }
 
173
 
 
174
  errs_before = grub_err_printed_errors;
 
175
 
 
176
  if (entry->submenu)
 
177
    {
 
178
      grub_env_context_open ();
 
179
      menu = grub_zalloc (sizeof (*menu));
 
180
      if (! menu)
 
181
        return;
 
182
      grub_env_set_menu (menu);
 
183
    }
 
184
 
 
185
  grub_env_set ("chosen", entry->title);
 
186
  grub_script_execute_sourcecode (entry->sourcecode, entry->argc, entry->args);
 
187
 
 
188
  if (errs_before != grub_err_printed_errors)
 
189
    grub_wait_after_message ();
 
190
 
 
191
  if (grub_errno == GRUB_ERR_NONE && grub_loader_is_loaded ())
 
192
    /* Implicit execution of boot, only if something is loaded.  */
 
193
    grub_command_execute ("boot", 0, 0);
 
194
 
 
195
  if (entry->submenu)
 
196
    {
 
197
      if (menu && menu->size)
 
198
        {
 
199
          grub_show_menu (menu, 1);
 
200
          grub_normal_free_menu (menu);
 
201
        }
 
202
      grub_env_context_close ();
 
203
    }
 
204
}
 
205
 
 
206
/* Execute ENTRY from the menu MENU, falling back to entries specified
 
207
   in the environment variable "fallback" if it fails.  CALLBACK is a
 
208
   pointer to a struct of function pointers which are used to allow the
 
209
   caller provide feedback to the user.  */
 
210
void
 
211
grub_menu_execute_with_fallback (grub_menu_t menu,
 
212
                                 grub_menu_entry_t entry,
 
213
                                 grub_menu_execute_callback_t callback,
 
214
                                 void *callback_data)
 
215
{
 
216
  int fallback_entry;
 
217
 
 
218
  callback->notify_booting (entry, callback_data);
 
219
 
 
220
  grub_menu_execute_entry (entry);
 
221
 
 
222
  /* Deal with fallback entries.  */
 
223
  while ((fallback_entry = get_and_remove_first_entry_number ("fallback"))
 
224
         >= 0)
 
225
    {
 
226
      grub_print_error ();
 
227
      grub_errno = GRUB_ERR_NONE;
 
228
 
 
229
      entry = grub_menu_get_entry (menu, fallback_entry);
 
230
      callback->notify_fallback (entry, callback_data);
 
231
      grub_menu_execute_entry (entry);
 
232
      /* If the function call to execute the entry returns at all, then this is
 
233
         taken to indicate a boot failure.  For menu entries that do something
 
234
         other than actually boot an operating system, this could assume
 
235
         incorrectly that something failed.  */
 
236
    }
 
237
 
 
238
  callback->notify_failure (callback_data);
 
239
}
 
240
 
 
241
static struct grub_menu_viewer *viewers;
 
242
 
 
243
static void
 
244
menu_set_chosen_entry (int entry)
 
245
{
 
246
  struct grub_menu_viewer *cur;
 
247
  for (cur = viewers; cur; cur = cur->next)
 
248
    cur->set_chosen_entry (entry, cur->data);
 
249
}
 
250
 
 
251
static void
 
252
menu_print_timeout (int timeout)
 
253
{
 
254
  struct grub_menu_viewer *cur;
 
255
  for (cur = viewers; cur; cur = cur->next)
 
256
    cur->print_timeout (timeout, cur->data);
 
257
}
 
258
 
 
259
static void
 
260
menu_fini (void)
 
261
{
 
262
  struct grub_menu_viewer *cur, *next;
 
263
  for (cur = viewers; cur; cur = next)
 
264
    {
 
265
      next = cur->next;
 
266
      cur->fini (cur->data);
 
267
      grub_free (cur);
 
268
    }
 
269
  viewers = NULL;
 
270
}
 
271
 
 
272
static void
 
273
menu_init (int entry, grub_menu_t menu, int nested)
 
274
{
 
275
  struct grub_term_output *term;
 
276
 
 
277
  FOR_ACTIVE_TERM_OUTPUTS(term)
 
278
  {
 
279
    grub_err_t err;
 
280
 
 
281
    if (grub_gfxmenu_try_hook && grub_strcmp (term->name, "gfxterm") == 0)
 
282
      {
 
283
        err = grub_gfxmenu_try_hook (entry, menu, nested);
 
284
        if(!err)
 
285
          continue;
 
286
        grub_errno = GRUB_ERR_NONE;
 
287
      }
 
288
 
 
289
    err = grub_menu_try_text (term, entry, menu, nested);
 
290
    if(!err)
 
291
      continue;
 
292
    grub_print_error ();
 
293
    grub_errno = GRUB_ERR_NONE;
 
294
  }
 
295
}
 
296
 
 
297
static void
 
298
clear_timeout (void)
 
299
{
 
300
  struct grub_menu_viewer *cur;
 
301
  for (cur = viewers; cur; cur = cur->next)
 
302
    cur->clear_timeout (cur->data);
 
303
}
 
304
 
 
305
void
 
306
grub_menu_register_viewer (struct grub_menu_viewer *viewer)
 
307
{
 
308
  viewer->next = viewers;
 
309
  viewers = viewer;
 
310
}
 
311
 
 
312
/* Get the entry number from the variable NAME.  */
 
313
static int
 
314
get_entry_number (grub_menu_t menu, const char *name)
 
315
{
 
316
  char *val;
 
317
  int entry;
 
318
 
 
319
  val = grub_env_get (name);
 
320
  if (! val)
 
321
    return -1;
 
322
 
 
323
  grub_error_push ();
 
324
 
 
325
  entry = (int) grub_strtoul (val, 0, 0);
 
326
 
 
327
  if (grub_errno == GRUB_ERR_BAD_NUMBER)
 
328
    {
 
329
      /* See if the variable matches the title of a menu entry.  */
 
330
      grub_menu_entry_t e = menu->entry_list;
 
331
      int i;
 
332
 
 
333
      grub_errno = GRUB_ERR_NONE;
 
334
 
 
335
      for (i = 0; e; i++)
 
336
        {
 
337
          if (grub_strcmp (e->title, val) == 0)
 
338
            {
 
339
              entry = i;
 
340
              break;
 
341
            }
 
342
          e = e->next;
 
343
        }
 
344
 
 
345
      if (! e)
 
346
        entry = -1;
 
347
    }
 
348
 
 
349
  if (grub_errno != GRUB_ERR_NONE)
 
350
    {
 
351
      grub_errno = GRUB_ERR_NONE;
 
352
      entry = -1;
 
353
    }
 
354
 
 
355
  grub_error_pop ();
 
356
 
 
357
  return entry;
 
358
}
 
359
 
 
360
#define GRUB_MENU_PAGE_SIZE 10
 
361
 
 
362
/* Show the menu and handle menu entry selection.  Returns the menu entry
 
363
   index that should be executed or -1 if no entry should be executed (e.g.,
 
364
   Esc pressed to exit a sub-menu or switching menu viewers).
 
365
   If the return value is not -1, then *AUTO_BOOT is nonzero iff the menu
 
366
   entry to be executed is a result of an automatic default selection because
 
367
   of the timeout.  */
 
368
static int
 
369
run_menu (grub_menu_t menu, int nested, int *auto_boot)
 
370
{
 
371
  grub_uint64_t saved_time;
 
372
  int default_entry, current_entry;
 
373
  int timeout;
 
374
 
 
375
  default_entry = get_entry_number (menu, "default");
 
376
 
 
377
  /* If DEFAULT_ENTRY is not within the menu entries, fall back to
 
378
     the first entry.  */
 
379
  if (default_entry < 0 || default_entry >= menu->size)
 
380
    default_entry = 0;
 
381
 
 
382
  /* If timeout is 0, drawing is pointless (and ugly).  */
 
383
  if (grub_menu_get_timeout () == 0)
 
384
    {
 
385
      *auto_boot = 1;
 
386
      return default_entry;
 
387
    }
 
388
 
 
389
  current_entry = default_entry;
 
390
 
 
391
  /* Initialize the time.  */
 
392
  saved_time = grub_get_time_ms ();
 
393
 
 
394
 refresh:
 
395
  menu_init (current_entry, menu, nested);
 
396
 
 
397
  timeout = grub_menu_get_timeout ();
 
398
 
 
399
  if (timeout > 0)
 
400
    menu_print_timeout (timeout);
 
401
  else
 
402
    clear_timeout ();
 
403
 
 
404
  while (1)
 
405
    {
 
406
      int c;
 
407
      timeout = grub_menu_get_timeout ();
 
408
 
 
409
      if (grub_normal_exit_level)
 
410
        return -1;
 
411
 
 
412
      if (timeout > 0)
 
413
        {
 
414
          grub_uint64_t current_time;
 
415
 
 
416
          current_time = grub_get_time_ms ();
 
417
          if (current_time - saved_time >= 1000)
 
418
            {
 
419
              timeout--;
 
420
              grub_menu_set_timeout (timeout);
 
421
              saved_time = current_time;
 
422
              menu_print_timeout (timeout);
 
423
            }
 
424
        }
 
425
 
 
426
      if (timeout == 0)
 
427
        {
 
428
          grub_env_unset ("timeout");
 
429
          *auto_boot = 1;
 
430
          menu_fini ();
 
431
          return default_entry;
 
432
        }
 
433
 
 
434
      if (grub_checkkey () >= 0 || timeout < 0)
 
435
        {
 
436
          c = grub_getkey ();
 
437
 
 
438
          if (timeout >= 0)
 
439
            {
 
440
              grub_env_unset ("timeout");
 
441
              grub_env_unset ("fallback");
 
442
              clear_timeout ();
 
443
            }
 
444
 
 
445
          switch (c)
 
446
            {
 
447
            case GRUB_TERM_KEY_HOME:
 
448
            case GRUB_TERM_CTRL | 'a':
 
449
              current_entry = 0;
 
450
              menu_set_chosen_entry (current_entry);
 
451
              break;
 
452
 
 
453
            case GRUB_TERM_KEY_END:
 
454
            case GRUB_TERM_CTRL | 'e':
 
455
              current_entry = menu->size - 1;
 
456
              menu_set_chosen_entry (current_entry);
 
457
              break;
 
458
 
 
459
            case GRUB_TERM_KEY_UP:
 
460
            case GRUB_TERM_CTRL | 'p':
 
461
            case '^':
 
462
              if (current_entry > 0)
 
463
                current_entry--;
 
464
              menu_set_chosen_entry (current_entry);
 
465
              break;
 
466
 
 
467
            case GRUB_TERM_CTRL | 'n':
 
468
            case GRUB_TERM_KEY_DOWN:
 
469
            case 'v':
 
470
              if (current_entry < menu->size - 1)
 
471
                current_entry++;
 
472
              menu_set_chosen_entry (current_entry);
 
473
              break;
 
474
 
 
475
            case GRUB_TERM_CTRL | 'g':
 
476
            case GRUB_TERM_KEY_PPAGE:
 
477
              if (current_entry < GRUB_MENU_PAGE_SIZE)
 
478
                current_entry = 0;
 
479
              else
 
480
                current_entry -= GRUB_MENU_PAGE_SIZE;
 
481
              menu_set_chosen_entry (current_entry);
 
482
              break;
 
483
 
 
484
            case GRUB_TERM_CTRL | 'c':
 
485
            case GRUB_TERM_KEY_NPAGE:
 
486
              if (current_entry + GRUB_MENU_PAGE_SIZE < menu->size)
 
487
                current_entry += GRUB_MENU_PAGE_SIZE;
 
488
              else
 
489
                current_entry = menu->size - 1;
 
490
              menu_set_chosen_entry (current_entry);
 
491
              break;
 
492
 
 
493
            case '\n':
 
494
            case '\r':
 
495
            case GRUB_TERM_KEY_RIGHT:
 
496
            case GRUB_TERM_CTRL | 'f':
 
497
              menu_fini ();
 
498
              *auto_boot = 0;
 
499
              return current_entry;
 
500
 
 
501
            case '\e':
 
502
              if (nested)
 
503
                {
 
504
                  menu_fini ();
 
505
                  return -1;
 
506
                }
 
507
              break;
 
508
 
 
509
            case 'c':
 
510
              menu_fini ();
 
511
              grub_cmdline_run (1);
 
512
              goto refresh;
 
513
 
 
514
            case 'e':
 
515
              menu_fini ();
 
516
                {
 
517
                  grub_menu_entry_t e = grub_menu_get_entry (menu, current_entry);
 
518
                  if (e)
 
519
                    grub_menu_entry_run (e);
 
520
                }
 
521
              goto refresh;
 
522
 
 
523
            default:
 
524
              {
 
525
                grub_menu_entry_t entry;
 
526
                int i;
 
527
                for (i = 0, entry = menu->entry_list; i < menu->size;
 
528
                     i++, entry = entry->next)
 
529
                  if (entry->hotkey == c)
 
530
                    {
 
531
                      menu_fini ();
 
532
                      *auto_boot = 0;
 
533
                      return i;
 
534
                    }
 
535
              }
 
536
              break;
 
537
            }
 
538
        }
 
539
    }
 
540
 
 
541
  /* Never reach here.  */
 
542
  return -1;
 
543
}
 
544
 
 
545
/* Callback invoked immediately before a menu entry is executed.  */
 
546
static void
 
547
notify_booting (grub_menu_entry_t entry,
 
548
                void *userdata __attribute__((unused)))
 
549
{
 
550
  grub_printf ("  ");
 
551
  grub_printf_ (N_("Booting \'%s\'"), entry->title);
 
552
  grub_printf ("\n\n");
 
553
}
 
554
 
 
555
/* Callback invoked when a default menu entry executed because of a timeout
 
556
   has failed and an attempt will be made to execute the next fallback
 
557
   entry, ENTRY.  */
 
558
static void
 
559
notify_fallback (grub_menu_entry_t entry,
 
560
                 void *userdata __attribute__((unused)))
 
561
{
 
562
  grub_printf ("\n   ");
 
563
  grub_printf_ (N_("Falling back to \'%s\'"), entry->title);
 
564
  grub_printf ("\n\n");
 
565
  grub_millisleep (DEFAULT_ENTRY_ERROR_DELAY_MS);
 
566
}
 
567
 
 
568
/* Callback invoked when a menu entry has failed and there is no remaining
 
569
   fallback entry to attempt.  */
 
570
static void
 
571
notify_execution_failure (void *userdata __attribute__((unused)))
 
572
{
 
573
  if (grub_errno != GRUB_ERR_NONE)
 
574
    {
 
575
      grub_print_error ();
 
576
      grub_errno = GRUB_ERR_NONE;
 
577
    }
 
578
  grub_printf ("\n  ");
 
579
  grub_printf_ (N_("Failed to boot both default and fallback entries.\n"));
 
580
  grub_wait_after_message ();
 
581
}
 
582
 
 
583
/* Callbacks used by the text menu to provide user feedback when menu entries
 
584
   are executed.  */
 
585
static struct grub_menu_execute_callback execution_callback =
 
586
{
 
587
  .notify_booting = notify_booting,
 
588
  .notify_fallback = notify_fallback,
 
589
  .notify_failure = notify_execution_failure
 
590
};
 
591
 
 
592
static grub_err_t
 
593
show_menu (grub_menu_t menu, int nested)
 
594
{
 
595
  while (1)
 
596
    {
 
597
      int boot_entry;
 
598
      grub_menu_entry_t e;
 
599
      int auto_boot;
 
600
 
 
601
      boot_entry = run_menu (menu, nested, &auto_boot);
 
602
      if (boot_entry < 0)
 
603
        break;
 
604
 
 
605
      e = grub_menu_get_entry (menu, boot_entry);
 
606
      if (! e)
 
607
        continue; /* Menu is empty.  */
 
608
 
 
609
      grub_cls ();
 
610
 
 
611
      if (auto_boot)
 
612
        grub_menu_execute_with_fallback (menu, e, &execution_callback, 0);
 
613
      else
 
614
        grub_menu_execute_entry (e);
 
615
    }
 
616
 
 
617
  return GRUB_ERR_NONE;
 
618
}
 
619
 
 
620
grub_err_t
 
621
grub_show_menu (grub_menu_t menu, int nested)
 
622
{
 
623
  grub_err_t err1, err2;
 
624
 
 
625
  while (1)
 
626
    {
 
627
      err1 = show_menu (menu, nested);
 
628
      grub_print_error ();
 
629
 
 
630
      if (grub_normal_exit_level)
 
631
        break;
 
632
 
 
633
      err2 = grub_auth_check_authentication (NULL);
 
634
      if (err2)
 
635
        {
 
636
          grub_print_error ();
 
637
          grub_errno = GRUB_ERR_NONE;
 
638
          continue;
 
639
        }
 
640
 
 
641
      break;
 
642
    }
 
643
 
 
644
  return err1;
 
645
}