#include <stdio.h>
#include <stdlib.h>
+#include <stddef.h>
#include <string.h>
#include <errno.h>
#include <libintl.h>
#include <libzfs.h>
#include <libshare.h>
#include "libshare_impl.h"
-#include "nfs.h"
-#include "smb.h"
-static sa_share_impl_t alloc_share(const char *zfsname, const char *path);
-static void free_share(sa_share_impl_t share);
-
-static int fstypes_count;
-static sa_fstype_t *fstypes;
-
-sa_fstype_t *
-register_fstype(const char *name, const sa_share_ops_t *ops)
+#define init_share(zfsname, path, shareopts) \
+ { \
+ .sa_zfsname = zfsname, \
+ .sa_mountpoint = path, \
+ .sa_shareopts = shareopts, \
+ }
+#define find_proto(pcol) \
+ /* CSTYLED */ \
+ ({ \
+ sa_fstype_t prot = { \
+ .protocol = pcol, \
+ }; \
+ avl_find(&fstypes, &prot, NULL); \
+ })
+
+static avl_tree_t fstypes;
+
+static int
+fstypes_compar(const void *lhs, const void *rhs)
{
- sa_fstype_t *fstype;
-
- fstype = calloc(1, sizeof (sa_fstype_t));
-
- if (fstype == NULL)
- return (NULL);
-
- fstype->name = name;
- fstype->ops = ops;
- fstype->fsinfo_index = fstypes_count;
-
- fstypes_count++;
-
- fstype->next = fstypes;
- fstypes = fstype;
-
- return (fstype);
+ const sa_fstype_t *l = lhs, *r = rhs;
+ int cmp = strcmp(l->protocol, r->protocol);
+ return ((0 < cmp) - (cmp < 0));
}
__attribute__((constructor)) static void
libshare_init(void)
{
- libshare_nfs_init();
- libshare_smb_init();
+ avl_create(&fstypes, fstypes_compar,
+ sizeof (sa_fstype_t), offsetof(sa_fstype_t, node));
+ avl_add(&fstypes, &libshare_nfs_type);
+ avl_add(&fstypes, &libshare_smb_type);
}
int
sa_enable_share(const char *zfsname, const char *mountpoint,
const char *shareopts, const char *protocol)
{
- int rc, ret = SA_OK;
- boolean_t found_protocol = B_FALSE;
- sa_fstype_t *fstype;
-
- sa_share_impl_t impl_share = alloc_share(zfsname, mountpoint);
- if (impl_share == NULL)
- return (SA_NO_MEMORY);
-
- fstype = fstypes;
- while (fstype != NULL) {
- if (strcmp(fstype->name, protocol) == 0) {
-
- rc = fstype->ops->update_shareopts(impl_share,
- shareopts);
- if (rc != SA_OK)
- break;
+ sa_fstype_t *fstype = find_proto(protocol);
+ if (!fstype)
+ return (SA_INVALID_PROTOCOL);
- rc = fstype->ops->enable_share(impl_share);
- if (rc != SA_OK)
- ret = rc;
-
- found_protocol = B_TRUE;
- }
-
- fstype = fstype->next;
- }
- free_share(impl_share);
-
- return (found_protocol ? ret : SA_INVALID_PROTOCOL);
+ const struct sa_share_impl args =
+ init_share(zfsname, mountpoint, shareopts);
+ return (fstype->enable_share(&args));
}
int
sa_disable_share(const char *mountpoint, const char *protocol)
{
- int rc, ret = SA_OK;
- boolean_t found_protocol = B_FALSE;
- sa_fstype_t *fstype;
-
- sa_share_impl_t impl_share = alloc_share(NULL, mountpoint);
- if (impl_share == NULL)
- return (SA_NO_MEMORY);
-
- fstype = fstypes;
- while (fstype != NULL) {
- if (strcmp(fstype->name, protocol) == 0) {
+ sa_fstype_t *fstype = find_proto(protocol);
+ if (!fstype)
+ return (SA_INVALID_PROTOCOL);
- rc = fstype->ops->disable_share(impl_share);
- if (rc != SA_OK)
- ret = rc;
-
- found_protocol = B_TRUE;
- }
-
- fstype = fstype->next;
- }
- free_share(impl_share);
-
- return (found_protocol ? ret : SA_INVALID_PROTOCOL);
+ const struct sa_share_impl args = init_share(NULL, mountpoint, NULL);
+ return (fstype->disable_share(&args));
}
boolean_t
sa_is_shared(const char *mountpoint, const char *protocol)
{
- sa_fstype_t *fstype;
- boolean_t ret = B_FALSE;
-
- /* guid value is not used */
- sa_share_impl_t impl_share = alloc_share(NULL, mountpoint);
- if (impl_share == NULL)
+ sa_fstype_t *fstype = find_proto(protocol);
+ if (!fstype)
return (B_FALSE);
- fstype = fstypes;
- while (fstype != NULL) {
- if (strcmp(fstype->name, protocol) == 0) {
- ret = fstype->ops->is_shared(impl_share);
- }
- fstype = fstype->next;
- }
- free_share(impl_share);
- return (ret);
+ const struct sa_share_impl args = init_share(NULL, mountpoint, NULL);
+ return (fstype->is_shared(&args));
}
void
sa_commit_shares(const char *protocol)
{
- sa_fstype_t *fstype = fstypes;
- while (fstype != NULL) {
- if (strcmp(fstype->name, protocol) == 0)
- fstype->ops->commit_shares();
- fstype = fstype->next;
- }
+ sa_fstype_t *fstype = find_proto(protocol);
+ if (!fstype)
+ return;
+
+ fstype->commit_shares();
}
/*
sa_errorstr(int err)
{
static char errstr[32];
- char *ret = NULL;
switch (err) {
case SA_OK:
- ret = dgettext(TEXT_DOMAIN, "ok");
- break;
+ return (dgettext(TEXT_DOMAIN, "ok"));
case SA_NO_SUCH_PATH:
- ret = dgettext(TEXT_DOMAIN, "path doesn't exist");
- break;
+ return (dgettext(TEXT_DOMAIN, "path doesn't exist"));
case SA_NO_MEMORY:
- ret = dgettext(TEXT_DOMAIN, "no memory");
- break;
+ return (dgettext(TEXT_DOMAIN, "no memory"));
case SA_DUPLICATE_NAME:
- ret = dgettext(TEXT_DOMAIN, "name in use");
- break;
+ return (dgettext(TEXT_DOMAIN, "name in use"));
case SA_BAD_PATH:
- ret = dgettext(TEXT_DOMAIN, "bad path");
- break;
+ return (dgettext(TEXT_DOMAIN, "bad path"));
case SA_NO_SUCH_GROUP:
- ret = dgettext(TEXT_DOMAIN, "no such group");
- break;
+ return (dgettext(TEXT_DOMAIN, "no such group"));
case SA_CONFIG_ERR:
- ret = dgettext(TEXT_DOMAIN, "configuration error");
- break;
+ return (dgettext(TEXT_DOMAIN, "configuration error"));
case SA_SYSTEM_ERR:
- ret = dgettext(TEXT_DOMAIN, "system error");
- break;
+ return (dgettext(TEXT_DOMAIN, "system error"));
case SA_SYNTAX_ERR:
- ret = dgettext(TEXT_DOMAIN, "syntax error");
- break;
+ return (dgettext(TEXT_DOMAIN, "syntax error"));
case SA_NO_PERMISSION:
- ret = dgettext(TEXT_DOMAIN, "no permission");
- break;
+ return (dgettext(TEXT_DOMAIN, "no permission"));
case SA_BUSY:
- ret = dgettext(TEXT_DOMAIN, "busy");
- break;
+ return (dgettext(TEXT_DOMAIN, "busy"));
case SA_NO_SUCH_PROP:
- ret = dgettext(TEXT_DOMAIN, "no such property");
- break;
+ return (dgettext(TEXT_DOMAIN, "no such property"));
case SA_INVALID_NAME:
- ret = dgettext(TEXT_DOMAIN, "invalid name");
- break;
+ return (dgettext(TEXT_DOMAIN, "invalid name"));
case SA_INVALID_PROTOCOL:
- ret = dgettext(TEXT_DOMAIN, "invalid protocol");
- break;
+ return (dgettext(TEXT_DOMAIN, "invalid protocol"));
case SA_NOT_ALLOWED:
- ret = dgettext(TEXT_DOMAIN, "operation not allowed");
- break;
+ return (dgettext(TEXT_DOMAIN, "operation not allowed"));
case SA_BAD_VALUE:
- ret = dgettext(TEXT_DOMAIN, "bad property value");
- break;
+ return (dgettext(TEXT_DOMAIN, "bad property value"));
case SA_INVALID_SECURITY:
- ret = dgettext(TEXT_DOMAIN, "invalid security type");
- break;
+ return (dgettext(TEXT_DOMAIN, "invalid security type"));
case SA_NO_SUCH_SECURITY:
- ret = dgettext(TEXT_DOMAIN, "security type not found");
- break;
+ return (dgettext(TEXT_DOMAIN, "security type not found"));
case SA_VALUE_CONFLICT:
- ret = dgettext(TEXT_DOMAIN, "property value conflict");
- break;
+ return (dgettext(TEXT_DOMAIN, "property value conflict"));
case SA_NOT_IMPLEMENTED:
- ret = dgettext(TEXT_DOMAIN, "not implemented");
- break;
+ return (dgettext(TEXT_DOMAIN, "not implemented"));
case SA_INVALID_PATH:
- ret = dgettext(TEXT_DOMAIN, "invalid path");
- break;
+ return (dgettext(TEXT_DOMAIN, "invalid path"));
case SA_NOT_SUPPORTED:
- ret = dgettext(TEXT_DOMAIN, "operation not supported");
- break;
+ return (dgettext(TEXT_DOMAIN, "operation not supported"));
case SA_PROP_SHARE_ONLY:
- ret = dgettext(TEXT_DOMAIN, "property not valid for group");
- break;
+ return (dgettext(TEXT_DOMAIN, "property not valid for group"));
case SA_NOT_SHARED:
- ret = dgettext(TEXT_DOMAIN, "not shared");
- break;
+ return (dgettext(TEXT_DOMAIN, "not shared"));
case SA_NO_SUCH_RESOURCE:
- ret = dgettext(TEXT_DOMAIN, "no such resource");
- break;
+ return (dgettext(TEXT_DOMAIN, "no such resource"));
case SA_RESOURCE_REQUIRED:
- ret = dgettext(TEXT_DOMAIN, "resource name required");
- break;
+ return (dgettext(TEXT_DOMAIN, "resource name required"));
case SA_MULTIPLE_ERROR:
- ret = dgettext(TEXT_DOMAIN, "errors from multiple protocols");
- break;
+ return (dgettext(TEXT_DOMAIN,
+ "errors from multiple protocols"));
case SA_PATH_IS_SUBDIR:
- ret = dgettext(TEXT_DOMAIN, "path is a subpath of share");
- break;
+ return (dgettext(TEXT_DOMAIN, "path is a subpath of share"));
case SA_PATH_IS_PARENTDIR:
- ret = dgettext(TEXT_DOMAIN, "path is parent of a share");
- break;
+ return (dgettext(TEXT_DOMAIN, "path is parent of a share"));
case SA_NO_SECTION:
- ret = dgettext(TEXT_DOMAIN, "protocol requires a section");
- break;
+ return (dgettext(TEXT_DOMAIN, "protocol requires a section"));
case SA_NO_PROPERTIES:
- ret = dgettext(TEXT_DOMAIN, "properties not found");
- break;
+ return (dgettext(TEXT_DOMAIN, "properties not found"));
case SA_NO_SUCH_SECTION:
- ret = dgettext(TEXT_DOMAIN, "section not found");
- break;
+ return (dgettext(TEXT_DOMAIN, "section not found"));
case SA_PASSWORD_ENC:
- ret = dgettext(TEXT_DOMAIN, "passwords must be encrypted");
- break;
+ return (dgettext(TEXT_DOMAIN, "passwords must be encrypted"));
case SA_SHARE_EXISTS:
- ret = dgettext(TEXT_DOMAIN, "path or file is already shared");
- break;
+ return (dgettext(TEXT_DOMAIN,
+ "path or file is already shared"));
default:
(void) snprintf(errstr, sizeof (errstr),
dgettext(TEXT_DOMAIN, "unknown %d"), err);
- ret = errstr;
+ return (errstr);
}
- return (ret);
}
int
-sa_validate_shareopts(const char *options, const char *proto)
-{
- sa_fstype_t *fstype;
-
- fstype = fstypes;
- while (fstype != NULL) {
- if (strcmp(fstype->name, proto) != 0) {
- fstype = fstype->next;
- continue;
- }
-
- return (fstype->ops->validate_shareopts(options));
- }
-
- return (SA_INVALID_PROTOCOL);
-}
-
-static sa_share_impl_t
-alloc_share(const char *zfsname, const char *mountpoint)
+sa_validate_shareopts(const char *options, const char *protocol)
{
- sa_share_impl_t impl_share;
-
- impl_share = calloc(1, sizeof (struct sa_share_impl));
-
- if (impl_share == NULL)
- return (NULL);
-
- if (mountpoint != NULL &&
- ((impl_share->sa_mountpoint = strdup(mountpoint)) == NULL)) {
- free(impl_share);
- return (NULL);
- }
-
- if (zfsname != NULL &&
- ((impl_share->sa_zfsname = strdup(zfsname)) == NULL)) {
- free(impl_share->sa_mountpoint);
- free(impl_share);
- return (NULL);
- }
-
- impl_share->sa_fsinfo = calloc(fstypes_count,
- sizeof (sa_share_fsinfo_t));
- if (impl_share->sa_fsinfo == NULL) {
- free(impl_share->sa_mountpoint);
- free(impl_share->sa_zfsname);
- free(impl_share);
- return (NULL);
- }
-
- return (impl_share);
-}
-
-static void
-free_share(sa_share_impl_t impl_share)
-{
- sa_fstype_t *fstype;
-
- fstype = fstypes;
- while (fstype != NULL) {
- fstype->ops->clear_shareopts(impl_share);
- fstype = fstype->next;
- }
+ sa_fstype_t *fstype = find_proto(protocol);
+ if (!fstype)
+ return (SA_INVALID_PROTOCOL);
- free(impl_share->sa_mountpoint);
- free(impl_share->sa_zfsname);
- free(impl_share->sa_fsinfo);
- free(impl_share);
+ return (fstype->validate_shareopts(options));
}
#define ZFS_EXPORTS_FILE ZFS_EXPORTS_DIR"/zfs.exports"
#define ZFS_EXPORTS_LOCK ZFS_EXPORTS_FILE".lock"
-static sa_fstype_t *nfs_fstype;
-
typedef int (*nfs_shareopt_callback_t)(const char *opt, const char *value,
void *cookie);
nfs_host_callback_t callback, void *cookie)
{
nfs_host_cookie_t udata;
- char *shareopts;
udata.callback = callback;
udata.sharepath = impl_share->sa_mountpoint;
udata.tmpfile = tmpfile;
udata.security = "sys";
- shareopts = FSINFO(impl_share, nfs_fstype)->shareopts;
-
- return (foreach_nfs_shareopt(shareopts, foreach_nfs_host_cb,
- &udata));
+ return (foreach_nfs_shareopt(impl_share->sa_shareopts,
+ foreach_nfs_host_cb, &udata));
}
/*
static int
nfs_enable_share_impl(sa_share_impl_t impl_share, FILE *tmpfile)
{
- char *shareopts, *linux_opts;
+ char *linux_opts;
int error;
- shareopts = FSINFO(impl_share, nfs_fstype)->shareopts;
- error = get_linux_shareopts(shareopts, &linux_opts);
+ error = get_linux_shareopts(impl_share->sa_shareopts, &linux_opts);
if (error != SA_OK)
return (error);
return (SA_OK);
}
-static int
-nfs_update_shareopts(sa_share_impl_t impl_share, const char *shareopts)
-{
- FSINFO(impl_share, nfs_fstype)->shareopts = (char *)shareopts;
- return (SA_OK);
-}
-
-/*
- * Clears a share's NFS options. Used by libshare to
- * clean up shares that are about to be free()'d.
- */
-static void
-nfs_clear_shareopts(sa_share_impl_t impl_share)
-{
- FSINFO(impl_share, nfs_fstype)->shareopts = NULL;
-}
-
static int
nfs_commit_shares(void)
{
return (libzfs_run_process(argv[0], argv, 0));
}
-static const sa_share_ops_t nfs_shareops = {
+sa_fstype_t libshare_nfs_type = {
+ .protocol = "nfs",
+
.enable_share = nfs_enable_share,
.disable_share = nfs_disable_share,
.is_shared = nfs_is_shared,
.validate_shareopts = nfs_validate_shareopts,
- .update_shareopts = nfs_update_shareopts,
- .clear_shareopts = nfs_clear_shareopts,
.commit_shares = nfs_commit_shares,
};
-
-/*
- * Initializes the NFS functionality of libshare.
- */
-void
-libshare_nfs_init(void)
-{
- nfs_fstype = register_fstype("nfs", &nfs_shareops);
-}