2
* GRUB -- GRand Unified Bootloader
3
* Copyright (C) 2000, 2001 Free Software Foundation, Inc.
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22
grub_jmp_buf restart_env;
24
#if defined(PRESET_MENU_STRING) || defined(SUPPORT_DISKLESS)
26
# if defined(PRESET_MENU_STRING)
27
static const char *preset_menu = PRESET_MENU_STRING;
28
# elif defined(SUPPORT_DISKLESS)
29
/* Execute the command "bootp" automatically. */
30
static const char *preset_menu = "bootp\n";
31
# endif /* SUPPORT_DISKLESS */
33
static int preset_menu_offset;
36
open_preset_menu (void)
39
/* Unless the user explicitly requests to use the preset menu,
40
always opening the preset menu fails in the grub shell. */
41
if (! use_preset_menu)
43
#endif /* GRUB_UTIL */
45
preset_menu_offset = 0;
46
return preset_menu != 0;
50
read_from_preset_menu (char *buf, int maxlen)
52
int len = grub_strlen (preset_menu + preset_menu_offset);
57
grub_memmove (buf, preset_menu + preset_menu_offset, len);
58
preset_menu_offset += len;
64
close_preset_menu (void)
66
/* Disable the preset menu. */
70
#else /* ! PRESET_MENU_STRING && ! SUPPORT_DISKLESS */
72
#define open_preset_menu() 0
73
#define read_from_preset_menu(buf, maxlen) 0
74
#define close_preset_menu()
76
#endif /* ! PRESET_MENU_STRING && ! SUPPORT_DISKLESS */
80
get_entry (char *list, int num, int nested)
84
for (i = 0; i < num; i++)
90
while (nested && *(list++));
98
print_entries (int y, int size, int first, char *menu_entries)
101
int disp_up = DISP_UP;
102
int disp_down = DISP_DOWN;
104
#ifdef SUPPORT_SERIAL
105
if (terminal & TERMINAL_SERIAL)
107
disp_up = ACS_UARROW;
108
disp_down = ACS_DARROW;
110
#endif /* SUPPORT_SERIAL */
115
grub_putchar (disp_up);
119
menu_entries = get_entry (menu_entries, first, 0);
121
for (i = 1; i <= size; i++)
127
while (*menu_entries)
131
grub_putchar (*menu_entries);
138
if (*(menu_entries - 1))
145
gotoxy (77, y + size);
148
grub_putchar (disp_down);
155
print_entries_raw (int size, int first, char *menu_entries)
159
#define LINE_LENGTH 67
161
for (i = 0; i < LINE_LENGTH; i++)
165
for (i = first; i < size; i++)
167
/* grub's printf can't %02d so ... */
170
grub_printf ("%d: %s\n", i, get_entry (menu_entries, i, 0));
173
for (i = 0; i < LINE_LENGTH; i++)
182
print_border (int y, int size)
185
int disp_ul = DISP_UL;
186
int disp_ur = DISP_UR;
187
int disp_ll = DISP_LL;
188
int disp_lr = DISP_LR;
189
int disp_horiz = DISP_HORIZ;
190
int disp_vert = DISP_VERT;
192
#ifdef SUPPORT_SERIAL
193
if (terminal & TERMINAL_SERIAL)
195
disp_ul = ACS_ULCORNER;
196
disp_ur = ACS_URCORNER;
197
disp_ll = ACS_LLCORNER;
198
disp_lr = ACS_LRCORNER;
199
disp_horiz = ACS_HLINE;
200
disp_vert = ACS_VLINE;
202
#endif /* SUPPORT_SERIAL */
205
/* Color the menu. The menu is 75 * 14 characters. */
206
# ifdef SUPPORT_SERIAL
207
if ((terminal & TERMINAL_CONSOLE)
208
# ifdef SUPPORT_HERCULES
209
|| (terminal & TERMINAL_HERCULES)
214
for (i = 0; i < 14; i++)
217
for (j = 0; j < 75; j++)
219
gotoxy (j + 1, i + y);
220
set_attrib (normal_color);
228
grub_putchar (disp_ul);
229
for (i = 0; i < 73; i++)
230
grub_putchar (disp_horiz);
231
grub_putchar (disp_ur);
242
grub_putchar (disp_vert);
244
grub_putchar (disp_vert);
249
grub_putchar (disp_ll);
250
for (i = 0; i < 73; i++)
251
grub_putchar (disp_horiz);
252
grub_putchar (disp_lr);
256
set_line (int y, int entryno, int attr, char *menu_entries)
260
#ifdef SUPPORT_SERIAL
261
if (terminal & TERMINAL_SERIAL)
263
menu_entries = get_entry (menu_entries, entryno, 0);
266
for (x = 3; x < 75; x++)
268
if (*menu_entries && x < 71)
269
grub_putchar (*menu_entries++);
275
#endif /* SUPPORT_SERIAL */
277
for (x = 2; x < 75; x++)
287
/* Set the attribute of the line Y to normal state. */
289
set_line_normal (int y, int entryno, char *menu_entries)
292
set_line (y, entryno, A_NORMAL, menu_entries);
294
set_line (y, entryno, normal_color, menu_entries);
298
/* Set the attribute of the line Y to highlight state. */
300
set_line_highlight (int y, int entryno, char *menu_entries)
302
#ifdef SUPPORT_SERIAL
303
if (terminal & TERMINAL_SERIAL)
304
grub_printf ("\e[7m");
305
#endif /* SUPPORT_SERIAL */
308
set_line (y, entryno, A_REVERSE, menu_entries);
310
set_line (y, entryno, highlight_color, menu_entries);
313
#ifdef SUPPORT_SERIAL
314
if (terminal & TERMINAL_SERIAL)
315
grub_printf ("\e[0m");
316
#endif /* SUPPORT_SERIAL */
320
run_menu (char *menu_entries, char *config_entries, int num_entries,
321
char *heap, int entryno)
323
int c, time1, time2 = -1, first_entry = 0;
325
int disp_up = DISP_UP;
326
int disp_down = DISP_DOWN;
329
* Main loop for menu UI.
333
/* Dumb terminal always use all entries for display
334
invariant for TERMINAL_DUMB: first_entry == 0 */
335
if (! (terminal & TERMINAL_DUMB))
344
/* If the timeout was expired or wasn't set, force to show the menu
346
if (grub_timeout < 0)
349
/* If SHOW_MENU is false, don't display the menu until ESC is pressed. */
352
/* Get current time. */
353
while ((time1 = getrtsecs ()) == 0xFF)
358
/* Check if ESC is pressed. */
359
if (checkkey () != -1 && ASCII_CHAR (getkey ()) == '\e')
366
/* If GRUB_TIMEOUT is expired, boot the default entry. */
368
&& (time1 = getrtsecs ()) != time2
371
if (grub_timeout <= 0)
380
/* Print a message. */
381
grub_printf ("\rPress `ESC' to enter the menu... %d ",
387
/* Only display the menu if the user wants to see it. */
390
/* Disable the auto fill mode. */
395
# ifdef SUPPORT_SERIAL
396
if (terminal & TERMINAL_CONSOLE)
397
# endif /* SUPPORT_SERIAL */
399
#endif /* ! GRUB_UTIL */
401
if (! (terminal & TERMINAL_DUMB))
402
print_border (3, 12);
405
/* In the grub shell, always use ACS_*. */
406
disp_up = ACS_UARROW;
407
disp_down = ACS_DARROW;
408
#else /* ! GRUB_UTIL */
409
# ifdef SUPPORT_SERIAL
410
if ((terminal & TERMINAL_CONSOLE)
411
# ifdef SUPPORT_HERCULES
412
|| (terminal & TERMINAL_HERCULES)
413
# endif /* SUPPORT_HERCULES */
417
disp_down = DISP_DOWN;
421
disp_up = ACS_UARROW;
422
disp_down = ACS_DARROW;
424
# endif /* SUPPORT_SERIAL */
425
#endif /* ! GRUB_UTIL */
427
if (terminal & TERMINAL_DUMB)
428
print_entries_raw (num_entries, first_entry, menu_entries);
431
Use the %c and %c keys to select which entry is highlighted.\n",
434
if (! auth && password)
437
Press enter to boot the selected OS or \'p\' to enter a\n\
438
password to unlock the next set of features.");
444
Press enter to boot the selected OS, \'e\' to edit the\n\
445
commands before booting, or \'c\' for a command-line.");
448
Press \'b\' to boot, \'e\' to edit the selected command in the\n\
449
boot sequence, \'c\' for a command-line, \'o\' to open a new line\n\
450
after (\'O\' for before) the selected line, \'d\' to remove the\n\
451
selected line, or escape to go back to the main menu.");
454
if (terminal & TERMINAL_DUMB)
455
grub_printf ("\n\nThe selected entry is %d ", entryno);
458
print_entries (3, 12, first_entry, menu_entries);
460
/* highlight initial line */
461
set_line_highlight (4 + entryno, first_entry + entryno,
466
/* XX using RT clock now, need to initialize value */
467
while ((time1 = getrtsecs()) == 0xFF);
471
/* Initialize to NULL just in case... */
474
if (grub_timeout >= 0 && (time1 = getrtsecs()) != time2 && time1 != 0xFF)
476
if (grub_timeout <= 0)
482
/* else not booting yet! */
485
if (terminal & TERMINAL_DUMB)
486
grub_printf ("\r Entry %d will be booted automatically in %d seconds. ",
487
entryno, grub_timeout);
491
printf ("The highlighted entry will be booted automatically in %d seconds. ", grub_timeout);
492
gotoxy (74, 4 + entryno);
498
/* Check for a keypress, however if TIMEOUT has been expired
499
(GRUB_TIMEOUT == -1) relax in GETKEY even if no key has been
501
This avoids polling (relevant in the grub-shell and later on
502
in grub if interrupt driven I/O is done). */
503
if ((checkkey () != -1) || (grub_timeout == -1))
505
/* Key was pressed, show which entry is selected before GETKEY,
506
since we're comming in here also on GRUB_TIMEOUT == -1 and
508
if (terminal & TERMINAL_DUMB)
509
grub_printf ("\r Highlighted entry is %d: ", entryno);
511
c = translate_keycode (getkey ());
513
if (grub_timeout >= 0)
515
if (terminal & TERMINAL_DUMB)
522
if (! (terminal & TERMINAL_DUMB))
523
gotoxy (74, 4 + entryno);
526
/* We told them above (at least in SUPPORT_SERIAL) to use
527
'^' or 'v' so accept these keys. */
528
if (c == 16 || c == '^')
530
if (terminal & TERMINAL_DUMB)
539
set_line_normal (4 + entryno, first_entry + entryno,
542
set_line_highlight (4 + entryno, first_entry + entryno,
545
else if (first_entry > 0)
548
print_entries (3, 12, first_entry, menu_entries);
549
set_line_highlight (4, first_entry + entryno,
554
if ((c == 14 || c == 'v') && first_entry + entryno + 1 < num_entries)
556
if (terminal & TERMINAL_DUMB)
561
set_line_normal (4 + entryno, first_entry + entryno,
564
set_line_highlight (4 + entryno, first_entry + entryno,
567
else if (num_entries > 12 + first_entry)
570
print_entries (3, 12, first_entry, menu_entries);
571
set_line_highlight (15, first_entry + entryno, menu_entries);
577
if ((c == '\n') || (c == '\r'))
582
if ((c == 'd') || (c == 'o') || (c == 'O'))
584
if (! (terminal & TERMINAL_DUMB))
585
set_line_normal (4 + entryno, first_entry + entryno,
588
/* insert after is almost exactly like insert before */
591
/* But `o' differs from `O', since it may causes
592
the menu screen to scroll up. */
593
if (entryno < 11 || (terminal & TERMINAL_DUMB))
601
cur_entry = get_entry (menu_entries,
602
first_entry + entryno,
607
memmove (cur_entry + 2, cur_entry,
608
((int) heap) - ((int) cur_entry));
617
else if (num_entries > 0)
619
char *ptr = get_entry(menu_entries,
620
first_entry + entryno + 1,
623
memmove (cur_entry, ptr, ((int) heap) - ((int) ptr));
624
heap -= (((int) ptr) - ((int) cur_entry));
628
if (entryno >= num_entries)
630
if (first_entry && num_entries < 12 + first_entry)
634
if (terminal & TERMINAL_DUMB)
636
grub_printf ("\n\n");
637
print_entries_raw (num_entries, first_entry,
643
print_entries (3, 12, first_entry, menu_entries);
644
set_line_highlight (4 + entryno, first_entry + entryno,
649
cur_entry = menu_entries;
656
if (! auth && password)
660
/* Do password check here! */
662
char *pptr = password;
664
if (terminal & TERMINAL_DUMB)
669
/* Wipe out the previously entered password */
670
memset (entered, 0, sizeof (entered));
671
get_cmdline (" Password: ", entered, 31, '*', 0);
673
while (! isspace (*pptr) && *pptr)
676
/* Make sure that PASSWORD is NUL-terminated. */
679
if (! check_password (entered, password, password_type))
681
char *new_file = config_file;
682
while (isspace (*pptr))
685
/* If *PPTR is NUL, then allow the user to use
686
privileged instructions, otherwise, load
687
another configuration file. */
690
while ((*(new_file++) = *(pptr++)) != 0)
693
/* Make sure that the user will not have
694
authority in the next configuration. */
700
/* Now the user is superhuman. */
707
printf ("Failed!\n Press any key to continue...");
717
int new_num_entries = 0, i = 0;
723
cur_entry = get_entry (config_entries,
724
first_entry + entryno,
730
new_heap = heap + NEW_HEAPSIZE + 1;
731
cur_entry = get_entry (menu_entries,
732
first_entry + entryno,
738
while ((*(new_heap++) = cur_entry[i++]) != 0);
741
while (config_entries && cur_entry[i]);
743
/* this only needs to be done if config_entries is non-NULL,
744
but it doesn't hurt to do it always */
748
run_menu (heap, NULL, new_num_entries, new_heap, 0);
752
print_cmdline_message (0);
754
new_heap = heap + NEW_HEAPSIZE + 1;
756
saved_drive = boot_drive;
757
saved_partition = install_partition;
758
current_drive = 0xFF;
760
if (! get_cmdline (PACKAGE " edit> ", new_heap,
761
NEW_HEAPSIZE + 1, 0, 1))
765
/* get length of new command */
766
while (new_heap[j++])
776
/* align rest of commands properly */
777
memmove (cur_entry + j, cur_entry + i,
778
((int) heap) - (((int) cur_entry) + i));
780
/* copy command to correct area */
781
memmove (cur_entry, new_heap, j);
791
enter_cmdline (heap, 0);
797
/* The same as ``quit''. */
805
/* Attempt to boot an entry. */
808
/* Enable the auto fill mode. */
816
printf (" Booting \'%s\'\n\n",
817
get_entry (menu_entries, first_entry + entryno, 0));
819
printf (" Booting command-list\n\n");
822
cur_entry = get_entry (config_entries, first_entry + entryno, 1);
824
/* Set CURRENT_ENTRYNO for the command "savedefault". */
825
current_entryno = first_entry + entryno;
827
if (run_script (cur_entry, heap))
829
if (fallback_entry < 0)
835
entryno = fallback_entry;
849
get_line_from_config (char *cmdline, int maxlen, int read_from_file)
851
int pos = 0, literal = 0, comment = 0;
852
char c; /* since we're loading it a byte at a time! */
858
if (! grub_read (&c, 1))
863
if (! read_from_preset_menu (&c, 1))
867
/* translate characters first! */
868
if (c == '\\' && ! literal)
875
if ((c == '\t') || (literal && (c == '\n')))
889
else if ((c != ' ') && (c != '\n'))
908
/* This is the starting function in C. */
912
int config_len, menu_len, num_entries;
913
char *config_entries, *menu_entries;
914
char *kill_buf = (char *) KILL_BUF;
916
auto void reset (void);
923
config_entries = (char *) mbi.drives_addr + mbi.drives_length;
924
menu_entries = (char *) MENU_BUF;
928
/* Initialize the environment for restarting Stage 2. */
929
grub_setjmp (restart_env);
931
/* Initialize the kill buffer. */
937
int is_opened, is_preset;
941
/* Here load the configuration file. */
945
#endif /* GRUB_UTIL */
949
/* STATE 0: Before any title command.
950
STATE 1: In a title command.
951
STATE >1: In a entry after a title command. */
952
int state = 0, prev_config_len = 0, prev_menu_len = 0;
955
/* Try the preset menu first. This will succeed at most once,
956
because close_preset_menu disables the preset menu. */
957
is_opened = is_preset = open_preset_menu ();
960
is_opened = grub_open (config_file);
967
/* This is necessary, because the menu must be overrided. */
970
cmdline = (char *) CMDLINE_BUF;
971
while (get_line_from_config (cmdline, NEW_HEAPSIZE,
974
struct builtin *builtin;
976
/* Get the pointer to the builtin structure. */
977
builtin = find_command (cmdline);
980
/* Unknown command. Just skip now. */
983
if (builtin->flags & BUILTIN_TITLE)
987
/* the command "title" is specially treated. */
990
/* The next title is found. */
992
config_entries[config_len++] = 0;
993
prev_menu_len = menu_len;
994
prev_config_len = config_len;
998
/* The first title is found. */
999
menu_len = prev_menu_len;
1000
config_len = prev_config_len;
1003
/* Reset the state. */
1006
/* Copy title into menu area. */
1007
ptr = skip_to (1, cmdline);
1008
while ((menu_entries[menu_len++] = *(ptr++)) != 0)
1013
/* Run a command found is possible. */
1014
if (builtin->flags & BUILTIN_MENU)
1016
char *arg = skip_to (1, cmdline);
1017
(builtin->func) (arg, BUILTIN_MENU);
1026
char *ptr = cmdline;
1029
/* Copy config file data to config area. */
1030
while ((config_entries[config_len++] = *ptr++) != 0)
1037
/* Finish the last entry. */
1039
config_entries[config_len++] = 0;
1043
menu_len = prev_menu_len;
1044
config_len = prev_config_len;
1047
menu_entries[menu_len++] = 0;
1048
config_entries[config_len++] = 0;
1049
grub_memmove (config_entries + config_len, menu_entries,
1051
menu_entries = config_entries + config_len;
1053
/* Check if the default entry is present. Otherwise reset
1054
it to fallback if fallback is valid, or to DEFAULT_ENTRY
1056
if (default_entry >= num_entries)
1058
if (fallback_entry < 0 || fallback_entry >= num_entries)
1061
default_entry = fallback_entry;
1065
close_preset_menu ();
1074
/* If no acceptable config file, goto command-line, starting
1075
heap from where the config entries would have been stored
1076
if there were any. */
1077
enter_cmdline (config_entries, 1);
1081
/* Run menu interface. */
1082
run_menu (menu_entries, config_entries, num_entries,
1083
menu_entries + menu_len, default_entry);