2010-08-01 Robert Millan <rmh@gnu.org>

* 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 `<sys/mount.h>' 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.
This commit is contained in:
Robert Millan 2010-08-01 22:59:02 +02:00
parent 8bfe31d82b
commit c882acc031
4 changed files with 196 additions and 106 deletions

View File

@ -1,3 +1,24 @@
2010-08-01 Robert Millan <rmh@gnu.org>
* 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 `<sys/mount.h>' 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 <cjwatson@ubuntu.com>
* 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 <rmh@gnu.org>
* 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 `<sys/mount.h>' 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 <rmh@gnu.org>
Prevent accidental use of uninitialized libzfs_handle.

View File

@ -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));

View File

@ -49,10 +49,6 @@
# 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>
@ -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;
}

View File

@ -19,6 +19,7 @@
#include <config.h>
#include <errno.h>
#include <error.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
@ -44,6 +45,15 @@
# include <libdevmapper.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
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