From c882acc031c3ee096c01ee73963ab4628155f3cc Mon Sep 17 00:00:00 2001 From: Robert Millan Date: Sun, 1 Aug 2010 22:59:02 +0200 Subject: [PATCH] 2010-08-01 Robert Millan * include/grub/emu/misc.h (grub_find_mount_point_from_dir) (grub_find_zpool_from_mount_point): New function prototypes. * kern/emu/getroot.c [HAVE_GETFSSTAT]: Move `' to ... * kern/emu/misc.c [HAVE_GETFSSTAT]: ... here. * kern/emu/getroot.c (find_mount_point_from_dir): Move to ... * kern/emu/misc.c (grub_find_mount_point_from_dir): ... this. Remove `static' attribute. * kern/emu/getroot.c (find_root_device_from_libzfs): Split code for finding zpool from mount point into ... * kern/emu/misc.c (grub_find_zpool_from_mount_point): ... this. * kern/emu/misc.c (grub_make_system_path_relative_to_its_root): When requested path is part of a ZFS pool, use grub_find_zpool_from_mount_point() to detect its filesystem name, and generate a path with `/fsname@path' syntax. --- ChangeLog | 42 ++++++++++++ include/grub/emu/misc.h | 8 ++- kern/emu/getroot.c | 112 +++----------------------------- kern/emu/misc.c | 140 +++++++++++++++++++++++++++++++++++++++- 4 files changed, 196 insertions(+), 106 deletions(-) diff --git a/ChangeLog b/ChangeLog index daf5517dc..2956129b3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,24 @@ +2010-08-01 Robert Millan + + * include/grub/emu/misc.h (grub_find_mount_point_from_dir) + (grub_find_zpool_from_mount_point): New function prototypes. + + * kern/emu/getroot.c [HAVE_GETFSSTAT]: Move `' to ... + * kern/emu/misc.c [HAVE_GETFSSTAT]: ... here. + + * kern/emu/getroot.c (find_mount_point_from_dir): Move to ... + * kern/emu/misc.c (grub_find_mount_point_from_dir): ... this. Remove + `static' attribute. + + * kern/emu/getroot.c (find_root_device_from_libzfs): Split code for + finding zpool from mount point into ... + * kern/emu/misc.c (grub_find_zpool_from_mount_point): ... this. + + * kern/emu/misc.c (grub_make_system_path_relative_to_its_root): When + requested path is part of a ZFS pool, use + grub_find_zpool_from_mount_point() to detect its filesystem name, + and generate a path with `/fsname@path' syntax. + 2010-08-01 Colin Watson * include/grub/util/libzfs.h (libzfs_init): Set argument list to @@ -39,6 +60,27 @@ * kern/misc.c (grub_memset): Optimise to reduce cache stalls. +2010-08-01 Robert Millan + + * include/grub/emu/misc.h (grub_find_mount_point_from_dir) + (grub_find_zpool_from_mount_point): New function prototypes. + + * kern/emu/getroot.c [HAVE_GETFSSTAT]: Move `' to ... + * kern/emu/misc.c [HAVE_GETFSSTAT]: ... here. + + * kern/emu/getroot.c (find_mount_point_from_dir): Move to ... + * kern/emu/misc.c (grub_find_mount_point_from_dir): ... this. Remove + `static' attribute. + + * kern/emu/getroot.c (find_root_device_from_libzfs): Split code for + finding zpool from mount point into ... + * kern/emu/misc.c (grub_find_zpool_from_mount_point): ... this. + + * kern/emu/misc.c (grub_make_system_path_relative_to_its_root): When + requested path is part of a ZFS pool, use + grub_find_zpool_from_mount_point() to detect its filesystem name, + and generate a path with `/fsname@path' syntax. + 2010-08-01 Robert Millan Prevent accidental use of uninitialized libzfs_handle. diff --git a/include/grub/emu/misc.h b/include/grub/emu/misc.h index dc48d91a8..5047a9406 100644 --- a/include/grub/emu/misc.h +++ b/include/grub/emu/misc.h @@ -44,7 +44,13 @@ extern const char *program_name; void grub_init_all (void); void grub_fini_all (void); -char *grub_make_system_path_relative_to_its_root (const char *path) __attribute__ ((warn_unused_result)); +char *grub_find_mount_point_from_dir (const char *dir) + __attribute__ ((warn_unused_result)); +void grub_find_zpool_from_mount_point (const char *mnt_point, + char **poolname, char **poolfs); + +char *grub_make_system_path_relative_to_its_root (const char *path) + __attribute__ ((warn_unused_result)); void * EXPORT_FUNC(xmalloc) (grub_size_t size) __attribute__ ((warn_unused_result)); void * EXPORT_FUNC(xrealloc) (void *ptr, grub_size_t size) __attribute__ ((warn_unused_result)); diff --git a/kern/emu/getroot.c b/kern/emu/getroot.c index 032608d1b..32044536d 100644 --- a/kern/emu/getroot.c +++ b/kern/emu/getroot.c @@ -49,10 +49,6 @@ # include #endif -#ifdef HAVE_GETFSSTAT -# include -#endif - #include #include #include @@ -98,66 +94,6 @@ xgetcwd (void) return path; } -#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR) - -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 ("/"); - } - } -} - -#endif - #ifdef __linux__ /* Statting something on a btrfs filesystem always returns a virtual device @@ -239,52 +175,20 @@ 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 *device; + char *poolname; + char *poolfs; 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 + mnt_point = grub_find_mount_point_from_dir (dir); + grub_find_zpool_from_mount_point (mnt_point, &poolname, &poolfs); if (! poolname) - return NULL; - - slash = strchr (poolname, '/'); - if (slash) { - *slash = '\0'; - poolfs = slash + 1; + free (mnt_point); + return NULL; } { @@ -317,6 +221,8 @@ find_root_device_from_libzfs (const char *dir) } free (poolname); + if (poolfs) + free (poolfs); return device; } diff --git a/kern/emu/misc.c b/kern/emu/misc.c index 851da7a07..0d71ef3d6 100644 --- a/kern/emu/misc.c +++ b/kern/emu/misc.c @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -44,6 +45,15 @@ # include #endif +#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR) +# include +# include +#endif + +#ifdef HAVE_GETFSSTAT +# include +#endif + int verbosity; void @@ -236,6 +246,114 @@ get_win32_path (const char *path) } #endif +#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR) +/* Not ZFS-specific in itself, but for now it's only used by ZFS-related code. */ +char * +grub_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 ("/"); + } + } +} +#endif + +#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR) + +/* ZFS has similar problems to those of btrfs (see above). */ +void +grub_find_zpool_from_mount_point (const char *mnt_point, char **poolname, char **poolfs) +{ + char *slash; + + *poolname = *poolfs = NULL; + +#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; + + slash = strchr (*poolname, '/'); + if (slash) + { + *slash = '\0'; + *poolfs = xstrdup (slash + 1); + } + else + *poolfs = xstrdup (""); +} +#endif + /* This function never prints trailing slashes (so that its output can be appended a slash unconditionally). */ char * @@ -243,16 +361,26 @@ grub_make_system_path_relative_to_its_root (const char *path) { struct stat st; char *p, *buf, *buf2, *buf3; + char *mnt_point, *poolname = NULL, *poolfs = NULL, *ret; uintptr_t offset = 0; dev_t num; size_t len; /* canonicalize. */ p = canonicalize_file_name (path); - if (p == NULL) grub_util_error ("failed to get canonical path of %s", path); +#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR) + /* For ZFS sub-pool filesystems, could be extended to others (btrfs?). */ + mnt_point = grub_find_mount_point_from_dir (p); + if (mnt_point) + { + grub_find_zpool_from_mount_point (mnt_point, &poolname, &poolfs); + free (mnt_point); + } +#endif + len = strlen (p) + 1; buf = xstrdup (p); free (p); @@ -331,7 +459,15 @@ grub_make_system_path_relative_to_its_root (const char *path) len--; } - return buf3; + if (poolfs) + { + ret = xasprintf ("/%s@%s", poolfs, buf3); + free (buf3); + } + else + ret = buf3; + + return ret; } #ifdef HAVE_DEVICE_MAPPER