#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+");
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;
}
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;
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)
{
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);
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
{
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",
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:
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;
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;
}
#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)
{
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;
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;
}
#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);
#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);
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 */