All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] Backup old boot sectors before installation
@ 2009-12-11  9:26 Zhu Yi
  2009-12-11  9:39 ` Felix Zielcke
  2009-12-24 21:21 ` Robert Millan
  0 siblings, 2 replies; 19+ messages in thread
From: Zhu Yi @ 2009-12-11  9:26 UTC (permalink / raw)
  To: grub-devel; +Cc: Zhu Yi

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 <yi.zhu@intel.com>
---
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);



^ permalink raw reply related	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2010-01-07 19:16 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-12-11  9:26 [PATCH] Backup old boot sectors before installation Zhu Yi
2009-12-11  9:39 ` Felix Zielcke
2009-12-11 22:23   ` Carles Pina i Estany
2009-12-14  2:48   ` Zhu Yi
2009-12-14  2:58     ` Isaac Dupree
2009-12-14  3:32       ` Zhu Yi
2009-12-14  2:59     ` kashyap garimella
2009-12-14  3:08       ` richardvoigt
2009-12-14  3:24         ` Isaac Dupree
2009-12-14  3:35           ` Zhu Yi
2009-12-14  3:52             ` Isaac Dupree
2009-12-14  3:15       ` Zhu Yi
2009-12-24 21:21 ` Robert Millan
2009-12-28  6:55   ` Zhu Yi
2009-12-28 22:04     ` Isaac Dupree
2009-12-29  3:21       ` Zhu Yi
2009-12-29  3:59         ` richardvoigt
2009-12-29  7:21           ` Zhu Yi
2010-01-07 19:15             ` rmh

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.