Index: util/i386/pc/grub-setup.c =================================================================== --- util/i386/pc/grub-setup.c (revision 2614) +++ util/i386/pc/grub-setup.c (working copy) @@ -53,6 +53,7 @@ #define DEFAULT_BOOT_FILE "boot.img" #define DEFAULT_CORE_FILE "core.img" +#define DEFAULT_BACKUP_FILE "bootsector.bak" /* This is the blocklist used in the diskboot image. */ struct boot_blocklist @@ -85,11 +86,11 @@ static void setup (const char *dir, - const char *boot_file, const char *core_file, - const char *root, const char *dest, int must_embed, int force) + const char *boot_file, const char *core_file, const char *backup_file, + const char *root, const char *dest, int must_embed, int force, int restore) { - char *boot_path, *core_path, *core_path_dev; - char *boot_img, *core_img; + char *boot_path, *core_path, *backup_path, *core_path_dev; + char *boot_img, *core_img, *backup_img; size_t boot_size, core_size; grub_uint16_t core_sectors; grub_device_t root_dev, dest_dev; @@ -107,7 +108,7 @@ = GRUB_BOOT_MACHINE_KERNEL_SEG + (GRUB_DISK_SECTOR_SIZE >> 4); grub_uint16_t last_length = GRUB_DISK_SECTOR_SIZE; grub_file_t file; - FILE *fp; + FILE *fp, *backup_fp; struct { grub_uint64_t start; grub_uint64_t end; } embed_region; embed_region.start = embed_region.end = ~0UL; @@ -196,6 +197,73 @@ current_segment += GRUB_DISK_SECTOR_SIZE >> 4; } + if(restore) + { + /* restore the boot sectors to the previous state */ + + /* open the backup file to restore the boot sectors */ + backup_path = grub_util_get_path (dir, backup_file); + backup_img = grub_util_read_image (backup_path); + + /* Open the destination device. */ + dest_dev = grub_device_open (dest); + if (! dest_dev) + grub_util_error ("%s", grub_errmsg); + + grub_util_info ("setting the root device to `%s'", root); + if (grub_env_set ("root", root) != GRUB_ERR_NONE) + grub_util_error ("%s", grub_errmsg); + + + /* read the image and get the variables */ + int offset = 0; + grub_uint64_t start = *((grub_uint64_t *) backup_img); + offset += 8; + + core_size = *((size_t *) (backup_img+offset)); + offset += 8; + + /* check the size of the backup image */ + size_t backup_img_size = core_size + GRUB_DISK_SECTOR_SIZE + sizeof(grub_uint64_t) + sizeof(size_t) + 1 /* seperation byte 0xff */ ; + if( grub_util_get_image_size (backup_path) != backup_img_size) + { + strcpy(grub_errmsg,"Invalid size of the image\n"); + goto unable_to_restore; + } + + if( (unsigned char)backup_img[offset + core_size] != 0xff) + { + strcpy(grub_errmsg,"The backup file is corrupted\n"); + goto unable_to_restore; + } + + /* Write the core image on the disk. */ + if (grub_disk_write (dest_dev->disk, start, 0, core_size, (char *)(backup_img+offset))) + grub_util_error ("%s", grub_errmsg); + + /* the byte after the core image has 0xff in the file */ + offset += core_size + 1; + + /* Write the mbr on the disk. */ + if (grub_disk_write (dest_dev->disk, 0, 0, GRUB_DISK_SECTOR_SIZE, (char *)(backup_img+offset))) + grub_util_error ("%s", grub_errmsg); + + /* free the used stuff */ + free(backup_img); + grub_device_close (dest_dev); + + return; + +unable_to_restore: + /* first free the used stuff */ + free(backup_img); + grub_device_close (dest_dev); + /* then report errors */ + grub_util_error("%s\nUnable to restore the boot sector",grub_errmsg); + return; + + } + /* Read the boot image by the OS service. */ boot_path = grub_util_get_path (dir, boot_file); boot_size = grub_util_get_image_size (boot_path); @@ -380,6 +448,63 @@ block->len = 0; block->segment = 0; + /* Save the boot sectors (including the embed region) before writing */ + backup_path = grub_util_get_path (dir, backup_file); + backup_fp = fopen (backup_path, "w"); + + if (!backup_fp) + { + grub_util_warn + ("Unable to save the boot sector. Reason: unable to open file\n"); + goto save_cleanup_backup_fp; + } + + /* 8 bytes for embed_region.start, another 8 for core_size, 1 byte for seperation */ + int backup_img_size = + core_size + GRUB_DISK_SECTOR_SIZE + 8 + 8 + 1 /* seperation byte 0xff */ ; + backup_img = (char *) xmalloc (backup_img_size); + + + int offset = 0; + + memcpy (backup_img, (char *) (&embed_region.start), sizeof (grub_uint64_t)); + offset += 8; + + memcpy (backup_img + offset, (char *) (&core_size), sizeof (size_t)); + offset += 8; + + if (grub_disk_read + (dest_dev->disk, embed_region.start, 0, core_size, backup_img + offset)) + { + grub_util_warn ("Unable to save the boot sector. Reason:%s\n", + grub_errmsg); + goto save_cleanup_backup_img; + } + offset += core_size; + + backup_img[offset++] = 0xff; /* seperation byte between core img and mbr */ + + if (grub_disk_read + (dest_dev->disk, 0, 0, GRUB_DISK_SECTOR_SIZE, backup_img + offset)) + { + grub_util_warn ("Unable to save the boot sector. Reason:%s\n", + grub_errmsg); + goto save_cleanup_backup_img; + } + offset += GRUB_DISK_SECTOR_SIZE; + + /* write image to file */ + fwrite (backup_img, 1, backup_img_size, backup_fp); + + goto save_cleanup_backup_img; + + +save_cleanup_backup_img: + free (backup_img); +save_cleanup_backup_fp: + fclose (backup_fp); + free (backup_path); + /* 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); @@ -555,9 +680,11 @@ {"directory", required_argument, 0, 'd'}, {"device-map", required_argument, 0, 'm'}, {"root-device", required_argument, 0, 'r'}, + {"backup-file", required_argument, 0, 'Z'}, {"force", no_argument, 0, 'f'}, {"help", no_argument, 0, 'h'}, {"version", no_argument, 0, 'V'}, + {"restore", no_argument, 0, 'z'}, {"verbose", no_argument, 0, 'v'}, {0, 0, 0, 0} }; @@ -576,17 +703,19 @@ \n\ -b, --boot-image=FILE use FILE as the boot image [default=%s]\n\ -c, --core-image=FILE use FILE as the core image [default=%s]\n\ + -Z, --backup-file=FILE use FILE as the backup/restore file [default=%s]\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\ -f, --force install even if problems are detected\n\ -h, --help display this message and exit\n\ + -z, --restore restore the boot sectors\n\ -V, --version print version information and exit\n\ -v, --verbose print verbose messages\n\ \n\ Report bugs to <%s>.\n\ ", - DEFAULT_BOOT_FILE, DEFAULT_CORE_FILE, DEFAULT_DIRECTORY, + DEFAULT_BOOT_FILE, DEFAULT_CORE_FILE, DEFAULT_BACKUP_FILE, DEFAULT_DIRECTORY, DEFAULT_DEVICE_MAP, PACKAGE_BUGREPORT); exit (status); @@ -609,18 +738,19 @@ { char *boot_file = 0; char *core_file = 0; + char *backup_file = 0; char *dir = 0; char *dev_map = 0; char *root_dev = 0; char *dest_dev; - int must_embed = 0, force = 0; + int must_embed = 0, force = 0, restore = 0; progname = "grub-setup"; /* 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:Z:hVvfz", options, 0); if (c == -1) break; @@ -678,6 +808,17 @@ verbosity++; break; + case 'Z': + if (backup_file) + free (backup_file); + + backup_file = xstrdup (optarg); + break; + + case 'z': + restore=1; + break; + default: usage (1); break; @@ -767,7 +908,8 @@ setup (dir ? : DEFAULT_DIRECTORY, boot_file ? : DEFAULT_BOOT_FILE, core_file ? : DEFAULT_CORE_FILE, - root_dev, grub_util_get_grub_dev (devicelist[i]), 1, force); + backup_file ? : DEFAULT_BACKUP_FILE, + root_dev, grub_util_get_grub_dev (devicelist[i]), 1, force,restore); } } else @@ -776,7 +918,8 @@ setup (dir ? : DEFAULT_DIRECTORY, boot_file ? : DEFAULT_BOOT_FILE, core_file ? : DEFAULT_CORE_FILE, - root_dev, dest_dev, must_embed, force); + backup_file ? : DEFAULT_BACKUP_FILE, + root_dev, dest_dev, must_embed, force,restore); /* Free resources. */ grub_fini_all ();