]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
Use Winapi on both cygwin and mingw32 to share more code between both.
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Mon, 23 Sep 2013 09:21:09 +0000 (11:21 +0200)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Mon, 23 Sep 2013 09:21:09 +0000 (11:21 +0200)
30 files changed:
ChangeLog
Makefile.util.def
conf/Makefile.extra-dist
configure.ac
grub-core/Makefile.core.def
grub-core/disk/geli.c
grub-core/kern/emu/hostdisk.c
grub-core/kern/emu/hostdisk_apple.c
grub-core/kern/emu/hostdisk_basic.c
grub-core/kern/emu/hostdisk_bsd.c
grub-core/kern/emu/hostdisk_cygwin.c [deleted file]
grub-core/kern/emu/hostdisk_freebsd.c
grub-core/kern/emu/hostdisk_hurd.c
grub-core/kern/emu/hostdisk_linux.c
grub-core/kern/emu/hostdisk_mingw.c [deleted file]
grub-core/kern/emu/hostdisk_os.c
grub-core/kern/emu/hostdisk_sun.c
grub-core/kern/emu/hostdisk_unix.c [new file with mode: 0644]
grub-core/kern/emu/hostdisk_windows.c [new file with mode: 0644]
grub-core/kern/emu/hostfs.c
grub-core/kern/emu/main.c
include/grub/emu/getroot.h
include/grub/emu/hostdisk.h
include/grub/util/windows.h [new file with mode: 0644]
util/getroot.c
util/getroot_cygwin.c [deleted file]
util/getroot_hurd.c
util/getroot_os.c
util/getroot_unix.c [new file with mode: 0644]
util/getroot_windows.c [new file with mode: 0644]

index 2280fde58b4601dc6afa0dad902c6822959360cb..9352cde14ca0de3ae6e97254be2e7849482760ad 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2013-09-23  Vladimir Serbinenko  <phcoder@gmail.com>
+
+       Use Winapi on both cygwin and mingw32 to share more code between both.
+
 2013-09-22  Andrey Borzenkov <arvidjaar@gmail.com>
 
        * util/grub-install.in: Add --grub-editenv option.
index 38ce370bf91d3bd2cf9297dea4e76842fd619107..c8c314dfdaf23dc02da00c88db796c0d3b135314 100644 (file)
@@ -10,12 +10,14 @@ library = {
   common = grub-core/kern/device.c;
   common = grub-core/kern/disk.c;
   common = util/getroot.c;
+  common = util/getroot_unix.c;
   common = util/getroot_os.c;
   common = util/getroot_devmapper.c;
   common = util/raid.c;
   common = grub-core/kern/emu/hostdisk.c;
   common = grub-core/kern/emu/hostdisk_devmapper.c;
   common = grub-core/kern/emu/hostdisk_os.c;
+  common = grub-core/kern/emu/hostdisk_unix.c;
   common = grub-core/kern/emu/misc.c;
   common = grub-core/kern/emu/mm.c;
   common = grub-core/kern/env.c;
index b666468e34339b709612a73978e01a940b604fb1..a32472556e085478d85e32355601c1cc67ef4927 100644 (file)
@@ -65,17 +65,16 @@ EXTRA_DIST += m4/math_h.m4
 EXTRA_DIST += grub-core/kern/emu/hostdisk_apple.c
 EXTRA_DIST += grub-core/kern/emu/hostdisk_basic.c
 EXTRA_DIST += grub-core/kern/emu/hostdisk_bsd.c
-EXTRA_DIST += grub-core/kern/emu/hostdisk_cygwin.c
 EXTRA_DIST += grub-core/kern/emu/hostdisk_freebsd.c
 EXTRA_DIST += grub-core/kern/emu/hostdisk_hurd.c
 EXTRA_DIST += grub-core/kern/emu/hostdisk_linux.c
-EXTRA_DIST += grub-core/kern/emu/hostdisk_mingw.c
+EXTRA_DIST += grub-core/kern/emu/hostdisk_windows.c
 EXTRA_DIST += grub-core/kern/emu/hostdisk_sun.c
 
 EXTRA_DIST += util/getroot_apple.c
 EXTRA_DIST += util/getroot_basic.c
 EXTRA_DIST += util/getroot_bsd.c
-EXTRA_DIST += util/getroot_cygwin.c
+EXTRA_DIST += util/getroot_windows.c
 EXTRA_DIST += util/getroot_freebsd.c
 EXTRA_DIST += util/getroot_hurd.c
 EXTRA_DIST += util/getroot_linux.c
index e6ad049f14d1815c880736292f97d7d03caeced3..01d11e8ee5e250721c2be76e5ddfdbbd23273be2 100644 (file)
@@ -182,7 +182,7 @@ case "$host_os" in
   netbsd*)                     host_kernel=netbsd ;;
   solaris*)                    host_kernel=illumos ;;
   darwin*)                     host_kernel=xnu ;;
-  cygwin)                      host_kernel=windows ;;
+  cygwin | windows* | mingw32*)        host_kernel=windows ;;
 esac
 
 case "$platform" in
@@ -333,6 +333,14 @@ AC_C_BIGENDIAN
 AC_CHECK_SIZEOF(void *)
 AC_CHECK_SIZEOF(long)
 
+case "$host_os" in
+  cygwin | windows* | mingw32*)
+     HOST_CPPFLAGS="$HOST_CPPFLAGS -DUNICODE=1 -D_WIN32_WINNT=0x0500"
+     CPPFLAGS="$CPPFLAGS -DUNICODE=1 -D_WIN32_WINNT=0x0500"
+     AC_CHECK_SIZEOF(TCHAR,,[#include <windows.h>])
+   ;;
+esac
+
 grub_apple_cc
 if test x$grub_cv_apple_cc = xyes ; then
   HOST_CPPFLAGS="$HOST_CPPFLAGS -fnested-functions"
index a4e6862bb5cf4c38613a9b789b8bedbcfe6f26f5..a7ff80e70531d8b9e45f4b5882b3fc88c40478e3 100644 (file)
@@ -241,6 +241,7 @@ kernel = {
   emu = kern/emu/error.c;
   emu = kern/emu/cache_s.S;
   emu = kern/emu/hostdisk.c;
+  emu = kern/emu/hostdisk_unix.c;
   emu = kern/emu/hostdisk_devmapper.c;
   emu = kern/emu/hostdisk_os.c;
   emu = kern/emu/hostfs.c;
index 2aa1ae08d3d69e0e0099980a9807fd03dcb60a49..ce6bb391194f6f685ed49eb6536d682589cbb8e9 100644 (file)
@@ -210,7 +210,7 @@ make_uuid (const struct grub_geli_phdr *header,
 char *
 grub_util_get_geli_uuid (const char *dev)
 {
-  int fd = open (dev, O_RDONLY);
+  grub_util_fd_t fd = grub_util_fd_open (dev, O_RDONLY);
   grub_uint64_t s;
   unsigned log_secsize;
   grub_uint8_t hdr[512];
@@ -218,7 +218,7 @@ grub_util_get_geli_uuid (const char *dev)
   char *uuid; 
   gcry_err_code_t err;
 
-  if (fd < 0)
+  if (!GRUB_UTIL_FD_IS_VALID (fd))
     return NULL;
 
   s = grub_util_get_fd_size (fd, dev, &log_secsize);
index f1f75705552e2ba4706259f41a6881fd94ae39fb..cbf50771f0250ef3cdda5eb6167627edbfce763c 100644 (file)
 #ifdef __linux__
 # include <sys/ioctl.h>         /* ioctl */
 # include <sys/mount.h>
-# if !defined(__GLIBC__) || \
-        ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1)))
-/* Maybe libc doesn't have large file support.  */
-#  include <linux/unistd.h>     /* _llseek */
-# endif /* (GLIBC < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR < 1)) */
 # ifndef BLKFLSBUF
 #  define BLKFLSBUF     _IO (0x12,97)   /* flush buffer cache */
 # endif /* ! BLKFLSBUF */
@@ -68,15 +63,6 @@ static struct
   int device_map;
 } map[256];
 
-struct grub_util_biosdisk_data
-{
-  char *dev;
-  int access_mode;
-  int fd;
-  int is_disk;
-  int device_map;
-};
-
 static int
 unescape_cmp (const char *a, const char *b_escaped)
 {
@@ -141,81 +127,42 @@ grub_util_biosdisk_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data,
   return 0;
 }
 
-#ifdef __MINGW32__
-
-grub_uint64_t
-grub_util_get_fd_size (int fd, const char *name,
-                      unsigned *log_secsize)
-{
-  return grub_util_get_fd_size_os (fd, name, log_secsize);
-}
-
-#else
-
-grub_uint64_t
-grub_util_get_fd_size (int fd, const char *name, unsigned *log_secsize)
-{
-  struct stat st;
-  grub_int64_t ret = -1;
-
-  if (fstat (fd, &st) < 0)
-    /* TRANSLATORS: "stat" comes from the name of POSIX function.  */
-    grub_util_error (_("cannot stat `%s': %s"), name, strerror (errno));
-#if GRUB_DISK_DEVS_ARE_CHAR
-  if (S_ISCHR (st.st_mode))
-#else
-  if (S_ISBLK (st.st_mode))
-#endif
-    ret = grub_util_get_fd_size_os (fd, name, log_secsize);
-  if (ret != -1LL)
-    return ret;
-
-  if (log_secsize)
-    *log_secsize = 9;
-
-  return st.st_size;
-}
-
-#endif
-
 static grub_err_t
 grub_util_biosdisk_open (const char *name, grub_disk_t disk)
 {
   int drive;
   struct stat st;
-  struct grub_util_biosdisk_data *data;
+  struct grub_util_hostdisk_data *data;
 
   drive = find_grub_drive (name);
+  grub_util_info ("drive = %d", drive);
   if (drive < 0)
     return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
                       "no mapping exists for `%s'", name);
 
   disk->id = drive;
-  disk->data = data = xmalloc (sizeof (struct grub_util_biosdisk_data));
+  disk->data = data = xmalloc (sizeof (struct grub_util_hostdisk_data));
   data->dev = NULL;
   data->access_mode = 0;
-  data->fd = -1;
+  data->fd = GRUB_UTIL_FD_INVALID;
   data->is_disk = 0;
   data->device_map = map[drive].device_map;
 
   /* Get the size.  */
   {
-    int fd;
+    grub_util_fd_t fd;
 
-#if defined(__MINGW32__)
-    fd = -1;
-#else
-    fd = open (map[drive].device, O_RDONLY);
-    if (fd == -1)
+    fd = grub_util_fd_open (map[drive].device, O_RDONLY);
+
+    if (!GRUB_UTIL_FD_IS_VALID(fd))
       return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("cannot open `%s': %s"),
                         map[drive].device, strerror (errno));
-#endif
 
     disk->total_sectors = grub_util_get_fd_size (fd, map[drive].device,
                                                 &disk->log_sector_size);
     disk->total_sectors >>= disk->log_sector_size;
 
-#if !defined(__MINGW32__)
+#if !defined(__MINGW32__) && !defined(__CYGWIN__)
 
 # if GRUB_DISK_DEVS_ARE_CHAR
     if (fstat (fd, &st) < 0 || ! S_ISCHR (st.st_mode))
@@ -223,10 +170,10 @@ grub_util_biosdisk_open (const char *name, grub_disk_t disk)
     if (fstat (fd, &st) < 0 || ! S_ISBLK (st.st_mode))
 # endif
       data->is_disk = 1;
-
-    close (fd);
 #endif
 
+    grub_util_fd_close (fd);
+
     grub_util_info ("the size of %s is %" PRIuGRUB_UINT64_T,
                    name, disk->total_sectors);
 
@@ -234,37 +181,6 @@ grub_util_biosdisk_open (const char *name, grub_disk_t disk)
   }
 }
 
-#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_seek (int fd, const char *name, grub_uint64_t off)
-{
-  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) off;
-  if (_llseek (fd, offset >> 32, offset & 0xffffffff, &result, SEEK_SET))
-    return grub_error (GRUB_ERR_BAD_DEVICE, N_("cannot seek `%s': %s"),
-                      name, strerror (errno));
-  return GRUB_ERR_NONE;
-}
-#else
-grub_err_t
-grub_util_fd_seek (int fd, const char *name, grub_uint64_t off)
-{
-  off_t offset = (off_t) off;
-
-  if (lseek (fd, offset, SEEK_SET) != offset)
-    return grub_error (GRUB_ERR_BAD_DEVICE, N_("cannot seek `%s': %s"),
-                      name, strerror (errno));
-  return 0;
-}
-#endif
-
 const char *
 grub_hostdisk_os_dev_to_grub_drive (const char *os_disk, int add)
 {
@@ -305,12 +221,13 @@ grub_hostdisk_os_dev_to_grub_drive (const char *os_disk, int add)
   return map[i].drive;
 }
 
-static int
-open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags,
-            grub_disk_addr_t *max)
+#ifndef __linux__
+grub_util_fd_t
+grub_util_fd_open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags,
+                         grub_disk_addr_t *max)
 {
-  int fd;
-  struct grub_util_biosdisk_data *data = disk->data;
+  grub_util_fd_t fd;
+  struct grub_util_hostdisk_data *data = disk->data;
 
   *max = ~0ULL;
 
@@ -327,87 +244,6 @@ open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags,
   flags |= O_BINARY;
 #endif
 
-#ifdef __linux__
-  /* Linux has a bug that the disk cache for a whole disk is not consistent
-     with the one for a partition of the disk.  */
-  {
-    int is_partition = 0;
-    char dev[PATH_MAX];
-    grub_disk_addr_t part_start = 0;
-
-    part_start = grub_partition_get_start (disk->partition);
-
-    strcpy (dev, map[disk->id].device);
-    if (disk->partition
-       && strncmp (map[disk->id].device, "/dev/", 5) == 0)
-      {
-       if (sector >= part_start)
-         is_partition = grub_hostdisk_linux_find_partition (dev, part_start);
-       else
-         *max = part_start - sector;
-      }
-
-  reopen:
-
-    if (data->dev && strcmp (data->dev, dev) == 0 &&
-       data->access_mode == (flags & O_ACCMODE))
-      {
-       grub_dprintf ("hostdisk", "reusing open device `%s'\n", dev);
-       fd = data->fd;
-      }
-    else
-      {
-       free (data->dev);
-       data->dev = 0;
-       if (data->fd != -1)
-         {
-           if (data->access_mode == O_RDWR || data->access_mode == O_WRONLY)
-             {
-               fsync (data->fd);
-               if (data->is_disk)
-                 ioctl (data->fd, BLKFLSBUF, 0);
-             }
-
-           close (data->fd);
-           data->fd = -1;
-         }
-
-       /* Open the partition.  */
-       grub_dprintf ("hostdisk", "opening the device `%s' in open_device()\n", dev);
-       fd = open (dev, flags);
-       if (fd < 0)
-         {
-           grub_error (GRUB_ERR_BAD_DEVICE, N_("cannot open `%s': %s"),
-                       dev, strerror (errno));
-           return -1;
-         }
-
-       data->dev = xstrdup (dev);
-       data->access_mode = (flags & O_ACCMODE);
-       data->fd = fd;
-
-       if (data->is_disk)
-         ioctl (data->fd, BLKFLSBUF, 0);
-      }
-
-    if (is_partition)
-      {
-       *max = grub_util_get_fd_size (fd, dev, 0);
-       *max >>= disk->log_sector_size;
-       if (sector - part_start >= *max)
-         {
-           *max = disk->partition->len - (sector - part_start);
-           if (*max == 0)
-             *max = ~0ULL;
-           is_partition = 0;
-           strcpy (dev, map[disk->id].device);
-           goto reopen;
-         }
-       sector -= part_start;
-       *max -= sector;
-      }
-  }
-#else /* ! __linux__ */
 #if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
   int sysctl_flags, sysctl_oldflags;
   size_t sysctl_size = sizeof (sysctl_flags);
@@ -415,14 +251,14 @@ open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags,
   if (sysctlbyname ("kern.geom.debugflags", &sysctl_oldflags, &sysctl_size, NULL, 0))
     {
       grub_error (GRUB_ERR_BAD_DEVICE, "cannot get current flags of sysctl kern.geom.debugflags");
-      return -1;
+      return GRUB_UTIL_FD_INVALID;
     }
   sysctl_flags = sysctl_oldflags | 0x10;
   if (! (sysctl_oldflags & 0x10)
       && sysctlbyname ("kern.geom.debugflags", NULL , 0, &sysctl_flags, sysctl_size))
     {
       grub_error (GRUB_ERR_BAD_DEVICE, "cannot set flags of sysctl kern.geom.debugflags");
-      return -1;
+      return GRUB_UTIL_FD_INVALID;
     }
 #endif
 
@@ -436,18 +272,16 @@ open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags,
     {
       free (data->dev);
       data->dev = 0;
-      if (data->fd != -1)
+      if (GRUB_UTIL_FD_IS_VALID(data->fd))
        {
            if (data->access_mode == O_RDWR || data->access_mode == O_WRONLY)
-             {
-               fsync (data->fd);
-             }
-           close (data->fd);
-           data->fd = -1;
+             grub_util_fd_sync (data->fd);
+           grub_util_fd_close (data->fd);
+           data->fd = GRUB_UTIL_FD_INVALID;
        }
 
-      fd = open (map[disk->id].device, flags);
-      if (fd >= 0)
+      fd = grub_util_fd_open (map[disk->id].device, flags);
+      if (GRUB_UTIL_FD_IS_VALID(fd))
        {
          data->dev = xstrdup (map[disk->id].device);
          data->access_mode = (flags & O_ACCMODE);
@@ -460,7 +294,7 @@ open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags,
       && sysctlbyname ("kern.geom.debugflags", NULL , 0, &sysctl_oldflags, sysctl_size))
     {
       grub_error (GRUB_ERR_BAD_DEVICE, "cannot set flags back to the old value for sysctl kern.geom.debugflags");
-      return -1;
+      return GRUB_UTIL_FD_INVALID;
     }
 #endif
 
@@ -470,77 +304,26 @@ open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags,
     fd = open(map[disk->id].device, flags | O_SHLOCK);
 #endif
 
-  if (fd < 0)
+  if (!GRUB_UTIL_FD_IS_VALID(data->fd))
     {
       grub_error (GRUB_ERR_BAD_DEVICE, N_("cannot open `%s': %s"),
                  map[disk->id].device, strerror (errno));
-      return -1;
+      return GRUB_UTIL_FD_INVALID;
     }
-#endif /* ! __linux__ */
 
   grub_hostdisk_configure_device_driver (fd);
 
   if (grub_util_fd_seek (fd, map[disk->id].device,
                         sector << disk->log_sector_size))
     {
-      close (fd);
-      return -1;
+      grub_util_fd_close (fd);
+      return GRUB_UTIL_FD_INVALID;
     }
 
   return fd;
 }
+#endif
 
-/* Read LEN bytes from FD in BUF. Return less than or equal to zero if an
-   error occurs, otherwise return LEN.  */
-ssize_t
-grub_util_fd_read (int fd, char *buf, size_t len)
-{
-  ssize_t size = len;
-
-  while (len)
-    {
-      ssize_t ret = read (fd, buf, len);
-
-      if (ret <= 0)
-        {
-          if (errno == EINTR)
-            continue;
-          else
-            return ret;
-        }
-
-      len -= ret;
-      buf += ret;
-    }
-
-  return size;
-}
-
-/* Write LEN bytes from BUF to FD. Return less than or equal to zero if an
-   error occurs, otherwise return LEN.  */
-ssize_t
-grub_util_fd_write (int fd, const char *buf, size_t len)
-{
-  ssize_t size = len;
-
-  while (len)
-    {
-      ssize_t ret = write (fd, buf, len);
-
-      if (ret <= 0)
-        {
-          if (errno == EINTR)
-            continue;
-          else
-            return ret;
-        }
-
-      len -= ret;
-      buf += ret;
-    }
-
-  return size;
-}
 
 static grub_err_t
 grub_util_biosdisk_read (grub_disk_t disk, grub_disk_addr_t sector,
@@ -548,10 +331,10 @@ grub_util_biosdisk_read (grub_disk_t disk, grub_disk_addr_t sector,
 {
   while (size)
     {
-      int fd;
+      grub_util_fd_t fd;
       grub_disk_addr_t max = ~0ULL;
-      fd = open_device (disk, sector, O_RDONLY, &max);
-      if (fd < 0)
+      fd = grub_util_fd_open_device (disk, sector, O_RDONLY, &max);
+      if (!GRUB_UTIL_FD_IS_VALID (fd))
        return grub_errno;
 
 #ifdef __linux__
@@ -583,10 +366,10 @@ grub_util_biosdisk_write (grub_disk_t disk, grub_disk_addr_t sector,
 {
   while (size)
     {
-      int fd;
+      grub_util_fd_t fd;
       grub_disk_addr_t max = ~0ULL;
-      fd = open_device (disk, sector, O_WRONLY, &max);
-      if (fd < 0)
+      fd = grub_util_fd_open_device (disk, sector, O_WRONLY, &max);
+      if (!GRUB_UTIL_FD_IS_VALID (fd))
        return grub_errno;
 
 #ifdef __linux__
@@ -614,18 +397,18 @@ grub_util_biosdisk_write (grub_disk_t disk, grub_disk_addr_t sector,
 grub_err_t
 grub_util_biosdisk_flush (struct grub_disk *disk)
 {
-  struct grub_util_biosdisk_data *data = disk->data;
+  struct grub_util_hostdisk_data *data = disk->data;
 
   if (disk->dev->id != GRUB_DISK_DEVICE_BIOSDISK_ID)
     return GRUB_ERR_NONE;
-  if (data->fd == -1)
+  if (!GRUB_UTIL_FD_IS_VALID (data->fd))
     {
       grub_disk_addr_t max;
-      data->fd = open_device (disk, 0, O_RDONLY, &max);
-      if (data->fd < 0)
+      data->fd = grub_util_fd_open_device (disk, 0, O_RDONLY, &max);
+      if (!GRUB_UTIL_FD_IS_VALID (data->fd))
        return grub_errno;
     }
-  fsync (data->fd);
+  grub_util_fd_sync (data->fd);
 #ifdef __linux__
   if (data->is_disk)
     ioctl (data->fd, BLKFLSBUF, 0);
@@ -636,14 +419,14 @@ grub_util_biosdisk_flush (struct grub_disk *disk)
 static void
 grub_util_biosdisk_close (struct grub_disk *disk)
 {
-  struct grub_util_biosdisk_data *data = disk->data;
+  struct grub_util_hostdisk_data *data = disk->data;
 
   free (data->dev);
-  if (data->fd != -1)
+  if (!GRUB_UTIL_FD_IS_VALID (data->fd))
     {
       if (data->access_mode == O_RDWR || data->access_mode == O_WRONLY)
        grub_util_biosdisk_flush (disk);
-      close (data->fd);
+      grub_util_fd_close (data->fd);
     }
   free (data);
 }
@@ -660,13 +443,31 @@ static struct grub_disk_dev grub_util_biosdisk_dev =
     .next = 0
   };
 
+static int
+grub_util_check_file_presence (const char *p)
+{
+#if defined (__MINGW32__) || defined(__CYGWIN__)
+  HANDLE h;
+  h = grub_util_fd_open (p, O_RDONLY);
+  if (!GRUB_UTIL_FD_IS_VALID(h))
+    return 0;
+  CloseHandle (h);
+  return 1;
+#else
+  struct stat st;
+
+  if (stat (p, &st) == -1)
+    return 0;
+  return 1;
+#endif
+}
+
 static void
 read_device_map (const char *dev_map)
 {
   FILE *fp;
   char buf[1024];      /* XXX */
   int lineno = 0;
-  struct stat st;
 
   if (dev_map[0] == '\0')
     {
@@ -770,12 +571,7 @@ read_device_map (const char *dev_map)
        e++;
       *e = '\0';
 
-#ifdef __MINGW32__
-      (void) st;
-      if (grub_util_get_fd_size (-1, p, NULL) == -1LL)
-#else
-      if (stat (p, &st) == -1)
-#endif
+      if (!grub_util_check_file_presence (p))
        {
          free (map[drive].drive);
          map[drive].drive = NULL;
index 8ba785e2ddfdb840943ecb62d9bd96b2c7b6c7eb..ac653bb6a68ad0fe707ce42ca0bd25cdfd6b1482 100644 (file)
@@ -45,7 +45,7 @@
 # include <sys/disk.h>
 
 grub_uint64_t
-grub_util_get_fd_size (int fd, const char *name, unsigned *log_secsize)
+grub_util_get_fd_size (grub_util_fd_t fd, const char *name, unsigned *log_secsize)
 {
   unsigned long long nr;
   unsigned sector_size, log_sector_size;
@@ -69,6 +69,6 @@ grub_util_get_fd_size (int fd, const char *name, unsigned *log_secsize)
 }
 
 void
-grub_hostdisk_configure_device_driver (int fd __attribute__ ((unused)))
+grub_hostdisk_configure_device_driver (grub_util_fd_t fd __attribute__ ((unused)))
 {
 }
index a9342d017ade8861d4f7818e6b9831060f8c5adc..7ea079557f51d5a6c9bcbd046f5494cc6f4ff2a0 100644 (file)
@@ -43,7 +43,7 @@
 #include <limits.h>
 
 grub_int64_t
-grub_util_get_fd_size_os (int fd __attribute__ ((unused)),
+grub_util_get_fd_size_os (grub_util_fd_t fd __attribute__ ((unused)),
                       const char *name __attribute__ ((unused)),
                       unsigned *log_secsize __attribute__ ((unused)))
 {
@@ -53,7 +53,7 @@ grub_util_get_fd_size_os (int fd __attribute__ ((unused)),
 }
 
 void
-grub_hostdisk_configure_device_driver (int fd __attribute__ ((unused)))
+grub_hostdisk_configure_device_driver (grub_util_fd_t fd __attribute__ ((unused)))
 {
 }
 
index b986f0321d3ae4eede99991e66a4454bc21ee6d6..a5dadf19559d46d5bf000f319125f5e7b381412b 100644 (file)
@@ -61,7 +61,7 @@
    floppy driver from retrying operations on failure, as otherwise the
    driver takes a while to abort when there is no floppy in the drive.  */
 void
-grub_hostdisk_configure_device_driver (int fd)
+grub_hostdisk_configure_device_driver (grub_util_fd_t fd)
 {
   struct stat st;
 
@@ -80,13 +80,13 @@ grub_hostdisk_configure_device_driver (int fd)
 }
 #else
 void
-grub_hostdisk_configure_device_driver (int fd __attribute__ ((unused)))
+grub_hostdisk_configure_device_driver (grub_util_fd_t fd __attribute__ ((unused)))
 {
 }
 #endif
 
 grub_int64_t
-grub_util_get_fd_size_os (int fd, const char *name, unsigned *log_secsize)
+grub_util_get_fd_size_os (grub_util_fd_t fd, const char *name, unsigned *log_secsize)
 {
   struct disklabel label;
   unsigned sector_size, log_sector_size;
diff --git a/grub-core/kern/emu/hostdisk_cygwin.c b/grub-core/kern/emu/hostdisk_cygwin.c
deleted file mode 100644 (file)
index c1e4bd5..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- *  GRUB  --  GRand Unified Bootloader
- *  Copyright (C) 1999,2000,2001,2002,2003,2004,2006,2007,2008,2009,2010,2011,2012,2013  Free Software Foundation, Inc.
- *
- *  GRUB is free software: you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation, either version 3 of the License, or
- *  (at your option) any later version.
- *
- *  GRUB is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <config-util.h>
-
-#include <grub/disk.h>
-#include <grub/partition.h>
-#include <grub/msdos_partition.h>
-#include <grub/types.h>
-#include <grub/err.h>
-#include <grub/emu/misc.h>
-#include <grub/emu/hostdisk.h>
-#include <grub/emu/getroot.h>
-#include <grub/misc.h>
-#include <grub/i18n.h>
-#include <grub/list.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <assert.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <limits.h>
-
-# include <sys/ioctl.h>
-# include <cygwin/fs.h> /* BLKGETSIZE64 */
-# include <cygwin/hdreg.h> /* HDIO_GETGEO */
-
-grub_int64_t
-grub_util_get_fd_size_os (int fd, const char *name, unsigned *log_secsize)
-{
-  unsigned long long nr;
-  unsigned sector_size, log_sector_size;
-
-  if (ioctl (fd, BLKGETSIZE64, &nr))
-    return -1;
-
-  if (ioctl (fd, BLKSSZGET, &sector_size))
-    return -1;
-
-  if (sector_size & (sector_size - 1) || !sector_size)
-    return -1;
-  for (log_sector_size = 0;
-       (1 << log_sector_size) < sector_size;
-       log_sector_size++);
-
-  if (log_secsize)
-    *log_secsize = log_sector_size;
-
-  if (nr & ((1 << log_sector_size) - 1))
-    grub_util_error ("%s", _("unaligned device size"));
-
-  return nr;
-}
-
-void
-grub_hostdisk_flush_initial_buffer (const char *os_dev __attribute__ ((unused)))
-{
-}
-
-void
-grub_hostdisk_configure_device_driver (int fd __attribute__ ((unused)))
-{
-}
index 72ff591372217212963f798d64dd777ef1a150b4..86d876c445386733db651f059fbb230f0a3101b8 100644 (file)
 # include <libgeom.h>
 
 void
-grub_hostdisk_configure_device_driver (int fd __attribute__ ((unused)))
+grub_hostdisk_configure_device_driver (grub_util_fd_t fd __attribute__ ((unused)))
 {
 }
 
 grub_int64_t
-grub_util_get_fd_size_os (int fd, const char *name, unsigned *log_secsize)
+grub_util_get_fd_size_os (grub_util_fd_t fd, const char *name, unsigned *log_secsize)
 {
   unsigned long long nr;
   unsigned sector_size, log_sector_size;
index 7a364ed2f0e9dd453a4cb5801827ea909c9b448b..36ce09a0cceb60a4a251744752966d239ff99610 100644 (file)
@@ -48,7 +48,7 @@
 #include <sys/mman.h>
 
 void
-grub_hostdisk_configure_device_driver (int fd __attribute__ ((unused)))
+grub_hostdisk_configure_device_driver (grub_util_fd_t fd __attribute__ ((unused)))
 {
 }
 
@@ -124,7 +124,7 @@ grub_util_hurd_get_disk_info (const char *dev, grub_uint32_t *secsize, grub_disk
 }
 
 grub_int64_t
-grub_util_get_fd_size_os (int fd, const char *name, unsigned *log_secsize)
+grub_util_get_fd_size_os (grub_util_fd_t fd, const char *name, unsigned *log_secsize)
 {
   grub_uint32_t sector_size;
   grub_disk_addr_t size;
index eef89ad427a231d478e8d89f7e12e82a9bdd61d9..fecc649e57a982f09be3ff626c25f473b701afca 100644 (file)
@@ -67,7 +67,7 @@ struct hd_geometry
 
 
 grub_int64_t
-grub_util_get_fd_size_os (int fd, const char *name, unsigned *log_secsize)
+grub_util_get_fd_size_os (grub_util_fd_t fd, const char *name, unsigned *log_secsize)
 {
   unsigned long long nr;
   unsigned sector_size, log_sector_size;
@@ -96,7 +96,7 @@ grub_util_get_fd_size_os (int fd, const char *name, unsigned *log_secsize)
 grub_disk_addr_t
 grub_util_find_partition_start_os (const char *dev)
 {
-  int fd;
+  grub_util_fd_t fd;
   struct hd_geometry hdg;
 
   fd = open (dev, O_RDONLY);
@@ -195,7 +195,7 @@ grub_hostdisk_linux_find_partition (char *dev, grub_disk_addr_t sector)
 
   for (i = 1; i < 10000; i++)
     {
-      int fd;
+      grub_util_fd_t fd;
       grub_disk_addr_t start;
 
       sprintf (p, format, i);
@@ -239,7 +239,7 @@ grub_hostdisk_linux_find_partition (char *dev, grub_disk_addr_t sector)
 void
 grub_hostdisk_flush_initial_buffer (const char *os_dev)
 {
-  int fd;
+  grub_util_fd_t fd;
   struct stat st;
 
   fd = open (os_dev, O_RDONLY);
@@ -249,7 +249,114 @@ grub_hostdisk_flush_initial_buffer (const char *os_dev)
     close (fd);
 }
 
-void
-grub_hostdisk_configure_device_driver (int fd __attribute__ ((unused)))
+int
+grub_util_fd_open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags,
+                         grub_disk_addr_t *max)
 {
+  grub_util_fd_t fd;
+  struct grub_util_hostdisk_data *data = disk->data;
+
+  *max = ~0ULL;
+
+#ifdef O_LARGEFILE
+  flags |= O_LARGEFILE;
+#endif
+#ifdef O_SYNC
+  flags |= O_SYNC;
+#endif
+#ifdef O_FSYNC
+  flags |= O_FSYNC;
+#endif
+#ifdef O_BINARY
+  flags |= O_BINARY;
+#endif
+
+  /* Linux has a bug that the disk cache for a whole disk is not consistent
+     with the one for a partition of the disk.  */
+  {
+    int is_partition = 0;
+    char dev[PATH_MAX];
+    grub_disk_addr_t part_start = 0;
+
+    part_start = grub_partition_get_start (disk->partition);
+
+    strcpy (dev, grub_util_biosdisk_get_osdev (disk));
+    if (disk->partition
+       && strncmp (dev, "/dev/", 5) == 0)
+      {
+       if (sector >= part_start)
+         is_partition = grub_hostdisk_linux_find_partition (dev, part_start);
+       else
+         *max = part_start - sector;
+      }
+
+  reopen:
+
+    if (data->dev && strcmp (data->dev, dev) == 0 &&
+       data->access_mode == (flags & O_ACCMODE))
+      {
+       grub_dprintf ("hostdisk", "reusing open device `%s'\n", dev);
+       fd = data->fd;
+      }
+    else
+      {
+       free (data->dev);
+       data->dev = 0;
+       if (data->fd != -1)
+         {
+           if (data->access_mode == O_RDWR || data->access_mode == O_WRONLY)
+             {
+               fsync (data->fd);
+               if (data->is_disk)
+                 ioctl (data->fd, BLKFLSBUF, 0);
+             }
+
+           close (data->fd);
+           data->fd = -1;
+         }
+
+       /* Open the partition.  */
+       grub_dprintf ("hostdisk", "opening the device `%s' in open_device()\n", dev);
+       fd = open (dev, flags);
+       if (fd < 0)
+         {
+           grub_error (GRUB_ERR_BAD_DEVICE, N_("cannot open `%s': %s"),
+                       dev, strerror (errno));
+           return -1;
+         }
+
+       data->dev = xstrdup (dev);
+       data->access_mode = (flags & O_ACCMODE);
+       data->fd = fd;
+
+       if (data->is_disk)
+         ioctl (data->fd, BLKFLSBUF, 0);
+      }
+
+    if (is_partition)
+      {
+       *max = grub_util_get_fd_size (fd, dev, 0);
+       *max >>= disk->log_sector_size;
+       if (sector - part_start >= *max)
+         {
+           *max = disk->partition->len - (sector - part_start);
+           if (*max == 0)
+             *max = ~0ULL;
+           is_partition = 0;
+           strcpy (dev, grub_util_biosdisk_get_osdev (disk));
+           goto reopen;
+         }
+       sector -= part_start;
+       *max -= sector;
+      }
+  }
+
+  if (grub_util_fd_seek (fd, grub_util_biosdisk_get_osdev (disk),
+                        sector << disk->log_sector_size))
+    {
+      close (fd);
+      return -1;
+    }
+
+  return fd;
 }
diff --git a/grub-core/kern/emu/hostdisk_mingw.c b/grub-core/kern/emu/hostdisk_mingw.c
deleted file mode 100644 (file)
index eceb5d4..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- *  GRUB  --  GRand Unified Bootloader
- *  Copyright (C) 1999,2000,2001,2002,2003,2004,2006,2007,2008,2009,2010,2011,2012,2013  Free Software Foundation, Inc.
- *
- *  GRUB is free software: you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation, either version 3 of the License, or
- *  (at your option) any later version.
- *
- *  GRUB is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <config-util.h>
-
-#include <grub/disk.h>
-#include <grub/partition.h>
-#include <grub/msdos_partition.h>
-#include <grub/types.h>
-#include <grub/err.h>
-#include <grub/emu/misc.h>
-#include <grub/emu/hostdisk.h>
-#include <grub/emu/getroot.h>
-#include <grub/misc.h>
-#include <grub/i18n.h>
-#include <grub/list.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <assert.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <limits.h>
-
-#include <windows.h>
-#include <winioctl.h>
-#include "dirname.h"
-
-grub_int64_t
-grub_util_get_fd_size_os (int fd __attribute__ ((unused)),
-                         const char *name_in,
-                         unsigned *log_secsize)
-{
-  HANDLE hd;
-  grub_int64_t size = -1LL;
-  int log_sector_size = 9;
-  char *name = xstrdup (name_in);
-
-  if (log_secsize)
-    *log_secsize = log_sector_size;
-
-  strip_trailing_slashes(name);
-  hd = CreateFile (name, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
-                   0, OPEN_EXISTING, 0, 0);
-
-  if (hd == INVALID_HANDLE_VALUE)
-    {
-      free (name);
-      return size;
-    }
-
-  if (((name[0] == '/') || (name[0] == '\\')) &&
-      ((name[1] == '/') || (name[1] == '\\')) &&
-      (name[2] == '.') &&
-      ((name[3] == '/') || (name[3] == '\\')) &&
-      (! strncasecmp (name + 4, "PHYSICALDRIVE", 13)))
-    {
-      DWORD nr;
-      DISK_GEOMETRY g;
-
-      if (! DeviceIoControl (hd, IOCTL_DISK_GET_DRIVE_GEOMETRY,
-                             0, 0, &g, sizeof (g), &nr, 0))
-        goto fail;
-
-      size = g.Cylinders.QuadPart;
-      size *= g.TracksPerCylinder * g.SectorsPerTrack * g.BytesPerSector;
-
-      for (log_sector_size = 0;
-          (1 << log_sector_size) < g.BytesPerSector;
-          log_sector_size++);
-    }
-  else
-    {
-      ULARGE_INTEGER s;
-
-      s.LowPart = GetFileSize (hd, &s.HighPart);
-      size = s.QuadPart;
-    }
-
- fail:
-
-  if (log_secsize)
-    *log_secsize = log_sector_size;
-
-  free (name);
-
-  CloseHandle (hd);
-
-  return size;
-}
-
-void
-grub_hostdisk_configure_device_driver (int fd __attribute__ ((unused)))
-{
-}
-
-void
-grub_hostdisk_flush_initial_buffer (const char *os_dev __attribute__ ((unused)))
-{
-}
index c21b76439c92d43bc03912c9447bc64ec8e31ed9..1957510e2e72ec9d3ec4b6b75159fb847b4d3d3a 100644 (file)
 #include "hostdisk_sun.c"
 #elif defined(__GNU__)
 #include "hostdisk_hurd.c"
-#elif defined(__CYGWIN__)
-#include "hostdisk_cygwin.c"
-#elif defined(__MINGW32__)
-#include "hostdisk_mingw.c"
+#elif defined(__CYGWIN__) || defined(__MINGW32__)
+#include "hostdisk_windows.c"
 #else
 # warning "No hostdisk OS-specific functions is available for your system. Device detection may not work properly."
 #include "hostdisk_basic.c"
index 0232fa253fb64e71629b5d79bd68ffdeeb375334..fa691a0c99b5c8eac79681b606068a63ffa9a5b8 100644 (file)
@@ -45,7 +45,7 @@
 # include <sys/dkio.h>
 
 grub_int64_t
-grub_util_get_fd_size_os (int fd, const char *name, unsigned *log_secsize)
+grub_util_get_fd_size_os (grub_util_fd_t fd, const char *name, unsigned *log_secsize)
 {
   struct dk_minfo minfo;
   unsigned sector_size, log_sector_size;
@@ -68,7 +68,7 @@ grub_util_get_fd_size_os (int fd, const char *name, unsigned *log_secsize)
 }
 
 void
-grub_hostdisk_configure_device_driver (int fd __attribute__ ((unused)))
+grub_hostdisk_configure_device_driver (grub_util_fd_t fd __attribute__ ((unused)))
 {
 }
 
diff --git a/grub-core/kern/emu/hostdisk_unix.c b/grub-core/kern/emu/hostdisk_unix.c
new file mode 100644 (file)
index 0000000..fcadbe3
--- /dev/null
@@ -0,0 +1,169 @@
+/* hostdisk.c - emulate biosdisk */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 1999,2000,2001,2002,2003,2004,2006,2007,2008,2009,2010,2011,2012,2013  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config-util.h>
+
+#include <grub/disk.h>
+#include <grub/partition.h>
+#include <grub/msdos_partition.h>
+#include <grub/types.h>
+#include <grub/err.h>
+#include <grub/emu/misc.h>
+#include <grub/emu/hostdisk.h>
+#include <grub/emu/getroot.h>
+#include <grub/misc.h>
+#include <grub/i18n.h>
+#include <grub/list.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+
+#if !defined (__CYGWIN__) && !defined (__MINGW32__)
+
+#ifdef __linux__
+# include <sys/ioctl.h>         /* ioctl */
+# include <sys/mount.h>
+# if !defined(__GLIBC__) || \
+        ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1)))
+/* Maybe libc doesn't have large file support.  */
+#  include <linux/unistd.h>     /* _llseek */
+# endif /* (GLIBC < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR < 1)) */
+# ifndef BLKFLSBUF
+#  define BLKFLSBUF     _IO (0x12,97)   /* flush buffer cache */
+# endif /* ! BLKFLSBUF */
+#endif /* __linux__ */
+
+grub_uint64_t
+grub_util_get_fd_size (grub_util_fd_t fd, const char *name, unsigned *log_secsize)
+{
+  struct stat st;
+  grub_int64_t ret = -1;
+
+  if (fstat (fd, &st) < 0)
+    /* TRANSLATORS: "stat" comes from the name of POSIX function.  */
+    grub_util_error (_("cannot stat `%s': %s"), name, strerror (errno));
+#if GRUB_DISK_DEVS_ARE_CHAR
+  if (S_ISCHR (st.st_mode))
+#else
+  if (S_ISBLK (st.st_mode))
+#endif
+    ret = grub_util_get_fd_size_os (fd, name, log_secsize);
+  if (ret != -1LL)
+    return ret;
+
+  if (log_secsize)
+    *log_secsize = 9;
+
+  return st.st_size;
+}
+
+#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_seek (grub_util_fd_t fd, const char *name, grub_uint64_t off)
+{
+  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) off;
+  if (_llseek (fd, offset >> 32, offset & 0xffffffff, &result, SEEK_SET))
+    return grub_error (GRUB_ERR_BAD_DEVICE, N_("cannot seek `%s': %s"),
+                      name, strerror (errno));
+  return GRUB_ERR_NONE;
+}
+#else
+grub_err_t
+grub_util_fd_seek (grub_util_fd_t fd, const char *name, grub_uint64_t off)
+{
+  off_t offset = (off_t) off;
+
+  if (lseek (fd, offset, SEEK_SET) != offset)
+    return grub_error (GRUB_ERR_BAD_DEVICE, N_("cannot seek `%s': %s"),
+                      name, strerror (errno));
+  return 0;
+}
+#endif
+
+
+/* Read LEN bytes from FD in BUF. Return less than or equal to zero if an
+   error occurs, otherwise return LEN.  */
+ssize_t
+grub_util_fd_read (grub_util_fd_t fd, char *buf, size_t len)
+{
+  ssize_t size = len;
+
+  while (len)
+    {
+      ssize_t ret = read (fd, buf, len);
+
+      if (ret <= 0)
+        {
+          if (errno == EINTR)
+            continue;
+          else
+            return ret;
+        }
+
+      len -= ret;
+      buf += ret;
+    }
+
+  return size;
+}
+
+/* Write LEN bytes from BUF to FD. Return less than or equal to zero if an
+   error occurs, otherwise return LEN.  */
+ssize_t
+grub_util_fd_write (grub_util_fd_t fd, const char *buf, size_t len)
+{
+  ssize_t size = len;
+
+  while (len)
+    {
+      ssize_t ret = write (fd, buf, len);
+
+      if (ret <= 0)
+        {
+          if (errno == EINTR)
+            continue;
+          else
+            return ret;
+        }
+
+      len -= ret;
+      buf += ret;
+    }
+
+  return size;
+}
+
+#endif
diff --git a/grub-core/kern/emu/hostdisk_windows.c b/grub-core/kern/emu/hostdisk_windows.c
new file mode 100644 (file)
index 0000000..4ebb2f3
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 1999,2000,2001,2002,2003,2004,2006,2007,2008,2009,2010,2011,2012,2013  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config-util.h>
+
+#include <grub/disk.h>
+#include <grub/partition.h>
+#include <grub/msdos_partition.h>
+#include <grub/types.h>
+#include <grub/err.h>
+#include <grub/emu/misc.h>
+#include <grub/emu/hostdisk.h>
+#include <grub/emu/getroot.h>
+#include <grub/misc.h>
+#include <grub/i18n.h>
+#include <grub/list.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+
+#include <grub/util/windows.h>
+#include <grub/charset.h>
+
+#include <windows.h>
+#include <winioctl.h>
+
+#ifdef __CYGWIN__
+LPTSTR
+grub_util_get_windows_path (const char *path)
+{
+  LPTSTR winpath;
+  winpath = xmalloc (sizeof (winpath[0]) * PATH_MAX);
+  if (cygwin_conv_path (sizeof (winpath[0]) == 1 ? CCP_POSIX_TO_WIN_A
+                       : CCP_POSIX_TO_WIN_W, path, winpath,
+                       sizeof (winpath[0]) * PATH_MAX))
+    grub_util_error ("%s", _("cygwin_conv_path() failed"));
+  return winpath;
+}
+#else
+LPTSTR
+grub_util_get_windows_path (const char *path)
+{
+#if SIZEOF_TCHAR == 1
+  return xstrdup (path);
+#elif SIZEOF_TCHAR == 2
+  size_t ssz = strlen (path);
+  size_t tsz = 2 * (GRUB_MAX_UTF16_PER_UTF8 * ssz + 1);
+  LPTSTR ret = xmalloc (tsz);
+  tsz = grub_utf8_to_utf16 (ret, tsz, (const grub_uint8_t *) path, ssz, NULL);
+  ret[tsz] = 0;
+  return ret;
+#else
+#error SIZEOF_TCHAR
+#error "Unsupported TCHAR size"
+#endif
+}
+#endif
+
+grub_uint64_t
+grub_util_get_fd_size (grub_util_fd_t hd, const char *name_in,
+                      unsigned *log_secsize)
+{
+  grub_int64_t size = -1LL;
+  int log_sector_size = 9;
+  LPTSTR name = grub_util_get_windows_path (name_in);
+
+  if (log_secsize)
+    *log_secsize = log_sector_size;
+
+  if (((name[0] == '/') || (name[0] == '\\')) &&
+      ((name[1] == '/') || (name[1] == '\\')) &&
+      ((name[2] == '.') || (name[2] == '?')) &&
+      ((name[3] == '/') || (name[3] == '\\')))
+    {
+      DWORD nr;
+      DISK_GEOMETRY g;
+
+      if (! DeviceIoControl (hd, IOCTL_DISK_GET_DRIVE_GEOMETRY,
+                             0, 0, &g, sizeof (g), &nr, 0))
+        goto fail;
+
+      size = g.Cylinders.QuadPart;
+      size *= g.TracksPerCylinder * g.SectorsPerTrack * g.BytesPerSector;
+
+      for (log_sector_size = 0;
+          (1 << log_sector_size) < g.BytesPerSector;
+          log_sector_size++);
+    }
+  else
+    {
+      ULARGE_INTEGER s;
+
+      s.LowPart = GetFileSize (hd, &s.HighPart);
+      size = s.QuadPart;
+    }
+
+ fail:
+
+  if (log_secsize)
+    *log_secsize = log_sector_size;
+
+  free (name);
+
+  return size;
+}
+
+void
+grub_hostdisk_configure_device_driver (grub_util_fd_t fd __attribute__ ((unused)))
+{
+}
+
+void
+grub_hostdisk_flush_initial_buffer (const char *os_dev __attribute__ ((unused)))
+{
+}
+
+grub_err_t
+grub_util_fd_seek (grub_util_fd_t fd, const char *name, grub_uint64_t off)
+{
+  LARGE_INTEGER offset;
+  offset.QuadPart = off;
+
+  if (!SetFilePointerEx (fd, offset, NULL, FILE_BEGIN))
+    return grub_error (GRUB_ERR_BAD_DEVICE, N_("cannot seek `%s': %s"),
+                      name, strerror (errno));
+  return 0;
+}
+
+grub_util_fd_t
+grub_util_fd_open (const char *os_dev, int flags)
+{
+  DWORD flg = 0;
+  LPTSTR dev = grub_util_get_windows_path (os_dev);
+  grub_util_fd_t ret;
+
+  if (flags & O_WRONLY)
+    flg |= GENERIC_WRITE;
+  if (flags & O_RDONLY)
+    flg |= GENERIC_READ;
+  flg = GENERIC_READ;
+  ret = CreateFile (dev, flg, FILE_SHARE_READ | FILE_SHARE_WRITE,
+                   0, OPEN_EXISTING, 0, 0);
+  free (dev);
+  grub_util_info ("handle = %p", ret);
+  return ret;
+}
+
+ssize_t
+grub_util_fd_read (grub_util_fd_t fd, char *buf, size_t len)
+{
+  DWORD real_read;
+  if (!ReadFile(fd, buf, len, &real_read, NULL))
+    {
+      grub_util_info ("read err %x", (int) GetLastError ());
+      return -1;
+    }
+  grub_util_info ("successful read");
+  return real_read;
+}
+
+ssize_t
+grub_util_fd_write (grub_util_fd_t fd, const char *buf, size_t len)
+{
+  DWORD real_read;
+  if (!WriteFile(fd, buf, len, &real_read, NULL))
+    {
+      grub_util_info ("write err %x", (int) GetLastError ());
+      return -1;
+    }
+
+  grub_util_info ("successful write");
+  return real_read;
+}
index 727f7becea587dd1b8b7e747afc522ef7afa05e1..ba309489f315864f3946dac4255843063d87002b 100644 (file)
@@ -132,7 +132,13 @@ grub_hostfs_open (struct grub_file *file, const char *name)
 
   file->data = data;
 
+#if defined (__CYGWIN__) || defined (__MINGW32__)
+  fseek (f, 0, SEEK_END);
+  file->size = ftello (f);
+  fseek (f, 0, SEEK_SET);
+#else
   file->size = grub_util_get_fd_size (fileno (f), name, NULL);
+#endif
 
   return GRUB_ERR_NONE;
 }
index 99ef90ce1e83c91655d0465da9c03984566d9c19..eea57f9ef1fc7201184d91413c1b316d8d2b8a16 100644 (file)
@@ -234,7 +234,7 @@ main (int argc, char *argv[])
   return 0;
 }
 
-#ifdef __MINGW32__
+#if defined (__MINGW32__) || defined (__CYGWIN__)
 
 void
 grub_millisleep (grub_uint32_t ms)
index e4b903fa6816528086f5fa973ef4c5cbe8100908..bbba7308cec423068e4e1390bae935f20f0fb3d7 100644 (file)
@@ -75,10 +75,12 @@ char *
 grub_util_get_devmapper_grub_dev (const char *os_dev);
 
 /* Functions provided by getroot.c.  */
-#if !defined (__MINGW32__) && !defined (__CYGWIN__) && !defined (__GNU__)
+#if !defined (__MINGW32__) && !defined (__CYGWIN__)
 #include <sys/types.h>
 pid_t
 grub_util_exec_pipe (char **argv, int *fd);
+void
+grub_util_pull_lvm_by_command (const char *os_dev);
 #endif
 char **
 grub_util_find_root_devices_from_poolname (char *poolname);
index fd882dfad0bf1f395d8a2697f18c1cca8b0d328b..ef27c6d7a02ebcc4f4f2c40f827999b0fd954b41 100644 (file)
 #include <grub/partition.h>
 #include <sys/types.h>
 
+#if defined (__CYGWIN__) || defined (__MINGW32__)
+#include <windows.h>
+typedef HANDLE grub_util_fd_t;
+#define GRUB_UTIL_FD_INVALID INVALID_HANDLE_VALUE
+#define GRUB_UTIL_FD_IS_VALID(x) ((x) != GRUB_UTIL_FD_INVALID)
+#define grub_util_fd_close(x) CloseHandle(x)
+#define grub_util_fd_sync(x) FlushFileBuffers(x)
+grub_util_fd_t
+grub_util_fd_open (const char *os_dev, int flags);
+#else
+typedef int grub_util_fd_t;
+#define GRUB_UTIL_FD_INVALID -1
+#define GRUB_UTIL_FD_IS_VALID(x) ((x) >= 0)
+#define grub_util_fd_close(x) close(x)
+#define grub_util_fd_sync(x) fsync(x)
+#define grub_util_fd_open(x,y) open(x,y)
+#endif
+
+grub_util_fd_t
+grub_util_fd_open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags,
+                         grub_disk_addr_t *max);
+
 void grub_util_biosdisk_init (const char *dev_map);
 void grub_util_biosdisk_fini (void);
 char *grub_util_biosdisk_get_grub_dev (const char *os_dev);
@@ -34,9 +56,9 @@ const char *
 grub_util_biosdisk_get_compatibility_hint (grub_disk_t disk);
 grub_err_t grub_util_biosdisk_flush (struct grub_disk *disk);
 grub_err_t
-grub_util_fd_seek (int fd, const char *name, grub_uint64_t sector);
-ssize_t grub_util_fd_read (int fd, char *buf, size_t len);
-ssize_t grub_util_fd_write (int fd, const char *buf, size_t len);
+grub_util_fd_seek (grub_util_fd_t fd, const char *name, grub_uint64_t sector);
+ssize_t grub_util_fd_read (grub_util_fd_t fd, char *buf, size_t len);
+ssize_t grub_util_fd_write (grub_util_fd_t fd, const char *buf, size_t len);
 grub_err_t
 grub_cryptodisk_cheat_mount (const char *sourcedev, const char *cheat);
 void grub_util_cryptodisk_print_uuid (grub_disk_t disk);
@@ -55,7 +77,7 @@ const char *
 grub_hostdisk_os_dev_to_grub_drive (const char *os_dev, int add);
 
 grub_uint64_t
-grub_util_get_fd_size (int fd, const char *name, unsigned *log_secsize);
+grub_util_get_fd_size (grub_util_fd_t fd, const char *name, unsigned *log_secsize);
 
 char *
 grub_util_get_os_disk (const char *os_dev);
@@ -73,7 +95,7 @@ grub_util_get_dm_node_linear_info (const char *dev,
 
 /* Supplied by hostdisk_*.c.  */
 grub_int64_t
-grub_util_get_fd_size_os (int fd, const char *name, unsigned *log_secsize);
+grub_util_get_fd_size_os (grub_util_fd_t fd, const char *name, unsigned *log_secsize);
 /* REturns partition offset in 512B blocks.  */
 grub_disk_addr_t
 grub_hostdisk_find_partition_start_os (const char *dev);
@@ -84,7 +106,7 @@ grub_hostdisk_find_partition_start_os (const char *dev);
    For now it's non-nop only on NetBSD.
 */
 void
-grub_hostdisk_configure_device_driver (int fd);
+grub_hostdisk_configure_device_driver (grub_util_fd_t fd);
 void
 grub_hostdisk_flush_initial_buffer (const char *os_dev);
 
@@ -94,11 +116,13 @@ grub_hostdisk_flush_initial_buffer (const char *os_dev);
 #define GRUB_DISK_DEVS_ARE_CHAR 0
 #endif
 
-#ifdef __GNU__
-int
-grub_util_hurd_get_disk_info (const char *dev, grub_uint32_t *secsize,
-                             grub_disk_addr_t *offset,
-                             grub_disk_addr_t *size, char **parent);
-#endif
+struct grub_util_hostdisk_data
+{
+  char *dev;
+  int access_mode;
+  grub_util_fd_t fd;
+  int is_disk;
+  int device_map;
+};
 
 #endif /* ! GRUB_BIOSDISK_MACHINE_UTIL_HEADER */
diff --git a/include/grub/util/windows.h b/include/grub/util/windows.h
new file mode 100644 (file)
index 0000000..2645fcc
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2013  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_WINDOWS_UTIL_HEADER
+#define GRUB_WINDOWS_UTIL_HEADER       1
+
+#include <windows.h>
+
+LPTSTR
+grub_util_get_windows_path (const char *unix_path);
+
+char *
+grub_util_tchar_to_utf8 (LPCTSTR in);
+
+#endif
index eab6f24df220db61b6f914db8d14ad07f7fd946b..8673ede5f92c0e704dcc7437724bed63e7eccdb4 100644 (file)
 #endif /* ! FLOPPY_MAJOR */
 #endif
 
-#ifdef __GNU__
-#include <hurd.h>
-#include <hurd/lookup.h>
-#include <hurd/fs.h>
-#include <sys/mman.h>
-#endif
-
 #include <sys/types.h>
 
 #if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR)
 #include <grub/emu/hostdisk.h>
 #include <grub/emu/getroot.h>
 
-#ifdef __CYGWIN__
-# include <sys/ioctl.h>
-# include <cygwin/fs.h> /* BLKGETSIZE64 */
-# include <cygwin/hdreg.h> /* HDIO_GETGEO */
-# include <sys/cygwin.h>
-
-# define MAJOR(dev)    ((unsigned) ((dev) >> 16))
-# define FLOPPY_MAJOR  2
-#endif
-
 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
 # define MAJOR(dev) major(dev)
 # define FLOPPY_MAJOR  2
 # endif /* ! RAW_FLOPPY_MAJOR */
 #endif /* defined(__NetBSD__) */
 
-#if !defined (__MINGW32__) && !defined (__CYGWIN__)
-
-static void
-pull_lvm_by_command (const char *os_dev);
-#endif
-
-#if ! defined(__CYGWIN__)
-
-static void
-strip_extra_slashes (char *dir)
-{
-  char *p = dir;
-
-  while ((p = strchr (p, '/')) != 0)
-    {
-      if (p[1] == '/')
-       {
-         memmove (p, p + 1, strlen (p));
-         continue;
-       }
-      else if (p[1] == '\0')
-       {
-         if (p > dir)
-           p[0] = '\0';
-         break;
-       }
-
-      p++;
-    }
-}
-
-static char *
-xgetcwd (void)
-{
-  size_t size = 10;
-  char *path;
-
-  path = xmalloc (size);
-  while (! getcwd (path, size))
-    {
-      size <<= 1;
-      path = xrealloc (path, size);
-    }
-
-  return path;
-}
-
-#endif
-
-#if !defined (__MINGW32__) && !defined (__CYGWIN__)
-
-#include <sys/types.h>
-#include <sys/wait.h>
-
-pid_t
-grub_util_exec_pipe (char **argv, int *fd)
-{
-  int mdadm_pipe[2];
-  pid_t mdadm_pid;
-
-  *fd = 0;
-
-  if (pipe (mdadm_pipe) < 0)
-    {
-      grub_util_warn (_("Unable to create pipe: %s"),
-                     strerror (errno));
-      return 0;
-    }
-  mdadm_pid = fork ();
-  if (mdadm_pid < 0)
-    grub_util_error (_("Unable to fork: %s"), strerror (errno));
-  else if (mdadm_pid == 0)
-    {
-      /* Child.  */
-
-      /* Close fd's.  */
-      grub_util_devmapper_cleanup ();
-      grub_diskfilter_fini ();
-
-      /* Ensure child is not localised.  */
-      setenv ("LC_ALL", "C", 1);
-
-      close (mdadm_pipe[0]);
-      dup2 (mdadm_pipe[1], STDOUT_FILENO);
-      close (mdadm_pipe[1]);
-
-      execvp (argv[0], argv);
-      exit (127);
-    }
-  else
-    {
-      close (mdadm_pipe[1]);
-      *fd = mdadm_pipe[0];
-      return mdadm_pid;
-    }
-}
-
-#endif
-
-#if !defined (__CYGWIN__) && !defined(__MINGW32__) && !defined (__GNU__)
-char **
-grub_util_find_root_devices_from_poolname (char *poolname)
-{
-  char **devices = 0;
-  size_t ndevices = 0;
-  size_t devices_allocated = 0;
-
-#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR)
-  zpool_handle_t *zpool;
-  libzfs_handle_t *libzfs;
-  nvlist_t *config, *vdev_tree;
-  nvlist_t **children;
-  unsigned int nvlist_count;
-  unsigned int i;
-  char *device = 0;
-
-  libzfs = grub_get_libzfs_handle ();
-  if (! libzfs)
-    return NULL;
-
-  zpool = zpool_open (libzfs, poolname);
-  config = zpool_get_config (zpool, NULL);
-
-  if (nvlist_lookup_nvlist (config, "vdev_tree", &vdev_tree) != 0)
-    error (1, errno, "nvlist_lookup_nvlist (\"vdev_tree\")");
-
-  if (nvlist_lookup_nvlist_array (vdev_tree, "children", &children, &nvlist_count) != 0)
-    error (1, errno, "nvlist_lookup_nvlist_array (\"children\")");
-  assert (nvlist_count > 0);
-
-  while (nvlist_lookup_nvlist_array (children[0], "children",
-                                    &children, &nvlist_count) == 0)
-    assert (nvlist_count > 0);
-
-  for (i = 0; i < nvlist_count; i++)
-    {
-      if (nvlist_lookup_string (children[i], "path", &device) != 0)
-       error (1, errno, "nvlist_lookup_string (\"path\")");
-
-      struct stat st;
-      if (stat (device, &st) == 0)
-       {
-#ifdef __sun__
-         if (grub_memcmp (device, "/dev/dsk/", sizeof ("/dev/dsk/") - 1)
-             == 0)
-           device = xasprintf ("/dev/rdsk/%s",
-                               device + sizeof ("/dev/dsk/") - 1);
-         else if (grub_memcmp (device, "/devices", sizeof ("/devices") - 1)
-                  == 0
-                  && grub_memcmp (device + strlen (device) - 4,
-                                  ",raw", 4) != 0)
-           device = xasprintf ("%s,raw", device);
-         else
-#endif
-           device = xstrdup (device);
-         if (ndevices >= devices_allocated)
-           {
-             devices_allocated = 2 * (devices_allocated + 8);
-             devices = xrealloc (devices, sizeof (devices[0])
-                                 * devices_allocated);
-           }
-         devices[ndevices++] = device;
-       }
-
-      device = NULL;
-    }
-
-  zpool_close (zpool);
-#else
-  FILE *fp;
-  int ret;
-  char *line;
-  size_t len;
-  int st;
-
-  char name[PATH_MAX + 1], state[257], readlen[257], writelen[257];
-  char cksum[257], notes[257];
-  unsigned int dummy;
-  char *argv[4];
-  pid_t pid;
-  int fd;
-
-  /* execvp has inconvenient types, hence the casts.  None of these
-     strings will actually be modified.  */
-  argv[0] = (char *) "zpool";
-  argv[1] = (char *) "status";
-  argv[2] = (char *) poolname;
-  argv[3] = NULL;
-
-  pid = grub_util_exec_pipe (argv, &fd);
-  if (!pid)
-    return NULL;
-
-  fp = fdopen (fd, "r");
-  if (!fp)
-    {
-      grub_util_warn (_("Unable to open stream from %s: %s"),
-                     "zpool", strerror (errno));
-      goto out;
-    }
-
-  st = 0;
-  while (1)
-    {
-      line = NULL;
-      ret = getline (&line, &len, fp);
-      if (ret == -1)
-       break;
-       
-      if (sscanf (line, " %s %256s %256s %256s %256s %256s",
-                 name, state, readlen, writelen, cksum, notes) >= 5)
-       switch (st)
-         {
-         case 0:
-           if (!strcmp (name, "NAME")
-               && !strcmp (state, "STATE")
-               && !strcmp (readlen, "READ")
-               && !strcmp (writelen, "WRITE")
-               && !strcmp (cksum, "CKSUM"))
-             st++;
-           break;
-         case 1:
-           {
-             char *ptr = line;
-             while (1)
-               {
-                 if (strncmp (ptr, poolname, strlen (poolname)) == 0
-                     && grub_isspace(ptr[strlen (poolname)]))
-                   st++;
-                 if (!grub_isspace (*ptr))
-                   break;
-                 ptr++;
-               }
-           }
-           break;
-         case 2:
-           if (strcmp (name, "mirror") && !sscanf (name, "mirror-%u", &dummy)
-               && !sscanf (name, "raidz%u", &dummy)
-               && !sscanf (name, "raidz1%u", &dummy)
-               && !sscanf (name, "raidz2%u", &dummy)
-               && !sscanf (name, "raidz3%u", &dummy)
-               && !strcmp (state, "ONLINE"))
-             {
-               if (ndevices >= devices_allocated)
-                 {
-                   devices_allocated = 2 * (devices_allocated + 8);
-                   devices = xrealloc (devices, sizeof (devices[0])
-                                       * devices_allocated);
-                 }
-               if (name[0] == '/')
-                 devices[ndevices++] = xstrdup (name);
-               else
-                 devices[ndevices++] = xasprintf ("/dev/%s", name);
-             }
-           break;
-         }
-       
-      free (line);
-    }
-
- out:
-  close (fd);
-  waitpid (pid, NULL, 0);
-#endif
-  if (devices)
-    {
-      if (ndevices >= devices_allocated)
-       {
-         devices_allocated = 2 * (devices_allocated + 8);
-         devices = xrealloc (devices, sizeof (devices[0])
-                             * devices_allocated);
-       }
-      devices[ndevices++] = 0;
-    }
-  return devices;
-}
-
-#endif
-
-#if !defined (__MINGW32__) && !defined (__CYGWIN__) && !defined (__GNU__)
-
-static char **
-find_root_devices_from_libzfs (const char *dir)
-{
-  char **devices = NULL;
-  char *poolname;
-  char *poolfs;
-
-  grub_find_zpool_from_dir (dir, &poolname, &poolfs);
-  if (! poolname)
-    return NULL;
-
-  devices = grub_util_find_root_devices_from_poolname (poolname);
-
-  free (poolname);
-  if (poolfs)
-    free (poolfs);
-
-  return devices;
-}
-
-#endif
-
-#ifdef __MINGW32__
-
-char *
-grub_find_device (const char *dir __attribute__ ((unused)),
-                  dev_t dev __attribute__ ((unused)))
-{
-  return 0;
-}
-
-#elif ! defined(__CYGWIN__)
-
-char *
-grub_find_device (const char *dir, dev_t dev)
-{
-  DIR *dp;
-  char *saved_cwd;
-  struct dirent *ent;
-
-  if (! dir)
-    {
-#ifdef __CYGWIN__
-      return NULL;
-#else
-      dir = "/dev";
-#endif
-    }
-
-  dp = opendir (dir);
-  if (! dp)
-    return 0;
-
-  saved_cwd = xgetcwd ();
-
-  grub_util_info ("changing current directory to %s", dir);
-  if (chdir (dir) < 0)
-    {
-      free (saved_cwd);
-      closedir (dp);
-      return 0;
-    }
-
-  while ((ent = readdir (dp)) != 0)
-    {
-      struct stat st;
-
-      /* Avoid:
-        - dotfiles (like "/dev/.tmp.md0") since they could be duplicates.
-        - dotdirs (like "/dev/.static") since they could contain duplicates.  */
-      if (ent->d_name[0] == '.')
-       continue;
-
-      if (lstat (ent->d_name, &st) < 0)
-       /* Ignore any error.  */
-       continue;
-
-      if (S_ISLNK (st.st_mode)) {
-#ifdef __linux__
-       if (strcmp (dir, "mapper") == 0 || strcmp (dir, "/dev/mapper") == 0) {
-         /* Follow symbolic links under /dev/mapper/; the canonical name
-            may be something like /dev/dm-0, but the names under
-            /dev/mapper/ are more human-readable and so we prefer them if
-            we can get them.  */
-         if (stat (ent->d_name, &st) < 0)
-           continue;
-       } else
-#endif /* __linux__ */
-       /* Don't follow other symbolic links.  */
-       continue;
-      }
-
-      if (S_ISDIR (st.st_mode))
-       {
-         /* Find it recursively.  */
-         char *res;
-
-         res = grub_find_device (ent->d_name, dev);
-
-         if (res)
-           {
-             if (chdir (saved_cwd) < 0)
-               grub_util_error ("%s",
-                                _("cannot restore the original directory"));
-
-             free (saved_cwd);
-             closedir (dp);
-             return res;
-           }
-       }
-
-#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__)
-      if (S_ISCHR (st.st_mode) && st.st_rdev == dev)
-#else
-      if (S_ISBLK (st.st_mode) && st.st_rdev == dev)
-#endif
-       {
-#ifdef __linux__
-         /* Skip device names like /dev/dm-0, which are short-hand aliases
-            to more descriptive device names, e.g. those under /dev/mapper */
-         if (ent->d_name[0] == 'd' &&
-             ent->d_name[1] == 'm' &&
-             ent->d_name[2] == '-' &&
-             ent->d_name[3] >= '0' &&
-             ent->d_name[3] <= '9')
-           continue;
-#endif
-
-         /* Found!  */
-         char *res;
-         char *cwd;
-#if defined(__NetBSD__) || defined(__OpenBSD__)
-         /* Convert this block device to its character (raw) device.  */
-         const char *template = "%s/r%s";
-#else
-         /* Keep the device name as it is.  */
-         const char *template = "%s/%s";
-#endif
-
-         cwd = xgetcwd ();
-         res = xmalloc (strlen (cwd) + strlen (ent->d_name) + 3);
-         sprintf (res, template, cwd, ent->d_name);
-         strip_extra_slashes (res);
-         free (cwd);
-
-         /* /dev/root is not a real block device keep looking, takes care
-            of situation where root filesystem is on the same partition as
-            grub files */
-
-         if (strcmp(res, "/dev/root") == 0)
-           {
-             free (res);
-             continue;
-           }
-
-         if (chdir (saved_cwd) < 0)
-           grub_util_error ("%s", _("cannot restore the original directory"));
-
-         free (saved_cwd);
-         closedir (dp);
-         return res;
-       }
-    }
-
-  if (chdir (saved_cwd) < 0)
-    grub_util_error ("%s", _("cannot restore the original directory"));
-
-  free (saved_cwd);
-  closedir (dp);
-  return 0;
-}
-
-#else /* __CYGWIN__ */
-
-/* Read drive/partition serial number from mbr/boot sector,
-   return 0 on read error, ~0 on unknown serial.  */
-static unsigned
-get_bootsec_serial (const char *os_dev, int mbr)
-{
-  /* Read boot sector.  */
-  int fd = open (os_dev, O_RDONLY);
-  if (fd < 0)
-    return 0;
-  unsigned char buf[0x200];
-  int n = read (fd, buf, sizeof (buf));
-  close (fd);
-  if (n != sizeof(buf))
-    return 0;
-
-  /* Check signature.  */
-  if (!(buf[0x1fe] == 0x55 && buf[0x1ff] == 0xaa))
-    return ~0;
-
-  /* Serial number offset depends on boot sector type.  */
-  if (mbr)
-    n = 0x1b8;
-  else if (memcmp (buf + 0x03, "NTFS", 4) == 0)
-    n = 0x048;
-  else if (memcmp (buf + 0x52, "FAT32", 5) == 0)
-    n = 0x043;
-  else if (memcmp (buf + 0x36, "FAT", 3) == 0)
-    n = 0x027;
-  else
-    return ~0;
-
-  unsigned serial = *(unsigned *)(buf + n);
-  if (serial == 0)
-    return ~0;
-  return serial;
-}
-
-#pragma GCC diagnostic warning "-Wdeprecated-declarations"
-
-char *
-grub_find_device (const char *path, dev_t dev)
-{
-  /* No root device for /cygdrive.  */
-  if (dev == (DEV_CYGDRIVE_MAJOR << 16))
-    return 0;
-
-  /* Convert to full POSIX and Win32 path.  */
-  char fullpath[PATH_MAX], winpath[PATH_MAX];
-
-  cygwin_conv_path (CCP_WIN_A_TO_POSIX, path, fullpath, sizeof (fullpath));
-  cygwin_conv_path (CCP_POSIX_TO_WIN_A, fullpath, winpath, sizeof (winpath));
-
-  /* If identical, this is no real filesystem path.  */
-  if (strcmp (fullpath, winpath) == 0)
-    return 0;
-
-  /* Check for floppy drive letter.  */
-  if (winpath[0] && winpath[1] == ':' && strchr ("AaBb", winpath[0]))
-    return xstrdup (strchr ("Aa", winpath[0]) ? "/dev/fd0" : "/dev/fd1");
-
-  /* Cygwin returns the partition serial number in stat.st_dev.
-     This is never identical to the device number of the emulated
-     /dev/sdXN device, so above grub_find_device () does not work.
-     Search the partition with the same serial in boot sector instead.  */
-  char devpath[sizeof ("/dev/sda15") + 13]; /* Size + Paranoia.  */
-  int d;
-  for (d = 'a'; d <= 'z'; d++)
-    {
-      sprintf (devpath, "/dev/sd%c", d);
-      if (get_bootsec_serial (devpath, 1) == 0)
-       continue;
-      int p;
-      for (p = 1; p <= 15; p++)
-       {
-         sprintf (devpath, "/dev/sd%c%d", d, p);
-         unsigned ser = get_bootsec_serial (devpath, 0);
-         if (ser == 0)
-           break;
-         if (ser != (unsigned)~0 && dev == (dev_t)ser)
-           return xstrdup (devpath);
-       }
-    }
-  return 0;
-}
-
-#endif /* __CYGWIN__ */
-
-char **
-grub_guess_root_devices (const char *dir)
-{
-  char **os_dev = NULL;
-#ifndef __GNU__
-  struct stat st;
-  dev_t dev;
-
-#ifdef __linux__
-  if (!os_dev)
-    os_dev = grub_find_root_devices_from_mountinfo (dir, NULL);
-#endif /* __linux__ */
-
-#if !defined (__MINGW32__) && !defined (__CYGWIN__)
-  if (!os_dev)
-    os_dev = find_root_devices_from_libzfs (dir);
-#endif
-
-  if (os_dev)
-    {
-      char **cur;
-      for (cur = os_dev; *cur; cur++)
-       {
-         char *tmp = *cur;
-         int root, dm;
-         if (strcmp (*cur, "/dev/root") == 0
-             || strncmp (*cur, "/dev/dm-", sizeof ("/dev/dm-") - 1) == 0)
-           *cur = tmp;
-         else
-           {
-             *cur = canonicalize_file_name (tmp);
-             if (*cur == NULL)
-               grub_util_error (_("failed to get canonical path of `%s'"), tmp);
-             free (tmp);
-           }
-         root = (strcmp (*cur, "/dev/root") == 0);
-         dm = (strncmp (*cur, "/dev/dm-", sizeof ("/dev/dm-") - 1) == 0);
-         if (!dm && !root)
-           continue;
-         if (stat (*cur, &st) < 0)
-           break;
-         free (*cur);
-         dev = st.st_rdev;
-         *cur = grub_find_device (dm ? "/dev/mapper" : "/dev", dev);
-       }
-      if (!*cur)
-       return os_dev;
-      for (cur = os_dev; *cur; cur++)
-       free (*cur);
-      free (os_dev);
-      os_dev = 0;
-    }
-
-  if (stat (dir, &st) < 0)
-    grub_util_error (_("cannot stat `%s': %s"), dir, strerror (errno));
-
-  dev = st.st_dev;
-#endif /* !__GNU__ */
-
-  os_dev = xmalloc (2 * sizeof (os_dev[0]));
-  
-#ifdef __CYGWIN__
-  /* Cygwin specific function.  */
-  os_dev[0] = grub_find_device (dir, dev);
-
-#elif defined __GNU__
-  /* GNU/Hurd specific function.  */
-  os_dev[0] = grub_util_find_hurd_root_device (dir);
-
-#else
-
-  /* This might be truly slow, but is there any better way?  */
-  os_dev[0] = grub_find_device ("/dev", dev);
-#endif
-  if (!os_dev[0])
-    {
-      free (os_dev);
-      return 0;
-    }
-
-  os_dev[1] = 0;
-
-  return os_dev;
-}
-
 grub_disk_addr_t
 grub_util_find_partition_start (const char *dev)
 {
@@ -764,7 +120,7 @@ grub_util_pull_device (const char *os_dev)
     {
     case GRUB_DEV_ABSTRACTION_LVM:
 #if !defined (__MINGW32__) && !defined (__CYGWIN__)
-      pull_lvm_by_command (os_dev);
+      grub_util_pull_lvm_by_command (os_dev);
 #endif
       /* Fallthrough in case that lvm-tools are unavailable.  */
     case GRUB_DEV_ABSTRACTION_LUKS:
@@ -796,7 +152,6 @@ grub_util_get_grub_dev (const char *os_dev)
   return grub_util_biosdisk_get_grub_dev (os_dev);
 }
 
-
 int
 grub_util_get_dev_abstraction (const char *os_dev)
 {
@@ -815,151 +170,6 @@ grub_util_get_dev_abstraction (const char *os_dev)
   return grub_util_get_dev_abstraction_os (os_dev);
 }
 
-#if !defined (__MINGW32__) && !defined (__CYGWIN__)
-
-static void
-pull_lvm_by_command (const char *os_dev)
-{
-  char *argv[8];
-  int fd;
-  pid_t pid;
-  FILE *mdadm;
-  char *buf = NULL;
-  size_t len = 0;
-  char *vgname = NULL;
-  const char *iptr;
-  char *optr;
-  char *vgid = NULL;
-  grub_size_t vgidlen = 0;
-
-  vgid = grub_util_get_vg_uuid (os_dev);
-  if (vgid)
-    vgidlen = grub_strlen (vgid);
-
-  if (!vgid)
-    {
-      if (strncmp (os_dev, LVM_DEV_MAPPER_STRING,
-                  sizeof (LVM_DEV_MAPPER_STRING) - 1)
-         != 0)
-       return;
-
-      vgname = xmalloc (strlen (os_dev + sizeof (LVM_DEV_MAPPER_STRING) - 1) + 1);
-      for (iptr = os_dev + sizeof (LVM_DEV_MAPPER_STRING) - 1, optr = vgname; *iptr; )
-       if (*iptr != '-')
-         *optr++ = *iptr++;
-       else if (iptr[0] == '-' && iptr[1] == '-')
-         {
-           iptr += 2;
-           *optr++ = '-';
-         }
-       else
-         break;
-      *optr = '\0';
-    }
-
-  /* execvp has inconvenient types, hence the casts.  None of these
-     strings will actually be modified.  */
-  /* by default PV name is left aligned in 10 character field, meaning that
-     we do not know where name ends. Using dummy --separator disables
-     alignment. We have a single field, so separator itself is not output */
-  argv[0] = (char *) "vgs";
-  argv[1] = (char *) "--options";
-  if (vgid)
-    argv[2] = (char *) "vg_uuid,pv_name";
-  else
-    argv[2] = (char *) "pv_name";
-  argv[3] = (char *) "--noheadings";
-  argv[4] = (char *) "--separator";
-  argv[5] = (char *) ":";
-  argv[6] = vgname;
-  argv[7] = NULL;
-
-  pid = grub_util_exec_pipe (argv, &fd);
-  free (vgname);
-
-  if (!pid)
-    return;
-
-  /* Parent.  Read mdadm's output.  */
-  mdadm = fdopen (fd, "r");
-  if (! mdadm)
-    {
-      grub_util_warn (_("Unable to open stream from %s: %s"),
-                     "vgs", strerror (errno));
-      goto out;
-    }
-
-  while (getline (&buf, &len, mdadm) > 0)
-    {
-      char *ptr;
-      /* LVM adds two spaces as standard prefix */
-      for (ptr = buf; ptr < buf + 2 && *ptr == ' '; ptr++);
-
-      if (vgid && (grub_strncmp (vgid, ptr, vgidlen) != 0
-                  || ptr[vgidlen] != ':'))
-       continue;
-      if (vgid)
-       ptr += vgidlen + 1;
-      if (*ptr == '\0')
-       continue;
-      *(ptr + strlen (ptr) - 1) = '\0';
-      grub_util_pull_device (ptr);
-    }
-
-out:
-  close (fd);
-  waitpid (pid, NULL, 0);
-  free (buf);
-}
-
-#endif
-
-int
-grub_util_biosdisk_is_floppy (grub_disk_t disk)
-{
-  struct stat st;
-  int fd;
-  const char *dname;
-
-  dname = grub_util_biosdisk_get_osdev (disk);
-
-  if (!dname)
-    return 0;
-
-  fd = open (dname, O_RDONLY);
-  /* Shouldn't happen.  */
-  if (fd == -1)
-    return 0;
-
-  /* Shouldn't happen either.  */
-  if (fstat (fd, &st) < 0)
-    {
-      close (fd);
-      return 0;
-    }
-
-  close (fd);
-
-#if defined(__NetBSD__)
-  if (major(st.st_rdev) == RAW_FLOPPY_MAJOR)
-    return 1;
-#endif
-
-#if defined(FLOPPY_MAJOR)
-  if (major(st.st_rdev) == FLOPPY_MAJOR)
-#else
-  /* Some kernels (e.g. kFreeBSD) don't have a static major number
-     for floppies, but they still use a "fd[0-9]" pathname.  */
-  if (dname[5] == 'f'
-      && dname[6] == 'd'
-      && dname[7] >= '0'
-      && dname[7] <= '9')
-#endif
-    return 1;
-
-  return 0;
-}
-
 static char *
 convert_system_partition_to_system_disk (const char *os_dev, struct stat *st,
                                         int *is_part)
@@ -1012,7 +222,7 @@ make_device_name (const char *drive, int dos_part, int bsd_part)
   ptr = ret;
   for (iptr = drive; *iptr; iptr++)
     {
-      if (*iptr == ',')
+      if (*iptr == ',' || *iptr == '\\')
        *ptr++ = '\\';
       *ptr++ = *iptr;
     }
@@ -1029,11 +239,13 @@ make_device_name (const char *drive, int dos_part, int bsd_part)
 char *
 grub_util_get_os_disk (const char *os_dev)
 {
-  struct stat st;
   int is_part;
 
   grub_util_info ("Looking for %s", os_dev);
 
+#if !defined (__MINGW32__) && !defined (__CYGWIN__)
+  struct stat st;
+
   if (stat (os_dev, &st) < 0)
     {
       const char *errstr = strerror (errno); 
@@ -1044,6 +256,9 @@ grub_util_get_os_disk (const char *os_dev)
     }
 
   return convert_system_partition_to_system_disk (os_dev, &st, &is_part);
+#else
+  return convert_system_partition_to_system_disk (os_dev, NULL, &is_part);
+#endif
 }
 
 #if !defined(__APPLE__)
@@ -1079,13 +294,16 @@ find_partition (grub_disk_t dsk __attribute__ ((unused)),
 char *
 grub_util_biosdisk_get_grub_dev (const char *os_dev)
 {
+#if !defined (__MINGW32__) && !defined (__CYGWIN__)
   struct stat st;
+#endif
   const char *drive;
   char *sys_disk;
   int is_part;
 
   grub_util_info ("Looking for %s", os_dev);
 
+#if !defined (__MINGW32__) && !defined (__CYGWIN__)
   if (stat (os_dev, &st) < 0)
     {
       const char *errstr = strerror (errno); 
@@ -1094,9 +312,21 @@ grub_util_biosdisk_get_grub_dev (const char *os_dev)
       grub_util_info (_("cannot stat `%s': %s"), os_dev, errstr);
       return 0;
     }
-
   drive = find_system_device (os_dev, &st, 1, 1);
+
+#if GRUB_DISK_DEVS_ARE_CHAR
+  if (! S_ISCHR (st.st_mode))
+#else
+  if (! S_ISBLK (st.st_mode))
+#endif
+    return make_device_name (drive, -1, -1);
+
   sys_disk = convert_system_partition_to_system_disk (os_dev, &st, &is_part);
+#else
+  drive = find_system_device (os_dev, NULL, 1, 1);
+  sys_disk = convert_system_partition_to_system_disk (os_dev, NULL, &is_part);
+#endif
+
   if (!sys_disk)
     return 0;
   grub_util_info ("%s is a parent of %s", sys_disk, os_dev);
@@ -1107,13 +337,6 @@ grub_util_biosdisk_get_grub_dev (const char *os_dev)
     }
   free (sys_disk);
 
-#if GRUB_DISK_DEVS_ARE_CHAR
-  if (! S_ISCHR (st.st_mode))
-#else
-  if (! S_ISBLK (st.st_mode))
-#endif
-    return make_device_name (drive, -1, -1);
-
 #if defined(__APPLE__)
   /* Apple uses "/dev/r?disk[0-9]+(s[0-9]+)?".  */
   {
@@ -1228,7 +451,11 @@ grub_util_biosdisk_get_grub_dev (const char *os_dev)
            grub_errno = GRUB_ERR_NONE;
 
            canon = canonicalize_file_name (os_dev);
+#if !defined (__MINGW32__) && !defined (__CYGWIN__)
            drive = find_system_device (canon ? : os_dev, &st, 0, 1);
+#else
+           drive = find_system_device (canon ? : os_dev, NULL, 0, 1);
+#endif
            if (canon)
              free (canon);
            return make_device_name (drive, -1, -1);
@@ -1311,27 +538,6 @@ grub_util_check_char_device (const char *blk_dev)
     return 0;
 }
 
-#ifdef __CYGWIN__
-/* Convert POSIX path to Win32 path,
-   remove drive letter, replace backslashes.  */
-static char *
-get_win32_path (const char *path)
-{
-  char winpath[PATH_MAX];
-  if (cygwin_conv_path (CCP_POSIX_TO_WIN_A, path, winpath, sizeof(winpath)))
-    grub_util_error ("%s", _("cygwin_conv_path() failed"));
-
-  int len = strlen (winpath);
-  int offs = (len > 2 && winpath[1] == ':' ? 2 : 0);
-
-  int i;
-  for (i = offs; i < len; i++)
-    if (winpath[i] == '\\')
-      winpath[i] = '/';
-  return xstrdup (winpath + offs);
-}
-#endif
-
 #ifdef HAVE_LIBZFS
 static libzfs_handle_t *__libzfs_handle;
 
@@ -1356,216 +562,3 @@ grub_get_libzfs_handle (void)
 }
 #endif /* HAVE_LIBZFS */
 
-#if !defined (__MINGW32__) && !defined (__CYGWIN__)
-/* ZFS has similar problems to those of btrfs (see above).  */
-void
-grub_find_zpool_from_dir (const char *dir, char **poolname, char **poolfs)
-{
-  char *slash;
-
-  *poolname = *poolfs = NULL;
-
-#if defined(HAVE_STRUCT_STATFS_F_FSTYPENAME) && defined(HAVE_STRUCT_STATFS_F_MNTFROMNAME)
-  /* FreeBSD and GNU/kFreeBSD.  */
-  {
-    struct statfs mnt;
-
-    if (statfs (dir, &mnt) != 0)
-      return;
-
-    if (strcmp (mnt.f_fstypename, "zfs") != 0)
-      return;
-
-    *poolname = xstrdup (mnt.f_mntfromname);
-  }
-#elif defined(HAVE_GETEXTMNTENT)
-  /* Solaris.  */
-  {
-    struct stat st;
-    struct extmnttab mnt;
-
-    if (stat (dir, &st) != 0)
-      return;
-
-    FILE *mnttab = fopen ("/etc/mnttab", "r");
-    if (! mnttab)
-      return;
-
-    while (getextmntent (mnttab, &mnt, sizeof (mnt)) == 0)
-      {
-       if (makedev (mnt.mnt_major, mnt.mnt_minor) == st.st_dev
-           && !strcmp (mnt.mnt_fstype, "zfs"))
-         {
-           *poolname = xstrdup (mnt.mnt_special);
-           break;
-         }
-      }
-
-    fclose (mnttab);
-  }
-#endif
-
-  if (! *poolname)
-    return;
-
-  slash = strchr (*poolname, '/');
-  if (slash)
-    {
-      *slash = '\0';
-      *poolfs = xstrdup (slash + 1);
-    }
-  else
-    *poolfs = xstrdup ("");
-}
-#endif
-
-/* This function never prints trailing slashes (so that its output
-   can be appended a slash unconditionally).  */
-char *
-grub_make_system_path_relative_to_its_root (const char *path)
-{
-  struct stat st;
-  char *p, *buf, *buf2, *buf3, *ret;
-  uintptr_t offset = 0;
-  dev_t num;
-  size_t len;
-  char *poolfs = NULL;
-
-  /* canonicalize.  */
-  p = canonicalize_file_name (path);
-  if (p == NULL)
-    grub_util_error (_("failed to get canonical path of `%s'"), path);
-
-  /* For ZFS sub-pool filesystems, could be extended to others (btrfs?).  */
-#if !defined (__MINGW32__) && !defined (__CYGWIN__)
-  {
-    char *dummy;
-    grub_find_zpool_from_dir (p, &dummy, &poolfs);
-  }
-#endif
-
-  len = strlen (p) + 1;
-  buf = xstrdup (p);
-  free (p);
-
-  if (stat (buf, &st) < 0)
-    grub_util_error (_("cannot stat `%s': %s"), buf, strerror (errno));
-
-  buf2 = xstrdup (buf);
-  num = st.st_dev;
-
-  /* This loop sets offset to the number of chars of the root
-     directory we're inspecting.  */
-  while (1)
-    {
-      p = strrchr (buf, '/');
-      if (p == NULL)
-       /* This should never happen.  */
-       grub_util_error ("%s",
-                        /* TRANSLATORS: canonical pathname is the
-                           complete one e.g. /etc/fstab. It has
-                           to contain `/' normally, if it doesn't
-                           we're in trouble and throw this error.  */
-                        _("no `/' in canonical filename"));
-      if (p != buf)
-       *p = 0;
-      else
-       *++p = 0;
-
-      if (stat (buf, &st) < 0)
-       grub_util_error (_("cannot stat `%s': %s"), buf, strerror (errno));
-
-      /* buf is another filesystem; we found it.  */
-      if (st.st_dev != num)
-       {
-         /* offset == 0 means path given is the mount point.
-            This works around special-casing of "/" in Un*x.  This function never
-            prints trailing slashes (so that its output can be appended a slash
-            unconditionally).  Each slash in is considered a preceding slash, and
-            therefore the root directory is an empty string.  */
-         if (offset == 0)
-           {
-             free (buf);
-#ifdef __linux__
-             {
-               char *bind;
-               grub_free (grub_find_root_devices_from_mountinfo (buf2, &bind));
-               if (bind && bind[0] && bind[1])
-                 {
-                   buf3 = bind;
-                   goto parsedir;
-                 }
-               grub_free (bind);
-             }
-#endif
-             free (buf2);
-             if (poolfs)
-               return xasprintf ("/%s/@", poolfs);
-             return xstrdup ("");
-           }
-         else
-           break;
-       }
-
-      offset = p - buf;
-      /* offset == 1 means root directory.  */
-      if (offset == 1)
-       {
-         /* Include leading slash.  */
-         offset = 0;
-         break;
-       }
-    }
-  free (buf);
-  buf3 = xstrdup (buf2 + offset);
-  buf2[offset] = 0;
-#ifdef __linux__
-  {
-    char *bind;
-    grub_free (grub_find_root_devices_from_mountinfo (buf2, &bind));
-    if (bind && bind[0] && bind[1])
-      {
-       char *temp = buf3;
-       buf3 = grub_xasprintf ("%s%s%s", bind, buf3[0] == '/' ?"":"/", buf3);
-       grub_free (temp);
-      }
-    grub_free (bind);
-  }
-#endif
-  
-  free (buf2);
-
-#ifdef __CYGWIN__
-  if (st.st_dev != (DEV_CYGDRIVE_MAJOR << 16))
-    {
-      /* Reached some mount point not below /cygdrive.
-        GRUB does not know Cygwin's emulated mounts,
-        convert to Win32 path.  */
-      grub_util_info ("Cygwin path = %s\n", buf3);
-      char * temp = get_win32_path (buf3);
-      free (buf3);
-      buf3 = temp;
-    }
-#endif
-
-#ifdef __linux__
- parsedir:
-#endif
-  /* Remove trailing slashes, return empty string if root directory.  */
-  len = strlen (buf3);
-  while (len > 0 && buf3[len - 1] == '/')
-    {
-      buf3[len - 1] = '\0';
-      len--;
-    }
-
-  if (poolfs)
-    {
-      ret = xasprintf ("/%s/@%s", poolfs, buf3);
-      free (buf3);
-    }
-  else
-    ret = buf3;
-
-  return ret;
-}
diff --git a/util/getroot_cygwin.c b/util/getroot_cygwin.c
deleted file mode 100644 (file)
index 6407d2c..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- *  GRUB  --  GRand Unified Bootloader
- *  Copyright (C) 1999,2000,2001,2002,2003,2006,2007,2008,2009,2010,2011,2012,2013  Free Software Foundation, Inc.
- *
- *  GRUB is free software: you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation, either version 3 of the License, or
- *  (at your option) any later version.
- *
- *  GRUB is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <config-util.h>
-#include <config.h>
-
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <string.h>
-#include <dirent.h>
-#include <errno.h>
-#include <error.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#ifdef HAVE_LIMITS_H
-#include <limits.h>
-#endif
-
-#include <grub/types.h>
-
-#include <grub/util/misc.h>
-#include <grub/util/lvm.h>
-#include <grub/mm.h>
-#include <grub/misc.h>
-#include <grub/emu/misc.h>
-#include <grub/emu/hostdisk.h>
-#include <grub/emu/getroot.h>
-
-#include <sys/wait.h>
-
-# include <sys/ioctl.h>
-# include <cygwin/fs.h> /* BLKGETSIZE64 */
-# include <cygwin/hdreg.h> /* HDIO_GETGEO */
-# include <sys/cygwin.h>
-
-
-char *
-grub_util_part_to_disk (const char *os_dev,
-                       struct stat *st __attribute__ ((unused)),
-                       int *is_part)
-{
-  char *path = xstrdup (os_dev);
-  if (strncmp ("/dev/sd", path, 7) == 0 && 'a' <= path[7] && path[7] <= 'z'
-      && path[8])
-    {
-      *is_part = 1;
-      path[8] = 0;
-    }
-  return path;
-}
-
-enum grub_dev_abstraction_types
-grub_util_get_dev_abstraction_os (const char *os_dev __attribute__((unused)))
-{
-  return GRUB_DEV_ABSTRACTION_NONE;
-}
-
-int
-grub_util_pull_device_os (const char *os_dev __attribute__ ((unused)),
-                         enum grub_dev_abstraction_types ab __attribute__ ((unused)))
-{
-  return 0;
-}
-
-char *
-grub_util_get_grub_dev_os (const char *os_dev __attribute__ ((unused)))
-{
-  return NULL;
-}
-
-grub_disk_addr_t
-grub_util_find_partition_start_os (const char *dev)
-{
-  int fd;
-  struct hd_geometry hdg;
-
-  fd = open (dev, O_RDONLY);
-  if (fd == -1)
-    {
-      grub_error (GRUB_ERR_BAD_DEVICE, N_("cannot open `%s': %s"),
-                 dev, strerror (errno));
-      return 0;
-    }
-
-  if (ioctl (fd, HDIO_GETGEO, &hdg))
-    {
-      grub_error (GRUB_ERR_BAD_DEVICE,
-                 "cannot get disk geometry of `%s'", dev);
-      close (fd);
-      return 0;
-    }
-
-  close (fd);
-
-  return hdg.start;
-}
index f63f4de74299daade657fa900ae6299bdfb271f8..0cd29dc0e865e19dab59e700922205806c8e111a 100644 (file)
@@ -52,8 +52,7 @@
 #include <hurd/fs.h>
 #include <sys/mman.h>
 
-
-char *
+static char *
 grub_util_find_hurd_root_device (const char *path)
 {
   file_t file;
@@ -219,3 +218,24 @@ grub_util_find_partition_start_os (const char *dev)
   free (path);
   return -1;
 }
+
+char **
+grub_guess_root_devices (const char *dir)
+{
+  char **os_dev = NULL;
+
+  os_dev = xmalloc (2 * sizeof (os_dev[0]));
+
+  /* GNU/Hurd specific function.  */
+  os_dev[0] = grub_util_find_hurd_root_device (dir);
+
+  if (!os_dev[0])
+    {
+      free (os_dev);
+      return 0;
+    }
+
+  os_dev[1] = 0;
+
+  return os_dev;
+}
index fee9f210090d1fb2a540346c403f79603884dac8..a2ed13262432ff3be2cb57476d1ccd32c7a4896c 100644 (file)
@@ -10,8 +10,8 @@
 #include "getroot_sun.c"
 #elif defined(__GNU__)
 #include "getroot_hurd.c"
-#elif defined(__CYGWIN__)
-#include "getroot_cygwin.c"
+#elif defined(__CYGWIN__) || defined (__MINGW32__)
+#include "getroot_windows.c"
 #else
 # warning "No getroot OS-specific functions is available for your system. Device detection may not work properly."
 #include "getroot_basic.c"
diff --git a/util/getroot_unix.c b/util/getroot_unix.c
new file mode 100644 (file)
index 0000000..bdf60f0
--- /dev/null
@@ -0,0 +1,931 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 1999,2000,2001,2002,2003,2006,2007,2008,2009,2010,2011  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config-util.h>
+#include <config.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <dirent.h>
+#include <errno.h>
+#include <error.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+#include <grub/util/misc.h>
+#include <grub/util/lvm.h>
+#include <grub/cryptodisk.h>
+#include <grub/i18n.h>
+
+#if !defined (__MINGW32__) && !defined (__CYGWIN__)
+
+#ifdef __linux__
+#include <sys/ioctl.h>         /* ioctl */
+#include <sys/mount.h>
+#ifndef MAJOR
+# ifndef MINORBITS
+#  define MINORBITS    8
+# endif /* ! MINORBITS */
+# define MAJOR(dev)    ((unsigned) ((dev) >> MINORBITS))
+#endif /* ! MAJOR */
+#ifndef FLOPPY_MAJOR
+# define FLOPPY_MAJOR  2
+#endif /* ! FLOPPY_MAJOR */
+#endif
+
+#include <sys/types.h>
+
+#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR)
+# include <grub/util/libzfs.h>
+# include <grub/util/libnvpair.h>
+#endif
+
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/emu/misc.h>
+#include <grub/emu/hostdisk.h>
+#include <grub/emu/getroot.h>
+
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+# define MAJOR(dev) major(dev)
+# define FLOPPY_MAJOR  2
+#endif
+
+#if defined (__FreeBSD__) || defined (__FreeBSD_kernel__)
+#include <sys/mount.h>
+#endif
+
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+# include <sys/ioctl.h>
+# include <sys/disklabel.h>    /* struct disklabel */
+# include <sys/disk.h>    /* struct dkwedge_info */
+#include <sys/param.h>
+#include <sys/mount.h>
+#endif /* defined(__NetBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) */
+
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+# define MAJOR(dev) major(dev)
+# ifdef HAVE_GETRAWPARTITION
+#  include <util.h>    /* getrawpartition */
+# endif /* HAVE_GETRAWPARTITION */
+#if defined(__NetBSD__)
+# include <sys/fdio.h>
+#endif
+# ifndef FLOPPY_MAJOR
+#  define FLOPPY_MAJOR 2
+# endif /* ! FLOPPY_MAJOR */
+# ifndef RAW_FLOPPY_MAJOR
+#  define RAW_FLOPPY_MAJOR     9
+# endif /* ! RAW_FLOPPY_MAJOR */
+#endif /* defined(__NetBSD__) */
+
+#include <sys/types.h>
+#include <sys/wait.h>
+
+static void
+strip_extra_slashes (char *dir)
+{
+  char *p = dir;
+
+  while ((p = strchr (p, '/')) != 0)
+    {
+      if (p[1] == '/')
+       {
+         memmove (p, p + 1, strlen (p));
+         continue;
+       }
+      else if (p[1] == '\0')
+       {
+         if (p > dir)
+           p[0] = '\0';
+         break;
+       }
+
+      p++;
+    }
+}
+
+static char *
+xgetcwd (void)
+{
+  size_t size = 10;
+  char *path;
+
+  path = xmalloc (size);
+  while (! getcwd (path, size))
+    {
+      size <<= 1;
+      path = xrealloc (path, size);
+    }
+
+  return path;
+}
+
+pid_t
+grub_util_exec_pipe (char **argv, int *fd)
+{
+  int mdadm_pipe[2];
+  pid_t mdadm_pid;
+
+  *fd = 0;
+
+  if (pipe (mdadm_pipe) < 0)
+    {
+      grub_util_warn (_("Unable to create pipe: %s"),
+                     strerror (errno));
+      return 0;
+    }
+  mdadm_pid = fork ();
+  if (mdadm_pid < 0)
+    grub_util_error (_("Unable to fork: %s"), strerror (errno));
+  else if (mdadm_pid == 0)
+    {
+      /* Child.  */
+
+      /* Close fd's.  */
+      grub_util_devmapper_cleanup ();
+      grub_diskfilter_fini ();
+
+      /* Ensure child is not localised.  */
+      setenv ("LC_ALL", "C", 1);
+
+      close (mdadm_pipe[0]);
+      dup2 (mdadm_pipe[1], STDOUT_FILENO);
+      close (mdadm_pipe[1]);
+
+      execvp (argv[0], argv);
+      exit (127);
+    }
+  else
+    {
+      close (mdadm_pipe[1]);
+      *fd = mdadm_pipe[0];
+      return mdadm_pid;
+    }
+}
+
+#if !defined (__GNU__)
+char **
+grub_util_find_root_devices_from_poolname (char *poolname)
+{
+  char **devices = 0;
+  size_t ndevices = 0;
+  size_t devices_allocated = 0;
+
+#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR)
+  zpool_handle_t *zpool;
+  libzfs_handle_t *libzfs;
+  nvlist_t *config, *vdev_tree;
+  nvlist_t **children;
+  unsigned int nvlist_count;
+  unsigned int i;
+  char *device = 0;
+
+  libzfs = grub_get_libzfs_handle ();
+  if (! libzfs)
+    return NULL;
+
+  zpool = zpool_open (libzfs, poolname);
+  config = zpool_get_config (zpool, NULL);
+
+  if (nvlist_lookup_nvlist (config, "vdev_tree", &vdev_tree) != 0)
+    error (1, errno, "nvlist_lookup_nvlist (\"vdev_tree\")");
+
+  if (nvlist_lookup_nvlist_array (vdev_tree, "children", &children, &nvlist_count) != 0)
+    error (1, errno, "nvlist_lookup_nvlist_array (\"children\")");
+  assert (nvlist_count > 0);
+
+  while (nvlist_lookup_nvlist_array (children[0], "children",
+                                    &children, &nvlist_count) == 0)
+    assert (nvlist_count > 0);
+
+  for (i = 0; i < nvlist_count; i++)
+    {
+      if (nvlist_lookup_string (children[i], "path", &device) != 0)
+       error (1, errno, "nvlist_lookup_string (\"path\")");
+
+      struct stat st;
+      if (stat (device, &st) == 0)
+       {
+#ifdef __sun__
+         if (grub_memcmp (device, "/dev/dsk/", sizeof ("/dev/dsk/") - 1)
+             == 0)
+           device = xasprintf ("/dev/rdsk/%s",
+                               device + sizeof ("/dev/dsk/") - 1);
+         else if (grub_memcmp (device, "/devices", sizeof ("/devices") - 1)
+                  == 0
+                  && grub_memcmp (device + strlen (device) - 4,
+                                  ",raw", 4) != 0)
+           device = xasprintf ("%s,raw", device);
+         else
+#endif
+           device = xstrdup (device);
+         if (ndevices >= devices_allocated)
+           {
+             devices_allocated = 2 * (devices_allocated + 8);
+             devices = xrealloc (devices, sizeof (devices[0])
+                                 * devices_allocated);
+           }
+         devices[ndevices++] = device;
+       }
+
+      device = NULL;
+    }
+
+  zpool_close (zpool);
+#else
+  FILE *fp;
+  int ret;
+  char *line;
+  size_t len;
+  int st;
+
+  char name[PATH_MAX + 1], state[257], readlen[257], writelen[257];
+  char cksum[257], notes[257];
+  unsigned int dummy;
+  char *argv[4];
+  pid_t pid;
+  int fd;
+
+  /* execvp has inconvenient types, hence the casts.  None of these
+     strings will actually be modified.  */
+  argv[0] = (char *) "zpool";
+  argv[1] = (char *) "status";
+  argv[2] = (char *) poolname;
+  argv[3] = NULL;
+
+  pid = grub_util_exec_pipe (argv, &fd);
+  if (!pid)
+    return NULL;
+
+  fp = fdopen (fd, "r");
+  if (!fp)
+    {
+      grub_util_warn (_("Unable to open stream from %s: %s"),
+                     "zpool", strerror (errno));
+      goto out;
+    }
+
+  st = 0;
+  while (1)
+    {
+      line = NULL;
+      ret = getline (&line, &len, fp);
+      if (ret == -1)
+       break;
+       
+      if (sscanf (line, " %s %256s %256s %256s %256s %256s",
+                 name, state, readlen, writelen, cksum, notes) >= 5)
+       switch (st)
+         {
+         case 0:
+           if (!strcmp (name, "NAME")
+               && !strcmp (state, "STATE")
+               && !strcmp (readlen, "READ")
+               && !strcmp (writelen, "WRITE")
+               && !strcmp (cksum, "CKSUM"))
+             st++;
+           break;
+         case 1:
+           {
+             char *ptr = line;
+             while (1)
+               {
+                 if (strncmp (ptr, poolname, strlen (poolname)) == 0
+                     && grub_isspace(ptr[strlen (poolname)]))
+                   st++;
+                 if (!grub_isspace (*ptr))
+                   break;
+                 ptr++;
+               }
+           }
+           break;
+         case 2:
+           if (strcmp (name, "mirror") && !sscanf (name, "mirror-%u", &dummy)
+               && !sscanf (name, "raidz%u", &dummy)
+               && !sscanf (name, "raidz1%u", &dummy)
+               && !sscanf (name, "raidz2%u", &dummy)
+               && !sscanf (name, "raidz3%u", &dummy)
+               && !strcmp (state, "ONLINE"))
+             {
+               if (ndevices >= devices_allocated)
+                 {
+                   devices_allocated = 2 * (devices_allocated + 8);
+                   devices = xrealloc (devices, sizeof (devices[0])
+                                       * devices_allocated);
+                 }
+               if (name[0] == '/')
+                 devices[ndevices++] = xstrdup (name);
+               else
+                 devices[ndevices++] = xasprintf ("/dev/%s", name);
+             }
+           break;
+         }
+       
+      free (line);
+    }
+
+ out:
+  close (fd);
+  waitpid (pid, NULL, 0);
+#endif
+  if (devices)
+    {
+      if (ndevices >= devices_allocated)
+       {
+         devices_allocated = 2 * (devices_allocated + 8);
+         devices = xrealloc (devices, sizeof (devices[0])
+                             * devices_allocated);
+       }
+      devices[ndevices++] = 0;
+    }
+  return devices;
+}
+
+static char **
+find_root_devices_from_libzfs (const char *dir)
+{
+  char **devices = NULL;
+  char *poolname;
+  char *poolfs;
+
+  grub_find_zpool_from_dir (dir, &poolname, &poolfs);
+  if (! poolname)
+    return NULL;
+
+  devices = grub_util_find_root_devices_from_poolname (poolname);
+
+  free (poolname);
+  if (poolfs)
+    free (poolfs);
+
+  return devices;
+}
+
+char *
+grub_find_device (const char *dir, dev_t dev)
+{
+  DIR *dp;
+  char *saved_cwd;
+  struct dirent *ent;
+
+  if (! dir)
+    dir = "/dev";
+
+  dp = opendir (dir);
+  if (! dp)
+    return 0;
+
+  saved_cwd = xgetcwd ();
+
+  grub_util_info ("changing current directory to %s", dir);
+  if (chdir (dir) < 0)
+    {
+      free (saved_cwd);
+      closedir (dp);
+      return 0;
+    }
+
+  while ((ent = readdir (dp)) != 0)
+    {
+      struct stat st;
+
+      /* Avoid:
+        - dotfiles (like "/dev/.tmp.md0") since they could be duplicates.
+        - dotdirs (like "/dev/.static") since they could contain duplicates.  */
+      if (ent->d_name[0] == '.')
+       continue;
+
+      if (lstat (ent->d_name, &st) < 0)
+       /* Ignore any error.  */
+       continue;
+
+      if (S_ISLNK (st.st_mode)) {
+#ifdef __linux__
+       if (strcmp (dir, "mapper") == 0 || strcmp (dir, "/dev/mapper") == 0) {
+         /* Follow symbolic links under /dev/mapper/; the canonical name
+            may be something like /dev/dm-0, but the names under
+            /dev/mapper/ are more human-readable and so we prefer them if
+            we can get them.  */
+         if (stat (ent->d_name, &st) < 0)
+           continue;
+       } else
+#endif /* __linux__ */
+       /* Don't follow other symbolic links.  */
+       continue;
+      }
+
+      if (S_ISDIR (st.st_mode))
+       {
+         /* Find it recursively.  */
+         char *res;
+
+         res = grub_find_device (ent->d_name, dev);
+
+         if (res)
+           {
+             if (chdir (saved_cwd) < 0)
+               grub_util_error ("%s",
+                                _("cannot restore the original directory"));
+
+             free (saved_cwd);
+             closedir (dp);
+             return res;
+           }
+       }
+
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__)
+      if (S_ISCHR (st.st_mode) && st.st_rdev == dev)
+#else
+      if (S_ISBLK (st.st_mode) && st.st_rdev == dev)
+#endif
+       {
+#ifdef __linux__
+         /* Skip device names like /dev/dm-0, which are short-hand aliases
+            to more descriptive device names, e.g. those under /dev/mapper */
+         if (ent->d_name[0] == 'd' &&
+             ent->d_name[1] == 'm' &&
+             ent->d_name[2] == '-' &&
+             ent->d_name[3] >= '0' &&
+             ent->d_name[3] <= '9')
+           continue;
+#endif
+
+         /* Found!  */
+         char *res;
+         char *cwd;
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+         /* Convert this block device to its character (raw) device.  */
+         const char *template = "%s/r%s";
+#else
+         /* Keep the device name as it is.  */
+         const char *template = "%s/%s";
+#endif
+
+         cwd = xgetcwd ();
+         res = xmalloc (strlen (cwd) + strlen (ent->d_name) + 3);
+         sprintf (res, template, cwd, ent->d_name);
+         strip_extra_slashes (res);
+         free (cwd);
+
+         /* /dev/root is not a real block device keep looking, takes care
+            of situation where root filesystem is on the same partition as
+            grub files */
+
+         if (strcmp(res, "/dev/root") == 0)
+           {
+             free (res);
+             continue;
+           }
+
+         if (chdir (saved_cwd) < 0)
+           grub_util_error ("%s", _("cannot restore the original directory"));
+
+         free (saved_cwd);
+         closedir (dp);
+         return res;
+       }
+    }
+
+  if (chdir (saved_cwd) < 0)
+    grub_util_error ("%s", _("cannot restore the original directory"));
+
+  free (saved_cwd);
+  closedir (dp);
+  return 0;
+}
+
+char **
+grub_guess_root_devices (const char *dir)
+{
+  char **os_dev = NULL;
+  struct stat st;
+  dev_t dev;
+
+#ifdef __linux__
+  if (!os_dev)
+    os_dev = grub_find_root_devices_from_mountinfo (dir, NULL);
+#endif /* __linux__ */
+
+  if (!os_dev)
+    os_dev = find_root_devices_from_libzfs (dir);
+
+  if (os_dev)
+    {
+      char **cur;
+      for (cur = os_dev; *cur; cur++)
+       {
+         char *tmp = *cur;
+         int root, dm;
+         if (strcmp (*cur, "/dev/root") == 0
+             || strncmp (*cur, "/dev/dm-", sizeof ("/dev/dm-") - 1) == 0)
+           *cur = tmp;
+         else
+           {
+             *cur = canonicalize_file_name (tmp);
+             if (*cur == NULL)
+               grub_util_error (_("failed to get canonical path of `%s'"), tmp);
+             free (tmp);
+           }
+         root = (strcmp (*cur, "/dev/root") == 0);
+         dm = (strncmp (*cur, "/dev/dm-", sizeof ("/dev/dm-") - 1) == 0);
+         if (!dm && !root)
+           continue;
+         if (stat (*cur, &st) < 0)
+           break;
+         free (*cur);
+         dev = st.st_rdev;
+         *cur = grub_find_device (dm ? "/dev/mapper" : "/dev", dev);
+       }
+      if (!*cur)
+       return os_dev;
+      for (cur = os_dev; *cur; cur++)
+       free (*cur);
+      free (os_dev);
+      os_dev = 0;
+    }
+
+  if (stat (dir, &st) < 0)
+    grub_util_error (_("cannot stat `%s': %s"), dir, strerror (errno));
+
+  dev = st.st_dev;
+
+  os_dev = xmalloc (2 * sizeof (os_dev[0]));
+
+  /* This might be truly slow, but is there any better way?  */
+  os_dev[0] = grub_find_device ("/dev", dev);
+
+  if (!os_dev[0])
+    {
+      free (os_dev);
+      return 0;
+    }
+
+  os_dev[1] = 0;
+
+  return os_dev;
+}
+
+#endif
+
+void
+grub_util_pull_lvm_by_command (const char *os_dev)
+{
+  char *argv[8];
+  int fd;
+  pid_t pid;
+  FILE *mdadm;
+  char *buf = NULL;
+  size_t len = 0;
+  char *vgname = NULL;
+  const char *iptr;
+  char *optr;
+  char *vgid = NULL;
+  grub_size_t vgidlen = 0;
+
+  vgid = grub_util_get_vg_uuid (os_dev);
+  if (vgid)
+    vgidlen = grub_strlen (vgid);
+
+  if (!vgid)
+    {
+      if (strncmp (os_dev, LVM_DEV_MAPPER_STRING,
+                  sizeof (LVM_DEV_MAPPER_STRING) - 1)
+         != 0)
+       return;
+
+      vgname = xmalloc (strlen (os_dev + sizeof (LVM_DEV_MAPPER_STRING) - 1) + 1);
+      for (iptr = os_dev + sizeof (LVM_DEV_MAPPER_STRING) - 1, optr = vgname; *iptr; )
+       if (*iptr != '-')
+         *optr++ = *iptr++;
+       else if (iptr[0] == '-' && iptr[1] == '-')
+         {
+           iptr += 2;
+           *optr++ = '-';
+         }
+       else
+         break;
+      *optr = '\0';
+    }
+
+  /* execvp has inconvenient types, hence the casts.  None of these
+     strings will actually be modified.  */
+  /* by default PV name is left aligned in 10 character field, meaning that
+     we do not know where name ends. Using dummy --separator disables
+     alignment. We have a single field, so separator itself is not output */
+  argv[0] = (char *) "vgs";
+  argv[1] = (char *) "--options";
+  if (vgid)
+    argv[2] = (char *) "vg_uuid,pv_name";
+  else
+    argv[2] = (char *) "pv_name";
+  argv[3] = (char *) "--noheadings";
+  argv[4] = (char *) "--separator";
+  argv[5] = (char *) ":";
+  argv[6] = vgname;
+  argv[7] = NULL;
+
+  pid = grub_util_exec_pipe (argv, &fd);
+  free (vgname);
+
+  if (!pid)
+    return;
+
+  /* Parent.  Read mdadm's output.  */
+  mdadm = fdopen (fd, "r");
+  if (! mdadm)
+    {
+      grub_util_warn (_("Unable to open stream from %s: %s"),
+                     "vgs", strerror (errno));
+      goto out;
+    }
+
+  while (getline (&buf, &len, mdadm) > 0)
+    {
+      char *ptr;
+      /* LVM adds two spaces as standard prefix */
+      for (ptr = buf; ptr < buf + 2 && *ptr == ' '; ptr++);
+
+      if (vgid && (grub_strncmp (vgid, ptr, vgidlen) != 0
+                  || ptr[vgidlen] != ':'))
+       continue;
+      if (vgid)
+       ptr += vgidlen + 1;
+      if (*ptr == '\0')
+       continue;
+      *(ptr + strlen (ptr) - 1) = '\0';
+      grub_util_pull_device (ptr);
+    }
+
+out:
+  close (fd);
+  waitpid (pid, NULL, 0);
+  free (buf);
+}
+
+/* ZFS has similar problems to those of btrfs (see above).  */
+void
+grub_find_zpool_from_dir (const char *dir, char **poolname, char **poolfs)
+{
+  char *slash;
+
+  *poolname = *poolfs = NULL;
+
+#if defined(HAVE_STRUCT_STATFS_F_FSTYPENAME) && defined(HAVE_STRUCT_STATFS_F_MNTFROMNAME)
+  /* FreeBSD and GNU/kFreeBSD.  */
+  {
+    struct statfs mnt;
+
+    if (statfs (dir, &mnt) != 0)
+      return;
+
+    if (strcmp (mnt.f_fstypename, "zfs") != 0)
+      return;
+
+    *poolname = xstrdup (mnt.f_mntfromname);
+  }
+#elif defined(HAVE_GETEXTMNTENT)
+  /* Solaris.  */
+  {
+    struct stat st;
+    struct extmnttab mnt;
+
+    if (stat (dir, &st) != 0)
+      return;
+
+    FILE *mnttab = fopen ("/etc/mnttab", "r");
+    if (! mnttab)
+      return;
+
+    while (getextmntent (mnttab, &mnt, sizeof (mnt)) == 0)
+      {
+       if (makedev (mnt.mnt_major, mnt.mnt_minor) == st.st_dev
+           && !strcmp (mnt.mnt_fstype, "zfs"))
+         {
+           *poolname = xstrdup (mnt.mnt_special);
+           break;
+         }
+      }
+
+    fclose (mnttab);
+  }
+#endif
+
+  if (! *poolname)
+    return;
+
+  slash = strchr (*poolname, '/');
+  if (slash)
+    {
+      *slash = '\0';
+      *poolfs = xstrdup (slash + 1);
+    }
+  else
+    *poolfs = xstrdup ("");
+}
+
+/* This function never prints trailing slashes (so that its output
+   can be appended a slash unconditionally).  */
+char *
+grub_make_system_path_relative_to_its_root (const char *path)
+{
+  struct stat st;
+  char *p, *buf, *buf2, *buf3, *ret;
+  uintptr_t offset = 0;
+  dev_t num;
+  size_t len;
+  char *poolfs = NULL;
+
+  /* canonicalize.  */
+  p = canonicalize_file_name (path);
+  if (p == NULL)
+    grub_util_error (_("failed to get canonical path of `%s'"), path);
+
+  /* For ZFS sub-pool filesystems, could be extended to others (btrfs?).  */
+  {
+    char *dummy;
+    grub_find_zpool_from_dir (p, &dummy, &poolfs);
+  }
+
+  len = strlen (p) + 1;
+  buf = xstrdup (p);
+  free (p);
+
+  if (stat (buf, &st) < 0)
+    grub_util_error (_("cannot stat `%s': %s"), buf, strerror (errno));
+
+  buf2 = xstrdup (buf);
+  num = st.st_dev;
+
+  /* This loop sets offset to the number of chars of the root
+     directory we're inspecting.  */
+  while (1)
+    {
+      p = strrchr (buf, '/');
+      if (p == NULL)
+       /* This should never happen.  */
+       grub_util_error ("%s",
+                        /* TRANSLATORS: canonical pathname is the
+                           complete one e.g. /etc/fstab. It has
+                           to contain `/' normally, if it doesn't
+                           we're in trouble and throw this error.  */
+                        _("no `/' in canonical filename"));
+      if (p != buf)
+       *p = 0;
+      else
+       *++p = 0;
+
+      if (stat (buf, &st) < 0)
+       grub_util_error (_("cannot stat `%s': %s"), buf, strerror (errno));
+
+      /* buf is another filesystem; we found it.  */
+      if (st.st_dev != num)
+       {
+         /* offset == 0 means path given is the mount point.
+            This works around special-casing of "/" in Un*x.  This function never
+            prints trailing slashes (so that its output can be appended a slash
+            unconditionally).  Each slash in is considered a preceding slash, and
+            therefore the root directory is an empty string.  */
+         if (offset == 0)
+           {
+             free (buf);
+#ifdef __linux__
+             {
+               char *bind;
+               grub_free (grub_find_root_devices_from_mountinfo (buf2, &bind));
+               if (bind && bind[0] && bind[1])
+                 {
+                   buf3 = bind;
+                   goto parsedir;
+                 }
+               grub_free (bind);
+             }
+#endif
+             free (buf2);
+             if (poolfs)
+               return xasprintf ("/%s/@", poolfs);
+             return xstrdup ("");
+           }
+         else
+           break;
+       }
+
+      offset = p - buf;
+      /* offset == 1 means root directory.  */
+      if (offset == 1)
+       {
+         /* Include leading slash.  */
+         offset = 0;
+         break;
+       }
+    }
+  free (buf);
+  buf3 = xstrdup (buf2 + offset);
+  buf2[offset] = 0;
+#ifdef __linux__
+  {
+    char *bind;
+    grub_free (grub_find_root_devices_from_mountinfo (buf2, &bind));
+    if (bind && bind[0] && bind[1])
+      {
+       char *temp = buf3;
+       buf3 = grub_xasprintf ("%s%s%s", bind, buf3[0] == '/' ?"":"/", buf3);
+       grub_free (temp);
+      }
+    grub_free (bind);
+  }
+#endif
+  
+  free (buf2);
+
+#ifdef __linux__
+ parsedir:
+#endif
+  /* Remove trailing slashes, return empty string if root directory.  */
+  len = strlen (buf3);
+  while (len > 0 && buf3[len - 1] == '/')
+    {
+      buf3[len - 1] = '\0';
+      len--;
+    }
+
+  if (poolfs)
+    {
+      ret = xasprintf ("/%s/@%s", poolfs, buf3);
+      free (buf3);
+    }
+  else
+    ret = buf3;
+
+  return ret;
+}
+
+int
+grub_util_biosdisk_is_floppy (grub_disk_t disk)
+{
+  struct stat st;
+  int fd;
+  const char *dname;
+
+  dname = grub_util_biosdisk_get_osdev (disk);
+
+  if (!dname)
+    return 0;
+
+  fd = open (dname, O_RDONLY);
+  /* Shouldn't happen.  */
+  if (fd == -1)
+    return 0;
+
+  /* Shouldn't happen either.  */
+  if (fstat (fd, &st) < 0)
+    {
+      close (fd);
+      return 0;
+    }
+
+  close (fd);
+
+#if defined(__NetBSD__)
+  if (major(st.st_rdev) == RAW_FLOPPY_MAJOR)
+    return 1;
+#endif
+
+#if defined(FLOPPY_MAJOR)
+  if (major(st.st_rdev) == FLOPPY_MAJOR)
+#else
+  /* Some kernels (e.g. kFreeBSD) don't have a static major number
+     for floppies, but they still use a "fd[0-9]" pathname.  */
+  if (dname[5] == 'f'
+      && dname[6] == 'd'
+      && dname[7] >= '0'
+      && dname[7] <= '9')
+#endif
+    return 1;
+
+  return 0;
+}
+
+#endif
diff --git a/util/getroot_windows.c b/util/getroot_windows.c
new file mode 100644 (file)
index 0000000..b023af5
--- /dev/null
@@ -0,0 +1,346 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 1999,2000,2001,2002,2003,2006,2007,2008,2009,2010,2011,2012,2013  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config-util.h>
+#include <config.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <dirent.h>
+#include <errno.h>
+#include <error.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#include <grub/types.h>
+
+#include <grub/util/misc.h>
+#include <grub/util/lvm.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/emu/misc.h>
+#include <grub/emu/hostdisk.h>
+#include <grub/emu/getroot.h>
+#include <grub/charset.h>
+#include <grub/util/windows.h>
+#include <windows.h>
+#include <winioctl.h>
+
+char *
+grub_util_tchar_to_utf8 (LPCTSTR in)
+{
+#if SIZEOF_TCHAR == 1
+  return xstrdup (path);
+#elif SIZEOF_TCHAR == 2
+  size_t ssz;
+  for (ssz = 0; in[ssz]; ssz++);
+
+  size_t tsz = GRUB_MAX_UTF8_PER_UTF16 * ssz + 1;
+  grub_uint8_t *ret = xmalloc (tsz);
+  *grub_utf16_to_utf8 (ret, in, ssz) = '\0';
+  return (char *) ret;
+#else
+#error "Unsupported TCHAR size"
+#endif
+}
+
+#if SIZEOF_TCHAR == 1
+#define tcsnicmp strncasecmp
+#define tclen strlen
+#elif SIZEOF_TCHAR == 2
+#define tcsnicmp wcsnicmp
+#define tclen wcslen
+#endif
+
+char **
+grub_guess_root_devices (const char *dir)
+{
+  char **os_dev = NULL;
+  TCHAR *dirwindows, *mntpointwindows;
+  TCHAR *ptr;
+  TCHAR volumename[100];
+  size_t mntpointwindows_sz;
+
+  dirwindows = grub_util_get_windows_path (dir);
+  if (!dirwindows)
+    return 0;
+
+  mntpointwindows_sz = strlen (dir) * 2 + 1;
+  mntpointwindows = xmalloc ((mntpointwindows_sz + 1) * sizeof (mntpointwindows[0]));
+
+  if (!GetVolumePathName (dirwindows,
+                         mntpointwindows,
+                         mntpointwindows_sz))
+    {
+      free (dirwindows);
+      free (mntpointwindows);
+      return 0;      
+    }
+
+  if (!mntpointwindows[0])
+    {
+      free (dirwindows);
+      free (mntpointwindows);
+      return 0;      
+    }
+  
+  for (ptr = mntpointwindows; *ptr; ptr++);
+  if (*(ptr - 1) != '\\')
+    {
+      *ptr = '\\';
+      *(ptr + 1) = '\0';
+    }
+
+  if (!GetVolumeNameForVolumeMountPoint (mntpointwindows,
+                                        volumename,
+                                        ARRAY_SIZE (volumename)))
+    {
+      free (dirwindows);
+      free (mntpointwindows);
+      return 0;
+    }
+  os_dev = xmalloc (2 * sizeof (os_dev[0]));
+
+  for (ptr = volumename; *ptr; ptr++);
+  while (ptr > volumename && *(ptr - 1) == '\\')
+    *--ptr = '\0';
+
+  os_dev[0] = grub_util_tchar_to_utf8 (volumename);
+  free (dirwindows);
+  free (mntpointwindows);
+
+  if (!os_dev[0])
+    {
+      free (os_dev);
+      return 0;
+    }
+
+  os_dev[1] = 0;
+
+  return os_dev;
+}
+
+char *
+grub_util_part_to_disk (const char *os_dev,
+                       struct stat *st __attribute__ ((unused)),
+                       int *is_part)
+{
+  HANDLE hd;
+  LPTSTR name = grub_util_get_windows_path (os_dev);
+  VOLUME_DISK_EXTENTS exts;
+  DWORD extsbytes;
+  char *ret;
+
+  if (((name[0] == '/') || (name[0] == '\\')) &&
+      ((name[1] == '/') || (name[1] == '\\')) &&
+      ((name[2] == '.') || (name[2] == '?')) &&
+      ((name[3] == '/') || (name[3] == '\\'))
+      && (tcsnicmp (name + 4, TEXT("PhysicalDrive"), sizeof ("PhysicalDrive") - 1) == 0
+         || tcsnicmp (name + 4, TEXT("Harddisk"), sizeof ("Harddisk") - 1) == 0
+         || ((name[4] == 'A' || name[4] == 'a' || name[4] == 'B' || name[4] == 'b')
+             && name[5] == ':' && name[6] == '\0')))
+    {
+      grub_util_info ("Matches full disk pattern");
+      ret = grub_util_tchar_to_utf8 (name);
+      free (name);
+      return ret;
+    }
+
+  hd = CreateFile (name, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
+                   0, OPEN_EXISTING, 0, 0);
+  if (hd == INVALID_HANDLE_VALUE)
+    {
+      grub_util_info ("CreateFile failed");
+      ret = grub_util_tchar_to_utf8 (name);
+      free (name);
+      return ret;
+    }
+
+  if (!DeviceIoControl(hd, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
+                      NULL, 0, &exts, sizeof (exts), &extsbytes, NULL))
+    {
+      grub_util_info ("IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS failed");
+      ret = grub_util_tchar_to_utf8 (name);
+      CloseHandle (hd);
+      free (name);
+      return ret;
+    }
+  
+  CloseHandle (hd);
+
+  *is_part = 1;
+  free (name);
+  return xasprintf ("\\\\?\\PhysicalDrive%lu", (unsigned long) exts.Extents[0].DiskNumber);
+}
+
+enum grub_dev_abstraction_types
+grub_util_get_dev_abstraction_os (const char *os_dev __attribute__((unused)))
+{
+  return GRUB_DEV_ABSTRACTION_NONE;
+}
+
+int
+grub_util_pull_device_os (const char *os_dev __attribute__ ((unused)),
+                         enum grub_dev_abstraction_types ab __attribute__ ((unused)))
+{
+  return 0;
+}
+
+char *
+grub_util_get_grub_dev_os (const char *os_dev __attribute__ ((unused)))
+{
+  return NULL;
+}
+
+
+grub_disk_addr_t
+grub_util_find_partition_start_os (const char *os_dev)
+{
+  HANDLE hd;
+  LPTSTR name = grub_util_get_windows_path (os_dev);
+  VOLUME_DISK_EXTENTS exts;
+  DWORD extsbytes;
+  char *ret;
+
+  if (((name[0] == '/') || (name[0] == '\\')) &&
+      ((name[1] == '/') || (name[1] == '\\')) &&
+      ((name[2] == '.') || (name[2] == '?')) &&
+      ((name[3] == '/') || (name[3] == '\\'))
+      && (tcsnicmp (name + 4, TEXT("PhysicalDrive"), sizeof ("PhysicalDrive") - 1) == 0
+         || tcsnicmp (name + 4, TEXT("Harddisk"), sizeof ("Harddisk") - 1) == 0
+         || ((name[4] == 'A' || name[4] == 'a' || name[4] == 'B' || name[4] == 'b')
+             && name[5] == ':' && name[6] == '\0')))
+    {
+      ret = grub_util_tchar_to_utf8 (name);
+      free (name);
+      return 0;
+    }
+
+  hd = CreateFile (name, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
+                   0, OPEN_EXISTING, 0, 0);
+  if (hd == INVALID_HANDLE_VALUE)
+    {
+      ret = grub_util_tchar_to_utf8 (name);
+      free (name);
+      return 0;
+    }
+
+  if (!DeviceIoControl(hd, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
+                      NULL, 0, &exts, sizeof (exts), &extsbytes, NULL))
+    {
+      ret = grub_util_tchar_to_utf8 (name);
+      CloseHandle (hd);
+      free (name);
+      return 0;
+    }
+  
+  CloseHandle (hd);
+  free (name);
+  return exts.Extents[0].StartingOffset.QuadPart / 512;
+}
+
+char *
+grub_make_system_path_relative_to_its_root (const char *path)
+{
+  TCHAR *dirwindows, *mntpointwindows;
+  TCHAR *ptr;
+  TCHAR volumename[100];
+  size_t mntpointwindows_sz;
+  size_t offset, flen;
+  TCHAR *ret;
+  char *cret;
+
+  dirwindows = grub_util_get_windows_path (path);
+  if (!dirwindows)
+    return xstrdup (path);
+
+  mntpointwindows_sz = strlen (path) * 2 + 1;
+  mntpointwindows = xmalloc ((mntpointwindows_sz + 1) * sizeof (mntpointwindows[0]));
+
+  if (!GetVolumePathName (dirwindows,
+                         mntpointwindows,
+                         mntpointwindows_sz))
+    {
+      offset = 0;
+      if (dirwindows[0] && dirwindows[1] == ':')
+       offset = 2;
+    }
+  offset = tclen (mntpointwindows);
+  free (mntpointwindows);
+  flen = tclen (dirwindows);
+  if (offset > flen)
+    {
+      offset = 0;
+      if (dirwindows[0] && dirwindows[1] == ':')
+       offset = 2;
+    }
+  ret = xmalloc (sizeof (ret[0]) * (flen - offset + 2));
+  if (dirwindows[offset] != '\\'
+      && dirwindows[offset] != '/'
+      && dirwindows[offset])
+    {
+      ret[0] = '\\';
+      memcpy (ret + 1, dirwindows + offset, (flen - offset + 1) * sizeof (ret[0]));
+    }
+  else
+    memcpy (ret, dirwindows + offset, (flen - offset + 1) * sizeof (ret[0]));
+
+  free (dirwindows);
+
+  for (ptr = ret; *ptr; ptr++)
+    if (*ptr == '\\')
+      *ptr = '/';
+
+  cret = grub_util_tchar_to_utf8 (ret);
+  free (ret);
+
+  return cret;
+}
+
+int
+grub_util_biosdisk_is_floppy (grub_disk_t disk)
+{
+  int ret;
+  const char *dname;
+  LPTSTR name;
+
+  dname = grub_util_biosdisk_get_osdev (disk);
+
+  if (!dname)
+    return 0;
+
+  name = grub_util_get_windows_path (dname);
+
+  ret = (((name[0] == '/') || (name[0] == '\\')) &&
+        ((name[1] == '/') || (name[1] == '\\')) &&
+        ((name[2] == '.') || (name[2] == '?')) &&
+        ((name[3] == '/') || (name[3] == '\\'))
+        && (name[4] == 'A' || name[4] == 'a' || name[4] == 'B' || name[4] == 'b')
+        && name[5] == ':' && name[6] == '\0');
+  free (name);
+
+  return ret;
+}