]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
2010-07-30 Robert Millan <rmh@gnu.org>
authorRobert Millan <rmh@aybabtu.com>
Fri, 30 Jul 2010 19:43:12 +0000 (21:43 +0200)
committerRobert Millan <rmh@aybabtu.com>
Fri, 30 Jul 2010 19:43:12 +0000 (21:43 +0200)
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().

ChangeLog
configure.ac
include/grub/util/libnvpair.h [new file with mode: 0644]
include/grub/util/libzfs.h [new file with mode: 0644]
include/grub/util/misc.h
kern/emu/getroot.c
util/grub-probe.c
util/misc.c

index 4026428a72cf3eace87a280b5d7e04192daa7a3f..041f9cadd6da7bbddfbe12beb1664a14685fc7db 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,31 @@
+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)
index aa7f3a15164935fcac58248f8b431da9947f79bd..cc97c7f770534f4271f6798ca7e9cba6b5a88e5a 100644 (file)
@@ -247,7 +247,7 @@ else
 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.
@@ -799,6 +799,15 @@ if test x"$device_mapper_excuse" = x ; then
                [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.
diff --git a/include/grub/util/libnvpair.h b/include/grub/util/libnvpair.h
new file mode 100644 (file)
index 0000000..c4fe174
--- /dev/null
@@ -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 <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
diff --git a/include/grub/util/libzfs.h b/include/grub/util/libzfs.h
new file mode 100644 (file)
index 0000000..a17c47e
--- /dev/null
@@ -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 <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
index 48dfbb8686db9353616a2a92a19e3192d3bdb374..699b9cf2c8bd219a3b9ed96e0d30862f3d80a181 100644 (file)
@@ -59,5 +59,6 @@ char *make_system_path_relative_to_its_root (const char *path);
 char *canonicalize_file_name (const char *path);
 
 void grub_util_init_nls (void);
+void grub_util_init_libzfs (void);
 
 #endif /* ! GRUB_UTIL_MISC_HEADER */
index 58dbac9b4d62d23269cde9bc68b898bb1574a3a6..f2f6311fffb9e67e9118e5d329f05f7f41d4e084 100644 (file)
 #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>
@@ -86,6 +97,62 @@ xgetcwd (void)
   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,88 @@ find_root_device_from_mountinfo (const char *dir)
 
 #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 *
@@ -458,6 +607,12 @@ grub_guess_root_device (const char *dir)
     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);
 
index 56cbc5592c7f040c2df0709c5c24da7e152a04f1..52f2b374758717808661414e29fd7eb06400a5e6 100644 (file)
@@ -359,6 +359,7 @@ main (int argc, char *argv[])
   set_program_name (argv[0]);
 
   grub_util_init_nls ();
+  grub_util_init_libzfs ();
 
   /* Check for options.  */
   while (1)
index 91bc25a554ec98769837d83f7ebb4f799ead083f..0859197bf65a62d5313936a417d82294d2f511ab 100644 (file)
@@ -36,6 +36,7 @@
 #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>
@@ -293,6 +294,25 @@ grub_util_init_nls (void)
   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