eefaa55f64
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Reviewed-by: Matthew Ahrens <mahrens@delphix.com> Reviewed-by: John Kennedy <john.kennedy@delphix.com> Signed-off-by: Ahelenia Ziemiańska <nabijaczleweli@nabijaczleweli.xyz> Closes #12048
366 lines
8.3 KiB
C
366 lines
8.3 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
|
|
* Copyright (c) 2018, 2020 by Delphix. All rights reserved.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
#include <strings.h>
|
|
#include <libintl.h>
|
|
#include <sys/file.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 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)
|
|
{
|
|
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);
|
|
}
|
|
|
|
__attribute__((constructor)) static void
|
|
libshare_init(void)
|
|
{
|
|
libshare_nfs_init();
|
|
libshare_smb_init();
|
|
}
|
|
|
|
int
|
|
sa_enable_share(const char *zfsname, const char *mountpoint,
|
|
const char *shareopts, 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;
|
|
|
|
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);
|
|
}
|
|
|
|
int
|
|
sa_disable_share(const char *mountpoint, 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) {
|
|
|
|
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);
|
|
}
|
|
|
|
boolean_t
|
|
sa_is_shared(const char *mountpoint, 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)
|
|
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);
|
|
}
|
|
|
|
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_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_validate_shareopts(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);
|
|
}
|
|
|
|
static sa_share_impl_t
|
|
alloc_share(const char *zfsname, const char *mountpoint)
|
|
{
|
|
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;
|
|
}
|
|
|
|
free(impl_share->sa_mountpoint);
|
|
free(impl_share->sa_zfsname);
|
|
free(impl_share->sa_fsinfo);
|
|
free(impl_share);
|
|
}
|