grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] Backup old boot sectors before installation


From: Zhu Yi
Subject: [PATCH] Backup old boot sectors before installation
Date: Fri, 11 Dec 2009 17:26:01 +0800

Add a feature to backup the old boot sectors before overwritting
them with grub2 boot and core images. Users can later recover the
previous boot sectors with grub-install --recover option.

P.S. I found this might be a useful feature after I overwrote my
second PGP encrypted hard disk (Windows XP installed) boot sectors
by grub2 by mistake.
    
Signed-off-by: Zhu Yi <address@hidden>
---
diff --git a/util/i386/pc/grub-install.in b/util/i386/pc/grub-install.in
index 8a06213..c33bd87 100644
--- a/util/i386/pc/grub-install.in
+++ b/util/i386/pc/grub-install.in
@@ -51,6 +51,7 @@ no_floppy=
 force_lba=
 recheck=no
 debug=no
+recover=
 
 if [ "${target_cpu}-${platform}" = "i386-pc" ] ; then
     disk_module=biosdisk
@@ -77,6 +78,7 @@ Install GRUB on your drive.
   --no-floppy             do not probe any floppy drive
   --recheck               probe a device map even if it already exists
   --force                 install even if problems are detected
+  --recover               restore the previous boot sectors
 EOF
 if [ "${target_cpu}-${platform}" = "i386-pc" ] ; then
     cat <<EOF
@@ -129,6 +131,10 @@ for option in "$@"; do
        debug=yes ;;
     -f | --force)
         setup_force="--force" ;;
+    --recover)
+        recover="$grub_prefix/bootsectors.bak" ;;
+    --recover=*)
+        recover=`echo "$option" | sed 's/--recover=//'` ;;
     -*)
        echo "Unrecognized option \`$option'" 1>&2
        usage
@@ -203,6 +209,37 @@ else
     exit 1
 fi
 
+if test -f "$recover"; then
+    if test `stat -c%s $recover` -eq 512; then
+        echo "The backup file $recover contains MBR only. Did you install"
+        echo "grub2 using UNRELIABLE blocklist with --force? If so, try to"
+        echo "recover with `dd if=$recover of=$1 bs=512 count=1`. But you"
+        echo "take your own risk!"
+        exit 1
+    fi
+    start=`od -j512 -N8 -An -td8 $recover`
+    start2=`od -j92 -N8 -An -td8 $grubdir/boot.img`
+
+    # Synaty check for the recovery file
+    if test $start -ne $start2; then
+        echo "Error: start position of $recover doesn't match with boot.img"
+        exit 1
+    fi
+    if test $((`stat -c%s $recover` - 520)) -ne \
+       `stat -c%s $grubdir/core.img`; then
+        echo "Error: $recover doesn't match current core.img"
+        exit 1
+    fi
+
+    # Recovery
+    dd if=$recover of=$install_device bs=512 count=1 > /dev/null 2>&1
+    dd if=$recover of=$install_device skip=520 seek=`expr $start \* 512` \
+       bs=1 > /dev/null 2>&1
+    rm -f $recover
+    echo "Recover boot sectors from $recover successfully"
+    exit 0
+fi
+
 # Create the GRUB directory if it is not present.
 test -d "$bootdir" || mkdir "$bootdir" || exit 1
 test -d "$grubdir" || mkdir "$grubdir" || exit 1
diff --git a/util/i386/pc/grub-setup.c b/util/i386/pc/grub-setup.c
index c536be0..e862e9b 100644
--- a/util/i386/pc/grub-setup.c
+++ b/util/i386/pc/grub-setup.c
@@ -45,7 +45,9 @@ static const grub_gpt_part_type_t 
grub_gpt_partition_type_bios_boot = GRUB_GPT_P
 #include <stdlib.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <fcntl.h>
 #include <dirent.h>
+#include <errno.h>
 #include <grub/util/getroot.h>
 
 #define _GNU_SOURCE    1
@@ -53,6 +55,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 +88,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 *backup_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 +399,63 @@ setup (const char *dir,
   block->len = 0;
   block->segment = 0;
 
+  int grub_disk_backup(grub_disk_t disk, grub_disk_addr_t sector,
+                      grub_off_t offset, grub_size_t size, const char *path)
+  {
+    char *tmp_buf;
+    char mbr[GRUB_DISK_SECTOR_SIZE];
+    int fd;
+
+    grub_util_info ("opening the backup file `%s'", path);
+    fd = open (path, O_CREAT|O_EXCL|O_WRONLY);
+    if (fd < 0) {
+      if (errno == EEXIST)
+        return 0;
+      else {
+        fprintf (stderr, "couldn't open backup file `%s'", path);
+        return -1;
+      }
+    }
+
+    fp = fdopen (fd, "wb");
+    if (! fp) {
+      close (fd);
+      return -1;
+    }
+
+    /* Backup MBR */
+    if (grub_disk_read (disk, 0, 0, GRUB_DISK_SECTOR_SIZE, mbr) !=
+        GRUB_ERR_NONE) {
+      fclose (fp);
+      return -1;
+    }
+
+    grub_util_write_image (mbr, GRUB_DISK_SECTOR_SIZE, fp);
+
+    /* Record the start position of core image */
+    if (fwrite(&sector, sizeof(sector), 1, fp) != 1) {
+      fclose (fp);
+      return -1;
+    }
+
+    /* Backup the sectors will be overwritten by core image */
+    tmp_buf = xmalloc (size);
+    if (grub_disk_read (disk, sector, offset, size, tmp_buf) != GRUB_ERR_NONE) 
{
+      fclose (fp);
+      return -1;
+    }
+
+    grub_util_write_image (tmp_buf, size, fp);
+
+    fclose (fp);
+    return 0;
+  }
+
+  /* Backup MBR and the sectors will be overwritten by core image */
+  if (grub_disk_backup (dest_dev->disk, embed_region.start, 0, core_size,
+                       grub_util_get_path (dir, 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);
@@ -548,6 +608,11 @@ unable_to_embed:
   grub_util_write_image (core_img, GRUB_DISK_SECTOR_SIZE * 2, fp);
   fclose (fp);
 
+  /* Backup MBR */
+  if (grub_disk_backup (dest_dev->disk, 0, 0, GRUB_DISK_SECTOR_SIZE,
+                       grub_util_get_path (dir, backup_file)))
+    grub_util_error ("failed to backup previous boot sectors");
+
   /* Write the boot image onto the disk.  */
   if (grub_disk_write (dest_dev->disk, 0, 0, GRUB_DISK_SECTOR_SIZE, boot_img))
     grub_util_error ("%s", grub_errmsg);
@@ -596,6 +661,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\
+  -k, --backup-file=FILE  use FILE as the backup file [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 +671,7 @@ 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_BACKUP_FILE, PACKAGE_BUGREPORT);
 
   exit (status);
 }
@@ -627,6 +693,7 @@ main (int argc, char *argv[])
 {
   char *boot_file = 0;
   char *core_file = 0;
+  char *backup_file = 0;
   char *dir = 0;
   char *dev_map = 0;
   char *root_dev = 0;
@@ -638,7 +705,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:k:hVvf", options, 0);
 
       if (c == -1)
        break;
@@ -680,6 +747,13 @@ main (int argc, char *argv[])
            root_dev = xstrdup (optarg);
            break;
 
+         case 'k':
+            if (backup_file)
+              free (backup_file);
+
+            backup_file = xstrdup (optarg);
+            break;
+
          case 'f':
            force = 1;
            break;
@@ -789,6 +863,7 @@ main (int argc, char *argv[])
          setup (dir ? : DEFAULT_DIRECTORY,
                 boot_file ? : DEFAULT_BOOT_FILE,
                 core_file ? : DEFAULT_CORE_FILE,
+                backup_file ? : DEFAULT_BACKUP_FILE,
                 root_dev, grub_util_get_grub_dev (devicelist[i]), 1, force, 
fs_probe);
        }
     }
@@ -798,6 +873,7 @@ main (int argc, char *argv[])
     setup (dir ? : DEFAULT_DIRECTORY,
           boot_file ? : DEFAULT_BOOT_FILE,
           core_file ? : DEFAULT_CORE_FILE,
+          backup_file ? : DEFAULT_BACKUP_FILE,
           root_dev, dest_dev, must_embed, force, fs_probe);
 
   /* Free resources.  */
@@ -806,6 +882,7 @@ main (int argc, char *argv[])
 
   free (boot_file);
   free (core_file);
+  free (backup_file);
   free (dir);
   free (dev_map);
   free (root_dev);




reply via email to

[Prev in Thread] Current Thread [Next in Thread]