]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
Add cheatmounting
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Fri, 22 Apr 2011 17:20:46 +0000 (19:20 +0200)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Fri, 22 Apr 2011 17:20:46 +0000 (19:20 +0200)
grub-core/disk/luks.c
grub-core/kern/emu/getroot.c
grub-core/kern/emu/hostdisk.c
include/grub/emu/hostdisk.h

index 4d907b4c648e71ddb4b405066eed4f856dbd7367..99dd3a8e6b5f058f75d4fe5250b256ed04e03e39 100644 (file)
 #include <grub/crypto.h>
 #include <grub/extcmd.h>
 #include <grub/i18n.h>
+#ifdef GRUB_UTIL
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <grub/emu/hostdisk.h>
+#include <unistd.h>
+#include <string.h>
+#endif
 
 GRUB_MOD_LICENSE ("GPLv3+");
 
@@ -80,6 +89,10 @@ struct grub_luks
   unsigned long id, source_id;
   enum grub_disk_dev_id source_dev_id;
   char uuid[sizeof (((struct grub_luks_phdr *) 0)->uuid) + 1];
+#ifdef GRUB_UTIL
+  char *cheat;
+  int cheat_fd;
+#endif
   struct grub_luks *next;
 };
 typedef struct grub_luks *grub_luks_t;
@@ -497,6 +510,12 @@ grub_luks_scan_device_real (const char *name, grub_disk_t source)
     }
 
   newdev->source = grub_strdup (name);
+  if (!newdev->source)
+    {
+      grub_free (newdev);
+      return grub_errno;
+    }
+
   newdev->source_id = source->id;
   newdev->source_dev_id = source->dev->id;
   newdev->next = luks_list;
@@ -507,6 +526,48 @@ grub_luks_scan_device_real (const char *name, grub_disk_t source)
   return GRUB_ERR_NONE;
 }
 
+#ifdef GRUB_UTIL
+grub_err_t
+grub_luks_cheat_mount (const char *sourcedev, const char *cheat)
+{
+  grub_err_t err;
+  struct grub_luks_phdr header;
+  grub_luks_t newdev;
+  grub_disk_t source;
+
+  /* Try to open disk.  */
+  source = grub_disk_open (sourcedev);
+  if (!source)
+    return grub_errno;
+
+  /* Read the LUKS header.  */
+  err = grub_disk_read (source, 0, 0, sizeof (header), &header);
+  if (err)
+    return err;
+
+  newdev = configure_ciphers (&header);
+  grub_disk_close (source);
+  if (!newdev)
+    return grub_errno;
+
+  newdev->cheat = grub_strdup (cheat);
+  newdev->source = grub_strdup (sourcedev);
+  if (!newdev->source || !newdev->cheat)
+    {
+      grub_free (newdev->source);
+      grub_free (newdev->cheat);
+      grub_free (newdev);
+      return grub_errno;
+    }
+  newdev->cheat_fd = -1;
+  newdev->source_id = source->id;
+  newdev->source_dev_id = source->dev->id;
+  newdev->next = luks_list;
+  luks_list = newdev;
+  return GRUB_ERR_NONE;
+}
+#endif
+
 static int
 grub_luks_scan_device (const char *name)
 {
@@ -575,6 +636,17 @@ grub_luks_open (const char *name, grub_disk_t disk,
   if (!dev)
     return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "No such device");
 
+#ifdef GRUB_UTIL
+  if (dev->cheat)
+    {
+      if (dev->cheat_fd == -1)
+       dev->cheat_fd = open (dev->cheat, O_RDONLY);
+      if (dev->cheat_fd == -1)
+       return grub_error (GRUB_ERR_IO, "couldn't open %s: %s",
+                          dev->cheat, strerror (errno));
+    }
+#endif
+
   if (!dev->source_disk)
     {
       grub_dprintf ("luks", "Opening device %s\n", name);
@@ -599,11 +671,17 @@ grub_luks_close (grub_disk_t disk)
 
   dev->ref--;
 
-  if (dev->ref == 0)
+  if (dev->ref != 0)
+    return;
+#ifdef GRUB_UTIL
+  if (dev->cheat)
     {
-      grub_disk_close (dev->source_disk);
-      dev->source_disk = NULL;
+      close (dev->cheat_fd);
+      dev->cheat_fd = -1;
     }
+#endif
+  grub_disk_close (dev->source_disk);
+  dev->source_disk = NULL;
 }
 
 static grub_err_t
@@ -612,6 +690,21 @@ grub_luks_read (grub_disk_t disk, grub_disk_addr_t sector,
 {
   grub_luks_t dev = (grub_luks_t) disk->data;
   grub_err_t err;
+
+#ifdef GRUB_UTIL
+  if (dev->cheat)
+    {
+      err = grub_util_fd_sector_seek (dev->cheat_fd, dev->cheat, sector);
+      if (err)
+       return err;
+      if (grub_util_fd_read (dev->cheat_fd, buf, size << GRUB_DISK_SECTOR_BITS)
+         != (ssize_t) (size << GRUB_DISK_SECTOR_BITS))
+       return grub_error (GRUB_ERR_READ_ERROR, "cannot read from `%s'",
+                          dev->cheat);
+      return GRUB_ERR_NONE;
+    }
+#endif
+
   grub_dprintf ("luks",
                "Reading %" PRIuGRUB_SIZE " sectors from sector 0x%"
                PRIxGRUB_UINT64_T " with offset of %" PRIuGRUB_UINT32_T "\n",
index 6cc745833b2dd23ef53ba6c08bff1da95403a8ca..c3a971689c72990b03615b2b34c94cacb932c7a2 100644 (file)
@@ -865,7 +865,9 @@ out:
 void
 grub_util_pull_device (const char *os_dev)
 {
-  switch (grub_util_get_dev_abstraction (os_dev))
+  int ab;
+  ab = grub_util_get_dev_abstraction (os_dev);
+  switch (ab)
     {
     case GRUB_DEV_ABSTRACTION_LVM:
     case GRUB_DEV_ABSTRACTION_LUKS:
@@ -875,6 +877,7 @@ grub_util_pull_device (const char *os_dev)
        struct dm_tree_node *node;
        struct dm_tree_node *child;
        void *handle = NULL;
+       char *lastsubdev = NULL;
 
        if (!grub_util_open_dm (os_dev, &tree, &node))
          return;
@@ -887,9 +890,26 @@ grub_util_pull_device (const char *os_dev)
              continue;
            subdev = grub_find_device ("/dev", makedev (dm->major, dm->minor));
            if (subdev)
-             grub_util_pull_device (subdev);
+             {
+               lastsubdev = subdev;
+               grub_util_pull_device (subdev);
+             }
          }
-       dm_tree_free (tree);
+       if (ab == GRUB_DEV_ABSTRACTION_LUKS && lastsubdev)
+         {
+           char *grdev = grub_util_get_grub_dev (lastsubdev);
+           dm_tree_free (tree);
+           if (grdev)
+             {
+               grub_err_t err;
+               err = grub_luks_cheat_mount (grdev, os_dev);
+               if (err)
+                 grub_util_error ("Can't mount LUKS: %s", grub_errmsg);
+             }
+           grub_free (grdev);
+         }
+       else
+         dm_tree_free (tree);
       }
 #endif
       return;
index 9b65d417e3e7b5e0795ec9c2901bb2ce997fc0d8..110d3e29190406a902d9467bb06298daa4728001 100644 (file)
@@ -631,6 +631,37 @@ linux_find_partition (char *dev, unsigned long sector)
 }
 #endif /* __linux__ */
 
+#if defined(__linux__) && (!defined(__GLIBC__) || \
+        ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1))))
+  /* Maybe libc doesn't have large file support.  */
+grub_err_t
+grub_util_fd_sector_seek (int fd, const char *name, grub_disk_addr_t sector)
+{
+  loff_t offset, result;
+  static int _llseek (uint filedes, ulong hi, ulong lo,
+                     loff_t *res, uint wh);
+  _syscall5 (int, _llseek, uint, filedes, ulong, hi, ulong, lo,
+            loff_t *, res, uint, wh);
+
+  offset = (loff_t) sector << GRUB_DISK_SECTOR_BITS;
+  if (_llseek (fd, offset >> 32, offset & 0xffffffff, &result, SEEK_SET))
+    {
+      return grub_error (GRUB_ERR_BAD_DEVICE, "cannot seek `%s'", name);
+    }
+  return GRUB_ERR_NONE;
+}
+#else
+grub_err_t
+grub_util_fd_sector_seek (int fd, const char *name, grub_disk_addr_t sector)
+{
+  off_t offset = (off_t) sector << GRUB_DISK_SECTOR_BITS;
+
+  if (lseek (fd, offset, SEEK_SET) != offset)
+    return grub_error (GRUB_ERR_BAD_DEVICE, "cannot seek `%s'", name);
+  return 0;
+}
+#endif
+
 static int
 open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags)
 {
@@ -781,44 +812,19 @@ open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags)
   configure_device_driver (fd);
 #endif /* defined(__NetBSD__) */
 
-#if defined(__linux__) && (!defined(__GLIBC__) || \
-        ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1))))
-  /* Maybe libc doesn't have large file support.  */
-  {
-    loff_t offset, result;
-    static int _llseek (uint filedes, ulong hi, ulong lo,
-                        loff_t *res, uint wh);
-    _syscall5 (int, _llseek, uint, filedes, ulong, hi, ulong, lo,
-               loff_t *, res, uint, wh);
-
-    offset = (loff_t) sector << GRUB_DISK_SECTOR_BITS;
-    if (_llseek (fd, offset >> 32, offset & 0xffffffff, &result, SEEK_SET))
-      {
-       grub_error (GRUB_ERR_BAD_DEVICE, "cannot seek `%s'", map[disk->id].device);
-       close (fd);
-       return -1;
-      }
-  }
-#else
-  {
-    off_t offset = (off_t) sector << GRUB_DISK_SECTOR_BITS;
-
-    if (lseek (fd, offset, SEEK_SET) != offset)
-      {
-       grub_error (GRUB_ERR_BAD_DEVICE, "cannot seek `%s'", map[disk->id].device);
-       close (fd);
-       return -1;
-      }
-  }
-#endif
+  if (grub_util_fd_sector_seek (fd, map[disk->id].device, sector))
+    {
+      close (fd);
+      return -1;
+    }
 
   return fd;
 }
 
 /* Read LEN bytes from FD in BUF. Return less than or equal to zero if an
    error occurs, otherwise return LEN.  */
-static ssize_t
-nread (int fd, char *buf, size_t len)
+ssize_t
+grub_util_fd_read (int fd, char *buf, size_t len)
 {
   ssize_t size = len;
 
@@ -901,7 +907,8 @@ grub_util_biosdisk_read (grub_disk_t disk, grub_disk_addr_t sector,
         sectors that are read together with the MBR in one read.  It
         should only remap the MBR, so we split the read in two
         parts. -jochen  */
-      if (nread (fd, buf, GRUB_DISK_SECTOR_SIZE) != GRUB_DISK_SECTOR_SIZE)
+      if (grub_util_fd_read (fd, buf, GRUB_DISK_SECTOR_SIZE)
+         != GRUB_DISK_SECTOR_SIZE)
        {
          grub_error (GRUB_ERR_READ_ERROR, "cannot read `%s'", map[disk->id].device);
          return grub_errno;
@@ -912,7 +919,7 @@ grub_util_biosdisk_read (grub_disk_t disk, grub_disk_addr_t sector,
     }
 #endif /* __linux__ */
 
-  if (nread (fd, buf, size << GRUB_DISK_SECTOR_BITS)
+  if (grub_util_fd_read (fd, buf, size << GRUB_DISK_SECTOR_BITS)
       != (ssize_t) (size << GRUB_DISK_SECTOR_BITS))
     grub_error (GRUB_ERR_READ_ERROR, "cannot read from `%s'", map[disk->id].device);
 
index 803c0f755b1ef1e0bc28145316c388744e49cf4f..c7a794d68530e3c204b76f7543331d642ae818c5 100644 (file)
@@ -21,6 +21,7 @@
 #define GRUB_BIOSDISK_MACHINE_UTIL_HEADER      1
 
 #include <grub/disk.h>
+#include <sys/types.h>
 
 void grub_util_biosdisk_init (const char *dev_map);
 void grub_util_biosdisk_fini (void);
@@ -30,5 +31,10 @@ int grub_util_biosdisk_is_present (const char *name);
 int grub_util_biosdisk_is_floppy (grub_disk_t disk);
 grub_err_t grub_util_biosdisk_flush (struct grub_disk *disk);
 void grub_util_pull_device (const char *osname);
+grub_err_t
+grub_util_fd_sector_seek (int fd, const char *name, grub_disk_addr_t sector);
+ssize_t grub_util_fd_read (int fd, char *buf, size_t len);
+grub_err_t
+grub_luks_cheat_mount (const char *sourcedev, const char *cheat);
 
 #endif /* ! GRUB_BIOSDISK_MACHINE_UTIL_HEADER */