New version, with a few bugfixes (find_mount_point_from_dir logic,
use heap allocation, support pools with multiple filesystems).
ChangeLog entry is the same.
=== 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 <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

=== 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 <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

=== 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 <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>
@@ -41,6 +43,15 @@
 # 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 @@
   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 <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 @@
   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

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to