summaryrefslogtreecommitdiff
path: root/usr/src/lib/libshare/common/libshare_zfs.c
diff options
context:
space:
mode:
authordougm <none@none>2006-12-12 12:58:52 -0800
committerdougm <none@none>2006-12-12 12:58:52 -0800
commit1cea05af420c1992d793dc442f4e30c7269fc107 (patch)
tree92b6f3cc0e455d0e04c39f80ee517172f6480108 /usr/src/lib/libshare/common/libshare_zfs.c
parentf229d58b8d8b280c11d5ba6bf476acae7e8f03bd (diff)
downloadillumos-joyent-1cea05af420c1992d793dc442f4e30c7269fc107.tar.gz
6496726 sharemgt issues if you install SUNWCrnet/SUNWCreq/SUNWCuser in snv_53.
Diffstat (limited to 'usr/src/lib/libshare/common/libshare_zfs.c')
-rw-r--r--usr/src/lib/libshare/common/libshare_zfs.c411
1 files changed, 301 insertions, 110 deletions
diff --git a/usr/src/lib/libshare/common/libshare_zfs.c b/usr/src/lib/libshare/common/libshare_zfs.c
index 26bf9a8f9a..bf7d3bf074 100644
--- a/usr/src/lib/libshare/common/libshare_zfs.c
+++ b/usr/src/lib/libshare/common/libshare_zfs.c
@@ -26,21 +26,168 @@
#pragma ident "%Z%%M% %I% %E% SMI"
-#include "libfsmgt.h"
#include <libzfs.h>
#include <string.h>
#include <libshare.h>
#include "libshare_impl.h"
+#include <libintl.h>
extern sa_share_t _sa_add_share(sa_group_t, char *, int, int *);
extern sa_group_t _sa_create_zfs_group(sa_group_t, char *);
extern char *sa_fstype(char *);
extern void set_node_attr(void *, char *, char *);
extern int sa_is_share(void *);
+
+/*
+ * File system specific code for ZFS. The original code was stolen
+ * from the "zfs" command and modified to better suit this library's
+ * usage.
+ */
+
+typedef struct get_all_cbdata {
+ zfs_handle_t **cb_handles;
+ size_t cb_alloc;
+ size_t cb_used;
+} get_all_cbdata_t;
+
+static libzfs_handle_t *zfs_libhandle = NULL;
+static zfs_handle_t **zfs_list = NULL;
+static size_t zfs_list_count = 0;
+
+/*
+ * sa_zfs_init()
+ *
+ * initialize an access handle into libzfs
+ */
+
+void
+sa_zfs_init()
+{
+ zfs_libhandle = libzfs_init();
+ libzfs_print_on_error(zfs_libhandle, B_TRUE);
+}
+
+/*
+ * sa_zfs_fini()
+ *
+ * cleanup data structures and the libzfs handle used for accessing
+ * zfs file share info.
+ */
+
+void
+sa_zfs_fini()
+{
+ if (zfs_libhandle != NULL) {
+ libzfs_fini(zfs_libhandle);
+ zfs_libhandle = NULL;
+ if (zfs_list != NULL) {
+ /*
+ * contents of zfs_list were already freed by the call to
+ * libzfs_fini().
+ */
+ free(zfs_list);
+ zfs_list = NULL;
+ }
+ }
+}
+
+/*
+ * get_one_filesystem(zfs_handle_t, data)
+ *
+ * an interator function called while iterating through the ZFS
+ * root. It accumulates into an array of file system handles that can
+ * be used to derive info about those file systems.
+ */
+
+static int
+get_one_filesystem(zfs_handle_t *zhp, void *data)
+{
+ get_all_cbdata_t *cbp = data;
+
+ /*
+ * Skip any zvols
+ */
+ if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) {
+ zfs_close(zhp);
+ return (0);
+ }
+
+ if (cbp->cb_alloc == cbp->cb_used) {
+ zfs_handle_t **handles;
+
+ if (cbp->cb_alloc == 0)
+ cbp->cb_alloc = 64;
+ else
+ cbp->cb_alloc *= 2;
+
+ handles = calloc(1, cbp->cb_alloc * sizeof (void *));
+ if (handles == NULL) {
+ return (0);
+ }
+
+ if (cbp->cb_handles) {
+ (void) memcpy(handles, cbp->cb_handles,
+ cbp->cb_used * sizeof (void *));
+ free(cbp->cb_handles);
+ }
+
+ cbp->cb_handles = handles;
+ }
+
+ cbp->cb_handles[cbp->cb_used++] = zhp;
+
+ return (zfs_iter_filesystems(zhp, get_one_filesystem, data));
+}
+
/*
- * File system specific code for ZFS
+ * get_all_filesystems(zfs_handle_t ***fslist, size_t *count)
+ *
+ * iterate through all ZFS file systems starting at the root. Returns
+ * a count and an array of handle pointers. Allocating is only done
+ * once. The caller does not need to free since it will be done at
+ * sa_zfs_fini() time.
*/
+static void
+get_all_filesystems(zfs_handle_t ***fslist, size_t *count)
+{
+ get_all_cbdata_t cb = { 0 };
+
+ if (zfs_list != NULL) {
+ *fslist = zfs_list;
+ *count = zfs_list_count;
+ return;
+ }
+
+ (void) zfs_iter_root(zfs_libhandle, get_one_filesystem, &cb);
+
+ zfs_list = *fslist = cb.cb_handles;
+ zfs_list_count = *count = cb.cb_used;
+}
+
+/*
+ * mountpoint_compare(a, b)
+ *
+ * compares the mountpoint on two zfs file systems handles.
+ * returns values following strcmp() model.
+ */
+
+static int
+mountpoint_compare(const void *a, const void *b)
+{
+ zfs_handle_t **za = (zfs_handle_t **)a;
+ zfs_handle_t **zb = (zfs_handle_t **)b;
+ char mounta[MAXPATHLEN];
+ char mountb[MAXPATHLEN];
+
+ verify(zfs_prop_get(*za, ZFS_PROP_MOUNTPOINT, mounta,
+ sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0);
+ verify(zfs_prop_get(*zb, ZFS_PROP_MOUNTPOINT, mountb,
+ sizeof (mountb), NULL, NULL, 0, B_FALSE) == 0);
+
+ return (strcmp(mounta, mountb));
+}
+
/*
* get_zfs_dataset(path)
*
@@ -52,29 +199,44 @@ extern int sa_is_share(void *);
static char *
get_zfs_dataset(char *path)
{
- fs_mntlist_t *list;
- fs_mntlist_t *cur;
- int err;
+ size_t i, count = 0;
char *dataset = NULL;
+ zfs_handle_t **zlist;
+ char mountpoint[ZFS_MAXPROPLEN];
+
+ get_all_filesystems(&zlist, &count);
+ qsort(zlist, count, sizeof (void *), mountpoint_compare);
+ for (i = 0; i < count; i++) {
+ /* must have a mountpoint */
+ if (zfs_prop_get(zlist[i], ZFS_PROP_MOUNTPOINT, mountpoint,
+ sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) {
+ /* no mountpoint */
+ continue;
+ }
- list = fs_get_filtered_mount_list(NULL, NULL, "zfs", NULL,
- NULL, 0, &err);
- for (cur = list; cur != NULL; cur = cur->next) {
- if (strcmp(path, cur->mountp) == 0 ||
- strncmp(path, cur->mountp, strlen(cur->mountp)) == 0) {
- /*
- * we want the longest resource so keep trying. This
- * check avoids dropping out on a partial match. ZFS
- * resources are ordered when mounted in order to
- * ensure inheritence of properties.
- */
- dataset = cur->resource;
+ /* mountpoint must be a path */
+ if (strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) == 0 ||
+ strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0)
+ continue;
+
+ /* canmount must be set */
+ if (!zfs_prop_get_int(zlist[i], ZFS_PROP_CANMOUNT))
+ continue;
+
+ /*
+ * have a mountable handle but want to skip those marked none
+ * and legacy
+ */
+ if (strcmp(mountpoint, path) == 0) {
+ dataset = (char *)zfs_get_name(zlist[i]);
+ break;
}
+
}
+
if (dataset != NULL) {
dataset = strdup(dataset);
}
- fs_free_mount_list(list);
return (dataset);
}
@@ -97,7 +259,7 @@ get_zfs_property(char *dataset, zfs_prop_t property)
if (handle != NULL) {
if (zfs_prop_get(handle, property, shareopts,
sizeof (shareopts), NULL, NULL, 0,
- FALSE) == 0) {
+ B_FALSE) == 0) {
zfs_close(handle);
libzfs_fini(libhandle);
return (strdup(shareopts));
@@ -133,7 +295,7 @@ sa_zfs_is_shared(char *path)
if (handle != NULL) {
if (zfs_prop_get(handle, ZFS_PROP_SHARENFS, shareopts,
sizeof (shareopts), NULL, NULL, 0,
- FALSE) == 0 &&
+ B_FALSE) == 0 &&
strcmp(shareopts, "off") != 0)
ret = 1; /* it is shared */
zfs_close(handle);
@@ -275,21 +437,19 @@ sa_get_zfs_shares(char *groupname)
sa_group_t zfsgroup;
int legacy = 0;
int err;
- fs_mntlist_t *list;
- fs_mntlist_t *cur;
- zfs_handle_t *handle = NULL;
+ zfs_handle_t **zlist;
char shareopts[ZFS_MAXPROPLEN];
sa_share_t share;
zfs_source_t source;
char sourcestr[ZFS_MAXPROPLEN];
- libzfs_handle_t *libhandle;
+ char mountpoint[ZFS_MAXPROPLEN];
char *options;
+ size_t count = 0, i;
/*
* if we can't access libzfs, don't bother doing anything.
*/
- libhandle = libzfs_init();
- if (libhandle == NULL)
+ if (zfs_libhandle == NULL)
return (SA_SYSTEM_ERR);
zfsgroup = find_or_create_group(groupname, "nfs", &err);
@@ -298,94 +458,125 @@ sa_get_zfs_shares(char *groupname)
* need to walk the mounted ZFS pools and datasets to
* find shares that are possible.
*/
- list = fs_get_filtered_mount_list(NULL, NULL, "zfs", NULL,
- NULL, 0, &err);
+ get_all_filesystems(&zlist, &count);
+ qsort(zlist, count, sizeof (void *), mountpoint_compare);
+
group = zfsgroup;
- for (cur = list; cur != NULL; cur = cur->next) {
- handle = zfs_open(libhandle, cur->resource,
- ZFS_TYPE_FILESYSTEM);
- if (handle != NULL) {
- source = ZFS_SRC_ALL;
- if (zfs_prop_get(handle, ZFS_PROP_SHARENFS, shareopts,
+ for (i = 0; i < count; i++) {
+ char *dataset;
+
+ source = ZFS_SRC_ALL;
+ if (zfs_prop_get(zlist[i], ZFS_PROP_MOUNTPOINT, mountpoint,
+ sizeof (mountpoint), NULL, NULL, 0,
+ B_FALSE) != 0) {
+ /* no mountpoint */
+ continue;
+ }
+
+ /*
+ * zfs_get_name value must not be freed. It is just a
+ * pointer to a value in the handle.
+ */
+ if ((dataset = (char *)zfs_get_name(zlist[i])) == NULL)
+ continue;
+
+ /*
+ * only deal with "mounted" file systems since
+ * unmounted file systems can't actually be shared.
+ */
+
+ if (!zfs_is_mounted(zlist[i], NULL))
+ continue;
+
+ if (zfs_prop_get(zlist[i], ZFS_PROP_SHARENFS, shareopts,
sizeof (shareopts), &source, sourcestr,
ZFS_MAXPROPLEN,
- FALSE) == 0 &&
+ B_FALSE) == 0 &&
strcmp(shareopts, "off") != 0) {
- /* it is shared so add to list */
- share = sa_find_share(cur->mountp);
- err = SA_OK;
- if (share != NULL) {
- /*
- * A zfs file system had been shared
- * through tradiditional methods
- * (share/dfstab or added to a non-zfs
- * group. Now it has been added to a
- * ZFS group via the zfs
- * command. Remove from previous
- * config and setup with current
- * options.
- */
- err = sa_remove_share(share);
- share = NULL;
- }
- if (err == SA_OK) {
- if (source & ZFS_SRC_INHERITED) {
- int doshopt = 0;
- /*
- * Need to find the "real" parent
- * sub-group. It may not be mounted,
- * but it was identified in the
- * "sourcestr" variable. The real
- * parent not mounted can occur if
- * "canmount=off and sharenfs=on".
- */
- group = find_or_create_zfs_subgroup(sourcestr,
- shareopts,
- &doshopt);
- if (group != NULL) {
- share = _sa_add_share(group, cur->mountp,
+ /* it is shared so add to list */
+ share = sa_find_share(mountpoint);
+ err = SA_OK;
+ if (share != NULL) {
+ /*
+ * A zfs file system had been shared
+ * through traditional methods
+ * (share/dfstab or added to a non-zfs
+ * group. Now it has been added to a
+ * ZFS group via the zfs
+ * command. Remove from previous
+ * config and setup with current
+ * options.
+ */
+ err = sa_remove_share(share);
+ share = NULL;
+ }
+ if (err == SA_OK) {
+ if (source & ZFS_SRC_INHERITED) {
+ int doshopt = 0;
+ /*
+ * Need to find the "real" parent
+ * sub-group. It may not be mounted, but it
+ * was identified in the "sourcestr"
+ * variable. The real parent not mounted can
+ * occur if "canmount=off and sharenfs=on".
+ */
+ group = find_or_create_zfs_subgroup(sourcestr,
+ shareopts, &doshopt);
+ if (group != NULL) {
+ share = _sa_add_share(group, mountpoint,
SA_SHARE_TRANSIENT,
&err);
- /*
- * some options may only be on
- * shares. If the opt string
- * contains one of those, we
- * put it just on the share.
- */
- if (share != NULL &&
- doshopt == SA_PROP_SHARE_ONLY) {
- options = strdup(shareopts);
- if (options != NULL) {
- err = sa_parse_legacy_options(share,
+ /*
+ * some options may only be on
+ * shares. If the opt string
+ * contains one of those, we
+ * put it just on the share.
+ */
+ if (share != NULL &&
+ doshopt == SA_PROP_SHARE_ONLY) {
+ options = strdup(shareopts);
+ if (options != NULL) {
+ err = sa_parse_legacy_options(share,
options, "nfs");
- free(options);
- }
+ free(options);
}
- } else {
- err = SA_NO_MEMORY;
}
} else {
+ err = SA_NO_MEMORY;
+ }
+ } else {
+ group = _sa_create_zfs_group(zfsgroup, dataset);
+ if (group == NULL) {
+ static int err = 0;
/*
- * this is a sub-group that actually
- * contains the sharenfs property as
- * opposed to a share that inherited.
+ * there is a problem, but we can't do
+ * anything about it at this point so
+ * we issue a warning an move on.
*/
- group = _sa_create_zfs_group(zfsgroup,
- cur->resource);
- set_node_attr(group, "zfs", "true");
- share = _sa_add_share(group, cur->mountp,
- SA_SHARE_TRANSIENT,
- &err);
- if (err == SA_OK) {
- if (strcmp(shareopts, "on") != 0) {
- options = strdup(shareopts);
- if (options != NULL) {
- err = sa_parse_legacy_options(group,
+ if (err == 0) {
+ /* only print error once */
+ (void) fprintf(stderr,
+ gettext("Cannot create ZFS subgroup "
+ "during initialization:"
+ " %s\n"),
+ sa_errorstr(SA_SYSTEM_ERR));
+ err = 1;
+ }
+ continue;
+ }
+ set_node_attr(group, "zfs", "true");
+ share = _sa_add_share(group, mountpoint,
+ SA_SHARE_TRANSIENT, &err);
+ if (err == SA_OK) {
+ if (strcmp(shareopts, "on") != 0) {
+ options = strdup(shareopts);
+ if (options != NULL) {
+ err = sa_parse_legacy_options(group,
options,
"nfs");
- free(options);
- }
- if (err == SA_PROP_SHARE_ONLY) {
+ free(options);
+ }
+ if (err == SA_PROP_SHARE_ONLY) {
/*
* Same as above, some
* properties may only be on
@@ -397,28 +588,28 @@ sa_get_zfs_shares(char *groupname)
* attempting to put it on the
* share.
*/
- options = strdup(shareopts);
- if (options != NULL)
- err = sa_parse_legacy_options(
+ options = strdup(shareopts);
+ if (options != NULL)
+ err = sa_parse_legacy_options(
share,
options,
"nfs");
free(options);
}
- /* unmark the share's changed state */
- set_node_attr(share, "changed", NULL);
- }
+ /* unmark the share's changed state */
+ set_node_attr(share, "changed", NULL);
}
}
}
}
}
}
- if (list != NULL)
- fs_free_mount_list(list);
}
- if (libhandle != NULL)
- libzfs_fini(libhandle);
+ /*
+ * Don't need to free the "zlist" variable since it is only a
+ * pointer to a cached value that will be freed when
+ * sa_fini() is called.
+ */
return (legacy);
}