/*
* 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) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
*/
#include <strings.h>
#include <libintl.h>
#include <libnvpair.h>
#include <sys/stat.h>
#include <errno.h>
#include <synch.h>
#include <note.h>
#include <sys/param.h>
#include <sys/sysmacros.h>
#include <sys/mnttab.h>
#include <libshare.h>
#include <libshare_impl.h>
#include <sharefs/share.h>
#include <sharefs/sharetab.h>
static int sa_legacy_init(void);
static void sa_legacy_fini(void);
static void *sa_legacy_open(libshare_handle_t *);
static void sa_legacy_close(void *);
static int sa_legacy_share_write(libshare_handle_t *, nvlist_t *, boolean_t);
static int sa_legacy_share_read(libshare_handle_t *, const char *,
const char *, nvlist_t **);
static int sa_legacy_share_read_init(libshare_handle_t *, sa_read_hdl_t *);
static int sa_legacy_share_read_next(libshare_handle_t *, sa_read_hdl_t *,
nvlist_t **);
static int sa_legacy_share_read_fini(libshare_handle_t *, sa_read_hdl_t *);
static int sa_legacy_share_remove(libshare_handle_t *, const char *,
const char *, boolean_t);
static int sa_legacy_share_get_acl(libshare_handle_t *, const char *,
const char *, acl_t **);
static int sa_legacy_share_set_acl(libshare_handle_t *, const char *,
const char *, acl_t *);
static int sa_legacy_get_mntpnt_for_path(libshare_handle_t *, const char *,
char *, size_t, char *, size_t, char *, size_t);
static int sa_legacy_sharing_enabled(libshare_handle_t *, const char *,
const char *, sa_proto_t *);
static int sa_legacy_sharing_get_prop(libshare_handle_t *, const char *,
const char *, sa_proto_t, char **);
static int sa_legacy_sharing_set_prop(libshare_handle_t *, const char *,
const char *, sa_proto_t, const char *);
static int sa_legacy_is_legacy(libshare_handle_t *, const char *, boolean_t *);
static int sa_legacy_is_zoned(libshare_handle_t *, const char *, boolean_t *);
struct legacy_mount; /* forward declaration */
typedef struct legacy_mount {
struct legacy_mount *lm_next;
char *lm_mntpnt;
char *lm_mntopts;
} legacy_mount_t;
typedef struct legacy_handle {
scf_handle_t *legacy_smf_hdl;
scf_instance_t *legacy_smf_instance;
scf_scope_t *legacy_smf_scope;
scf_service_t *legacy_smf_service;
legacy_mount_t *legacy_mounts;
} legacy_handle_t;
static void sa_legacy_cleanup_smf(legacy_handle_t *);
static int sa_legacy_check_mounts(legacy_handle_t *, char *, char *, size_t,
char *, size_t);
static void sa_legacy_cleanup_mounts(legacy_handle_t *);
sa_fs_ops_t sa_plugin_ops = {
.saf_hdr = {
.pi_ptype = SA_PLUGIN_FS,
.pi_type = SA_FS_LEGACY,
.pi_name = "legacy",
.pi_version = SA_LIBSHARE_VERSION,
.pi_flags = 0,
.pi_init = sa_legacy_init,
.pi_fini = sa_legacy_fini
},
.saf_open = sa_legacy_open,
.saf_close = sa_legacy_close,
.saf_reset = NULL,
.saf_share_write = sa_legacy_share_write,
.saf_share_read = sa_legacy_share_read,
.saf_share_read_init = sa_legacy_share_read_init,
.saf_share_read_next = sa_legacy_share_read_next,
.saf_share_read_fini = sa_legacy_share_read_fini,
.saf_share_remove = sa_legacy_share_remove,
.saf_share_get_acl = sa_legacy_share_get_acl,
.saf_share_set_acl = sa_legacy_share_set_acl,
.saf_get_mntpnt_for_path = sa_legacy_get_mntpnt_for_path,
.saf_sharing_enabled = sa_legacy_sharing_enabled,
.saf_sharing_get_prop = sa_legacy_sharing_get_prop,
.saf_sharing_set_prop = sa_legacy_sharing_set_prop,
.saf_is_legacy = sa_legacy_is_legacy,
.saf_is_zoned = sa_legacy_is_zoned,
.saf_share_notify = NULL
};
static int
sa_legacy_init(void)
{
return (SA_OK);
}
static void
sa_legacy_fini(void)
{
/* do nothing */
}
static void
sa_legacy_cleanup_smf(legacy_handle_t *hdl)
{
if (hdl->legacy_smf_scope != NULL) {
scf_scope_destroy(hdl->legacy_smf_scope);
hdl->legacy_smf_scope = NULL;
}
if (hdl->legacy_smf_hdl != NULL) {
scf_handle_destroy(hdl->legacy_smf_hdl);
hdl->legacy_smf_hdl = NULL;
}
if (hdl->legacy_smf_instance != NULL) {
scf_instance_destroy(hdl->legacy_smf_instance);
hdl->legacy_smf_instance = NULL;
}
if (hdl->legacy_smf_service != NULL) {
scf_service_destroy(hdl->legacy_smf_service);
hdl->legacy_smf_service = NULL;
}
}
static void
sa_legacy_cleanup_mounts(legacy_handle_t *hdl)
{
legacy_mount_t *lm;
while ((lm = hdl->legacy_mounts) != NULL) {
hdl->legacy_mounts = lm->lm_next;
free(lm->lm_mntpnt);
free(lm->lm_mntopts);
free(lm);
}
}
static legacy_handle_t *
legacy_init(void)
{
legacy_handle_t *hdl;
if ((hdl = calloc(1, sizeof (legacy_handle_t))) == NULL)
return (NULL);
if ((hdl->legacy_smf_hdl = scf_handle_create(SCF_VERSION)) == NULL)
goto err;
if (scf_handle_bind(hdl->legacy_smf_hdl) != 0)
goto err;
if ((hdl->legacy_smf_instance =
scf_instance_create(hdl->legacy_smf_hdl)) == NULL)
goto err;
if ((hdl->legacy_smf_scope =
scf_scope_create(hdl->legacy_smf_hdl)) == NULL)
goto err;
if (scf_handle_get_scope(hdl->legacy_smf_hdl, SCF_SCOPE_LOCAL,
hdl->legacy_smf_scope) != 0)
goto err;
if ((hdl->legacy_smf_service =
scf_service_create(hdl->legacy_smf_hdl)) == NULL)
goto err;
if (scf_scope_get_service(hdl->legacy_smf_scope, "network/shares",
hdl->legacy_smf_service) != 0)
goto err;
if (scf_service_get_instance(hdl->legacy_smf_service, "default",
hdl->legacy_smf_instance) != 0)
goto err;
return (hdl);
err:
sa_legacy_cleanup_smf(hdl);
free(hdl);
return (NULL);
}
static void
legacy_fini(legacy_handle_t *hdl)
{
sa_legacy_cleanup_smf(hdl);
sa_legacy_cleanup_mounts(hdl);
free(hdl);
}
static void *
sa_legacy_open(libshare_handle_t *shdl)
{
NOTE(ARGUNUSED(shdl))
legacy_handle_t *hdl;
if ((hdl = legacy_init()) == NULL) {
salog_error(0, "libshare_legacy: failed to open legacy handle");
return (NULL);
}
return (hdl);
}
static void
sa_legacy_close(void *legacy_hdl)
{
legacy_fini(legacy_hdl);
}
/*
* sa_legacy_fix_share_name
*
* some valid SMB share names contain characters illegal in SMF. This
* function maps to a valid character set. Since it is only used when
* referencing SMF, it only needs a one way mapping.
*/
static char *
sa_legacy_fix_share_name(const char *sharename)
{
static char hex[] = "0123456789abcdef";
static char invalid[] = " .&,#$^(){}~_";
char buf[MAXNAMELEN];
char *newshare = buf;
char *limit = buf + MAXNAMELEN - 1;
newshare += snprintf(buf, sizeof (buf), "S-");
while (*sharename != '\0' && newshare < limit) {
if (strchr(invalid, *sharename) != NULL) {
*newshare++ = '_';
*newshare++ = hex[(*sharename & 0xF0) >> 4];
*newshare++ = hex[*sharename & 0xF];
} else {
*newshare++ = *sharename;
}
sharename++;
}
*newshare = '\0';
return (strdup(buf));
}
/*
* legacy_common_transaction
*
* implements both store and remove of SMF property.
*/
static int
legacy_common_transaction(legacy_handle_t *hdl, const char *shname,
char *buf, size_t buflen, boolean_t dowrite)
{
scf_transaction_t *trans = NULL;
scf_propertygroup_t *pg = NULL;
scf_value_t *value = NULL;
scf_transaction_entry_t *entry = NULL;
int ret = SA_OK;
char *sharename;
sharename = sa_legacy_fix_share_name(shname);
if (sharename == NULL) {
ret = SA_NO_MEMORY;
goto err;
}
trans = scf_transaction_create(hdl->legacy_smf_hdl);
if (trans == NULL) {
ret = SA_SYSTEM_ERR;
goto err;
}
pg = scf_pg_create(hdl->legacy_smf_hdl);
if (pg == NULL) {
ret = SA_SYSTEM_ERR;
goto err;
}
if (scf_instance_get_pg(hdl->legacy_smf_instance, LEGACY_PG, pg) != 0) {
if (scf_instance_add_pg(hdl->legacy_smf_instance, LEGACY_PG,
SCF_GROUP_FRAMEWORK, 0, pg) != 0) {
switch (scf_error()) {
case SCF_ERROR_PERMISSION_DENIED:
ret = SA_NO_PERMISSION;
break;
default:
ret = SA_SYSTEM_ERR;
break;
}
goto err;
}
}
if (scf_transaction_start(trans, pg) != 0) {
ret = SA_SYSTEM_ERR;
goto err;
}
value = scf_value_create(hdl->legacy_smf_hdl);
entry = scf_entry_create(hdl->legacy_smf_hdl);
if (value == NULL || entry == NULL) {
ret = SA_SYSTEM_ERR;
goto err;
}
if (dowrite) {
if (scf_transaction_property_change(trans, entry,
sharename, SCF_TYPE_OPAQUE) == 0 ||
scf_transaction_property_new(trans, entry,
sharename, SCF_TYPE_OPAQUE) == 0) {
if (scf_value_set_opaque(value, buf, buflen) == 0) {
if (scf_entry_add_value(entry, value) != 0) {
ret = SA_SYSTEM_ERR;
scf_value_destroy(value);
}
/* The value is in the transaction */
value = NULL;
} else {
/* Value couldn't be constructed */
ret = SA_SYSTEM_ERR;
}
/* The entry is in the transaction or NULL */
entry = NULL;
} else {
ret = SA_SYSTEM_ERR;
}
} else {
if (scf_transaction_property_delete(trans, entry,
sharename) != 0)
ret = SA_SYSTEM_ERR;
else
entry = NULL;
}
if (ret == SA_SYSTEM_ERR)
goto err;
if (scf_transaction_commit(trans) < 0)
ret = SA_SYSTEM_ERR;
scf_transaction_destroy_children(trans);
scf_transaction_destroy(trans);
err:
if (ret == SA_SYSTEM_ERR &&
scf_error() == SCF_ERROR_PERMISSION_DENIED)
ret = SA_NO_PERMISSION;
/*
* Cleanup if there were any errors that didn't leave these
* values where they would be cleaned up later.
*/
if (value != NULL)
scf_value_destroy(value);
if (entry != NULL)
scf_entry_destroy(entry);
if (pg != NULL)
scf_pg_destroy(pg);
switch (ret) {
case SA_SYSTEM_ERR:
salog_error(ret, "legacy_share_rsrc_write: SMF error: %s",
scf_strerror(scf_error()));
break;
default:
if (ret != SA_OK)
salog_error(ret, "legacy_share_rsrc_write");
break;
}
free(sharename);
return (ret);
}
static int
legacy_share_rsrc_write(legacy_handle_t *hdl, char *shname, char *buf,
size_t buflen)
{
int ret;
ret = legacy_common_transaction(hdl, shname, buf, buflen, B_TRUE);
return (ret);
}
/*ARGSUSED*/
static int
sa_legacy_share_write(libshare_handle_t *shdl, nvlist_t *share,
boolean_t persist)
{
legacy_handle_t *legacy_hdl;
char *sh_name;
size_t buflen;
char *bufp = NULL;
int rc;
if ((sh_name = sa_share_get_name(share)) == NULL) {
rc = SA_NO_SHARE_NAME;
salog_error(rc, "sa_legacy_share_write");
goto out;
}
if (nvlist_pack(share, &bufp, &buflen, NV_ENCODE_XDR, 0) != 0) {
rc = SA_XDR_ENCODE_ERR;
salog_error(rc, "sa_legacy_share_write: %s", sh_name);
goto out;
}
if ((legacy_hdl = sa_get_fs_handle(shdl, SA_FS_LEGACY, &rc)) == NULL)
goto out;
rc = legacy_share_rsrc_write(legacy_hdl, sh_name, bufp, buflen);
if (rc < 0) {
rc = SA_SYSTEM_ERR;
salog_error(0, "sa_legacy_share_write: "
"error writing share '%s': %s",
sh_name, strerror(errno));
goto out;
} else {
rc = SA_OK;
}
out:
if (bufp != NULL)
free(bufp);
return (rc);
}
static int
sa_legacy_share_read(libshare_handle_t *shdl, const char *fs_name,
const char *sh_name, nvlist_t **share)
{
nvlist_t *shareval = NULL;
sa_read_hdl_t hdl;
int rc = SA_SHARE_NOT_FOUND;
char *path;
char *sharename;
char *mntpnt;
rc = sa_legacy_share_read_init(shdl, &hdl);
if (rc != SA_OK)
return (rc);
mntpnt = malloc(MAXPATHLEN);
if (mntpnt == NULL)
goto done;
/* While fs_name should be a mountpoint, make sure */
rc = sa_legacy_get_mntpnt_for_path(shdl, fs_name, mntpnt,
MAXPATHLEN, NULL, 0, NULL, 0);
if (rc != SA_OK)
goto done;
hdl.srh_mntpnt = mntpnt;
for (rc = sa_legacy_share_read_next(shdl, &hdl, &shareval);
rc == SA_OK && shareval != NULL;
rc = sa_legacy_share_read_next(shdl, &hdl, &shareval)) {
path = sa_share_get_path(shareval);
sharename = sa_share_get_name(shareval);
if (path == NULL || sharename == NULL) {
nvlist_free(shareval);
continue;
}
if (strcmp(sharename, sh_name) == 0) {
rc = SA_OK;
break;
}
nvlist_free(shareval);
}
done:
if (rc == SA_OK)
*share = shareval;
(void) sa_legacy_share_read_fini(shdl, &hdl);
free(mntpnt);
return (rc);
}
static int
sa_legacy_share_read_fini(libshare_handle_t *shdl, sa_read_hdl_t *hdl)
{
NOTE(ARGUNUSED(shdl))
scf_pg_destroy(hdl->srh_smf_pg);
hdl->srh_smf_pg = NULL;
scf_iter_destroy(hdl->srh_smf_iter);
hdl->srh_smf_iter = NULL;
scf_value_destroy(hdl->srh_smf_value);
hdl->srh_smf_value = NULL;
scf_property_destroy(hdl->srh_smf_prop);
hdl->srh_smf_prop = NULL;
return (SA_OK);
}
static int
sa_legacy_share_read_init(libshare_handle_t *shdl, sa_read_hdl_t *hdl)
{
legacy_handle_t *legacy_hdl;
int rc;
if ((legacy_hdl = sa_get_fs_handle(shdl, SA_FS_LEGACY, &rc)) == NULL)
return (rc);
hdl->srh_smf_pg = scf_pg_create(legacy_hdl->legacy_smf_hdl);
hdl->srh_smf_iter = scf_iter_create(legacy_hdl->legacy_smf_hdl);
hdl->srh_smf_value = scf_value_create(legacy_hdl->legacy_smf_hdl);
hdl->srh_smf_prop = scf_property_create(legacy_hdl->legacy_smf_hdl);
if (hdl->srh_smf_iter == NULL || hdl->srh_smf_value == NULL ||
hdl->srh_smf_prop == NULL || hdl->srh_smf_pg == NULL) {
rc = SA_SYSTEM_ERR;
} else {
if (scf_instance_get_pg(legacy_hdl->legacy_smf_instance,
LEGACY_PG, hdl->srh_smf_pg) != 0) {
if (scf_instance_add_pg(legacy_hdl->legacy_smf_instance,
LEGACY_PG, SCF_GROUP_FRAMEWORK, 0,
hdl->srh_smf_pg) != 0) {
rc = SA_SYSTEM_ERR;
}
}
if (scf_iter_pg_properties(hdl->srh_smf_iter,
hdl->srh_smf_pg) != 0) {
rc = SA_SYSTEM_ERR;
}
}
if (rc != SA_OK)
(void) sa_legacy_share_read_fini(shdl, hdl);
return (rc);
}
static int
sa_legacy_share_read_next(libshare_handle_t *shdl, sa_read_hdl_t *hdl,
nvlist_t **share)
{
NOTE(ARGUNUSED(shdl))
int ret = SA_OK;
void *nvlist;
size_t nvlistsize;
char *name;
char *mntpnt;
name = malloc(scf_limit(SCF_LIMIT_MAX_NAME_LENGTH));
if (name == NULL)
return (SA_NO_MEMORY);
nvlistsize = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
nvlist = malloc(nvlistsize);
if (nvlist == NULL) {
ret = SA_NO_MEMORY;
goto done;
}
while (ret == SA_OK) {
if (scf_iter_next_property(hdl->srh_smf_iter,
hdl->srh_smf_prop) == 0) {
ret = SA_SHARE_NOT_FOUND;
break;
}
if (scf_property_get_name(hdl->srh_smf_prop, name,
scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) > 0) {
if (strcmp(name, "action_authorization") == 0 ||
strcmp(name, "value_authorization") == 0)
continue;
if (scf_property_get_value(hdl->srh_smf_prop,
hdl->srh_smf_value) == 0) {
if (scf_value_get_opaque(hdl->srh_smf_value,
nvlist, nvlistsize) >= 0) {
if (nvlist_unpack(nvlist,
nvlistsize, share, 0) != 0)
ret = SA_SYSTEM_ERR;
} else {
ret = SA_SYSTEM_ERR;
}
if (ret != SA_OK)
break;
mntpnt = sa_share_get_mntpnt(*share);
if (mntpnt != NULL &&
strcmp(mntpnt, hdl->srh_mntpnt) == 0)
break;
/* skip since on other file system */
nvlist_free(*share);
*share = NULL;
} else {
ret = SA_SYSTEM_ERR;
}
} else {
ret = SA_SYSTEM_ERR;
}
}
done:
free(name);
if (nvlist != NULL)
free(nvlist);
return (ret);
}
static int
sa_legacy_share_remove(libshare_handle_t *shdl, const char *fs_name,
const char *sh_name, boolean_t persist)
{
NOTE(ARGUNUSED(fs_name))
NOTE(ARGUNUSED(persist))
legacy_handle_t *legacy_hdl;
scf_property_t *prop;
int rc;
if ((legacy_hdl = sa_get_fs_handle(shdl, SA_FS_LEGACY, &rc)) == NULL)
return (rc);
prop = scf_property_create(legacy_hdl->legacy_smf_hdl);
if (prop == NULL) {
rc = SA_SYSTEM_ERR;
goto err;
}
rc = legacy_common_transaction(legacy_hdl, sh_name, NULL, 0, B_FALSE);
err:
if (rc == SA_SYSTEM_ERR && scf_error() == SCF_ERROR_PERMISSION_DENIED)
rc = SA_NO_PERMISSION;
if (prop != NULL)
scf_property_destroy(prop);
return (rc);
}
static int
sa_legacy_share_get_acl(libshare_handle_t *shdl, const char *sh_name,
const char *sh_path, acl_t **aclp)
{
NOTE(ARGUNUSED(shdl))
NOTE(ARGUNUSED(sh_name))
NOTE(ARGUNUSED(sh_path))
NOTE(ARGUNUSED(aclp))
return (SA_NOT_SUPPORTED);
}
static int
sa_legacy_share_set_acl(libshare_handle_t *shdl, const char *sh_name,
const char *sh_path, acl_t *acl)
{
NOTE(ARGUNUSED(shdl))
NOTE(ARGUNUSED(sh_name))
NOTE(ARGUNUSED(sh_path))
NOTE(ARGUNUSED(acl))
return (SA_NOT_SUPPORTED);
}
/*
* sa_legacy_get_mntpnt_for_path
*
* A path identifies its mount point by its st_dev field in stat. To
* find the mount point, work backward up the path until the st_dev
* doesn't match. The last to match was the root (mountpoint).
*/
static int
sa_legacy_get_mntpnt_for_path(libshare_handle_t *shdl, const char *sh_path,
char *mntpnt, size_t mp_len, char *volname, size_t vn_len, char *mntopts,
size_t opt_len)
{
NOTE(ARGUNUSED(shdl))
legacy_handle_t *legacy_hdl;
char *path = NULL;
struct stat64 st;
FILE *mnttab;
struct mnttab entry, result;
int ret = SA_INVALID_SHARE_MNTPNT;
int err;
#if defined(lint)
volname = volname;
vn_len = vn_len;
#endif
if (stat64(sh_path, &st) < 0)
return (SA_PATH_NOT_FOUND);
mnttab = fopen(MNTTAB, "r");
if (mnttab == NULL)
return (SA_SYSTEM_ERR);
(void) memset(&entry, '\0', sizeof (entry));
entry.mnt_mountp = (char *)sh_path;
/* special case of mount point being the path */
if (getmntany(mnttab, &result, &entry) == 0) {
(void) fclose(mnttab);
if (mntpnt != NULL)
(void) strlcpy(mntpnt, result.mnt_mountp, mp_len);
if (mntopts != 0)
(void) strlcpy(mntopts, result.mnt_mntopts, opt_len);
return (SA_OK);
}
path = strdup(sh_path);
if (path == NULL) {
ret = SA_NO_MEMORY;
goto done;
}
if ((legacy_hdl = sa_get_fs_handle(shdl, SA_FS_LEGACY, &err)) == NULL) {
ret = err;
goto done;
}
while (*path != '\0') {
char *work;
work = strrchr(path, '/');
if (work != NULL) {
*work = '\0';
if (strlen(path) == 0) {
/*
* lookup mnttab entry for "/"
*/
ret = sa_legacy_check_mounts(legacy_hdl, "/",
mntpnt, mp_len, mntopts, opt_len);
} else {
ret = sa_legacy_check_mounts(legacy_hdl, path,
mntpnt, mp_len, mntopts, opt_len);
}
if (ret == SA_OK)
break;
if (ret == SA_NO_SHARE_DIR)
ret = SA_PATH_NOT_FOUND;
}
}
done:
(void) fclose(mnttab);
free(path);
return (ret);
}
static int
sa_legacy_sharing_enabled(libshare_handle_t *shdl, const char *sh_path,
const char *sh_name, sa_proto_t *protos)
{
NOTE(ARGUNUSED(shdl))
NOTE(ARGUNUSED(sh_path))
NOTE(ARGUNUSED(sh_name))
/*
* There isn't a way to mark a legacy file system as
* shareable. Assume ALL.
*/
*protos = SA_PROT_ALL;
return (SA_OK);
}
static int
sa_legacy_sharing_get_prop(libshare_handle_t *shdl, const char *mntpnt,
const char *sh_name, sa_proto_t protos, char **props)
{
NOTE(ARGUNUSED(shdl))
NOTE(ARGUNUSED(mntpnt))
NOTE(ARGUNUSED(sh_name))
NOTE(ARGUNUSED(protos))
*props = strdup("on");
if (*props == NULL)
return (SA_NO_MEMORY);
return (SA_OK);
}
static int
sa_legacy_sharing_set_prop(libshare_handle_t *shdl, const char *mntpnt,
const char *sh_name, sa_proto_t protos, const char *props)
{
NOTE(ARGUNUSED(shdl))
NOTE(ARGUNUSED(mntpnt))
NOTE(ARGUNUSED(sh_name))
NOTE(ARGUNUSED(protos))
NOTE(ARGUNUSED(props))
return (SA_OK);
}
static int
sa_legacy_is_legacy(libshare_handle_t *shdl, const char *sh_path,
boolean_t *legacy)
{
NOTE(ARGUNUSED(shdl))
NOTE(ARGUNUSED(sh_path))
*legacy = B_TRUE;
return (SA_OK);
}
/*
* sa_legacy_mntpnt_is_zoned
*
* always return negative
*/
/* ARGSUSED */
static int
sa_legacy_is_zoned(libshare_handle_t *shdl, const char *mntpnt,
boolean_t *zoned)
{
NOTE(ARGUNUSED(shdl))
NOTE(ARGUNUSED(mntpnt))
*zoned = B_FALSE;
return (0);
}
static int
sa_legacy_check_mounts(legacy_handle_t *legacy_hdl, char *path, char *mntpnt,
size_t mp_len, char *mntopts, size_t opt_len)
{
legacy_mount_t *mount;
legacy_mount_t *prevmount;
FILE *mnttab;
int ret = SA_NO_SHARE_DIR;
struct mnttab entry;
struct stat64 st;
static struct stat64 check;
if (check.st_mtime == 0)
(void) stat64(MNTTAB, &check);
/*
* since sa_legacy_cleanup_mounts() sets legacy_mounts to NULL
* when cleaning so we use that to force a reload of the mount
* table.
*/
if (legacy_hdl->legacy_mounts != NULL) {
(void) stat64(MNTTAB, &st);
if (st.st_mtime != check.st_mtime)
sa_legacy_cleanup_mounts(legacy_hdl);
check = st;
}
if (legacy_hdl->legacy_mounts == NULL) {
mnttab = fopen(MNTTAB, "r");
if (mnttab == NULL) {
ret = SA_SYSTEM_ERR;
goto done;
}
prevmount = mount = NULL;
while (getmntent(mnttab, &entry) == 0) {
mount = calloc(1, sizeof (legacy_mount_t));
if (mount == NULL) {
ret = SA_NO_MEMORY;
break;
}
mount->lm_mntpnt = strdup(entry.mnt_mountp);
if (mount->lm_mntpnt == NULL) {
free(mount);
ret = SA_NO_MEMORY;
break;
}
mount->lm_mntopts = strdup(entry.mnt_mntopts);
if (mount->lm_mntopts == NULL) {
free(mount->lm_mntpnt);
free(mount);
ret = SA_NO_MEMORY;
break;
}
if (prevmount == NULL) {
legacy_hdl->legacy_mounts = mount;
} else {
prevmount->lm_next = mount;
}
prevmount = mount;
}
(void) fclose(mnttab);
}
for (mount = legacy_hdl->legacy_mounts; mount != NULL;
mount = mount->lm_next) {
if (strcmp(path, mount->lm_mntpnt) == 0) {
if (mntpnt != NULL) {
(void) strlcpy(mntpnt, mount->lm_mntpnt,
mp_len);
}
if (mntopts != NULL) {
(void) strlcpy(mntopts, mount->lm_mntopts,
opt_len);
}
ret = SA_OK;
break;
}
}
done:
if (ret != SA_OK && ret != SA_NO_SHARE_DIR)
sa_legacy_cleanup_mounts(legacy_hdl);
return (ret);
}