+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.
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;
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
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
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"
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;
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];
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);
#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 */
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)
{
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))
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);
}
}
-#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)
{
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;
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);
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
{
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);
&& 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
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,
{
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__
{
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__
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);
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);
}
.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')
{
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;
# 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;
}
void
-grub_hostdisk_configure_device_driver (int fd __attribute__ ((unused)))
+grub_hostdisk_configure_device_driver (grub_util_fd_t fd __attribute__ ((unused)))
{
}
#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)))
{
}
void
-grub_hostdisk_configure_device_driver (int fd __attribute__ ((unused)))
+grub_hostdisk_configure_device_driver (grub_util_fd_t fd __attribute__ ((unused)))
{
}
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;
}
#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;
+++ /dev/null
-/*
- * 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, §or_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)))
-{
-}
# 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;
#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)))
{
}
}
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;
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;
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);
for (i = 1; i < 10000; i++)
{
- int fd;
+ grub_util_fd_t fd;
grub_disk_addr_t start;
sprintf (p, format, i);
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);
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;
}
+++ /dev/null
-/*
- * 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)))
-{
-}
#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"
# 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;
}
void
-grub_hostdisk_configure_device_driver (int fd __attribute__ ((unused)))
+grub_hostdisk_configure_device_driver (grub_util_fd_t fd __attribute__ ((unused)))
{
}
--- /dev/null
+/* 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
--- /dev/null
+/*
+ * 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;
+}
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;
}
return 0;
}
-#ifdef __MINGW32__
+#if defined (__MINGW32__) || defined (__CYGWIN__)
void
grub_millisleep (grub_uint32_t ms)
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);
#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);
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);
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);
/* 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);
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);
#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 */
--- /dev/null
+/*
+ * 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
#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)
{
{
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:
return grub_util_biosdisk_get_grub_dev (os_dev);
}
-
int
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)
ptr = ret;
for (iptr = drive; *iptr; iptr++)
{
- if (*iptr == ',')
+ if (*iptr == ',' || *iptr == '\\')
*ptr++ = '\\';
*ptr++ = *iptr;
}
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);
}
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__)
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);
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);
}
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]+)?". */
{
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);
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;
}
#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;
-}
+++ /dev/null
-/*
- * 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;
-}
#include <hurd/fs.h>
#include <sys/mman.h>
-
-char *
+static char *
grub_util_find_hurd_root_device (const char *path)
{
file_t file;
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;
+}
#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"
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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;
+}