Make grub-setup backup the old boot sectors into a file (bootsectors.bak) before overwriting it. The backup image starts from the MBR to the end of core.img position (including embed regions). This makes it possible for a user to later restore it.
A new option -o|--restore (with optional argument) is added for grub-setup to restore the backup image into the install device. A simple `dd` won't work when partitioning has been changed after the backup. The --restore option only restores the MBR and the boot sectors overwritten by core.img (embed region is excluded). Signed-off-by: Zhu Yi <yi....@intel.com> diff --git a/util/i386/pc/grub-setup.c b/util/i386/pc/grub-setup.c index c536be0..e8dc2b7 100644 --- a/util/i386/pc/grub-setup.c +++ b/util/i386/pc/grub-setup.c @@ -53,6 +53,7 @@ static const grub_gpt_part_type_t grub_gpt_partition_type_bios_boot = GRUB_GPT_P #define DEFAULT_BOOT_FILE "boot.img" #define DEFAULT_CORE_FILE "core.img" +#define DEFAULT_BACKUP_FILE "bootsectors.bak" /* This is the blocklist used in the diskboot image. */ struct boot_blocklist @@ -85,7 +86,7 @@ grub_refresh (void) static void setup (const char *dir, - const char *boot_file, const char *core_file, + const char *boot_file, const char *core_file, const char *restore_file, const char *root, const char *dest, int must_embed, int force, int fs_probe) { char *boot_path, *core_path, *core_path_dev; @@ -396,6 +397,59 @@ setup (const char *dir, block->len = 0; block->segment = 0; + int grub_disk_backup(grub_disk_t disk, const char *file) + { + char *path = grub_util_get_path (dir, file); + char *buf; + grub_size_t size; + + grub_util_info ("opening backup file `%s'", path); + fp = fopen (path, "wb"); + if (! fp) { + free (path); + return -1; + } + + size = GRUB_DISK_SECTOR_SIZE * embed_region.start + core_size; + buf = xmalloc (size); + if (grub_disk_read (disk, 0, 0, size, buf) != GRUB_ERR_NONE) { + free (path); + fclose (fp); + return -1; + } + + grub_util_write_image (buf, size, fp); + + free (buf); + free (path); + fclose (fp); + return 0; + } + + void grub_disk_restore(grub_disk_t disk, const char *path) + { + size_t size = grub_util_get_image_size (path); + char *img; + + if (size != GRUB_DISK_SECTOR_SIZE * embed_region.start + core_size) + grub_util_error ("Invalid backup image `%s'", path); + + img = grub_util_read_image (path); + grub_disk_write (disk, 0, 0, GRUB_DISK_SECTOR_SIZE, img); + grub_disk_write (disk, embed_region.start, 0, core_size, + img + GRUB_DISK_SECTOR_SIZE * embed_region.start); + free (img); + } + + if (restore_file) { + grub_disk_restore (dest_dev->disk, restore_file); + goto finish; + } + + /* Backup old boot sectors */ + if (grub_disk_backup (dest_dev->disk, DEFAULT_BACKUP_FILE)) + grub_util_error ("failed to backup previous boot sectors"); + /* Write the core image onto the disk. */ if (grub_disk_write (dest_dev->disk, embed_region.start, 0, core_size, core_img)) grub_util_error ("%s", grub_errmsg); @@ -571,6 +625,7 @@ static struct option options[] = {"directory", required_argument, 0, 'd'}, {"device-map", required_argument, 0, 'm'}, {"root-device", required_argument, 0, 'r'}, + {"restore", optional_argument, 0, 'o'}, {"force", no_argument, 0, 'f'}, {"skip-fs-probe", no_argument, 0, 's'}, {"help", no_argument, 0, 'h'}, @@ -596,6 +651,7 @@ DEVICE must be a GRUB device (e.g. ``(hd0,1)'').\n\ -d, --directory=DIR use GRUB files in the directory DIR [default=%s]\n\ -m, --device-map=FILE use FILE as the device map [default=%s]\n\ -r, --root-device=DEV use DEV as the root device [default=guessed]\n\ + -o, --restore[=FILE] restore boot sectors from backup image [default=%s]\n\ -f, --force install even if problems are detected\n\ -s, --skip-fs-probe do not probe for filesystems in DEVICE\n\ -h, --help display this message and exit\n\ @@ -605,7 +661,8 @@ DEVICE must be a GRUB device (e.g. ``(hd0,1)'').\n\ Report bugs to <%s>.\n\ ", DEFAULT_BOOT_FILE, DEFAULT_CORE_FILE, DEFAULT_DIRECTORY, - DEFAULT_DEVICE_MAP, PACKAGE_BUGREPORT); + DEFAULT_DEVICE_MAP, DEFAULT_DIRECTORY "/" DEFAULT_BACKUP_FILE, + PACKAGE_BUGREPORT); exit (status); } @@ -627,6 +684,7 @@ main (int argc, char *argv[]) { char *boot_file = 0; char *core_file = 0; + char *restore_file = 0; char *dir = 0; char *dev_map = 0; char *root_dev = 0; @@ -638,7 +696,7 @@ main (int argc, char *argv[]) /* Check for options. */ while (1) { - int c = getopt_long (argc, argv, "b:c:d:m:r:hVvf", options, 0); + int c = getopt_long (argc, argv, "b:c:d:m:r:o::hVvfs", options, 0); if (c == -1) break; @@ -680,6 +738,17 @@ main (int argc, char *argv[]) root_dev = xstrdup (optarg); break; + case 'o': + if (restore_file) + free (restore_file); + + if (optarg) + restore_file = xstrdup (optarg); + else + restore_file = grub_util_get_path (dir ? dir : DEFAULT_DIRECTORY, + DEFAULT_BACKUP_FILE); + break; + case 'f': force = 1; break; @@ -788,7 +857,7 @@ main (int argc, char *argv[]) { setup (dir ? : DEFAULT_DIRECTORY, boot_file ? : DEFAULT_BOOT_FILE, - core_file ? : DEFAULT_CORE_FILE, + core_file ? : DEFAULT_CORE_FILE, restore_file, root_dev, grub_util_get_grub_dev (devicelist[i]), 1, force, fs_probe); } } @@ -797,7 +866,7 @@ main (int argc, char *argv[]) /* Do the real work. */ setup (dir ? : DEFAULT_DIRECTORY, boot_file ? : DEFAULT_BOOT_FILE, - core_file ? : DEFAULT_CORE_FILE, + core_file ? : DEFAULT_CORE_FILE, restore_file, root_dev, dest_dev, must_embed, force, fs_probe); /* Free resources. */ @@ -806,6 +875,7 @@ main (int argc, char *argv[]) free (boot_file); free (core_file); + free (restore_file); free (dir); free (dev_map); free (root_dev); _______________________________________________ Grub-devel mailing list Grub-devel@gnu.org http://lists.gnu.org/mailman/listinfo/grub-devel