1 /* builtins.c - the GRUB builtin commands */ 2 /* 3 * GRUB -- GRand Unified Bootloader 4 * Copyright (C) 1999,2000,2001,2002,2003,2004 Free Software Foundation, Inc. 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 */ 20 21 /* Include stdio.h before shared.h, because we can't define 22 WITHOUT_LIBC_STUBS here. */ 23 #ifdef GRUB_UTIL 24 # include <stdio.h> 25 #endif 26 27 #include <shared.h> 28 #include <filesys.h> 29 #include <term.h> 30 31 #ifdef SUPPORT_NETBOOT 32 # include <grub.h> 33 #endif 34 35 #ifdef SUPPORT_SERIAL 36 # include <serial.h> 37 # include <terminfo.h> 38 #endif 39 40 #ifdef GRUB_UTIL 41 # include <device.h> 42 #else /* ! GRUB_UTIL */ 43 # include <apic.h> 44 # include <smp-imps.h> 45 #endif /* ! GRUB_UTIL */ 46 47 #ifdef USE_MD5_PASSWORDS 48 # include <md5.h> 49 #endif 50 51 /* The type of kernel loaded. */ 52 kernel_t kernel_type; 53 /* The boot device. */ 54 static int bootdev; 55 /* True when the debug mode is turned on, and false 56 when it is turned off. */ 57 int debug = 0; 58 /* The default entry. */ 59 int default_entry = 0; 60 /* The fallback entry. */ 61 int fallback_entryno; 62 int fallback_entries[MAX_FALLBACK_ENTRIES]; 63 /* The number of current entry. */ 64 int current_entryno; 65 /* The address for Multiboot command-line buffer. */ 66 static char *mb_cmdline; 67 /* The password. */ 68 char *password; 69 /* The password type. */ 70 password_t password_type; 71 /* The flag for indicating that the user is authoritative. */ 72 int auth = 0; 73 /* The timeout. */ 74 int grub_timeout = -1; 75 /* Whether to show the menu or not. */ 76 int show_menu = 1; 77 /* The BIOS drive map. */ 78 static unsigned short bios_drive_map[DRIVE_MAP_SIZE + 1]; 79 80 /* Prototypes for allowing straightfoward calling of builtins functions 81 inside other functions. */ 82 static int configfile_func (char *arg, int flags); 83 #ifdef SUPPORT_NETBOOT 84 static void solaris_config_file (void); 85 #endif 86 87 #if defined(__sun) && !defined(GRUB_UTIL) 88 extern void __enable_execute_stack (void *); 89 void 90 __enable_execute_stack (void *addr) 91 { 92 } 93 #endif /* __sun && !GRUB_UTIL */ 94 95 /* Initialize the data for builtins. */ 96 void 97 init_builtins (void) 98 { 99 kernel_type = KERNEL_TYPE_NONE; 100 /* BSD and chainloading evil hacks! */ 101 bootdev = set_bootdev (0); 102 mb_cmdline = (char *) MB_CMDLINE_BUF; 103 } 104 105 /* Initialize the data for the configuration file. */ 106 void 107 init_config (void) 108 { 109 default_entry = 0; 110 password = 0; 111 fallback_entryno = -1; 112 fallback_entries[0] = -1; 113 grub_timeout = -1; 114 } 115 116 /* Check a password for correctness. Returns 0 if password was 117 correct, and a value != 0 for error, similarly to strcmp. */ 118 int 119 check_password (char *entered, char* expected, password_t type) 120 { 121 switch (type) 122 { 123 case PASSWORD_PLAIN: 124 return strcmp (entered, expected); 125 126 #ifdef USE_MD5_PASSWORDS 127 case PASSWORD_MD5: 128 return check_md5_password (entered, expected); 129 #endif 130 default: 131 /* unsupported password type: be secure */ 132 return 1; 133 } 134 } 135 136 /* Print which sector is read when loading a file. */ 137 static void 138 disk_read_print_func (int sector, int offset, int length) 139 { 140 grub_printf ("[%d,%d,%d]", sector, offset, length); 141 } 142 143 144 /* blocklist */ 145 static int 146 blocklist_func (char *arg, int flags) 147 { 148 char *dummy = (char *) RAW_ADDR (0x100000); 149 int start_sector; 150 int num_sectors = 0; 151 int num_entries = 0; 152 int last_length = 0; 153 154 /* Collect contiguous blocks into one entry as many as possible, 155 and print the blocklist notation on the screen. */ 156 static void disk_read_blocklist_func (int sector, int offset, int length) 157 { 158 if (num_sectors > 0) 159 { 160 if (start_sector + num_sectors == sector 161 && offset == 0 && last_length == SECTOR_SIZE) 162 { 163 num_sectors++; 164 last_length = length; 165 return; 166 } 167 else 168 { 169 if (last_length == SECTOR_SIZE) 170 grub_printf ("%s%d+%d", num_entries ? "," : "", 171 start_sector - part_start, num_sectors); 172 else if (num_sectors > 1) 173 grub_printf ("%s%d+%d,%d[0-%d]", num_entries ? "," : "", 174 start_sector - part_start, num_sectors-1, 175 start_sector + num_sectors-1 - part_start, 176 last_length); 177 else 178 grub_printf ("%s%d[0-%d]", num_entries ? "," : "", 179 start_sector - part_start, last_length); 180 num_entries++; 181 num_sectors = 0; 182 } 183 } 184 185 if (offset > 0) 186 { 187 grub_printf("%s%d[%d-%d]", num_entries ? "," : "", 188 sector-part_start, offset, offset+length); 189 num_entries++; 190 } 191 else 192 { 193 start_sector = sector; 194 num_sectors = 1; 195 last_length = length; 196 } 197 } 198 199 /* Open the file. */ 200 if (! grub_open (arg)) 201 return 1; 202 203 /* Print the device name. */ 204 grub_printf ("(%cd%d", 205 (current_drive & 0x80) ? 'h' : 'f', 206 current_drive & ~0x80); 207 208 if ((current_partition & 0xFF0000) != 0xFF0000) 209 grub_printf (",%d", (current_partition >> 16) & 0xFF); 210 211 if ((current_partition & 0x00FF00) != 0x00FF00) 212 grub_printf (",%c", 'a' + ((current_partition >> 8) & 0xFF)); 213 214 grub_printf (")"); 215 216 /* Read in the whole file to DUMMY. */ 217 disk_read_hook = disk_read_blocklist_func; 218 if (! grub_read (dummy, -1)) 219 goto fail; 220 221 /* The last entry may not be printed yet. Don't check if it is a 222 * full sector, since it doesn't matter if we read too much. */ 223 if (num_sectors > 0) 224 grub_printf ("%s%d+%d", num_entries ? "," : "", 225 start_sector - part_start, num_sectors); 226 227 grub_printf ("\n"); 228 229 fail: 230 disk_read_hook = 0; 231 grub_close (); 232 return errnum; 233 } 234 235 static struct builtin builtin_blocklist = 236 { 237 "blocklist", 238 blocklist_func, 239 BUILTIN_CMDLINE | BUILTIN_HELP_LIST, 240 "blocklist FILE", 241 "Print the blocklist notation of the file FILE." 242 }; 243 244 /* boot */ 245 static int 246 boot_func (char *arg, int flags) 247 { 248 /* Clear the int15 handler if we can boot the kernel successfully. 249 This assumes that the boot code never fails only if KERNEL_TYPE is 250 not KERNEL_TYPE_NONE. Is this assumption is bad? */ 251 if (kernel_type != KERNEL_TYPE_NONE) 252 unset_int15_handler (); 253 254 #ifdef SUPPORT_NETBOOT 255 /* Shut down the networking. */ 256 cleanup_net (); 257 #endif 258 259 switch (kernel_type) 260 { 261 case KERNEL_TYPE_FREEBSD: 262 case KERNEL_TYPE_NETBSD: 263 /* *BSD */ 264 bsd_boot (kernel_type, bootdev, (char *) mbi.cmdline); 265 break; 266 267 case KERNEL_TYPE_LINUX: 268 /* Linux */ 269 linux_boot (); 270 break; 271 272 case KERNEL_TYPE_BIG_LINUX: 273 /* Big Linux */ 274 big_linux_boot (); 275 break; 276 277 case KERNEL_TYPE_CHAINLOADER: 278 /* Chainloader */ 279 280 /* Check if we should set the int13 handler. */ 281 if (bios_drive_map[0] != 0) 282 { 283 int i; 284 285 /* Search for SAVED_DRIVE. */ 286 for (i = 0; i < DRIVE_MAP_SIZE; i++) 287 { 288 if (! bios_drive_map[i]) 289 break; 290 else if ((bios_drive_map[i] & 0xFF) == saved_drive) 291 { 292 /* Exchage SAVED_DRIVE with the mapped drive. */ 293 saved_drive = (bios_drive_map[i] >> 8) & 0xFF; 294 break; 295 } 296 } 297 298 /* Set the handler. This is somewhat dangerous. */ 299 set_int13_handler (bios_drive_map); 300 } 301 302 gateA20 (0); 303 boot_drive = saved_drive; 304 chain_stage1 (0, BOOTSEC_LOCATION, boot_part_addr); 305 break; 306 307 case KERNEL_TYPE_MULTIBOOT: 308 /* Multiboot */ 309 #ifdef SUPPORT_NETBOOT 310 #ifdef SOLARIS_NETBOOT 311 if (current_drive == NETWORK_DRIVE) { 312 /* 313 * XXX Solaris hack: use drive_info to pass network information 314 * Turn off the flag bit to the loader is technically 315 * multiboot compliant. 316 */ 317 mbi.flags &= ~MB_INFO_DRIVE_INFO; 318 mbi.drives_length = dhcpack_length; 319 mbi.drives_addr = dhcpack_buf; 320 } 321 #endif /* SOLARIS_NETBOOT */ 322 #endif 323 multi_boot ((int) entry_addr, (int) &mbi); 324 break; 325 326 default: 327 errnum = ERR_BOOT_COMMAND; 328 return 1; 329 } 330 331 return 0; 332 } 333 334 static struct builtin builtin_boot = 335 { 336 "boot", 337 boot_func, 338 BUILTIN_CMDLINE | BUILTIN_HELP_LIST, 339 "boot", 340 "Boot the OS/chain-loader which has been loaded." 341 }; 342 343 344 #ifdef SUPPORT_NETBOOT 345 /* bootp */ 346 static int 347 bootp_func (char *arg, int flags) 348 { 349 int with_configfile = 0; 350 351 if (grub_memcmp (arg, "--with-configfile", sizeof ("--with-configfile") - 1) 352 == 0) 353 { 354 with_configfile = 1; 355 arg = skip_to (0, arg); 356 } 357 358 if (! bootp ()) 359 { 360 if (errnum == ERR_NONE) 361 errnum = ERR_DEV_VALUES; 362 363 return 1; 364 } 365 366 /* Notify the configuration. */ 367 print_network_configuration (); 368 369 /* XXX: this can cause an endless loop, but there is no easy way to 370 detect such a loop unfortunately. */ 371 if (with_configfile) 372 configfile_func (config_file, flags); 373 374 return 0; 375 } 376 377 static struct builtin builtin_bootp = 378 { 379 "bootp", 380 bootp_func, 381 BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST, 382 "bootp [--with-configfile]", 383 "Initialize a network device via BOOTP. If the option `--with-configfile'" 384 " is given, try to load a configuration file specified by the 150 vendor" 385 " tag." 386 }; 387 #endif /* SUPPORT_NETBOOT */ 388 389 390 /* cat */ 391 static int 392 cat_func (char *arg, int flags) 393 { 394 char c; 395 396 if (! grub_open (arg)) 397 return 1; 398 399 while (grub_read (&c, 1)) 400 { 401 /* Because running "cat" with a binary file can confuse the terminal, 402 print only some characters as they are. */ 403 if (grub_isspace (c) || (c >= ' ' && c <= '~')) 404 grub_putchar (c); 405 else 406 grub_putchar ('?'); 407 } 408 409 grub_close (); 410 return 0; 411 } 412 413 static struct builtin builtin_cat = 414 { 415 "cat", 416 cat_func, 417 BUILTIN_CMDLINE | BUILTIN_HELP_LIST, 418 "cat FILE", 419 "Print the contents of the file FILE." 420 }; 421 422 423 /* chainloader */ 424 static int 425 chainloader_func (char *arg, int flags) 426 { 427 int force = 0; 428 char *file = arg; 429 430 /* If the option `--force' is specified? */ 431 if (substring ("--force", arg) <= 0) 432 { 433 force = 1; 434 file = skip_to (0, arg); 435 } 436 437 /* Open the file. */ 438 if (! grub_open (file)) 439 { 440 kernel_type = KERNEL_TYPE_NONE; 441 return 1; 442 } 443 444 /* Read the first block. */ 445 if (grub_read ((char *) BOOTSEC_LOCATION, SECTOR_SIZE) != SECTOR_SIZE) 446 { 447 grub_close (); 448 kernel_type = KERNEL_TYPE_NONE; 449 450 /* This below happens, if a file whose size is less than 512 bytes 451 is loaded. */ 452 if (errnum == ERR_NONE) 453 errnum = ERR_EXEC_FORMAT; 454 455 return 1; 456 } 457 458 /* If not loading it forcibly, check for the signature. */ 459 if (! force 460 && (*((unsigned short *) (BOOTSEC_LOCATION + BOOTSEC_SIG_OFFSET)) 461 != BOOTSEC_SIGNATURE)) 462 { 463 grub_close (); 464 errnum = ERR_EXEC_FORMAT; 465 kernel_type = KERNEL_TYPE_NONE; 466 return 1; 467 } 468 469 grub_close (); 470 kernel_type = KERNEL_TYPE_CHAINLOADER; 471 472 /* XXX: Windows evil hack. For now, only the first five letters are 473 checked. */ 474 if (IS_PC_SLICE_TYPE_FAT (current_slice) 475 && ! grub_memcmp ((char *) BOOTSEC_LOCATION + BOOTSEC_BPB_SYSTEM_ID, 476 "MSWIN", 5)) 477 *((unsigned long *) (BOOTSEC_LOCATION + BOOTSEC_BPB_HIDDEN_SECTORS)) 478 = part_start; 479 480 errnum = ERR_NONE; 481 482 return 0; 483 } 484 485 static struct builtin builtin_chainloader = 486 { 487 "chainloader", 488 chainloader_func, 489 BUILTIN_CMDLINE | BUILTIN_HELP_LIST, 490 "chainloader [--force] FILE", 491 "Load the chain-loader FILE. If --force is specified, then load it" 492 " forcibly, whether the boot loader signature is present or not." 493 }; 494 495 496 /* This function could be used to debug new filesystem code. Put a file 497 in the new filesystem and the same file in a well-tested filesystem. 498 Then, run "cmp" with the files. If no output is obtained, probably 499 the code is good, otherwise investigate what's wrong... */ 500 /* cmp FILE1 FILE2 */ 501 static int 502 cmp_func (char *arg, int flags) 503 { 504 /* The filenames. */ 505 char *file1, *file2; 506 /* The addresses. */ 507 char *addr1, *addr2; 508 int i; 509 /* The size of the file. */ 510 int size; 511 512 /* Get the filenames from ARG. */ 513 file1 = arg; 514 file2 = skip_to (0, arg); 515 if (! *file1 || ! *file2) 516 { 517 errnum = ERR_BAD_ARGUMENT; 518 return 1; 519 } 520 521 /* Terminate the filenames for convenience. */ 522 nul_terminate (file1); 523 nul_terminate (file2); 524 525 /* Read the whole data from FILE1. */ 526 addr1 = (char *) RAW_ADDR (0x100000); 527 if (! grub_open (file1)) 528 return 1; 529 530 /* Get the size. */ 531 size = filemax; 532 if (grub_read (addr1, -1) != size) 533 { 534 grub_close (); 535 return 1; 536 } 537 538 grub_close (); 539 540 /* Read the whole data from FILE2. */ 541 addr2 = addr1 + size; 542 if (! grub_open (file2)) 543 return 1; 544 545 /* Check if the size of FILE2 is equal to the one of FILE2. */ 546 if (size != filemax) 547 { 548 grub_printf ("Differ in size: 0x%x [%s], 0x%x [%s]\n", 549 size, file1, filemax, file2); 550 grub_close (); 551 return 0; 552 } 553 554 if (! grub_read (addr2, -1)) 555 { 556 grub_close (); 557 return 1; 558 } 559 560 grub_close (); 561 562 /* Now compare ADDR1 with ADDR2. */ 563 for (i = 0; i < size; i++) 564 { 565 if (addr1[i] != addr2[i]) 566 grub_printf ("Differ at the offset %d: 0x%x [%s], 0x%x [%s]\n", 567 i, (unsigned) addr1[i], file1, 568 (unsigned) addr2[i], file2); 569 } 570 571 return 0; 572 } 573 574 static struct builtin builtin_cmp = 575 { 576 "cmp", 577 cmp_func, 578 BUILTIN_CMDLINE, 579 "cmp FILE1 FILE2", 580 "Compare the file FILE1 with the FILE2 and inform the different values" 581 " if any." 582 }; 583 584 585 /* color */ 586 /* Set new colors used for the menu interface. Support two methods to 587 specify a color name: a direct integer representation and a symbolic 588 color name. An example of the latter is "blink-light-gray/blue". */ 589 static int 590 color_func (char *arg, int flags) 591 { 592 char *normal; 593 char *highlight; 594 int new_normal_color; 595 int new_highlight_color; 596 static char *color_list[16] = 597 { 598 "black", 599 "blue", 600 "green", 601 "cyan", 602 "red", 603 "magenta", 604 "brown", 605 "light-gray", 606 "dark-gray", 607 "light-blue", 608 "light-green", 609 "light-cyan", 610 "light-red", 611 "light-magenta", 612 "yellow", 613 "white" 614 }; 615 616 /* Convert the color name STR into the magical number. */ 617 static int color_number (char *str) 618 { 619 char *ptr; 620 int i; 621 int color = 0; 622 623 /* Find the separator. */ 624 for (ptr = str; *ptr && *ptr != '/'; ptr++) 625 ; 626 627 /* If not found, return -1. */ 628 if (! *ptr) 629 return -1; 630 631 /* Terminate the string STR. */ 632 *ptr++ = 0; 633 634 /* If STR contains the prefix "blink-", then set the `blink' bit 635 in COLOR. */ 636 if (substring ("blink-", str) <= 0) 637 { 638 color = 0x80; 639 str += 6; 640 } 641 642 /* Search for the color name. */ 643 for (i = 0; i < 16; i++) 644 if (grub_strcmp (color_list[i], str) == 0) 645 { 646 color |= i; 647 break; 648 } 649 650 if (i == 16) 651 return -1; 652 653 str = ptr; 654 nul_terminate (str); 655 656 /* Search for the color name. */ 657 for (i = 0; i < 8; i++) 658 if (grub_strcmp (color_list[i], str) == 0) 659 { 660 color |= i << 4; 661 break; 662 } 663 664 if (i == 8) 665 return -1; 666 667 return color; 668 } 669 670 normal = arg; 671 highlight = skip_to (0, arg); 672 673 new_normal_color = color_number (normal); 674 if (new_normal_color < 0 && ! safe_parse_maxint (&normal, &new_normal_color)) 675 return 1; 676 677 /* The second argument is optional, so set highlight_color 678 to inverted NORMAL_COLOR. */ 679 if (! *highlight) 680 new_highlight_color = ((new_normal_color >> 4) 681 | ((new_normal_color & 0xf) << 4)); 682 else 683 { 684 new_highlight_color = color_number (highlight); 685 if (new_highlight_color < 0 686 && ! safe_parse_maxint (&highlight, &new_highlight_color)) 687 return 1; 688 } 689 690 if (current_term->setcolor) 691 current_term->setcolor (new_normal_color, new_highlight_color); 692 693 return 0; 694 } 695 696 static struct builtin builtin_color = 697 { 698 "color", 699 color_func, 700 BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST, 701 "color NORMAL [HIGHLIGHT]", 702 "Change the menu colors. The color NORMAL is used for most" 703 " lines in the menu, and the color HIGHLIGHT is used to highlight the" 704 " line where the cursor points. If you omit HIGHLIGHT, then the" 705 " inverted color of NORMAL is used for the highlighted line." 706 " The format of a color is \"FG/BG\". FG and BG are symbolic color names." 707 " A symbolic color name must be one of these: black, blue, green," 708 " cyan, red, magenta, brown, light-gray, dark-gray, light-blue," 709 " light-green, light-cyan, light-red, light-magenta, yellow and white." 710 " But only the first eight names can be used for BG. You can prefix" 711 " \"blink-\" to FG if you want a blinking foreground color." 712 }; 713 714 715 /* configfile */ 716 static int 717 configfile_func (char *arg, int flags) 718 { 719 char *new_config = config_file; 720 721 /* Check if the file ARG is present. */ 722 if (! grub_open (arg)) 723 return 1; 724 725 grub_close (); 726 727 /* Copy ARG to CONFIG_FILE. */ 728 while ((*new_config++ = *arg++) != 0) 729 ; 730 731 #ifdef GRUB_UTIL 732 /* Force to load the configuration file. */ 733 use_config_file = 1; 734 #endif 735 736 /* Make sure that the user will not be authoritative. */ 737 auth = 0; 738 739 /* Restart cmain. */ 740 grub_longjmp (restart_env, 0); 741 742 /* Never reach here. */ 743 return 0; 744 } 745 746 static struct builtin builtin_configfile = 747 { 748 "configfile", 749 configfile_func, 750 BUILTIN_CMDLINE | BUILTIN_HELP_LIST, 751 "configfile FILE", 752 "Load FILE as the configuration file." 753 }; 754 755 756 /* debug */ 757 static int 758 debug_func (char *arg, int flags) 759 { 760 if (debug) 761 { 762 debug = 0; 763 grub_printf (" Debug mode is turned off\n"); 764 } 765 else 766 { 767 debug = 1; 768 grub_printf (" Debug mode is turned on\n"); 769 } 770 771 return 0; 772 } 773 774 static struct builtin builtin_debug = 775 { 776 "debug", 777 debug_func, 778 BUILTIN_CMDLINE, 779 "debug", 780 "Turn on/off the debug mode." 781 }; 782 783 784 /* default */ 785 static int 786 default_func (char *arg, int flags) 787 { 788 #ifndef SUPPORT_DISKLESS 789 if (grub_strcmp (arg, "saved") == 0) 790 { 791 default_entry = saved_entryno; 792 return 0; 793 } 794 #endif /* SUPPORT_DISKLESS */ 795 796 if (! safe_parse_maxint (&arg, &default_entry)) 797 return 1; 798 799 return 0; 800 } 801 802 static struct builtin builtin_default = 803 { 804 "default", 805 default_func, 806 BUILTIN_MENU, 807 #if 0 808 "default [NUM | `saved']", 809 "Set the default entry to entry number NUM (if not specified, it is" 810 " 0, the first entry) or the entry number saved by savedefault." 811 #endif 812 }; 813 814 815 #ifdef GRUB_UTIL 816 /* device */ 817 static int 818 device_func (char *arg, int flags) 819 { 820 char *drive = arg; 821 char *device; 822 823 /* Get the drive number from DRIVE. */ 824 if (! set_device (drive)) 825 return 1; 826 827 /* Get the device argument. */ 828 device = skip_to (0, drive); 829 830 /* Terminate DEVICE. */ 831 nul_terminate (device); 832 833 if (! *device || ! check_device (device)) 834 { 835 errnum = ERR_FILE_NOT_FOUND; 836 return 1; 837 } 838 839 assign_device_name (current_drive, device); 840 841 return 0; 842 } 843 844 static struct builtin builtin_device = 845 { 846 "device", 847 device_func, 848 BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST, 849 "device DRIVE DEVICE", 850 "Specify DEVICE as the actual drive for a BIOS drive DRIVE. This command" 851 " can be used only in the grub shell." 852 }; 853 #endif /* GRUB_UTIL */ 854 855 #ifdef SUPPORT_NETBOOT 856 /* Debug Function for RPC */ 857 #ifdef RPC_DEBUG 858 /* portmap */ 859 static int 860 portmap_func (char *arg, int flags) 861 { 862 int port, prog, ver; 863 if (! grub_eth_probe ()){ 864 grub_printf ("No ethernet card found.\n"); 865 errnum = ERR_DEV_VALUES; 866 return 1; 867 } 868 if ((prog = getdec(&arg)) == -1){ 869 grub_printf("Error prog number\n"); 870 return 1; 871 } 872 arg = skip_to (0, arg); 873 if ((ver = getdec(&arg)) == -1){ 874 grub_printf("Error ver number\n"); 875 return 1; 876 } 877 port = __pmapudp_getport(ARP_SERVER, prog, ver); 878 printf("portmap getport %d", port); 879 return 0; 880 } 881 882 static struct builtin builtin_portmap = 883 { 884 "portmap", 885 portmap_func, 886 BUILTIN_CMDLINE | BUILTIN_HELP_LIST, 887 "portmap prog_number vers_number", 888 "Do portmap with the prog_number and vers_number" 889 }; 890 #endif /* RPC_DEBUG */ 891 892 /* dhcp */ 893 static int 894 dhcp_func (char *arg, int flags) 895 { 896 int with_configfile = 0; 897 898 if (grub_memcmp (arg, "--with-configfile", sizeof ("--with-configfile") - 1) 899 == 0) 900 { 901 with_configfile = 1; 902 arg = skip_to (0, arg); 903 } 904 905 if (! dhcp ()) 906 { 907 if (errnum == ERR_NONE) 908 errnum = ERR_DEV_VALUES; 909 910 return 1; 911 } 912 913 /* Notify the configuration. */ 914 print_network_configuration (); 915 916 /* XXX: this can cause an endless loop, but there is no easy way to 917 detect such a loop unfortunately. */ 918 if (with_configfile) 919 configfile_func (config_file, flags); 920 else 921 solaris_config_file(); 922 923 return 0; 924 } 925 926 static void solaris_config_file (void) 927 { 928 static char menufile[64]; 929 static char hexdigit[] = "0123456789ABCDEF"; 930 char *c = menufile; 931 int i; 932 int err; 933 934 /* if config_file is from DHCP option 150, keep the setting */ 935 if (grub_strcmp(config_file, "/boot/grub/menu.lst") != 0) 936 return; 937 938 /* default solaris configfile name menu.lst.01<ether_addr> */ 939 grub_strcpy(c, "menu.lst.01"); 940 c += grub_strlen(c); 941 for (i = 0; i < ETH_ALEN; i++) { 942 unsigned char b = arptable[ARP_CLIENT].node[i]; 943 *c++ = hexdigit[b >> 4]; 944 *c++ = hexdigit[b & 0xf]; 945 } 946 *c = 0; 947 948 /* 949 * If the file exists, make it the default. Else, fallback 950 * to what it was. Make sure we don't change errnum in the 951 * process. 952 */ 953 err = errnum; 954 if (grub_open(menufile)) { 955 grub_strcpy(config_file, menufile); 956 grub_close(); 957 } else { 958 char *cp = config_file; 959 /* skip leading slashes for tftp */ 960 while (*cp == '/') 961 ++cp; 962 grub_memmove (config_file, cp, strlen(cp) + 1); 963 } 964 errnum = err; 965 } 966 967 static struct builtin builtin_dhcp = 968 { 969 "dhcp", 970 dhcp_func, 971 BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST, 972 "dhcp", 973 "Initialize a network device via DHCP." 974 }; 975 #endif /* SUPPORT_NETBOOT */ 976 977 static int terminal_func (char *arg, int flags); 978 979 static int verbose_func(char *arg, int flags) { 980 981 if (grub_strcmp(arg, "off") == 0) { 982 silent.status = DEFER_SILENT; 983 return; 984 } else 985 if (flags == BUILTIN_CMDLINE) { 986 silent.status = DEFER_VERBOSE; 987 return; 988 } 989 990 silent.status = VERBOSE; 991 992 /* get back to text console XXX setje -- tty??? */ 993 if (current_term->shutdown) { 994 (*current_term->shutdown)(); 995 current_term = term_table; /* assumption: console is first */ 996 } 997 998 /* dump the buffer */ 999 if (!silent.looped) { 1000 /* if the buffer hasn't looped, just print it */ 1001 printf("%s", silent.buffer); 1002 } else { 1003 /* 1004 * If the buffer has looped, first print the oldest part of the buffer, 1005 * which is one past the current null. Then print the newer part which 1006 * starts at the beginning of the buffer. 1007 */ 1008 printf("%s", silent.buffer_start + 1); 1009 printf("%s", silent.buffer); 1010 } 1011 1012 return 0; 1013 } 1014 1015 static struct builtin builtin_verbose = 1016 { 1017 "verbose", 1018 verbose_func, 1019 BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_SCRIPT | BUILTIN_HELP_LIST, 1020 "verbose", 1021 "Verbose output during menu entry (script) execution." 1022 }; 1023 1024 #ifdef SUPPORT_GRAPHICS 1025 1026 static int splashimage_func(char *arg, int flags) { 1027 char splashimage[64]; 1028 int i; 1029 1030 /* filename can only be 64 characters due to our buffer size */ 1031 if (strlen(arg) > 63) 1032 return 1; 1033 1034 if (flags == BUILTIN_SCRIPT) 1035 flags = BUILTIN_CMDLINE; 1036 1037 if (flags == BUILTIN_CMDLINE) { 1038 if (!grub_open(arg)) 1039 return 1; 1040 grub_close(); 1041 } 1042 1043 strcpy(splashimage, arg); 1044 1045 /* get rid of TERM_NEED_INIT from the graphics terminal. */ 1046 for (i = 0; term_table[i].name; i++) { 1047 if (grub_strcmp (term_table[i].name, "graphics") == 0) { 1048 term_table[i].flags &= ~TERM_NEED_INIT; 1049 break; 1050 } 1051 } 1052 1053 graphics_set_splash(splashimage); 1054 1055 if (flags == BUILTIN_CMDLINE && graphics_inited) { 1056 /* 1057 * calling graphics_end() here flickers the screen black. OTOH not 1058 * calling it gets us odd plane interlacing / early palette switching ? 1059 * ideally one should figure out how to double buffer and switch... 1060 */ 1061 graphics_end(); 1062 graphics_init(); 1063 graphics_cls(); 1064 } 1065 1066 /* FIXME: should we be explicitly switching the terminal as a 1067 * side effect here? */ 1068 terminal_func("graphics", flags); 1069 1070 reset_term = 0; 1071 1072 return 0; 1073 } 1074 1075 static struct builtin builtin_splashimage = 1076 { 1077 "splashimage", 1078 splashimage_func, 1079 BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_SCRIPT | BUILTIN_HELP_LIST, 1080 "splashimage FILE", 1081 "Load FILE as the background image when in graphics mode." 1082 }; 1083 1084 1085 /* foreground */ 1086 static int 1087 foreground_func(char *arg, int flags) 1088 { 1089 if (grub_strlen(arg) == 6) { 1090 int r = ((hex(arg[0]) << 4) | hex(arg[1])) >> 2; 1091 int g = ((hex(arg[2]) << 4) | hex(arg[3])) >> 2; 1092 int b = ((hex(arg[4]) << 4) | hex(arg[5])) >> 2; 1093 1094 foreground = (r << 16) | (g << 8) | b; 1095 if (graphics_inited) 1096 graphics_set_palette(15, r, g, b); 1097 1098 return (0); 1099 } 1100 1101 return (1); 1102 } 1103 1104 static struct builtin builtin_foreground = 1105 { 1106 "foreground", 1107 foreground_func, 1108 BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST, 1109 "foreground RRGGBB", 1110 "Sets the foreground color when in graphics mode." 1111 "RR is red, GG is green, and BB blue. Numbers must be in hexadecimal." 1112 }; 1113 1114 1115 /* background */ 1116 static int 1117 background_func(char *arg, int flags) 1118 { 1119 if (grub_strlen(arg) == 6) { 1120 int r = ((hex(arg[0]) << 4) | hex(arg[1])) >> 2; 1121 int g = ((hex(arg[2]) << 4) | hex(arg[3])) >> 2; 1122 int b = ((hex(arg[4]) << 4) | hex(arg[5])) >> 2; 1123 1124 background = (r << 16) | (g << 8) | b; 1125 if (graphics_inited) 1126 graphics_set_palette(0, r, g, b); 1127 return (0); 1128 } 1129 1130 return (1); 1131 } 1132 1133 static struct builtin builtin_background = 1134 { 1135 "background", 1136 background_func, 1137 BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST, 1138 "background RRGGBB", 1139 "Sets the background color when in graphics mode." 1140 "RR is red, GG is green, and BB blue. Numbers must be in hexadecimal." 1141 }; 1142 1143 #endif /* SUPPORT_GRAPHICS */ 1144 1145 1146 /* clear */ 1147 static int 1148 clear_func() 1149 { 1150 if (current_term->cls) 1151 current_term->cls(); 1152 1153 return 0; 1154 } 1155 1156 static struct builtin builtin_clear = 1157 { 1158 "clear", 1159 clear_func, 1160 BUILTIN_CMDLINE | BUILTIN_HELP_LIST, 1161 "clear", 1162 "Clear the screen" 1163 }; 1164 1165 /* displayapm */ 1166 static int 1167 displayapm_func (char *arg, int flags) 1168 { 1169 if (mbi.flags & MB_INFO_APM_TABLE) 1170 { 1171 grub_printf ("APM BIOS information:\n" 1172 " Version: 0x%x\n" 1173 " 32-bit CS: 0x%x\n" 1174 " Offset: 0x%x\n" 1175 " 16-bit CS: 0x%x\n" 1176 " 16-bit DS: 0x%x\n" 1177 " 32-bit CS length: 0x%x\n" 1178 " 16-bit CS length: 0x%x\n" 1179 " 16-bit DS length: 0x%x\n", 1180 (unsigned) apm_bios_info.version, 1181 (unsigned) apm_bios_info.cseg, 1182 apm_bios_info.offset, 1183 (unsigned) apm_bios_info.cseg_16, 1184 (unsigned) apm_bios_info.dseg_16, 1185 (unsigned) apm_bios_info.cseg_len, 1186 (unsigned) apm_bios_info.cseg_16_len, 1187 (unsigned) apm_bios_info.dseg_16_len); 1188 } 1189 else 1190 { 1191 grub_printf ("No APM BIOS found or probe failed\n"); 1192 } 1193 1194 return 0; 1195 } 1196 1197 static struct builtin builtin_displayapm = 1198 { 1199 "displayapm", 1200 displayapm_func, 1201 BUILTIN_CMDLINE | BUILTIN_HELP_LIST, 1202 "displayapm", 1203 "Display APM BIOS information." 1204 }; 1205 1206 1207 /* displaymem */ 1208 static int 1209 displaymem_func (char *arg, int flags) 1210 { 1211 if (get_eisamemsize () != -1) 1212 grub_printf (" EISA Memory BIOS Interface is present\n"); 1213 if (get_mmap_entry ((void *) SCRATCHADDR, 0) != 0 1214 || *((int *) SCRATCHADDR) != 0) 1215 grub_printf (" Address Map BIOS Interface is present\n"); 1216 1217 grub_printf (" Lower memory: %uK, " 1218 "Upper memory (to first chipset hole): %uK\n", 1219 mbi.mem_lower, mbi.mem_upper); 1220 1221 if (mbi.flags & MB_INFO_MEM_MAP) 1222 { 1223 struct AddrRangeDesc *map = (struct AddrRangeDesc *) mbi.mmap_addr; 1224 int end_addr = mbi.mmap_addr + mbi.mmap_length; 1225 1226 grub_printf (" [Address Range Descriptor entries " 1227 "immediately follow (values are 64-bit)]\n"); 1228 while (end_addr > (int) map) 1229 { 1230 char *str; 1231 1232 if (map->Type == MB_ARD_MEMORY) 1233 str = "Usable RAM"; 1234 else 1235 str = "Reserved"; 1236 grub_printf (" %s: Base Address: 0x%x X 4GB + 0x%x,\n" 1237 " Length: 0x%x X 4GB + 0x%x bytes\n", 1238 str, 1239 (unsigned long) (map->BaseAddr >> 32), 1240 (unsigned long) (map->BaseAddr & 0xFFFFFFFF), 1241 (unsigned long) (map->Length >> 32), 1242 (unsigned long) (map->Length & 0xFFFFFFFF)); 1243 1244 map = ((struct AddrRangeDesc *) (((int) map) + 4 + map->size)); 1245 } 1246 } 1247 1248 return 0; 1249 } 1250 1251 static struct builtin builtin_displaymem = 1252 { 1253 "displaymem", 1254 displaymem_func, 1255 BUILTIN_CMDLINE | BUILTIN_HELP_LIST, 1256 "displaymem", 1257 "Display what GRUB thinks the system address space map of the" 1258 " machine is, including all regions of physical RAM installed." 1259 }; 1260 1261 1262 /* dump FROM TO */ 1263 #ifdef GRUB_UTIL 1264 static int 1265 dump_func (char *arg, int flags) 1266 { 1267 char *from, *to; 1268 FILE *fp; 1269 char c; 1270 1271 from = arg; 1272 to = skip_to (0, arg); 1273 if (! *from || ! *to) 1274 { 1275 errnum = ERR_BAD_ARGUMENT; 1276 return 1; 1277 } 1278 1279 nul_terminate (from); 1280 nul_terminate (to); 1281 1282 if (! grub_open (from)) 1283 return 1; 1284 1285 fp = fopen (to, "w"); 1286 if (! fp) 1287 { 1288 errnum = ERR_WRITE; 1289 return 1; 1290 } 1291 1292 while (grub_read (&c, 1)) 1293 if (fputc (c, fp) == EOF) 1294 { 1295 errnum = ERR_WRITE; 1296 fclose (fp); 1297 return 1; 1298 } 1299 1300 if (fclose (fp) == EOF) 1301 { 1302 errnum = ERR_WRITE; 1303 return 1; 1304 } 1305 1306 grub_close (); 1307 return 0; 1308 } 1309 1310 static struct builtin builtin_dump = 1311 { 1312 "dump", 1313 dump_func, 1314 BUILTIN_CMDLINE, 1315 "dump FROM TO", 1316 "Dump the contents of the file FROM to the file TO. FROM must be" 1317 " a GRUB file and TO must be an OS file." 1318 }; 1319 #endif /* GRUB_UTIL */ 1320 1321 1322 static char embed_info[32]; 1323 /* embed */ 1324 /* Embed a Stage 1.5 in the first cylinder after MBR or in the 1325 bootloader block in a FFS. */ 1326 static int 1327 embed_func (char *arg, int flags) 1328 { 1329 char *stage1_5; 1330 char *device; 1331 char *stage1_5_buffer = (char *) RAW_ADDR (0x100000); 1332 int len, size; 1333 int sector; 1334 1335 stage1_5 = arg; 1336 device = skip_to (0, stage1_5); 1337 1338 /* Open a Stage 1.5. */ 1339 if (! grub_open (stage1_5)) 1340 return 1; 1341 1342 /* Read the whole of the Stage 1.5. */ 1343 len = grub_read (stage1_5_buffer, -1); 1344 grub_close (); 1345 1346 if (errnum) 1347 return 1; 1348 1349 size = (len + SECTOR_SIZE - 1) / SECTOR_SIZE; 1350 1351 /* Get the device where the Stage 1.5 will be embedded. */ 1352 set_device (device); 1353 if (errnum) 1354 return 1; 1355 1356 if (current_partition == 0xFFFFFF) 1357 { 1358 /* Embed it after the MBR. */ 1359 1360 char mbr[SECTOR_SIZE]; 1361 char ezbios_check[2*SECTOR_SIZE]; 1362 int i; 1363 1364 /* Open the partition. */ 1365 if (! open_partition ()) 1366 return 1; 1367 1368 /* No floppy has MBR. */ 1369 if (! (current_drive & 0x80)) 1370 { 1371 errnum = ERR_DEV_VALUES; 1372 return 1; 1373 } 1374 1375 /* Read the MBR of CURRENT_DRIVE. */ 1376 if (! rawread (current_drive, PC_MBR_SECTOR, 0, SECTOR_SIZE, mbr)) 1377 return 1; 1378 1379 /* Sanity check. */ 1380 if (! PC_MBR_CHECK_SIG (mbr)) 1381 { 1382 errnum = ERR_BAD_PART_TABLE; 1383 return 1; 1384 } 1385 1386 /* Check if the disk can store the Stage 1.5. */ 1387 for (i = 0; i < 4; i++) 1388 if (PC_SLICE_TYPE (mbr, i) && PC_SLICE_START (mbr, i) - 1 < size) 1389 { 1390 errnum = ERR_NO_DISK_SPACE; 1391 return 1; 1392 } 1393 1394 /* Check for EZ-BIOS signature. It should be in the third 1395 * sector, but due to remapping it can appear in the second, so 1396 * load and check both. 1397 */ 1398 if (! rawread (current_drive, 1, 0, 2 * SECTOR_SIZE, ezbios_check)) 1399 return 1; 1400 1401 if (! memcmp (ezbios_check + 3, "AERMH", 5) 1402 || ! memcmp (ezbios_check + 512 + 3, "AERMH", 5)) 1403 { 1404 /* The space after the MBR is used by EZ-BIOS which we must 1405 * not overwrite. 1406 */ 1407 errnum = ERR_NO_DISK_SPACE; 1408 return 1; 1409 } 1410 1411 sector = 1; 1412 } 1413 else 1414 { 1415 /* Embed it in the bootloader block in the filesystem. */ 1416 int start_sector; 1417 1418 /* Open the partition. */ 1419 if (! open_device ()) 1420 return 1; 1421 1422 /* Check if the current slice supports embedding. */ 1423 if (fsys_table[fsys_type].embed_func == 0 1424 || ! fsys_table[fsys_type].embed_func (&start_sector, size)) 1425 { 1426 errnum = ERR_DEV_VALUES; 1427 return 1; 1428 } 1429 1430 sector = part_start + start_sector; 1431 } 1432 1433 /* Clear the cache. */ 1434 buf_track = -1; 1435 1436 /* Now perform the embedding. */ 1437 if (! devwrite (sector - part_start, size, stage1_5_buffer)) 1438 return 1; 1439 1440 grub_printf (" %d sectors are embedded.\n", size); 1441 grub_sprintf (embed_info, "%d+%d", sector - part_start, size); 1442 return 0; 1443 } 1444 1445 static struct builtin builtin_embed = 1446 { 1447 "embed", 1448 embed_func, 1449 BUILTIN_CMDLINE, 1450 "embed STAGE1_5 DEVICE", 1451 "Embed the Stage 1.5 STAGE1_5 in the sectors after MBR if DEVICE" 1452 " is a drive, or in the \"bootloader\" area if DEVICE is a FFS partition." 1453 " Print the number of sectors which STAGE1_5 occupies if successful." 1454 }; 1455 1456 1457 /* fallback */ 1458 static int 1459 fallback_func (char *arg, int flags) 1460 { 1461 int i = 0; 1462 1463 while (*arg) 1464 { 1465 int entry; 1466 int j; 1467 1468 if (! safe_parse_maxint (&arg, &entry)) 1469 return 1; 1470 1471 /* Remove duplications to prevent infinite looping. */ 1472 for (j = 0; j < i; j++) 1473 if (entry == fallback_entries[j]) 1474 break; 1475 if (j != i) 1476 continue; 1477 1478 fallback_entries[i++] = entry; 1479 if (i == MAX_FALLBACK_ENTRIES) 1480 break; 1481 1482 arg = skip_to (0, arg); 1483 } 1484 1485 if (i < MAX_FALLBACK_ENTRIES) 1486 fallback_entries[i] = -1; 1487 1488 fallback_entryno = (i == 0) ? -1 : 0; 1489 1490 return 0; 1491 } 1492 1493 static struct builtin builtin_fallback = 1494 { 1495 "fallback", 1496 fallback_func, 1497 BUILTIN_MENU, 1498 #if 0 1499 "fallback NUM...", 1500 "Go into unattended boot mode: if the default boot entry has any" 1501 " errors, instead of waiting for the user to do anything, it" 1502 " immediately starts over using the NUM entry (same numbering as the" 1503 " `default' command). This obviously won't help if the machine" 1504 " was rebooted by a kernel that GRUB loaded." 1505 #endif 1506 }; 1507 1508 1509 /* find */ 1510 /* Search for the filename ARG in all of partitions. */ 1511 static int 1512 find_func (char *arg, int flags) 1513 { 1514 char *filename = arg; 1515 unsigned long drive; 1516 unsigned long tmp_drive = saved_drive; 1517 unsigned long tmp_partition = saved_partition; 1518 int got_file = 0; 1519 1520 /* Floppies. */ 1521 for (drive = 0; drive < 8; drive++) 1522 { 1523 current_drive = drive; 1524 current_partition = 0xFFFFFF; 1525 1526 if (open_device ()) 1527 { 1528 saved_drive = current_drive; 1529 saved_partition = current_partition; 1530 if (grub_open (filename)) 1531 { 1532 grub_close (); 1533 grub_printf (" (fd%d)\n", drive); 1534 got_file = 1; 1535 } 1536 } 1537 1538 errnum = ERR_NONE; 1539 } 1540 1541 /* Hard disks. */ 1542 for (drive = 0x80; drive < 0x88; drive++) 1543 { 1544 unsigned long part = 0xFFFFFF; 1545 unsigned long start, len, offset, ext_offset; 1546 int type, entry; 1547 char buf[SECTOR_SIZE]; 1548 1549 current_drive = drive; 1550 while (next_partition (drive, 0xFFFFFF, &part, &type, 1551 &start, &len, &offset, &entry, 1552 &ext_offset, buf)) 1553 { 1554 if (type != PC_SLICE_TYPE_NONE 1555 && ! IS_PC_SLICE_TYPE_BSD (type) 1556 && ! IS_PC_SLICE_TYPE_EXTENDED (type)) 1557 { 1558 current_partition = part; 1559 if (open_device ()) 1560 { 1561 saved_drive = current_drive; 1562 saved_partition = current_partition; 1563 if (grub_open (filename)) 1564 { 1565 int bsd_part = (part >> 8) & 0xFF; 1566 int pc_slice = part >> 16; 1567 1568 grub_close (); 1569 1570 if (bsd_part == 0xFF) 1571 grub_printf (" (hd%d,%d)\n", 1572 drive - 0x80, pc_slice); 1573 else 1574 grub_printf (" (hd%d,%d,%c)\n", 1575 drive - 0x80, pc_slice, bsd_part + 'a'); 1576 1577 got_file = 1; 1578 } 1579 } 1580 } 1581 1582 /* We want to ignore any error here. */ 1583 errnum = ERR_NONE; 1584 } 1585 1586 /* next_partition always sets ERRNUM in the last call, so clear 1587 it. */ 1588 errnum = ERR_NONE; 1589 } 1590 1591 saved_drive = tmp_drive; 1592 saved_partition = tmp_partition; 1593 1594 if (got_file) 1595 { 1596 errnum = ERR_NONE; 1597 return 0; 1598 } 1599 1600 errnum = ERR_FILE_NOT_FOUND; 1601 return 1; 1602 } 1603 1604 static struct builtin builtin_find = 1605 { 1606 "find", 1607 find_func, 1608 BUILTIN_CMDLINE | BUILTIN_HELP_LIST, 1609 "find FILENAME", 1610 "Search for the filename FILENAME in all of partitions and print the list of" 1611 " the devices which contain the file." 1612 }; 1613 1614 1615 /* fstest */ 1616 static int 1617 fstest_func (char *arg, int flags) 1618 { 1619 if (disk_read_hook) 1620 { 1621 disk_read_hook = NULL; 1622 printf (" Filesystem tracing is now off\n"); 1623 } 1624 else 1625 { 1626 disk_read_hook = disk_read_print_func; 1627 printf (" Filesystem tracing is now on\n"); 1628 } 1629 1630 return 0; 1631 } 1632 1633 static struct builtin builtin_fstest = 1634 { 1635 "fstest", 1636 fstest_func, 1637 BUILTIN_CMDLINE, 1638 "fstest", 1639 "Toggle filesystem test mode." 1640 }; 1641 1642 1643 /* geometry */ 1644 static int 1645 geometry_func (char *arg, int flags) 1646 { 1647 struct geometry geom; 1648 char *msg; 1649 char *device = arg; 1650 #ifdef GRUB_UTIL 1651 char *ptr; 1652 #endif 1653 1654 /* Get the device number. */ 1655 set_device (device); 1656 if (errnum) 1657 return 1; 1658 1659 /* Check for the geometry. */ 1660 if (get_diskinfo (current_drive, &geom)) 1661 { 1662 errnum = ERR_NO_DISK; 1663 return 1; 1664 } 1665 1666 /* Attempt to read the first sector, because some BIOSes turns out not 1667 to support LBA even though they set the bit 0 in the support 1668 bitmap, only after reading something actually. */ 1669 if (biosdisk (BIOSDISK_READ, current_drive, &geom, 0, 1, SCRATCHSEG)) 1670 { 1671 errnum = ERR_READ; 1672 return 1; 1673 } 1674 1675 #ifdef GRUB_UTIL 1676 ptr = skip_to (0, device); 1677 if (*ptr) 1678 { 1679 char *cylinder, *head, *sector, *total_sector; 1680 int num_cylinder, num_head, num_sector, num_total_sector; 1681 1682 cylinder = ptr; 1683 head = skip_to (0, cylinder); 1684 sector = skip_to (0, head); 1685 total_sector = skip_to (0, sector); 1686 if (! safe_parse_maxint (&cylinder, &num_cylinder) 1687 || ! safe_parse_maxint (&head, &num_head) 1688 || ! safe_parse_maxint (§or, &num_sector)) 1689 return 1; 1690 1691 disks[current_drive].cylinders = num_cylinder; 1692 disks[current_drive].heads = num_head; 1693 disks[current_drive].sectors = num_sector; 1694 1695 if (safe_parse_maxint (&total_sector, &num_total_sector)) 1696 disks[current_drive].total_sectors = num_total_sector; 1697 else 1698 disks[current_drive].total_sectors 1699 = num_cylinder * num_head * num_sector; 1700 errnum = 0; 1701 1702 geom = disks[current_drive]; 1703 buf_drive = -1; 1704 } 1705 #endif /* GRUB_UTIL */ 1706 1707 #ifdef GRUB_UTIL 1708 msg = device_map[current_drive]; 1709 #else 1710 if (geom.flags & BIOSDISK_FLAG_LBA_EXTENSION) 1711 msg = "LBA"; 1712 else 1713 msg = "CHS"; 1714 #endif 1715 1716 grub_printf ("drive 0x%x: C/H/S = %d/%d/%d, " 1717 "The number of sectors = %d, %s\n", 1718 current_drive, 1719 geom.cylinders, geom.heads, geom.sectors, 1720 geom.total_sectors, msg); 1721 real_open_partition (1); 1722 1723 return 0; 1724 } 1725 1726 static struct builtin builtin_geometry = 1727 { 1728 "geometry", 1729 geometry_func, 1730 BUILTIN_CMDLINE | BUILTIN_HELP_LIST, 1731 "geometry DRIVE [CYLINDER HEAD SECTOR [TOTAL_SECTOR]]", 1732 "Print the information for a drive DRIVE. In the grub shell, you can" 1733 " set the geometry of the drive arbitrarily. The number of the cylinders," 1734 " the one of the heads, the one of the sectors and the one of the total" 1735 " sectors are set to CYLINDER, HEAD, SECTOR and TOTAL_SECTOR," 1736 " respectively. If you omit TOTAL_SECTOR, then it will be calculated based" 1737 " on the C/H/S values automatically." 1738 }; 1739 1740 1741 /* halt */ 1742 static int 1743 halt_func (char *arg, int flags) 1744 { 1745 int no_apm; 1746 1747 no_apm = (grub_memcmp (arg, "--no-apm", 8) == 0); 1748 grub_halt (no_apm); 1749 1750 /* Never reach here. */ 1751 return 1; 1752 } 1753 1754 static struct builtin builtin_halt = 1755 { 1756 "halt", 1757 halt_func, 1758 BUILTIN_CMDLINE | BUILTIN_HELP_LIST, 1759 "halt [--no-apm]", 1760 "Halt your system. If APM is avaiable on it, turn off the power using" 1761 " the APM BIOS, unless you specify the option `--no-apm'." 1762 }; 1763 1764 1765 /* help */ 1766 #define MAX_SHORT_DOC_LEN 39 1767 #define MAX_LONG_DOC_LEN 66 1768 1769 static int 1770 help_func (char *arg, int flags) 1771 { 1772 int all = 0; 1773 1774 if (grub_memcmp (arg, "--all", sizeof ("--all") - 1) == 0) 1775 { 1776 all = 1; 1777 arg = skip_to (0, arg); 1778 } 1779 1780 if (! *arg) 1781 { 1782 /* Invoked with no argument. Print the list of the short docs. */ 1783 struct builtin **builtin; 1784 int left = 1; 1785 1786 for (builtin = builtin_table; *builtin != 0; builtin++) 1787 { 1788 int len; 1789 int i; 1790 1791 /* If this cannot be used in the command-line interface, 1792 skip this. */ 1793 if (! ((*builtin)->flags & BUILTIN_CMDLINE)) 1794 continue; 1795 1796 /* If this doesn't need to be listed automatically and "--all" 1797 is not specified, skip this. */ 1798 if (! all && ! ((*builtin)->flags & BUILTIN_HELP_LIST)) 1799 continue; 1800 1801 len = grub_strlen ((*builtin)->short_doc); 1802 /* If the length of SHORT_DOC is too long, truncate it. */ 1803 if (len > MAX_SHORT_DOC_LEN - 1) 1804 len = MAX_SHORT_DOC_LEN - 1; 1805 1806 for (i = 0; i < len; i++) 1807 grub_putchar ((*builtin)->short_doc[i]); 1808 1809 for (; i < MAX_SHORT_DOC_LEN; i++) 1810 grub_putchar (' '); 1811 1812 if (! left) 1813 grub_putchar ('\n'); 1814 1815 left = ! left; 1816 } 1817 1818 /* If the last entry was at the left column, no newline was printed 1819 at the end. */ 1820 if (! left) 1821 grub_putchar ('\n'); 1822 } 1823 else 1824 { 1825 /* Invoked with one or more patterns. */ 1826 do 1827 { 1828 struct builtin **builtin; 1829 char *next_arg; 1830 1831 /* Get the next argument. */ 1832 next_arg = skip_to (0, arg); 1833 1834 /* Terminate ARG. */ 1835 nul_terminate (arg); 1836 1837 for (builtin = builtin_table; *builtin; builtin++) 1838 { 1839 /* Skip this if this is only for the configuration file. */ 1840 if (! ((*builtin)->flags & BUILTIN_CMDLINE)) 1841 continue; 1842 1843 if (substring (arg, (*builtin)->name) < 1) 1844 { 1845 char *doc = (*builtin)->long_doc; 1846 1847 /* At first, print the name and the short doc. */ 1848 grub_printf ("%s: %s\n", 1849 (*builtin)->name, (*builtin)->short_doc); 1850 1851 /* Print the long doc. */ 1852 while (*doc) 1853 { 1854 int len = grub_strlen (doc); 1855 int i; 1856 1857 /* If LEN is too long, fold DOC. */ 1858 if (len > MAX_LONG_DOC_LEN) 1859 { 1860 /* Fold this line at the position of a space. */ 1861 for (len = MAX_LONG_DOC_LEN; len > 0; len--) 1862 if (doc[len - 1] == ' ') 1863 break; 1864 } 1865 1866 grub_printf (" "); 1867 for (i = 0; i < len; i++) 1868 grub_putchar (*doc++); 1869 grub_putchar ('\n'); 1870 } 1871 } 1872 } 1873 1874 arg = next_arg; 1875 } 1876 while (*arg); 1877 } 1878 1879 return 0; 1880 } 1881 1882 static struct builtin builtin_help = 1883 { 1884 "help", 1885 help_func, 1886 BUILTIN_CMDLINE | BUILTIN_HELP_LIST, 1887 "help [--all] [PATTERN ...]", 1888 "Display helpful information about builtin commands. Not all commands" 1889 " aren't shown without the option `--all'." 1890 }; 1891 1892 1893 /* hiddenmenu */ 1894 static int 1895 hiddenmenu_func (char *arg, int flags) 1896 { 1897 show_menu = 0; 1898 return 0; 1899 } 1900 1901 static struct builtin builtin_hiddenmenu = 1902 { 1903 "hiddenmenu", 1904 hiddenmenu_func, 1905 BUILTIN_MENU, 1906 #if 0 1907 "hiddenmenu", 1908 "Hide the menu." 1909 #endif 1910 }; 1911 1912 1913 /* hide */ 1914 static int 1915 hide_func (char *arg, int flags) 1916 { 1917 if (! set_device (arg)) 1918 return 1; 1919 1920 if (! set_partition_hidden_flag (1)) 1921 return 1; 1922 1923 return 0; 1924 } 1925 1926 static struct builtin builtin_hide = 1927 { 1928 "hide", 1929 hide_func, 1930 BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST, 1931 "hide PARTITION", 1932 "Hide PARTITION by setting the \"hidden\" bit in" 1933 " its partition type code." 1934 }; 1935 1936 1937 #ifdef SUPPORT_NETBOOT 1938 /* ifconfig */ 1939 static int 1940 ifconfig_func (char *arg, int flags) 1941 { 1942 char *svr = 0, *ip = 0, *gw = 0, *sm = 0; 1943 1944 if (! grub_eth_probe ()) 1945 { 1946 grub_printf ("No ethernet card found.\n"); 1947 errnum = ERR_DEV_VALUES; 1948 return 1; 1949 } 1950 1951 while (*arg) 1952 { 1953 if (! grub_memcmp ("--server=", arg, sizeof ("--server=") - 1)) 1954 svr = arg + sizeof("--server=") - 1; 1955 else if (! grub_memcmp ("--address=", arg, sizeof ("--address=") - 1)) 1956 ip = arg + sizeof ("--address=") - 1; 1957 else if (! grub_memcmp ("--gateway=", arg, sizeof ("--gateway=") - 1)) 1958 gw = arg + sizeof ("--gateway=") - 1; 1959 else if (! grub_memcmp ("--mask=", arg, sizeof("--mask=") - 1)) 1960 sm = arg + sizeof ("--mask=") - 1; 1961 else 1962 { 1963 errnum = ERR_BAD_ARGUMENT; 1964 return 1; 1965 } 1966 1967 arg = skip_to (0, arg); 1968 } 1969 1970 if (! ifconfig (ip, sm, gw, svr)) 1971 { 1972 errnum = ERR_BAD_ARGUMENT; 1973 return 1; 1974 } 1975 1976 print_network_configuration (); 1977 return 0; 1978 } 1979 1980 static struct builtin builtin_ifconfig = 1981 { 1982 "ifconfig", 1983 ifconfig_func, 1984 BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST, 1985 "ifconfig [--address=IP] [--gateway=IP] [--mask=MASK] [--server=IP]", 1986 "Configure the IP address, the netmask, the gateway and the server" 1987 " address or print current network configuration." 1988 }; 1989 #endif /* SUPPORT_NETBOOT */ 1990 1991 1992 /* impsprobe */ 1993 static int 1994 impsprobe_func (char *arg, int flags) 1995 { 1996 #ifdef GRUB_UTIL 1997 /* In the grub shell, we cannot probe IMPS. */ 1998 errnum = ERR_UNRECOGNIZED; 1999 return 1; 2000 #else /* ! GRUB_UTIL */ 2001 if (!imps_probe ()) 2002 printf (" No MPS information found or probe failed\n"); 2003 2004 return 0; 2005 #endif /* ! GRUB_UTIL */ 2006 } 2007 2008 static struct builtin builtin_impsprobe = 2009 { 2010 "impsprobe", 2011 impsprobe_func, 2012 BUILTIN_CMDLINE, 2013 "impsprobe", 2014 "Probe the Intel Multiprocessor Specification 1.1 or 1.4" 2015 " configuration table and boot the various CPUs which are found into" 2016 " a tight loop." 2017 }; 2018 2019 2020 /* initrd */ 2021 static int 2022 initrd_func (char *arg, int flags) 2023 { 2024 switch (kernel_type) 2025 { 2026 case KERNEL_TYPE_LINUX: 2027 case KERNEL_TYPE_BIG_LINUX: 2028 if (! load_initrd (arg)) 2029 return 1; 2030 break; 2031 2032 default: 2033 errnum = ERR_NEED_LX_KERNEL; 2034 return 1; 2035 } 2036 2037 return 0; 2038 } 2039 2040 static struct builtin builtin_initrd = 2041 { 2042 "initrd", 2043 initrd_func, 2044 BUILTIN_CMDLINE | BUILTIN_HELP_LIST, 2045 "initrd FILE [ARG ...]", 2046 "Load an initial ramdisk FILE for a Linux format boot image and set the" 2047 " appropriate parameters in the Linux setup area in memory." 2048 }; 2049 2050 2051 /* install */ 2052 static int 2053 install_func (char *arg, int flags) 2054 { 2055 char *stage1_file, *dest_dev, *file, *addr; 2056 char *stage1_buffer = (char *) RAW_ADDR (0x100000); 2057 char *stage2_buffer = stage1_buffer + SECTOR_SIZE; 2058 char *old_sect = stage2_buffer + SECTOR_SIZE; 2059 char *stage2_first_buffer = old_sect + SECTOR_SIZE; 2060 char *stage2_second_buffer = stage2_first_buffer + SECTOR_SIZE; 2061 /* XXX: Probably SECTOR_SIZE is reasonable. */ 2062 char *config_filename = stage2_second_buffer + SECTOR_SIZE; 2063 char *dummy = config_filename + SECTOR_SIZE; 2064 int new_drive = GRUB_INVALID_DRIVE; 2065 int dest_drive, dest_partition, dest_sector; 2066 int src_drive, src_partition, src_part_start; 2067 int i; 2068 struct geometry dest_geom, src_geom; 2069 int saved_sector; 2070 int stage2_first_sector, stage2_second_sector; 2071 char *ptr; 2072 int installaddr, installlist; 2073 /* Point to the location of the name of a configuration file in Stage 2. */ 2074 char *config_file_location; 2075 /* If FILE is a Stage 1.5? */ 2076 int is_stage1_5 = 0; 2077 /* Must call grub_close? */ 2078 int is_open = 0; 2079 /* If LBA is forced? */ 2080 int is_force_lba = 0; 2081 /* Was the last sector full? */ 2082 int last_length = SECTOR_SIZE; 2083 2084 #ifdef GRUB_UTIL 2085 /* If the Stage 2 is in a partition mounted by an OS, this will store 2086 the filename under the OS. */ 2087 char *stage2_os_file = 0; 2088 #endif /* GRUB_UTIL */ 2089 2090 /* Save the first sector of Stage2 in STAGE2_SECT. */ 2091 static void disk_read_savesect_func (int sector, int offset, int length) 2092 { 2093 if (debug) 2094 printf ("[%d]", sector); 2095 2096 /* ReiserFS has files which sometimes contain data not aligned 2097 on sector boundaries. Returning an error is better than 2098 silently failing. */ 2099 if (offset != 0 || length != SECTOR_SIZE) 2100 errnum = ERR_UNALIGNED; 2101 2102 saved_sector = sector; 2103 } 2104 2105 /* Write SECTOR to INSTALLLIST, and update INSTALLADDR and 2106 INSTALLSECT. */ 2107 static void disk_read_blocklist_func (int sector, int offset, int length) 2108 { 2109 if (debug) 2110 printf("[%d]", sector); 2111 2112 if (offset != 0 || last_length != SECTOR_SIZE) 2113 { 2114 /* We found a non-sector-aligned data block. */ 2115 errnum = ERR_UNALIGNED; 2116 return; 2117 } 2118 2119 last_length = length; 2120 2121 if (*((unsigned long *) (installlist - 4)) 2122 + *((unsigned short *) installlist) != sector 2123 || installlist == (int) stage2_first_buffer + SECTOR_SIZE + 4) 2124 { 2125 installlist -= 8; 2126 2127 if (*((unsigned long *) (installlist - 8))) 2128 errnum = ERR_WONT_FIT; 2129 else 2130 { 2131 *((unsigned short *) (installlist + 2)) = (installaddr >> 4); 2132 *((unsigned long *) (installlist - 4)) = sector; 2133 } 2134 } 2135 2136 *((unsigned short *) installlist) += 1; 2137 installaddr += 512; 2138 } 2139 2140 /* First, check the GNU-style long option. */ 2141 while (1) 2142 { 2143 if (grub_memcmp ("--force-lba", arg, sizeof ("--force-lba") - 1) == 0) 2144 { 2145 is_force_lba = 1; 2146 arg = skip_to (0, arg); 2147 } 2148 #ifdef GRUB_UTIL 2149 else if (grub_memcmp ("--stage2=", arg, sizeof ("--stage2=") - 1) == 0) 2150 { 2151 stage2_os_file = arg + sizeof ("--stage2=") - 1; 2152 arg = skip_to (0, arg); 2153 nul_terminate (stage2_os_file); 2154 } 2155 #endif /* GRUB_UTIL */ 2156 else 2157 break; 2158 } 2159 2160 stage1_file = arg; 2161 dest_dev = skip_to (0, stage1_file); 2162 if (*dest_dev == 'd') 2163 { 2164 new_drive = 0; 2165 dest_dev = skip_to (0, dest_dev); 2166 } 2167 file = skip_to (0, dest_dev); 2168 addr = skip_to (0, file); 2169 2170 /* Get the installation address. */ 2171 if (! safe_parse_maxint (&addr, &installaddr)) 2172 { 2173 /* ADDR is not specified. */ 2174 installaddr = 0; 2175 ptr = addr; 2176 errnum = 0; 2177 } 2178 else 2179 ptr = skip_to (0, addr); 2180 2181 #ifndef NO_DECOMPRESSION 2182 /* Do not decompress Stage 1 or Stage 2. */ 2183 no_decompression = 1; 2184 #endif 2185 2186 /* Read Stage 1. */ 2187 is_open = grub_open (stage1_file); 2188 if (! is_open 2189 || ! grub_read (stage1_buffer, SECTOR_SIZE) == SECTOR_SIZE) 2190 goto fail; 2191 2192 /* Read the old sector from DEST_DEV. */ 2193 if (! set_device (dest_dev) 2194 || ! open_partition () 2195 || ! devread (0, 0, SECTOR_SIZE, old_sect)) 2196 goto fail; 2197 2198 /* Store the information for the destination device. */ 2199 dest_drive = current_drive; 2200 dest_partition = current_partition; 2201 dest_geom = buf_geom; 2202 dest_sector = part_start; 2203 2204 /* Copy the possible DOS BPB, 59 bytes at byte offset 3. */ 2205 grub_memmove (stage1_buffer + BOOTSEC_BPB_OFFSET, 2206 old_sect + BOOTSEC_BPB_OFFSET, 2207 BOOTSEC_BPB_LENGTH); 2208 2209 /* If for a hard disk, copy the possible MBR/extended part table. */ 2210 if (dest_drive & 0x80) 2211 grub_memmove (stage1_buffer + STAGE1_WINDOWS_NT_MAGIC, 2212 old_sect + STAGE1_WINDOWS_NT_MAGIC, 2213 STAGE1_PARTEND - STAGE1_WINDOWS_NT_MAGIC); 2214 2215 /* Check for the version and the signature of Stage 1. */ 2216 if (*((short *)(stage1_buffer + STAGE1_VER_MAJ_OFFS)) != COMPAT_VERSION 2217 || (*((unsigned short *) (stage1_buffer + BOOTSEC_SIG_OFFSET)) 2218 != BOOTSEC_SIGNATURE)) 2219 { 2220 errnum = ERR_BAD_VERSION; 2221 goto fail; 2222 } 2223 2224 /* This below is not true any longer. But should we leave this alone? */ 2225 2226 /* If DEST_DRIVE is a floppy, Stage 2 must have the iteration probe 2227 routine. */ 2228 if (! (dest_drive & 0x80) 2229 && (*((unsigned char *) (stage1_buffer + BOOTSEC_PART_OFFSET)) == 0x80 2230 || stage1_buffer[BOOTSEC_PART_OFFSET] == 0)) 2231 { 2232 errnum = ERR_BAD_VERSION; 2233 goto fail; 2234 } 2235 2236 grub_close (); 2237 2238 /* Open Stage 2. */ 2239 is_open = grub_open (file); 2240 if (! is_open) 2241 goto fail; 2242 2243 src_drive = current_drive; 2244 src_partition = current_partition; 2245 src_part_start = part_start; 2246 src_geom = buf_geom; 2247 2248 if (! new_drive) 2249 new_drive = src_drive; 2250 else if (src_drive != dest_drive) 2251 grub_printf ("Warning: the option `d' was not used, but the Stage 1 will" 2252 " be installed on a\ndifferent drive than the drive where" 2253 " the Stage 2 resides.\n"); 2254 2255 /* Set the boot drive. */ 2256 *((unsigned char *) (stage1_buffer + STAGE1_BOOT_DRIVE)) = new_drive; 2257 2258 /* Set the "force LBA" flag. */ 2259 *((unsigned char *) (stage1_buffer + STAGE1_FORCE_LBA)) = is_force_lba; 2260 2261 /* Set the boot drive mask. This is a workaround for buggy BIOSes which 2262 don't pass boot drive correctly. Instead, they pass 0x00 even when 2263 booted from 0x80. */ 2264 *((unsigned char *) (stage1_buffer + STAGE1_BOOT_DRIVE_MASK)) 2265 = (dest_drive & BIOS_FLAG_FIXED_DISK); 2266 2267 /* Read the first sector of Stage 2. */ 2268 disk_read_hook = disk_read_savesect_func; 2269 if (grub_read (stage2_first_buffer, SECTOR_SIZE) != SECTOR_SIZE) 2270 goto fail; 2271 2272 stage2_first_sector = saved_sector; 2273 2274 /* Read the second sector of Stage 2. */ 2275 if (grub_read (stage2_second_buffer, SECTOR_SIZE) != SECTOR_SIZE) 2276 goto fail; 2277 2278 stage2_second_sector = saved_sector; 2279 2280 /* Check for the version of Stage 2. */ 2281 if (*((short *) (stage2_second_buffer + STAGE2_VER_MAJ_OFFS)) 2282 != COMPAT_VERSION) 2283 { 2284 errnum = ERR_BAD_VERSION; 2285 goto fail; 2286 } 2287 2288 /* Check for the Stage 2 id. */ 2289 if (stage2_second_buffer[STAGE2_STAGE2_ID] != STAGE2_ID_STAGE2) 2290 is_stage1_5 = 1; 2291 2292 /* If INSTALLADDR is not specified explicitly in the command-line, 2293 determine it by the Stage 2 id. */ 2294 if (! installaddr) 2295 { 2296 if (! is_stage1_5) 2297 /* Stage 2. */ 2298 installaddr = 0x8000; 2299 else 2300 /* Stage 1.5. */ 2301 installaddr = 0x2000; 2302 } 2303 2304 *((unsigned long *) (stage1_buffer + STAGE1_STAGE2_SECTOR)) 2305 = stage2_first_sector; 2306 *((unsigned short *) (stage1_buffer + STAGE1_STAGE2_ADDRESS)) 2307 = installaddr; 2308 *((unsigned short *) (stage1_buffer + STAGE1_STAGE2_SEGMENT)) 2309 = installaddr >> 4; 2310 2311 i = (int) stage2_first_buffer + SECTOR_SIZE - 4; 2312 while (*((unsigned long *) i)) 2313 { 2314 if (i < (int) stage2_first_buffer 2315 || (*((int *) (i - 4)) & 0x80000000) 2316 || *((unsigned short *) i) >= 0xA00 2317 || *((short *) (i + 2)) == 0) 2318 { 2319 errnum = ERR_BAD_VERSION; 2320 goto fail; 2321 } 2322 2323 *((int *) i) = 0; 2324 *((int *) (i - 4)) = 0; 2325 i -= 8; 2326 } 2327 2328 installlist = (int) stage2_first_buffer + SECTOR_SIZE + 4; 2329 installaddr += SECTOR_SIZE; 2330 2331 /* Read the whole of Stage2 except for the first sector. */ 2332 grub_seek (SECTOR_SIZE); 2333 2334 disk_read_hook = disk_read_blocklist_func; 2335 if (! grub_read (dummy, -1)) 2336 goto fail; 2337 2338 disk_read_hook = 0; 2339 2340 /* Find a string for the configuration filename. */ 2341 config_file_location = stage2_second_buffer + STAGE2_VER_STR_OFFS; 2342 while (*(config_file_location++)) 2343 ; 2344 2345 /* Set the "force LBA" flag for Stage2. */ 2346 *((unsigned char *) (stage2_second_buffer + STAGE2_FORCE_LBA)) 2347 = is_force_lba; 2348 2349 if (*ptr == 'p') 2350 { 2351 *((long *) (stage2_second_buffer + STAGE2_INSTALLPART)) 2352 = src_partition; 2353 if (is_stage1_5) 2354 { 2355 /* Reset the device information in FILE if it is a Stage 1.5. */ 2356 unsigned long device = 0xFFFFFFFF; 2357 2358 grub_memmove (config_file_location, (char *) &device, 2359 sizeof (device)); 2360 } 2361 2362 ptr = skip_to (0, ptr); 2363 } 2364 2365 if (*ptr) 2366 { 2367 grub_strcpy (config_filename, ptr); 2368 nul_terminate (config_filename); 2369 2370 if (! is_stage1_5) 2371 /* If it is a Stage 2, just copy PTR to CONFIG_FILE_LOCATION. */ 2372 grub_strcpy (config_file_location, ptr); 2373 else 2374 { 2375 char *real_config; 2376 unsigned long device; 2377 2378 /* Translate the external device syntax to the internal device 2379 syntax. */ 2380 if (! (real_config = set_device (ptr))) 2381 { 2382 /* The Stage 2 PTR does not contain the device name, so 2383 use the root device instead. */ 2384 errnum = ERR_NONE; 2385 current_drive = saved_drive; 2386 current_partition = saved_partition; 2387 real_config = ptr; 2388 } 2389 2390 if (current_drive == src_drive) 2391 { 2392 /* If the drive where the Stage 2 resides is the same as 2393 the one where the Stage 1.5 resides, do not embed the 2394 drive number. */ 2395 current_drive = GRUB_INVALID_DRIVE; 2396 } 2397 2398 device = (current_drive << 24) | current_partition; 2399 grub_memmove (config_file_location, (char *) &device, 2400 sizeof (device)); 2401 grub_strcpy (config_file_location + sizeof (device), 2402 real_config); 2403 } 2404 2405 /* If a Stage 1.5 is used, then we need to modify the Stage2. */ 2406 if (is_stage1_5) 2407 { 2408 char *real_config_filename = skip_to (0, ptr); 2409 2410 is_open = grub_open (config_filename); 2411 if (! is_open) 2412 goto fail; 2413 2414 /* Skip the first sector. */ 2415 grub_seek (SECTOR_SIZE); 2416 2417 disk_read_hook = disk_read_savesect_func; 2418 if (grub_read (stage2_buffer, SECTOR_SIZE) != SECTOR_SIZE) 2419 goto fail; 2420 2421 disk_read_hook = 0; 2422 grub_close (); 2423 is_open = 0; 2424 2425 /* Sanity check. */ 2426 if (*(stage2_buffer + STAGE2_STAGE2_ID) != STAGE2_ID_STAGE2) 2427 { 2428 errnum = ERR_BAD_VERSION; 2429 goto fail; 2430 } 2431 2432 /* Set the "force LBA" flag for Stage2. */ 2433 *(stage2_buffer + STAGE2_FORCE_LBA) = is_force_lba; 2434 2435 /* If REAL_CONFIG_FILENAME is specified, copy it to the Stage2. */ 2436 if (*real_config_filename) 2437 { 2438 /* Specified */ 2439 char *location; 2440 2441 /* Find a string for the configuration filename. */ 2442 location = stage2_buffer + STAGE2_VER_STR_OFFS; 2443 while (*(location++)) 2444 ; 2445 2446 /* Copy the name. */ 2447 grub_strcpy (location, real_config_filename); 2448 } 2449 2450 /* Write it to the disk. */ 2451 buf_track = -1; 2452 2453 #ifdef GRUB_UTIL 2454 /* In the grub shell, access the Stage 2 via the OS filesystem 2455 service, if possible. */ 2456 if (stage2_os_file) 2457 { 2458 FILE *fp; 2459 2460 fp = fopen (stage2_os_file, "r+"); 2461 if (! fp) 2462 { 2463 errnum = ERR_FILE_NOT_FOUND; 2464 goto fail; 2465 } 2466 2467 if (fseek (fp, SECTOR_SIZE, SEEK_SET) != 0) 2468 { 2469 fclose (fp); 2470 errnum = ERR_BAD_VERSION; 2471 goto fail; 2472 } 2473 2474 if (fwrite (stage2_buffer, 1, SECTOR_SIZE, fp) 2475 != SECTOR_SIZE) 2476 { 2477 fclose (fp); 2478 errnum = ERR_WRITE; 2479 goto fail; 2480 } 2481 2482 fclose (fp); 2483 } 2484 else 2485 #endif /* GRUB_UTIL */ 2486 { 2487 if (! devwrite (saved_sector - part_start, 1, stage2_buffer)) 2488 goto fail; 2489 } 2490 } 2491 } 2492 2493 /* Clear the cache. */ 2494 buf_track = -1; 2495 2496 /* Write the modified sectors of Stage2 to the disk. */ 2497 #ifdef GRUB_UTIL 2498 if (! is_stage1_5 && stage2_os_file) 2499 { 2500 FILE *fp; 2501 2502 fp = fopen (stage2_os_file, "r+"); 2503 if (! fp) 2504 { 2505 errnum = ERR_FILE_NOT_FOUND; 2506 goto fail; 2507 } 2508 2509 if (fwrite (stage2_first_buffer, 1, SECTOR_SIZE, fp) != SECTOR_SIZE) 2510 { 2511 fclose (fp); 2512 errnum = ERR_WRITE; 2513 goto fail; 2514 } 2515 2516 if (fwrite (stage2_second_buffer, 1, SECTOR_SIZE, fp) != SECTOR_SIZE) 2517 { 2518 fclose (fp); 2519 errnum = ERR_WRITE; 2520 goto fail; 2521 } 2522 2523 fclose (fp); 2524 } 2525 else 2526 #endif /* GRUB_UTIL */ 2527 { 2528 /* The first. */ 2529 current_drive = src_drive; 2530 current_partition = src_partition; 2531 2532 if (! open_partition ()) 2533 goto fail; 2534 2535 if (! devwrite (stage2_first_sector - src_part_start, 1, 2536 stage2_first_buffer)) 2537 goto fail; 2538 2539 if (! devwrite (stage2_second_sector - src_part_start, 1, 2540 stage2_second_buffer)) 2541 goto fail; 2542 } 2543 2544 /* Write the modified sector of Stage 1 to the disk. */ 2545 current_drive = dest_drive; 2546 current_partition = dest_partition; 2547 if (! open_partition ()) 2548 goto fail; 2549 2550 devwrite (0, 1, stage1_buffer); 2551 2552 fail: 2553 if (is_open) 2554 grub_close (); 2555 2556 disk_read_hook = 0; 2557 2558 #ifndef NO_DECOMPRESSION 2559 no_decompression = 0; 2560 #endif 2561 2562 return errnum; 2563 } 2564 2565 static struct builtin builtin_install = 2566 { 2567 "install", 2568 install_func, 2569 BUILTIN_CMDLINE, 2570 "install [--stage2=STAGE2_FILE] [--force-lba] STAGE1 [d] DEVICE STAGE2 [ADDR] [p] [CONFIG_FILE] [REAL_CONFIG_FILE]", 2571 "Install STAGE1 on DEVICE, and install a blocklist for loading STAGE2" 2572 " as a Stage 2. If the option `d' is present, the Stage 1 will always" 2573 " look for the disk where STAGE2 was installed, rather than using" 2574 " the booting drive. The Stage 2 will be loaded at address ADDR, which" 2575 " will be determined automatically if you don't specify it. If" 2576 " the option `p' or CONFIG_FILE is present, then the first block" 2577 " of Stage 2 is patched with new values of the partition and name" 2578 " of the configuration file used by the true Stage 2 (for a Stage 1.5," 2579 " this is the name of the true Stage 2) at boot time. If STAGE2 is a Stage" 2580 " 1.5 and REAL_CONFIG_FILE is present, then the Stage 2 CONFIG_FILE is" 2581 " patched with the configuration filename REAL_CONFIG_FILE." 2582 " If the option `--force-lba' is specified, disable some sanity checks" 2583 " for LBA mode. If the option `--stage2' is specified, rewrite the Stage" 2584 " 2 via your OS's filesystem instead of the raw device." 2585 }; 2586 2587 2588 /* ioprobe */ 2589 static int 2590 ioprobe_func (char *arg, int flags) 2591 { 2592 #ifdef GRUB_UTIL 2593 2594 errnum = ERR_UNRECOGNIZED; 2595 return 1; 2596 2597 #else /* ! GRUB_UTIL */ 2598 2599 unsigned short *port; 2600 2601 /* Get the drive number. */ 2602 set_device (arg); 2603 if (errnum) 2604 return 1; 2605 2606 /* Clean out IO_MAP. */ 2607 grub_memset ((char *) io_map, 0, IO_MAP_SIZE * sizeof (unsigned short)); 2608 2609 /* Track the int13 handler. */ 2610 track_int13 (current_drive); 2611 2612 /* Print out the result. */ 2613 for (port = io_map; *port != 0; port++) 2614 grub_printf (" 0x%x", (unsigned int) *port); 2615 2616 return 0; 2617 2618 #endif /* ! GRUB_UTIL */ 2619 } 2620 2621 static struct builtin builtin_ioprobe = 2622 { 2623 "ioprobe", 2624 ioprobe_func, 2625 BUILTIN_CMDLINE, 2626 "ioprobe DRIVE", 2627 "Probe I/O ports used for the drive DRIVE." 2628 }; 2629 2630 2631 /* kernel */ 2632 static int 2633 kernel_func (char *arg, int flags) 2634 { 2635 int len; 2636 kernel_t suggested_type = KERNEL_TYPE_NONE; 2637 unsigned long load_flags = 0; 2638 2639 #ifndef AUTO_LINUX_MEM_OPT 2640 load_flags |= KERNEL_LOAD_NO_MEM_OPTION; 2641 #endif 2642 2643 /* Deal with GNU-style long options. */ 2644 while (1) 2645 { 2646 /* If the option `--type=TYPE' is specified, convert the string to 2647 a kernel type. */ 2648 if (grub_memcmp (arg, "--type=", 7) == 0) 2649 { 2650 arg += 7; 2651 2652 if (grub_memcmp (arg, "netbsd", 6) == 0) 2653 suggested_type = KERNEL_TYPE_NETBSD; 2654 else if (grub_memcmp (arg, "freebsd", 7) == 0) 2655 suggested_type = KERNEL_TYPE_FREEBSD; 2656 else if (grub_memcmp (arg, "openbsd", 7) == 0) 2657 /* XXX: For now, OpenBSD is identical to NetBSD, from GRUB's 2658 point of view. */ 2659 suggested_type = KERNEL_TYPE_NETBSD; 2660 else if (grub_memcmp (arg, "linux", 5) == 0) 2661 suggested_type = KERNEL_TYPE_LINUX; 2662 else if (grub_memcmp (arg, "biglinux", 8) == 0) 2663 suggested_type = KERNEL_TYPE_BIG_LINUX; 2664 else if (grub_memcmp (arg, "multiboot", 9) == 0) 2665 suggested_type = KERNEL_TYPE_MULTIBOOT; 2666 else 2667 { 2668 errnum = ERR_BAD_ARGUMENT; 2669 return 1; 2670 } 2671 } 2672 /* If the `--no-mem-option' is specified, don't pass a Linux's mem 2673 option automatically. If the kernel is another type, this flag 2674 has no effect. */ 2675 else if (grub_memcmp (arg, "--no-mem-option", 15) == 0) 2676 load_flags |= KERNEL_LOAD_NO_MEM_OPTION; 2677 else 2678 break; 2679 2680 /* Try the next. */ 2681 arg = skip_to (0, arg); 2682 } 2683 2684 len = grub_strlen (arg); 2685 2686 /* Reset MB_CMDLINE. */ 2687 mb_cmdline = (char *) MB_CMDLINE_BUF; 2688 if (len + 1 > MB_CMDLINE_BUFLEN) 2689 { 2690 errnum = ERR_WONT_FIT; 2691 return 1; 2692 } 2693 2694 /* Copy the command-line to MB_CMDLINE. */ 2695 grub_memmove (mb_cmdline, arg, len + 1); 2696 kernel_type = load_image (arg, mb_cmdline, suggested_type, load_flags); 2697 if (kernel_type == KERNEL_TYPE_NONE) 2698 return 1; 2699 2700 mb_cmdline += len + 1; 2701 return 0; 2702 } 2703 2704 static struct builtin builtin_kernel = 2705 { 2706 "kernel", 2707 kernel_func, 2708 BUILTIN_CMDLINE | BUILTIN_HELP_LIST, 2709 "kernel [--no-mem-option] [--type=TYPE] FILE [ARG ...]", 2710 "Attempt to load the primary boot image from FILE. The rest of the" 2711 " line is passed verbatim as the \"kernel command line\". Any modules" 2712 " must be reloaded after using this command. The option --type is used" 2713 " to suggest what type of kernel to be loaded. TYPE must be either of" 2714 " \"netbsd\", \"freebsd\", \"openbsd\", \"linux\", \"biglinux\" and" 2715 " \"multiboot\". The option --no-mem-option tells GRUB not to pass a" 2716 " Linux's mem option automatically." 2717 }; 2718 2719 2720 /* lock */ 2721 static int 2722 lock_func (char *arg, int flags) 2723 { 2724 if (! auth && password) 2725 { 2726 errnum = ERR_PRIVILEGED; 2727 return 1; 2728 } 2729 2730 return 0; 2731 } 2732 2733 static struct builtin builtin_lock = 2734 { 2735 "lock", 2736 lock_func, 2737 BUILTIN_CMDLINE, 2738 "lock", 2739 "Break a command execution unless the user is authenticated." 2740 }; 2741 2742 2743 /* makeactive */ 2744 static int 2745 makeactive_func (char *arg, int flags) 2746 { 2747 if (! make_saved_active ()) 2748 return 1; 2749 2750 return 0; 2751 } 2752 2753 static struct builtin builtin_makeactive = 2754 { 2755 "makeactive", 2756 makeactive_func, 2757 BUILTIN_CMDLINE | BUILTIN_HELP_LIST, 2758 "makeactive", 2759 "Set the active partition on the root disk to GRUB's root device." 2760 " This command is limited to _primary_ PC partitions on a hard disk." 2761 }; 2762 2763 2764 /* map */ 2765 /* Map FROM_DRIVE to TO_DRIVE. */ 2766 static int 2767 map_func (char *arg, int flags) 2768 { 2769 char *to_drive; 2770 char *from_drive; 2771 unsigned long to, from; 2772 int i; 2773 2774 to_drive = arg; 2775 from_drive = skip_to (0, arg); 2776 2777 /* Get the drive number for TO_DRIVE. */ 2778 set_device (to_drive); 2779 if (errnum) 2780 return 1; 2781 to = current_drive; 2782 2783 /* Get the drive number for FROM_DRIVE. */ 2784 set_device (from_drive); 2785 if (errnum) 2786 return 1; 2787 from = current_drive; 2788 2789 /* Search for an empty slot in BIOS_DRIVE_MAP. */ 2790 for (i = 0; i < DRIVE_MAP_SIZE; i++) 2791 { 2792 /* Perhaps the user wants to override the map. */ 2793 if ((bios_drive_map[i] & 0xff) == from) 2794 break; 2795 2796 if (! bios_drive_map[i]) 2797 break; 2798 } 2799 2800 if (i == DRIVE_MAP_SIZE) 2801 { 2802 errnum = ERR_WONT_FIT; 2803 return 1; 2804 } 2805 2806 if (to == from) 2807 /* If TO is equal to FROM, delete the entry. */ 2808 grub_memmove ((char *) &bios_drive_map[i], (char *) &bios_drive_map[i + 1], 2809 sizeof (unsigned short) * (DRIVE_MAP_SIZE - i)); 2810 else 2811 bios_drive_map[i] = from | (to << 8); 2812 2813 return 0; 2814 } 2815 2816 static struct builtin builtin_map = 2817 { 2818 "map", 2819 map_func, 2820 BUILTIN_CMDLINE | BUILTIN_HELP_LIST, 2821 "map TO_DRIVE FROM_DRIVE", 2822 "Map the drive FROM_DRIVE to the drive TO_DRIVE. This is necessary" 2823 " when you chain-load some operating systems, such as DOS, if such an" 2824 " OS resides at a non-first drive." 2825 }; 2826 2827 2828 #ifdef USE_MD5_PASSWORDS 2829 /* md5crypt */ 2830 static int 2831 md5crypt_func (char *arg, int flags) 2832 { 2833 char crypted[36]; 2834 char key[32]; 2835 unsigned int seed; 2836 int i; 2837 const char *const seedchars = 2838 "./0123456789ABCDEFGHIJKLMNOPQRST" 2839 "UVWXYZabcdefghijklmnopqrstuvwxyz"; 2840 2841 /* First create a salt. */ 2842 2843 /* The magical prefix. */ 2844 grub_memset (crypted, 0, sizeof (crypted)); 2845 grub_memmove (crypted, "$1$", 3); 2846 2847 /* Create the length of a salt. */ 2848 seed = currticks (); 2849 2850 /* Generate a salt. */ 2851 for (i = 0; i < 8 && seed; i++) 2852 { 2853 /* FIXME: This should be more random. */ 2854 crypted[3 + i] = seedchars[seed & 0x3f]; 2855 seed >>= 6; 2856 } 2857 2858 /* A salt must be terminated with `$', if it is less than 8 chars. */ 2859 crypted[3 + i] = '$'; 2860 2861 #ifdef DEBUG_MD5CRYPT 2862 grub_printf ("salt = %s\n", crypted); 2863 #endif 2864 2865 /* Get a password. */ 2866 grub_memset (key, 0, sizeof (key)); 2867 get_cmdline ("Password: ", key, sizeof (key) - 1, '*', 0); 2868 2869 /* Crypt the key. */ 2870 make_md5_password (key, crypted); 2871 2872 grub_printf ("Encrypted: %s\n", crypted); 2873 return 0; 2874 } 2875 2876 static struct builtin builtin_md5crypt = 2877 { 2878 "md5crypt", 2879 md5crypt_func, 2880 BUILTIN_CMDLINE | BUILTIN_HELP_LIST, 2881 "md5crypt", 2882 "Generate a password in MD5 format." 2883 }; 2884 #endif /* USE_MD5_PASSWORDS */ 2885 2886 2887 /* module */ 2888 static int 2889 module_func (char *arg, int flags) 2890 { 2891 int len = grub_strlen (arg); 2892 2893 switch (kernel_type) 2894 { 2895 case KERNEL_TYPE_MULTIBOOT: 2896 if (mb_cmdline + len + 1 > (char *) MB_CMDLINE_BUF + MB_CMDLINE_BUFLEN) 2897 { 2898 errnum = ERR_WONT_FIT; 2899 return 1; 2900 } 2901 grub_memmove (mb_cmdline, arg, len + 1); 2902 if (! load_module (arg, mb_cmdline)) 2903 return 1; 2904 mb_cmdline += len + 1; 2905 break; 2906 2907 case KERNEL_TYPE_LINUX: 2908 case KERNEL_TYPE_BIG_LINUX: 2909 if (! load_initrd (arg)) 2910 return 1; 2911 break; 2912 2913 default: 2914 errnum = ERR_NEED_MB_KERNEL; 2915 return 1; 2916 } 2917 2918 return 0; 2919 } 2920 2921 static struct builtin builtin_module = 2922 { 2923 "module", 2924 module_func, 2925 BUILTIN_CMDLINE | BUILTIN_HELP_LIST, 2926 "module FILE [ARG ...]", 2927 "Load a boot module FILE for a Multiboot format boot image (no" 2928 " interpretation of the file contents is made, so users of this" 2929 " command must know what the kernel in question expects). The" 2930 " rest of the line is passed as the \"module command line\", like" 2931 " the `kernel' command." 2932 }; 2933 2934 2935 /* modulenounzip */ 2936 static int 2937 modulenounzip_func (char *arg, int flags) 2938 { 2939 int ret; 2940 2941 #ifndef NO_DECOMPRESSION 2942 no_decompression = 1; 2943 #endif 2944 2945 ret = module_func (arg, flags); 2946 2947 #ifndef NO_DECOMPRESSION 2948 no_decompression = 0; 2949 #endif 2950 2951 return ret; 2952 } 2953 2954 static struct builtin builtin_modulenounzip = 2955 { 2956 "modulenounzip", 2957 modulenounzip_func, 2958 BUILTIN_CMDLINE | BUILTIN_HELP_LIST, 2959 "modulenounzip FILE [ARG ...]", 2960 "The same as `module', except that automatic decompression is" 2961 " disabled." 2962 }; 2963 2964 2965 /* pager [on|off] */ 2966 static int 2967 pager_func (char *arg, int flags) 2968 { 2969 /* If ARG is empty, toggle the flag. */ 2970 if (! *arg) 2971 use_pager = ! use_pager; 2972 else if (grub_memcmp (arg, "on", 2) == 0) 2973 use_pager = 1; 2974 else if (grub_memcmp (arg, "off", 3) == 0) 2975 use_pager = 0; 2976 else 2977 { 2978 errnum = ERR_BAD_ARGUMENT; 2979 return 1; 2980 } 2981 2982 grub_printf (" Internal pager is now %s\n", use_pager ? "on" : "off"); 2983 return 0; 2984 } 2985 2986 static struct builtin builtin_pager = 2987 { 2988 "pager", 2989 pager_func, 2990 BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST, 2991 "pager [FLAG]", 2992 "Toggle pager mode with no argument. If FLAG is given and its value" 2993 " is `on', turn on the mode. If FLAG is `off', turn off the mode." 2994 }; 2995 2996 2997 /* partnew PART TYPE START LEN */ 2998 static int 2999 partnew_func (char *arg, int flags) 3000 { 3001 int new_type, new_start, new_len; 3002 int start_cl, start_ch, start_dh; 3003 int end_cl, end_ch, end_dh; 3004 int entry; 3005 char mbr[512]; 3006 3007 /* Convert a LBA address to a CHS address in the INT 13 format. */ 3008 auto void lba_to_chs (int lba, int *cl, int *ch, int *dh); 3009 void lba_to_chs (int lba, int *cl, int *ch, int *dh) 3010 { 3011 int cylinder, head, sector; 3012 3013 sector = lba % buf_geom.sectors + 1; 3014 head = (lba / buf_geom.sectors) % buf_geom.heads; 3015 cylinder = lba / (buf_geom.sectors * buf_geom.heads); 3016 3017 if (cylinder >= buf_geom.cylinders) 3018 cylinder = buf_geom.cylinders - 1; 3019 3020 *cl = sector | ((cylinder & 0x300) >> 2); 3021 *ch = cylinder & 0xFF; 3022 *dh = head; 3023 } 3024 3025 /* Get the drive and the partition. */ 3026 if (! set_device (arg)) 3027 return 1; 3028 3029 /* The drive must be a hard disk. */ 3030 if (! (current_drive & 0x80)) 3031 { 3032 errnum = ERR_BAD_ARGUMENT; 3033 return 1; 3034 } 3035 3036 /* The partition must a primary partition. */ 3037 if ((current_partition >> 16) > 3 3038 || (current_partition & 0xFFFF) != 0xFFFF) 3039 { 3040 errnum = ERR_BAD_ARGUMENT; 3041 return 1; 3042 } 3043 3044 entry = current_partition >> 16; 3045 3046 /* Get the new partition type. */ 3047 arg = skip_to (0, arg); 3048 if (! safe_parse_maxint (&arg, &new_type)) 3049 return 1; 3050 3051 /* The partition type is unsigned char. */ 3052 if (new_type > 0xFF) 3053 { 3054 errnum = ERR_BAD_ARGUMENT; 3055 return 1; 3056 } 3057 3058 /* Get the new partition start. */ 3059 arg = skip_to (0, arg); 3060 if (! safe_parse_maxint (&arg, &new_start)) 3061 return 1; 3062 3063 /* Get the new partition length. */ 3064 arg = skip_to (0, arg); 3065 if (! safe_parse_maxint (&arg, &new_len)) 3066 return 1; 3067 3068 /* Read the MBR. */ 3069 if (! rawread (current_drive, 0, 0, SECTOR_SIZE, mbr)) 3070 return 1; 3071 3072 /* Check if the new partition will fit in the disk. */ 3073 if (new_start + new_len > buf_geom.total_sectors) 3074 { 3075 errnum = ERR_GEOM; 3076 return 1; 3077 } 3078 3079 /* Store the partition information in the MBR. */ 3080 lba_to_chs (new_start, &start_cl, &start_ch, &start_dh); 3081 lba_to_chs (new_start + new_len - 1, &end_cl, &end_ch, &end_dh); 3082 3083 PC_SLICE_FLAG (mbr, entry) = 0; 3084 PC_SLICE_HEAD (mbr, entry) = start_dh; 3085 PC_SLICE_SEC (mbr, entry) = start_cl; 3086 PC_SLICE_CYL (mbr, entry) = start_ch; 3087 PC_SLICE_TYPE (mbr, entry) = new_type; 3088 PC_SLICE_EHEAD (mbr, entry) = end_dh; 3089 PC_SLICE_ESEC (mbr, entry) = end_cl; 3090 PC_SLICE_ECYL (mbr, entry) = end_ch; 3091 PC_SLICE_START (mbr, entry) = new_start; 3092 PC_SLICE_LENGTH (mbr, entry) = new_len; 3093 3094 /* Make sure that the MBR has a valid signature. */ 3095 PC_MBR_SIG (mbr) = PC_MBR_SIGNATURE; 3096 3097 /* Write back the MBR to the disk. */ 3098 buf_track = -1; 3099 if (! rawwrite (current_drive, 0, mbr)) 3100 return 1; 3101 3102 return 0; 3103 } 3104 3105 static struct builtin builtin_partnew = 3106 { 3107 "partnew", 3108 partnew_func, 3109 BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST, 3110 "partnew PART TYPE START LEN", 3111 "Create a primary partition at the starting address START with the" 3112 " length LEN, with the type TYPE. START and LEN are in sector units." 3113 }; 3114 3115 3116 /* parttype PART TYPE */ 3117 static int 3118 parttype_func (char *arg, int flags) 3119 { 3120 int new_type; 3121 unsigned long part = 0xFFFFFF; 3122 unsigned long start, len, offset, ext_offset; 3123 int entry, type; 3124 char mbr[512]; 3125 3126 /* Get the drive and the partition. */ 3127 if (! set_device (arg)) 3128 return 1; 3129 3130 /* The drive must be a hard disk. */ 3131 if (! (current_drive & 0x80)) 3132 { 3133 errnum = ERR_BAD_ARGUMENT; 3134 return 1; 3135 } 3136 3137 /* The partition must be a PC slice. */ 3138 if ((current_partition >> 16) == 0xFF 3139 || (current_partition & 0xFFFF) != 0xFFFF) 3140 { 3141 errnum = ERR_BAD_ARGUMENT; 3142 return 1; 3143 } 3144 3145 /* Get the new partition type. */ 3146 arg = skip_to (0, arg); 3147 if (! safe_parse_maxint (&arg, &new_type)) 3148 return 1; 3149 3150 /* The partition type is unsigned char. */ 3151 if (new_type > 0xFF) 3152 { 3153 errnum = ERR_BAD_ARGUMENT; 3154 return 1; 3155 } 3156 3157 /* Look for the partition. */ 3158 while (next_partition (current_drive, 0xFFFFFF, &part, &type, 3159 &start, &len, &offset, &entry, 3160 &ext_offset, mbr)) 3161 { 3162 if (part == current_partition) 3163 { 3164 /* Found. */ 3165 3166 /* Set the type to NEW_TYPE. */ 3167 PC_SLICE_TYPE (mbr, entry) = new_type; 3168 3169 /* Write back the MBR to the disk. */ 3170 buf_track = -1; 3171 if (! rawwrite (current_drive, offset, mbr)) 3172 return 1; 3173 3174 /* Succeed. */ 3175 return 0; 3176 } 3177 } 3178 3179 /* The partition was not found. ERRNUM was set by next_partition. */ 3180 return 1; 3181 } 3182 3183 static struct builtin builtin_parttype = 3184 { 3185 "parttype", 3186 parttype_func, 3187 BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST, 3188 "parttype PART TYPE", 3189 "Change the type of the partition PART to TYPE." 3190 }; 3191 3192 3193 /* password */ 3194 static int 3195 password_func (char *arg, int flags) 3196 { 3197 int len; 3198 password_t type = PASSWORD_PLAIN; 3199 3200 #ifdef USE_MD5_PASSWORDS 3201 if (grub_memcmp (arg, "--md5", 5) == 0) 3202 { 3203 type = PASSWORD_MD5; 3204 arg = skip_to (0, arg); 3205 } 3206 #endif 3207 if (grub_memcmp (arg, "--", 2) == 0) 3208 { 3209 type = PASSWORD_UNSUPPORTED; 3210 arg = skip_to (0, arg); 3211 } 3212 3213 if ((flags & (BUILTIN_CMDLINE | BUILTIN_SCRIPT)) != 0) 3214 { 3215 /* Do password check! */ 3216 char entered[32]; 3217 3218 /* Wipe out any previously entered password */ 3219 entered[0] = 0; 3220 get_cmdline ("Password: ", entered, 31, '*', 0); 3221 3222 nul_terminate (arg); 3223 if (check_password (entered, arg, type) != 0) 3224 { 3225 errnum = ERR_PRIVILEGED; 3226 return 1; 3227 } 3228 } 3229 else 3230 { 3231 len = grub_strlen (arg); 3232 3233 /* PASSWORD NUL NUL ... */ 3234 if (len + 2 > PASSWORD_BUFLEN) 3235 { 3236 errnum = ERR_WONT_FIT; 3237 return 1; 3238 } 3239 3240 /* Copy the password and clear the rest of the buffer. */ 3241 password = (char *) PASSWORD_BUF; 3242 grub_memmove (password, arg, len); 3243 grub_memset (password + len, 0, PASSWORD_BUFLEN - len); 3244 password_type = type; 3245 } 3246 return 0; 3247 } 3248 3249 static struct builtin builtin_password = 3250 { 3251 "password", 3252 password_func, 3253 BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_NO_ECHO, 3254 "password [--md5] PASSWD [FILE]", 3255 "If used in the first section of a menu file, disable all" 3256 " interactive editing control (menu entry editor and" 3257 " command line). If the password PASSWD is entered, it loads the" 3258 " FILE as a new config file and restarts the GRUB Stage 2. If you" 3259 " omit the argument FILE, then GRUB just unlocks privileged" 3260 " instructions. You can also use it in the script section, in" 3261 " which case it will ask for the password, before continueing." 3262 " The option --md5 tells GRUB that PASSWD is encrypted with" 3263 " md5crypt." 3264 }; 3265 3266 3267 /* pause */ 3268 static int 3269 pause_func (char *arg, int flags) 3270 { 3271 printf("%s\n", arg); 3272 3273 /* If ESC is returned, then abort this entry. */ 3274 if (ASCII_CHAR (getkey ()) == 27) 3275 return 1; 3276 3277 return 0; 3278 } 3279 3280 static struct builtin builtin_pause = 3281 { 3282 "pause", 3283 pause_func, 3284 BUILTIN_CMDLINE | BUILTIN_NO_ECHO, 3285 "pause [MESSAGE ...]", 3286 "Print MESSAGE, then wait until a key is pressed." 3287 }; 3288 3289 3290 #ifdef GRUB_UTIL 3291 /* quit */ 3292 static int 3293 quit_func (char *arg, int flags) 3294 { 3295 stop (); 3296 3297 /* Never reach here. */ 3298 return 0; 3299 } 3300 3301 static struct builtin builtin_quit = 3302 { 3303 "quit", 3304 quit_func, 3305 BUILTIN_CMDLINE | BUILTIN_HELP_LIST, 3306 "quit", 3307 "Exit from the GRUB shell." 3308 }; 3309 #endif /* GRUB_UTIL */ 3310 3311 3312 #ifdef SUPPORT_NETBOOT 3313 /* rarp */ 3314 static int 3315 rarp_func (char *arg, int flags) 3316 { 3317 if (! rarp ()) 3318 { 3319 if (errnum == ERR_NONE) 3320 errnum = ERR_DEV_VALUES; 3321 3322 return 1; 3323 } 3324 3325 /* Notify the configuration. */ 3326 print_network_configuration (); 3327 return 0; 3328 } 3329 3330 static struct builtin builtin_rarp = 3331 { 3332 "rarp", 3333 rarp_func, 3334 BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST, 3335 "rarp", 3336 "Initialize a network device via RARP." 3337 }; 3338 #endif /* SUPPORT_NETBOOT */ 3339 3340 3341 static int 3342 read_func (char *arg, int flags) 3343 { 3344 int addr; 3345 3346 if (! safe_parse_maxint (&arg, &addr)) 3347 return 1; 3348 3349 grub_printf ("Address 0x%x: Value 0x%x\n", 3350 addr, *((unsigned *) RAW_ADDR (addr))); 3351 return 0; 3352 } 3353 3354 static struct builtin builtin_read = 3355 { 3356 "read", 3357 read_func, 3358 BUILTIN_CMDLINE, 3359 "read ADDR", 3360 "Read a 32-bit value from memory at address ADDR and" 3361 " display it in hex format." 3362 }; 3363 3364 3365 /* reboot */ 3366 static int 3367 reboot_func (char *arg, int flags) 3368 { 3369 grub_reboot (); 3370 3371 /* Never reach here. */ 3372 return 1; 3373 } 3374 3375 static struct builtin builtin_reboot = 3376 { 3377 "reboot", 3378 reboot_func, 3379 BUILTIN_CMDLINE | BUILTIN_HELP_LIST, 3380 "reboot", 3381 "Reboot your system." 3382 }; 3383 3384 3385 /* Print the root device information. */ 3386 static void 3387 print_root_device (void) 3388 { 3389 if (saved_drive == NETWORK_DRIVE) 3390 { 3391 /* Network drive. */ 3392 grub_printf (" (nd):"); 3393 } 3394 else if (saved_drive & 0x80) 3395 { 3396 /* Hard disk drive. */ 3397 grub_printf (" (hd%d", saved_drive - 0x80); 3398 3399 if ((saved_partition & 0xFF0000) != 0xFF0000) 3400 grub_printf (",%d", saved_partition >> 16); 3401 3402 if ((saved_partition & 0x00FF00) != 0x00FF00) 3403 grub_printf (",%c", ((saved_partition >> 8) & 0xFF) + 'a'); 3404 3405 grub_printf ("):"); 3406 } 3407 else 3408 { 3409 /* Floppy disk drive. */ 3410 grub_printf (" (fd%d):", saved_drive); 3411 } 3412 3413 /* Print the filesystem information. */ 3414 current_partition = saved_partition; 3415 current_drive = saved_drive; 3416 print_fsys_type (); 3417 } 3418 3419 static int 3420 real_root_func (char *arg, int attempt_mount) 3421 { 3422 int hdbias = 0; 3423 char *biasptr; 3424 char *next; 3425 3426 /* If ARG is empty, just print the current root device. */ 3427 if (! *arg) 3428 { 3429 print_root_device (); 3430 return 0; 3431 } 3432 3433 /* Call set_device to get the drive and the partition in ARG. */ 3434 next = set_device (arg); 3435 if (! next) 3436 return 1; 3437 3438 /* Ignore ERR_FSYS_MOUNT. */ 3439 if (attempt_mount) 3440 { 3441 if (! open_device () && errnum != ERR_FSYS_MOUNT) 3442 return 1; 3443 } 3444 else 3445 { 3446 /* This is necessary, because the location of a partition table 3447 must be set appropriately. */ 3448 if (open_partition ()) 3449 { 3450 set_bootdev (0); 3451 if (errnum) 3452 return 1; 3453 } 3454 } 3455 3456 /* Clear ERRNUM. */ 3457 errnum = 0; 3458 saved_partition = current_partition; 3459 saved_drive = current_drive; 3460 3461 if (attempt_mount) 3462 { 3463 /* BSD and chainloading evil hacks !! */ 3464 biasptr = skip_to (0, next); 3465 safe_parse_maxint (&biasptr, &hdbias); 3466 errnum = 0; 3467 bootdev = set_bootdev (hdbias); 3468 if (errnum) 3469 return 1; 3470 3471 /* Print the type of the filesystem. */ 3472 print_fsys_type (); 3473 } 3474 3475 return 0; 3476 } 3477 3478 static int 3479 root_func (char *arg, int flags) 3480 { 3481 return real_root_func (arg, 1); 3482 } 3483 3484 static struct builtin builtin_root = 3485 { 3486 "root", 3487 root_func, 3488 BUILTIN_CMDLINE | BUILTIN_HELP_LIST, 3489 "root [DEVICE [HDBIAS]]", 3490 "Set the current \"root device\" to the device DEVICE, then" 3491 " attempt to mount it to get the partition size (for passing the" 3492 " partition descriptor in `ES:ESI', used by some chain-loaded" 3493 " bootloaders), the BSD drive-type (for booting BSD kernels using" 3494 " their native boot format), and correctly determine " 3495 " the PC partition where a BSD sub-partition is located. The" 3496 " optional HDBIAS parameter is a number to tell a BSD kernel" 3497 " how many BIOS drive numbers are on controllers before the current" 3498 " one. For example, if there is an IDE disk and a SCSI disk, and your" 3499 " FreeBSD root partition is on the SCSI disk, then use a `1' for HDBIAS." 3500 }; 3501 3502 3503 /* rootnoverify */ 3504 static int 3505 rootnoverify_func (char *arg, int flags) 3506 { 3507 return real_root_func (arg, 0); 3508 } 3509 3510 static struct builtin builtin_rootnoverify = 3511 { 3512 "rootnoverify", 3513 rootnoverify_func, 3514 BUILTIN_CMDLINE | BUILTIN_HELP_LIST, 3515 "rootnoverify [DEVICE [HDBIAS]]", 3516 "Similar to `root', but don't attempt to mount the partition. This" 3517 " is useful for when an OS is outside of the area of the disk that" 3518 " GRUB can read, but setting the correct root device is still" 3519 " desired. Note that the items mentioned in `root' which" 3520 " derived from attempting the mount will NOT work correctly." 3521 }; 3522 3523 3524 /* savedefault */ 3525 static int 3526 savedefault_func (char *arg, int flags) 3527 { 3528 #if !defined(SUPPORT_DISKLESS) && !defined(GRUB_UTIL) 3529 unsigned long tmp_drive = saved_drive; 3530 unsigned long tmp_partition = saved_partition; 3531 char *default_file = (char *) DEFAULT_FILE_BUF; 3532 char buf[10]; 3533 char sect[SECTOR_SIZE]; 3534 int entryno; 3535 int sector_count = 0; 3536 int saved_sectors[2]; 3537 int saved_offsets[2]; 3538 int saved_lengths[2]; 3539 3540 /* Save sector information about at most two sectors. */ 3541 auto void disk_read_savesect_func (int sector, int offset, int length); 3542 void disk_read_savesect_func (int sector, int offset, int length) 3543 { 3544 if (sector_count < 2) 3545 { 3546 saved_sectors[sector_count] = sector; 3547 saved_offsets[sector_count] = offset; 3548 saved_lengths[sector_count] = length; 3549 } 3550 sector_count++; 3551 } 3552 3553 /* This command is only useful when you boot an entry from the menu 3554 interface. */ 3555 if (! (flags & BUILTIN_SCRIPT)) 3556 { 3557 errnum = ERR_UNRECOGNIZED; 3558 return 1; 3559 } 3560 3561 /* Determine a saved entry number. */ 3562 if (*arg) 3563 { 3564 if (grub_memcmp (arg, "fallback", sizeof ("fallback") - 1) == 0) 3565 { 3566 int i; 3567 int index = 0; 3568 3569 for (i = 0; i < MAX_FALLBACK_ENTRIES; i++) 3570 { 3571 if (fallback_entries[i] < 0) 3572 break; 3573 if (fallback_entries[i] == current_entryno) 3574 { 3575 index = i + 1; 3576 break; 3577 } 3578 } 3579 3580 if (index >= MAX_FALLBACK_ENTRIES || fallback_entries[index] < 0) 3581 { 3582 /* This is the last. */ 3583 errnum = ERR_BAD_ARGUMENT; 3584 return 1; 3585 } 3586 3587 entryno = fallback_entries[index]; 3588 } 3589 else if (! safe_parse_maxint (&arg, &entryno)) 3590 return 1; 3591 } 3592 else 3593 entryno = current_entryno; 3594 3595 /* Open the default file. */ 3596 saved_drive = boot_drive; 3597 saved_partition = install_partition; 3598 if (grub_open (default_file)) 3599 { 3600 int len; 3601 3602 disk_read_hook = disk_read_savesect_func; 3603 len = grub_read (buf, sizeof (buf)); 3604 disk_read_hook = 0; 3605 grub_close (); 3606 3607 if (len != sizeof (buf)) 3608 { 3609 /* This is too small. Do not modify the file manually, please! */ 3610 errnum = ERR_READ; 3611 goto fail; 3612 } 3613 3614 if (sector_count > 2) 3615 { 3616 /* Is this possible?! Too fragmented! */ 3617 errnum = ERR_FSYS_CORRUPT; 3618 goto fail; 3619 } 3620 3621 /* Set up a string to be written. */ 3622 grub_memset (buf, '\n', sizeof (buf)); 3623 grub_sprintf (buf, "%d", entryno); 3624 3625 if (saved_lengths[0] < sizeof (buf)) 3626 { 3627 /* The file is anchored to another file and the first few bytes 3628 are spanned in two sectors. Uggh... */ 3629 if (! rawread (current_drive, saved_sectors[0], 0, SECTOR_SIZE, 3630 sect)) 3631 goto fail; 3632 grub_memmove (sect + saved_offsets[0], buf, saved_lengths[0]); 3633 if (! rawwrite (current_drive, saved_sectors[0], sect)) 3634 goto fail; 3635 3636 if (! rawread (current_drive, saved_sectors[1], 0, SECTOR_SIZE, 3637 sect)) 3638 goto fail; 3639 grub_memmove (sect + saved_offsets[1], 3640 buf + saved_lengths[0], 3641 sizeof (buf) - saved_lengths[0]); 3642 if (! rawwrite (current_drive, saved_sectors[1], sect)) 3643 goto fail; 3644 } 3645 else 3646 { 3647 /* This is a simple case. It fits into a single sector. */ 3648 if (! rawread (current_drive, saved_sectors[0], 0, SECTOR_SIZE, 3649 sect)) 3650 goto fail; 3651 grub_memmove (sect + saved_offsets[0], buf, sizeof (buf)); 3652 if (! rawwrite (current_drive, saved_sectors[0], sect)) 3653 goto fail; 3654 } 3655 3656 /* Clear the cache. */ 3657 buf_track = -1; 3658 } 3659 3660 fail: 3661 saved_drive = tmp_drive; 3662 saved_partition = tmp_partition; 3663 return errnum; 3664 #else /* ! SUPPORT_DISKLESS && ! GRUB_UTIL */ 3665 errnum = ERR_UNRECOGNIZED; 3666 return 1; 3667 #endif /* ! SUPPORT_DISKLESS && ! GRUB_UTIL */ 3668 } 3669 3670 static struct builtin builtin_savedefault = 3671 { 3672 "savedefault", 3673 savedefault_func, 3674 BUILTIN_CMDLINE, 3675 "savedefault [NUM | `fallback']", 3676 "Save the current entry as the default boot entry if no argument is" 3677 " specified. If a number is specified, this number is saved. If" 3678 " `fallback' is used, next fallback entry is saved." 3679 }; 3680 3681 3682 #ifdef SUPPORT_SERIAL 3683 /* serial */ 3684 static int 3685 serial_func (char *arg, int flags) 3686 { 3687 unsigned short port = serial_hw_get_port (0); 3688 unsigned int speed = 9600; 3689 int word_len = UART_8BITS_WORD; 3690 int parity = UART_NO_PARITY; 3691 int stop_bit_len = UART_1_STOP_BIT; 3692 3693 /* Process GNU-style long options. 3694 FIXME: We should implement a getopt-like function, to avoid 3695 duplications. */ 3696 while (1) 3697 { 3698 if (grub_memcmp (arg, "--unit=", sizeof ("--unit=") - 1) == 0) 3699 { 3700 char *p = arg + sizeof ("--unit=") - 1; 3701 int unit; 3702 3703 if (! safe_parse_maxint (&p, &unit)) 3704 return 1; 3705 3706 if (unit < 0 || unit > 3) 3707 { 3708 errnum = ERR_DEV_VALUES; 3709 return 1; 3710 } 3711 3712 port = serial_hw_get_port (unit); 3713 } 3714 else if (grub_memcmp (arg, "--speed=", sizeof ("--speed=") - 1) == 0) 3715 { 3716 char *p = arg + sizeof ("--speed=") - 1; 3717 int num; 3718 3719 if (! safe_parse_maxint (&p, &num)) 3720 return 1; 3721 3722 speed = (unsigned int) num; 3723 } 3724 else if (grub_memcmp (arg, "--port=", sizeof ("--port=") - 1) == 0) 3725 { 3726 char *p = arg + sizeof ("--port=") - 1; 3727 int num; 3728 3729 if (! safe_parse_maxint (&p, &num)) 3730 return 1; 3731 3732 port = (unsigned short) num; 3733 } 3734 else if (grub_memcmp (arg, "--word=", sizeof ("--word=") - 1) == 0) 3735 { 3736 char *p = arg + sizeof ("--word=") - 1; 3737 int len; 3738 3739 if (! safe_parse_maxint (&p, &len)) 3740 return 1; 3741 3742 switch (len) 3743 { 3744 case 5: word_len = UART_5BITS_WORD; break; 3745 case 6: word_len = UART_6BITS_WORD; break; 3746 case 7: word_len = UART_7BITS_WORD; break; 3747 case 8: word_len = UART_8BITS_WORD; break; 3748 default: 3749 errnum = ERR_BAD_ARGUMENT; 3750 return 1; 3751 } 3752 } 3753 else if (grub_memcmp (arg, "--stop=", sizeof ("--stop=") - 1) == 0) 3754 { 3755 char *p = arg + sizeof ("--stop=") - 1; 3756 int len; 3757 3758 if (! safe_parse_maxint (&p, &len)) 3759 return 1; 3760 3761 switch (len) 3762 { 3763 case 1: stop_bit_len = UART_1_STOP_BIT; break; 3764 case 2: stop_bit_len = UART_2_STOP_BITS; break; 3765 default: 3766 errnum = ERR_BAD_ARGUMENT; 3767 return 1; 3768 } 3769 } 3770 else if (grub_memcmp (arg, "--parity=", sizeof ("--parity=") - 1) == 0) 3771 { 3772 char *p = arg + sizeof ("--parity=") - 1; 3773 3774 if (grub_memcmp (p, "no", sizeof ("no") - 1) == 0) 3775 parity = UART_NO_PARITY; 3776 else if (grub_memcmp (p, "odd", sizeof ("odd") - 1) == 0) 3777 parity = UART_ODD_PARITY; 3778 else if (grub_memcmp (p, "even", sizeof ("even") - 1) == 0) 3779 parity = UART_EVEN_PARITY; 3780 else 3781 { 3782 errnum = ERR_BAD_ARGUMENT; 3783 return 1; 3784 } 3785 } 3786 # ifdef GRUB_UTIL 3787 /* In the grub shell, don't use any port number but open a tty 3788 device instead. */ 3789 else if (grub_memcmp (arg, "--device=", sizeof ("--device=") - 1) == 0) 3790 { 3791 char *p = arg + sizeof ("--device=") - 1; 3792 char dev[256]; /* XXX */ 3793 char *q = dev; 3794 3795 while (*p && ! grub_isspace (*p)) 3796 *q++ = *p++; 3797 3798 *q = 0; 3799 serial_set_device (dev); 3800 } 3801 # endif /* GRUB_UTIL */ 3802 else 3803 break; 3804 3805 arg = skip_to (0, arg); 3806 } 3807 3808 /* Initialize the serial unit. */ 3809 if (! serial_hw_init (port, speed, word_len, parity, stop_bit_len)) 3810 { 3811 errnum = ERR_BAD_ARGUMENT; 3812 return 1; 3813 } 3814 3815 return 0; 3816 } 3817 3818 static struct builtin builtin_serial = 3819 { 3820 "serial", 3821 serial_func, 3822 BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST, 3823 "serial [--unit=UNIT] [--port=PORT] [--speed=SPEED] [--word=WORD] [--parity=PARITY] [--stop=STOP] [--device=DEV]", 3824 "Initialize a serial device. UNIT is a digit that specifies which serial" 3825 " device is used (e.g. 0 == COM1). If you need to specify the port number," 3826 " set it by --port. SPEED is the DTE-DTE speed. WORD is the word length," 3827 " PARITY is the type of parity, which is one of `no', `odd' and `even'." 3828 " STOP is the length of stop bit(s). The option --device can be used only" 3829 " in the grub shell, which specifies the file name of a tty device. The" 3830 " default values are COM1, 9600, 8N1." 3831 }; 3832 #endif /* SUPPORT_SERIAL */ 3833 3834 3835 /* setkey */ 3836 struct keysym 3837 { 3838 char *unshifted_name; /* the name in unshifted state */ 3839 char *shifted_name; /* the name in shifted state */ 3840 unsigned char unshifted_ascii; /* the ascii code in unshifted state */ 3841 unsigned char shifted_ascii; /* the ascii code in shifted state */ 3842 unsigned char keycode; /* keyboard scancode */ 3843 }; 3844 3845 /* The table for key symbols. If the "shifted" member of an entry is 3846 NULL, the entry does not have shifted state. */ 3847 static struct keysym keysym_table[] = 3848 { 3849 {"escape", 0, 0x1b, 0, 0x01}, 3850 {"1", "exclam", '1', '!', 0x02}, 3851 {"2", "at", '2', '@', 0x03}, 3852 {"3", "numbersign", '3', '#', 0x04}, 3853 {"4", "dollar", '4', '$', 0x05}, 3854 {"5", "percent", '5', '%', 0x06}, 3855 {"6", "caret", '6', '^', 0x07}, 3856 {"7", "ampersand", '7', '&', 0x08}, 3857 {"8", "asterisk", '8', '*', 0x09}, 3858 {"9", "parenleft", '9', '(', 0x0a}, 3859 {"0", "parenright", '0', ')', 0x0b}, 3860 {"minus", "underscore", '-', '_', 0x0c}, 3861 {"equal", "plus", '=', '+', 0x0d}, 3862 {"backspace", 0, '\b', 0, 0x0e}, 3863 {"tab", 0, '\t', 0, 0x0f}, 3864 {"q", "Q", 'q', 'Q', 0x10}, 3865 {"w", "W", 'w', 'W', 0x11}, 3866 {"e", "E", 'e', 'E', 0x12}, 3867 {"r", "R", 'r', 'R', 0x13}, 3868 {"t", "T", 't', 'T', 0x14}, 3869 {"y", "Y", 'y', 'Y', 0x15}, 3870 {"u", "U", 'u', 'U', 0x16}, 3871 {"i", "I", 'i', 'I', 0x17}, 3872 {"o", "O", 'o', 'O', 0x18}, 3873 {"p", "P", 'p', 'P', 0x19}, 3874 {"bracketleft", "braceleft", '[', '{', 0x1a}, 3875 {"bracketright", "braceright", ']', '}', 0x1b}, 3876 {"enter", 0, '\n', 0, 0x1c}, 3877 {"control", 0, 0, 0, 0x1d}, 3878 {"a", "A", 'a', 'A', 0x1e}, 3879 {"s", "S", 's', 'S', 0x1f}, 3880 {"d", "D", 'd', 'D', 0x20}, 3881 {"f", "F", 'f', 'F', 0x21}, 3882 {"g", "G", 'g', 'G', 0x22}, 3883 {"h", "H", 'h', 'H', 0x23}, 3884 {"j", "J", 'j', 'J', 0x24}, 3885 {"k", "K", 'k', 'K', 0x25}, 3886 {"l", "L", 'l', 'L', 0x26}, 3887 {"semicolon", "colon", ';', ':', 0x27}, 3888 {"quote", "doublequote", '\'', '"', 0x28}, 3889 {"backquote", "tilde", '`', '~', 0x29}, 3890 {"shift", 0, 0, 0, 0x2a}, 3891 {"backslash", "bar", '\\', '|', 0x2b}, 3892 {"z", "Z", 'z', 'Z', 0x2c}, 3893 {"x", "X", 'x', 'X', 0x2d}, 3894 {"c", "C", 'c', 'C', 0x2e}, 3895 {"v", "V", 'v', 'V', 0x2f}, 3896 {"b", "B", 'b', 'B', 0x30}, 3897 {"n", "N", 'n', 'N', 0x31}, 3898 {"m", "M", 'm', 'M', 0x32}, 3899 {"comma", "less", ',', '<', 0x33}, 3900 {"period", "greater", '.', '>', 0x34}, 3901 {"slash", "question", '/', '?', 0x35}, 3902 {"alt", 0, 0, 0, 0x38}, 3903 {"space", 0, ' ', 0, 0x39}, 3904 {"capslock", 0, 0, 0, 0x3a}, 3905 {"F1", 0, 0, 0, 0x3b}, 3906 {"F2", 0, 0, 0, 0x3c}, 3907 {"F3", 0, 0, 0, 0x3d}, 3908 {"F4", 0, 0, 0, 0x3e}, 3909 {"F5", 0, 0, 0, 0x3f}, 3910 {"F6", 0, 0, 0, 0x40}, 3911 {"F7", 0, 0, 0, 0x41}, 3912 {"F8", 0, 0, 0, 0x42}, 3913 {"F9", 0, 0, 0, 0x43}, 3914 {"F10", 0, 0, 0, 0x44}, 3915 /* Caution: do not add NumLock here! we cannot deal with it properly. */ 3916 {"delete", 0, 0x7f, 0, 0x53} 3917 }; 3918 3919 static int 3920 setkey_func (char *arg, int flags) 3921 { 3922 char *to_key, *from_key; 3923 int to_code, from_code; 3924 int map_in_interrupt = 0; 3925 3926 static int find_key_code (char *key) 3927 { 3928 int i; 3929 3930 for (i = 0; i < sizeof (keysym_table) / sizeof (keysym_table[0]); i++) 3931 { 3932 if (keysym_table[i].unshifted_name && 3933 grub_strcmp (key, keysym_table[i].unshifted_name) == 0) 3934 return keysym_table[i].keycode; 3935 else if (keysym_table[i].shifted_name && 3936 grub_strcmp (key, keysym_table[i].shifted_name) == 0) 3937 return keysym_table[i].keycode; 3938 } 3939 3940 return 0; 3941 } 3942 3943 static int find_ascii_code (char *key) 3944 { 3945 int i; 3946 3947 for (i = 0; i < sizeof (keysym_table) / sizeof (keysym_table[0]); i++) 3948 { 3949 if (keysym_table[i].unshifted_name && 3950 grub_strcmp (key, keysym_table[i].unshifted_name) == 0) 3951 return keysym_table[i].unshifted_ascii; 3952 else if (keysym_table[i].shifted_name && 3953 grub_strcmp (key, keysym_table[i].shifted_name) == 0) 3954 return keysym_table[i].shifted_ascii; 3955 } 3956 3957 return 0; 3958 } 3959 3960 to_key = arg; 3961 from_key = skip_to (0, to_key); 3962 3963 if (! *to_key) 3964 { 3965 /* If the user specifies no argument, reset the key mappings. */ 3966 grub_memset (bios_key_map, 0, KEY_MAP_SIZE * sizeof (unsigned short)); 3967 grub_memset (ascii_key_map, 0, KEY_MAP_SIZE * sizeof (unsigned short)); 3968 3969 return 0; 3970 } 3971 else if (! *from_key) 3972 { 3973 /* The user must specify two arguments or zero argument. */ 3974 errnum = ERR_BAD_ARGUMENT; 3975 return 1; 3976 } 3977 3978 nul_terminate (to_key); 3979 nul_terminate (from_key); 3980 3981 to_code = find_ascii_code (to_key); 3982 from_code = find_ascii_code (from_key); 3983 if (! to_code || ! from_code) 3984 { 3985 map_in_interrupt = 1; 3986 to_code = find_key_code (to_key); 3987 from_code = find_key_code (from_key); 3988 if (! to_code || ! from_code) 3989 { 3990 errnum = ERR_BAD_ARGUMENT; 3991 return 1; 3992 } 3993 } 3994 3995 if (map_in_interrupt) 3996 { 3997 int i; 3998 3999 /* Find an empty slot. */ 4000 for (i = 0; i < KEY_MAP_SIZE; i++) 4001 { 4002 if ((bios_key_map[i] & 0xff) == from_code) 4003 /* Perhaps the user wants to overwrite the map. */ 4004 break; 4005 4006 if (! bios_key_map[i]) 4007 break; 4008 } 4009 4010 if (i == KEY_MAP_SIZE) 4011 { 4012 errnum = ERR_WONT_FIT; 4013 return 1; 4014 } 4015 4016 if (to_code == from_code) 4017 /* If TO is equal to FROM, delete the entry. */ 4018 grub_memmove ((char *) &bios_key_map[i], 4019 (char *) &bios_key_map[i + 1], 4020 sizeof (unsigned short) * (KEY_MAP_SIZE - i)); 4021 else 4022 bios_key_map[i] = (to_code << 8) | from_code; 4023 4024 /* Ugly but should work. */ 4025 unset_int15_handler (); 4026 set_int15_handler (); 4027 } 4028 else 4029 { 4030 int i; 4031 4032 /* Find an empty slot. */ 4033 for (i = 0; i < KEY_MAP_SIZE; i++) 4034 { 4035 if ((ascii_key_map[i] & 0xff) == from_code) 4036 /* Perhaps the user wants to overwrite the map. */ 4037 break; 4038 4039 if (! ascii_key_map[i]) 4040 break; 4041 } 4042 4043 if (i == KEY_MAP_SIZE) 4044 { 4045 errnum = ERR_WONT_FIT; 4046 return 1; 4047 } 4048 4049 if (to_code == from_code) 4050 /* If TO is equal to FROM, delete the entry. */ 4051 grub_memmove ((char *) &ascii_key_map[i], 4052 (char *) &ascii_key_map[i + 1], 4053 sizeof (unsigned short) * (KEY_MAP_SIZE - i)); 4054 else 4055 ascii_key_map[i] = (to_code << 8) | from_code; 4056 } 4057 4058 return 0; 4059 } 4060 4061 static struct builtin builtin_setkey = 4062 { 4063 "setkey", 4064 setkey_func, 4065 BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST, 4066 "setkey [TO_KEY FROM_KEY]", 4067 "Change the keyboard map. The key FROM_KEY is mapped to the key TO_KEY." 4068 " A key must be an alphabet, a digit, or one of these: escape, exclam," 4069 " at, numbersign, dollar, percent, caret, ampersand, asterisk, parenleft," 4070 " parenright, minus, underscore, equal, plus, backspace, tab, bracketleft," 4071 " braceleft, bracketright, braceright, enter, control, semicolon, colon," 4072 " quote, doublequote, backquote, tilde, shift, backslash, bar, comma," 4073 " less, period, greater, slash, question, alt, space, capslock, FX (X" 4074 " is a digit), and delete. If no argument is specified, reset key" 4075 " mappings." 4076 }; 4077 4078 4079 /* setup */ 4080 static int 4081 setup_func (char *arg, int flags) 4082 { 4083 /* Point to the string of the installed drive/partition. */ 4084 char *install_ptr; 4085 /* Point to the string of the drive/parition where the GRUB images 4086 reside. */ 4087 char *image_ptr; 4088 unsigned long installed_drive, installed_partition; 4089 unsigned long image_drive, image_partition; 4090 unsigned long tmp_drive, tmp_partition; 4091 char stage1[64]; 4092 char stage2[64]; 4093 char config_filename[64]; 4094 char real_config_filename[64]; 4095 char cmd_arg[256]; 4096 char device[16]; 4097 char *buffer = (char *) RAW_ADDR (0x100000); 4098 int is_force_lba = 0; 4099 char *stage2_arg = 0; 4100 char *prefix = 0; 4101 4102 auto int check_file (char *file); 4103 auto void sprint_device (int drive, int partition); 4104 auto int embed_stage1_5 (char * stage1_5, int drive, int partition); 4105 4106 /* Check if the file FILE exists like Autoconf. */ 4107 int check_file (char *file) 4108 { 4109 int ret; 4110 4111 grub_printf (" Checking if \"%s\" exists... ", file); 4112 ret = grub_open (file); 4113 if (ret) 4114 { 4115 grub_close (); 4116 grub_printf ("yes\n"); 4117 } 4118 else 4119 grub_printf ("no\n"); 4120 4121 return ret; 4122 } 4123 4124 /* Construct a device name in DEVICE. */ 4125 void sprint_device (int drive, int partition) 4126 { 4127 grub_sprintf (device, "(%cd%d", 4128 (drive & 0x80) ? 'h' : 'f', 4129 drive & ~0x80); 4130 if ((partition & 0xFF0000) != 0xFF0000) 4131 { 4132 char tmp[16]; 4133 grub_sprintf (tmp, ",%d", (partition >> 16) & 0xFF); 4134 grub_strncat (device, tmp, 256); 4135 } 4136 if ((partition & 0x00FF00) != 0x00FF00) 4137 { 4138 char tmp[16]; 4139 grub_sprintf (tmp, ",%c", 'a' + ((partition >> 8) & 0xFF)); 4140 grub_strncat (device, tmp, 256); 4141 } 4142 grub_strncat (device, ")", 256); 4143 } 4144 4145 int embed_stage1_5 (char *stage1_5, int drive, int partition) 4146 { 4147 /* We install GRUB into the MBR, so try to embed the 4148 Stage 1.5 in the sectors right after the MBR. */ 4149 sprint_device (drive, partition); 4150 grub_sprintf (cmd_arg, "%s %s", stage1_5, device); 4151 4152 /* Notify what will be run. */ 4153 grub_printf (" Running \"embed %s\"... ", cmd_arg); 4154 4155 embed_func (cmd_arg, flags); 4156 if (! errnum) 4157 { 4158 /* Construct the blocklist representation. */ 4159 grub_sprintf (buffer, "%s%s", device, embed_info); 4160 grub_printf ("succeeded\n"); 4161 return 1; 4162 } 4163 else 4164 { 4165 grub_printf ("failed (this is not fatal)\n"); 4166 return 0; 4167 } 4168 } 4169 4170 struct stage1_5_map { 4171 char *fsys; 4172 char *name; 4173 }; 4174 struct stage1_5_map stage1_5_map[] = 4175 { 4176 {"ext2fs", "/e2fs_stage1_5"}, 4177 {"fat", "/fat_stage1_5"}, 4178 {"ufs2", "/ufs2_stage1_5"}, 4179 {"ffs", "/ffs_stage1_5"}, 4180 {"iso9660", "/iso9660_stage1_5"}, 4181 {"jfs", "/jfs_stage1_5"}, 4182 {"minix", "/minix_stage1_5"}, 4183 {"reiserfs", "/reiserfs_stage1_5"}, 4184 {"vstafs", "/vstafs_stage1_5"}, 4185 {"xfs", "/xfs_stage1_5"}, 4186 {"ufs", "/ufs_stage1_5"} 4187 }; 4188 4189 tmp_drive = saved_drive; 4190 tmp_partition = saved_partition; 4191 4192 /* Check if the user specifies --force-lba. */ 4193 while (1) 4194 { 4195 if (grub_memcmp ("--force-lba", arg, sizeof ("--force-lba") - 1) == 0) 4196 { 4197 is_force_lba = 1; 4198 arg = skip_to (0, arg); 4199 } 4200 else if (grub_memcmp ("--prefix=", arg, sizeof ("--prefix=") - 1) == 0) 4201 { 4202 prefix = arg + sizeof ("--prefix=") - 1; 4203 arg = skip_to (0, arg); 4204 nul_terminate (prefix); 4205 } 4206 #ifdef GRUB_UTIL 4207 else if (grub_memcmp ("--stage2=", arg, sizeof ("--stage2=") - 1) == 0) 4208 { 4209 stage2_arg = arg; 4210 arg = skip_to (0, arg); 4211 nul_terminate (stage2_arg); 4212 } 4213 #endif /* GRUB_UTIL */ 4214 else 4215 break; 4216 } 4217 4218 install_ptr = arg; 4219 image_ptr = skip_to (0, install_ptr); 4220 4221 /* Make sure that INSTALL_PTR is valid. */ 4222 set_device (install_ptr); 4223 if (errnum) 4224 return 1; 4225 4226 installed_drive = current_drive; 4227 installed_partition = current_partition; 4228 4229 /* Mount the drive pointed by IMAGE_PTR. */ 4230 if (*image_ptr) 4231 { 4232 /* If the drive/partition where the images reside is specified, 4233 get the drive and the partition. */ 4234 set_device (image_ptr); 4235 if (errnum) 4236 return 1; 4237 } 4238 else 4239 { 4240 /* If omitted, use SAVED_PARTITION and SAVED_DRIVE. */ 4241 current_drive = saved_drive; 4242 current_partition = saved_partition; 4243 } 4244 4245 image_drive = saved_drive = current_drive; 4246 image_partition = saved_partition = current_partition; 4247 4248 /* Open it. */ 4249 if (! open_device ()) 4250 goto fail; 4251 4252 /* Check if stage1 exists. If the user doesn't specify the option 4253 `--prefix', attempt /boot/grub and /grub. */ 4254 /* NOTE: It is dangerous to run this command without `--prefix' in the 4255 grub shell, since that affects `--stage2'. */ 4256 if (! prefix) 4257 { 4258 prefix = "/boot/grub"; 4259 grub_sprintf (stage1, "%s%s", prefix, "/stage1"); 4260 if (! check_file (stage1)) 4261 { 4262 errnum = ERR_NONE; 4263 prefix = "/grub"; 4264 grub_sprintf (stage1, "%s%s", prefix, "/stage1"); 4265 if (! check_file (stage1)) 4266 goto fail; 4267 } 4268 } 4269 else 4270 { 4271 grub_sprintf (stage1, "%s%s", prefix, "/stage1"); 4272 if (! check_file (stage1)) 4273 goto fail; 4274 } 4275 4276 /* The prefix was determined. */ 4277 grub_sprintf (stage2, "%s%s", prefix, "/stage2"); 4278 grub_sprintf (config_filename, "%s%s", prefix, "/menu.lst"); 4279 *real_config_filename = 0; 4280 4281 /* Check if stage2 exists. */ 4282 if (! check_file (stage2)) 4283 goto fail; 4284 4285 { 4286 char *fsys = fsys_table[fsys_type].name; 4287 int i; 4288 int size = sizeof (stage1_5_map) / sizeof (stage1_5_map[0]); 4289 4290 /* Iterate finding the same filesystem name as FSYS. */ 4291 for (i = 0; i < size; i++) 4292 if (grub_strcmp (fsys, stage1_5_map[i].fsys) == 0) 4293 { 4294 /* OK, check if the Stage 1.5 exists. */ 4295 char stage1_5[64]; 4296 4297 grub_sprintf (stage1_5, "%s%s", prefix, stage1_5_map[i].name); 4298 if (check_file (stage1_5)) 4299 { 4300 if (embed_stage1_5 (stage1_5, 4301 installed_drive, installed_partition) 4302 || embed_stage1_5 (stage1_5, 4303 image_drive, image_partition)) 4304 { 4305 grub_strcpy (real_config_filename, config_filename); 4306 sprint_device (image_drive, image_partition); 4307 grub_sprintf (config_filename, "%s%s", device, stage2); 4308 grub_strcpy (stage2, buffer); 4309 } 4310 } 4311 errnum = 0; 4312 break; 4313 } 4314 } 4315 4316 /* Construct a string that is used by the command "install" as its 4317 arguments. */ 4318 sprint_device (installed_drive, installed_partition); 4319 4320 #if 1 4321 /* Don't embed a drive number unnecessarily. */ 4322 grub_sprintf (cmd_arg, "%s%s%s%s %s%s %s p %s %s", 4323 is_force_lba? "--force-lba " : "", 4324 stage2_arg? stage2_arg : "", 4325 stage2_arg? " " : "", 4326 stage1, 4327 (installed_drive != image_drive) ? "d " : "", 4328 device, 4329 stage2, 4330 config_filename, 4331 real_config_filename); 4332 #else /* NOT USED */ 4333 /* This code was used, because we belived some BIOSes had a problem 4334 that they didn't pass a booting drive correctly. It turned out, 4335 however, stage1 could trash a booting drive when checking LBA support, 4336 because some BIOSes modified the register %dx in INT 13H, AH=48H. 4337 So it becamed unclear whether GRUB should use a pre-defined booting 4338 drive or not. If the problem still exists, it would be necessary to 4339 switch back to this code. */ 4340 grub_sprintf (cmd_arg, "%s%s%s%s d %s %s p %s %s", 4341 is_force_lba? "--force-lba " : "", 4342 stage2_arg? stage2_arg : "", 4343 stage2_arg? " " : "", 4344 stage1, 4345 device, 4346 stage2, 4347 config_filename, 4348 real_config_filename); 4349 #endif /* NOT USED */ 4350 4351 /* Notify what will be run. */ 4352 grub_printf (" Running \"install %s\"... ", cmd_arg); 4353 4354 /* Make sure that SAVED_DRIVE and SAVED_PARTITION are identical 4355 with IMAGE_DRIVE and IMAGE_PARTITION, respectively. */ 4356 saved_drive = image_drive; 4357 saved_partition = image_partition; 4358 4359 /* Run the command. */ 4360 if (! install_func (cmd_arg, flags)) 4361 grub_printf ("succeeded\nDone.\n"); 4362 else 4363 grub_printf ("failed\n"); 4364 4365 fail: 4366 saved_drive = tmp_drive; 4367 saved_partition = tmp_partition; 4368 return errnum; 4369 } 4370 4371 static struct builtin builtin_setup = 4372 { 4373 "setup", 4374 setup_func, 4375 BUILTIN_CMDLINE | BUILTIN_HELP_LIST, 4376 "setup [--prefix=DIR] [--stage2=STAGE2_FILE] [--force-lba] INSTALL_DEVICE [IMAGE_DEVICE]", 4377 "Set up the installation of GRUB automatically. This command uses" 4378 " the more flexible command \"install\" in the backend and installs" 4379 " GRUB into the device INSTALL_DEVICE. If IMAGE_DEVICE is specified," 4380 " then find the GRUB images in the device IMAGE_DEVICE, otherwise" 4381 " use the current \"root device\", which can be set by the command" 4382 " \"root\". If you know that your BIOS should support LBA but GRUB" 4383 " doesn't work in LBA mode, specify the option `--force-lba'." 4384 " If you install GRUB under the grub shell and you cannot unmount the" 4385 " partition where GRUB images reside, specify the option `--stage2'" 4386 " to tell GRUB the file name under your OS." 4387 }; 4388 4389 4390 #if defined(SUPPORT_SERIAL) || defined(SUPPORT_HERCULES) || defined(SUPPORT_GRAPHICS) 4391 /* terminal */ 4392 static int 4393 terminal_func (char *arg, int flags) 4394 { 4395 /* The index of the default terminal in TERM_TABLE. */ 4396 int default_term = -1; 4397 struct term_entry *prev_term = current_term; 4398 int to = -1; 4399 int lines = 0; 4400 int no_message = 0; 4401 unsigned long term_flags = 0; 4402 /* XXX: Assume less than 32 terminals. */ 4403 unsigned long term_bitmap = 0; 4404 4405 /* Get GNU-style long options. */ 4406 while (1) 4407 { 4408 if (grub_memcmp (arg, "--dumb", sizeof ("--dumb") - 1) == 0) 4409 term_flags |= TERM_DUMB; 4410 else if (grub_memcmp (arg, "--no-echo", sizeof ("--no-echo") - 1) == 0) 4411 /* ``--no-echo'' implies ``--no-edit''. */ 4412 term_flags |= (TERM_NO_ECHO | TERM_NO_EDIT); 4413 else if (grub_memcmp (arg, "--no-edit", sizeof ("--no-edit") - 1) == 0) 4414 term_flags |= TERM_NO_EDIT; 4415 else if (grub_memcmp (arg, "--timeout=", sizeof ("--timeout=") - 1) == 0) 4416 { 4417 char *val = arg + sizeof ("--timeout=") - 1; 4418 4419 if (! safe_parse_maxint (&val, &to)) 4420 return 1; 4421 } 4422 else if (grub_memcmp (arg, "--lines=", sizeof ("--lines=") - 1) == 0) 4423 { 4424 char *val = arg + sizeof ("--lines=") - 1; 4425 4426 if (! safe_parse_maxint (&val, &lines)) 4427 return 1; 4428 4429 /* Probably less than four is meaningless.... */ 4430 if (lines < 4) 4431 { 4432 errnum = ERR_BAD_ARGUMENT; 4433 return 1; 4434 } 4435 } 4436 else if (grub_memcmp (arg, "--silent", sizeof ("--silent") - 1) == 0) 4437 no_message = 1; 4438 else 4439 break; 4440 4441 arg = skip_to (0, arg); 4442 } 4443 4444 /* If no argument is specified, show current setting. */ 4445 if (! *arg) 4446 { 4447 grub_printf ("%s%s%s%s\n", 4448 current_term->name, 4449 current_term->flags & TERM_DUMB ? " (dumb)" : "", 4450 current_term->flags & TERM_NO_EDIT ? " (no edit)" : "", 4451 current_term->flags & TERM_NO_ECHO ? " (no echo)" : ""); 4452 return 0; 4453 } 4454 4455 while (*arg) 4456 { 4457 int i; 4458 char *next = skip_to (0, arg); 4459 4460 nul_terminate (arg); 4461 4462 for (i = 0; term_table[i].name; i++) 4463 { 4464 if (grub_strcmp (arg, term_table[i].name) == 0) 4465 { 4466 if (term_table[i].flags & TERM_NEED_INIT) 4467 { 4468 errnum = ERR_DEV_NEED_INIT; 4469 return 1; 4470 } 4471 4472 if (default_term < 0) 4473 default_term = i; 4474 4475 term_bitmap |= (1 << i); 4476 break; 4477 } 4478 } 4479 4480 if (! term_table[i].name) 4481 { 4482 errnum = ERR_BAD_ARGUMENT; 4483 return 1; 4484 } 4485 4486 arg = next; 4487 } 4488 4489 /* If multiple terminals are specified, wait until the user pushes any 4490 key on one of the terminals. */ 4491 if (term_bitmap & ~(1 << default_term)) 4492 { 4493 int time1, time2 = -1; 4494 4495 /* XXX: Disable the pager. */ 4496 count_lines = -1; 4497 4498 /* Get current time. */ 4499 while ((time1 = getrtsecs ()) == 0xFF) 4500 ; 4501 4502 /* Wait for a key input. */ 4503 while (to) 4504 { 4505 int i; 4506 4507 for (i = 0; term_table[i].name; i++) 4508 { 4509 if (term_bitmap & (1 << i)) 4510 { 4511 if (term_table[i].checkkey () >= 0) 4512 { 4513 (void) term_table[i].getkey (); 4514 default_term = i; 4515 4516 goto end; 4517 } 4518 } 4519 } 4520 4521 /* Prompt the user, once per sec. */ 4522 if ((time1 = getrtsecs ()) != time2 && time1 != 0xFF) 4523 { 4524 if (! no_message) 4525 { 4526 /* Need to set CURRENT_TERM to each of selected 4527 terminals. */ 4528 for (i = 0; term_table[i].name; i++) 4529 if (term_bitmap & (1 << i)) 4530 { 4531 current_term = term_table + i; 4532 grub_printf ("\rPress any key to continue.\n"); 4533 } 4534 4535 /* Restore CURRENT_TERM. */ 4536 current_term = prev_term; 4537 } 4538 4539 time2 = time1; 4540 if (to > 0) 4541 to--; 4542 } 4543 } 4544 } 4545 4546 end: 4547 current_term = term_table + default_term; 4548 current_term->flags = term_flags; 4549 4550 if (lines) 4551 max_lines = lines; 4552 else 4553 max_lines = current_term->max_lines; 4554 4555 /* If the interface is currently the command-line, 4556 restart it to repaint the screen. */ 4557 if ((current_term != prev_term) && (flags & BUILTIN_CMDLINE)){ 4558 if (prev_term->shutdown) 4559 prev_term->shutdown(); 4560 if (current_term->startup) 4561 current_term->startup(); 4562 grub_longjmp (restart_cmdline_env, 0); 4563 } 4564 4565 return 0; 4566 } 4567 4568 static struct builtin builtin_terminal = 4569 { 4570 "terminal", 4571 terminal_func, 4572 BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST, 4573 "terminal [--dumb] [--no-echo] [--no-edit] [--timeout=SECS] [--lines=LINES] [--silent] [console] [serial] [hercules] [graphics]", 4574 "Select a terminal. When multiple terminals are specified, wait until" 4575 " you push any key to continue. If both console and serial are specified," 4576 " the terminal to which you input a key first will be selected. If no" 4577 " argument is specified, print current setting. The option --dumb" 4578 " specifies that your terminal is dumb, otherwise, vt100-compatibility" 4579 " is assumed. If you specify --no-echo, input characters won't be echoed." 4580 " If you specify --no-edit, the BASH-like editing feature will be disabled." 4581 " If --timeout is present, this command will wait at most for SECS" 4582 " seconds. The option --lines specifies the maximum number of lines." 4583 " The option --silent is used to suppress messages." 4584 }; 4585 #endif /* SUPPORT_SERIAL || SUPPORT_HERCULES || SUPPORT_GRAPHICS */ 4586 4587 4588 #ifdef SUPPORT_SERIAL 4589 static int 4590 terminfo_func (char *arg, int flags) 4591 { 4592 struct terminfo term; 4593 4594 if (*arg) 4595 { 4596 struct 4597 { 4598 const char *name; 4599 char *var; 4600 } 4601 options[] = 4602 { 4603 {"--name=", term.name}, 4604 {"--cursor-address=", term.cursor_address}, 4605 {"--clear-screen=", term.clear_screen}, 4606 {"--enter-standout-mode=", term.enter_standout_mode}, 4607 {"--exit-standout-mode=", term.exit_standout_mode} 4608 }; 4609 4610 grub_memset (&term, 0, sizeof (term)); 4611 4612 while (*arg) 4613 { 4614 int i; 4615 char *next = skip_to (0, arg); 4616 4617 nul_terminate (arg); 4618 4619 for (i = 0; i < sizeof (options) / sizeof (options[0]); i++) 4620 { 4621 const char *name = options[i].name; 4622 int len = grub_strlen (name); 4623 4624 if (! grub_memcmp (arg, name, len)) 4625 { 4626 grub_strcpy (options[i].var, ti_unescape_string (arg + len)); 4627 break; 4628 } 4629 } 4630 4631 if (i == sizeof (options) / sizeof (options[0])) 4632 { 4633 errnum = ERR_BAD_ARGUMENT; 4634 return errnum; 4635 } 4636 4637 arg = next; 4638 } 4639 4640 if (term.name[0] == 0 || term.cursor_address[0] == 0) 4641 { 4642 errnum = ERR_BAD_ARGUMENT; 4643 return errnum; 4644 } 4645 4646 ti_set_term (&term); 4647 } 4648 else 4649 { 4650 /* No option specifies printing out current settings. */ 4651 ti_get_term (&term); 4652 4653 grub_printf ("name=%s\n", 4654 ti_escape_string (term.name)); 4655 grub_printf ("cursor_address=%s\n", 4656 ti_escape_string (term.cursor_address)); 4657 grub_printf ("clear_screen=%s\n", 4658 ti_escape_string (term.clear_screen)); 4659 grub_printf ("enter_standout_mode=%s\n", 4660 ti_escape_string (term.enter_standout_mode)); 4661 grub_printf ("exit_standout_mode=%s\n", 4662 ti_escape_string (term.exit_standout_mode)); 4663 } 4664 4665 return 0; 4666 } 4667 4668 static struct builtin builtin_terminfo = 4669 { 4670 "terminfo", 4671 terminfo_func, 4672 BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST, 4673 "terminfo [--name=NAME --cursor-address=SEQ [--clear-screen=SEQ]" 4674 " [--enter-standout-mode=SEQ] [--exit-standout-mode=SEQ]]", 4675 4676 "Define the capabilities of your terminal. Use this command to" 4677 " define escape sequences, if it is not vt100-compatible." 4678 " You may use \\e for ESC and ^X for a control character." 4679 " If no option is specified, the current settings are printed." 4680 }; 4681 #endif /* SUPPORT_SERIAL */ 4682 4683 4684 /* testload */ 4685 static int 4686 testload_func (char *arg, int flags) 4687 { 4688 int i; 4689 4690 kernel_type = KERNEL_TYPE_NONE; 4691 4692 if (! grub_open (arg)) 4693 return 1; 4694 4695 disk_read_hook = disk_read_print_func; 4696 4697 /* Perform filesystem test on the specified file. */ 4698 /* Read whole file first. */ 4699 grub_printf ("Whole file: "); 4700 4701 grub_read ((char *) RAW_ADDR (0x100000), -1); 4702 4703 /* Now compare two sections of the file read differently. */ 4704 4705 for (i = 0; i < 0x10ac0; i++) 4706 { 4707 *((unsigned char *) RAW_ADDR (0x200000 + i)) = 0; 4708 *((unsigned char *) RAW_ADDR (0x300000 + i)) = 1; 4709 } 4710 4711 /* First partial read. */ 4712 grub_printf ("\nPartial read 1: "); 4713 4714 grub_seek (0); 4715 grub_read ((char *) RAW_ADDR (0x200000), 0x7); 4716 grub_read ((char *) RAW_ADDR (0x200007), 0x100); 4717 grub_read ((char *) RAW_ADDR (0x200107), 0x10); 4718 grub_read ((char *) RAW_ADDR (0x200117), 0x999); 4719 grub_read ((char *) RAW_ADDR (0x200ab0), 0x10); 4720 grub_read ((char *) RAW_ADDR (0x200ac0), 0x10000); 4721 4722 /* Second partial read. */ 4723 grub_printf ("\nPartial read 2: "); 4724 4725 grub_seek (0); 4726 grub_read ((char *) RAW_ADDR (0x300000), 0x10000); 4727 grub_read ((char *) RAW_ADDR (0x310000), 0x10); 4728 grub_read ((char *) RAW_ADDR (0x310010), 0x7); 4729 grub_read ((char *) RAW_ADDR (0x310017), 0x10); 4730 grub_read ((char *) RAW_ADDR (0x310027), 0x999); 4731 grub_read ((char *) RAW_ADDR (0x3109c0), 0x100); 4732 4733 grub_printf ("\nHeader1 = 0x%x, next = 0x%x, next = 0x%x, next = 0x%x\n", 4734 *((int *) RAW_ADDR (0x200000)), 4735 *((int *) RAW_ADDR (0x200004)), 4736 *((int *) RAW_ADDR (0x200008)), 4737 *((int *) RAW_ADDR (0x20000c))); 4738 4739 grub_printf ("Header2 = 0x%x, next = 0x%x, next = 0x%x, next = 0x%x\n", 4740 *((int *) RAW_ADDR (0x300000)), 4741 *((int *) RAW_ADDR (0x300004)), 4742 *((int *) RAW_ADDR (0x300008)), 4743 *((int *) RAW_ADDR (0x30000c))); 4744 4745 for (i = 0; i < 0x10ac0; i++) 4746 if (*((unsigned char *) RAW_ADDR (0x200000 + i)) 4747 != *((unsigned char *) RAW_ADDR (0x300000 + i))) 4748 break; 4749 4750 grub_printf ("Max is 0x10ac0: i=0x%x, filepos=0x%x\n", i, filepos); 4751 disk_read_hook = 0; 4752 grub_close (); 4753 return 0; 4754 } 4755 4756 static struct builtin builtin_testload = 4757 { 4758 "testload", 4759 testload_func, 4760 BUILTIN_CMDLINE, 4761 "testload FILE", 4762 "Read the entire contents of FILE in several different ways and" 4763 " compares them, to test the filesystem code. The output is somewhat" 4764 " cryptic, but if no errors are reported and the final `i=X," 4765 " filepos=Y' reading has X and Y equal, then it is definitely" 4766 " consistent, and very likely works correctly subject to a" 4767 " consistent offset error. If this test succeeds, then a good next" 4768 " step is to try loading a kernel." 4769 }; 4770 4771 4772 /* testvbe MODE */ 4773 static int 4774 testvbe_func (char *arg, int flags) 4775 { 4776 int mode_number; 4777 struct vbe_controller controller; 4778 struct vbe_mode mode; 4779 4780 if (! *arg) 4781 { 4782 errnum = ERR_BAD_ARGUMENT; 4783 return 1; 4784 } 4785 4786 if (! safe_parse_maxint (&arg, &mode_number)) 4787 return 1; 4788 4789 /* Preset `VBE2'. */ 4790 grub_memmove (controller.signature, "VBE2", 4); 4791 4792 /* Detect VBE BIOS. */ 4793 if (get_vbe_controller_info (&controller) != 0x004F) 4794 { 4795 grub_printf (" VBE BIOS is not present.\n"); 4796 return 0; 4797 } 4798 4799 if (controller.version < 0x0200) 4800 { 4801 grub_printf (" VBE version %d.%d is not supported.\n", 4802 (int) (controller.version >> 8), 4803 (int) (controller.version & 0xFF)); 4804 return 0; 4805 } 4806 4807 if (get_vbe_mode_info (mode_number, &mode) != 0x004F 4808 || (mode.mode_attributes & 0x0091) != 0x0091) 4809 { 4810 grub_printf (" Mode 0x%x is not supported.\n", mode_number); 4811 return 0; 4812 } 4813 4814 /* Now trip to the graphics mode. */ 4815 if (set_vbe_mode (mode_number | (1 << 14)) != 0x004F) 4816 { 4817 grub_printf (" Switching to Mode 0x%x failed.\n", mode_number); 4818 return 0; 4819 } 4820 4821 /* Draw something on the screen... */ 4822 { 4823 unsigned char *base_buf = (unsigned char *) mode.phys_base; 4824 int scanline = controller.version >= 0x0300 4825 ? mode.linear_bytes_per_scanline : mode.bytes_per_scanline; 4826 /* FIXME: this assumes that any depth is a modulo of 8. */ 4827 int bpp = mode.bits_per_pixel / 8; 4828 int width = mode.x_resolution; 4829 int height = mode.y_resolution; 4830 int x, y; 4831 unsigned color = 0; 4832 4833 /* Iterate drawing on the screen, until the user hits any key. */ 4834 while (checkkey () == -1) 4835 { 4836 for (y = 0; y < height; y++) 4837 { 4838 unsigned char *line_buf = base_buf + scanline * y; 4839 4840 for (x = 0; x < width; x++) 4841 { 4842 unsigned char *buf = line_buf + bpp * x; 4843 int i; 4844 4845 for (i = 0; i < bpp; i++, buf++) 4846 *buf = (color >> (i * 8)) & 0xff; 4847 } 4848 4849 color++; 4850 } 4851 } 4852 4853 /* Discard the input. */ 4854 getkey (); 4855 } 4856 4857 /* Back to the default text mode. */ 4858 if (set_vbe_mode (0x03) != 0x004F) 4859 { 4860 /* Why?! */ 4861 grub_reboot (); 4862 } 4863 4864 return 0; 4865 } 4866 4867 static struct builtin builtin_testvbe = 4868 { 4869 "testvbe", 4870 testvbe_func, 4871 BUILTIN_CMDLINE | BUILTIN_HELP_LIST, 4872 "testvbe MODE", 4873 "Test the VBE mode MODE. Hit any key to return." 4874 }; 4875 4876 4877 #ifdef SUPPORT_NETBOOT 4878 /* tftpserver */ 4879 static int 4880 tftpserver_func (char *arg, int flags) 4881 { 4882 if (! *arg || ! ifconfig (0, 0, 0, arg)) 4883 { 4884 errnum = ERR_BAD_ARGUMENT; 4885 return 1; 4886 } 4887 4888 print_network_configuration (); 4889 return 0; 4890 } 4891 4892 static struct builtin builtin_tftpserver = 4893 { 4894 "tftpserver", 4895 tftpserver_func, 4896 BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST, 4897 "tftpserver IPADDR", 4898 "Override the TFTP server address." 4899 }; 4900 #endif /* SUPPORT_NETBOOT */ 4901 4902 4903 /* timeout */ 4904 static int 4905 timeout_func (char *arg, int flags) 4906 { 4907 if (! safe_parse_maxint (&arg, &grub_timeout)) 4908 return 1; 4909 4910 return 0; 4911 } 4912 4913 static struct builtin builtin_timeout = 4914 { 4915 "timeout", 4916 timeout_func, 4917 BUILTIN_MENU, 4918 #if 0 4919 "timeout SEC", 4920 "Set a timeout, in SEC seconds, before automatically booting the" 4921 " default entry (normally the first entry defined)." 4922 #endif 4923 }; 4924 4925 4926 /* title */ 4927 static int 4928 title_func (char *arg, int flags) 4929 { 4930 /* This function is not actually used at least currently. */ 4931 return 0; 4932 } 4933 4934 static struct builtin builtin_title = 4935 { 4936 "title", 4937 title_func, 4938 BUILTIN_TITLE, 4939 #if 0 4940 "title [NAME ...]", 4941 "Start a new boot entry, and set its name to the contents of the" 4942 " rest of the line, starting with the first non-space character." 4943 #endif 4944 }; 4945 4946 4947 /* unhide */ 4948 static int 4949 unhide_func (char *arg, int flags) 4950 { 4951 if (! set_device (arg)) 4952 return 1; 4953 4954 if (! set_partition_hidden_flag (0)) 4955 return 1; 4956 4957 return 0; 4958 } 4959 4960 static struct builtin builtin_unhide = 4961 { 4962 "unhide", 4963 unhide_func, 4964 BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST, 4965 "unhide PARTITION", 4966 "Unhide PARTITION by clearing the \"hidden\" bit in its" 4967 " partition type code." 4968 }; 4969 4970 4971 /* uppermem */ 4972 static int 4973 uppermem_func (char *arg, int flags) 4974 { 4975 if (! safe_parse_maxint (&arg, (int *) &mbi.mem_upper)) 4976 return 1; 4977 4978 mbi.flags &= ~MB_INFO_MEM_MAP; 4979 return 0; 4980 } 4981 4982 static struct builtin builtin_uppermem = 4983 { 4984 "uppermem", 4985 uppermem_func, 4986 BUILTIN_CMDLINE | BUILTIN_HELP_LIST, 4987 "uppermem KBYTES", 4988 "Force GRUB to assume that only KBYTES kilobytes of upper memory are" 4989 " installed. Any system address range maps are discarded." 4990 }; 4991 4992 4993 /* vbeprobe */ 4994 static int 4995 vbeprobe_func (char *arg, int flags) 4996 { 4997 struct vbe_controller controller; 4998 unsigned short *mode_list; 4999 int mode_number = -1; 5000 5001 auto unsigned long vbe_far_ptr_to_linear (unsigned long); 5002 5003 unsigned long vbe_far_ptr_to_linear (unsigned long ptr) 5004 { 5005 unsigned short seg = (ptr >> 16); 5006 unsigned short off = (ptr & 0xFFFF); 5007 5008 return (seg << 4) + off; 5009 } 5010 5011 if (*arg) 5012 { 5013 if (! safe_parse_maxint (&arg, &mode_number)) 5014 return 1; 5015 } 5016 5017 /* Set the signature to `VBE2', to obtain VBE 3.0 information. */ 5018 grub_memmove (controller.signature, "VBE2", 4); 5019 5020 if (get_vbe_controller_info (&controller) != 0x004F) 5021 { 5022 grub_printf (" VBE BIOS is not present.\n"); 5023 return 0; 5024 } 5025 5026 /* Check the version. */ 5027 if (controller.version < 0x0200) 5028 { 5029 grub_printf (" VBE version %d.%d is not supported.\n", 5030 (int) (controller.version >> 8), 5031 (int) (controller.version & 0xFF)); 5032 return 0; 5033 } 5034 5035 /* Print some information. */ 5036 grub_printf (" VBE version %d.%d\n", 5037 (int) (controller.version >> 8), 5038 (int) (controller.version & 0xFF)); 5039 5040 /* Iterate probing modes. */ 5041 for (mode_list 5042 = (unsigned short *) vbe_far_ptr_to_linear (controller.video_mode); 5043 *mode_list != 0xFFFF; 5044 mode_list++) 5045 { 5046 struct vbe_mode mode; 5047 5048 if (get_vbe_mode_info (*mode_list, &mode) != 0x004F) 5049 continue; 5050 5051 /* Skip this, if this is not supported or linear frame buffer 5052 mode is not support. */ 5053 if ((mode.mode_attributes & 0x0081) != 0x0081) 5054 continue; 5055 5056 if (mode_number == -1 || mode_number == *mode_list) 5057 { 5058 char *model; 5059 switch (mode.memory_model) 5060 { 5061 case 0x00: model = "Text"; break; 5062 case 0x01: model = "CGA graphics"; break; 5063 case 0x02: model = "Hercules graphics"; break; 5064 case 0x03: model = "Planar"; break; 5065 case 0x04: model = "Packed pixel"; break; 5066 case 0x05: model = "Non-chain 4, 256 color"; break; 5067 case 0x06: model = "Direct Color"; break; 5068 case 0x07: model = "YUV"; break; 5069 default: model = "Unknown"; break; 5070 } 5071 5072 grub_printf (" 0x%x: %s, %ux%ux%u\n", 5073 (unsigned) *mode_list, 5074 model, 5075 (unsigned) mode.x_resolution, 5076 (unsigned) mode.y_resolution, 5077 (unsigned) mode.bits_per_pixel); 5078 5079 if (mode_number != -1) 5080 break; 5081 } 5082 } 5083 5084 if (mode_number != -1 && mode_number != *mode_list) 5085 grub_printf (" Mode 0x%x is not found or supported.\n", mode_number); 5086 5087 return 0; 5088 } 5089 5090 static struct builtin builtin_vbeprobe = 5091 { 5092 "vbeprobe", 5093 vbeprobe_func, 5094 BUILTIN_CMDLINE | BUILTIN_HELP_LIST, 5095 "vbeprobe [MODE]", 5096 "Probe VBE information. If the mode number MODE is specified, show only" 5097 " the information about only the mode." 5098 }; 5099 5100 5101 /* The table of builtin commands. Sorted in dictionary order. */ 5102 struct builtin *builtin_table[] = 5103 { 5104 #ifdef SUPPORT_GRAPHICS 5105 &builtin_background, 5106 #endif 5107 &builtin_blocklist, 5108 &builtin_boot, 5109 #ifdef SUPPORT_NETBOOT 5110 &builtin_bootp, 5111 #endif /* SUPPORT_NETBOOT */ 5112 &builtin_cat, 5113 &builtin_chainloader, 5114 &builtin_clear, 5115 &builtin_cmp, 5116 &builtin_color, 5117 &builtin_configfile, 5118 &builtin_debug, 5119 &builtin_default, 5120 #ifdef GRUB_UTIL 5121 &builtin_device, 5122 #endif /* GRUB_UTIL */ 5123 #ifdef SUPPORT_NETBOOT 5124 &builtin_dhcp, 5125 #endif /* SUPPORT_NETBOOT */ 5126 &builtin_displayapm, 5127 &builtin_displaymem, 5128 #ifdef GRUB_UTIL 5129 &builtin_dump, 5130 #endif /* GRUB_UTIL */ 5131 &builtin_embed, 5132 &builtin_fallback, 5133 &builtin_find, 5134 #ifdef SUPPORT_GRAPHICS 5135 &builtin_foreground, 5136 #endif 5137 &builtin_fstest, 5138 &builtin_geometry, 5139 &builtin_halt, 5140 &builtin_help, 5141 &builtin_hiddenmenu, 5142 &builtin_hide, 5143 #ifdef SUPPORT_NETBOOT 5144 &builtin_ifconfig, 5145 #endif /* SUPPORT_NETBOOT */ 5146 &builtin_impsprobe, 5147 &builtin_initrd, 5148 &builtin_install, 5149 &builtin_ioprobe, 5150 &builtin_kernel, 5151 &builtin_lock, 5152 &builtin_makeactive, 5153 &builtin_map, 5154 #ifdef USE_MD5_PASSWORDS 5155 &builtin_md5crypt, 5156 #endif /* USE_MD5_PASSWORDS */ 5157 &builtin_module, 5158 &builtin_modulenounzip, 5159 &builtin_pager, 5160 &builtin_partnew, 5161 &builtin_parttype, 5162 &builtin_password, 5163 &builtin_pause, 5164 #if defined(RPC_DEBUG) && defined(SUPPORT_NETBOOT) 5165 &builtin_portmap, 5166 #endif /* RPC_DEBUG && SUPPORT_NETBOOT */ 5167 #ifdef GRUB_UTIL 5168 &builtin_quit, 5169 #endif /* GRUB_UTIL */ 5170 #ifdef SUPPORT_NETBOOT 5171 &builtin_rarp, 5172 #endif /* SUPPORT_NETBOOT */ 5173 &builtin_read, 5174 &builtin_reboot, 5175 &builtin_root, 5176 &builtin_rootnoverify, 5177 &builtin_savedefault, 5178 #ifdef SUPPORT_SERIAL 5179 &builtin_serial, 5180 #endif /* SUPPORT_SERIAL */ 5181 &builtin_setkey, 5182 &builtin_setup, 5183 #ifdef SUPPORT_GRAPHICS 5184 &builtin_splashimage, 5185 #endif /* SUPPORT_GRAPHICS */ 5186 #if defined(SUPPORT_SERIAL) || defined(SUPPORT_HERCULES) || defined(SUPPORT_GRAPHICS) 5187 &builtin_terminal, 5188 #endif /* SUPPORT_SERIAL || SUPPORT_HERCULES || SUPPORT_GRAPHICS */ 5189 #ifdef SUPPORT_SERIAL 5190 &builtin_terminfo, 5191 #endif /* SUPPORT_SERIAL */ 5192 &builtin_testload, 5193 &builtin_testvbe, 5194 #ifdef SUPPORT_NETBOOT 5195 &builtin_tftpserver, 5196 #endif /* SUPPORT_NETBOOT */ 5197 &builtin_timeout, 5198 &builtin_title, 5199 &builtin_unhide, 5200 &builtin_uppermem, 5201 &builtin_vbeprobe, 5202 &builtin_verbose, 5203 0 5204 }; 5205