📄 builtins.c
字号:
default: errnum = ERR_NEED_LX_KERNEL; return 1; } return 0;}static struct builtin builtin_initrd ={ "initrd", initrd_func, BUILTIN_CMDLINE | BUILTIN_HELP_LIST, "initrd FILE [ARG ...]", "Load an initial ramdisk FILE for a Linux format boot image and set the" " appropriate parameters in the Linux setup area in memory."};/* install */static intinstall_func (char *arg, int flags){ char *stage1_file, *dest_dev, *file, *addr; char *stage1_buffer = (char *) RAW_ADDR (0x100000); char *stage2_buffer = stage1_buffer + SECTOR_SIZE; char *old_sect = stage2_buffer + SECTOR_SIZE; char *stage2_first_buffer = old_sect + SECTOR_SIZE; char *stage2_second_buffer = stage2_first_buffer + SECTOR_SIZE; /* XXX: Probably SECTOR_SIZE is reasonable. */ char *config_filename = stage2_second_buffer + SECTOR_SIZE; char *dummy = config_filename + SECTOR_SIZE; int new_drive = GRUB_INVALID_DRIVE; int dest_drive, dest_partition, dest_sector; int src_drive, src_partition, src_part_start; int i; struct geometry dest_geom, src_geom; int saved_sector; int stage2_first_sector, stage2_second_sector; char *ptr; int installaddr, installlist; /* Point to the location of the name of a configuration file in Stage 2. */ char *config_file_location; /* If FILE is a Stage 1.5? */ int is_stage1_5 = 0; /* Must call grub_close? */ int is_open = 0; /* If LBA is forced? */ int is_force_lba = 0; /* Was the last sector full? */ int last_length = SECTOR_SIZE; #ifdef GRUB_UTIL /* If the Stage 2 is in a partition mounted by an OS, this will store the filename under the OS. */ char *stage2_os_file = 0;#endif /* GRUB_UTIL */ /* Save the first sector of Stage2 in STAGE2_SECT. */ static void disk_read_savesect_func (int sector, int offset, int length) { if (debug) printf ("[%d]", sector); /* ReiserFS has files which sometimes contain data not aligned on sector boundaries. Returning an error is better than silently failing. */ if (offset != 0 || length != SECTOR_SIZE) errnum = ERR_UNALIGNED; saved_sector = sector; } /* Write SECTOR to INSTALLLIST, and update INSTALLADDR and INSTALLSECT. */ static void disk_read_blocklist_func (int sector, int offset, int length) { if (debug) printf("[%d]", sector); if (offset != 0 || last_length != SECTOR_SIZE) { /* We found a non-sector-aligned data block. */ errnum = ERR_UNALIGNED; return; } last_length = length; if (*((unsigned long *) (installlist - 4)) + *((unsigned short *) installlist) != sector || installlist == (int) stage2_first_buffer + SECTOR_SIZE + 4) { installlist -= 8; if (*((unsigned long *) (installlist - 8))) errnum = ERR_WONT_FIT; else { *((unsigned short *) (installlist + 2)) = (installaddr >> 4); *((unsigned long *) (installlist - 4)) = sector; } } *((unsigned short *) installlist) += 1; installaddr += 512; } /* First, check the GNU-style long option. */ while (1) { if (grub_memcmp ("--force-lba", arg, sizeof ("--force-lba") - 1) == 0) { is_force_lba = 1; arg = skip_to (0, arg); }#ifdef GRUB_UTIL else if (grub_memcmp ("--stage2=", arg, sizeof ("--stage2=") - 1) == 0) { stage2_os_file = arg + sizeof ("--stage2=") - 1; arg = skip_to (0, arg); nul_terminate (stage2_os_file); }#endif /* GRUB_UTIL */ else break; } stage1_file = arg; dest_dev = skip_to (0, stage1_file); if (*dest_dev == 'd') { new_drive = 0; dest_dev = skip_to (0, dest_dev); } file = skip_to (0, dest_dev); addr = skip_to (0, file); /* Get the installation address. */ if (! safe_parse_maxint (&addr, &installaddr)) { /* ADDR is not specified. */ installaddr = 0; ptr = addr; errnum = 0; } else ptr = skip_to (0, addr);#ifndef NO_DECOMPRESSION /* Do not decompress Stage 1 or Stage 2. */ no_decompression = 1;#endif /* Read Stage 1. */ is_open = grub_open (stage1_file); if (! is_open || ! grub_read (stage1_buffer, SECTOR_SIZE) == SECTOR_SIZE) goto fail; /* Read the old sector from DEST_DEV. */ if (! set_device (dest_dev) || ! open_partition () || ! devread (0, 0, SECTOR_SIZE, old_sect)) goto fail; /* Store the information for the destination device. */ dest_drive = current_drive; dest_partition = current_partition; dest_geom = buf_geom; dest_sector = part_start; /* Copy the possible DOS BPB, 59 bytes at byte offset 3. */ grub_memmove (stage1_buffer + BOOTSEC_BPB_OFFSET, old_sect + BOOTSEC_BPB_OFFSET, BOOTSEC_BPB_LENGTH); /* If for a hard disk, copy the possible MBR/extended part table. */ if (dest_drive & 0x80) grub_memmove (stage1_buffer + STAGE1_WINDOWS_NT_MAGIC, old_sect + STAGE1_WINDOWS_NT_MAGIC, STAGE1_PARTEND - STAGE1_WINDOWS_NT_MAGIC); /* Check for the version and the signature of Stage 1. */ if (*((short *)(stage1_buffer + STAGE1_VER_MAJ_OFFS)) != COMPAT_VERSION || (*((unsigned short *) (stage1_buffer + BOOTSEC_SIG_OFFSET)) != BOOTSEC_SIGNATURE)) { errnum = ERR_BAD_VERSION; goto fail; } /* This below is not true any longer. But should we leave this alone? */ /* If DEST_DRIVE is a floppy, Stage 2 must have the iteration probe routine. */ if (! (dest_drive & 0x80) && (*((unsigned char *) (stage1_buffer + BOOTSEC_PART_OFFSET)) == 0x80 || stage1_buffer[BOOTSEC_PART_OFFSET] == 0)) { errnum = ERR_BAD_VERSION; goto fail; } grub_close (); /* Open Stage 2. */ is_open = grub_open (file); if (! is_open) goto fail; src_drive = current_drive; src_partition = current_partition; src_part_start = part_start; src_geom = buf_geom; if (! new_drive) new_drive = src_drive; else if (src_drive != dest_drive) grub_printf ("Warning: the option `d' was not used, but the Stage 1 will" " be installed on a\ndifferent drive than the drive where" " the Stage 2 resides.\n"); /* Set the boot drive. */ *((unsigned char *) (stage1_buffer + STAGE1_BOOT_DRIVE)) = new_drive; /* Set the "force LBA" flag. */ *((unsigned char *) (stage1_buffer + STAGE1_FORCE_LBA)) = is_force_lba; /* Set the boot drive mask. This is a workaround for buggy BIOSes which don't pass boot drive correctly. Instead, they pass 0x00 even when booted from 0x80. */ *((unsigned char *) (stage1_buffer + STAGE1_BOOT_DRIVE_MASK)) = (dest_drive & BIOS_FLAG_FIXED_DISK); /* Read the first sector of Stage 2. */ disk_read_hook = disk_read_savesect_func; if (grub_read (stage2_first_buffer, SECTOR_SIZE) != SECTOR_SIZE) goto fail; stage2_first_sector = saved_sector; /* Read the second sector of Stage 2. */ if (grub_read (stage2_second_buffer, SECTOR_SIZE) != SECTOR_SIZE) goto fail; stage2_second_sector = saved_sector; /* Check for the version of Stage 2. */ if (*((short *) (stage2_second_buffer + STAGE2_VER_MAJ_OFFS)) != COMPAT_VERSION) { errnum = ERR_BAD_VERSION; goto fail; } /* Check for the Stage 2 id. */ if (stage2_second_buffer[STAGE2_STAGE2_ID] != STAGE2_ID_STAGE2) is_stage1_5 = 1; /* If INSTALLADDR is not specified explicitly in the command-line, determine it by the Stage 2 id. */ if (! installaddr) { if (! is_stage1_5) /* Stage 2. */ installaddr = 0x8000; else /* Stage 1.5. */ installaddr = 0x2000; } *((unsigned long *) (stage1_buffer + STAGE1_STAGE2_SECTOR)) = stage2_first_sector; *((unsigned short *) (stage1_buffer + STAGE1_STAGE2_ADDRESS)) = installaddr; *((unsigned short *) (stage1_buffer + STAGE1_STAGE2_SEGMENT)) = installaddr >> 4; i = (int) stage2_first_buffer + SECTOR_SIZE - 4; while (*((unsigned long *) i)) { if (i < (int) stage2_first_buffer || (*((int *) (i - 4)) & 0x80000000) || *((unsigned short *) i) >= 0xA00 || *((short *) (i + 2)) == 0) { errnum = ERR_BAD_VERSION; goto fail; } *((int *) i) = 0; *((int *) (i - 4)) = 0; i -= 8; } installlist = (int) stage2_first_buffer + SECTOR_SIZE + 4; installaddr += SECTOR_SIZE; /* Read the whole of Stage2 except for the first sector. */ grub_seek (SECTOR_SIZE); disk_read_hook = disk_read_blocklist_func; if (! grub_read (dummy, -1)) goto fail; disk_read_hook = 0; /* Find a string for the configuration filename. */ config_file_location = stage2_second_buffer + STAGE2_VER_STR_OFFS; while (*(config_file_location++)) ; /* Set the "force LBA" flag for Stage2. */ *((unsigned char *) (stage2_second_buffer + STAGE2_FORCE_LBA)) = is_force_lba; if (*ptr == 'p') { *((long *) (stage2_second_buffer + STAGE2_INSTALLPART)) = src_partition; if (is_stage1_5) { /* Reset the device information in FILE if it is a Stage 1.5. */ unsigned long device = 0xFFFFFFFF; grub_memmove (config_file_location, (char *) &device, sizeof (device)); } ptr = skip_to (0, ptr); } if (*ptr) { grub_strcpy (config_filename, ptr); nul_terminate (config_filename); if (! is_stage1_5) /* If it is a Stage 2, just copy PTR to CONFIG_FILE_LOCATION. */ grub_strcpy (config_file_location, ptr); else { char *real_config; unsigned long device; /* Translate the external device syntax to the internal device syntax. */ if (! (real_config = set_device (ptr))) { /* The Stage 2 PTR does not contain the device name, so use the root device instead. */ errnum = ERR_NONE; current_drive = saved_drive; current_partition = saved_partition; real_config = ptr; } if (current_drive == src_drive) { /* If the drive where the Stage 2 resides is the same as the one where the Stage 1.5 resides, do not embed the drive number. */ current_drive = GRUB_INVALID_DRIVE; } device = (current_drive << 24) | current_partition; grub_memmove (config_file_location, (char *) &device, sizeof (device)); grub_strcpy (config_file_location + sizeof (device), real_config); } /* If a Stage 1.5 is used, then we need to modify the Stage2. */ if (is_stage1_5) { char *real_config_filename = skip_to (0, ptr); is_open = grub_open (config_filename); if (! is_open) goto fail; /* Skip the first sector. */ grub_seek (SECTOR_SIZE); disk_read_hook = disk_read_savesect_func; if (grub_read (stage2_buffer, SECTOR_SIZE) != SECTOR_SIZE) goto fail; disk_read_hook = 0; grub_close (); is_open = 0; /* Sanity check. */ if (*(stage2_buffer + STAGE2_STAGE2_ID) != STAGE2_ID_STAGE2) { errnum = ERR_BAD_VERSION; goto fail; } /* Set the "force LBA" flag for Stage2. */ *(stage2_buffer + STAGE2_FORCE_LBA) = is_force_lba; /* If REAL_CONFIG_FILENAME is specified, copy it to the Stage2. */ if (*real_config_filename) { /* Specified */ char *location; /* Find a string for the configuration filename. */ location = stage2_buffer + STAGE2_VER_STR_OFFS; while (*(location++)) ; /* Copy the name. */ grub_strcpy (location, real_config_filename); } /* Write it to the disk. */ buf_track = -1;#ifdef GRUB_UTIL /* In the grub shell, access the Stage 2 via the OS filesystem service, if possible. */ if (stage2_os_file) { FILE *fp; fp = fopen (stage2_os_file, "r+"); if (! fp) { errnum = ERR_FILE_NOT_FOUND; goto fail; } if (fseek (fp, SECTOR_SIZE, SEEK_SET) != 0) { fclose (fp); errnum = ERR_BAD_VERSION; goto fail; } if (fwrite (stage2_buffer, 1, SECTOR_SIZE, fp) != SECTOR_SIZE) { fclose (fp); errnum = ERR_WRITE; goto fail; } fclose (fp); } else#endif /* GRUB_UTIL */ { if (! devwrite (saved_sector - part_start, 1, stage2_buffer)) goto fail; } } } /* Clear the cache. */ buf_track = -1; /* Write the modified sectors of Stage2 to the disk. */#ifdef GRUB_UTIL if (! is_stage1_5 && stage2_os_file) { FILE *fp; fp = fopen (stage2_os_file, "r+"); if (! fp) { errnum = ERR_FILE_NOT_FOUND; goto fail; } if (fwrite (stage2_first_buffer, 1, SECTOR_SIZE, fp) != SECTOR_SIZE) { fclose (fp); errnum = ERR_WRITE; goto fail; } if (fwrite (stage2_second_buffer, 1, SECTOR_SIZE, fp) != SECTOR_SIZE) { fclose (fp); errnum = ERR_WRITE; goto fail; } fclose (fp); } else#endif /* GRUB_UTIL */ { /* The first. */ current_drive = src_drive; current_partition = src_partition; if (! open_partition ()) goto fail; if (! devwrite (stage2_first_sector - src_part_start, 1, stage2_first_buffer)) goto fail; if (! devwrite (stage2_second_sector - src_part_start, 1, stage2_second_buffer)) goto fail; } /* Write the modified sector of Stage 1 to the disk. */ current_drive = dest_drive; current_partition = dest_partition; if (! open_partition ()) goto fail; devwrite (0, 1, stage1_buffer); fail: if (is_open) grub_close (); disk_read_hook = 0; #ifndef NO_DECOMPRESSION no_decompression = 0;#endif return errnum;}static struct builtin builtin_install ={ "install", install_func, BUILTIN_CMDLINE, "install [--stage2=STAGE2_FILE] [--force-lba] STAGE1 [d] DEVICE STAGE2 [ADDR] [p] [CONFIG_FILE] [REAL_CONFIG_FILE]", "Install STAGE1 on DEVICE, and install a blocklist for loading STAGE2" " as a Stage 2. If the option `d' is present, the Stage 1 will always" " look for the disk where STAGE2 was installed, rather than using" " the booting drive. The Stage 2 will be loaded at address ADDR, which" " will be determined automatically if you don't specify it. If" " the option `p' or CONFIG_FILE is present, then the first block" " of Stage 2 is patched with new values of the partition and name" " of the configuration file used by the true Stage 2 (for a Stage 1.5," " this is the name of the true Stage 2) at boot time. If STAGE2 is a Stage" " 1.5 and REAL_CONFIG_FILE is present, then the Stage 2 CONFIG_FILE is" " patched with the configuration filename REAL_CONFIG_FILE." " If the option `--force-lba' is specified, disable some sanity checks" " for LBA mode. If the option `--stage2' is specified, rewrite the Stage" " 2 via your OS's filesystem instead of the raw device."};/* ioprobe */static intioprobe_func (char *arg, int flags){#ifdef GRUB_UTIL
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -