~jonathank89/burg/burg-percise

« back to all changes in this revision

Viewing changes to normal/menu.c

merge mainline into mips

Show diffs side-by-side

added added

removed removed

Lines of Context:
27
27
#include <grub/command.h>
28
28
#include <grub/parser.h>
29
29
#include <grub/auth.h>
 
30
#include <grub/i18n.h>
 
31
#include <grub/term.h>
 
32
 
 
33
/* Time to delay after displaying an error message about a default/fallback
 
34
   entry failing to boot.  */
 
35
#define DEFAULT_ENTRY_ERROR_DELAY_MS  2500
 
36
 
 
37
grub_err_t (*grub_gfxmenu_try_hook) (int entry, grub_menu_t menu,
 
38
                                     int nested) = NULL;
 
39
 
 
40
/* Wait until the user pushes any key so that the user
 
41
   can see what happened.  */
 
42
void
 
43
grub_wait_after_message (void)
 
44
{
 
45
  grub_putchar ('\n');
 
46
  grub_printf_ (N_("Press any key to continue..."));
 
47
  (void) grub_getkey ();
 
48
  grub_putchar ('\n');
 
49
}
30
50
 
31
51
/* Get a menu entry by its index in the entry list.  */
32
52
grub_menu_entry_t
178
198
 
179
199
  callback->notify_failure (callback_data);
180
200
}
 
201
 
 
202
static struct grub_menu_viewer *viewers;
 
203
 
 
204
static void
 
205
menu_set_chosen_entry (int entry)
 
206
{
 
207
  struct grub_menu_viewer *cur;
 
208
  for (cur = viewers; cur; cur = cur->next)
 
209
    cur->set_chosen_entry (entry, cur->data);
 
210
}
 
211
 
 
212
static void
 
213
menu_print_timeout (int timeout)
 
214
{
 
215
  struct grub_menu_viewer *cur;
 
216
  for (cur = viewers; cur; cur = cur->next)
 
217
    cur->print_timeout (timeout, cur->data);
 
218
}
 
219
 
 
220
static void
 
221
menu_fini (void)
 
222
{
 
223
  struct grub_menu_viewer *cur, *next;
 
224
  for (cur = viewers; cur; cur = next)
 
225
    {
 
226
      next = cur->next;
 
227
      cur->fini (cur->data);
 
228
      grub_free (cur);
 
229
    }
 
230
  viewers = NULL;
 
231
}
 
232
 
 
233
static void
 
234
menu_init (int entry, grub_menu_t menu, int nested)
 
235
{
 
236
  struct grub_term_output *term;
 
237
 
 
238
  FOR_ACTIVE_TERM_OUTPUTS(term)
 
239
  {
 
240
    grub_err_t err;
 
241
 
 
242
    if (grub_gfxmenu_try_hook && grub_strcmp (term->name, "gfxterm") == 0)
 
243
      {
 
244
        err = grub_gfxmenu_try_hook (entry, menu, nested);
 
245
        if(!err)
 
246
          continue;
 
247
        grub_print_error ();
 
248
        grub_errno = GRUB_ERR_NONE;
 
249
      }
 
250
 
 
251
    err = grub_menu_try_text (term, entry, menu, nested);
 
252
    if(!err)
 
253
      continue;
 
254
    grub_print_error ();
 
255
    grub_errno = GRUB_ERR_NONE;
 
256
  }
 
257
}
 
258
 
 
259
static void
 
260
clear_timeout (void)
 
261
{
 
262
  struct grub_menu_viewer *cur;
 
263
  for (cur = viewers; cur; cur = cur->next)
 
264
    cur->clear_timeout (cur->data);
 
265
}
 
266
 
 
267
void
 
268
grub_menu_register_viewer (struct grub_menu_viewer *viewer)
 
269
{
 
270
  viewer->next = viewers;
 
271
  viewers = viewer;
 
272
}
 
273
 
 
274
/* Get the entry number from the variable NAME.  */
 
275
static int
 
276
get_entry_number (const char *name)
 
277
{
 
278
  char *val;
 
279
  int entry;
 
280
 
 
281
  val = grub_env_get (name);
 
282
  if (! val)
 
283
    return -1;
 
284
 
 
285
  grub_error_push ();
 
286
 
 
287
  entry = (int) grub_strtoul (val, 0, 0);
 
288
 
 
289
  if (grub_errno != GRUB_ERR_NONE)
 
290
    {
 
291
      grub_errno = GRUB_ERR_NONE;
 
292
      entry = -1;
 
293
    }
 
294
 
 
295
  grub_error_pop ();
 
296
 
 
297
  return entry;
 
298
}
 
299
 
 
300
#define GRUB_MENU_PAGE_SIZE 10
 
301
 
 
302
/* Show the menu and handle menu entry selection.  Returns the menu entry
 
303
   index that should be executed or -1 if no entry should be executed (e.g.,
 
304
   Esc pressed to exit a sub-menu or switching menu viewers).
 
305
   If the return value is not -1, then *AUTO_BOOT is nonzero iff the menu
 
306
   entry to be executed is a result of an automatic default selection because
 
307
   of the timeout.  */
 
308
static int
 
309
run_menu (grub_menu_t menu, int nested, int *auto_boot)
 
310
{
 
311
  grub_uint64_t saved_time;
 
312
  int default_entry, current_entry;
 
313
  int timeout;
 
314
 
 
315
  default_entry = get_entry_number ("default");
 
316
 
 
317
  /* If DEFAULT_ENTRY is not within the menu entries, fall back to
 
318
     the first entry.  */
 
319
  if (default_entry < 0 || default_entry >= menu->size)
 
320
    default_entry = 0;
 
321
 
 
322
  /* If timeout is 0, drawing is pointless (and ugly).  */
 
323
  if (grub_menu_get_timeout () == 0)
 
324
    {
 
325
      *auto_boot = 1;
 
326
      return default_entry;
 
327
    }
 
328
 
 
329
  current_entry = default_entry;
 
330
 
 
331
  /* Initialize the time.  */
 
332
  saved_time = grub_get_time_ms ();
 
333
 
 
334
 refresh:
 
335
  menu_init (current_entry, menu, nested);
 
336
 
 
337
  timeout = grub_menu_get_timeout ();
 
338
 
 
339
  if (timeout > 0)
 
340
    menu_print_timeout (timeout);
 
341
 
 
342
  while (1)
 
343
    {
 
344
      int c;
 
345
      timeout = grub_menu_get_timeout ();
 
346
 
 
347
      if (grub_normal_exit_level)
 
348
        return -1;
 
349
 
 
350
      if (timeout > 0)
 
351
        {
 
352
          grub_uint64_t current_time;
 
353
 
 
354
          current_time = grub_get_time_ms ();
 
355
          if (current_time - saved_time >= 1000)
 
356
            {
 
357
              timeout--;
 
358
              grub_menu_set_timeout (timeout);
 
359
              saved_time = current_time;
 
360
              menu_print_timeout (timeout);
 
361
            }
 
362
        }
 
363
 
 
364
      if (timeout == 0)
 
365
        {
 
366
          grub_env_unset ("timeout");
 
367
          *auto_boot = 1;
 
368
          menu_fini ();
 
369
          return default_entry;
 
370
        }
 
371
 
 
372
      if (grub_checkkey () >= 0 || timeout < 0)
 
373
        {
 
374
          c = GRUB_TERM_ASCII_CHAR (grub_getkey ());
 
375
 
 
376
          if (timeout >= 0)
 
377
            {
 
378
              grub_env_unset ("timeout");
 
379
              grub_env_unset ("fallback");
 
380
              clear_timeout ();
 
381
            }
 
382
 
 
383
          switch (c)
 
384
            {
 
385
            case GRUB_TERM_HOME:
 
386
              current_entry = 0;
 
387
              menu_set_chosen_entry (current_entry);
 
388
              break;
 
389
 
 
390
            case GRUB_TERM_END:
 
391
              current_entry = menu->size - 1;
 
392
              menu_set_chosen_entry (current_entry);
 
393
              break;
 
394
 
 
395
            case GRUB_TERM_UP:
 
396
            case '^':
 
397
              if (current_entry > 0)
 
398
                current_entry--;
 
399
              menu_set_chosen_entry (current_entry);
 
400
              break;
 
401
 
 
402
            case GRUB_TERM_DOWN:
 
403
            case 'v':
 
404
              if (current_entry < menu->size - 1)
 
405
                current_entry++;
 
406
              menu_set_chosen_entry (current_entry);
 
407
              break;
 
408
 
 
409
            case GRUB_TERM_PPAGE:
 
410
              if (current_entry < GRUB_MENU_PAGE_SIZE)
 
411
                current_entry = 0;
 
412
              else
 
413
                current_entry -= GRUB_MENU_PAGE_SIZE;
 
414
              menu_set_chosen_entry (current_entry);
 
415
              break;
 
416
 
 
417
            case GRUB_TERM_NPAGE:
 
418
              if (current_entry + GRUB_MENU_PAGE_SIZE < menu->size)
 
419
                current_entry += GRUB_MENU_PAGE_SIZE;
 
420
              else
 
421
                current_entry = menu->size - 1;
 
422
              menu_set_chosen_entry (current_entry);
 
423
              break;
 
424
 
 
425
            case '\n':
 
426
            case '\r':
 
427
            case 6:
 
428
              menu_fini ();
 
429
              *auto_boot = 0;
 
430
              return current_entry;
 
431
 
 
432
            case '\e':
 
433
              if (nested)
 
434
                {
 
435
                  menu_fini ();
 
436
                  return -1;
 
437
                }
 
438
              break;
 
439
 
 
440
            case 'c':
 
441
              menu_fini ();
 
442
              grub_cmdline_run (1);
 
443
              goto refresh;
 
444
 
 
445
            case 'e':
 
446
              menu_fini ();
 
447
                {
 
448
                  grub_menu_entry_t e = grub_menu_get_entry (menu, current_entry);
 
449
                  if (e)
 
450
                    grub_menu_entry_run (e);
 
451
                }
 
452
              goto refresh;
 
453
 
 
454
            default:
 
455
              break;
 
456
            }
 
457
        }
 
458
    }
 
459
 
 
460
  /* Never reach here.  */
 
461
  return -1;
 
462
}
 
463
 
 
464
/* Callback invoked immediately before a menu entry is executed.  */
 
465
static void
 
466
notify_booting (grub_menu_entry_t entry,
 
467
                void *userdata __attribute__((unused)))
 
468
{
 
469
  grub_printf ("  ");
 
470
  grub_printf_ (N_("Booting \'%s\'"), entry->title);
 
471
  grub_printf ("\n\n");
 
472
}
 
473
 
 
474
/* Callback invoked when a default menu entry executed because of a timeout
 
475
   has failed and an attempt will be made to execute the next fallback
 
476
   entry, ENTRY.  */
 
477
static void
 
478
notify_fallback (grub_menu_entry_t entry,
 
479
                 void *userdata __attribute__((unused)))
 
480
{
 
481
  grub_printf ("\n   ");
 
482
  grub_printf_ (N_("Falling back to \'%s\'"), entry->title);
 
483
  grub_printf ("\n\n");
 
484
  grub_millisleep (DEFAULT_ENTRY_ERROR_DELAY_MS);
 
485
}
 
486
 
 
487
/* Callback invoked when a menu entry has failed and there is no remaining
 
488
   fallback entry to attempt.  */
 
489
static void
 
490
notify_execution_failure (void *userdata __attribute__((unused)))
 
491
{
 
492
  if (grub_errno != GRUB_ERR_NONE)
 
493
    {
 
494
      grub_print_error ();
 
495
      grub_errno = GRUB_ERR_NONE;
 
496
    }
 
497
  grub_printf ("\n  ");
 
498
  grub_printf_ (N_("Failed to boot default entries.\n"));
 
499
  grub_wait_after_message ();
 
500
}
 
501
 
 
502
/* Callbacks used by the text menu to provide user feedback when menu entries
 
503
   are executed.  */
 
504
static struct grub_menu_execute_callback execution_callback =
 
505
{
 
506
  .notify_booting = notify_booting,
 
507
  .notify_fallback = notify_fallback,
 
508
  .notify_failure = notify_execution_failure
 
509
};
 
510
 
 
511
static grub_err_t
 
512
show_menu (grub_menu_t menu, int nested)
 
513
{
 
514
  while (1)
 
515
    {
 
516
      int boot_entry;
 
517
      grub_menu_entry_t e;
 
518
      int auto_boot;
 
519
 
 
520
      boot_entry = run_menu (menu, nested, &auto_boot);
 
521
      if (boot_entry < 0)
 
522
        break;
 
523
 
 
524
      e = grub_menu_get_entry (menu, boot_entry);
 
525
      if (! e)
 
526
        continue; /* Menu is empty.  */
 
527
 
 
528
      grub_cls ();
 
529
 
 
530
      if (auto_boot)
 
531
        {
 
532
          grub_menu_execute_with_fallback (menu, e, &execution_callback, 0);
 
533
        }
 
534
      else
 
535
        {
 
536
          grub_errno = GRUB_ERR_NONE;
 
537
          grub_menu_execute_entry (e);
 
538
          if (grub_errno != GRUB_ERR_NONE)
 
539
            {
 
540
              grub_print_error ();
 
541
              grub_errno = GRUB_ERR_NONE;
 
542
              grub_wait_after_message ();
 
543
            }
 
544
        }
 
545
    }
 
546
 
 
547
  return GRUB_ERR_NONE;
 
548
}
 
549
 
 
550
grub_err_t
 
551
grub_show_menu (grub_menu_t menu, int nested)
 
552
{
 
553
  grub_err_t err1, err2;
 
554
 
 
555
  while (1)
 
556
    {
 
557
      err1 = show_menu (menu, nested);
 
558
      grub_print_error ();
 
559
 
 
560
      if (grub_normal_exit_level)
 
561
        break;
 
562
 
 
563
      err2 = grub_auth_check_authentication (NULL);
 
564
      if (err2)
 
565
        {
 
566
          grub_print_error ();
 
567
          grub_errno = GRUB_ERR_NONE;
 
568
          continue;
 
569
        }
 
570
 
 
571
      break;
 
572
    }
 
573
 
 
574
  return err1;
 
575
}