=== modified file 'configure.ac'
--- configure.ac 2010-07-04 22:45:14 +0000
+++ configure.ac 2010-07-29 13:43:00 +0000
@@ -247,7 +247,7 @@
fi
# Check for functions.
-AC_CHECK_FUNCS(posix_memalign memalign asprintf vasprintf)
+AC_CHECK_FUNCS(posix_memalign memalign asprintf vasprintf getfsstat)
# For grub-mkisofs
AC_HEADER_MAJOR
@@ -806,6 +806,15 @@
[device_mapper_excuse="need devmapper library"])
fi
+AC_CHECK_LIB([zfs], [libzfs_init],
+ [LDFLAGS="$LDFLAGS -lzfs"
+ AC_DEFINE([HAVE_LIBZFS], [1],
+ [Define to 1 if you have the ZFS library.])],)
+AC_CHECK_LIB([nvpair], [nvlist_print],
+ [LDFLAGS="$LDFLAGS -lnvpair"
+ AC_DEFINE([HAVE_LIBNVPAIR], [1],
+ [Define to 1 if you have the NVPAIR library.])],)
+
AC_SUBST(ASFLAGS)
# Output files.
=== added file 'include/grub/util/libnvpair.h'
--- include/grub/util/libnvpair.h 1970-01-01 00:00:00 +0000
+++ include/grub/util/libnvpair.h 2010-07-29 11:48:47 +0000
@@ -0,0 +1,31 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2010 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 .
+ */
+
+#ifndef GRUB_LIBNVPAIR_UTIL_HEADER
+#define GRUB_LIBNVPAIR_UTIL_HEADER 1
+
+#include /* FILE */
+
+typedef void nvlist_t;
+
+int nvlist_lookup_string (nvlist_t *, const char *, char **);
+int nvlist_lookup_nvlist (nvlist_t *, const char *, nvlist_t **);
+int nvlist_lookup_nvlist_array (nvlist_t *, const char *, nvlist_t ***, unsigned int *);
+void nvlist_print (FILE *, nvlist_t *);
+
+#endif
=== added file 'include/grub/util/libzfs.h'
--- include/grub/util/libzfs.h 1970-01-01 00:00:00 +0000
+++ include/grub/util/libzfs.h 2010-07-29 11:48:36 +0000
@@ -0,0 +1,39 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2010 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 .
+ */
+
+#ifndef GRUB_LIBZFS_UTIL_HEADER
+#define GRUB_LIBZFS_UTIL_HEADER 1
+
+#include
+
+typedef void libzfs_handle_t;
+typedef void zpool_handle_t;
+
+extern libzfs_handle_t *libzfs_init ();
+extern void libzfs_fini (libzfs_handle_t *);
+
+extern zpool_handle_t *zpool_open (libzfs_handle_t *, const char *);
+extern void zpool_close (zpool_handle_t *);
+
+extern int zpool_get_physpath (zpool_handle_t *, const char *);
+
+extern nvlist_t *zpool_get_config (zpool_handle_t *, nvlist_t **);
+
+extern libzfs_handle_t *libzfs_handle;
+
+#endif
=== modified file 'include/grub/util/misc.h'
--- include/grub/util/misc.h 2010-04-27 15:25:12 +0000
+++ include/grub/util/misc.h 2010-07-29 10:34:03 +0000
@@ -59,5 +59,6 @@
char *canonicalize_file_name (const char *path);
void grub_util_init_nls (void);
+void grub_util_init_libzfs (void);
#endif /* ! GRUB_UTIL_MISC_HEADER */
=== modified file 'kern/emu/getroot.c'
--- kern/emu/getroot.c 2010-07-20 22:09:45 +0000
+++ kern/emu/getroot.c 2010-07-29 15:30:35 +0000
@@ -20,11 +20,13 @@
#include
#include
#include
+#include
#include
#include
#include
#include
#include
+#include
#include
#include
#include
@@ -41,6 +43,15 @@
# include
#endif
+#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR)
+# include
+# include
+#endif
+
+#ifdef HAVE_GETFSSTAT
+# include
+#endif
+
#include
#include
#include
@@ -86,6 +97,62 @@
return path;
}
+static char *
+find_mount_point_from_dir (const char *dir)
+{
+ struct stat st;
+ typeof (st.st_dev) fs;
+ char *prev, *next, *slash, *statdir;
+
+ if (stat (dir, &st) == -1)
+ error (1, errno, "stat (%s)", dir);
+
+ fs = st.st_dev;
+
+ prev = xstrdup (dir);
+
+ while (1)
+ {
+ /* Remove last slash. */
+ next = xstrdup (prev);
+ slash = strrchr (next, '/');
+ if (! slash)
+ {
+ free (next);
+ free (prev);
+ return NULL;
+ }
+ *slash = '\0';
+
+ /* A next empty string counts as /. */
+ if (next[0] == '\0')
+ statdir = "/";
+ else
+ statdir = next;
+
+ if (stat (statdir, &st) == -1)
+ error (1, errno, "stat (%s)", next);
+
+ if (st.st_dev != fs)
+ {
+ /* Found mount point. */
+ free (next);
+ return prev;
+ }
+
+ free (prev);
+ prev = next;
+
+ /* We've already seen an empty string, which means we
+ reached /. Nothing left to do. */
+ if (prev[0] == '\0')
+ {
+ free (prev);
+ return xstrdup ("/");
+ }
+ }
+}
+
#ifdef __linux__
/* Statting something on a btrfs filesystem always returns a virtual device
@@ -166,6 +233,78 @@
#endif /* __linux__ */
+#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR)
+
+/* ZFS has similar problems to those of btrfs (see above). */
+static char *
+find_root_device_from_libzfs (const char *dir)
+{
+ char *device;
+ char *poolname = NULL;
+ char *poolfs = NULL;
+ char *mnt_point;
+ char *slash;
+
+ mnt_point = find_mount_point_from_dir (dir);
+
+#ifdef HAVE_GETFSSTAT
+ {
+ int mnt_count = getfsstat (NULL, 0, MNT_WAIT);
+ if (mnt_count == -1)
+ error (1, errno, "getfsstat");
+
+ struct statfs *mnt = xmalloc (mnt_count * sizeof (*mnt));
+
+ mnt_count = getfsstat (mnt, mnt_count * sizeof (*mnt), MNT_WAIT);
+ if (mnt_count == -1)
+ error (1, errno, "getfsstat");
+
+ unsigned int i;
+ for (i = 0; i < (unsigned) mnt_count; i++)
+ if (!strcmp (mnt[i].f_fstypename, "zfs")
+ && !strcmp (mnt[i].f_mntonname, mnt_point))
+ {
+ poolname = xstrdup (mnt[i].f_mntfromname);
+ break;
+ }
+
+ free (mnt);
+ }
+#endif
+
+ if (! poolname)
+ return NULL;
+
+ slash = strchr (poolname, '/');
+ if (slash)
+ {
+ *slash = '\0';
+ poolfs = slash + 1;
+ }
+
+ {
+ zpool_handle_t *zpool;
+ nvlist_t *nvlist;
+ nvlist_t **nvlist_array;
+ unsigned int nvlist_count;
+
+ zpool = zpool_open (libzfs_handle, poolname);
+ nvlist = zpool_get_config (zpool, NULL);
+
+ nvlist_lookup_nvlist (nvlist, "vdev_tree", &nvlist);
+ nvlist_lookup_nvlist_array (nvlist, "children", &nvlist_array, &nvlist_count);
+ assert (nvlist_count > 0);
+ nvlist_lookup_string (nvlist_array[0], "path", &device);
+
+ zpool_close (zpool);
+ }
+
+ free (poolname);
+
+ return device;
+}
+#endif
+
#ifdef __MINGW32__
static char *
@@ -458,6 +597,12 @@
return os_dev;
#endif /* __linux__ */
+#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR)
+ os_dev = find_root_device_from_libzfs (dir);
+ if (os_dev)
+ return os_dev;
+#endif
+
if (stat (dir, &st) < 0)
grub_util_error ("cannot stat `%s'", dir);
=== modified file 'util/grub-probe.c'
--- util/grub-probe.c 2010-07-02 17:35:07 +0000
+++ util/grub-probe.c 2010-07-29 10:35:24 +0000
@@ -348,6 +348,7 @@
set_program_name (argv[0]);
grub_util_init_nls ();
+ grub_util_init_libzfs ();
/* Check for options. */
while (1)
=== modified file 'util/misc.c'
--- util/misc.c 2010-05-20 22:16:10 +0000
+++ util/misc.c 2010-07-29 11:55:45 +0000
@@ -36,6 +36,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -293,6 +294,25 @@
textdomain (PACKAGE);
#endif /* (defined(ENABLE_NLS) && ENABLE_NLS) */
}
+
+#ifdef HAVE_LIBZFS
+libzfs_handle_t *libzfs_handle;
+
+static void
+fini_libzfs (void)
+{
+ libzfs_fini (libzfs_handle);
+}
+#endif
+
+void
+grub_util_init_libzfs (void)
+{
+#ifdef HAVE_LIBZFS
+ libzfs_handle = libzfs_init ();
+ atexit (fini_libzfs);
+#endif
+}
#endif
int