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