/*
* 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
* 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
*/
/*
*/
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <fcntl.h>
#include <strings.h>
#include <syslog.h>
#include <ctype.h>
#include <errno.h>
#include <assert.h>
#include <libnvpair.h>
#include <libintl.h>
#include <zone.h>
#include <note.h>
#include <iconv.h>
#include <langinfo.h>
#include <sharefs/sharetab.h>
#include "libshare.h"
#include "libshare_impl.h"
#define CONV_TO_UTF8 0
static int conv_utf8_common(int, const char *, char **);
/*
* non-shareable file system types. Add new types here.
*/
static char *sa_fstype_table[] = {
"devfs",
"fd",
"proc",
"fifofs",
"namefs",
"sockfs",
"specfs",
"dcfs",
};
/*
* sa_fstype(path)
*
* Given path, return the string representing the path's file system
* type. This is used to discover ZFS shares.
*/
int
{
int err;
if (err < 0) {
switch (errno) {
case ENOENT:
case ENOTDIR:
/*
* Distinquish between path not found and
* other errors since we want to know this in
* order to remove a share after it has been
* removed (deleted) from the system without
* unsharing.
*/
break;
case EACCES:
break;
default:
err = SA_SYSTEM_ERR;
break;
}
} else {
}
/*
* If we have a valid path at this point, return the fstype
* via result (if not NULL)
*/
err = SA_NO_MEMORY;
}
return (err);
}
void
{
}
/*
* sa_fixup_path
*
* Normalize a string by reducing all the repeated slash characters in
* path and removing all trailing slashes.
*
* char *buf = strdup("//d1//d2//d3///d4////");
* sa_fixup_path(buf);
*
* Would result in path containing the following string:
*
*
* If path contains all slashes, then remove all but first /.
*
* This function modifies the contents of path in place and returns
* a pointer to path.
*/
char *
{
char *p, *q;
return (path);
/* reduce all repeating slashes in path */
p = q = path;
while (*p) {
*q++ = *p;
if (*p == '/')
while (*p == '/')
++p;
else
++p;
}
*q = '\0';
/* now remove any trailing slash */
if (p != path && *p == '/')
*p = '\0';
return (path);
}
static int
{
int i;
char *sh_name;
for (i = 0; i < cnt; ++i) {
continue;
return (SA_DUPLICATE_NAME);
}
}
return (SA_OK);
}
/*
* sa_resolve_share_name_conflict
*
* This share has a name conflict with an existing share.
* Adjust the name by adding a number to the end of the name (~<cnt>)
* incrementing until a unique name is found.
*
* If a unique name is found, update the share and write to disk.
*/
int
{
char *sh_name;
char *sh_path;
char *old_name;
int cnt = 0;
int len;
int rc;
return (SA_NO_SHARE_NAME);
return (SA_NO_SHARE_PATH);
return (SA_NO_MEMORY);
if (sa_share_get_proto(share, p))
proto |= p;
}
do {
++cnt;
if (len == 0) {
return (SA_INVALID_SHARE_NAME);
}
len--;
}
} while (rc == SA_DUPLICATE_NAME);
return (rc);
return (SA_NO_MEMORY);
return (rc);
}
if (acl_valid) {
sh_acl);
if (rc == SA_NOT_SUPPORTED)
salog_error(0, "%s:%s:%s failed to set ACL: "
sa_strerror(rc));
}
}
}
if (acl_valid)
return (rc);
}
/*
* sa_name_adjust(path, count)
*
* Add a ~<count> in place of last few characters. The total number of
* characters is dependent on count.
*/
static int
{
if (count > 10)
len--;
if (count > 100)
len--;
if (count > 1000)
len--;
if (len > 0)
else
return (SA_INVALID_SHARE_NAME);
return (SA_OK);
}
/*
* sa_path_to_shr_name(path)
*
* change all illegal characters to something else. For now, all get
* converted to '_' and the leading and trailing '/' are stripped off.
* This is used to construct a valid share name from a path.
*
* The list of invalid characters includes control characters
* and the following:
*
* " / \ [ ] : | < > + ; , ? * =
*
* Control characters are defined as 0x00 - 0x1F inclusive and 0x7f.
* Using specific test here instead of iscntrl macro because the
* behavior of iscntrl() is affected by the current locale and may
* contain additional characters (ie 0x80-0x9f).
*
* Caller must pass a valid path.
*/
void
{
char *p = path;
char *q;
/*
* Strip leading and trailing /'s.
*/
p += strspn(p, "/");
q = strchr(p, '\0');
while ((--q, *q == '/'))
*q = '\0';
}
if (*p == '\0') {
return;
}
/*
* Stride over path components until the remaining
* path is no longer than SA_MAX_SHARE_NAME.
*/
q = p;
++q;
p = q;
}
}
/*
* If the path is still longer than SA_MAX_SHARE_NAME,
* take the trailing SA_MAX_SHARE_NAME characters.
*/
}
/*
* convert any illegal characters to underscore
*/
for (p = path; *p != '\0'; ++p) {
((*p >= 0) && (*p <= 0x1f)))
*p = '_';
}
}
/*
* sa_share_from_path
*
* This routine will create a default share name from the given path.
* It will either return a new share with name and path set or
* an existing share with the default share name for the specified path.
*/
int
{
int rc;
int count;
char *sh_name;
char *path;
return (SA_NO_MEMORY);
count = 0;
do {
/*
* Check for the existance of a share with the new name.
* If a share exists, is it for this path?
* If so return existing share else
* try to fixup the name and search again.
* If no share is found, create a new share and set the
* name and path properties.
*/
/*
* this share is for a different path
* try to fix up name and try again
*/
count++;
return (SA_INVALID_SHARE_NAME);
}
}
} else {
/*
* share does not exist, create new one
*/
return (SA_NO_MEMORY);
}
}
return (SA_OK);
}
/*
* sa_prop_cmp_list
*
* This function tries to find the null-terminated string key in
* the string vector plist. The string vector must be terminated
* with a NULL pointer.
*
* If a match is found, the vector index is returned. If no match
* is found, -1 is returned.
*
*/
int
{
int i;
return (-1);
return (i);
}
return (-1);
}
/*
* sa_prop_case_cmp_list
*
* similar to the above except comparisons are case-insensitive
*/
int
{
int i;
return (-1);
return (i);
}
return (-1);
}
void
sa_trace(const char *s)
{
}
void
{
}
char *
{
switch (err) {
case SA_OK:
case SA_INTERNAL_ERR:
case SA_SYSTEM_ERR:
case SA_NO_MEMORY:
case SA_SYNTAX_ERR:
case SA_NOT_IMPLEMENTED:
case SA_NOT_SUPPORTED:
" or protocol not installed"));
case SA_BUSY:
case SA_CONFIG_ERR:
case SA_SHARE_NOT_FOUND:
case SA_DUPLICATE_NAME:
case SA_DUPLICATE_PATH:
"same path exist"));
case SA_DUPLICATE_PROP:
return (dgettext(TEXT_DOMAIN,
"property specified more than once"));
case SA_DUPLICATE_PROTO:
return (dgettext(TEXT_DOMAIN,
"protocol specified more than once"));
case SA_NO_SHARE_NAME:
case SA_NO_SHARE_PATH:
case SA_NO_SHARE_DESC:
case SA_NO_SHARE_PROTO:
case SA_NO_SECTION:
case SA_NO_SUCH_PROTO:
return (dgettext(TEXT_DOMAIN,
"share not configured for protocol"));
case SA_NO_SUCH_PROP:
case SA_NO_SUCH_SECURITY:
case SA_NO_SUCH_SECTION:
case SA_NO_PERMISSION:
case SA_INVALID_SHARE:
case SA_INVALID_SHARE_NAME:
case SA_INVALID_SHARE_PATH:
case SA_INVALID_SHARE_MNTPNT:
case SA_INVALID_PROP:
case SA_INVALID_SMB_PROP:
case SA_INVALID_NFS_PROP:
case SA_INVALID_PROP_VAL:
case SA_INVALID_PROTO:
case SA_INVALID_SECURITY:
case SA_INVALID_UNAME:
case SA_INVALID_UID:
case SA_INVALID_FNAME:
case SA_PARTIAL_PUBLISH:
case SA_PARTIAL_UNPUBLISH:
case SA_INVALID_READ_HDL:
case SA_INVALID_PLUGIN:
case SA_INVALID_PLUGIN_TYPE:
case SA_INVALID_PLUGIN_OPS:
case SA_INVALID_PLUGIN_NAME:
case SA_NO_PLUGIN_DIR:
case SA_NO_SHARE_DIR:
case SA_PATH_NOT_FOUND:
case SA_MNTPNT_NOT_FOUND:
case SA_NOT_SHARED_PROTO:
case SA_ANCESTOR_SHARED:
case SA_DESCENDANT_SHARED:
case SA_XDR_ENCODE_ERR:
case SA_XDR_DECODE_ERR:
case SA_PASSWORD_ENC:
case SA_SCF_ERROR:
"error"));
case SA_DOOR_ERROR:
case SA_STALE_HANDLE:
"value"));
case SA_SHARE_OTHERZONE:
"shares managed from non-global zone." :
"shares managed from global zone.")));
case SA_INVALID_ZONE:
"zone"));
case SA_PROTO_NOT_INSTALLED:
case SA_INVALID_FSTYPE:
case SA_READ_ONLY:
case SA_LOCALE_NOT_SUPPORTED:
case SA_ACL_SET_ERROR:
case SA_SHARE_CONFLICT:
default:
}
}
static void
{
if (err == 0)
else
}
void
{
}
void
{
}
void
{
}
void
{
}
{
int i;
for (i = 0; sa_fstype_table[i] != NULL; i++)
return (B_FALSE);
return (B_TRUE);
}
static int
{
}
static int
{
char *opts;
char *namep;
char *valp;
char *nextp;
return (GLOBAL_ZONEID);
++valp;
*nextp = '\0';
}
}
return (zone_ctx);
}
/*
* sa_mntpnt_in_current_zone
*
* This routine determines if the mntpnt is shareable in
* the current zone. Each mnttab entry has an mountpoint
* option (sharezone) that specifies the zoneid it is mounted in.
*
* Currently there are a couple of exceptions. If the mount option
* does not exist, the global zone is assumed. Also any dataset with
* the 'zoned' property set to 'on' cannot be shared in GZ.
*/
{
return (B_FALSE);
if (cur_zone == GLOBAL_ZONEID) {
if (shr_zone != GLOBAL_ZONEID)
return (B_FALSE);
return (B_FALSE);
return (B_TRUE);
} else {
return (B_FALSE);
return (B_TRUE);
}
}
/*
* Equivalent to the strchr(3C) function except it honors the back
* slash escape convention.
*/
char *
{
char *curp;
return (NULL);
if (*curp == c)
break;
else if (*curp == '\\')
curp++;
/* make sure we don't go off the end of the string */
if (*curp == '\0')
break;
}
if (*curp == '\0')
return (curp);
}
/*
* Strip back slash escape from string if there are any. Always
* returns new string unless memory failure.
*/
char *
{
char *curp;
char *newstring;
char *newcp;
return (NULL);
return (NULL);
while (*curp != '\0') {
if (*curp == '\\') {
curp++;
/* make sure we don't go off the end of the string */
if (*curp == '\0')
break;
}
}
return (newstring);
}
/*
* Convert the input string to utf8 from the current locale.
* If the current locale codeset cannot be determined, use the
* "C" locale.
* On success, the converted string is stored in the newly
* allocated output buffer and the pointer is returned in 'outbufp'
* It is the responsibilty of the caller to free this memory.
*/
int
{
}
/*
* Convert the input string from utf8 to current locale.
* If the current locale codeset cannot be determined, use the
* "C" locale.
* On success, the converted string is stored in the newly
* allocated output buffer and the pointer is returned in 'outbufp'
* It is the responsibilty of the caller to free this memory.
*/
int
{
}
static int
{
char *curlocale;
char *outptr;
return (SA_INTERNAL_ERR);
curlocale = "646";
if (direction == CONV_TO_UTF8)
else
switch (errno) {
case EINVAL:
return (SA_LOCALE_NOT_SUPPORTED);
case ENOMEM:
return (SA_NO_MEMORY);
default:
return (SA_SYSTEM_ERR);
}
}
/* Assume worst case of characters expanding to 4 bytes. */
(void) iconv_close(cd);
return (SA_NO_MEMORY);
}
(void) iconv_close(cd);
return (SA_SYSTEM_ERR);
}
return (SA_OK);
}
{
char *status;
return (SA_INVALID_PROTO);
return (SA_INVALID_PROTO);
return (SA_PROTO_NOT_INSTALLED);
return (SA_OK);
}
sa_valid_protocols(void)
{
char *status;
status = sa_proto_get_status(p);
proto |= p;
}
}
return (proto);
}