files rather than one file with loads of #if's.
* util/getroot.c: Likewise.
+2013-09-22 Vladimir Serbinenko <phcoder@gmail.com>
+
+ * grub-core/kern/emu/hostdisk.c: Disentagle into a series of OS-specific
+ files rather than one file with loads of #if's.
+ * util/getroot.c: Likewise.
+
2013-09-22 Vladimir Serbinenko <phcoder@gmail.com>
* grub-core/lib/posix_wrap/sys/types.h: Use stddef on *BSD.
common = grub-core/kern/device.c;
common = grub-core/kern/disk.c;
common = util/getroot.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/misc.c;
common = grub-core/kern/emu/mm.c;
common = grub-core/kern/env.c;
EXTRA_DIST += m4/uintmax_t.m4
EXTRA_DIST += m4/visibility.m4
EXTRA_DIST += m4/math_h.m4
+
+EXTRA_DIST += grub-core/kern/emu/hostdisk_apple.c
+EXTRA_DIST += grub-core/kern/emu/hostdisk_basic.c
+EXTRA_DIST += grub-core/kern/emu/hostdisk_bsd.c
+EXTRA_DIST += grub-core/kern/emu/hostdisk_cygwin.c
+EXTRA_DIST += grub-core/kern/emu/hostdisk_freebsd.c
+EXTRA_DIST += grub-core/kern/emu/hostdisk_hurd.c
+EXTRA_DIST += grub-core/kern/emu/hostdisk_linux.c
+EXTRA_DIST += grub-core/kern/emu/hostdisk_mingw.c
+EXTRA_DIST += grub-core/kern/emu/hostdisk_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_freebsd.c
+EXTRA_DIST += util/getroot_hurd.c
+EXTRA_DIST += util/getroot_linux.c
+EXTRA_DIST += util/getroot_sun.c
emu = kern/emu/error.c;
emu = kern/emu/cache_s.S;
emu = kern/emu/hostdisk.c;
+ emu = kern/emu/hostdisk_devmapper.c;
+ emu = kern/emu/hostdisk_os.c;
emu = kern/emu/hostfs.c;
emu = kern/emu/main.c;
emu = kern/emu/argp_common.c;
#include <errno.h>
#include <limits.h>
-#ifdef __MINGW32__
-#include <windows.h>
-#include <winioctl.h>
-#include "dirname.h"
-#endif
-
#ifdef __linux__
# include <sys/ioctl.h> /* ioctl */
# include <sys/mount.h>
# define BLKFLSBUF _IO (0x12,97) /* flush buffer cache */
# endif /* ! BLKFLSBUF */
# include <sys/ioctl.h> /* ioctl */
-# ifndef HDIO_GETGEO
-# define HDIO_GETGEO 0x0301 /* get device geometry */
-/* If HDIO_GETGEO is not defined, it is unlikely that hd_geometry is
- defined. */
-struct hd_geometry
-{
- unsigned char heads;
- unsigned char sectors;
- unsigned short cylinders;
- unsigned long start;
-};
-# endif /* ! HDIO_GETGEO */
-# ifndef BLKGETSIZE64
-# define BLKGETSIZE64 _IOR(0x12,114,size_t) /* return device size */
-# endif /* ! BLKGETSIZE64 */
#endif /* __linux__ */
-#ifdef __CYGWIN__
-# include <sys/ioctl.h>
-# include <cygwin/fs.h> /* BLKGETSIZE64 */
-# include <cygwin/hdreg.h> /* HDIO_GETGEO */
-#endif
-
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
-# include <sys/disk.h> /* DIOCGMEDIASIZE */
-# include <sys/param.h>
# include <sys/sysctl.h>
-# include <sys/mount.h>
-#include <libgeom.h>
-#endif
-
-#if defined (__sun__)
-# include <sys/dkio.h>
-#endif
-
-#if defined(__APPLE__)
-# include <sys/disk.h>
-#endif
-
-#ifdef HAVE_DEVICE_MAPPER
-# include <libdevmapper.h>
#endif
-#if defined(__NetBSD__) || defined(__OpenBSD__)
-# define HAVE_DIOCGDINFO
-# include <sys/ioctl.h>
-# include <sys/disklabel.h> /* struct disklabel */
-# include <sys/disk.h> /* struct dkwedge_info */
-#else /* !defined(__NetBSD__) && !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__) */
-# undef HAVE_DIOCGDINFO
-#endif /* defined(__NetBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) */
-
-#if defined(__NetBSD__) || defined(__OpenBSD__)
-# ifdef HAVE_GETRAWPARTITION
-# include <util.h> /* getrawpartition */
-# endif /* HAVE_GETRAWPARTITION */
-# if defined(__NetBSD__)
-# include <sys/fdio.h>
-# endif
-# if defined(__OpenBSD__)
-# include <sys/dkio.h>
-# endif
-# ifndef RAW_FLOPPY_MAJOR
-# define RAW_FLOPPY_MAJOR 9
-# endif /* ! RAW_FLOPPY_MAJOR */
-#endif /* defined(__NetBSD__) */
-
static struct
{
char *drive;
int device_map;
};
-#ifdef __linux__
-/* Check if we have devfs support. */
-static int
-have_devfs (void)
-{
- static int dev_devfsd_exists = -1;
-
- if (dev_devfsd_exists < 0)
- {
- struct stat st;
-
- dev_devfsd_exists = stat ("/dev/.devfsd", &st) == 0;
- }
-
- return dev_devfsd_exists;
-}
-#endif /* __linux__ */
-
-#if defined(__NetBSD__)
-/* Adjust device driver parameters. This function should be called just
- after successfully opening the device. For now, it simply prevents the
- floppy driver from retrying operations on failure, as otherwise the
- driver takes a while to abort when there is no floppy in the drive. */
-static void
-configure_device_driver (int fd)
-{
- struct stat st;
-
- if (fstat (fd, &st) < 0 || ! S_ISCHR (st.st_mode))
- return;
- if (major(st.st_rdev) == RAW_FLOPPY_MAJOR)
- {
- int floppy_opts;
-
- if (ioctl (fd, FDIOCGETOPTS, &floppy_opts) == -1)
- return;
- floppy_opts |= FDOPT_NORETRY;
- if (ioctl (fd, FDIOCSETOPTS, &floppy_opts) == -1)
- return;
- }
-}
-#endif /* defined(__NetBSD__) */
-
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 __attribute__ ((unused)), const char *name_in,
+grub_util_get_fd_size (int fd, const char *name,
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;
+ return grub_util_get_fd_size_os (fd, name, log_secsize);
}
-#endif
+#else
-#if !defined(__MINGW32__)
grub_uint64_t
grub_util_get_fd_size (int fd, const char *name, unsigned *log_secsize)
{
-#if !defined (__GNU__)
-# if defined(__NetBSD__) || defined(__OpenBSD__)
- struct disklabel label;
-# elif defined (__sun__)
- struct dk_minfo minfo;
-# else
- unsigned long long nr;
-# endif
-#endif
- unsigned sector_size, log_sector_size;
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 defined(__linux__) || defined(__CYGWIN__) || defined(__FreeBSD__) || \
- defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__NetBSD__) \
- || defined (__sun__) || defined(__OpenBSD__)
-
-# if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__NetBSD__) || defined (__sun__) || defined(__OpenBSD__)
- if (! S_ISCHR (st.st_mode))
-# else
- if (! S_ISBLK (st.st_mode))
-# endif
- goto fail;
-
-# if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
- if (ioctl (fd, DIOCGMEDIASIZE, &nr))
-# elif defined(__APPLE__)
- if (ioctl (fd, DKIOCGETBLOCKCOUNT, &nr))
-# elif defined(__NetBSD__) || defined(__OpenBSD__)
-# if defined(__NetBSD__)
- configure_device_driver (fd);
-# endif
- if (ioctl (fd, DIOCGDINFO, &label) == -1)
-# elif defined (__sun__)
- if (!ioctl (fd, DKIOCGMEDIAINFO, &minfo))
-# else
- if (ioctl (fd, BLKGETSIZE64, &nr))
-# endif
- goto fail;
-
-# if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
- if (ioctl (fd, DIOCGSECTORSIZE, §or_size))
- goto fail;
-# elif defined(__APPLE__)
- if (ioctl (fd, DKIOCGETBLOCKSIZE, §or_size))
- goto fail;
-# elif defined(__sun__)
- sector_size = minfo.dki_lbsize;
-# elif defined(__NetBSD__) || defined(__OpenBSD__)
- sector_size = label.d_secsize;
-# else
- if (ioctl (fd, BLKSSZGET, §or_size))
- goto fail;
-# endif
- if (sector_size & (sector_size - 1) || !sector_size)
- goto fail;
- for (log_sector_size = 0;
- (1 << log_sector_size) < sector_size;
- log_sector_size++);
-
- if (log_secsize)
- *log_secsize = log_sector_size;
-
-# if defined (__APPLE__)
- return nr << log_sector_size;
-# elif defined(__NetBSD__) || defined(__OpenBSD__)
- return (grub_uint64_t) label.d_secperunit << log_sector_size;
-# elif defined (__sun__)
- return minfo.dki_capacity << log_sector_size;
-# else
- if (nr & ((1 << log_sector_size) - 1))
- grub_util_error ("%s", _("unaligned device size"));
-
- return nr;
-# endif
-
- fail:
-
- /* In GNU/Hurd, stat() will return the right size. */
-#elif !defined (__GNU__)
-# warning "No special routine to get the size of a block device is implemented for your OS. This is not possibly fatal."
+#if GRUB_DISK_DEVS_ARE_CHAR
+ if (S_ISCHR (st.st_mode))
+#else
+ if (S_ISBLK (st.st_mode))
#endif
-
- sector_size = 512;
- log_sector_size = 9;
+ ret = grub_util_get_fd_size_os (fd, name, log_secsize);
+ if (ret != -1LL)
+ return ret;
if (log_secsize)
- *log_secsize = 9;
+ *log_secsize = 9;
return st.st_size;
}
+
#endif
static grub_err_t
#if !defined(__MINGW32__)
-# if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__NetBSD__)
+# if GRUB_DISK_DEVS_ARE_CHAR
if (fstat (fd, &st) < 0 || ! S_ISCHR (st.st_mode))
# else
if (fstat (fd, &st) < 0 || ! S_ISBLK (st.st_mode))
}
}
-#ifdef HAVE_DEVICE_MAPPER
-static void device_mapper_null_log (int level __attribute__ ((unused)),
- const char *file __attribute__ ((unused)),
- int line __attribute__ ((unused)),
- int dm_errno __attribute__ ((unused)),
- const char *f __attribute__ ((unused)),
- ...)
-{
-}
-
-int
-grub_device_mapper_supported (void)
-{
- static int supported = -1;
-
- if (supported == -1)
- {
- struct dm_task *dmt;
-
- /* Suppress annoying log messages. */
- dm_log_with_errno_init (&device_mapper_null_log);
-
- dmt = dm_task_create (DM_DEVICE_VERSION);
- supported = (dmt != NULL);
- if (dmt)
- dm_task_destroy (dmt);
-
- /* Restore the original logger. */
- dm_log_with_errno_init (NULL);
- }
-
- return supported;
-}
-#endif /* HAVE_DEVICE_MAPPER */
-
-int
-grub_util_device_is_mapped (const char *dev)
-{
-#ifdef HAVE_DEVICE_MAPPER
- struct stat st;
-
- if (!grub_device_mapper_supported ())
- return 0;
-
- if (stat (dev, &st) < 0)
- return 0;
-
- return dm_is_dm_major (major (st.st_rdev));
-#else
- return 0;
-#endif /* HAVE_DEVICE_MAPPER */
-}
-
-#ifdef HAVE_DEVICE_MAPPER
-int
-grub_util_get_dm_node_linear_info (const char *dev,
- int *maj, int *min,
- grub_disk_addr_t *st)
-{
- struct dm_task *dmt;
- void *next = NULL;
- uint64_t length, start;
- char *target, *params;
- char *ptr;
- int major = 0, minor = 0;
- int first = 1;
- grub_disk_addr_t partstart = 0;
- const char *node_uuid;
-
- while (1)
- {
- dmt = dm_task_create(DM_DEVICE_TABLE);
- if (!dmt)
- break;
-
- if (! (first ? dm_task_set_name (dmt, dev)
- : dm_task_set_major_minor (dmt, major, minor, 0)))
- {
- dm_task_destroy (dmt);
- break;
- }
- dm_task_no_open_count(dmt);
- if (!dm_task_run(dmt))
- {
- dm_task_destroy (dmt);
- break;
- }
- node_uuid = dm_task_get_uuid (dmt);
- if (node_uuid && (strncmp (node_uuid, "LVM-", 4) == 0
- || strncmp (node_uuid, "mpath-", 6) == 0
- || strncmp (node_uuid, "DMRAID-", 7) == 0))
- {
- dm_task_destroy (dmt);
- break;
- }
-
- next = dm_get_next_target(dmt, next, &start, &length,
- &target, ¶ms);
- if (grub_strcmp (target, "linear") != 0)
- {
- dm_task_destroy (dmt);
- break;
- }
- major = grub_strtoul (params, &ptr, 10);
- if (grub_errno)
- {
- dm_task_destroy (dmt);
- grub_errno = GRUB_ERR_NONE;
- return 0;
- }
- if (*ptr != ':')
- {
- dm_task_destroy (dmt);
- return 0;
- }
- ptr++;
- minor = grub_strtoul (ptr, &ptr, 10);
- if (grub_errno)
- {
- grub_errno = GRUB_ERR_NONE;
- dm_task_destroy (dmt);
- return 0;
- }
-
- if (*ptr != ' ')
- {
- dm_task_destroy (dmt);
- return 0;
- }
- ptr++;
- partstart += grub_strtoull (ptr, &ptr, 10);
- if (grub_errno)
- {
- grub_errno = GRUB_ERR_NONE;
- dm_task_destroy (dmt);
- return 0;
- }
-
- dm_task_destroy (dmt);
- first = 0;
- if (!dm_is_dm_major (major))
- break;
- }
- if (first)
- return 0;
- if (maj)
- *maj = major;
- if (min)
- *min = minor;
- if (st)
- *st = partstart;
- return 1;
-}
-#endif
-
-#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
-
-/* FIXME: geom actually gives us the whole container hierarchy.
- It can be used more efficiently than this. */
-void
-grub_util_follow_gpart_up (const char *name, grub_disk_addr_t *off_out, char **name_out)
-{
- struct gmesh mesh;
- struct gclass *class;
- int error;
- struct ggeom *geom;
-
- grub_util_info ("following geom '%s'", name);
-
- error = geom_gettree (&mesh);
- if (error != 0)
- /* TRANSLATORS: geom is the name of (k)FreeBSD device framework.
- Usually left untranslated.
- */
- grub_util_error ("%s", _("couldn't open geom"));
-
- LIST_FOREACH (class, &mesh.lg_class, lg_class)
- if (strcasecmp (class->lg_name, "part") == 0)
- break;
- if (!class)
- /* TRANSLATORS: geom is the name of (k)FreeBSD device framework.
- Usually left untranslated. "part" is the identifier of one of its
- classes. */
- grub_util_error ("%s", _("couldn't find geom `part' class"));
-
- LIST_FOREACH (geom, &class->lg_geom, lg_geom)
- {
- struct gprovider *provider;
- LIST_FOREACH (provider, &geom->lg_provider, lg_provider)
- if (strcmp (provider->lg_name, name) == 0)
- {
- char *name_tmp = xstrdup (geom->lg_name);
- grub_disk_addr_t off = 0;
- struct gconfig *config;
- grub_util_info ("geom '%s' has parent '%s'", name, geom->lg_name);
-
- grub_util_follow_gpart_up (name_tmp, &off, name_out);
- free (name_tmp);
- LIST_FOREACH (config, &provider->lg_config, lg_config)
- if (strcasecmp (config->lg_name, "start") == 0)
- off += strtoull (config->lg_val, 0, 10);
- if (off_out)
- *off_out = off;
- return;
- }
- }
- grub_util_info ("geom '%s' has no parent", name);
- if (name_out)
- *name_out = xstrdup (name);
- if (off_out)
- *off_out = 0;
-}
-
-grub_disk_addr_t
-grub_hostdisk_find_partition_start (const char *dev)
-{
- grub_disk_addr_t out;
- if (strncmp (dev, "/dev/", sizeof ("/dev/") - 1) != 0)
- return 0;
- grub_util_follow_gpart_up (dev + sizeof ("/dev/") - 1, &out, NULL);
-
- return out;
-}
-
-#elif defined(__linux__) || defined(__CYGWIN__) || defined(HAVE_DIOCGDINFO) || defined (__sun__)
-grub_disk_addr_t
-grub_hostdisk_find_partition_start (const char *dev)
-{
- int fd;
-#ifdef __sun__
- struct extpart_info pinfo;
-# elif !defined(HAVE_DIOCGDINFO)
- struct hd_geometry hdg;
-# else /* defined(HAVE_DIOCGDINFO) */
-# if defined(__NetBSD__)
- struct dkwedge_info dkw;
-# endif /* defined(__NetBSD__) */
- struct disklabel label;
- int p_index;
-# endif /* !defined(HAVE_DIOCGDINFO) */
-
-# ifdef HAVE_DEVICE_MAPPER
- grub_disk_addr_t partition_start;
- if (grub_util_device_is_mapped (dev)
- && grub_util_get_dm_node_linear_info (dev, 0, 0, &partition_start))
- return partition_start;
-# endif /* HAVE_DEVICE_MAPPER */
-
- 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 defined(__sun__)
- if (ioctl (fd, DKIOCEXTPARTINFO, &pinfo))
-# elif !defined(HAVE_DIOCGDINFO)
- if (ioctl (fd, HDIO_GETGEO, &hdg))
-# else /* defined(HAVE_DIOCGDINFO) */
-# if defined(__NetBSD__)
- configure_device_driver (fd);
- /* First handle the case of disk wedges. */
- if (ioctl (fd, DIOCGWEDGEINFO, &dkw) == 0)
- {
- close (fd);
- return (grub_disk_addr_t) dkw.dkw_offset;
- }
-# endif /* defined(__NetBSD__) */
- if (ioctl (fd, DIOCGDINFO, &label) == -1)
-# endif /* !defined(HAVE_DIOCGDINFO) */
- {
- grub_error (GRUB_ERR_BAD_DEVICE,
-# if !defined(HAVE_DIOCGDINFO)
- "cannot get disk geometry of `%s'", dev);
-# else /* defined(HAVE_DIOCGDINFO) */
- "cannot get disk label of `%s'", dev);
-# endif /* !defined(HAVE_DIOCGDINFO) */
- close (fd);
- return 0;
- }
-
- close (fd);
-
-#ifdef __sun__
- return pinfo.p_start;
-# elif !defined(HAVE_DIOCGDINFO)
- return hdg.start;
-# else /* defined(HAVE_DIOCGDINFO) */
- if (dev[0])
- p_index = dev[strlen(dev) - 1] - 'a';
- else
- p_index = -1;
-
- if (p_index >= label.d_npartitions || p_index < 0)
- {
- grub_error (GRUB_ERR_BAD_DEVICE,
- "no disk label entry for `%s'", dev);
- return 0;
- }
- return (grub_disk_addr_t) label.d_partitions[p_index].p_offset;
-# endif /* !defined(HAVE_DIOCGDINFO) */
-}
-#endif /* __linux__ || __CYGWIN__ || HAVE_DIOCGDINFO */
-
-#ifdef __linux__
-/* Cache of partition start sectors for each disk. */
-struct linux_partition_cache
-{
- struct linux_partition_cache *next;
- struct linux_partition_cache **prev;
- char *dev;
- unsigned long start;
- int partno;
-};
-
-struct linux_partition_cache *linux_partition_cache_list;
-
-static int
-linux_find_partition (char *dev, grub_disk_addr_t sector)
-{
- size_t len = strlen (dev);
- const char *format;
- char *p;
- int i;
- char real_dev[PATH_MAX];
- struct linux_partition_cache *cache;
- int missing = 0;
-
- strcpy(real_dev, dev);
-
- if (have_devfs () && strcmp (real_dev + len - 5, "/disc") == 0)
- {
- p = real_dev + len - 4;
- format = "part%d";
- }
- else if (strncmp (real_dev, "/dev/disk/by-id/",
- sizeof ("/dev/disk/by-id/") - 1) == 0)
- {
- p = real_dev + len;
- format = "-part%d";
- }
- else if (real_dev[len - 1] >= '0' && real_dev[len - 1] <= '9')
- {
- p = real_dev + len;
- format = "p%d";
- }
- else
- {
- p = real_dev + len;
- format = "%d";
- }
-
- for (cache = linux_partition_cache_list; cache; cache = cache->next)
- {
- if (strcmp (cache->dev, dev) == 0 && cache->start == sector)
- {
- sprintf (p, format, cache->partno);
- strcpy (dev, real_dev);
- return 1;
- }
- }
-
- for (i = 1; i < 10000; i++)
- {
- int fd;
- grub_disk_addr_t start;
-
- sprintf (p, format, i);
-
- fd = open (real_dev, O_RDONLY);
- if (fd == -1)
- {
- if (missing++ < 10)
- continue;
- else
- return 0;
- }
- missing = 0;
- close (fd);
-
- start = grub_hostdisk_find_partition_start (real_dev);
- /* We don't care about errors here. */
- grub_errno = GRUB_ERR_NONE;
-
- if (start == sector)
- {
- struct linux_partition_cache *new_cache_item;
-
- new_cache_item = xmalloc (sizeof *new_cache_item);
- new_cache_item->dev = xstrdup (dev);
- new_cache_item->start = start;
- new_cache_item->partno = i;
- grub_list_push (GRUB_AS_LIST_P (&linux_partition_cache_list),
- GRUB_AS_LIST (new_cache_item));
-
- strcpy (dev, real_dev);
- return 1;
- }
- }
-
- return 0;
-}
-#endif /* __linux__ */
-
#if defined(__linux__) && (!defined(__GLIBC__) || \
((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1))))
/* Maybe libc doesn't have large file support. */
}
#endif
-static void
-flush_initial_buffer (const char *os_dev __attribute__ ((unused)))
-{
-#ifdef __linux__
- int fd;
- struct stat st;
-
- fd = open (os_dev, O_RDONLY);
- if (fd >= 0 && fstat (fd, &st) >= 0 && S_ISBLK (st.st_mode))
- ioctl (fd, BLKFLSBUF, 0);
- if (fd >= 0)
- close (fd);
-#endif
-}
-
const char *
grub_hostdisk_os_dev_to_grub_drive (const char *os_disk, int add)
{
strcpy (map[i].drive + sizeof ("hostdisk/") - 1, os_disk);
map[i].device_map = 0;
- flush_initial_buffer (os_disk);
+ grub_hostdisk_flush_initial_buffer (os_disk);
return map[i].drive;
}
&& strncmp (map[disk->id].device, "/dev/", 5) == 0)
{
if (sector >= part_start)
- is_partition = linux_find_partition (dev, part_start);
+ is_partition = grub_hostdisk_linux_find_partition (dev, part_start);
else
*max = part_start - sector;
}
if (data->access_mode == O_RDWR || data->access_mode == O_WRONLY)
{
fsync (data->fd);
-#ifdef __linux__
if (data->is_disk)
ioctl (data->fd, BLKFLSBUF, 0);
-#endif
}
close (data->fd);
data->access_mode = (flags & O_ACCMODE);
data->fd = fd;
-#ifdef __linux__
if (data->is_disk)
ioctl (data->fd, BLKFLSBUF, 0);
-#endif
}
if (is_partition)
if (data->access_mode == O_RDWR || data->access_mode == O_WRONLY)
{
fsync (data->fd);
-#ifdef __linux__
- if (data->is_disk)
- ioctl (data->fd, BLKFLSBUF, 0);
-#endif
}
close (data->fd);
data->fd = -1;
}
#endif /* ! __linux__ */
-#if defined(__NetBSD__)
- configure_device_driver (fd);
-#endif /* defined(__NetBSD__) */
+ grub_hostdisk_configure_device_driver (fd);
if (grub_util_fd_seek (fd, map[disk->id].device,
sector << disk->log_sector_size))
grub_util_info ("adding `%s' -> `%s' from device.map", map[drive].drive,
map[drive].device);
- flush_initial_buffer (map[drive].device);
+ grub_hostdisk_flush_initial_buffer (map[drive].device);
}
fclose (fp);
--- /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/disk.h>
+
+grub_uint64_t
+grub_util_get_fd_size (int fd, const char *name, unsigned *log_secsize)
+{
+ unsigned long long nr;
+ unsigned sector_size, log_sector_size;
+
+ if (ioctl (fd, DKIOCGETBLOCKCOUNT, &nr))
+ return -1;
+
+ if (ioctl (fd, DKIOCGETBLOCKSIZE, §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;
+
+ return nr << log_sector_size;
+}
+
+void
+grub_hostdisk_configure_device_driver (int fd __attribute__ ((unused)))
+{
+}
--- /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>
+
+grub_int64_t
+grub_util_get_fd_size_os (int fd __attribute__ ((unused)),
+ const char *name __attribute__ ((unused)),
+ unsigned *log_secsize __attribute__ ((unused)))
+{
+# warning "No special routine to get the size of a block device is implemented for your OS. This is not possibly fatal."
+
+ return -1;
+}
+
+void
+grub_hostdisk_configure_device_driver (int fd __attribute__ ((unused)))
+{
+}
+
+void
+grub_hostdisk_flush_initial_buffer (const char *os_dev __attribute__ ((unused)))
+{
+}
--- /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 <sys/disklabel.h> /* struct disklabel */
+# include <sys/disk.h> /* struct dkwedge_info */
+# ifdef HAVE_GETRAWPARTITION
+# include <util.h> /* getrawpartition */
+# endif /* HAVE_GETRAWPARTITION */
+# if defined(__NetBSD__)
+# include <sys/fdio.h>
+# endif
+# if defined(__OpenBSD__)
+# include <sys/dkio.h>
+# endif
+
+#if defined(__NetBSD__)
+/* Adjust device driver parameters. This function should be called just
+ after successfully opening the device. For now, it simply prevents the
+ 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)
+{
+ struct stat st;
+
+ if (fstat (fd, &st) < 0 || ! S_ISCHR (st.st_mode))
+ return;
+ if (major(st.st_rdev) == RAW_FLOPPY_MAJOR)
+ {
+ int floppy_opts;
+
+ if (ioctl (fd, FDIOCGETOPTS, &floppy_opts) == -1)
+ return;
+ floppy_opts |= FDOPT_NORETRY;
+ if (ioctl (fd, FDIOCSETOPTS, &floppy_opts) == -1)
+ return;
+ }
+}
+#else
+void
+grub_hostdisk_configure_device_driver (int fd __attribute__ ((unused)))
+{
+}
+#endif
+
+grub_int64_t
+grub_util_get_fd_size_os (int fd, const char *name, unsigned *log_secsize)
+{
+ struct disklabel label;
+ unsigned sector_size, log_sector_size;
+
+ grub_hostdisk_configure_device_driver (fd);
+
+ if (ioctl (fd, DIOCGDINFO, &label) == -1)
+ return -1;
+
+ sector_size = label.d_secsize;
+ 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;
+
+ return (grub_uint64_t) label.d_secperunit << log_sector_size;
+}
+
+void
+grub_hostdisk_flush_initial_buffer (const char *os_dev __attribute__ ((unused)))
+{
+}
--- /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)))
+{
+}
--- /dev/null
+#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>
+
+
+#ifdef HAVE_DEVICE_MAPPER
+# include <libdevmapper.h>
+
+static void device_mapper_null_log (int level __attribute__ ((unused)),
+ const char *file __attribute__ ((unused)),
+ int line __attribute__ ((unused)),
+ int dm_errno __attribute__ ((unused)),
+ const char *f __attribute__ ((unused)),
+ ...)
+{
+}
+
+int
+grub_device_mapper_supported (void)
+{
+ static int supported = -1;
+
+ if (supported == -1)
+ {
+ struct dm_task *dmt;
+
+ /* Suppress annoying log messages. */
+ dm_log_with_errno_init (&device_mapper_null_log);
+
+ dmt = dm_task_create (DM_DEVICE_VERSION);
+ supported = (dmt != NULL);
+ if (dmt)
+ dm_task_destroy (dmt);
+
+ /* Restore the original logger. */
+ dm_log_with_errno_init (NULL);
+ }
+
+ return supported;
+}
+
+int
+grub_util_device_is_mapped (const char *dev)
+{
+ struct stat st;
+
+ if (!grub_device_mapper_supported ())
+ return 0;
+
+ if (stat (dev, &st) < 0)
+ return 0;
+
+ return dm_is_dm_major (major (st.st_rdev));
+}
+
+int
+grub_util_get_dm_node_linear_info (const char *dev,
+ int *maj, int *min,
+ grub_disk_addr_t *st)
+{
+ struct dm_task *dmt;
+ void *next = NULL;
+ uint64_t length, start;
+ char *target, *params;
+ char *ptr;
+ int major = 0, minor = 0;
+ int first = 1;
+ grub_disk_addr_t partstart = 0;
+ const char *node_uuid;
+
+ while (1)
+ {
+ dmt = dm_task_create(DM_DEVICE_TABLE);
+ if (!dmt)
+ break;
+
+ if (! (first ? dm_task_set_name (dmt, dev)
+ : dm_task_set_major_minor (dmt, major, minor, 0)))
+ {
+ dm_task_destroy (dmt);
+ break;
+ }
+ dm_task_no_open_count(dmt);
+ if (!dm_task_run(dmt))
+ {
+ dm_task_destroy (dmt);
+ break;
+ }
+ node_uuid = dm_task_get_uuid (dmt);
+ if (node_uuid && (strncmp (node_uuid, "LVM-", 4) == 0
+ || strncmp (node_uuid, "mpath-", 6) == 0
+ || strncmp (node_uuid, "DMRAID-", 7) == 0))
+ {
+ dm_task_destroy (dmt);
+ break;
+ }
+
+ next = dm_get_next_target(dmt, next, &start, &length,
+ &target, ¶ms);
+ if (grub_strcmp (target, "linear") != 0)
+ {
+ dm_task_destroy (dmt);
+ break;
+ }
+ major = grub_strtoul (params, &ptr, 10);
+ if (grub_errno)
+ {
+ dm_task_destroy (dmt);
+ grub_errno = GRUB_ERR_NONE;
+ return 0;
+ }
+ if (*ptr != ':')
+ {
+ dm_task_destroy (dmt);
+ return 0;
+ }
+ ptr++;
+ minor = grub_strtoul (ptr, &ptr, 10);
+ if (grub_errno)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ dm_task_destroy (dmt);
+ return 0;
+ }
+
+ if (*ptr != ' ')
+ {
+ dm_task_destroy (dmt);
+ return 0;
+ }
+ ptr++;
+ partstart += grub_strtoull (ptr, &ptr, 10);
+ if (grub_errno)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ dm_task_destroy (dmt);
+ return 0;
+ }
+
+ dm_task_destroy (dmt);
+ first = 0;
+ if (!dm_is_dm_major (major))
+ break;
+ }
+ if (first)
+ return 0;
+ if (maj)
+ *maj = major;
+ if (min)
+ *min = minor;
+ if (st)
+ *st = partstart;
+ return 1;
+}
+#else
+
+int
+grub_util_device_is_mapped (const char *dev __attribute__ ((unused)))
+{
+ return 0;
+}
+
+int
+grub_util_get_dm_node_linear_info (const char *dev __attribute__ ((unused)),
+ int *maj __attribute__ ((unused)),
+ int *min __attribute__ ((unused)),
+ grub_disk_addr_t *st __attribute__ ((unused)))
+{
+ return 0;
+}
+
+#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 <sys/disk.h> /* DIOCGMEDIASIZE */
+# include <sys/param.h>
+# include <sys/sysctl.h>
+# include <sys/mount.h>
+# include <libgeom.h>
+
+void
+grub_hostdisk_configure_device_driver (int fd __attribute__ ((unused)))
+{
+}
+
+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, DIOCGMEDIASIZE, &nr))
+ return -1;
+
+ if (ioctl (fd, DIOCGSECTORSIZE, §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 & (sector_size - 1))
+ grub_util_error ("%s", _("unaligned device size"));
+
+ return nr;
+}
+
+void
+grub_hostdisk_flush_initial_buffer (const char *os_dev __attribute__ ((unused)))
+{
+}
--- /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 <hurd.h>
+#include <hurd/lookup.h>
+#include <hurd/fs.h>
+#include <sys/mman.h>
+
+void
+grub_hostdisk_configure_device_driver (int fd __attribute__ ((unused)))
+{
+}
+
+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)
+{
+ file_t file;
+ mach_port_t *ports;
+ int *ints;
+ loff_t *offsets;
+ char *data;
+ error_t err;
+ mach_msg_type_number_t num_ports = 0, num_ints = 0, num_offsets = 0, data_len = 0;
+
+ file = file_name_lookup (dev, 0, 0);
+ if (file == MACH_PORT_NULL)
+ return 0;
+
+ err = file_get_storage_info (file,
+ &ports, &num_ports,
+ &ints, &num_ints,
+ &offsets, &num_offsets,
+ &data, &data_len);
+
+ if (num_ints < 1)
+ grub_util_error (_("Storage info for `%s' does not include type"), dev);
+ if (ints[0] != STORAGE_DEVICE)
+ grub_util_error (_("`%s' is not a local disk"), dev);
+
+ if (num_offsets != 2)
+ grub_util_error (_("Storage info for `%s' does indicate neither plain partition nor plain disk"), dev);
+ if (parent)
+ {
+ *parent = NULL;
+ if (num_ints >= 5)
+ {
+ size_t len = ints[4];
+ if (len > data_len)
+ len = data_len;
+ *parent = xmalloc (len+1);
+ memcpy (*parent, data, len);
+ (*parent)[len] = '\0';
+ }
+ }
+ if (offset)
+ *offset = offsets[0];
+ if (size)
+ *size = offsets[1];
+ if (secsize)
+ *secsize = ints[2];
+ if (ports && num_ports > 0)
+ {
+ mach_msg_type_number_t i;
+ for (i = 0; i < num_ports; i++)
+ {
+ mach_port_t port = ports[i];
+ if (port != MACH_PORT_NULL)
+ mach_port_deallocate (mach_task_self(), port);
+ }
+ munmap ((caddr_t) ports, num_ports * sizeof (*ports));
+ }
+
+ if (ints && num_ints > 0)
+ munmap ((caddr_t) ints, num_ints * sizeof (*ints));
+ if (offsets && num_offsets > 0)
+ munmap ((caddr_t) offsets, num_offsets * sizeof (*offsets));
+ if (data && data_len > 0)
+ munmap (data, data_len);
+ mach_port_deallocate (mach_task_self (), file);
+
+ return 1;
+}
+
+grub_int64_t
+grub_util_get_fd_size_os (int fd, const char *name, unsigned *log_secsize)
+{
+ grub_uint32_t sector_size;
+ grub_disk_addr_t size;
+ unsigned log_sector_size;
+
+ if (!grub_util_hurd_get_disk_info (name, §or_size, NULL, &size, NULL))
+ 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;
+
+ return size << log_sector_size;
+}
+
+void
+grub_hostdisk_flush_initial_buffer (const char *os_dev __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>
+
+# include <sys/ioctl.h> /* ioctl */
+# include <sys/mount.h>
+# ifndef BLKFLSBUF
+# define BLKFLSBUF _IO (0x12,97) /* flush buffer cache */
+# endif /* ! BLKFLSBUF */
+# include <sys/ioctl.h> /* ioctl */
+# ifndef HDIO_GETGEO
+# define HDIO_GETGEO 0x0301 /* get device geometry */
+/* If HDIO_GETGEO is not defined, it is unlikely that hd_geometry is
+ defined. */
+struct hd_geometry
+{
+ unsigned char heads;
+ unsigned char sectors;
+ unsigned short cylinders;
+ unsigned long start;
+};
+# endif /* ! HDIO_GETGEO */
+# ifndef BLKGETSIZE64
+# define BLKGETSIZE64 _IOR(0x12,114,size_t) /* return device size */
+# endif /* ! BLKGETSIZE64 */
+
+
+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;
+}
+
+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;
+}
+
+/* Cache of partition start sectors for each disk. */
+struct linux_partition_cache
+{
+ struct linux_partition_cache *next;
+ struct linux_partition_cache **prev;
+ char *dev;
+ unsigned long start;
+ int partno;
+};
+
+struct linux_partition_cache *linux_partition_cache_list;
+
+/* Check if we have devfs support. */
+static int
+have_devfs (void)
+{
+ static int dev_devfsd_exists = -1;
+
+ if (dev_devfsd_exists < 0)
+ {
+ struct stat st;
+
+ dev_devfsd_exists = stat ("/dev/.devfsd", &st) == 0;
+ }
+
+ return dev_devfsd_exists;
+}
+
+int
+grub_hostdisk_linux_find_partition (char *dev, grub_disk_addr_t sector)
+{
+ size_t len = strlen (dev);
+ const char *format;
+ char *p;
+ int i;
+ char real_dev[PATH_MAX];
+ struct linux_partition_cache *cache;
+ int missing = 0;
+
+ strcpy(real_dev, dev);
+
+ if (have_devfs () && strcmp (real_dev + len - 5, "/disc") == 0)
+ {
+ p = real_dev + len - 4;
+ format = "part%d";
+ }
+ else if (strncmp (real_dev, "/dev/disk/by-id/",
+ sizeof ("/dev/disk/by-id/") - 1) == 0)
+ {
+ p = real_dev + len;
+ format = "-part%d";
+ }
+ else if (real_dev[len - 1] >= '0' && real_dev[len - 1] <= '9')
+ {
+ p = real_dev + len;
+ format = "p%d";
+ }
+ else
+ {
+ p = real_dev + len;
+ format = "%d";
+ }
+
+ for (cache = linux_partition_cache_list; cache; cache = cache->next)
+ {
+ if (strcmp (cache->dev, dev) == 0 && cache->start == sector)
+ {
+ sprintf (p, format, cache->partno);
+ strcpy (dev, real_dev);
+ return 1;
+ }
+ }
+
+ for (i = 1; i < 10000; i++)
+ {
+ int fd;
+ grub_disk_addr_t start;
+
+ sprintf (p, format, i);
+
+ fd = open (real_dev, O_RDONLY);
+ if (fd == -1)
+ {
+ if (missing++ < 10)
+ continue;
+ else
+ return 0;
+ }
+ missing = 0;
+ close (fd);
+
+ if (!grub_util_device_is_mapped (real_dev)
+ || !grub_util_get_dm_node_linear_info (real_dev, 0, 0, &start))
+ start = grub_util_find_partition_start_os (real_dev);
+ /* We don't care about errors here. */
+ grub_errno = GRUB_ERR_NONE;
+
+ if (start == sector)
+ {
+ struct linux_partition_cache *new_cache_item;
+
+ new_cache_item = xmalloc (sizeof *new_cache_item);
+ new_cache_item->dev = xstrdup (dev);
+ new_cache_item->start = start;
+ new_cache_item->partno = i;
+ grub_list_push (GRUB_AS_LIST_P (&linux_partition_cache_list),
+ GRUB_AS_LIST (new_cache_item));
+
+ strcpy (dev, real_dev);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+void
+grub_hostdisk_flush_initial_buffer (const char *os_dev)
+{
+ int fd;
+ struct stat st;
+
+ fd = open (os_dev, O_RDONLY);
+ if (fd >= 0 && fstat (fd, &st) >= 0 && S_ISBLK (st.st_mode))
+ ioctl (fd, BLKFLSBUF, 0);
+ if (fd >= 0)
+ close (fd);
+}
+
+void
+grub_hostdisk_configure_device_driver (int fd __attribute__ ((unused)))
+{
+}
--- /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)))
+{
+}
--- /dev/null
+#ifdef __linux__
+#include "hostdisk_linux.c"
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+#include "hostdisk_freebsd.c"
+#elif defined(__NetBSD__) || defined(__OpenBSD__)
+#include "hostdisk_bsd.c"
+#elif defined(__APPLE__)
+#include "hostdisk_apple.c"
+#elif defined(__sun__)
+#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"
+#else
+# warning "No hostdisk OS-specific functions is available for your system. Device detection may not work properly."
+#include "hostdisk_basic.c"
+#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 <sys/dkio.h>
+
+grub_int64_t
+grub_util_get_fd_size_os (int fd, const char *name, unsigned *log_secsize)
+{
+ struct dk_minfo minfo;
+ unsigned sector_size, log_sector_size;
+
+ if (!ioctl (fd, DKIOCGMEDIAINFO, &minfo))
+ return -1;
+
+ sector_size = minfo.dki_lbsize;
+
+ 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;
+
+ return minfo.dki_capacity << log_sector_size;
+}
+
+void
+grub_hostdisk_configure_device_driver (int fd __attribute__ ((unused)))
+{
+}
+
+void
+grub_hostdisk_flush_initial_buffer (const char *os_dev __attribute__ ((unused)))
+{
+}
#ifndef GRUB_UTIL_GETROOT_HEADER
#define GRUB_UTIL_GETROOT_HEADER 1
+#include <grub/types.h>
+
#include <sys/types.h>
enum grub_dev_abstraction_types {
};
char *grub_find_device (const char *dir, dev_t dev);
+void grub_util_pull_device (const char *osname);
char **grub_guess_root_devices (const char *dir);
int grub_util_get_dev_abstraction (const char *os_dev);
-char *grub_util_get_grub_dev (const char *os_dev);
char *grub_make_system_path_relative_to_its_root (const char *path);
const char *grub_util_check_block_device (const char *blk_dev);
const char *grub_util_check_char_device (const char *blk_dev);
+char *grub_util_get_grub_dev (const char *os_dev);
#ifdef __linux__
char **grub_util_raid_getmembers (const char *name, int bootable);
#endif
char **name_out);
#endif
+#include <sys/stat.h>
+
+#ifdef __linux__
+char **
+grub_find_root_devices_from_mountinfo (const char *dir, char **relroot);
+#endif
+#if defined (__GNU__)
+char *
+grub_util_find_hurd_root_device (const char *path);
+#endif
+
+/* Devmapper functions provided by getroot_devmapper.c. */
+void
+grub_util_pull_devmapper (const char *os_dev);
+int
+grub_util_device_is_mapped_stat (struct stat *st);
+void grub_util_devmapper_cleanup (void);
+enum grub_dev_abstraction_types
+grub_util_get_dm_abstraction (const char *os_dev);
+char *
+grub_util_get_vg_uuid (const char *os_dev);
+char *
+grub_util_devmapper_part_to_disk (struct stat *st,
+ int *is_part, const char *os_dev);
+char *
+grub_util_get_devmapper_grub_dev (const char *os_dev);
+
+/* Functions provided by getroot.c. */
+#if !defined (__MINGW32__) && !defined (__CYGWIN__) && !defined (__GNU__)
+#include <sys/types.h>
+pid_t
+grub_util_exec_pipe (char **argv, int *fd);
+#endif
+char **
+grub_util_find_root_devices_from_poolname (char *poolname);
+
+grub_disk_addr_t
+grub_util_find_partition_start (const char *dev);
+
+/* OS-specific functions provided by getroot_*.c. */
+enum grub_dev_abstraction_types
+grub_util_get_dev_abstraction_os (const char *os_dev);
+char *
+grub_util_part_to_disk (const char *os_dev, struct stat *st,
+ int *is_part);
+int
+grub_util_pull_device_os (const char *osname,
+ enum grub_dev_abstraction_types ab);
+char *
+grub_util_get_grub_dev_os (const char *os_dev);
+grub_disk_addr_t
+grub_util_find_partition_start_os (const char *dev);
+
#endif /* ! GRUB_UTIL_GETROOT_HEADER */
const char *
grub_util_biosdisk_get_compatibility_hint (grub_disk_t disk);
grub_err_t grub_util_biosdisk_flush (struct grub_disk *disk);
-void grub_util_pull_device (const char *osname);
grub_err_t
grub_util_fd_seek (int fd, const char *name, grub_uint64_t sector);
ssize_t grub_util_fd_read (int fd, char *buf, size_t len);
grub_embed_type_t embed_type,
grub_disk_addr_t **sectors);
#endif
-grub_disk_addr_t
-grub_hostdisk_find_partition_start (const char *dev);
const char *
grub_hostdisk_os_dev_to_grub_drive (const char *os_dev, int add);
char *
grub_util_get_os_disk (const char *os_dev);
-#ifdef HAVE_DEVICE_MAPPER
+#ifdef __linux__
+int
+grub_hostdisk_linux_find_partition (char *dev, grub_disk_addr_t sector);
+#endif
+
int
grub_util_get_dm_node_linear_info (const char *dev,
int *maj, int *min,
grub_disk_addr_t *st);
+
+
+/* Supplied by hostdisk_*.c. */
+grub_int64_t
+grub_util_get_fd_size_os (int 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);
+/* Adjust device driver parameters. This function should be called just
+ after successfully opening the device. For now, it simply prevents the
+ floppy driver from retrying operations on failure, as otherwise the
+ driver takes a while to abort when there is no floppy in the drive.
+ For now it's non-nop only on NetBSD.
+*/
+void
+grub_hostdisk_configure_device_driver (int fd);
+void
+grub_hostdisk_flush_initial_buffer (const char *os_dev);
+
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__NetBSD__) || defined (__sun__) || defined(__OpenBSD__)
+#define GRUB_DISK_DEVS_ARE_CHAR 1
+#else
+#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
#endif /* ! GRUB_BIOSDISK_MACHINE_UTIL_HEADER */
#ifndef GRUB_LVM_UTIL_HEADER
#define GRUB_LVM_UTIL_HEADER 1
-#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
-
-#ifdef __linux__
-#define LVM_DEV_MAPPER_STRING "/dev/mapper/"
-#else
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
#define LVM_DEV_MAPPER_STRING "/dev/linux_lvm/"
-#endif
-
+#else
+#define LVM_DEV_MAPPER_STRING "/dev/mapper/"
#endif
#endif /* ! GRUB_RAID_UTIL_HEADER */
#include <grub/cryptodisk.h>
#include <grub/i18n.h>
-#ifdef HAVE_DEVICE_MAPPER
-# include <libdevmapper.h>
+#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
#ifdef __GNU__
#include <sys/types.h>
-#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__)
-# include <sys/param.h>
-# include <sys/mount.h>
-#endif
-
#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR)
# include <grub/util/libzfs.h>
# include <grub/util/libnvpair.h>
#endif
-#ifdef __sun__
-# include <sys/types.h>
-# include <sys/mkdev.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>
-#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
-
#ifdef __CYGWIN__
# include <sys/ioctl.h>
# include <cygwin/fs.h> /* BLKGETSIZE64 */
#endif
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
-# include <sys/disk.h> /* DIOCGMEDIASIZE */
-# include <sys/param.h>
-# include <sys/sysctl.h>
-# include <sys/mount.h>
-#include <libgeom.h>
# define MAJOR(dev) major(dev)
# define FLOPPY_MAJOR 2
#endif
-#if defined (__sun__)
-# include <sys/dkio.h>
-#endif
-
-#if defined(__APPLE__)
-# include <sys/disk.h>
-# include <sys/param.h>
-# include <sys/sysctl.h>
-# include <sys/mount.h>
-#endif
-
-#ifdef HAVE_DEVICE_MAPPER
-# include <libdevmapper.h>
+#if defined (__FreeBSD__) || defined (__FreeBSD_kernel__)
+#include <sys/mount.h>
#endif
#if defined(__NetBSD__) || defined(__OpenBSD__)
-# define HAVE_DIOCGDINFO
# include <sys/ioctl.h>
# include <sys/disklabel.h> /* struct disklabel */
# include <sys/disk.h> /* struct dkwedge_info */
-#else /* !defined(__NetBSD__) && !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__) */
-# undef HAVE_DIOCGDINFO
+#include <sys/param.h>
+#include <sys/mount.h>
#endif /* defined(__NetBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) */
-#if defined(__NetBSD__) || defined(__OpenBSD__)
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+# define MAJOR(dev) major(dev)
# ifdef HAVE_GETRAWPARTITION
# include <util.h> /* getrawpartition */
# endif /* HAVE_GETRAWPARTITION */
# endif /* ! RAW_FLOPPY_MAJOR */
#endif /* defined(__NetBSD__) */
-#ifdef __linux__
-/* Defines taken from btrfs/ioctl.h. */
-
-struct btrfs_ioctl_dev_info_args
-{
- grub_uint64_t devid;
- grub_uint8_t uuid[16];
- grub_uint64_t bytes_used;
- grub_uint64_t total_bytes;
- grub_uint64_t unused[379];
- grub_uint8_t path[1024];
-};
-
-struct btrfs_ioctl_fs_info_args
-{
- grub_uint64_t max_id;
- grub_uint64_t num_devices;
- grub_uint8_t fsid[16];
- grub_uint64_t reserved[124];
-};
-
-#define BTRFS_IOC_DEV_INFO _IOWR(0x94, 30, \
- struct btrfs_ioctl_dev_info_args)
-#define BTRFS_IOC_FS_INFO _IOR(0x94, 31, \
- struct btrfs_ioctl_fs_info_args)
-#endif
+#if !defined (__MINGW32__) && !defined (__CYGWIN__)
-#ifdef __linux__
-static int
-grub_util_is_imsm (const char *os_dev);
+static void
+pull_lvm_by_command (const char *os_dev);
#endif
-#if ! defined(__CYGWIN__) && !defined(__GNU__)
+#if ! defined(__CYGWIN__)
static void
strip_extra_slashes (char *dir)
#endif
-#if !defined (__MINGW32__) && !defined (__CYGWIN__) && !defined (__GNU__)
+#if !defined (__MINGW32__) && !defined (__CYGWIN__)
#include <sys/types.h>
#include <sys/wait.h>
-static pid_t
-exec_pipe (char **argv, int *fd)
+pid_t
+grub_util_exec_pipe (char **argv, int *fd)
{
int mdadm_pipe[2];
pid_t mdadm_pid;
/* Child. */
/* Close fd's. */
-#ifdef HAVE_DEVICE_MAPPER
- dm_lib_release ();
-#endif
+ grub_util_devmapper_cleanup ();
grub_diskfilter_fini ();
/* Ensure child is not localised. */
}
}
-static char **
-find_root_devices_from_poolname (char *poolname)
+#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;
argv[2] = (char *) poolname;
argv[3] = NULL;
- pid = exec_pipe (argv, &fd);
+ pid = grub_util_exec_pipe (argv, &fd);
if (!pid)
return NULL;
#endif
-#ifdef __linux__
-
-#define ESCAPED_PATH_MAX (4 * PATH_MAX)
-struct mountinfo_entry
-{
- int id;
- int major, minor;
- char enc_root[ESCAPED_PATH_MAX + 1], enc_path[ESCAPED_PATH_MAX + 1];
- char fstype[ESCAPED_PATH_MAX + 1], device[ESCAPED_PATH_MAX + 1];
-};
-
-/* Statting something on a btrfs filesystem always returns a virtual device
- major/minor pair rather than the real underlying device, because btrfs
- can span multiple underlying devices (and even if it's currently only
- using a single device it can be dynamically extended onto another). We
- can't deal with the multiple-device case yet, but in the meantime, we can
- at least cope with the single-device case by scanning
- /proc/self/mountinfo. */
-static void
-unescape (char *str)
-{
- char *optr;
- const char *iptr;
- for (iptr = optr = str; *iptr; optr++)
- {
- if (iptr[0] == '\\' && iptr[1] >= '0' && iptr[1] < '8'
- && iptr[2] >= '0' && iptr[2] < '8'
- && iptr[3] >= '0' && iptr[3] < '8')
- {
- *optr = (((iptr[1] - '0') << 6) | ((iptr[2] - '0') << 3)
- | (iptr[3] - '0'));
- iptr += 4;
- }
- else
- *optr = *iptr++;
- }
- *optr = 0;
-}
-
-static char **
-grub_find_root_devices_from_btrfs (const char *dir)
-{
- int fd;
- struct btrfs_ioctl_fs_info_args fsi;
- int i, j = 0;
- char **ret;
-
- fd = open (dir, 0);
- if (!fd)
- return NULL;
-
- if (ioctl (fd, BTRFS_IOC_FS_INFO, &fsi) < 0)
- {
- close (fd);
- return NULL;
- }
-
- ret = xmalloc ((fsi.num_devices + 1) * sizeof (ret[0]));
-
- for (i = 1; i <= fsi.max_id && j < fsi.num_devices; i++)
- {
- struct btrfs_ioctl_dev_info_args devi;
- memset (&devi, 0, sizeof (devi));
- devi.devid = i;
- if (ioctl (fd, BTRFS_IOC_DEV_INFO, &devi) < 0)
- {
- close (fd);
- free (ret);
- return NULL;
- }
- ret[j++] = xstrdup ((char *) devi.path);
- if (j >= fsi.num_devices)
- break;
- }
- close (fd);
- ret[j] = 0;
- return ret;
-}
-
-static char **
-grub_find_root_devices_from_mountinfo (const char *dir, char **relroot)
-{
- FILE *fp;
- char *buf = NULL;
- size_t len = 0;
- grub_size_t entry_len = 0, entry_max = 4;
- struct mountinfo_entry *entries;
- struct mountinfo_entry parent_entry = { 0, 0, 0, "", "", "", "" };
- int i;
-
- if (! *dir)
- dir = "/";
- if (relroot)
- *relroot = NULL;
-
- fp = fopen ("/proc/self/mountinfo", "r");
- if (! fp)
- return NULL; /* fall through to other methods */
-
- entries = xmalloc (entry_max * sizeof (*entries));
-
- /* First, build a list of relevant visible mounts. */
- while (getline (&buf, &len, fp) > 0)
- {
- struct mountinfo_entry entry;
- int count;
- size_t enc_path_len;
- const char *sep;
-
- if (sscanf (buf, "%d %d %u:%u %s %s%n",
- &entry.id, &parent_entry.id, &entry.major, &entry.minor,
- entry.enc_root, entry.enc_path, &count) < 6)
- continue;
-
- unescape (entry.enc_root);
- unescape (entry.enc_path);
-
- enc_path_len = strlen (entry.enc_path);
- /* Check that enc_path is a prefix of dir. The prefix must either be
- the entire string, or end with a slash, or be immediately followed
- by a slash. */
- if (strncmp (dir, entry.enc_path, enc_path_len) != 0 ||
- (enc_path_len && dir[enc_path_len - 1] != '/' &&
- dir[enc_path_len] && dir[enc_path_len] != '/'))
- continue;
-
- sep = strstr (buf + count, " - ");
- if (!sep)
- continue;
-
- sep += sizeof (" - ") - 1;
- if (sscanf (sep, "%s %s", entry.fstype, entry.device) != 2)
- continue;
-
- unescape (entry.device);
-
- /* Using the mount IDs, find out where this fits in the list of
- visible mount entries we've seen so far. There are three
- interesting cases. Firstly, it may be inserted at the end: this is
- the usual case of /foo/bar being mounted after /foo. Secondly, it
- may be inserted at the start: for example, this can happen for
- filesystems that are mounted before / and later moved under it.
- Thirdly, it may occlude part or all of the existing filesystem
- tree, in which case the end of the list needs to be pruned and this
- new entry will be inserted at the end. */
- if (entry_len >= entry_max)
- {
- entry_max <<= 1;
- entries = xrealloc (entries, entry_max * sizeof (*entries));
- }
-
- if (!entry_len)
- {
- /* Initialise list. */
- entry_len = 2;
- entries[0] = parent_entry;
- entries[1] = entry;
- }
- else
- {
- for (i = entry_len - 1; i >= 0; i--)
- {
- if (entries[i].id == parent_entry.id)
- {
- /* Insert at end, pruning anything previously above this. */
- entry_len = i + 2;
- entries[i + 1] = entry;
- break;
- }
- else if (i == 0 && entries[i].id == entry.id)
- {
- /* Insert at start. */
- entry_len++;
- memmove (entries + 1, entries,
- (entry_len - 1) * sizeof (*entries));
- entries[0] = parent_entry;
- entries[1] = entry;
- break;
- }
- }
- }
- }
-
- /* Now scan visible mounts for the ones we're interested in. */
- for (i = entry_len - 1; i >= 0; i--)
- {
- char **ret = NULL;
- if (!*entries[i].device)
- continue;
-
- if (grub_strcmp (entries[i].fstype, "fuse.zfs") == 0
- || grub_strcmp (entries[i].fstype, "zfs") == 0)
- {
- char *slash;
- slash = strchr (entries[i].device, '/');
- if (slash)
- *slash = 0;
- ret = find_root_devices_from_poolname (entries[i].device);
- if (slash)
- *slash = '/';
- if (relroot)
- {
- if (!slash)
- *relroot = xasprintf ("/@%s", entries[i].enc_root);
- else if (strchr (slash + 1, '@'))
- *relroot = xasprintf ("/%s%s", slash + 1, entries[i].enc_root);
- else
- *relroot = xasprintf ("/%s@%s", slash + 1, entries[i].enc_root);
- }
- }
- else if (grub_strcmp (entries[i].fstype, "btrfs") == 0)
- {
- ret = grub_find_root_devices_from_btrfs (dir);
- if (relroot)
- {
- char *ptr;
- *relroot = xmalloc (strlen (entries[i].enc_root) +
- 2 + strlen (dir));
- ptr = grub_stpcpy (*relroot, entries[i].enc_root);
- if (strlen (dir) > strlen (entries[i].enc_path))
- {
- while (ptr > *relroot && *(ptr - 1) == '/')
- ptr--;
- if (dir[strlen (entries[i].enc_path)] != '/')
- *ptr++ = '/';
- ptr = grub_stpcpy (ptr, dir + strlen (entries[i].enc_path));
- }
- *ptr = 0;
- }
- }
- if (!ret)
- {
- ret = xmalloc (2 * sizeof (ret[0]));
- ret[0] = strdup (entries[i].device);
- ret[1] = 0;
- if (relroot)
- *relroot = strdup (entries[i].enc_root);
- }
- free (buf);
- free (entries);
- fclose (fp);
- return ret;
- }
-
- free (buf);
- free (entries);
- fclose (fp);
- return NULL;
-}
-
-#endif /* __linux__ */
-
#if !defined (__MINGW32__) && !defined (__CYGWIN__) && !defined (__GNU__)
static char **
if (! poolname)
return NULL;
- devices = find_root_devices_from_poolname (poolname);
+ devices = grub_util_find_root_devices_from_poolname (poolname);
free (poolname);
if (poolfs)
return 0;
}
-#elif defined (__GNU__)
-
-static char *
-find_hurd_root_device (const char *path)
-{
- file_t file;
- error_t err;
- char *argz = NULL, *name = NULL, *ret;
- size_t argz_len = 0;
- int i;
-
- file = file_name_lookup (path, 0, 0);
- if (file == MACH_PORT_NULL)
- /* TRANSLATORS: The first %s is the file being looked at, the second %s is
- the error message. */
- grub_util_error (_("cannot open `%s': %s"), path, strerror (errno));
-
- /* This returns catenated 0-terminated strings. */
- err = file_get_fs_options (file, &argz, &argz_len);
- if (err)
- /* TRANSLATORS: On GNU/Hurd, a "translator" is similar to a filesystem
- mount, but handled by a userland daemon, whose invocation command line
- is being fetched here. First %s is the file being looked at (for which
- we are fetching the "translator" command line), second %s is the error
- message.
- */
- grub_util_error (_("cannot get translator command line "
- "for path `%s': %s"), path, strerror(err));
- if (argz_len == 0)
- grub_util_error (_("translator command line is empty for path `%s'"), path);
-
- /* Make sure the string is terminated. */
- argz[argz_len-1] = 0;
-
- /* Skip first word (translator path) and options. */
- for (i = strlen (argz) + 1; i < argz_len; i += strlen (argz + i) + 1)
- {
- if (argz[i] != '-')
- {
- /* Non-option. Only accept one, assumed to be the FS path. */
- /* XXX: this should be replaced by an RPC to the translator. */
- if (name)
- /* TRANSLATORS: we expect to get something like
- /hurd/foobar --option1 --option2=baz /dev/something
- */
- grub_util_error (_("translator `%s' for path `%s' has several "
- "non-option words, at least `%s' and `%s'"),
- argz, path, name, argz + i);
- name = argz + i;
- }
- }
-
- if (!name)
- /* TRANSLATORS: we expect to get something like
- /hurd/foobar --option1 --option2=baz /dev/something
- */
- grub_util_error (_("translator `%s' for path `%s' is given only options, "
- "cannot find device part"), argz, path);
-
- if (strncmp (name, "device:", sizeof ("device:") - 1) == 0)
- {
- char *dev_name = name + sizeof ("device:") - 1;
- size_t size = sizeof ("/dev/") - 1 + strlen (dev_name) + 1;
- char *next;
- ret = malloc (size);
- next = stpncpy (ret, "/dev/", size);
- stpncpy (next, dev_name, size - (next - ret));
- }
- else if (!strncmp (name, "file:", sizeof ("file:") - 1))
- ret = strdup (name + sizeof ("file:") - 1);
- else
- ret = strdup (name);
-
- munmap (argz, argz_len);
- return ret;
-}
-
#elif ! defined(__CYGWIN__)
char *
/* Found! */
char *res;
char *cwd;
-#if defined(__NetBSD__)
+#if defined(__NetBSD__) || defined(__OpenBSD__)
/* Convert this block device to its character (raw) device. */
const char *template = "%s/r%s";
#else
#elif defined __GNU__
/* GNU/Hurd specific function. */
- os_dev[0] = find_hurd_root_device (dir);
+ os_dev[0] = grub_util_find_hurd_root_device (dir);
#else
return os_dev;
}
-#ifdef HAVE_DEVICE_MAPPER
-
-static int
-grub_util_open_dm (const char *os_dev, struct dm_tree **tree,
- struct dm_tree_node **node)
+grub_disk_addr_t
+grub_util_find_partition_start (const char *dev)
{
- uint32_t maj, min;
- struct stat st;
-
- *node = NULL;
- *tree = NULL;
-
- if (stat (os_dev, &st) < 0)
- return 0;
+ grub_disk_addr_t partition_start;
+ if (grub_util_device_is_mapped (dev)
+ && grub_util_get_dm_node_linear_info (dev, 0, 0, &partition_start))
+ return partition_start;
- maj = major (st.st_rdev);
- min = minor (st.st_rdev);
-
- if (!dm_is_dm_major (maj))
- return 0;
-
- *tree = dm_tree_create ();
- if (! *tree)
- {
- grub_puts_ (N_("Failed to create `device-mapper' tree"));
- grub_dprintf ("hostdisk", "dm_tree_create failed\n");
- return 0;
- }
-
- if (! dm_tree_add_dev (*tree, maj, min))
- {
- grub_dprintf ("hostdisk", "dm_tree_add_dev failed\n");
- dm_tree_free (*tree);
- *tree = NULL;
- return 0;
- }
-
- *node = dm_tree_find_node (*tree, maj, min);
- if (! *node)
- {
- grub_dprintf ("hostdisk", "dm_tree_find_node failed\n");
- dm_tree_free (*tree);
- *tree = NULL;
- return 0;
- }
- return 1;
+ return grub_util_find_partition_start_os (dev);
}
-#endif
-
-#ifdef HAVE_DEVICE_MAPPER
-static char *
-get_dm_uuid (const char *os_dev)
+void
+grub_util_pull_device (const char *os_dev)
{
- struct dm_tree *tree;
- struct dm_tree_node *node;
- const char *node_uuid;
- char *ret;
-
- if (!grub_util_open_dm (os_dev, &tree, &node))
- return NULL;
-
- node_uuid = dm_tree_node_get_uuid (node);
- if (! node_uuid)
+ enum grub_dev_abstraction_types ab;
+ ab = grub_util_get_dev_abstraction (os_dev);
+ switch (ab)
{
- grub_dprintf ("hostdisk", "%s has no DM uuid\n", os_dev);
- dm_tree_free (tree);
- return NULL;
- }
-
- ret = grub_strdup (node_uuid);
-
- dm_tree_free (tree);
-
- return ret;
-}
+ case GRUB_DEV_ABSTRACTION_LVM:
+#if !defined (__MINGW32__) && !defined (__CYGWIN__)
+ pull_lvm_by_command (os_dev);
#endif
+ /* Fallthrough in case that lvm-tools are unavailable. */
+ case GRUB_DEV_ABSTRACTION_LUKS:
+ grub_util_pull_devmapper (os_dev);
+ return;
-#ifdef __linux__
-
-static enum grub_dev_abstraction_types
-grub_util_get_dm_abstraction (const char *os_dev)
-{
-#ifdef HAVE_DEVICE_MAPPER
- char *uuid;
-
- uuid = get_dm_uuid (os_dev);
-
- if (uuid == NULL)
- return GRUB_DEV_ABSTRACTION_NONE;
-
- if (strncmp (uuid, "LVM-", 4) == 0)
- {
- grub_free (uuid);
- return GRUB_DEV_ABSTRACTION_LVM;
- }
- if (strncmp (uuid, "CRYPT-LUKS1-", 4) == 0)
- {
- grub_free (uuid);
- return GRUB_DEV_ABSTRACTION_LUKS;
+ default:
+ if (grub_util_pull_device_os (os_dev, ab))
+ return;
+ case GRUB_DEV_ABSTRACTION_NONE:
+ free (grub_util_biosdisk_get_grub_dev (os_dev));
+ return;
}
-
- grub_free (uuid);
- return GRUB_DEV_ABSTRACTION_NONE;
-#else
- if ((strncmp ("/dev/mapper/", os_dev, 12) != 0))
- return GRUB_DEV_ABSTRACTION_NONE;
- return GRUB_DEV_ABSTRACTION_LVM;
-#endif
}
-#endif
-
-#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
-#include <libgeom.h>
-
-static const char *
-grub_util_get_geom_abstraction (const char *dev)
+char *
+grub_util_get_grub_dev (const char *os_dev)
{
- char *whole;
- struct gmesh mesh;
- struct gclass *class;
- const char *name;
- int err;
-
- if (strncmp (dev, "/dev/", sizeof ("/dev/") - 1) != 0)
- return 0;
- name = dev + sizeof ("/dev/") - 1;
- grub_util_follow_gpart_up (name, NULL, &whole);
-
- grub_util_info ("following geom '%s'", name);
+ char *ret;
- err = geom_gettree (&mesh);
- if (err != 0)
- /* TRANSLATORS: geom is the name of (k)FreeBSD device framework.
- Usually left untranslated.
- */
- grub_util_error ("%s", _("couldn't open geom"));
+ grub_util_pull_device (os_dev);
- LIST_FOREACH (class, &mesh.lg_class, lg_class)
- {
- struct ggeom *geom;
- LIST_FOREACH (geom, &class->lg_geom, lg_geom)
- {
- struct gprovider *provider;
- LIST_FOREACH (provider, &geom->lg_provider, lg_provider)
- if (strcmp (provider->lg_name, name) == 0)
- return class->lg_name;
- }
- }
- return NULL;
+ ret = grub_util_get_devmapper_grub_dev (os_dev);
+ if (ret)
+ return ret;
+ ret = grub_util_get_grub_dev_os (os_dev);
+ if (ret)
+ return ret;
+ return grub_util_biosdisk_get_grub_dev (os_dev);
}
-#endif
+
int
grub_util_get_dev_abstraction (const char *os_dev)
{
-#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+ enum grub_dev_abstraction_types ret;
+
/* User explicitly claims that this drive is visible by BIOS. */
if (grub_util_biosdisk_is_present (os_dev))
return GRUB_DEV_ABSTRACTION_NONE;
-#endif
-
-#ifdef __linux__
- enum grub_dev_abstraction_types ret;
/* Check for LVM and LUKS. */
ret = grub_util_get_dm_abstraction (os_dev);
if (ret != GRUB_DEV_ABSTRACTION_NONE)
return ret;
- /* Check for RAID. */
- if (!strncmp (os_dev, "/dev/md", 7) && ! grub_util_device_is_mapped (os_dev)
- && !grub_util_is_imsm (os_dev))
- return GRUB_DEV_ABSTRACTION_RAID;
-#endif
-
-#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
- const char *abstrac;
- abstrac = grub_util_get_geom_abstraction (os_dev);
- grub_util_info ("abstraction of %s is %s", os_dev, abstrac);
- if (abstrac && grub_strcasecmp (abstrac, "eli") == 0)
- return GRUB_DEV_ABSTRACTION_GELI;
-
- /* Check for LVM. */
- if (!strncmp (os_dev, LVM_DEV_MAPPER_STRING, sizeof(LVM_DEV_MAPPER_STRING)-1))
- return GRUB_DEV_ABSTRACTION_LVM;
-#endif
-
- /* No abstraction found. */
- return GRUB_DEV_ABSTRACTION_NONE;
+ return grub_util_get_dev_abstraction_os (os_dev);
}
-#if !defined (__MINGW32__) && !defined (__CYGWIN__) && !defined (__GNU__)
+#if !defined (__MINGW32__) && !defined (__CYGWIN__)
static void
pull_lvm_by_command (const char *os_dev)
char *vgid = NULL;
grub_size_t vgidlen = 0;
-#ifdef HAVE_DEVICE_MAPPER
- char *uuid;
-
- uuid = get_dm_uuid (os_dev);
- if (uuid)
- {
- int dashes[] = { 0, 6, 10, 14, 18, 22, 26, 32};
- unsigned i;
- vgid = xmalloc (grub_strlen (uuid));
- optr = vgid;
- for (i = 0; i < ARRAY_SIZE (dashes) - 1; i++)
- {
- memcpy (optr, uuid + sizeof ("LVM-") - 1 + dashes[i],
- dashes[i+1] - dashes[i]);
- optr += dashes[i+1] - dashes[i];
- *optr++ = '-';
- }
- optr--;
- *optr = '\0';
- vgidlen = optr - vgid;
- }
-#endif
+ vgid = grub_util_get_vg_uuid (os_dev);
+ if (vgid)
+ vgidlen = grub_strlen (vgid);
if (!vgid)
{
argv[6] = vgname;
argv[7] = NULL;
- pid = exec_pipe (argv, &fd);
+ pid = grub_util_exec_pipe (argv, &fd);
free (vgname);
if (!pid)
#endif
-#ifdef __linux__
-static char *
-get_mdadm_uuid (const char *os_dev)
-{
- char *argv[5];
- int fd;
- pid_t pid;
- FILE *mdadm;
- char *buf = NULL;
- size_t len = 0;
- char *name = NULL;
-
- /* execvp has inconvenient types, hence the casts. None of these
- strings will actually be modified. */
- argv[0] = (char *) "mdadm";
- argv[1] = (char *) "--detail";
- argv[2] = (char *) "--export";
- argv[3] = (char *) os_dev;
- argv[4] = NULL;
-
- pid = exec_pipe (argv, &fd);
-
- if (!pid)
- return NULL;
-
- /* Parent. Read mdadm's output. */
- mdadm = fdopen (fd, "r");
- if (! mdadm)
- {
- grub_util_warn (_("Unable to open stream from %s: %s"),
- "mdadm", strerror (errno));
- goto out;
- }
-
- while (getline (&buf, &len, mdadm) > 0)
- {
- if (strncmp (buf, "MD_UUID=", sizeof ("MD_UUID=") - 1) == 0)
- {
- char *name_start, *ptri, *ptro;
-
- free (name);
- name_start = buf + sizeof ("MD_UUID=") - 1;
- ptro = name = xmalloc (strlen (name_start) + 1);
- for (ptri = name_start; *ptri && *ptri != '\n' && *ptri != '\r';
- ptri++)
- if ((*ptri >= '0' && *ptri <= '9')
- || (*ptri >= 'a' && *ptri <= 'f')
- || (*ptri >= 'A' && *ptri <= 'F'))
- *ptro++ = *ptri;
- *ptro = 0;
- }
- }
-
-out:
- close (fd);
- waitpid (pid, NULL, 0);
- free (buf);
-
- return name;
-}
-
-static int
-grub_util_is_imsm (const char *os_dev)
-{
- int retry;
- int is_imsm = 0;
- int container_seen = 0;
- const char *dev = os_dev;
-
- do
- {
- char *argv[5];
- int fd;
- pid_t pid;
- FILE *mdadm;
- char *buf = NULL;
- size_t len = 0;
-
- retry = 0; /* We'll do one more pass if device is part of container */
-
- /* execvp has inconvenient types, hence the casts. None of these
- strings will actually be modified. */
- argv[0] = (char *) "mdadm";
- argv[1] = (char *) "--detail";
- argv[2] = (char *) "--export";
- argv[3] = (char *) dev;
- argv[4] = NULL;
-
- pid = exec_pipe (argv, &fd);
-
- if (!pid)
- {
- if (dev != os_dev)
- free ((void *) dev);
- return 0;
- }
-
- /* Parent. Read mdadm's output. */
- mdadm = fdopen (fd, "r");
- if (! mdadm)
- {
- grub_util_warn (_("Unable to open stream from %s: %s"),
- "mdadm", strerror (errno));
- close (fd);
- waitpid (pid, NULL, 0);
- if (dev != os_dev)
- free ((void *) dev);
- return 0;
- }
-
- while (getline (&buf, &len, mdadm) > 0)
- {
- if (strncmp (buf, "MD_CONTAINER=", sizeof ("MD_CONTAINER=") - 1) == 0
- && !container_seen)
- {
- char *newdev, *ptr;
- newdev = xstrdup (buf + sizeof ("MD_CONTAINER=") - 1);
- ptr = newdev + strlen (newdev) - 1;
- for (; ptr >= newdev && (*ptr == '\n' || *ptr == '\r'); ptr--);
- ptr[1] = 0;
- grub_util_info ("Container of %s is %s", dev, newdev);
- dev = newdev;
- container_seen = retry = 1;
- break;
- }
- if (strncmp (buf, "MD_METADATA=imsm",
- sizeof ("MD_METADATA=imsm") - 1) == 0)
- {
- is_imsm = 1;
- grub_util_info ("%s is imsm", dev);
- break;
- }
- }
-
- free (buf);
- close (fd);
- waitpid (pid, NULL, 0);
- }
- while (retry);
-
- if (dev != os_dev)
- free ((void *) dev);
- return is_imsm;
-}
-#endif /* __linux__ */
-
-void
-grub_util_pull_device (const char *os_dev)
-{
- int ab;
- ab = grub_util_get_dev_abstraction (os_dev);
- switch (ab)
- {
- case GRUB_DEV_ABSTRACTION_GELI:
-#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
- {
- char *whole;
- struct gmesh mesh;
- struct gclass *class;
- const char *name;
- int err;
- char *lastsubdev = NULL;
-
- if (strncmp (os_dev, "/dev/", sizeof ("/dev/") - 1) != 0)
- return;
- name = os_dev + sizeof ("/dev/") - 1;
- grub_util_follow_gpart_up (name, NULL, &whole);
-
- grub_util_info ("following geom '%s'", name);
-
- err = geom_gettree (&mesh);
- if (err != 0)
- /* TRANSLATORS: geom is the name of (k)FreeBSD device framework.
- Usually left untranslated.
- */
- grub_util_error ("%s", _("couldn't open geom"));
-
- LIST_FOREACH (class, &mesh.lg_class, lg_class)
- {
- struct ggeom *geom;
- LIST_FOREACH (geom, &class->lg_geom, lg_geom)
- {
- struct gprovider *provider;
- LIST_FOREACH (provider, &geom->lg_provider, lg_provider)
- if (strcmp (provider->lg_name, name) == 0)
- {
- struct gconsumer *consumer;
- char *fname;
-
- LIST_FOREACH (consumer, &geom->lg_consumer, lg_consumer)
- break;
- if (!consumer)
- grub_util_error ("%s",
- _("couldn't find geli consumer"));
- fname = xasprintf ("/dev/%s", consumer->lg_provider->lg_name);
- grub_util_info ("consumer %s", consumer->lg_provider->lg_name);
- lastsubdev = consumer->lg_provider->lg_name;
- grub_util_pull_device (fname);
- free (fname);
- }
- }
- }
- if (ab == GRUB_DEV_ABSTRACTION_GELI && lastsubdev)
- {
- char *fname = xasprintf ("/dev/%s", lastsubdev);
- char *grdev = grub_util_get_grub_dev (fname);
- free (fname);
-
- if (grdev)
- {
- grub_err_t gr_err;
- gr_err = grub_cryptodisk_cheat_mount (grdev, os_dev);
- if (gr_err)
- grub_util_error (_("can't mount encrypted volume `%s': %s"),
- lastsubdev, grub_errmsg);
- }
-
- grub_free (grdev);
- }
- }
-#endif
- break;
-
- case GRUB_DEV_ABSTRACTION_LVM:
-#if !defined (__MINGW32__) && !defined (__CYGWIN__) && !defined (__GNU__)
- pull_lvm_by_command (os_dev);
-#endif
- /* Fallthrough in case that lvm-tools are unavailable. */
- case GRUB_DEV_ABSTRACTION_LUKS:
-#ifdef HAVE_DEVICE_MAPPER
- {
- struct dm_tree *tree;
- struct dm_tree_node *node;
- struct dm_tree_node *child;
- void *handle = NULL;
- char *lastsubdev = NULL;
-
- if (!grub_util_open_dm (os_dev, &tree, &node))
- return;
-
- while ((child = dm_tree_next_child (&handle, node, 0)))
- {
- const struct dm_info *dm = dm_tree_node_get_info (child);
- char *subdev;
- if (!dm)
- continue;
- subdev = grub_find_device ("/dev", makedev (dm->major, dm->minor));
- if (subdev)
- {
- lastsubdev = subdev;
- grub_util_pull_device (subdev);
- }
- }
- if (ab == GRUB_DEV_ABSTRACTION_LUKS && lastsubdev)
- {
- char *grdev = grub_util_get_grub_dev (lastsubdev);
- dm_tree_free (tree);
- if (grdev)
- {
- grub_err_t err;
- err = grub_cryptodisk_cheat_mount (grdev, os_dev);
- if (err)
- grub_util_error (_("can't mount encrypted volume `%s': %s"),
- lastsubdev, grub_errmsg);
- }
- grub_free (grdev);
- }
- else
- dm_tree_free (tree);
- }
-#endif
- return;
- case GRUB_DEV_ABSTRACTION_RAID:
-#ifdef __linux__
- {
- char **devicelist = grub_util_raid_getmembers (os_dev, 0);
- int i;
- for (i = 0; devicelist[i];i++)
- {
- grub_util_pull_device (devicelist[i]);
- free (devicelist[i]);
- }
- free (devicelist);
- }
-#endif
- return;
-
- default: /* GRUB_DEV_ABSTRACTION_NONE */
- free (grub_util_biosdisk_get_grub_dev (os_dev));
- return;
- }
-}
-
int
grub_util_biosdisk_is_floppy (grub_disk_t disk)
{
{
*is_part = 0;
-#if defined(__linux__)
- char *path = xmalloc (PATH_MAX);
-
- if (! realpath (os_dev, path))
- return NULL;
-
- if (strncmp ("/dev/", path, 5) == 0)
- {
- char *p = path + 5;
-
- /* If this is an IDE disk. */
- if (strncmp ("ide/", p, 4) == 0)
- {
- p = strstr (p, "part");
- if (p)
- {
- *is_part = 1;
- strcpy (p, "disc");
- }
-
- return path;
- }
-
- /* If this is a SCSI disk. */
- if (strncmp ("scsi/", p, 5) == 0)
- {
- p = strstr (p, "part");
- if (p)
- {
- *is_part = 1;
- strcpy (p, "disc");
- }
-
- return path;
- }
-
- /* If this is a DAC960 disk. */
- if (strncmp ("rd/c", p, 4) == 0)
- {
- /* /dev/rd/c[0-9]+d[0-9]+(p[0-9]+)? */
- p = strchr (p, 'p');
- if (p)
- {
- *is_part = 1;
- *p = '\0';
- }
-
- return path;
- }
-
- /* If this is a Mylex AcceleRAID Array. */
- if (strncmp ("rs/c", p, 4) == 0)
- {
- /* /dev/rd/c[0-9]+d[0-9]+(p[0-9]+)? */
- p = strchr (p, 'p');
- if (p)
- {
- *is_part = 1;
- *p = '\0';
- }
-
- return path;
- }
- /* If this is a CCISS disk. */
- if (strncmp ("cciss/c", p, sizeof ("cciss/c") - 1) == 0)
- {
- /* /dev/cciss/c[0-9]+d[0-9]+(p[0-9]+)? */
- p = strchr (p, 'p');
- if (p)
- {
- *is_part = 1;
- *p = '\0';
- }
-
- return path;
- }
-
- /* If this is an AOE disk. */
- if (strncmp ("etherd/e", p, sizeof ("etherd/e") - 1) == 0)
- {
- /* /dev/etherd/e[0-9]+\.[0-9]+(p[0-9]+)? */
- p = strchr (p, 'p');
- if (p)
- {
- *is_part = 1;
- *p = '\0';
- }
-
- return path;
- }
-
- /* If this is a Compaq Intelligent Drive Array. */
- if (strncmp ("ida/c", p, sizeof ("ida/c") - 1) == 0)
- {
- /* /dev/ida/c[0-9]+d[0-9]+(p[0-9]+)? */
- p = strchr (p, 'p');
- if (p)
- {
- *is_part = 1;
- *p = '\0';
- }
-
- return path;
- }
-
- /* If this is an I2O disk. */
- if (strncmp ("i2o/hd", p, sizeof ("i2o/hd") - 1) == 0)
- {
- /* /dev/i2o/hd[a-z]([0-9]+)? */
- if (p[sizeof ("i2o/hda") - 1])
- *is_part = 1;
- p[sizeof ("i2o/hda") - 1] = '\0';
- return path;
- }
-
- /* If this is a MultiMediaCard (MMC). */
- if (strncmp ("mmcblk", p, sizeof ("mmcblk") - 1) == 0)
- {
- /* /dev/mmcblk[0-9]+(p[0-9]+)? */
- p = strchr (p, 'p');
- if (p)
- {
- *is_part = 1;
- *p = '\0';
- }
-
- return path;
- }
-
- if (strncmp ("md", p, 2) == 0
- && p[2] >= '0' && p[2] <= '9')
- {
- char *ptr = p + 2;
- while (*ptr >= '0' && *ptr <= '9')
- ptr++;
- if (*ptr)
- *is_part = 1;
- *ptr = 0;
- return path;
- }
-
- if (strncmp ("nbd", p, 3) == 0
- && p[3] >= '0' && p[3] <= '9')
- {
- char *ptr = p + 3;
- while (*ptr >= '0' && *ptr <= '9')
- ptr++;
- if (*ptr)
- *is_part = 1;
- *ptr = 0;
- return path;
- }
-
- /* If this is an IDE, SCSI or Virtio disk. */
- if (strncmp ("vdisk", p, 5) == 0
- && p[5] >= 'a' && p[5] <= 'z')
- {
- /* /dev/vdisk[a-z][0-9]* */
- if (p[6])
- *is_part = 1;
- p[6] = '\0';
- return path;
- }
- if ((strncmp ("hd", p, 2) == 0
- || strncmp ("vd", p, 2) == 0
- || strncmp ("sd", p, 2) == 0)
- && p[2] >= 'a' && p[2] <= 'z')
- {
- char *pp = p + 2;
- while (*pp >= 'a' && *pp <= 'z')
- pp++;
- if (*pp)
- *is_part = 1;
- /* /dev/[hsv]d[a-z]+[0-9]* */
- *pp = '\0';
- return path;
- }
-
- /* If this is a Xen virtual block device. */
- if ((strncmp ("xvd", p, 3) == 0) && p[3] >= 'a' && p[3] <= 'z')
- {
- char *pp = p + 3;
- while (*pp >= 'a' && *pp <= 'z')
- pp++;
- if (*pp)
- *is_part = 1;
- /* /dev/xvd[a-z]+[0-9]* */
- *pp = '\0';
- return path;
- }
-
-#ifdef HAVE_DEVICE_MAPPER
- if (dm_is_dm_major (major (st->st_rdev)))
- {
- struct dm_tree *tree;
- uint32_t maj, min;
- struct dm_tree_node *node = NULL, *child;
- void *handle;
- const char *node_uuid, *mapper_name = NULL, *child_uuid, *child_name;
-
- tree = dm_tree_create ();
- if (! tree)
- {
- grub_util_info ("dm_tree_create failed");
- goto devmapper_out;
- }
-
- maj = major (st->st_rdev);
- min = minor (st->st_rdev);
- if (! dm_tree_add_dev (tree, maj, min))
- {
- grub_util_info ("dm_tree_add_dev failed");
- goto devmapper_out;
- }
-
- node = dm_tree_find_node (tree, maj, min);
- if (! node)
- {
- grub_util_info ("dm_tree_find_node failed");
- goto devmapper_out;
- }
- reiterate:
- node_uuid = dm_tree_node_get_uuid (node);
- if (! node_uuid)
- {
- grub_util_info ("%s has no DM uuid", path);
- goto devmapper_out;
- }
- if (strncmp (node_uuid, "LVM-", 4) == 0)
- {
- grub_util_info ("%s is an LVM", path);
- goto devmapper_out;
- }
- if (strncmp (node_uuid, "mpath-", 6) == 0)
- {
- /* Multipath partitions have partN-mpath-* UUIDs, and are
- linear mappings so are handled by
- grub_util_get_dm_node_linear_info. Multipath disks are not
- linear mappings and must be handled specially. */
- grub_util_info ("%s is a multipath disk", path);
- goto devmapper_out;
- }
- if (strncmp (node_uuid, "DMRAID-", 7) != 0)
- {
- int major, minor;
- const char *node_name;
- grub_util_info ("%s is not DM-RAID", path);
-
- if ((node_name = dm_tree_node_get_name (node))
- && grub_util_get_dm_node_linear_info (node_name,
- &major, &minor, 0))
- {
- *is_part = 1;
- if (tree)
- dm_tree_free (tree);
- free (path);
- char *ret = grub_find_device ("/dev",
- (major << 8) | minor);
- return ret;
- }
-
- goto devmapper_out;
- }
-
- handle = NULL;
- /* Counter-intuitively, device-mapper refers to the disk-like
- device containing a DM-RAID partition device as a "child" of
- the partition device. */
- child = dm_tree_next_child (&handle, node, 0);
- if (! child)
- {
- grub_util_info ("%s has no DM children", path);
- goto devmapper_out;
- }
- child_uuid = dm_tree_node_get_uuid (child);
- if (! child_uuid)
- {
- grub_util_info ("%s child has no DM uuid", path);
- goto devmapper_out;
- }
- else if (strncmp (child_uuid, "DMRAID-", 7) != 0)
- {
- grub_util_info ("%s child is not DM-RAID", path);
- goto devmapper_out;
- }
- child_name = dm_tree_node_get_name (child);
- if (! child_name)
- {
- grub_util_info ("%s child has no DM name", path);
- goto devmapper_out;
- }
- mapper_name = child_name;
- *is_part = 1;
- node = child;
- goto reiterate;
+ if (grub_util_device_is_mapped_stat (st))
+ return grub_util_devmapper_part_to_disk (st, is_part, os_dev);
-devmapper_out:
- if (! mapper_name && node)
- {
- /* This is a DM-RAID disk, not a partition. */
- mapper_name = dm_tree_node_get_name (node);
- if (! mapper_name)
- grub_util_info ("%s has no DM name", path);
- }
- char *ret;
- if (mapper_name)
- ret = xasprintf ("/dev/mapper/%s", mapper_name);
- else
- ret = NULL;
-
- if (tree)
- dm_tree_free (tree);
- free (path);
- return ret;
- }
-#endif /* HAVE_DEVICE_MAPPER */
- }
-
- return path;
-
-#elif defined(__GNU__)
- char *path = xstrdup (os_dev);
- if (strncmp ("/dev/sd", path, 7) == 0 || strncmp ("/dev/hd", path, 7) == 0)
- {
- char *p = strchr (path + 7, 's');
- if (p)
- {
- *is_part = 1;
- *p = '\0';
- }
- }
- return path;
-
-#elif defined(__CYGWIN__)
- 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;
-
-#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
- char *out, *out2;
- if (strncmp (os_dev, "/dev/", sizeof ("/dev/") - 1) != 0)
- return xstrdup (os_dev);
- grub_util_follow_gpart_up (os_dev + sizeof ("/dev/") - 1, NULL, &out);
-
- if (grub_strcmp (os_dev + sizeof ("/dev/") - 1, out) != 0)
- *is_part = 1;
- out2 = xasprintf ("/dev/%s", out);
- free (out);
-
- return out2;
-#elif defined(__APPLE__)
- char *path = xstrdup (os_dev);
- if (strncmp ("/dev/", path, 5) == 0)
- {
- char *p;
- for (p = path + 5; *p; ++p)
- if (grub_isdigit(*p))
- {
- p = strpbrk (p, "sp");
- if (p)
- {
- *is_part = 1;
- *p = '\0';
- }
- break;
- }
- }
- return path;
-
-#elif defined(__NetBSD__) || defined(__OpenBSD__)
- int rawpart = -1;
-# ifdef HAVE_GETRAWPARTITION
- rawpart = getrawpartition();
-# endif /* HAVE_GETRAWPARTITION */
- if (rawpart < 0)
- return xstrdup (os_dev);
-
-#if defined(__NetBSD__)
- /* NetBSD disk wedges are of the form "/dev/rdk.*". */
- if (strncmp ("/dev/rdk", os_dev, sizeof("/dev/rdk") - 1) == 0)
- {
- struct dkwedge_info dkw;
- int fd;
-
- fd = open (os_dev, O_RDONLY);
- if (fd == -1)
- {
- grub_error (GRUB_ERR_BAD_DEVICE,
- N_("cannot open `%s': %s"), os_dev,
- strerror (errno));
- return xstrdup (os_dev);
- }
- /* We don't call configure_device_driver since this isn't a floppy device name. */
- if (ioctl (fd, DIOCGWEDGEINFO, &dkw) == -1)
- {
- grub_error (GRUB_ERR_BAD_DEVICE,
- "cannot get disk wedge info of `%s'", os_dev);
- close (fd);
- return xstrdup (os_dev);
- }
- *is_part = (dkw.dkw_offset != 0);
- close (fd);
- return xasprintf ("/dev/r%s%c", dkw.dkw_parent, 'a' + rawpart);
- }
-#endif
-
- /* NetBSD (disk label) partitions are of the form "/dev/r[a-z]+[0-9][a-z]". */
- if (strncmp ("/dev/r", os_dev, sizeof("/dev/r") - 1) == 0 &&
- (os_dev[sizeof("/dev/r") - 1] >= 'a' && os_dev[sizeof("/dev/r") - 1] <= 'z') &&
- strncmp ("fd", os_dev + sizeof("/dev/r") - 1, sizeof("fd") - 1) != 0) /* not a floppy device name */
- {
- char *path = xstrdup (os_dev);
- char *p;
- for (p = path + sizeof("/dev/r"); *p >= 'a' && *p <= 'z'; p++);
- if (grub_isdigit(*p))
- {
- p++;
- if ((*p >= 'a' && *p <= 'z') && (*(p+1) == '\0'))
- {
- if (*p != 'a' + rawpart)
- *is_part = 1;
- /* path matches the required regular expression and
- p points to its last character. */
- *p = 'a' + rawpart;
- }
- }
- return path;
- }
-
- return xstrdup (os_dev);
+ *is_part = 0;
-#elif defined (__sun__)
- char *colon = grub_strrchr (os_dev, ':');
- if (grub_memcmp (os_dev, "/devices", sizeof ("/devices") - 1) == 0
- && colon)
- {
- char *ret = xmalloc (colon - os_dev + sizeof (":q,raw"));
- if (grub_strcmp (colon, ":q,raw") != 0)
- *is_part = 1;
- grub_memcpy (ret, os_dev, colon - os_dev);
- grub_memcpy (ret + (colon - os_dev), ":q,raw", sizeof (":q,raw"));
- return ret;
- }
- else
- return xstrdup (os_dev);
-#elif defined (__APPLE__)
- char *ptr;
- char *ret = xstrdup (os_dev);
- int disk = grub_memcmp (ret, "/dev/disk", sizeof ("/dev/disk") - 1) == 0;
- int rdisk = grub_memcmp (ret, "/dev/rdisk", sizeof ("/dev/rdisk") - 1) == 0;
- if (!disk && !rdisk)
- return ret;
- ptr = ret + sizeof ("/dev/disk") + rdisk - 1;
- while (*ptr >= '0' && *ptr <= '9')
- ptr++;
- if (*ptr)
- {
- *is_part = 1;
- *ptr = 0;
- }
- return ret;
-#else
-# warning "The function `convert_system_partition_to_system_disk' might not work on your OS correctly."
- return xstrdup (os_dev);
-#endif
+ return grub_util_part_to_disk (os_dev, st, is_part);
}
static const char *
return convert_system_partition_to_system_disk (os_dev, &st, &is_part);
}
-#if defined(__linux__) || defined(__CYGWIN__) || defined(HAVE_DIOCGDINFO) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined (__sun__)
+#if !defined(__APPLE__)
/* Context for grub_util_biosdisk_get_grub_dev. */
struct grub_util_biosdisk_get_grub_dev_ctx
{
}
free (sys_disk);
-#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__NetBSD__) || defined (__sun__)
+#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(__linux__) || defined(__CYGWIN__) || defined(HAVE_DIOCGDINFO) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined (__sun__) || defined(__OpenBSD__)
+#if defined(__APPLE__)
+ /* Apple uses "/dev/r?disk[0-9]+(s[0-9]+)?". */
+ {
+ const char *p;
+ int disk = (grub_memcmp (os_dev, "/dev/disk", sizeof ("/dev/disk") - 1)
+ == 0);
+ int rdisk = (grub_memcmp (os_dev, "/dev/rdisk", sizeof ("/dev/rdisk") - 1)
+ == 0);
+
+ if (!disk && !rdisk)
+ return make_device_name (drive, -1, -1);
+
+ p = os_dev + sizeof ("/dev/disk") + rdisk - 1;
+ while (*p >= '0' && *p <= '9')
+ p++;
+ if (*p != 's')
+ return make_device_name (drive, -1, -1);
+ p++;
+
+ return make_device_name (drive, strtol (p, NULL, 10) - 1, -1);
+ }
+
+#else
/* Linux counts partitions uniformly, whether a BSD partition or a DOS
partition, so mapping them to GRUB devices is not trivial.
name = make_device_name (drive, -1, -1);
-# if !defined(HAVE_DIOCGDINFO) && !defined(__sun__)
+# ifdef FLOPPY_MAJOR
if (MAJOR (st.st_rdev) == FLOPPY_MAJOR)
return name;
-# else /* defined(HAVE_DIOCGDINFO) */
+# else
/* Since os_dev and convert_system_partition_to_system_disk (os_dev) are
* different, we know that os_dev cannot be a floppy device. */
-# endif /* !defined(HAVE_DIOCGDINFO) */
+# endif
- ctx.start = grub_hostdisk_find_partition_start (os_dev);
+ ctx.start = grub_util_find_partition_start (os_dev);
if (grub_errno != GRUB_ERR_NONE)
{
free (name);
return 0;
}
+#if defined(__GNU__)
+ /* Some versions of Hurd use badly glued Linux code to handle partitions
+ resulting in partitions being promoted to disks. */
+ /* GNU uses "/dev/[hs]d[0-9]+(s[0-9]+[a-z]?)?". */
+ if (ctx.start == (grub_disk_addr_t) -1)
+ {
+ char *p;
+ int dos_part = -1;
+ int bsd_part = -1;
+
+ p = strrchr (os_dev + sizeof ("/dev/hd") - 1, 's');
+ if (p)
+ {
+ long int n;
+ char *q;
+
+ p++;
+ n = strtol (p, &q, 10);
+ if (p != q && n != GRUB_LONG_MIN && n != GRUB_LONG_MAX)
+ {
+ dos_part = (int) n - 1;
+
+ if (*q >= 'a' && *q <= 'g')
+ bsd_part = *q - 'a';
+ }
+ }
+
+ return make_device_name (drive, dos_part, bsd_part);
+ }
+#endif
+
grub_util_info ("%s starts from %" PRIuGRUB_UINT64_T, os_dev, ctx.start);
if (ctx.start == 0 && !is_part)
return name;
}
-#elif defined(__GNU__)
- /* GNU uses "/dev/[hs]d[0-9]+(s[0-9]+[a-z]?)?". */
- {
- char *p;
- int dos_part = -1;
- int bsd_part = -1;
-
- p = strrchr (os_dev, 's');
- if (p)
- {
- long int n;
- char *q;
-
- p++;
- n = strtol (p, &q, 10);
- if (p != q && n != GRUB_LONG_MIN && n != GRUB_LONG_MAX)
- {
- dos_part = (int) n - 1;
-
- if (*q >= 'a' && *q <= 'g')
- bsd_part = *q - 'a';
- }
- }
-
- return make_device_name (drive, dos_part, bsd_part);
- }
-
-#elif defined(__APPLE__)
- /* Apple uses "/dev/r?disk[0-9]+(s[0-9]+)?". */
- {
- const char *p;
- int disk = (grub_memcmp (os_dev, "/dev/disk", sizeof ("/dev/disk") - 1)
- == 0);
- int rdisk = (grub_memcmp (os_dev, "/dev/rdisk", sizeof ("/dev/rdisk") - 1)
- == 0);
-
- if (!disk && !rdisk)
- return make_device_name (drive, -1, -1);
-
- p = os_dev + sizeof ("/dev/disk") + rdisk - 1;
- while (*p >= '0' && *p <= '9')
- p++;
- if (*p != 's')
- return make_device_name (drive, -1, -1);
- p++;
-
- return make_device_name (drive, strtol (p, NULL, 10) - 1, -1);
- }
-#else
-# warning "The function `grub_util_biosdisk_get_grub_dev' might not work on your OS correctly."
- return make_device_name (drive, -1, -1);
#endif
}
return ret;
}
-char *
-grub_util_get_grub_dev (const char *os_dev)
-{
- char *grub_dev = NULL;
-
- grub_util_pull_device (os_dev);
-
- switch (grub_util_get_dev_abstraction (os_dev))
- {
-#ifdef HAVE_DEVICE_MAPPER
- case GRUB_DEV_ABSTRACTION_LVM:
- {
- char *uuid, *optr;
- unsigned i;
- int dashes[] = { 0, 6, 10, 14, 18, 22, 26, 32, 38, 42, 46, 50, 54, 58};
- uuid = get_dm_uuid (os_dev);
- if (!uuid)
- break;
- grub_dev = xmalloc (grub_strlen (uuid) + 40);
- optr = grub_stpcpy (grub_dev, "lvmid/");
- for (i = 0; i < ARRAY_SIZE (dashes) - 1; i++)
- {
- memcpy (optr, uuid + sizeof ("LVM-") - 1 + dashes[i],
- dashes[i+1] - dashes[i]);
- optr += dashes[i+1] - dashes[i];
- *optr++ = '-';
- }
- optr = stpcpy (optr, uuid + sizeof ("LVM-") - 1 + dashes[i]);
- *optr = '\0';
- grub_dev[sizeof("lvmid/xxxxxx-xxxx-xxxx-xxxx-xxxx-xxxx-xxxxxx") - 1]
- = '/';
- free (uuid);
- }
- break;
-#elif defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
- case GRUB_DEV_ABSTRACTION_LVM:
-
- {
- unsigned short len;
- grub_size_t offset = sizeof (LVM_DEV_MAPPER_STRING) - 1;
-
- len = strlen (os_dev) - offset + 1;
- grub_dev = xmalloc (len + sizeof ("lvm/"));
-
- grub_memcpy (grub_dev, "lvm/", sizeof ("lvm/") - 1);
- grub_memcpy (grub_dev + sizeof ("lvm/") - 1, os_dev + offset, len);
- }
-
- break;
-#endif
-
- case GRUB_DEV_ABSTRACTION_LUKS:
-#ifdef HAVE_DEVICE_MAPPER
- {
- char *uuid, *dash;
- uuid = get_dm_uuid (os_dev);
- if (!uuid)
- break;
- dash = grub_strchr (uuid + sizeof ("CRYPT-LUKS1-") - 1, '-');
- if (dash)
- *dash = 0;
- grub_dev = grub_xasprintf ("cryptouuid/%s",
- uuid + sizeof ("CRYPT-LUKS1-") - 1);
- grub_free (uuid);
- }
-#endif
- break;
-
-#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
- case GRUB_DEV_ABSTRACTION_GELI:
- {
- char *whole;
- struct gmesh mesh;
- struct gclass *class;
- const char *name;
- int err;
-
- if (strncmp (os_dev, "/dev/", sizeof ("/dev/") - 1) != 0)
- return 0;
- name = os_dev + sizeof ("/dev/") - 1;
- grub_util_follow_gpart_up (name, NULL, &whole);
-
- grub_util_info ("following geom '%s'", name);
-
- err = geom_gettree (&mesh);
- if (err != 0)
- /* TRANSLATORS: geom is the name of (k)FreeBSD device framework.
- Usually left untranslated.
- */
- grub_util_error ("%s", _("couldn't open geom"));
-
- LIST_FOREACH (class, &mesh.lg_class, lg_class)
- {
- struct ggeom *geom;
- LIST_FOREACH (geom, &class->lg_geom, lg_geom)
- {
- struct gprovider *provider;
- LIST_FOREACH (provider, &geom->lg_provider, lg_provider)
- if (strcmp (provider->lg_name, name) == 0)
- {
- struct gconsumer *consumer;
- char *fname;
- char *uuid;
-
- LIST_FOREACH (consumer, &geom->lg_consumer, lg_consumer)
- break;
- if (!consumer)
- grub_util_error ("%s",
- _("couldn't find geli consumer"));
- fname = xasprintf ("/dev/%s", consumer->lg_provider->lg_name);
- uuid = grub_util_get_geli_uuid (fname);
- if (!uuid)
- grub_util_error ("%s",
- _("couldn't retrieve geli UUID"));
- grub_dev = xasprintf ("cryptouuid/%s", uuid);
- free (fname);
- free (uuid);
- }
- }
- }
- }
- break;
-#endif
-
-#ifdef __linux__
- case GRUB_DEV_ABSTRACTION_RAID:
-
- if (os_dev[7] == '_' && os_dev[8] == 'd')
- {
- /* This a partitionable RAID device of the form /dev/md_dNNpMM. */
-
- char *p, *q;
-
- p = strdup (os_dev + sizeof ("/dev/md_d") - 1);
-
- q = strchr (p, 'p');
- if (q)
- *q = ',';
-
- grub_dev = xasprintf ("md%s", p);
- free (p);
- }
- else if (os_dev[7] == '/' && os_dev[8] == 'd')
- {
- /* This a partitionable RAID device of the form /dev/md/dNNpMM. */
-
- char *p, *q;
-
- p = strdup (os_dev + sizeof ("/dev/md/d") - 1);
-
- q = strchr (p, 'p');
- if (q)
- *q = ',';
-
- grub_dev = xasprintf ("md%s", p);
- free (p);
- }
- else if (os_dev[7] >= '0' && os_dev[7] <= '9')
- {
- char *p , *q;
-
- p = strdup (os_dev + sizeof ("/dev/md") - 1);
-
- q = strchr (p, 'p');
- if (q)
- *q = ',';
-
- grub_dev = xasprintf ("md%s", p);
- free (p);
- }
- else if (os_dev[7] == '/' && os_dev[8] >= '0' && os_dev[8] <= '9')
- {
- char *p , *q;
-
- p = strdup (os_dev + sizeof ("/dev/md/") - 1);
-
- q = strchr (p, 'p');
- if (q)
- *q = ',';
-
- grub_dev = xasprintf ("md%s", p);
- free (p);
- }
- else if (os_dev[7] == '/')
- {
- /* mdraid 1.x with a free name. */
- char *p , *q;
-
- p = strdup (os_dev + sizeof ("/dev/md/") - 1);
-
- q = strchr (p, 'p');
- if (q)
- *q = ',';
-
- grub_dev = xasprintf ("md/%s", p);
- free (p);
- }
- else
- grub_util_error (_("unknown kind of RAID device `%s'"), os_dev);
-
- {
- char *mdadm_name = get_mdadm_uuid (os_dev);
-
- if (mdadm_name)
- {
- const char *q;
-
- for (q = os_dev + strlen (os_dev) - 1; q >= os_dev
- && grub_isdigit (*q); q--);
-
- if (q >= os_dev && *q == 'p')
- {
- free (grub_dev);
- grub_dev = xasprintf ("mduuid/%s,%s", mdadm_name, q + 1);
- goto done;
- }
- free (grub_dev);
- grub_dev = xasprintf ("mduuid/%s", mdadm_name);
-
- done:
- free (mdadm_name);
- }
- }
- break;
-#endif /* __linux__ */
-
- default: /* GRUB_DEV_ABSTRACTION_NONE */
- grub_dev = grub_util_biosdisk_get_grub_dev (os_dev);
- }
-
- return grub_dev;
-}
-
const char *
grub_util_check_block_device (const char *blk_dev)
{
--- /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/disk.h>
+# include <sys/param.h>
+# include <sys/sysctl.h>
+# include <sys/mount.h>
+
+char *
+grub_util_part_to_disk (const char *os_dev, struct stat *st,
+ int *is_part)
+{
+ char *path = xstrdup (os_dev);
+ if (strncmp ("/dev/", path, 5) == 0)
+ {
+ char *p;
+ for (p = path + 5; *p; ++p)
+ if (grub_isdigit(*p))
+ {
+ p = strpbrk (p, "sp");
+ if (p)
+ {
+ *is_part = 1;
+ *p = '\0';
+ }
+ break;
+ }
+ }
+ 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 __attribute__ ((unused)))
+{
+ return 0;
+}
--- /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>
+
+
+char *
+grub_util_part_to_disk (const char *os_dev,
+ struct stat *st __attribute__ ((unused)),
+ int *is_part)
+{
+ *is_part = 0;
+ return xstrdup (os_dev);
+}
+
+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 __attribute__ ((unused)))
+{
+ return 0;
+}
--- /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 <sys/disklabel.h> /* struct disklabel */
+# include <sys/disk.h> /* struct dkwedge_info */
+# ifdef HAVE_GETRAWPARTITION
+# include <util.h> /* getrawpartition */
+# endif /* HAVE_GETRAWPARTITION */
+#if defined(__NetBSD__)
+# include <sys/fdio.h>
+#endif
+#if defined(__OpenBSD__)
+# include <sys/dkio.h>
+#endif
+
+char *
+grub_util_part_to_disk (const char *os_dev, struct stat *st,
+ int *is_part)
+{
+ int rawpart = -1;
+# ifdef HAVE_GETRAWPARTITION
+ rawpart = getrawpartition();
+# endif /* HAVE_GETRAWPARTITION */
+ if (rawpart < 0)
+ return xstrdup (os_dev);
+
+#if defined(__NetBSD__)
+ /* NetBSD disk wedges are of the form "/dev/rdk.*". */
+ if (strncmp ("/dev/rdk", os_dev, sizeof("/dev/rdk") - 1) == 0)
+ {
+ struct dkwedge_info dkw;
+ int fd;
+
+ fd = open (os_dev, O_RDONLY);
+ if (fd == -1)
+ {
+ grub_error (GRUB_ERR_BAD_DEVICE,
+ N_("cannot open `%s': %s"), os_dev,
+ strerror (errno));
+ return xstrdup (os_dev);
+ }
+ /* We don't call configure_device_driver since this isn't a floppy device name. */
+ if (ioctl (fd, DIOCGWEDGEINFO, &dkw) == -1)
+ {
+ grub_error (GRUB_ERR_BAD_DEVICE,
+ "cannot get disk wedge info of `%s'", os_dev);
+ close (fd);
+ return xstrdup (os_dev);
+ }
+ *is_part = (dkw.dkw_offset != 0);
+ close (fd);
+ return xasprintf ("/dev/r%s%c", dkw.dkw_parent, 'a' + rawpart);
+ }
+#endif
+
+ /* NetBSD (disk label) partitions are of the form "/dev/r[a-z]+[0-9][a-z]". */
+ if (strncmp ("/dev/r", os_dev, sizeof("/dev/r") - 1) == 0 &&
+ (os_dev[sizeof("/dev/r") - 1] >= 'a' && os_dev[sizeof("/dev/r") - 1] <= 'z') &&
+ strncmp ("fd", os_dev + sizeof("/dev/r") - 1, sizeof("fd") - 1) != 0) /* not a floppy device name */
+ {
+ char *path = xstrdup (os_dev);
+ char *p;
+ for (p = path + sizeof("/dev/r"); *p >= 'a' && *p <= 'z'; p++);
+ if (grub_isdigit(*p))
+ {
+ p++;
+ if ((*p >= 'a' && *p <= 'z') && (*(p+1) == '\0'))
+ {
+ if (*p != 'a' + rawpart)
+ *is_part = 1;
+ /* path matches the required regular expression and
+ p points to its last character. */
+ *p = 'a' + rawpart;
+ }
+ }
+ return path;
+ }
+
+ return xstrdup (os_dev);
+}
+
+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;
+# if defined(__NetBSD__)
+ struct dkwedge_info dkw;
+# endif /* defined(__NetBSD__) */
+ struct disklabel label;
+ int p_index;
+
+ 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 defined(__NetBSD__)
+ configure_device_driver (fd);
+ /* First handle the case of disk wedges. */
+ if (ioctl (fd, DIOCGWEDGEINFO, &dkw) == 0)
+ {
+ close (fd);
+ return (grub_disk_addr_t) dkw.dkw_offset;
+ }
+# endif /* defined(__NetBSD__) */
+
+ if (ioctl (fd, DIOCGDINFO, &label) == -1)
+ {
+ grub_error (GRUB_ERR_BAD_DEVICE,
+ "cannot get disk label of `%s'", dev);
+ close (fd);
+ return 0;
+ }
+
+ close (fd);
+
+ if (dev[0])
+ p_index = dev[strlen(dev) - 1] - 'a';
+ else
+ p_index = -1;
+
+ if (p_index >= label.d_npartitions || p_index < 0)
+ {
+ grub_error (GRUB_ERR_BAD_DEVICE,
+ "no disk label entry for `%s'", dev);
+ return 0;
+ }
+ return (grub_disk_addr_t) label.d_partitions[p_index].p_offset;
+}
--- /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;
+}
--- /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 <grub/emu/getroot.h>
+#include <grub/mm.h>
+
+#ifdef HAVE_DEVICE_MAPPER
+
+#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 <libdevmapper.h>
+
+#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>
+
+static int
+grub_util_open_dm (const char *os_dev, struct dm_tree **tree,
+ struct dm_tree_node **node)
+{
+ uint32_t maj, min;
+ struct stat st;
+
+ *node = NULL;
+ *tree = NULL;
+
+ if (stat (os_dev, &st) < 0)
+ return 0;
+
+ maj = major (st.st_rdev);
+ min = minor (st.st_rdev);
+
+ if (!dm_is_dm_major (maj))
+ return 0;
+
+ *tree = dm_tree_create ();
+ if (! *tree)
+ {
+ grub_puts_ (N_("Failed to create `device-mapper' tree"));
+ grub_dprintf ("hostdisk", "dm_tree_create failed\n");
+ return 0;
+ }
+
+ if (! dm_tree_add_dev (*tree, maj, min))
+ {
+ grub_dprintf ("hostdisk", "dm_tree_add_dev failed\n");
+ dm_tree_free (*tree);
+ *tree = NULL;
+ return 0;
+ }
+
+ *node = dm_tree_find_node (*tree, maj, min);
+ if (! *node)
+ {
+ grub_dprintf ("hostdisk", "dm_tree_find_node failed\n");
+ dm_tree_free (*tree);
+ *tree = NULL;
+ return 0;
+ }
+ return 1;
+}
+
+static char *
+get_dm_uuid (const char *os_dev)
+{
+ struct dm_tree *tree;
+ struct dm_tree_node *node;
+ const char *node_uuid;
+ char *ret;
+
+ if (!grub_util_open_dm (os_dev, &tree, &node))
+ return NULL;
+
+ node_uuid = dm_tree_node_get_uuid (node);
+ if (! node_uuid)
+ {
+ grub_dprintf ("hostdisk", "%s has no DM uuid\n", os_dev);
+ dm_tree_free (tree);
+ return NULL;
+ }
+
+ ret = grub_strdup (node_uuid);
+
+ dm_tree_free (tree);
+
+ return ret;
+}
+
+enum grub_dev_abstraction_types
+grub_util_get_dm_abstraction (const char *os_dev)
+{
+ char *uuid;
+
+ uuid = get_dm_uuid (os_dev);
+
+ if (uuid == NULL)
+ return GRUB_DEV_ABSTRACTION_NONE;
+
+ if (strncmp (uuid, "LVM-", 4) == 0)
+ {
+ grub_free (uuid);
+ return GRUB_DEV_ABSTRACTION_LVM;
+ }
+ if (strncmp (uuid, "CRYPT-LUKS1-", 4) == 0)
+ {
+ grub_free (uuid);
+ return GRUB_DEV_ABSTRACTION_LUKS;
+ }
+
+ grub_free (uuid);
+ return GRUB_DEV_ABSTRACTION_NONE;
+}
+
+void
+grub_util_pull_devmapper (const char *os_dev)
+{
+ struct dm_tree *tree;
+ struct dm_tree_node *node;
+ struct dm_tree_node *child;
+ void *handle = NULL;
+ char *lastsubdev = NULL;
+ char *uuid;
+
+ uuid = get_dm_uuid (os_dev);
+
+ if (!grub_util_open_dm (os_dev, &tree, &node))
+ return;
+
+ while ((child = dm_tree_next_child (&handle, node, 0)))
+ {
+ const struct dm_info *dm = dm_tree_node_get_info (child);
+ char *subdev;
+ if (!dm)
+ continue;
+ subdev = grub_find_device ("/dev", makedev (dm->major, dm->minor));
+ if (subdev)
+ {
+ lastsubdev = subdev;
+ grub_util_pull_device (subdev);
+ }
+ }
+ if (uuid && strncmp (uuid, "CRYPT-LUKS1-", sizeof ("CRYPT-LUKS1-") - 1) == 0
+ && lastsubdev)
+ {
+ char *grdev = grub_util_get_grub_dev (lastsubdev);
+ dm_tree_free (tree);
+ if (grdev)
+ {
+ grub_err_t err;
+ err = grub_cryptodisk_cheat_mount (grdev, os_dev);
+ if (err)
+ grub_util_error (_("can't mount encrypted volume `%s': %s"),
+ lastsubdev, grub_errmsg);
+ }
+ grub_free (grdev);
+ }
+ else
+ dm_tree_free (tree);
+}
+
+char *
+grub_util_devmapper_part_to_disk (struct stat *st,
+ int *is_part, const char *path)
+{
+ struct dm_tree *tree;
+ uint32_t maj, min;
+ struct dm_tree_node *node = NULL, *child;
+ void *handle;
+ const char *node_uuid, *mapper_name = NULL, *child_uuid, *child_name;
+
+ tree = dm_tree_create ();
+ if (! tree)
+ {
+ grub_util_info ("dm_tree_create failed");
+ goto devmapper_out;
+ }
+
+ maj = major (st->st_rdev);
+ min = minor (st->st_rdev);
+ if (! dm_tree_add_dev (tree, maj, min))
+ {
+ grub_util_info ("dm_tree_add_dev failed");
+ goto devmapper_out;
+ }
+
+ node = dm_tree_find_node (tree, maj, min);
+ if (! node)
+ {
+ grub_util_info ("dm_tree_find_node failed");
+ goto devmapper_out;
+ }
+ reiterate:
+ node_uuid = dm_tree_node_get_uuid (node);
+ if (! node_uuid)
+ {
+ grub_util_info ("%s has no DM uuid", path);
+ goto devmapper_out;
+ }
+ if (strncmp (node_uuid, "LVM-", 4) == 0)
+ {
+ grub_util_info ("%s is an LVM", path);
+ goto devmapper_out;
+ }
+ if (strncmp (node_uuid, "mpath-", 6) == 0)
+ {
+ /* Multipath partitions have partN-mpath-* UUIDs, and are
+ linear mappings so are handled by
+ grub_util_get_dm_node_linear_info. Multipath disks are not
+ linear mappings and must be handled specially. */
+ grub_util_info ("%s is a multipath disk", path);
+ goto devmapper_out;
+ }
+ if (strncmp (node_uuid, "DMRAID-", 7) != 0)
+ {
+ int major, minor;
+ const char *node_name;
+ grub_util_info ("%s is not DM-RAID", path);
+
+ if ((node_name = dm_tree_node_get_name (node))
+ && grub_util_get_dm_node_linear_info (node_name,
+ &major, &minor, 0))
+ {
+ *is_part = 1;
+ if (tree)
+ dm_tree_free (tree);
+ char *ret = grub_find_device ("/dev",
+ (major << 8) | minor);
+ return ret;
+ }
+
+ goto devmapper_out;
+ }
+
+ handle = NULL;
+ /* Counter-intuitively, device-mapper refers to the disk-like
+ device containing a DM-RAID partition device as a "child" of
+ the partition device. */
+ child = dm_tree_next_child (&handle, node, 0);
+ if (! child)
+ {
+ grub_util_info ("%s has no DM children", path);
+ goto devmapper_out;
+ }
+ child_uuid = dm_tree_node_get_uuid (child);
+ if (! child_uuid)
+ {
+ grub_util_info ("%s child has no DM uuid", path);
+ goto devmapper_out;
+ }
+ else if (strncmp (child_uuid, "DMRAID-", 7) != 0)
+ {
+ grub_util_info ("%s child is not DM-RAID", path);
+ goto devmapper_out;
+ }
+ child_name = dm_tree_node_get_name (child);
+ if (! child_name)
+ {
+ grub_util_info ("%s child has no DM name", path);
+ goto devmapper_out;
+ }
+ mapper_name = child_name;
+ *is_part = 1;
+ node = child;
+ goto reiterate;
+
+ devmapper_out:
+ if (! mapper_name && node)
+ {
+ /* This is a DM-RAID disk, not a partition. */
+ mapper_name = dm_tree_node_get_name (node);
+ if (! mapper_name)
+ grub_util_info ("%s has no DM name", path);
+ }
+ char *ret;
+ if (mapper_name)
+ ret = xasprintf ("/dev/mapper/%s", mapper_name);
+ else
+ ret = NULL;
+
+ if (tree)
+ dm_tree_free (tree);
+ return ret;
+}
+
+int
+grub_util_device_is_mapped_stat (struct stat *st)
+{
+ if (!grub_device_mapper_supported ())
+ return 0;
+
+ return dm_is_dm_major (major (st->st_rdev));
+}
+
+char *
+grub_util_get_devmapper_grub_dev (const char *os_dev)
+{
+ char *uuid, *optr;
+ char *grub_dev;
+
+ uuid = get_dm_uuid (os_dev);
+ if (!uuid)
+ return NULL;
+
+ if (strncmp (uuid, "LVM-", sizeof ("LVM-") - 1) == 0)
+ {
+ unsigned i;
+ int dashes[] = { 0, 6, 10, 14, 18, 22, 26, 32, 38, 42, 46, 50, 54, 58};
+ grub_dev = xmalloc (grub_strlen (uuid) + 40);
+ optr = grub_stpcpy (grub_dev, "lvmid/");
+ for (i = 0; i < ARRAY_SIZE (dashes) - 1; i++)
+ {
+ memcpy (optr, uuid + sizeof ("LVM-") - 1 + dashes[i],
+ dashes[i+1] - dashes[i]);
+ optr += dashes[i+1] - dashes[i];
+ *optr++ = '-';
+ }
+ optr = stpcpy (optr, uuid + sizeof ("LVM-") - 1 + dashes[i]);
+ *optr = '\0';
+ grub_dev[sizeof("lvmid/xxxxxx-xxxx-xxxx-xxxx-xxxx-xxxx-xxxxxx") - 1]
+ = '/';
+ free (uuid);
+ return grub_dev;
+ }
+
+ if (strncmp (uuid, "CRYPT-LUKS1-", sizeof ("CRYPT-LUKS1-") - 1) == 0)
+ {
+ char *dash;
+ dash = grub_strchr (uuid + sizeof ("CRYPT-LUKS1-") - 1, '-');
+ if (dash)
+ *dash = 0;
+ grub_dev = grub_xasprintf ("cryptouuid/%s",
+ uuid + sizeof ("CRYPT-LUKS1-") - 1);
+ grub_free (uuid);
+ return grub_dev;
+ }
+ return NULL;
+}
+
+char *
+grub_util_get_vg_uuid (const char *os_dev)
+{
+ char *uuid, *vgid;
+ int dashes[] = { 0, 6, 10, 14, 18, 22, 26, 32};
+ unsigned i;
+ char *optr;
+
+ uuid = get_dm_uuid (os_dev);
+ if (!uuid)
+ return NULL;
+
+ vgid = xmalloc (grub_strlen (uuid));
+ optr = vgid;
+ for (i = 0; i < ARRAY_SIZE (dashes) - 1; i++)
+ {
+ memcpy (optr, uuid + sizeof ("LVM-") - 1 + dashes[i],
+ dashes[i+1] - dashes[i]);
+ optr += dashes[i+1] - dashes[i];
+ *optr++ = '-';
+ }
+ optr--;
+ *optr = '\0';
+ return vgid;
+}
+
+void
+grub_util_devmapper_cleanup (void)
+{
+ dm_lib_release ();
+}
+
+#else
+void
+grub_util_pull_devmapper (const char *os_dev __attribute__ ((unused)))
+{
+ return;
+}
+
+int
+grub_util_device_is_mapped_stat (struct stat *st __attribute__ ((unused)))
+{
+ return 0;
+}
+
+void
+grub_util_devmapper_cleanup (void)
+{
+}
+
+enum grub_dev_abstraction_types
+grub_util_get_dm_abstraction (const char *os_dev __attribute__ ((unused)))
+{
+ return GRUB_DEV_ABSTRACTION_NONE;
+}
+
+char *
+grub_util_get_vg_uuid (const char *os_dev __attribute__ ((unused)))
+{
+ return NULL;
+}
+
+char *
+grub_util_devmapper_part_to_disk (struct stat *st __attribute__ ((unused)),
+ int *is_part __attribute__ ((unused)),
+ const char *os_dev __attribute__ ((unused)))
+{
+ return NULL;
+}
+
+char *
+grub_util_get_devmapper_grub_dev (const char *os_dev __attribute__ ((unused)))
+{
+ return NULL;
+}
+
+#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 <sys/param.h>
+# include <sys/mount.h>
+# include <sys/disk.h> /* DIOCGMEDIASIZE */
+# include <sys/param.h>
+# include <sys/sysctl.h>
+#include <libgeom.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/cryptodisk.h>
+
+#include <sys/wait.h>
+
+#include <libgeom.h>
+
+static const char *
+grub_util_get_geom_abstraction (const char *dev)
+{
+ char *whole;
+ struct gmesh mesh;
+ struct gclass *class;
+ const char *name;
+ int err;
+
+ if (strncmp (dev, "/dev/", sizeof ("/dev/") - 1) != 0)
+ return 0;
+ name = dev + sizeof ("/dev/") - 1;
+ grub_util_follow_gpart_up (name, NULL, &whole);
+
+ grub_util_info ("following geom '%s'", name);
+
+ err = geom_gettree (&mesh);
+ if (err != 0)
+ /* TRANSLATORS: geom is the name of (k)FreeBSD device framework.
+ Usually left untranslated.
+ */
+ grub_util_error ("%s", _("couldn't open geom"));
+
+ LIST_FOREACH (class, &mesh.lg_class, lg_class)
+ {
+ struct ggeom *geom;
+ LIST_FOREACH (geom, &class->lg_geom, lg_geom)
+ {
+ struct gprovider *provider;
+ LIST_FOREACH (provider, &geom->lg_provider, lg_provider)
+ if (strcmp (provider->lg_name, name) == 0)
+ return class->lg_name;
+ }
+ }
+ return NULL;
+}
+
+enum grub_dev_abstraction_types
+grub_util_get_dev_abstraction_os (const char *os_dev)
+{
+ const char *abstrac;
+ abstrac = grub_util_get_geom_abstraction (os_dev);
+ grub_util_info ("abstraction of %s is %s", os_dev, abstrac);
+ if (abstrac && grub_strcasecmp (abstrac, "eli") == 0)
+ return GRUB_DEV_ABSTRACTION_GELI;
+
+ /* Check for LVM. */
+ if (!strncmp (os_dev, LVM_DEV_MAPPER_STRING, sizeof(LVM_DEV_MAPPER_STRING)-1))
+ return GRUB_DEV_ABSTRACTION_LVM;
+ return GRUB_DEV_ABSTRACTION_NONE;
+}
+
+char *
+grub_util_part_to_disk (const char *os_dev, struct stat *st,
+ int *is_part)
+{
+ char *out, *out2;
+ if (strncmp (os_dev, "/dev/", sizeof ("/dev/") - 1) != 0)
+ return xstrdup (os_dev);
+ grub_util_follow_gpart_up (os_dev + sizeof ("/dev/") - 1, NULL, &out);
+
+ if (grub_strcmp (os_dev + sizeof ("/dev/") - 1, out) != 0)
+ *is_part = 1;
+ out2 = xasprintf ("/dev/%s", out);
+ free (out);
+
+ return out2;
+}
+
+int
+grub_util_pull_device_os (const char *os_dev,
+ enum grub_dev_abstraction_types ab)
+{
+ switch (ab)
+ {
+ case GRUB_DEV_ABSTRACTION_GELI:
+ {
+ char *whole;
+ struct gmesh mesh;
+ struct gclass *class;
+ const char *name;
+ int err;
+ char *lastsubdev = NULL;
+
+ if (strncmp (os_dev, "/dev/", sizeof ("/dev/") - 1) != 0)
+ return 1;
+ name = os_dev + sizeof ("/dev/") - 1;
+ grub_util_follow_gpart_up (name, NULL, &whole);
+
+ grub_util_info ("following geom '%s'", name);
+
+ err = geom_gettree (&mesh);
+ if (err != 0)
+ /* TRANSLATORS: geom is the name of (k)FreeBSD device framework.
+ Usually left untranslated.
+ */
+ grub_util_error ("%s", _("couldn't open geom"));
+
+ LIST_FOREACH (class, &mesh.lg_class, lg_class)
+ {
+ struct ggeom *geom;
+ LIST_FOREACH (geom, &class->lg_geom, lg_geom)
+ {
+ struct gprovider *provider;
+ LIST_FOREACH (provider, &geom->lg_provider, lg_provider)
+ if (strcmp (provider->lg_name, name) == 0)
+ {
+ struct gconsumer *consumer;
+ char *fname;
+
+ LIST_FOREACH (consumer, &geom->lg_consumer, lg_consumer)
+ break;
+ if (!consumer)
+ grub_util_error ("%s",
+ _("couldn't find geli consumer"));
+ fname = xasprintf ("/dev/%s", consumer->lg_provider->lg_name);
+ grub_util_info ("consumer %s", consumer->lg_provider->lg_name);
+ lastsubdev = consumer->lg_provider->lg_name;
+ grub_util_pull_device (fname);
+ free (fname);
+ }
+ }
+ }
+ if (ab == GRUB_DEV_ABSTRACTION_GELI && lastsubdev)
+ {
+ char *fname = xasprintf ("/dev/%s", lastsubdev);
+ char *grdev = grub_util_get_grub_dev (fname);
+ free (fname);
+
+ if (grdev)
+ {
+ grub_err_t gr_err;
+ gr_err = grub_cryptodisk_cheat_mount (grdev, os_dev);
+ if (gr_err)
+ grub_util_error (_("can't mount encrypted volume `%s': %s"),
+ lastsubdev, grub_errmsg);
+ }
+
+ grub_free (grdev);
+ }
+ }
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+char *
+grub_util_get_grub_dev_os (const char *os_dev)
+{
+ char *grub_dev = NULL;
+
+ switch (grub_util_get_dev_abstraction (os_dev))
+ {
+ /* Fallback for non-devmapper build. In devmapper-builds LVM is handled
+ in rub_util_get_devmapper_grub_dev and this point isn't reached.
+ */
+ case GRUB_DEV_ABSTRACTION_LVM:
+ {
+ unsigned short len;
+ grub_size_t offset = sizeof (LVM_DEV_MAPPER_STRING) - 1;
+
+ len = strlen (os_dev) - offset + 1;
+ grub_dev = xmalloc (len + sizeof ("lvm/"));
+
+ grub_memcpy (grub_dev, "lvm/", sizeof ("lvm/") - 1);
+ grub_memcpy (grub_dev + sizeof ("lvm/") - 1, os_dev + offset, len);
+ }
+ break;
+
+ case GRUB_DEV_ABSTRACTION_GELI:
+ {
+ char *whole;
+ struct gmesh mesh;
+ struct gclass *class;
+ const char *name;
+ int err;
+
+ if (strncmp (os_dev, "/dev/", sizeof ("/dev/") - 1) != 0)
+ return 0;
+ name = os_dev + sizeof ("/dev/") - 1;
+ grub_util_follow_gpart_up (name, NULL, &whole);
+
+ grub_util_info ("following geom '%s'", name);
+
+ err = geom_gettree (&mesh);
+ if (err != 0)
+ /* TRANSLATORS: geom is the name of (k)FreeBSD device framework.
+ Usually left untranslated.
+ */
+ grub_util_error ("%s", _("couldn't open geom"));
+
+ LIST_FOREACH (class, &mesh.lg_class, lg_class)
+ {
+ struct ggeom *geom;
+ LIST_FOREACH (geom, &class->lg_geom, lg_geom)
+ {
+ struct gprovider *provider;
+ LIST_FOREACH (provider, &geom->lg_provider, lg_provider)
+ if (strcmp (provider->lg_name, name) == 0)
+ {
+ struct gconsumer *consumer;
+ char *fname;
+ char *uuid;
+
+ LIST_FOREACH (consumer, &geom->lg_consumer, lg_consumer)
+ break;
+ if (!consumer)
+ grub_util_error ("%s",
+ _("couldn't find geli consumer"));
+ fname = xasprintf ("/dev/%s", consumer->lg_provider->lg_name);
+ uuid = grub_util_get_geli_uuid (fname);
+ if (!uuid)
+ grub_util_error ("%s",
+ _("couldn't retrieve geli UUID"));
+ grub_dev = xasprintf ("cryptouuid/%s", uuid);
+ free (fname);
+ free (uuid);
+ }
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return grub_dev;
+}
+
+/* FIXME: geom actually gives us the whole container hierarchy.
+ It can be used more efficiently than this. */
+void
+grub_util_follow_gpart_up (const char *name, grub_disk_addr_t *off_out, char **name_out)
+{
+ struct gmesh mesh;
+ struct gclass *class;
+ int err;
+ struct ggeom *geom;
+
+ grub_util_info ("following geom '%s'", name);
+
+ err = geom_gettree (&mesh);
+ if (err != 0)
+ /* TRANSLATORS: geom is the name of (k)FreeBSD device framework.
+ Usually left untranslated.
+ */
+ grub_util_error ("%s", _("couldn't open geom"));
+
+ LIST_FOREACH (class, &mesh.lg_class, lg_class)
+ if (strcasecmp (class->lg_name, "part") == 0)
+ break;
+ if (!class)
+ /* TRANSLATORS: geom is the name of (k)FreeBSD device framework.
+ Usually left untranslated. "part" is the identifier of one of its
+ classes. */
+ grub_util_error ("%s", _("couldn't find geom `part' class"));
+
+ LIST_FOREACH (geom, &class->lg_geom, lg_geom)
+ {
+ struct gprovider *provider;
+ LIST_FOREACH (provider, &geom->lg_provider, lg_provider)
+ if (strcmp (provider->lg_name, name) == 0)
+ {
+ char *name_tmp = xstrdup (geom->lg_name);
+ grub_disk_addr_t off = 0;
+ struct gconfig *config;
+ grub_util_info ("geom '%s' has parent '%s'", name, geom->lg_name);
+
+ grub_util_follow_gpart_up (name_tmp, &off, name_out);
+ free (name_tmp);
+ LIST_FOREACH (config, &provider->lg_config, lg_config)
+ if (strcasecmp (config->lg_name, "start") == 0)
+ off += strtoull (config->lg_val, 0, 10);
+ if (off_out)
+ *off_out = off;
+ return;
+ }
+ }
+ grub_util_info ("geom '%s' has no parent", name);
+ if (name_out)
+ *name_out = xstrdup (name);
+ if (off_out)
+ *off_out = 0;
+}
+
+grub_disk_addr_t
+grub_util_find_partition_start_os (const char *dev)
+{
+ grub_disk_addr_t out;
+ if (strncmp (dev, "/dev/", sizeof ("/dev/") - 1) != 0)
+ return 0;
+ grub_util_follow_gpart_up (dev + sizeof ("/dev/") - 1, &out, NULL);
+
+ return out;
+}
--- /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 <hurd.h>
+#include <hurd/lookup.h>
+#include <hurd/fs.h>
+#include <sys/mman.h>
+
+
+char *
+grub_util_find_hurd_root_device (const char *path)
+{
+ file_t file;
+ error_t err;
+ char *argz = NULL, *name = NULL, *ret;
+ size_t argz_len = 0;
+ int i;
+
+ file = file_name_lookup (path, 0, 0);
+ if (file == MACH_PORT_NULL)
+ /* TRANSLATORS: The first %s is the file being looked at, the second %s is
+ the error message. */
+ grub_util_error (_("cannot open `%s': %s"), path, strerror (errno));
+
+ /* This returns catenated 0-terminated strings. */
+ err = file_get_fs_options (file, &argz, &argz_len);
+ if (err)
+ /* TRANSLATORS: On GNU/Hurd, a "translator" is similar to a filesystem
+ mount, but handled by a userland daemon, whose invocation command line
+ is being fetched here. First %s is the file being looked at (for which
+ we are fetching the "translator" command line), second %s is the error
+ message.
+ */
+ grub_util_error (_("cannot get translator command line "
+ "for path `%s': %s"), path, strerror(err));
+ if (argz_len == 0)
+ grub_util_error (_("translator command line is empty for path `%s'"), path);
+
+ /* Make sure the string is terminated. */
+ argz[argz_len-1] = 0;
+
+ /* Skip first word (translator path) and options. */
+ for (i = strlen (argz) + 1; i < argz_len; i += strlen (argz + i) + 1)
+ {
+ if (argz[i] != '-')
+ {
+ /* Non-option. Only accept one, assumed to be the FS path. */
+ /* XXX: this should be replaced by an RPC to the translator. */
+ if (name)
+ /* TRANSLATORS: we expect to get something like
+ /hurd/foobar --option1 --option2=baz /dev/something
+ */
+ grub_util_error (_("translator `%s' for path `%s' has several "
+ "non-option words, at least `%s' and `%s'"),
+ argz, path, name, argz + i);
+ name = argz + i;
+ }
+ }
+
+ if (!name)
+ /* TRANSLATORS: we expect to get something like
+ /hurd/foobar --option1 --option2=baz /dev/something
+ */
+ grub_util_error (_("translator `%s' for path `%s' is given only options, "
+ "cannot find device part"), argz, path);
+
+ if (strncmp (name, "device:", sizeof ("device:") - 1) == 0)
+ {
+ char *dev_name = name + sizeof ("device:") - 1;
+ size_t size = sizeof ("/dev/") - 1 + strlen (dev_name) + 1;
+ char *next;
+ ret = malloc (size);
+ next = stpncpy (ret, "/dev/", size);
+ stpncpy (next, dev_name, size - (next - ret));
+ }
+ else if (!strncmp (name, "file:", sizeof ("file:") - 1))
+ ret = strdup (name + sizeof ("file:") - 1);
+ else
+ ret = strdup (name);
+
+ munmap (argz, argz_len);
+ return ret;
+}
+
+static int
+is_fulldisk (const char *child, const char *parent)
+{
+ if (strcmp (parent, child) == 0)
+ return 1;
+ if (strncmp (parent, "/dev/", sizeof ("/dev/") - 1) == 0
+ && child[0] !=0 && strcmp (parent + sizeof ("/dev/") - 1, child) == 0)
+ return 1;
+ if (strncmp (child, "/dev/", sizeof ("/dev/") - 1) == 0
+ && parent[0] != 0 && strcmp (child + sizeof ("/dev/") - 1, parent) == 0)
+ return 1;
+ return 0;
+}
+
+char *
+grub_util_part_to_disk (const char *os_dev,
+ struct stat *st __attribute__ ((unused)),
+ int *is_part)
+{
+ char *path;
+ grub_disk_addr_t offset;
+ char *p;
+
+ if (!grub_util_hurd_get_disk_info (os_dev, NULL, &offset, NULL, &path))
+ return xstrdup (os_dev);
+
+ /* Some versions of Hurd use badly glued Linux code to handle partitions
+ resulting in partitions being promoted to disks. */
+ if (path && !(offset == 0 && is_fulldisk (path, os_dev)
+ && (strncmp ("/dev/sd", os_dev, 7) == 0
+ || strncmp ("/dev/hd", os_dev, 7) == 0)))
+ {
+ *is_part = !is_fulldisk (path, os_dev);
+ if (path[0] != '/')
+ {
+ char *n = xasprintf ("/dev/%s", path);
+ free (path);
+ path = n;
+ }
+ return path;
+ }
+ free (path);
+
+ path = xstrdup (os_dev);
+
+ p = strchr (path + 7, 's');
+ if (p)
+ {
+ *is_part = 1;
+ *p = '\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)
+{
+ grub_uint32_t secsize;
+ grub_disk_addr_t offset;
+ char *path;
+ if (!grub_util_hurd_get_disk_info (dev, &secsize, &offset, NULL, &path))
+ return 0;
+ if (path && !(offset == 0 && is_fulldisk (path, dev)
+ && (strncmp ("/dev/sd", dev, 7) == 0
+ || strncmp ("/dev/hd", dev, 7) == 0)))
+ {
+ free (path);
+ return (secsize / 512) * offset;
+ }
+ free (path);
+ return -1;
+}
--- /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 <sys/ioctl.h> /* ioctl */
+#include <sys/mount.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>
+
+
+/* Defines taken from btrfs/ioctl.h. */
+
+struct btrfs_ioctl_dev_info_args
+{
+ grub_uint64_t devid;
+ grub_uint8_t uuid[16];
+ grub_uint64_t bytes_used;
+ grub_uint64_t total_bytes;
+ grub_uint64_t unused[379];
+ grub_uint8_t path[1024];
+};
+
+struct btrfs_ioctl_fs_info_args
+{
+ grub_uint64_t max_id;
+ grub_uint64_t num_devices;
+ grub_uint8_t fsid[16];
+ grub_uint64_t reserved[124];
+};
+
+#define BTRFS_IOC_DEV_INFO _IOWR(0x94, 30, \
+ struct btrfs_ioctl_dev_info_args)
+#define BTRFS_IOC_FS_INFO _IOR(0x94, 31, \
+ struct btrfs_ioctl_fs_info_args)
+
+static int
+grub_util_is_imsm (const char *os_dev);
+
+
+#define ESCAPED_PATH_MAX (4 * PATH_MAX)
+struct mountinfo_entry
+{
+ int id;
+ int major, minor;
+ char enc_root[ESCAPED_PATH_MAX + 1], enc_path[ESCAPED_PATH_MAX + 1];
+ char fstype[ESCAPED_PATH_MAX + 1], device[ESCAPED_PATH_MAX + 1];
+};
+
+/* Statting something on a btrfs filesystem always returns a virtual device
+ major/minor pair rather than the real underlying device, because btrfs
+ can span multiple underlying devices (and even if it's currently only
+ using a single device it can be dynamically extended onto another). We
+ can't deal with the multiple-device case yet, but in the meantime, we can
+ at least cope with the single-device case by scanning
+ /proc/self/mountinfo. */
+static void
+unescape (char *str)
+{
+ char *optr;
+ const char *iptr;
+ for (iptr = optr = str; *iptr; optr++)
+ {
+ if (iptr[0] == '\\' && iptr[1] >= '0' && iptr[1] < '8'
+ && iptr[2] >= '0' && iptr[2] < '8'
+ && iptr[3] >= '0' && iptr[3] < '8')
+ {
+ *optr = (((iptr[1] - '0') << 6) | ((iptr[2] - '0') << 3)
+ | (iptr[3] - '0'));
+ iptr += 4;
+ }
+ else
+ *optr = *iptr++;
+ }
+ *optr = 0;
+}
+
+static char **
+grub_find_root_devices_from_btrfs (const char *dir)
+{
+ int fd;
+ struct btrfs_ioctl_fs_info_args fsi;
+ int i, j = 0;
+ char **ret;
+
+ fd = open (dir, 0);
+ if (!fd)
+ return NULL;
+
+ if (ioctl (fd, BTRFS_IOC_FS_INFO, &fsi) < 0)
+ {
+ close (fd);
+ return NULL;
+ }
+
+ ret = xmalloc ((fsi.num_devices + 1) * sizeof (ret[0]));
+
+ for (i = 1; i <= fsi.max_id && j < fsi.num_devices; i++)
+ {
+ struct btrfs_ioctl_dev_info_args devi;
+ memset (&devi, 0, sizeof (devi));
+ devi.devid = i;
+ if (ioctl (fd, BTRFS_IOC_DEV_INFO, &devi) < 0)
+ {
+ close (fd);
+ free (ret);
+ return NULL;
+ }
+ ret[j++] = xstrdup ((char *) devi.path);
+ if (j >= fsi.num_devices)
+ break;
+ }
+ close (fd);
+ ret[j] = 0;
+ return ret;
+}
+
+char **
+grub_find_root_devices_from_mountinfo (const char *dir, char **relroot)
+{
+ FILE *fp;
+ char *buf = NULL;
+ size_t len = 0;
+ grub_size_t entry_len = 0, entry_max = 4;
+ struct mountinfo_entry *entries;
+ struct mountinfo_entry parent_entry = { 0, 0, 0, "", "", "", "" };
+ int i;
+
+ if (! *dir)
+ dir = "/";
+ if (relroot)
+ *relroot = NULL;
+
+ fp = fopen ("/proc/self/mountinfo", "r");
+ if (! fp)
+ return NULL; /* fall through to other methods */
+
+ entries = xmalloc (entry_max * sizeof (*entries));
+
+ /* First, build a list of relevant visible mounts. */
+ while (getline (&buf, &len, fp) > 0)
+ {
+ struct mountinfo_entry entry;
+ int count;
+ size_t enc_path_len;
+ const char *sep;
+
+ if (sscanf (buf, "%d %d %u:%u %s %s%n",
+ &entry.id, &parent_entry.id, &entry.major, &entry.minor,
+ entry.enc_root, entry.enc_path, &count) < 6)
+ continue;
+
+ unescape (entry.enc_root);
+ unescape (entry.enc_path);
+
+ enc_path_len = strlen (entry.enc_path);
+ /* Check that enc_path is a prefix of dir. The prefix must either be
+ the entire string, or end with a slash, or be immediately followed
+ by a slash. */
+ if (strncmp (dir, entry.enc_path, enc_path_len) != 0 ||
+ (enc_path_len && dir[enc_path_len - 1] != '/' &&
+ dir[enc_path_len] && dir[enc_path_len] != '/'))
+ continue;
+
+ sep = strstr (buf + count, " - ");
+ if (!sep)
+ continue;
+
+ sep += sizeof (" - ") - 1;
+ if (sscanf (sep, "%s %s", entry.fstype, entry.device) != 2)
+ continue;
+
+ unescape (entry.device);
+
+ /* Using the mount IDs, find out where this fits in the list of
+ visible mount entries we've seen so far. There are three
+ interesting cases. Firstly, it may be inserted at the end: this is
+ the usual case of /foo/bar being mounted after /foo. Secondly, it
+ may be inserted at the start: for example, this can happen for
+ filesystems that are mounted before / and later moved under it.
+ Thirdly, it may occlude part or all of the existing filesystem
+ tree, in which case the end of the list needs to be pruned and this
+ new entry will be inserted at the end. */
+ if (entry_len >= entry_max)
+ {
+ entry_max <<= 1;
+ entries = xrealloc (entries, entry_max * sizeof (*entries));
+ }
+
+ if (!entry_len)
+ {
+ /* Initialise list. */
+ entry_len = 2;
+ entries[0] = parent_entry;
+ entries[1] = entry;
+ }
+ else
+ {
+ for (i = entry_len - 1; i >= 0; i--)
+ {
+ if (entries[i].id == parent_entry.id)
+ {
+ /* Insert at end, pruning anything previously above this. */
+ entry_len = i + 2;
+ entries[i + 1] = entry;
+ break;
+ }
+ else if (i == 0 && entries[i].id == entry.id)
+ {
+ /* Insert at start. */
+ entry_len++;
+ memmove (entries + 1, entries,
+ (entry_len - 1) * sizeof (*entries));
+ entries[0] = parent_entry;
+ entries[1] = entry;
+ break;
+ }
+ }
+ }
+ }
+
+ /* Now scan visible mounts for the ones we're interested in. */
+ for (i = entry_len - 1; i >= 0; i--)
+ {
+ char **ret = NULL;
+ if (!*entries[i].device)
+ continue;
+
+ if (grub_strcmp (entries[i].fstype, "fuse.zfs") == 0
+ || grub_strcmp (entries[i].fstype, "zfs") == 0)
+ {
+ char *slash;
+ slash = strchr (entries[i].device, '/');
+ if (slash)
+ *slash = 0;
+ ret = grub_util_find_root_devices_from_poolname (entries[i].device);
+ if (slash)
+ *slash = '/';
+ if (relroot)
+ {
+ if (!slash)
+ *relroot = xasprintf ("/@%s", entries[i].enc_root);
+ else if (strchr (slash + 1, '@'))
+ *relroot = xasprintf ("/%s%s", slash + 1, entries[i].enc_root);
+ else
+ *relroot = xasprintf ("/%s@%s", slash + 1, entries[i].enc_root);
+ }
+ }
+ else if (grub_strcmp (entries[i].fstype, "btrfs") == 0)
+ {
+ ret = grub_find_root_devices_from_btrfs (dir);
+ if (relroot)
+ {
+ char *ptr;
+ *relroot = xmalloc (strlen (entries[i].enc_root) +
+ 2 + strlen (dir));
+ ptr = grub_stpcpy (*relroot, entries[i].enc_root);
+ if (strlen (dir) > strlen (entries[i].enc_path))
+ {
+ while (ptr > *relroot && *(ptr - 1) == '/')
+ ptr--;
+ if (dir[strlen (entries[i].enc_path)] != '/')
+ *ptr++ = '/';
+ ptr = grub_stpcpy (ptr, dir + strlen (entries[i].enc_path));
+ }
+ *ptr = 0;
+ }
+ }
+ if (!ret)
+ {
+ ret = xmalloc (2 * sizeof (ret[0]));
+ ret[0] = strdup (entries[i].device);
+ ret[1] = 0;
+ if (relroot)
+ *relroot = strdup (entries[i].enc_root);
+ }
+ free (buf);
+ free (entries);
+ fclose (fp);
+ return ret;
+ }
+
+ free (buf);
+ free (entries);
+ fclose (fp);
+ return NULL;
+}
+
+static char *
+get_mdadm_uuid (const char *os_dev)
+{
+ char *argv[5];
+ int fd;
+ pid_t pid;
+ FILE *mdadm;
+ char *buf = NULL;
+ size_t len = 0;
+ char *name = NULL;
+
+ /* execvp has inconvenient types, hence the casts. None of these
+ strings will actually be modified. */
+ argv[0] = (char *) "mdadm";
+ argv[1] = (char *) "--detail";
+ argv[2] = (char *) "--export";
+ argv[3] = (char *) os_dev;
+ argv[4] = NULL;
+
+ pid = grub_util_exec_pipe (argv, &fd);
+
+ if (!pid)
+ return NULL;
+
+ /* Parent. Read mdadm's output. */
+ mdadm = fdopen (fd, "r");
+ if (! mdadm)
+ {
+ grub_util_warn (_("Unable to open stream from %s: %s"),
+ "mdadm", strerror (errno));
+ goto out;
+ }
+
+ while (getline (&buf, &len, mdadm) > 0)
+ {
+ if (strncmp (buf, "MD_UUID=", sizeof ("MD_UUID=") - 1) == 0)
+ {
+ char *name_start, *ptri, *ptro;
+
+ free (name);
+ name_start = buf + sizeof ("MD_UUID=") - 1;
+ ptro = name = xmalloc (strlen (name_start) + 1);
+ for (ptri = name_start; *ptri && *ptri != '\n' && *ptri != '\r';
+ ptri++)
+ if ((*ptri >= '0' && *ptri <= '9')
+ || (*ptri >= 'a' && *ptri <= 'f')
+ || (*ptri >= 'A' && *ptri <= 'F'))
+ *ptro++ = *ptri;
+ *ptro = 0;
+ }
+ }
+
+out:
+ close (fd);
+ waitpid (pid, NULL, 0);
+ free (buf);
+
+ return name;
+}
+
+static int
+grub_util_is_imsm (const char *os_dev)
+{
+ int retry;
+ int is_imsm = 0;
+ int container_seen = 0;
+ const char *dev = os_dev;
+
+ do
+ {
+ char *argv[5];
+ int fd;
+ pid_t pid;
+ FILE *mdadm;
+ char *buf = NULL;
+ size_t len = 0;
+
+ retry = 0; /* We'll do one more pass if device is part of container */
+
+ /* execvp has inconvenient types, hence the casts. None of these
+ strings will actually be modified. */
+ argv[0] = (char *) "mdadm";
+ argv[1] = (char *) "--detail";
+ argv[2] = (char *) "--export";
+ argv[3] = (char *) dev;
+ argv[4] = NULL;
+
+ pid = grub_util_exec_pipe (argv, &fd);
+
+ if (!pid)
+ {
+ if (dev != os_dev)
+ free ((void *) dev);
+ return 0;
+ }
+
+ /* Parent. Read mdadm's output. */
+ mdadm = fdopen (fd, "r");
+ if (! mdadm)
+ {
+ grub_util_warn (_("Unable to open stream from %s: %s"),
+ "mdadm", strerror (errno));
+ close (fd);
+ waitpid (pid, NULL, 0);
+ if (dev != os_dev)
+ free ((void *) dev);
+ return 0;
+ }
+
+ while (getline (&buf, &len, mdadm) > 0)
+ {
+ if (strncmp (buf, "MD_CONTAINER=", sizeof ("MD_CONTAINER=") - 1) == 0
+ && !container_seen)
+ {
+ char *newdev, *ptr;
+ newdev = xstrdup (buf + sizeof ("MD_CONTAINER=") - 1);
+ ptr = newdev + strlen (newdev) - 1;
+ for (; ptr >= newdev && (*ptr == '\n' || *ptr == '\r'); ptr--);
+ ptr[1] = 0;
+ grub_util_info ("Container of %s is %s", dev, newdev);
+ dev = newdev;
+ container_seen = retry = 1;
+ break;
+ }
+ if (strncmp (buf, "MD_METADATA=imsm",
+ sizeof ("MD_METADATA=imsm") - 1) == 0)
+ {
+ is_imsm = 1;
+ grub_util_info ("%s is imsm", dev);
+ break;
+ }
+ }
+
+ free (buf);
+ close (fd);
+ waitpid (pid, NULL, 0);
+ }
+ while (retry);
+
+ if (dev != os_dev)
+ free ((void *) dev);
+ return is_imsm;
+}
+
+char *
+grub_util_part_to_disk (const char *os_dev, struct stat *st,
+ int *is_part)
+{
+ char *path = xmalloc (PATH_MAX);
+
+ if (! realpath (os_dev, path))
+ return NULL;
+
+ if (strncmp ("/dev/", path, 5) == 0)
+ {
+ char *p = path + 5;
+
+ /* If this is an IDE disk. */
+ if (strncmp ("ide/", p, 4) == 0)
+ {
+ p = strstr (p, "part");
+ if (p)
+ {
+ *is_part = 1;
+ strcpy (p, "disc");
+ }
+
+ return path;
+ }
+
+ /* If this is a SCSI disk. */
+ if (strncmp ("scsi/", p, 5) == 0)
+ {
+ p = strstr (p, "part");
+ if (p)
+ {
+ *is_part = 1;
+ strcpy (p, "disc");
+ }
+
+ return path;
+ }
+
+ /* If this is a DAC960 disk. */
+ if (strncmp ("rd/c", p, 4) == 0)
+ {
+ /* /dev/rd/c[0-9]+d[0-9]+(p[0-9]+)? */
+ p = strchr (p, 'p');
+ if (p)
+ {
+ *is_part = 1;
+ *p = '\0';
+ }
+
+ return path;
+ }
+
+ /* If this is a Mylex AcceleRAID Array. */
+ if (strncmp ("rs/c", p, 4) == 0)
+ {
+ /* /dev/rd/c[0-9]+d[0-9]+(p[0-9]+)? */
+ p = strchr (p, 'p');
+ if (p)
+ {
+ *is_part = 1;
+ *p = '\0';
+ }
+
+ return path;
+ }
+ /* If this is a CCISS disk. */
+ if (strncmp ("cciss/c", p, sizeof ("cciss/c") - 1) == 0)
+ {
+ /* /dev/cciss/c[0-9]+d[0-9]+(p[0-9]+)? */
+ p = strchr (p, 'p');
+ if (p)
+ {
+ *is_part = 1;
+ *p = '\0';
+ }
+
+ return path;
+ }
+
+ /* If this is an AOE disk. */
+ if (strncmp ("etherd/e", p, sizeof ("etherd/e") - 1) == 0)
+ {
+ /* /dev/etherd/e[0-9]+\.[0-9]+(p[0-9]+)? */
+ p = strchr (p, 'p');
+ if (p)
+ {
+ *is_part = 1;
+ *p = '\0';
+ }
+
+ return path;
+ }
+
+ /* If this is a Compaq Intelligent Drive Array. */
+ if (strncmp ("ida/c", p, sizeof ("ida/c") - 1) == 0)
+ {
+ /* /dev/ida/c[0-9]+d[0-9]+(p[0-9]+)? */
+ p = strchr (p, 'p');
+ if (p)
+ {
+ *is_part = 1;
+ *p = '\0';
+ }
+
+ return path;
+ }
+
+ /* If this is an I2O disk. */
+ if (strncmp ("i2o/hd", p, sizeof ("i2o/hd") - 1) == 0)
+ {
+ /* /dev/i2o/hd[a-z]([0-9]+)? */
+ if (p[sizeof ("i2o/hda") - 1])
+ *is_part = 1;
+ p[sizeof ("i2o/hda") - 1] = '\0';
+ return path;
+ }
+
+ /* If this is a MultiMediaCard (MMC). */
+ if (strncmp ("mmcblk", p, sizeof ("mmcblk") - 1) == 0)
+ {
+ /* /dev/mmcblk[0-9]+(p[0-9]+)? */
+ p = strchr (p, 'p');
+ if (p)
+ {
+ *is_part = 1;
+ *p = '\0';
+ }
+
+ return path;
+ }
+
+ if (strncmp ("md", p, 2) == 0
+ && p[2] >= '0' && p[2] <= '9')
+ {
+ char *ptr = p + 2;
+ while (*ptr >= '0' && *ptr <= '9')
+ ptr++;
+ if (*ptr)
+ *is_part = 1;
+ *ptr = 0;
+ return path;
+ }
+
+ if (strncmp ("nbd", p, 3) == 0
+ && p[3] >= '0' && p[3] <= '9')
+ {
+ char *ptr = p + 3;
+ while (*ptr >= '0' && *ptr <= '9')
+ ptr++;
+ if (*ptr)
+ *is_part = 1;
+ *ptr = 0;
+ return path;
+ }
+
+ /* If this is an IDE, SCSI or Virtio disk. */
+ if (strncmp ("vdisk", p, 5) == 0
+ && p[5] >= 'a' && p[5] <= 'z')
+ {
+ /* /dev/vdisk[a-z][0-9]* */
+ if (p[6])
+ *is_part = 1;
+ p[6] = '\0';
+ return path;
+ }
+ if ((strncmp ("hd", p, 2) == 0
+ || strncmp ("vd", p, 2) == 0
+ || strncmp ("sd", p, 2) == 0)
+ && p[2] >= 'a' && p[2] <= 'z')
+ {
+ char *pp = p + 2;
+ while (*pp >= 'a' && *pp <= 'z')
+ pp++;
+ if (*pp)
+ *is_part = 1;
+ /* /dev/[hsv]d[a-z]+[0-9]* */
+ *pp = '\0';
+ return path;
+ }
+
+ /* If this is a Xen virtual block device. */
+ if ((strncmp ("xvd", p, 3) == 0) && p[3] >= 'a' && p[3] <= 'z')
+ {
+ char *pp = p + 3;
+ while (*pp >= 'a' && *pp <= 'z')
+ pp++;
+ if (*pp)
+ *is_part = 1;
+ /* /dev/xvd[a-z]+[0-9]* */
+ *pp = '\0';
+ return path;
+ }
+ }
+
+ return path;
+}
+
+char *
+grub_util_get_raid_grub_dev (const char *os_dev)
+{
+ char *grub_dev = NULL;
+ if (os_dev[7] == '_' && os_dev[8] == 'd')
+ {
+ /* This a partitionable RAID device of the form /dev/md_dNNpMM. */
+
+ char *p, *q;
+
+ p = strdup (os_dev + sizeof ("/dev/md_d") - 1);
+
+ q = strchr (p, 'p');
+ if (q)
+ *q = ',';
+
+ grub_dev = xasprintf ("md%s", p);
+ free (p);
+ }
+ else if (os_dev[7] == '/' && os_dev[8] == 'd')
+ {
+ /* This a partitionable RAID device of the form /dev/md/dNNpMM. */
+
+ char *p, *q;
+
+ p = strdup (os_dev + sizeof ("/dev/md/d") - 1);
+
+ q = strchr (p, 'p');
+ if (q)
+ *q = ',';
+
+ grub_dev = xasprintf ("md%s", p);
+ free (p);
+ }
+ else if (os_dev[7] >= '0' && os_dev[7] <= '9')
+ {
+ char *p , *q;
+
+ p = strdup (os_dev + sizeof ("/dev/md") - 1);
+
+ q = strchr (p, 'p');
+ if (q)
+ *q = ',';
+
+ grub_dev = xasprintf ("md%s", p);
+ free (p);
+ }
+ else if (os_dev[7] == '/' && os_dev[8] >= '0' && os_dev[8] <= '9')
+ {
+ char *p , *q;
+
+ p = strdup (os_dev + sizeof ("/dev/md/") - 1);
+
+ q = strchr (p, 'p');
+ if (q)
+ *q = ',';
+
+ grub_dev = xasprintf ("md%s", p);
+ free (p);
+ }
+ else if (os_dev[7] == '/')
+ {
+ /* mdraid 1.x with a free name. */
+ char *p , *q;
+
+ p = strdup (os_dev + sizeof ("/dev/md/") - 1);
+
+ q = strchr (p, 'p');
+ if (q)
+ *q = ',';
+
+ grub_dev = xasprintf ("md/%s", p);
+ free (p);
+ }
+ else
+ grub_util_error (_("unknown kind of RAID device `%s'"), os_dev);
+
+ {
+ char *mdadm_name = get_mdadm_uuid (os_dev);
+
+ if (mdadm_name)
+ {
+ const char *q;
+
+ for (q = os_dev + strlen (os_dev) - 1; q >= os_dev
+ && grub_isdigit (*q); q--);
+
+ if (q >= os_dev && *q == 'p')
+ {
+ free (grub_dev);
+ grub_dev = xasprintf ("mduuid/%s,%s", mdadm_name, q + 1);
+ goto done;
+ }
+ free (grub_dev);
+ grub_dev = xasprintf ("mduuid/%s", mdadm_name);
+
+ done:
+ free (mdadm_name);
+ }
+ }
+ return grub_dev;
+}
+
+enum grub_dev_abstraction_types
+grub_util_get_dev_abstraction_os (const char *os_dev)
+{
+#ifndef HAVE_DEVICE_MAPPER
+ if ((strncmp ("/dev/mapper/", os_dev, 12) == 0))
+ return GRUB_DEV_ABSTRACTION_LVM;
+#endif
+
+ /* Check for RAID. */
+ if (!strncmp (os_dev, "/dev/md", 7) && ! grub_util_device_is_mapped (os_dev)
+ && !grub_util_is_imsm (os_dev))
+ return GRUB_DEV_ABSTRACTION_RAID;
+ return GRUB_DEV_ABSTRACTION_NONE;
+}
+
+int
+grub_util_pull_device_os (const char *os_dev,
+ enum grub_dev_abstraction_types ab)
+{
+ switch (ab)
+ {
+ case GRUB_DEV_ABSTRACTION_RAID:
+ {
+ char **devicelist = grub_util_raid_getmembers (os_dev, 0);
+ int i;
+ for (i = 0; devicelist[i];i++)
+ {
+ grub_util_pull_device (devicelist[i]);
+ free (devicelist[i]);
+ }
+ free (devicelist);
+ }
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+char *
+grub_util_get_grub_dev_os (const char *os_dev)
+{
+ char *grub_dev = NULL;
+
+ switch (grub_util_get_dev_abstraction (os_dev))
+ {
+ /* Fallback for non-devmapper build. In devmapper-builds LVM is handled
+ in rub_util_get_devmapper_grub_dev and this point isn't reached.
+ */
+ case GRUB_DEV_ABSTRACTION_LVM:
+ {
+ unsigned short len;
+ grub_size_t offset = sizeof (LVM_DEV_MAPPER_STRING) - 1;
+
+ len = strlen (os_dev) - offset + 1;
+ grub_dev = xmalloc (len + sizeof ("lvm/"));
+
+ grub_memcpy (grub_dev, "lvm/", sizeof ("lvm/") - 1);
+ grub_memcpy (grub_dev + sizeof ("lvm/") - 1, os_dev + offset, len);
+ }
+ break;
+
+ case GRUB_DEV_ABSTRACTION_RAID:
+ grub_dev = grub_util_get_raid_grub_dev (os_dev);
+ break;
+
+ default: /* GRUB_DEV_ABSTRACTION_NONE */
+ break;
+ }
+
+ return grub_dev;
+}
--- /dev/null
+#ifdef __linux__
+#include "getroot_linux.c"
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+#include "getroot_freebsd.c"
+#elif defined(__NetBSD__) || defined(__OpenBSD__)
+#include "getroot_bsd.c"
+#elif defined(__APPLE__)
+#include "getroot_apple.c"
+#elif defined(__sun__)
+#include "getroot_sun.c"
+#elif defined(__GNU__)
+#include "getroot_hurd.c"
+#elif defined(__CYGWIN__)
+#include "getroot_cygwin.c"
+#else
+# warning "No getroot OS-specific functions is available for your system. Device detection may not work properly."
+#include "getroot_basic.c"
+#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 <sys/wait.h>
+
+# include <sys/types.h>
+# include <sys/mkdev.h>
+# include <sys/dkio.h>
+
+
+char *
+grub_util_part_to_disk (const char *os_dev,
+ struct stat *st __attribute__ ((unused)),
+ int *is_part)
+{
+ char *colon = grub_strrchr (os_dev, ':');
+ if (grub_memcmp (os_dev, "/devices", sizeof ("/devices") - 1) == 0
+ && colon)
+ {
+ char *ret = xmalloc (colon - os_dev + sizeof (":q,raw"));
+ if (grub_strcmp (colon, ":q,raw") != 0)
+ *is_part = 1;
+ grub_memcpy (ret, os_dev, colon - os_dev);
+ grub_memcpy (ret + (colon - os_dev), ":q,raw", sizeof (":q,raw"));
+ return ret;
+ }
+ else
+ return xstrdup (os_dev);
+}
+
+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 extpart_info pinfo;
+
+ 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, DKIOCEXTPARTINFO, &pinfo))
+ {
+ grub_error (GRUB_ERR_BAD_DEVICE,
+ "cannot get disk geometry of `%s'", dev);
+ close (fd);
+ return 0;
+ }
+
+ close (fd);
+
+ return pinfo.p_start;
+}