1 /*
2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2000,2001,2002,2004,2005 Free Software Foundation, Inc.
4 *
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.
9 *
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.
14 *
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.
18 */
19
20 #include <shared.h>
21 #include <term.h>
22 #include <expand.h>
23
24 #define MENU_ROWS 12
25
26 grub_jmp_buf restart_env;
27
28 struct silentbuf silent;
29 int reset_term;
30
31 #if defined(PRESET_MENU_STRING) || defined(SUPPORT_DISKLESS)
32
33 # if defined(PRESET_MENU_STRING)
34 static const char *preset_menu = PRESET_MENU_STRING;
35 # elif defined(SUPPORT_DISKLESS)
36 /* Execute the command "bootp" automatically. */
37 static const char *preset_menu = "dhcp\n";
38 # endif /* SUPPORT_DISKLESS */
39
40 static int preset_menu_offset;
41
42 static int
open_preset_menu(void)43 open_preset_menu (void)
44 {
45 #ifdef GRUB_UTIL
46 /* Unless the user explicitly requests to use the preset menu,
47 always opening the preset menu fails in the grub shell. */
48 if (! use_preset_menu)
49 return 0;
50 #endif /* GRUB_UTIL */
51
52 preset_menu_offset = 0;
53 return preset_menu != 0;
54 }
55
56 static int
read_from_preset_menu(char * buf,int maxlen)57 read_from_preset_menu (char *buf, int maxlen)
58 {
59 int len = grub_strlen (preset_menu + preset_menu_offset);
60
61 if (len > maxlen)
62 len = maxlen;
63
64 grub_memmove (buf, preset_menu + preset_menu_offset, len);
65 preset_menu_offset += len;
66
67 return len;
68 }
69
70 static void
close_preset_menu(void)71 close_preset_menu (void)
72 {
73 /* Disable the preset menu. */
74 preset_menu = 0;
75 }
76
77 #else /* ! PRESET_MENU_STRING && ! SUPPORT_DISKLESS */
78
79 #define open_preset_menu() 0
80 #define read_from_preset_menu(buf, maxlen) 0
81 #define close_preset_menu()
82
83 #endif /* ! PRESET_MENU_STRING && ! SUPPORT_DISKLESS */
84
85 static char *
get_entry(char * list,int num,int nested)86 get_entry (char *list, int num, int nested)
87 {
88 int i;
89
90 for (i = 0; i < num; i++)
91 {
92 do
93 {
94 while (*(list++));
95 }
96 while (nested && *(list++));
97 }
98
99 return list;
100 }
101
102 /* Print an entry in a line of the menu box. */
103 static void
print_entry(int y,int highlight,char * entry)104 print_entry (int y, int highlight, char *entry)
105 {
106 int x;
107
108 if (current_term->setcolorstate)
109 current_term->setcolorstate (COLOR_STATE_NORMAL);
110
111 if (highlight && current_term->setcolorstate)
112 current_term->setcolorstate (COLOR_STATE_HIGHLIGHT);
113
114 gotoxy (2, y);
115 grub_putchar (' ');
116 for (x = 3; x < 75; x++)
117 {
118 if (*entry && x <= 72)
119 {
120 if (x == 72)
121 grub_putchar (DISP_RIGHT);
122 else
123 grub_putchar (*entry++);
124 }
125 else
126 grub_putchar (' ');
127 }
128 gotoxy (74, y);
129
130 if (current_term->setcolorstate)
131 current_term->setcolorstate (COLOR_STATE_STANDARD);
132 }
133
134 /* Print entries in the menu box. */
135 static void
print_entries(int y,int size,int first,int entryno,char * menu_entries)136 print_entries (int y, int size, int first, int entryno, char *menu_entries)
137 {
138 int i;
139
140 gotoxy (77, y + 1);
141
142 if (first)
143 grub_putchar (DISP_UP);
144 else
145 grub_putchar (' ');
146
147 menu_entries = get_entry (menu_entries, first, 0);
148
149 for (i = 0; i < size; i++)
150 {
151 print_entry (y + i + 1, entryno == i, menu_entries);
152
153 while (*menu_entries)
154 menu_entries++;
155
156 if (*(menu_entries - 1))
157 menu_entries++;
158 }
159
160 gotoxy (77, y + size);
161
162 if (*menu_entries)
163 grub_putchar (DISP_DOWN);
164 else
165 grub_putchar (' ');
166
167 gotoxy (74, y + entryno + 1);
168 }
169
170 static void
print_entries_raw(int size,int first,char * menu_entries)171 print_entries_raw (int size, int first, char *menu_entries)
172 {
173 int i;
174
175 #define LINE_LENGTH 67
176
177 for (i = 0; i < LINE_LENGTH; i++)
178 grub_putchar ('-');
179 grub_putchar ('\n');
180
181 for (i = first; i < size; i++)
182 {
183 /* grub's printf can't %02d so ... */
184 if (i < 10)
185 grub_putchar (' ');
186 grub_printf ("%d: %s\n", i, get_entry (menu_entries, i, 0));
187 }
188
189 for (i = 0; i < LINE_LENGTH; i++)
190 grub_putchar ('-');
191 grub_putchar ('\n');
192
193 #undef LINE_LENGTH
194 }
195
196
197 static void
print_border(int y,int size)198 print_border (int y, int size)
199 {
200 int i;
201
202 if (current_term->setcolorstate)
203 current_term->setcolorstate (COLOR_STATE_NORMAL);
204
205 gotoxy (1, y);
206
207 grub_putchar (DISP_UL);
208 for (i = 0; i < 73; i++)
209 grub_putchar (DISP_HORIZ);
210 grub_putchar (DISP_UR);
211
212 i = 1;
213 while (1)
214 {
215 gotoxy (1, y + i);
216
217 if (i > size)
218 break;
219
220 grub_putchar (DISP_VERT);
221 gotoxy (75, y + i);
222 grub_putchar (DISP_VERT);
223
224 i++;
225 }
226
227 grub_putchar (DISP_LL);
228 for (i = 0; i < 73; i++)
229 grub_putchar (DISP_HORIZ);
230 grub_putchar (DISP_LR);
231
232 if (current_term->setcolorstate)
233 current_term->setcolorstate (COLOR_STATE_STANDARD);
234 }
235
236 static void
run_menu(char * menu_entries,char * config_entries,int num_entries,char * heap,int entryno)237 run_menu (char *menu_entries, char *config_entries, int num_entries,
238 char *heap, int entryno)
239 {
240 int c, time1, time2 = -1, first_entry = 0;
241 char *cur_entry = 0;
242 struct term_entry *prev_term = NULL;
243 const char *console = NULL;
244
245 /*
246 * Main loop for menu UI.
247 */
248
249 restart:
250 /* Dumb terminal always use all entries for display
251 invariant for TERM_DUMB: first_entry == 0 */
252 if (! (current_term->flags & TERM_DUMB))
253 {
254 while (entryno > MENU_ROWS - 1)
255 {
256 first_entry++;
257 entryno--;
258 }
259 }
260
261 /* If the timeout was expired or wasn't set, force to show the menu
262 interface. */
263 if (grub_timeout < 0)
264 show_menu = 1;
265
266 /* If SHOW_MENU is false, don't display the menu until ESC is pressed. */
267 if (! show_menu)
268 {
269 /* Get current time. */
270 while ((time1 = getrtsecs ()) == 0xFF)
271 ;
272
273 while (1)
274 {
275 /* Check if ESC is pressed. */
276 if (checkkey () != -1 && ASCII_CHAR (getkey ()) == '\e')
277 {
278 grub_timeout = -1;
279 show_menu = 1;
280 break;
281 }
282
283 /* If GRUB_TIMEOUT is expired, boot the default entry. */
284 if (grub_timeout >=0
285 && (time1 = getrtsecs ()) != time2
286 && time1 != 0xFF)
287 {
288 if (grub_timeout <= 0)
289 {
290 grub_timeout = -1;
291 goto boot_entry;
292 }
293
294 time2 = time1;
295 grub_timeout--;
296
297 /* Print a message. */
298 grub_printf ("\rPress `ESC' to enter the menu... %d ",
299 grub_timeout);
300 }
301 }
302 }
303
304 /* Only display the menu if the user wants to see it. */
305 if (show_menu)
306 {
307 init_page ();
308 setcursor (0);
309
310 if (current_term->flags & TERM_DUMB)
311 print_entries_raw (num_entries, first_entry, menu_entries);
312 else
313 print_border (3, MENU_ROWS);
314
315 grub_printf ("\n\
316 Use the %c and %c keys to select which entry is highlighted.\n",
317 DISP_UP, DISP_DOWN);
318
319 if (! auth && password)
320 {
321 printf ("\
322 Press enter to boot the selected OS or \'p\' to enter a\n\
323 password to unlock the next set of features.");
324 }
325 else
326 {
327 if (config_entries)
328 printf ("\
329 Press enter to boot the selected OS, \'e\' to edit the\n\
330 commands before booting, or \'c\' for a command-line.");
331 else
332 printf ("\
333 Press \'b\' to boot, \'e\' to edit the selected command in the\n\
334 boot sequence, \'c\' for a command-line, \'o\' to open a new line\n\
335 after (\'O\' for before) the selected line, \'d\' to remove the\n\
336 selected line, or escape to go back to the main menu.");
337 }
338
339 /* The selected OS console is special; if it's in use, tell the user. */
340 console = get_variable("os_console");
341 if (console != NULL) {
342 printf("\n\n Selected OS console device is '%s'."
343 "\n To change OS console device, enter command-line mode"
344 "\n and use 'variable os_console <dev>', then Esc to return."
345 "\n Valid <dev> values are: ttya, ttyb, ttyc, ttyd, vga",
346 console);
347 }
348
349 if (current_term->flags & TERM_DUMB)
350 grub_printf ("\n\nThe selected entry is %d ", entryno);
351 else
352 print_entries (3, MENU_ROWS, first_entry, entryno, menu_entries);
353 }
354
355 /* XX using RT clock now, need to initialize value */
356 while ((time1 = getrtsecs()) == 0xFF);
357
358 while (1)
359 {
360 /* Initialize to NULL just in case... */
361 cur_entry = NULL;
362
363 if (grub_timeout >= 0 && (time1 = getrtsecs()) != time2 && time1 != 0xFF)
364 {
365 if (grub_timeout <= 0)
366 {
367 grub_timeout = -1;
368 break;
369 }
370
371 /* else not booting yet! */
372 time2 = time1;
373
374 if (current_term->flags & TERM_DUMB)
375 grub_printf ("\r Entry %d will be booted automatically in %d seconds. ",
376 entryno, grub_timeout);
377 else
378 {
379 gotoxy (3, 22);
380 grub_printf ("The highlighted entry will be booted automatically in %d seconds. ",
381 grub_timeout);
382 gotoxy (74, 4 + entryno);
383 }
384
385 grub_timeout--;
386 }
387
388 /* Check for a keypress, however if TIMEOUT has been expired
389 (GRUB_TIMEOUT == -1) relax in GETKEY even if no key has been
390 pressed.
391 This avoids polling (relevant in the grub-shell and later on
392 in grub if interrupt driven I/O is done). */
393 if (checkkey () >= 0 || grub_timeout < 0)
394 {
395 /* Key was pressed, show which entry is selected before GETKEY,
396 since we're comming in here also on GRUB_TIMEOUT == -1 and
397 hang in GETKEY */
398 if (current_term->flags & TERM_DUMB)
399 grub_printf ("\r Highlighted entry is %d: ", entryno);
400
401 c = ASCII_CHAR (getkey ());
402
403 if (grub_timeout >= 0)
404 {
405 if (current_term->flags & TERM_DUMB)
406 grub_putchar ('\r');
407 else
408 gotoxy (3, 22);
409 printf (" ");
410 grub_timeout = -1;
411 fallback_entryno = -1;
412 if (! (current_term->flags & TERM_DUMB))
413 gotoxy (74, 4 + entryno);
414 }
415
416 /* We told them above (at least in SUPPORT_SERIAL) to use
417 '^' or 'v' so accept these keys. */
418 if (c == 16 || c == '^')
419 {
420 if (current_term->flags & TERM_DUMB)
421 {
422 if (entryno > 0)
423 entryno--;
424 }
425 else
426 {
427 if (entryno > 0)
428 {
429 print_entry (4 + entryno, 0,
430 get_entry (menu_entries,
431 first_entry + entryno,
432 0));
433 entryno--;
434 print_entry (4 + entryno, 1,
435 get_entry (menu_entries,
436 first_entry + entryno,
437 0));
438 }
439 else if (first_entry > 0)
440 {
441 first_entry--;
442 print_entries (3, MENU_ROWS, first_entry, entryno,
443 menu_entries);
444 }
445 }
446 }
447 else if ((c == 14 || c == 'v')
448 && first_entry + entryno + 1 < num_entries)
449 {
450 if (current_term->flags & TERM_DUMB)
451 entryno++;
452 else
453 {
454 if (entryno < MENU_ROWS - 1)
455 {
456 print_entry (4 + entryno, 0,
457 get_entry (menu_entries,
458 first_entry + entryno,
459 0));
460 entryno++;
461 print_entry (4 + entryno, 1,
462 get_entry (menu_entries,
463 first_entry + entryno,
464 0));
465 }
466 else if (num_entries > MENU_ROWS + first_entry)
467 {
468 first_entry++;
469 print_entries (3, MENU_ROWS, first_entry, entryno, menu_entries);
470 }
471 }
472 }
473 else if (c == 7)
474 {
475 /* Page Up */
476 first_entry -= MENU_ROWS;
477 if (first_entry < 0)
478 {
479 entryno += first_entry;
480 first_entry = 0;
481 if (entryno < 0)
482 entryno = 0;
483 }
484 print_entries (3, MENU_ROWS, first_entry, entryno, menu_entries);
485 }
486 else if (c == 3)
487 {
488 /* Page Down */
489 first_entry += MENU_ROWS;
490 if (first_entry + entryno + 1 >= num_entries)
491 {
492 first_entry = num_entries - MENU_ROWS;
493 if (first_entry < 0)
494 first_entry = 0;
495 entryno = num_entries - first_entry - 1;
496 }
497 print_entries (3, MENU_ROWS, first_entry, entryno, menu_entries);
498 }
499
500 if (config_entries)
501 {
502 if ((c == '\n') || (c == '\r') || (c == 6))
503 break;
504 }
505 else
506 {
507 if ((c == 'd') || (c == 'o') || (c == 'O'))
508 {
509 if (! (current_term->flags & TERM_DUMB))
510 print_entry (4 + entryno, 0,
511 get_entry (menu_entries,
512 first_entry + entryno,
513 0));
514
515 /* insert after is almost exactly like insert before */
516 if (c == 'o')
517 {
518 /* But `o' differs from `O', since it may causes
519 the menu screen to scroll up. */
520 if (entryno < MENU_ROWS - 1 ||
521 (current_term->flags & TERM_DUMB))
522 entryno++;
523 else
524 first_entry++;
525
526 c = 'O';
527 }
528
529 cur_entry = get_entry (menu_entries,
530 first_entry + entryno,
531 0);
532
533 if (c == 'O')
534 {
535 grub_memmove (cur_entry + 2, cur_entry,
536 ((int) heap) - ((int) cur_entry));
537
538 cur_entry[0] = ' ';
539 cur_entry[1] = 0;
540
541 heap += 2;
542
543 num_entries++;
544 }
545 else if (num_entries > 0)
546 {
547 char *ptr = get_entry(menu_entries,
548 first_entry + entryno + 1,
549 0);
550
551 grub_memmove (cur_entry, ptr,
552 ((int) heap) - ((int) ptr));
553 heap -= (((int) ptr) - ((int) cur_entry));
554
555 num_entries--;
556
557 if (entryno >= num_entries)
558 entryno--;
559 if (first_entry && num_entries < MENU_ROWS + first_entry)
560 first_entry--;
561 }
562
563 if (current_term->flags & TERM_DUMB)
564 {
565 grub_printf ("\n\n");
566 print_entries_raw (num_entries, first_entry,
567 menu_entries);
568 grub_printf ("\n");
569 }
570 else
571 print_entries (3, MENU_ROWS, first_entry, entryno, menu_entries);
572 }
573
574 cur_entry = menu_entries;
575 if (c == 27)
576 return;
577 if (c == 'b')
578 break;
579 }
580
581 if (! auth && password)
582 {
583 if (c == 'p')
584 {
585 /* Do password check here! */
586 char entered[32];
587 char *pptr = password;
588
589 if (current_term->flags & TERM_DUMB)
590 grub_printf ("\r ");
591 else
592 gotoxy (1, 21);
593
594 /* Wipe out the previously entered password */
595 grub_memset (entered, 0, sizeof (entered));
596 get_cmdline (" Password: ", entered, 31, '*', 0);
597
598 while (! isspace (*pptr) && *pptr)
599 pptr++;
600
601 /* Make sure that PASSWORD is NUL-terminated. */
602 *pptr++ = 0;
603
604 if (! check_password (entered, password, password_type))
605 {
606 char *new_file = config_file;
607 while (isspace (*pptr))
608 pptr++;
609
610 /* If *PPTR is NUL, then allow the user to use
611 privileged instructions, otherwise, load
612 another configuration file. */
613 if (*pptr != 0)
614 {
615 while ((*(new_file++) = *(pptr++)) != 0)
616 ;
617
618 /* Make sure that the user will not have
619 authority in the next configuration. */
620 auth = 0;
621 return;
622 }
623 else
624 {
625 /* Now the user is superhuman. */
626 auth = 1;
627 goto restart;
628 }
629 }
630 else
631 {
632 grub_printf ("Failed!\n Press any key to continue...");
633 getkey ();
634 goto restart;
635 }
636 }
637 }
638 else
639 {
640 if (c == 'e')
641 {
642 int new_num_entries = 0, i = 0;
643 char *new_heap;
644
645 if (config_entries)
646 {
647 new_heap = heap;
648 cur_entry = get_entry (config_entries,
649 first_entry + entryno,
650 1);
651 }
652 else
653 {
654 /* safe area! */
655 new_heap = heap + NEW_HEAPSIZE + 1;
656 cur_entry = get_entry (menu_entries,
657 first_entry + entryno,
658 0);
659 }
660
661 do
662 {
663 while ((*(new_heap++) = cur_entry[i++]) != 0);
664 new_num_entries++;
665 }
666 while (config_entries && cur_entry[i]);
667
668 /* this only needs to be done if config_entries is non-NULL,
669 but it doesn't hurt to do it always */
670 *(new_heap++) = 0;
671
672 if (config_entries)
673 run_menu (heap, NULL, new_num_entries, new_heap, 0);
674 else
675 {
676 cls ();
677 print_cmdline_message (0);
678
679 new_heap = heap + NEW_HEAPSIZE + 1;
680
681 saved_drive = boot_drive;
682 saved_partition = install_partition;
683 current_drive = GRUB_INVALID_DRIVE;
684
685 if (! get_cmdline (PACKAGE " edit> ", new_heap,
686 NEW_HEAPSIZE + 1, 0, 1))
687 {
688 int j = 0;
689
690 /* get length of new command */
691 while (new_heap[j++])
692 ;
693
694 if (j < 2)
695 {
696 j = 2;
697 new_heap[0] = ' ';
698 new_heap[1] = 0;
699 }
700
701 /* align rest of commands properly */
702 grub_memmove (cur_entry + j, cur_entry + i,
703 (int) heap - ((int) cur_entry + i));
704
705 /* copy command to correct area */
706 grub_memmove (cur_entry, new_heap, j);
707
708 heap += (j - i);
709 }
710 }
711
712 goto restart;
713 }
714 if (c == 'c')
715 {
716 enter_cmdline (heap, 0);
717 goto restart;
718 }
719 #ifdef GRUB_UTIL
720 if (c == 'q')
721 {
722 /* The same as ``quit''. */
723 stop ();
724 }
725 #endif
726 }
727 }
728 }
729
730 /* Attempt to boot an entry. */
731
732 boot_entry:
733
734 if (silent.status != DEFER_VERBOSE)
735 silent.status = SILENT;
736
737 reset_term = 1;
738
739 cls ();
740 setcursor (1);
741
742 /* if our terminal needed initialization, we should shut it down
743 * before booting the kernel, but we want to save what it was so
744 * we can come back if needed */
745 prev_term = current_term;
746
747 if (silent.status != SILENT)
748 if (current_term->shutdown) {
749 (*current_term->shutdown)();
750 current_term = term_table; /* assumption: console is first */
751 }
752
753 while (1)
754 {
755 if (config_entries)
756 printf (" Booting \'%s\'\n\n",
757 get_entry (menu_entries, first_entry + entryno, 0));
758 else
759 printf (" Booting command-list\n\n");
760
761 if (! cur_entry)
762 cur_entry = get_entry (config_entries, first_entry + entryno, 1);
763
764 /* Set CURRENT_ENTRYNO for the command "savedefault". */
765 current_entryno = first_entry + entryno;
766
767 if (run_script (cur_entry, heap))
768 {
769 if (fallback_entryno >= 0)
770 {
771 cur_entry = NULL;
772 first_entry = 0;
773 entryno = fallback_entries[fallback_entryno];
774 fallback_entryno++;
775 if (fallback_entryno >= MAX_FALLBACK_ENTRIES
776 || fallback_entries[fallback_entryno] < 0)
777 fallback_entryno = -1;
778 }
779 else
780 break;
781 }
782 else
783 break;
784 }
785
786 if (silent.status != SILENT) { /* don't reset if we never changed terms */
787 /* if we get back here, we should go back to what our term was before */
788 current_term = prev_term;
789 if (current_term->startup)
790 /* if our terminal fails to initialize, fall back to console since
791 * it should always work */
792 if ((*current_term->startup)() == 0)
793 current_term = term_table; /* we know that console is first */
794 }
795
796 show_menu = 1;
797 goto restart;
798 }
799
800
801 static int
get_line_from_config(char * cmdline,int maxlen,int read_from_file)802 get_line_from_config (char *cmdline, int maxlen, int read_from_file)
803 {
804 int pos = 0, literal = 0, comment = 0;
805 char c; /* since we're loading it a byte at a time! */
806
807 while (1)
808 {
809 if (read_from_file)
810 {
811 if (! grub_read (&c, 1))
812 break;
813 }
814 else
815 {
816 if (! read_from_preset_menu (&c, 1))
817 break;
818 }
819
820 /* Skip all carriage returns. */
821 if (c == '\r')
822 continue;
823
824 /* Replace tabs with spaces. */
825 if (c == '\t')
826 c = ' ';
827
828 /* The previous is a backslash, then... */
829 if (literal)
830 {
831 /* If it is a newline, replace it with a space and continue. */
832 if (c == '\n')
833 {
834 c = ' ';
835
836 /* Go back to overwrite a backslash. */
837 if (pos > 0)
838 pos--;
839 }
840
841 literal = 0;
842 }
843
844 /* translate characters first! */
845 if (c == '\\' && ! literal)
846 literal = 1;
847
848 if (comment)
849 {
850 if (c == '\n')
851 comment = 0;
852 }
853 else if (! pos)
854 {
855 if (c == '#')
856 comment = 1;
857 else if ((c != ' ') && (c != '\n'))
858 cmdline[pos++] = c;
859 }
860 else
861 {
862 if (c == '\n')
863 break;
864
865 if (pos < maxlen)
866 cmdline[pos++] = c;
867 }
868 }
869
870 cmdline[pos] = 0;
871
872 return pos;
873 }
874
875 extern int findroot_func (char *arg, int flags);
876
877 /* This is the starting function in C. */
878 void
cmain(void)879 cmain (void)
880 {
881 int config_len, menu_len, num_entries;
882 char *config_entries, *menu_entries;
883 char *kill_buf = (char *) KILL_BUF;
884
885 silent.status = DEFER_SILENT;
886 silent.looped = 0;
887 silent.buffer_start = silent.buffer;
888
889 auto void reset (void);
890 void reset (void)
891 {
892 count_lines = -1;
893 config_len = 0;
894 menu_len = 0;
895 num_entries = 0;
896 config_entries = (char *) mbi.drives_addr + mbi.drives_length;
897 menu_entries = (char *) MENU_BUF;
898 init_config ();
899 }
900
901 /* Initialize the environment for restarting Stage 2. */
902 grub_setjmp (restart_env);
903
904 /* Initialize the kill buffer. */
905 *kill_buf = 0;
906
907 /* Never return. */
908 for (;;)
909 {
910 int is_opened, is_preset;
911
912 reset ();
913
914 /* Here load the configuration file. */
915
916 #ifdef GRUB_UTIL
917 if (use_config_file)
918 #endif /* GRUB_UTIL */
919 {
920 char *default_file = (char *) DEFAULT_FILE_BUF;
921 int i;
922
923 /* Get a saved default entry if possible. */
924 saved_entryno = 0;
925 grub_strcpy (default_file, config_file);
926 for (i = grub_strlen(default_file); i >= 0; i--)
927 if (default_file[i] == '/')
928 {
929 i++;
930 break;
931 }
932 default_file[i] = 0;
933 grub_strncat (default_file + i, "default", DEFAULT_FILE_BUFLEN - i);
934 if (grub_open (default_file))
935 {
936 char buf[10]; /* This is good enough. */
937 char *p = buf;
938 int len;
939
940 len = grub_read (buf, sizeof (buf));
941 if (len > 0)
942 {
943 buf[sizeof (buf) - 1] = 0;
944 safe_parse_maxint (&p, &saved_entryno);
945 }
946
947 grub_close ();
948 }
949 errnum = ERR_NONE;
950
951 do
952 {
953 /* STATE 0: Before any title command.
954 STATE 1: In a title command.
955 STATE >1: In a entry after a title command. */
956 int state = 0, prev_config_len = 0, prev_menu_len = 0;
957 char *cmdline;
958
959 /* Try the preset menu first. This will succeed at most once,
960 because close_preset_menu disables the preset menu. */
961 is_opened = is_preset = open_preset_menu ();
962 if (! is_opened)
963 {
964 is_opened = grub_open (config_file);
965 }
966 /*
967 * we're not going to get very far if we weren't able to
968 * open the config file and this isn't a valid filesystem,
969 * so look for the config file somewhere else
970 */
971 if (!is_opened && errnum == ERR_FSYS_MOUNT &&
972 (findroot_func(config_file, 0) == 0)) {
973 is_opened = grub_open (config_file);
974 }
975
976 if (! is_opened) {
977 errnum = ERR_NONE;
978 break;
979 }
980
981 /* This is necessary, because the menu must be overrided. */
982 reset ();
983
984 cmdline = (char *) CMDLINE_BUF;
985 while (get_line_from_config (cmdline, NEW_HEAPSIZE,
986 ! is_preset))
987 {
988 struct builtin *builtin;
989
990 /* Get the pointer to the builtin structure. */
991 builtin = find_command (cmdline);
992 errnum = 0;
993 if (! builtin)
994 /* Unknown command. Just skip now. */
995 continue;
996
997 if (builtin->flags & BUILTIN_TITLE)
998 {
999 char *ptr;
1000
1001 /* the command "title" is specially treated. */
1002 if (state > 1)
1003 {
1004 /* The next title is found. */
1005 num_entries++;
1006 config_entries[config_len++] = 0;
1007 prev_menu_len = menu_len;
1008 prev_config_len = config_len;
1009 }
1010 else
1011 {
1012 /* The first title is found. */
1013 menu_len = prev_menu_len;
1014 config_len = prev_config_len;
1015 }
1016
1017 /* Reset the state. */
1018 state = 1;
1019
1020 /* Copy title into menu area. */
1021 ptr = skip_to (1, cmdline);
1022 while ((menu_entries[menu_len++] = *(ptr++)) != 0)
1023 ;
1024 }
1025 else if (! state)
1026 {
1027 /* Run a command found is possible. */
1028 if (builtin->flags & BUILTIN_MENU)
1029 {
1030 char *arg = skip_to (1, cmdline);
1031 (builtin->func) (arg, BUILTIN_MENU);
1032 errnum = 0;
1033 }
1034 else
1035 /* Ignored. */
1036 continue;
1037 }
1038 else
1039 {
1040 char *ptr = cmdline;
1041
1042 state++;
1043 /* Copy config file data to config area. */
1044 while ((config_entries[config_len++] = *ptr++) != 0)
1045 ;
1046 }
1047 }
1048
1049 if (state > 1)
1050 {
1051 /* Finish the last entry. */
1052 num_entries++;
1053 config_entries[config_len++] = 0;
1054 }
1055 else
1056 {
1057 menu_len = prev_menu_len;
1058 config_len = prev_config_len;
1059 }
1060
1061 menu_entries[menu_len++] = 0;
1062 config_entries[config_len++] = 0;
1063 grub_memmove (config_entries + config_len, menu_entries,
1064 menu_len);
1065 menu_entries = config_entries + config_len;
1066
1067 /* Make sure that all fallback entries are valid. */
1068 if (fallback_entryno >= 0)
1069 {
1070 for (i = 0; i < MAX_FALLBACK_ENTRIES; i++)
1071 {
1072 if (fallback_entries[i] < 0)
1073 break;
1074 if (fallback_entries[i] >= num_entries)
1075 {
1076 grub_memmove (fallback_entries + i,
1077 fallback_entries + i + 1,
1078 ((MAX_FALLBACK_ENTRIES - i - 1)
1079 * sizeof (int)));
1080 i--;
1081 }
1082 }
1083
1084 if (fallback_entries[0] < 0)
1085 fallback_entryno = -1;
1086 }
1087 /* Check if the default entry is present. Otherwise reset
1088 it to fallback if fallback is valid, or to DEFAULT_ENTRY
1089 if not. */
1090 if (default_entry >= num_entries)
1091 {
1092 if (fallback_entryno >= 0)
1093 {
1094 default_entry = fallback_entries[0];
1095 fallback_entryno++;
1096 if (fallback_entryno >= MAX_FALLBACK_ENTRIES
1097 || fallback_entries[fallback_entryno] < 0)
1098 fallback_entryno = -1;
1099 }
1100 else
1101 default_entry = 0;
1102 }
1103
1104 if (is_preset)
1105 close_preset_menu ();
1106 else
1107 grub_close ();
1108 }
1109 while (is_preset);
1110 }
1111
1112 /* go ahead and make sure the terminal is setup */
1113 if (current_term->startup)
1114 (*current_term->startup)();
1115
1116 if (! num_entries)
1117 {
1118 /* If no acceptable config file, goto command-line, starting
1119 heap from where the config entries would have been stored
1120 if there were any. */
1121 enter_cmdline (config_entries, 1);
1122 }
1123 else
1124 {
1125 /* Run menu interface. */
1126 run_menu (menu_entries, config_entries, num_entries,
1127 menu_entries + menu_len, default_entry);
1128 }
1129 }
1130 }
1131