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 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 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 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 * 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 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 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 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 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 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 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 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