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