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