📄 builtins.c
字号:
/* builtins.c - the GRUB builtin commands *//* * GRUB -- GRand Unified Bootloader * Copyright (C) 1999,2000,2001,2002,2003,2004 Free Software Foundation, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *//* Include stdio.h before shared.h, because we can't define WITHOUT_LIBC_STUBS here. */#ifdef GRUB_UTIL# include <stdio.h>#endif#include <shared.h>#include <filesys.h>#include <term.h>#ifdef SUPPORT_NETBOOT# define GRUB 1# include <etherboot.h>#endif#ifdef SUPPORT_SERIAL# include <serial.h># include <terminfo.h>#endif#ifdef GRUB_UTIL# include <device.h>#else /* ! GRUB_UTIL */# include <apic.h># include <smp-imps.h>#endif /* ! GRUB_UTIL */#ifdef USE_MD5_PASSWORDS# include <md5.h>#endif/* The type of kernel loaded. */kernel_t kernel_type;/* The boot device. */static int bootdev;/* True when the debug mode is turned on, and false when it is turned off. */int debug = 0;/* The default entry. */int default_entry = 0;/* The fallback entry. */int fallback_entry = -1;/* The number of current entry. */int current_entryno;/* The address for Multiboot command-line buffer. */static char *mb_cmdline;/* The password. */char *password;/* The password type. */password_t password_type;/* The flag for indicating that the user is authoritative. */int auth = 0;/* The timeout. */int grub_timeout = -1;/* Whether to show the menu or not. */int show_menu = 1;/* The BIOS drive map. */static unsigned short bios_drive_map[DRIVE_MAP_SIZE + 1];/* Prototypes for allowing straightfoward calling of builtins functions inside other functions. */static int configfile_func (char *arg, int flags);/* Initialize the data for builtins. */voidinit_builtins (void){ kernel_type = KERNEL_TYPE_NONE; /* BSD and chainloading evil hacks! */ bootdev = set_bootdev (0); mb_cmdline = (char *) MB_CMDLINE_BUF;}/* Initialize the data for the configuration file. */voidinit_config (void){ default_entry = 0; password = 0; fallback_entry = -1; grub_timeout = -1;}/* Check a password for correctness. Returns 0 if password was correct, and a value != 0 for error, similarly to strcmp. */intcheck_password (char *entered, char* expected, password_t type){ switch (type) { case PASSWORD_PLAIN: return strcmp (entered, expected);#ifdef USE_MD5_PASSWORDS case PASSWORD_MD5: return check_md5_password (entered, expected);#endif default: /* unsupported password type: be secure */ return 1; }}/* Print which sector is read when loading a file. */static voiddisk_read_print_func (int sector, int offset, int length){ grub_printf ("[%d,%d,%d]", sector, offset, length);}/* blocklist */static intblocklist_func (char *arg, int flags){ char *dummy = (char *) RAW_ADDR (0x100000); int start_sector; int num_sectors = 0; int num_entries = 0; int last_length = 0; /* Collect contiguous blocks into one entry as many as possible, and print the blocklist notation on the screen. */ static void disk_read_blocklist_func (int sector, int offset, int length) { if (num_sectors > 0) { if (start_sector + num_sectors == sector && offset == 0 && last_length == SECTOR_SIZE) { num_sectors++; last_length = length; return; } else { if (last_length == SECTOR_SIZE) grub_printf ("%s%d+%d", num_entries ? "," : "", start_sector - part_start, num_sectors); else if (num_sectors > 1) grub_printf ("%s%d+%d,%d[0-%d]", num_entries ? "," : "", start_sector - part_start, num_sectors-1, start_sector + num_sectors-1 - part_start, last_length); else grub_printf ("%s%d[0-%d]", num_entries ? "," : "", start_sector - part_start, last_length); num_entries++; num_sectors = 0; } } if (offset > 0) { grub_printf("%s%d[%d-%d]", num_entries ? "," : "", sector-part_start, offset, offset+length); num_entries++; } else { start_sector = sector; num_sectors = 1; last_length = length; } } /* Open the file. */ if (! grub_open (arg)) return 1; /* Print the device name. */ grub_printf ("(%cd%d", (current_drive & 0x80) ? 'h' : 'f', current_drive & ~0x80); if ((current_partition & 0xFF0000) != 0xFF0000) grub_printf (",%d", (current_partition >> 16) & 0xFF); if ((current_partition & 0x00FF00) != 0x00FF00) grub_printf (",%c", 'a' + ((current_partition >> 8) & 0xFF)); grub_printf (")"); /* Read in the whole file to DUMMY. */ disk_read_hook = disk_read_blocklist_func; if (! grub_read (dummy, -1)) goto fail; /* The last entry may not be printed yet. Don't check if it is a * full sector, since it doesn't matter if we read too much. */ if (num_sectors > 0) grub_printf ("%s%d+%d", num_entries ? "," : "", start_sector - part_start, num_sectors); grub_printf ("\n"); fail: disk_read_hook = 0; grub_close (); return errnum;}static struct builtin builtin_blocklist ={ "blocklist", blocklist_func, BUILTIN_CMDLINE | BUILTIN_HELP_LIST, "blocklist FILE", "Print the blocklist notation of the file FILE."};/* boot */static intboot_func (char *arg, int flags){ /* Clear the int15 handler if we can boot the kernel successfully. This assumes that the boot code never fails only if KERNEL_TYPE is not KERNEL_TYPE_NONE. Is this assumption is bad? */ if (kernel_type != KERNEL_TYPE_NONE) unset_int15_handler ();#ifdef SUPPORT_NETBOOT /* Shut down the networking. */ cleanup_net ();#endif switch (kernel_type) { case KERNEL_TYPE_FREEBSD: case KERNEL_TYPE_NETBSD: /* *BSD */ bsd_boot (kernel_type, bootdev, (char *) mbi.cmdline); break; case KERNEL_TYPE_LINUX: /* Linux */ linux_boot (); break; case KERNEL_TYPE_BIG_LINUX: /* Big Linux */ big_linux_boot (); break; case KERNEL_TYPE_CHAINLOADER: /* Chainloader */ /* Check if we should set the int13 handler. */ if (bios_drive_map[0] != 0) { int i; /* Search for SAVED_DRIVE. */ for (i = 0; i < DRIVE_MAP_SIZE; i++) { if (! bios_drive_map[i]) break; else if ((bios_drive_map[i] & 0xFF) == saved_drive) { /* Exchage SAVED_DRIVE with the mapped drive. */ saved_drive = (bios_drive_map[i] >> 8) & 0xFF; break; } } /* Set the handler. This is somewhat dangerous. */ set_int13_handler (bios_drive_map); } gateA20 (0); boot_drive = saved_drive; chain_stage1 (0, BOOTSEC_LOCATION, boot_part_addr); break; case KERNEL_TYPE_MULTIBOOT: /* Multiboot */ multi_boot ((int) entry_addr, (int) &mbi); break; default: errnum = ERR_BOOT_COMMAND; return 1; } return 0;}static struct builtin builtin_boot ={ "boot", boot_func, BUILTIN_CMDLINE | BUILTIN_HELP_LIST, "boot", "Boot the OS/chain-loader which has been loaded."};#ifdef SUPPORT_NETBOOT/* bootp */static intbootp_func (char *arg, int flags){ int with_configfile = 0; if (grub_memcmp (arg, "--with-configfile", sizeof ("--with-configfile") - 1) == 0) { with_configfile = 1; arg = skip_to (0, arg); } if (! bootp ()) { if (errnum == ERR_NONE) errnum = ERR_DEV_VALUES; return 1; } /* Notify the configuration. */ print_network_configuration (); /* XXX: this can cause an endless loop, but there is no easy way to detect such a loop unfortunately. */ if (with_configfile) configfile_func (config_file, flags); return 0;}static struct builtin builtin_bootp ={ "bootp", bootp_func, BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST, "bootp [--with-configfile]", "Initialize a network device via BOOTP. If the option `--with-configfile'" " is given, try to load a configuration file specified by the 150 vendor" " tag."};#endif /* SUPPORT_NETBOOT *//* cat */static intcat_func (char *arg, int flags){ char c; if (! grub_open (arg)) return 1; while (grub_read (&c, 1)) { /* Because running "cat" with a binary file can confuse the terminal, print only some characters as they are. */ if (grub_isspace (c) || (c >= ' ' && c <= '~')) grub_putchar (c); else grub_putchar ('?'); } grub_close (); return 0;}static struct builtin builtin_cat ={ "cat", cat_func, BUILTIN_CMDLINE | BUILTIN_HELP_LIST, "cat FILE", "Print the contents of the file FILE."};/* chainloader */static intchainloader_func (char *arg, int flags){ int force = 0; char *file = arg; /* If the option `--force' is specified? */ if (substring ("--force", arg) <= 0) { force = 1; file = skip_to (0, arg); } /* Open the file. */ if (! grub_open (file)) { kernel_type = KERNEL_TYPE_NONE; return 1; } /* Read the first block. */ if (grub_read ((char *) BOOTSEC_LOCATION, SECTOR_SIZE) != SECTOR_SIZE) { grub_close (); kernel_type = KERNEL_TYPE_NONE; /* This below happens, if a file whose size is less than 512 bytes is loaded. */ if (errnum == ERR_NONE) errnum = ERR_EXEC_FORMAT; return 1; } /* If not loading it forcibly, check for the signature. */ if (! force && (*((unsigned short *) (BOOTSEC_LOCATION + BOOTSEC_SIG_OFFSET)) != BOOTSEC_SIGNATURE)) { grub_close (); errnum = ERR_EXEC_FORMAT; kernel_type = KERNEL_TYPE_NONE; return 1; } grub_close (); kernel_type = KERNEL_TYPE_CHAINLOADER; /* XXX: Windows evil hack. For now, only the first five letters are checked. */ if (IS_PC_SLICE_TYPE_FAT (current_slice) && ! grub_memcmp ((char *) BOOTSEC_LOCATION + BOOTSEC_BPB_SYSTEM_ID, "MSWIN", 5)) *((unsigned long *) (BOOTSEC_LOCATION + BOOTSEC_BPB_HIDDEN_SECTORS)) = part_start; errnum = ERR_NONE; return 0;}static struct builtin builtin_chainloader ={ "chainloader", chainloader_func, BUILTIN_CMDLINE | BUILTIN_HELP_LIST, "chainloader [--force] FILE", "Load the chain-loader FILE. If --force is specified, then load it" " forcibly, whether the boot loader signature is present or not."};/* This function could be used to debug new filesystem code. Put a file in the new filesystem and the same file in a well-tested filesystem. Then, run "cmp" with the files. If no output is obtained, probably the code is good, otherwise investigate what's wrong... *//* cmp FILE1 FILE2 */static intcmp_func (char *arg, int flags){ /* The filenames. */ char *file1, *file2; /* The addresses. */ char *addr1, *addr2; int i; /* The size of the file. */ int size; /* Get the filenames from ARG. */ file1 = arg; file2 = skip_to (0, arg); if (! *file1 || ! *file2) { errnum = ERR_BAD_ARGUMENT; return 1; } /* Terminate the filenames for convenience. */ nul_terminate (file1); nul_terminate (file2); /* Read the whole data from FILE1. */ addr1 = (char *) RAW_ADDR (0x100000); if (! grub_open (file1)) return 1; /* Get the size. */ size = filemax; if (grub_read (addr1, -1) != size) { grub_close (); return 1; } grub_close (); /* Read the whole data from FILE2. */ addr2 = addr1 + size; if (! grub_open (file2)) return 1; /* Check if the size of FILE2 is equal to the one of FILE2. */ if (size != filemax) { grub_printf ("Differ in size: 0x%x [%s], 0x%x [%s]\n", size, file1, filemax, file2); grub_close (); return 0; } if (! grub_read (addr2, -1)) { grub_close (); return 1; } grub_close (); /* Now compare ADDR1 with ADDR2. */ for (i = 0; i < size; i++) { if (addr1[i] != addr2[i]) grub_printf ("Differ at the offset %d: 0x%x [%s], 0x%x [%s]\n", i, (unsigned) addr1[i], file1, (unsigned) addr2[i], file2); } return 0;}static struct builtin builtin_cmp ={ "cmp", cmp_func, BUILTIN_CMDLINE, "cmp FILE1 FILE2", "Compare the file FILE1 with the FILE2 and inform the different values" " if any."};/* color *//* Set new colors used for the menu interface. Support two methods to specify a color name: a direct integer representation and a symbolic color name. An example of the latter is "blink-light-gray/blue". */static int
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -