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