8111eb4abc
calloc(3) takes `nelem` (or `nmemb` in glibc) first, and then size of elements. No difference expected for having these in reverse order, however should follow the standard. http://pubs.opengroup.org/onlinepubs/009695399/functions/calloc.html Reviewed-by: Tony Hutter <hutter2@llnl.gov> Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Signed-off-by: Tomohiro Kusumi <kusumi.tomohiro@osnexus.com> Closes #7405
778 lines
17 KiB
C
778 lines
17 KiB
C
/*
|
|
* CDDL HEADER START
|
|
*
|
|
* The contents of this file are subject to the terms of the
|
|
* Common Development and Distribution License (the "License").
|
|
* You may not use this file except in compliance with the License.
|
|
*
|
|
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
|
* or http://www.opensolaris.org/os/licensing.
|
|
* See the License for the specific language governing permissions
|
|
* and limitations under the License.
|
|
*
|
|
* When distributing Covered Code, include this CDDL HEADER in each
|
|
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
|
* If applicable, add the following below this CDDL HEADER, with the
|
|
* fields enclosed by brackets "[]" replaced with your own identifying
|
|
* information: Portions Copyright [yyyy] [name of copyright owner]
|
|
*
|
|
* CDDL HEADER END
|
|
*/
|
|
|
|
/*
|
|
* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
|
|
* Copyright (c) 2011 Gunnar Beutner
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
#include <strings.h>
|
|
#include <libintl.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
#include <libzfs.h>
|
|
#include <libshare.h>
|
|
#include "libshare_impl.h"
|
|
#include "nfs.h"
|
|
#include "smb.h"
|
|
|
|
static sa_share_impl_t find_share(sa_handle_impl_t handle,
|
|
const char *sharepath);
|
|
static sa_share_impl_t alloc_share(const char *sharepath);
|
|
static void free_share(sa_share_impl_t share);
|
|
|
|
static void parse_sharetab(sa_handle_impl_t impl_handle);
|
|
static int process_share(sa_handle_impl_t impl_handle,
|
|
sa_share_impl_t impl_share, char *pathname, char *resource,
|
|
char *fstype, char *options, char *description,
|
|
char *dataset, boolean_t from_sharetab);
|
|
static void update_sharetab(sa_handle_impl_t impl_handle);
|
|
|
|
static int update_zfs_share(sa_share_impl_t impl_handle, const char *proto);
|
|
static int update_zfs_shares(sa_handle_impl_t impl_handle, const char *proto);
|
|
|
|
static int fstypes_count;
|
|
static sa_fstype_t *fstypes;
|
|
|
|
sa_fstype_t *
|
|
register_fstype(const char *name, const sa_share_ops_t *ops)
|
|
{
|
|
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);
|
|
}
|
|
|
|
sa_handle_t
|
|
sa_init(int init_service)
|
|
{
|
|
sa_handle_impl_t impl_handle;
|
|
|
|
impl_handle = calloc(1, sizeof (struct sa_handle_impl));
|
|
|
|
if (impl_handle == NULL)
|
|
return (NULL);
|
|
|
|
impl_handle->zfs_libhandle = libzfs_init();
|
|
|
|
if (impl_handle->zfs_libhandle != NULL) {
|
|
libzfs_print_on_error(impl_handle->zfs_libhandle, B_TRUE);
|
|
}
|
|
|
|
parse_sharetab(impl_handle);
|
|
update_zfs_shares(impl_handle, NULL);
|
|
|
|
return ((sa_handle_t)impl_handle);
|
|
}
|
|
|
|
__attribute__((constructor)) static void
|
|
libshare_init(void)
|
|
{
|
|
libshare_nfs_init();
|
|
libshare_smb_init();
|
|
}
|
|
|
|
static void
|
|
parse_sharetab(sa_handle_impl_t impl_handle)
|
|
{
|
|
FILE *fp;
|
|
char line[512];
|
|
char *eol, *pathname, *resource, *fstype, *options, *description;
|
|
|
|
fp = fopen(ZFS_SHARETAB, "r");
|
|
|
|
if (fp == NULL)
|
|
return;
|
|
|
|
while (fgets(line, sizeof (line), fp) != NULL) {
|
|
eol = line + strlen(line) - 1;
|
|
|
|
while (eol >= line) {
|
|
if (*eol != '\r' && *eol != '\n')
|
|
break;
|
|
|
|
*eol = '\0';
|
|
eol--;
|
|
}
|
|
|
|
pathname = line;
|
|
|
|
if ((resource = strchr(pathname, '\t')) == NULL)
|
|
continue;
|
|
|
|
*resource = '\0';
|
|
resource++;
|
|
|
|
if ((fstype = strchr(resource, '\t')) == NULL)
|
|
continue;
|
|
|
|
*fstype = '\0';
|
|
fstype++;
|
|
|
|
if ((options = strchr(fstype, '\t')) == NULL)
|
|
continue;
|
|
|
|
*options = '\0';
|
|
options++;
|
|
|
|
if ((description = strchr(fstype, '\t')) != NULL) {
|
|
*description = '\0';
|
|
description++;
|
|
}
|
|
|
|
if (strcmp(resource, "-") == 0)
|
|
resource = NULL;
|
|
|
|
(void) process_share(impl_handle, NULL, pathname, resource,
|
|
fstype, options, description, NULL, B_TRUE);
|
|
}
|
|
|
|
fclose(fp);
|
|
}
|
|
|
|
static void
|
|
update_sharetab(sa_handle_impl_t impl_handle)
|
|
{
|
|
sa_share_impl_t impl_share;
|
|
int temp_fd;
|
|
FILE *temp_fp;
|
|
char tempfile[] = ZFS_SHARETAB".XXXXXX";
|
|
sa_fstype_t *fstype;
|
|
const char *resource;
|
|
|
|
if (mkdir("/etc/dfs", 0755) < 0 && errno != EEXIST) {
|
|
return;
|
|
}
|
|
|
|
temp_fd = mkstemp(tempfile);
|
|
|
|
if (temp_fd < 0)
|
|
return;
|
|
|
|
temp_fp = fdopen(temp_fd, "w");
|
|
|
|
if (temp_fp == NULL)
|
|
return;
|
|
|
|
impl_share = impl_handle->shares;
|
|
while (impl_share != NULL) {
|
|
fstype = fstypes;
|
|
while (fstype != NULL) {
|
|
if (FSINFO(impl_share, fstype)->active &&
|
|
FSINFO(impl_share, fstype)->shareopts != NULL) {
|
|
resource = FSINFO(impl_share, fstype)->resource;
|
|
|
|
if (resource == NULL)
|
|
resource = "-";
|
|
|
|
fprintf(temp_fp, "%s\t%s\t%s\t%s\n",
|
|
impl_share->sharepath, resource,
|
|
fstype->name,
|
|
FSINFO(impl_share, fstype)->shareopts);
|
|
}
|
|
|
|
fstype = fstype->next;
|
|
}
|
|
|
|
impl_share = impl_share->next;
|
|
}
|
|
|
|
fflush(temp_fp);
|
|
fsync(temp_fd);
|
|
fclose(temp_fp);
|
|
|
|
(void) rename(tempfile, ZFS_SHARETAB);
|
|
}
|
|
|
|
typedef struct update_cookie_s {
|
|
sa_handle_impl_t handle;
|
|
const char *proto;
|
|
} update_cookie_t;
|
|
|
|
static int
|
|
update_zfs_shares_cb(zfs_handle_t *zhp, void *pcookie)
|
|
{
|
|
update_cookie_t *udata = (update_cookie_t *)pcookie;
|
|
char mountpoint[ZFS_MAXPROPLEN];
|
|
char shareopts[ZFS_MAXPROPLEN];
|
|
char *dataset;
|
|
zfs_type_t type = zfs_get_type(zhp);
|
|
|
|
if (type == ZFS_TYPE_FILESYSTEM &&
|
|
zfs_iter_filesystems(zhp, update_zfs_shares_cb, pcookie) != 0) {
|
|
zfs_close(zhp);
|
|
return (1);
|
|
}
|
|
|
|
if (type != ZFS_TYPE_FILESYSTEM) {
|
|
zfs_close(zhp);
|
|
return (0);
|
|
}
|
|
|
|
if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
|
|
sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) {
|
|
zfs_close(zhp);
|
|
return (0);
|
|
}
|
|
|
|
dataset = (char *)zfs_get_name(zhp);
|
|
|
|
if (dataset == NULL) {
|
|
zfs_close(zhp);
|
|
return (0);
|
|
}
|
|
|
|
if (!zfs_is_mounted(zhp, NULL)) {
|
|
zfs_close(zhp);
|
|
return (0);
|
|
}
|
|
|
|
if ((udata->proto == NULL || strcmp(udata->proto, "nfs") == 0) &&
|
|
zfs_prop_get(zhp, ZFS_PROP_SHARENFS, shareopts,
|
|
sizeof (shareopts), NULL, NULL, 0, B_FALSE) == 0 &&
|
|
strcmp(shareopts, "off") != 0) {
|
|
(void) process_share(udata->handle, NULL, mountpoint, NULL,
|
|
"nfs", shareopts, NULL, dataset, B_FALSE);
|
|
}
|
|
|
|
if ((udata->proto == NULL || strcmp(udata->proto, "smb") == 0) &&
|
|
zfs_prop_get(zhp, ZFS_PROP_SHARESMB, shareopts,
|
|
sizeof (shareopts), NULL, NULL, 0, B_FALSE) == 0 &&
|
|
strcmp(shareopts, "off") != 0) {
|
|
(void) process_share(udata->handle, NULL, mountpoint, NULL,
|
|
"smb", shareopts, NULL, dataset, B_FALSE);
|
|
}
|
|
|
|
zfs_close(zhp);
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
update_zfs_share(sa_share_impl_t impl_share, const char *proto)
|
|
{
|
|
sa_handle_impl_t impl_handle = impl_share->handle;
|
|
zfs_handle_t *zhp;
|
|
update_cookie_t udata;
|
|
|
|
if (impl_handle->zfs_libhandle == NULL)
|
|
return (SA_SYSTEM_ERR);
|
|
|
|
assert(impl_share->dataset != NULL);
|
|
|
|
zhp = zfs_open(impl_share->handle->zfs_libhandle, impl_share->dataset,
|
|
ZFS_TYPE_FILESYSTEM);
|
|
|
|
if (zhp == NULL)
|
|
return (SA_SYSTEM_ERR);
|
|
|
|
udata.handle = impl_handle;
|
|
udata.proto = proto;
|
|
(void) update_zfs_shares_cb(zhp, &udata);
|
|
|
|
return (SA_OK);
|
|
}
|
|
|
|
static int
|
|
update_zfs_shares(sa_handle_impl_t impl_handle, const char *proto)
|
|
{
|
|
update_cookie_t udata;
|
|
|
|
if (impl_handle->zfs_libhandle == NULL)
|
|
return (SA_SYSTEM_ERR);
|
|
|
|
udata.handle = impl_handle;
|
|
udata.proto = proto;
|
|
(void) zfs_iter_root(impl_handle->zfs_libhandle, update_zfs_shares_cb,
|
|
&udata);
|
|
|
|
return (SA_OK);
|
|
}
|
|
|
|
static int
|
|
process_share(sa_handle_impl_t impl_handle, sa_share_impl_t impl_share,
|
|
char *pathname, char *resource, char *proto,
|
|
char *options, char *description, char *dataset,
|
|
boolean_t from_sharetab)
|
|
{
|
|
struct stat statbuf;
|
|
int rc;
|
|
char *resource_dup = NULL, *dataset_dup = NULL;
|
|
boolean_t new_share;
|
|
sa_fstype_t *fstype;
|
|
|
|
new_share = B_FALSE;
|
|
|
|
if (impl_share == NULL)
|
|
impl_share = find_share(impl_handle, pathname);
|
|
|
|
if (impl_share == NULL) {
|
|
if (lstat(pathname, &statbuf) != 0 ||
|
|
!S_ISDIR(statbuf.st_mode))
|
|
return (SA_BAD_PATH);
|
|
|
|
impl_share = alloc_share(pathname);
|
|
|
|
if (impl_share == NULL) {
|
|
rc = SA_NO_MEMORY;
|
|
goto err;
|
|
}
|
|
|
|
new_share = B_TRUE;
|
|
}
|
|
|
|
if (dataset != NULL) {
|
|
dataset_dup = strdup(dataset);
|
|
|
|
if (dataset_dup == NULL) {
|
|
rc = SA_NO_MEMORY;
|
|
goto err;
|
|
}
|
|
}
|
|
|
|
free(impl_share->dataset);
|
|
impl_share->dataset = dataset_dup;
|
|
|
|
rc = SA_INVALID_PROTOCOL;
|
|
|
|
fstype = fstypes;
|
|
while (fstype != NULL) {
|
|
if (strcmp(fstype->name, proto) == 0) {
|
|
if (resource != NULL) {
|
|
resource_dup = strdup(resource);
|
|
|
|
if (resource_dup == NULL) {
|
|
rc = SA_NO_MEMORY;
|
|
goto err;
|
|
}
|
|
}
|
|
|
|
free(FSINFO(impl_share, fstype)->resource);
|
|
FSINFO(impl_share, fstype)->resource = resource_dup;
|
|
|
|
rc = fstype->ops->update_shareopts(impl_share,
|
|
resource, options);
|
|
|
|
if (rc == SA_OK && from_sharetab)
|
|
FSINFO(impl_share, fstype)->active = B_TRUE;
|
|
|
|
break;
|
|
}
|
|
|
|
fstype = fstype->next;
|
|
}
|
|
|
|
if (rc != SA_OK)
|
|
goto err;
|
|
|
|
if (new_share) {
|
|
impl_share->handle = impl_handle;
|
|
|
|
impl_share->next = impl_handle->shares;
|
|
impl_handle->shares = impl_share;
|
|
|
|
}
|
|
|
|
err:
|
|
if (rc != SA_OK) {
|
|
if (new_share)
|
|
free_share(impl_share);
|
|
}
|
|
|
|
return (rc);
|
|
}
|
|
|
|
void
|
|
sa_fini(sa_handle_t handle)
|
|
{
|
|
sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle;
|
|
sa_share_impl_t impl_share, next;
|
|
sa_share_impl_t *pcurr;
|
|
|
|
if (impl_handle == NULL)
|
|
return;
|
|
|
|
/*
|
|
* clean up shares which don't have a non-NULL dataset property,
|
|
* which means they're in sharetab but we couldn't find their
|
|
* ZFS dataset.
|
|
*/
|
|
pcurr = &(impl_handle->shares);
|
|
impl_share = *pcurr;
|
|
while (impl_share != NULL) {
|
|
next = impl_share->next;
|
|
|
|
if (impl_share->dataset == NULL) {
|
|
/* remove item from the linked list */
|
|
*pcurr = next;
|
|
|
|
sa_disable_share(impl_share, NULL);
|
|
|
|
free_share(impl_share);
|
|
} else {
|
|
pcurr = &(impl_share->next);
|
|
}
|
|
|
|
impl_share = next;
|
|
}
|
|
|
|
update_sharetab(impl_handle);
|
|
|
|
if (impl_handle->zfs_libhandle != NULL)
|
|
libzfs_fini(impl_handle->zfs_libhandle);
|
|
|
|
impl_share = impl_handle->shares;
|
|
while (impl_share != NULL) {
|
|
next = impl_share->next;
|
|
free_share(impl_share);
|
|
impl_share = next;
|
|
}
|
|
|
|
free(impl_handle);
|
|
}
|
|
|
|
static sa_share_impl_t
|
|
find_share(sa_handle_impl_t impl_handle, const char *sharepath)
|
|
{
|
|
sa_share_impl_t impl_share;
|
|
|
|
impl_share = impl_handle->shares;
|
|
while (impl_share != NULL) {
|
|
if (strcmp(impl_share->sharepath, sharepath) == 0) {
|
|
break;
|
|
}
|
|
|
|
impl_share = impl_share->next;
|
|
}
|
|
|
|
return (impl_share);
|
|
}
|
|
|
|
sa_share_t
|
|
sa_find_share(sa_handle_t handle, char *sharepath)
|
|
{
|
|
return ((sa_share_t)find_share((sa_handle_impl_t)handle, sharepath));
|
|
}
|
|
|
|
int
|
|
sa_enable_share(sa_share_t share, char *protocol)
|
|
{
|
|
sa_share_impl_t impl_share = (sa_share_impl_t)share;
|
|
int rc, ret = SA_OK;
|
|
boolean_t found_protocol = B_FALSE;
|
|
sa_fstype_t *fstype;
|
|
|
|
fstype = fstypes;
|
|
while (fstype != NULL) {
|
|
if (protocol == NULL || strcmp(fstype->name, protocol) == 0) {
|
|
update_zfs_share(impl_share, fstype->name);
|
|
|
|
rc = fstype->ops->enable_share(impl_share);
|
|
|
|
if (rc != SA_OK)
|
|
ret = rc;
|
|
else
|
|
FSINFO(impl_share, fstype)->active = B_TRUE;
|
|
|
|
found_protocol = B_TRUE;
|
|
}
|
|
|
|
fstype = fstype->next;
|
|
}
|
|
|
|
update_sharetab(impl_share->handle);
|
|
|
|
return (found_protocol ? ret : SA_INVALID_PROTOCOL);
|
|
}
|
|
|
|
int
|
|
sa_disable_share(sa_share_t share, char *protocol)
|
|
{
|
|
sa_share_impl_t impl_share = (sa_share_impl_t)share;
|
|
int rc, ret = SA_OK;
|
|
boolean_t found_protocol = B_FALSE;
|
|
sa_fstype_t *fstype;
|
|
|
|
fstype = fstypes;
|
|
while (fstype != NULL) {
|
|
if (protocol == NULL || strcmp(fstype->name, protocol) == 0) {
|
|
rc = fstype->ops->disable_share(impl_share);
|
|
|
|
if (rc == SA_OK) {
|
|
fstype->ops->clear_shareopts(impl_share);
|
|
|
|
FSINFO(impl_share, fstype)->active = B_FALSE;
|
|
} else
|
|
ret = rc;
|
|
|
|
found_protocol = B_TRUE;
|
|
}
|
|
|
|
fstype = fstype->next;
|
|
}
|
|
|
|
update_sharetab(impl_share->handle);
|
|
|
|
return (found_protocol ? ret : SA_INVALID_PROTOCOL);
|
|
}
|
|
|
|
/*
|
|
* sa_errorstr(err)
|
|
*
|
|
* convert an error value to an error string
|
|
*/
|
|
char *
|
|
sa_errorstr(int err)
|
|
{
|
|
static char errstr[32];
|
|
char *ret = NULL;
|
|
|
|
switch (err) {
|
|
case SA_OK:
|
|
ret = dgettext(TEXT_DOMAIN, "ok");
|
|
break;
|
|
case SA_NO_SUCH_PATH:
|
|
ret = dgettext(TEXT_DOMAIN, "path doesn't exist");
|
|
break;
|
|
case SA_NO_MEMORY:
|
|
ret = dgettext(TEXT_DOMAIN, "no memory");
|
|
break;
|
|
case SA_DUPLICATE_NAME:
|
|
ret = dgettext(TEXT_DOMAIN, "name in use");
|
|
break;
|
|
case SA_BAD_PATH:
|
|
ret = dgettext(TEXT_DOMAIN, "bad path");
|
|
break;
|
|
case SA_NO_SUCH_GROUP:
|
|
ret = dgettext(TEXT_DOMAIN, "no such group");
|
|
break;
|
|
case SA_CONFIG_ERR:
|
|
ret = dgettext(TEXT_DOMAIN, "configuration error");
|
|
break;
|
|
case SA_SYSTEM_ERR:
|
|
ret = dgettext(TEXT_DOMAIN, "system error");
|
|
break;
|
|
case SA_SYNTAX_ERR:
|
|
ret = dgettext(TEXT_DOMAIN, "syntax error");
|
|
break;
|
|
case SA_NO_PERMISSION:
|
|
ret = dgettext(TEXT_DOMAIN, "no permission");
|
|
break;
|
|
case SA_BUSY:
|
|
ret = dgettext(TEXT_DOMAIN, "busy");
|
|
break;
|
|
case SA_NO_SUCH_PROP:
|
|
ret = dgettext(TEXT_DOMAIN, "no such property");
|
|
break;
|
|
case SA_INVALID_NAME:
|
|
ret = dgettext(TEXT_DOMAIN, "invalid name");
|
|
break;
|
|
case SA_INVALID_PROTOCOL:
|
|
ret = dgettext(TEXT_DOMAIN, "invalid protocol");
|
|
break;
|
|
case SA_NOT_ALLOWED:
|
|
ret = dgettext(TEXT_DOMAIN, "operation not allowed");
|
|
break;
|
|
case SA_BAD_VALUE:
|
|
ret = dgettext(TEXT_DOMAIN, "bad property value");
|
|
break;
|
|
case SA_INVALID_SECURITY:
|
|
ret = dgettext(TEXT_DOMAIN, "invalid security type");
|
|
break;
|
|
case SA_NO_SUCH_SECURITY:
|
|
ret = dgettext(TEXT_DOMAIN, "security type not found");
|
|
break;
|
|
case SA_VALUE_CONFLICT:
|
|
ret = dgettext(TEXT_DOMAIN, "property value conflict");
|
|
break;
|
|
case SA_NOT_IMPLEMENTED:
|
|
ret = dgettext(TEXT_DOMAIN, "not implemented");
|
|
break;
|
|
case SA_INVALID_PATH:
|
|
ret = dgettext(TEXT_DOMAIN, "invalid path");
|
|
break;
|
|
case SA_NOT_SUPPORTED:
|
|
ret = dgettext(TEXT_DOMAIN, "operation not supported");
|
|
break;
|
|
case SA_PROP_SHARE_ONLY:
|
|
ret = dgettext(TEXT_DOMAIN, "property not valid for group");
|
|
break;
|
|
case SA_NOT_SHARED:
|
|
ret = dgettext(TEXT_DOMAIN, "not shared");
|
|
break;
|
|
case SA_NO_SUCH_RESOURCE:
|
|
ret = dgettext(TEXT_DOMAIN, "no such resource");
|
|
break;
|
|
case SA_RESOURCE_REQUIRED:
|
|
ret = dgettext(TEXT_DOMAIN, "resource name required");
|
|
break;
|
|
case SA_MULTIPLE_ERROR:
|
|
ret = dgettext(TEXT_DOMAIN, "errors from multiple protocols");
|
|
break;
|
|
case SA_PATH_IS_SUBDIR:
|
|
ret = dgettext(TEXT_DOMAIN, "path is a subpath of share");
|
|
break;
|
|
case SA_PATH_IS_PARENTDIR:
|
|
ret = dgettext(TEXT_DOMAIN, "path is parent of a share");
|
|
break;
|
|
case SA_NO_SECTION:
|
|
ret = dgettext(TEXT_DOMAIN, "protocol requires a section");
|
|
break;
|
|
case SA_NO_PROPERTIES:
|
|
ret = dgettext(TEXT_DOMAIN, "properties not found");
|
|
break;
|
|
case SA_NO_SUCH_SECTION:
|
|
ret = dgettext(TEXT_DOMAIN, "section not found");
|
|
break;
|
|
case SA_PASSWORD_ENC:
|
|
ret = dgettext(TEXT_DOMAIN, "passwords must be encrypted");
|
|
break;
|
|
case SA_SHARE_EXISTS:
|
|
ret = dgettext(TEXT_DOMAIN, "path or file is already shared");
|
|
break;
|
|
default:
|
|
(void) snprintf(errstr, sizeof (errstr),
|
|
dgettext(TEXT_DOMAIN, "unknown %d"), err);
|
|
ret = errstr;
|
|
}
|
|
return (ret);
|
|
}
|
|
|
|
int
|
|
sa_parse_legacy_options(sa_group_t group, char *options, 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);
|
|
}
|
|
|
|
boolean_t
|
|
sa_needs_refresh(sa_handle_t handle)
|
|
{
|
|
return (B_TRUE);
|
|
}
|
|
|
|
libzfs_handle_t *
|
|
sa_get_zfs_handle(sa_handle_t handle)
|
|
{
|
|
sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle;
|
|
|
|
if (impl_handle == NULL)
|
|
return (NULL);
|
|
|
|
return (impl_handle->zfs_libhandle);
|
|
}
|
|
|
|
static sa_share_impl_t
|
|
alloc_share(const char *sharepath)
|
|
{
|
|
sa_share_impl_t impl_share;
|
|
|
|
impl_share = calloc(1, sizeof (struct sa_share_impl));
|
|
|
|
if (impl_share == NULL)
|
|
return (NULL);
|
|
|
|
impl_share->sharepath = strdup(sharepath);
|
|
|
|
if (impl_share->sharepath == NULL) {
|
|
free(impl_share);
|
|
return (NULL);
|
|
}
|
|
|
|
impl_share->fsinfo = calloc(fstypes_count, sizeof (sa_share_fsinfo_t));
|
|
|
|
if (impl_share->fsinfo == NULL) {
|
|
free(impl_share->sharepath);
|
|
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);
|
|
|
|
free(FSINFO(impl_share, fstype)->resource);
|
|
|
|
fstype = fstype->next;
|
|
}
|
|
|
|
free(impl_share->sharepath);
|
|
free(impl_share->dataset);
|
|
free(impl_share->fsinfo);
|
|
free(impl_share);
|
|
}
|
|
|
|
int
|
|
sa_zfs_process_share(sa_handle_t handle, sa_group_t group, sa_share_t share,
|
|
char *mountpoint, char *proto, zprop_source_t source, char *shareopts,
|
|
char *sourcestr, char *dataset)
|
|
{
|
|
sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle;
|
|
sa_share_impl_t impl_share = (sa_share_impl_t)share;
|
|
|
|
return (process_share(impl_handle, impl_share, mountpoint, NULL,
|
|
proto, shareopts, NULL, dataset, B_FALSE));
|
|
}
|
|
|
|
void
|
|
sa_update_sharetab_ts(sa_handle_t handle)
|
|
{
|
|
sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle;
|
|
|
|
update_sharetab(impl_handle);
|
|
}
|