Enable `grub-probe -t device' resolution on ZFS.
* configure.ac: Check for getfsstat(), libzfs and libnvpair.
* include/grub/util/libnvpair.h: New file.
* include/grub/util/libzfs.h: New file.
* kern/emu/getroot.c: Include `<assert.h>' and `<error.h>'.
[HAVE_LIBZFS && HAVE_LIBNVPAIR]: Include `<grub/util/libzfs.h>' and
`<grub/util/libnvpair.h>'.
[HAVE_GETFSSTAT]: Include `<sys/mount.h>'.
(find_mount_point_from_dir): New static function.
[HAVE_LIBZFS && HAVE_LIBNVPAIR] (find_root_device_from_libzfs): New
function.
[HAVE_LIBZFS && HAVE_LIBNVPAIR] (grub_guess_root_device): Use
find_root_device_from_libzfs() before ressorting to find_root_device().
* include/grub/util/misc.h (grub_util_init_libzfs): New function
prototype.
* util/misc.c: Include `<grub/util/libzfs.h>'.
(grub_util_init_libzfs): New function.
[HAVE_LIBZFS] (libzfs_handle): New global variable.
[HAVE_LIBZFS] (fini_libzfs): New static function.
(grub_util_init_libzfs): New function.
* util/grub-probe.c (main): Call grub_util_init_libzfs().
+2010-07-30 Robert Millan <rmh@gnu.org>
+
+ Enable `grub-probe -t device' resolution on ZFS.
+
+ * configure.ac: Check for getfsstat(), libzfs and libnvpair.
+ * include/grub/util/libnvpair.h: New file.
+ * include/grub/util/libzfs.h: New file.
+
+ * kern/emu/getroot.c: Include `<assert.h>' and `<error.h>'.
+ [HAVE_LIBZFS && HAVE_LIBNVPAIR]: Include `<grub/util/libzfs.h>' and
+ `<grub/util/libnvpair.h>'.
+ [HAVE_GETFSSTAT]: Include `<sys/mount.h>'.
+
+ (find_mount_point_from_dir): New static function.
+ [HAVE_LIBZFS && HAVE_LIBNVPAIR] (find_root_device_from_libzfs): New
+ function.
+ [HAVE_LIBZFS && HAVE_LIBNVPAIR] (grub_guess_root_device): Use
+ find_root_device_from_libzfs() before ressorting to find_root_device().
+
+ * include/grub/util/misc.h (grub_util_init_libzfs): New function
+ prototype.
+ * util/misc.c: Include `<grub/util/libzfs.h>'.
+ (grub_util_init_libzfs): New function.
+ [HAVE_LIBZFS] (libzfs_handle): New global variable.
+ [HAVE_LIBZFS] (fini_libzfs): New static function.
+ (grub_util_init_libzfs): New function.
+ * util/grub-probe.c (main): Call grub_util_init_libzfs().
+
2010-07-30 Robert Millan <rmh@gnu.org>
* include/grub/emu/misc.h (grub_make_system_path_relative_to_its_root)
fi
# Check for functions.
-AC_CHECK_FUNCS(posix_memalign memalign asprintf vasprintf)
+AC_CHECK_FUNCS(posix_memalign memalign asprintf vasprintf getfsstat)
# For opendisk() and getrawpartition() on NetBSD.
# Used in util/deviceiter.c and in util/hostdisk.c.
[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.
--- /dev/null
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_LIBNVPAIR_UTIL_HEADER
+#define GRUB_LIBNVPAIR_UTIL_HEADER 1
+
+#include <stdio.h> /* 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
--- /dev/null
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_LIBZFS_UTIL_HEADER
+#define GRUB_LIBZFS_UTIL_HEADER 1
+
+#include <grub/util/libnvpair.h>
+
+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
char *canonicalize_file_name (const char *path);
void grub_util_init_nls (void);
+void grub_util_init_libzfs (void);
#endif /* ! GRUB_UTIL_MISC_HEADER */
#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>
# include <sys/wait.h>
#endif
+#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR)
+# include <grub/util/libzfs.h>
+# include <grub/util/libnvpair.h>
+#endif
+
+#ifdef HAVE_GETFSSTAT
+# include <sys/mount.h>
+#endif
+
#include <grub/mm.h>
#include <grub/misc.h>
#include <grub/emu/misc.h>
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
#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 = NULL;
+ 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);
+
+ if (nvlist_lookup_nvlist (nvlist, "vdev_tree", &nvlist) != 0)
+ error (1, errno, "nvlist_lookup_nvlist (\"vdev_tree\")");
+
+ if (nvlist_lookup_nvlist_array (nvlist, "children", &nvlist_array, &nvlist_count) != 0)
+ error (1, errno, "nvlist_lookup_nvlist_array (\"children\")");
+
+ do
+ {
+ assert (nvlist_count > 0);
+ } while (nvlist_lookup_nvlist_array (nvlist_array[0], "children",
+ &nvlist_array, &nvlist_count) == 0);
+
+ if (nvlist_lookup_string (nvlist_array[0], "path", &device) != 0)
+ error (1, errno, "nvlist_lookup_string (\"path\")");
+
+ zpool_close (zpool);
+ }
+
+ free (poolname);
+
+ return device;
+}
+#endif
+
#ifdef __MINGW32__
static char *
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);
set_program_name (argv[0]);
grub_util_init_nls ();
+ grub_util_init_libzfs ();
/* Check for options. */
while (1)
#include <grub/misc.h>
#include <grub/cache.h>
#include <grub/util/misc.h>
+#include <grub/util/libzfs.h>
#include <grub/mm.h>
#include <grub/term.h>
#include <grub/time.h>
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