commands.c revision a237e38e9161f0acd6451439d4a7dd597e66291d
/*
* 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
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <getopt.h>
#include <utmpx.h>
#include <pwd.h>
#include <auth_attr.h>
#include <secdb.h>
#include <errno.h>
#include <libshare.h>
#include "sharemgr.h"
#include <libscf.h>
#include <libintl.h>
static char *sa_get_usage(sa_usage_t);
/*
* Implementation of the common sub-commands supported by sharemgr.
* A number of helper functions are also included.
*/
/*
* has_protocol(group, proto)
* If the group has an optionset with the specified protocol,
* return true (1) otherwise false (0).
*/
static int
{
int result = 0;
result++;
}
return (result);
}
/*
* add_list(list, item)
* Adds a new list member that points to item to the list.
* If list is NULL, it starts a new list. The function returns
* the first member of the list.
*/
struct list *
{
} else {
return (listp);
}
return (new);
/* get to end of list */
}
return (listp);
}
/*
* free_list(list)
* Given a list, free all the members of the list;
*/
static void
{
}
}
/*
* check_authorization(instname, which)
*
* Checks to see if the specific type of authorization in which is
* enabled for the user in this SMF service instance.
*/
static int
{
int ret = 1;
ret = 0;
if (ret == 1) {
/* since names are restricted to SA_MAX_NAME_LEN won't overflow */
if (scf_handle_bind(handle) == 0) {
switch (which) {
case SVC_SET:
"general",
break;
case SVC_ACTION:
"general",
break;
}
}
}
}
/* make sure we have an authorization string property */
int i;
/* check if this user has one of the strings */
ret = 1;
break;
}
}
}
endauthattr();
} else {
/* no authorization string defined */
ret = 0;
}
return (ret);
}
/*
* check_authorizations(instname, flags)
*
* check all the needed authorizations for the user in this service
* instance. Return value of 1(true) or 0(false) indicates whether
* there are authorizations for the user or not.
*/
static int
{
int ret1 = 0;
int ret2 = 0;
int ret;
if (flags & SVC_ACTION)
switch (flags) {
case SVC_ACTION:
break;
case SVC_SET:
break;
case SVC_ACTION|SVC_SET:
break;
default:
/* if not flags set, we assume we don't need authorizations */
ret = 1;
}
return (ret);
}
/*
* enable_group(group, updateproto)
*
* enable all the shares in the specified group. This is a helper for
* enable_all_groups in order to simplify regular and subgroup (zfs)
* disabling. Group has already been checked for non-NULL.
*/
static void
{
if (updateproto != NULL)
}
}
/*
* enable_all_groups(list, setstate, online, updateproto)
* Given a list of groups, enable each one found. If updateproto
* is not NULL, then update all the shares for the protocol that
* was passed in.
*/
static int
int online, char *updateproto)
{
char *state;
char *name;
/* if itemdata != NULL then a single share */
}
if (setstate)
"enabled");
/* if itemdata == NULL then the whole group */
/*
* if the share is managed by ZFS, don't
* update any of the protocols since ZFS is
* handling this. updateproto will contain
* the name of the protocol that we want to
* update legacy files for.
*/
/* never update legacy for ZFS subgroups */
}
}
if (online) {
"%s:%s",
(void) smf_enable_instance(instance, 0);
}
} else {
}
}
}
}
}
}
return (ret);
}
/*
* chk_opt(optlistp, security, proto)
*
* Do a sanity check on the optlist provided for the protocol. This
* is a syntax check and verification that the property is either a
* general or specific to a names optionset.
*/
static int
{
char *sep = "";
int notfirst = 0;
int ret;
char *optname;
ret = OPT_ADD_OK;
if (!security)
} else {
if (security)
}
if (ret != OPT_ADD_OK) {
if (notfirst == 0)
switch (ret) {
case OPT_ADD_SYNTAX:
sep = ", ";
break;
case OPT_ADD_SECURITY:
sep = ", ";
break;
case OPT_ADD_PROPERTY:
sep = ", ";
break;
}
notfirst++;
}
}
if (notfirst) {
(void) printf("\n");
ret = SA_SYNTAX_ERR;
}
return (ret);
}
/*
* free_opt(optlist)
* Free the specified option list.
*/
static void
{
}
}
/*
* check property list for valid properties
* A null value is a remove which is always valid.
*/
static int
{
else
}
ret = SA_NO_MEMORY;
sa_errorstr(ret));
}
(void) sa_remove_property(prop);
}
}
return (ret);
}
/*
* add_optionset(group, optlist, protocol, *err)
* Add the options in optlist to an optionset and then add the optionset
* to the group.
*
* The return value indicates if there was a "change" while errors are
* returned via the *err parameters.
*/
static int
{
int result = 0;
}
/*
* add the property, but only if it is
* a non-NULL or non-zero length value
*/
(void) sa_remove_property(prop);
"%s: %s\n"),
sa_errorstr(ret));
}
}
" %s: %s\n"),
sa_errorstr(ret));
} else {
/* there was a change */
result = 1;
}
}
}
} else {
/* should check to see if value changed */
"property %s: %s\n"),
sa_errorstr(ret));
} else {
result = 1;
}
}
}
}
return (result);
}
/*
* sa_create(flags, argc, argv)
* create a new group
* this may or may not have a protocol associated with it.
* No protocol means "all" protocols in this case.
*/
static int
{
char *groupname;
int verbose = 0;
int dryrun = 0;
int c;
int err = 0;
int auth;
switch (c) {
case 'v':
verbose++;
break;
case 'n':
dryrun++;
break;
case 'P':
if (!sa_valid_protocol(protocol)) {
protocol);
return (SA_INVALID_PROTOCOL);
}
break;
case 'p':
switch (ret) {
case OPT_ADD_SYNTAX:
"property: %s\n"),
optarg);
return (SA_SYNTAX_ERR);
case OPT_ADD_SECURITY:
"to be set with set-security: %s\n"),
optarg);
return (SA_SYNTAX_ERR);
default:
break;
}
break;
default:
case 'h':
case '?':
return (0);
}
}
return (SA_BAD_PATH);
}
return (SA_SYNTAX_ERR);
}
/* lookup default protocol */
"with properties\n"));
return (SA_INVALID_PROTOCOL);
}
if (ret == OPT_ADD_SECURITY) {
"supported with create\n"));
return (SA_SYNTAX_ERR);
}
/*
* if a group already exists, we can only add a new protocol
* to it and not create a new one or add the same protocol
* again.
*/
/* group exists so must be a protocol add */
" with protocol %s\n"),
}
} else {
/* must add new protocol */
" specified.\n"));
}
} else {
/*
* is it a valid name? Must comply with SMF instance
* name restrictions.
*/
if (!sa_valid_group_name(groupname)) {
}
}
/* check protocol vs optlist */
/* check options, if any, for validity */
}
}
}
ret = SA_NO_MEMORY;
char **protolist;
int numprotos, i;
for (i = 0; i < numprotos; i++) {
}
}
/*
* we have a group and legal additions
*/
/*
* commit to configuration for protocols that
* need to do block updates. For NFS, this
* doesn't do anything but it will be run for
* all protocols that implement the
* appropriate plugin.
*/
} else {
(void) sa_remove_group(group);
}
} else {
sa_errorstr(ret));
}
}
}
return (ret);
}
/*
* group_status(group)
*
*/
static char *
{
char *state;
int enabled = 0;
enabled = 1;
}
}
}
/*
* sa_delete(flags, argc, argv)
*
* Delete a group.
*/
static int
{
char *groupname;
int verbose = 0;
int dryrun = 0;
int force = 0;
int c;
int auth;
switch (c) {
case 'v':
verbose++;
break;
case 'n':
dryrun++;
break;
case 'P':
if (!sa_valid_protocol(protocol)) {
protocol);
return (SA_INVALID_PROTOCOL);
}
break;
case 'S':
break;
case 'f':
force++;
break;
default:
case 'h':
case '?':
return (0);
}
}
return (SA_SYNTAX_ERR);
}
return (SA_SYNTAX_ERR);
}
"specified.\n"));
return (SA_SYNTAX_ERR);
}
/*
* Determine if the group already exists since it must in
* order to be removed.
*
* We can delete when:
*
* - group is empty
* - force flag is set
* - if protocol specified, only delete the protocol
*/
} else {
if (!dryrun) {
/*
* need to do the disable of each
* share, but don't actually do
* anything on a dryrun.
*/
share = next_share;
}
}
}
/* commit to configuration if not a dryrun */
}
} else {
/* a protocol delete */
/* only delete specified security */
} else {
}
} else {
/* have an optionset with protocol to delete */
/*
* now find all security sets for the protocol
* and remove them. Don't remove other
* protocols.
*/
char *secprot;
}
} else {
if (!dryrun)
}
}
}
}
sa_errorstr(ret));
}
return (ret);
}
/*
* strndupr(*buff, str, buffsize)
*
* used with small strings to duplicate and possibly increase the
* buffer size of a string.
*/
static char *
{
int limit;
return (NULL);
*buffsize = 64;
buff[0] = '\0';
}
}
} else {
/* if it fails, fail it hard */
}
return (buff);
}
/*
* group_proto(group)
*
* return a string of all the protocols (space separated) associated
* with this group.
*/
static char *
{
char *proto;
int buffsize = 0;
int addspace = 0;
/*
* get the protocol list by finding the optionsets on this
* group and extracting the type value. The initial call to
* strndupr() initailizes buff.
*/
/*
* extract out the protocol type from this optionset
* and append it to the buffer "buff". strndupr() will
* reallocate space as necessay.
*/
if (addspace++)
}
}
}
return (buff);
}
/*
* sa_list(flags, argc, argv)
*
* implements the "list" subcommand to list groups and optionally
* their state and protocols.
*/
static int
{
int verbose = 0;
int c;
#ifdef lint
#endif
switch (c) {
case 'v':
verbose++;
break;
case 'P':
if (!sa_valid_protocol(protocol)) {
"%s\n"),
protocol);
return (SA_INVALID_PROTOCOL);
}
break;
default:
case 'h':
case '?':
return (0);
}
}
char *name;
char *proto;
if (verbose) {
/*
* need the list of protocols
* and current status once
* available.
*/
}
}
(void) printf("\n");
}
}
}
return (0);
}
/*
* out_properties(optionset, proto, sec)
*
* Format the properties and encode the protocol and optional named
* optionset into the string.
*
* format is protocol[:name]=(property-list)
*/
static void
{
char *type;
char *value;
int spacer;
} else {
}
/*
* appropriate spacing. I.e. no prefixed space the
* first time through but a space on subsequent
* properties.
*/
spacer = 1;
else
(void) printf("\"\"");
}
}
(void) printf(")");
}
/*
* show_properties(group, protocol, prefix)
*
* print the properties for a group. If protocol is NULL, do all
* protocols otherwise only the specified protocol. All security
* (named groups specific to the protocol) are included.
*
* The "prefix" is always applied. The caller knows whether it wants
* some type of prefix string (white space) or not. Once the prefix
* has been output, it is reduced to the zero length string for the
* remainder of the property output.
*/
static void
{
char *value;
char *secvalue;
prefix = "";
}
prefix = "";
}
} else {
prefix = "";
}
prefix = "";
}
}
}
/*
* show_group(group, verbose, properties, proto, subgroup)
*
* helper function to show the contents of a group.
*/
static void
char *subgroup)
{
char *groupname;
char *sharepath;
char *resource;
char *description;
char *type;
int iszfs = 0;
return;
}
/*
* check to see if the group is managed by ZFS. If
* there is an attribute, then it is. A non-NULL zfs
* variable will trigger the different way to display
* and will remove the transient property indicator
* from the output.
*/
iszfs = 1;
}
else
if (properties) {
}
(void) printf("\n");
}
return;
}
/*
* have a group, so list the contents. Resource and
* description are only listed if verbose is set.
*/
if (verbose) {
(void) printf("\t* ");
else
(void) printf("\t ");
} else {
}
if (properties)
if (description != NULL) {
if (strlen(description) > 0) {
}
}
} else {
if (properties)
}
(void) printf("\n");
}
}
}
}
}
/*
* show_group_xml_init()
*
* Create an XML document that will be used to display config info via
* XML format.
*/
{
}
return (doc);
}
/*
* show_group_xml(doc, group)
*
* Copy the group info into the XML doc.
*/
static void
{
/*
* In the future, we may have interally used tags that
* should not appear in the XML output. Remove
* anything we don't want to show here.
*/
}
}
/*
* sa_show(flags, argc, argv)
*
* Implements the show subcommand.
*/
int
{
int verbose = 0;
int properties = 0;
int c;
int xml = 0;
#ifdef lint
#endif
switch (c) {
case 'v':
verbose++;
break;
case 'p':
properties++;
break;
case 'P':
if (!sa_valid_protocol(protocol)) {
protocol);
return (SA_INVALID_PROTOCOL);
}
break;
case 'x':
xml++;
break;
default:
case 'h':
case '?':
return (0);
}
}
if (xml) {
doc = show_group_xml_init();
ret = SA_NO_MEMORY;
}
/* no group specified so go through them all */
/*
* have a group so check if one we want and then list
* contents with appropriate options.
*/
if (xml)
else
}
} else {
/* have a specified list of groups */
if (xml)
else
} else {
}
}
}
}
return (ret);
}
/*
* enable_share(group, share, update_legacy)
*
* helper function to enable a share if the group is enabled.
*/
static int
int update_legacy)
{
char *value;
int enabled;
int iszfs = 0;
/*
* need to enable this share if the group is enabled but not
* otherwise. The enable is also done on each protocol
* represented in the group.
*/
/* remove legacy config if necessary */
if (update_legacy)
iszfs++;
}
/*
* Step through each optionset at the group level and
* enable the share based on the protocol type. This
* works because protocols must be set on the group
* for the protocol to be enabled.
*/
if (enabled)
if (update_legacy && !iszfs)
}
}
(void) sa_update_config(handle);
return (ret);
}
/*
* sa_addshare(flags, argc, argv)
*
* implements add-share subcommand.
*/
int
{
int verbose = 0;
int dryrun = 0;
int c;
char *description = NULL;
int auth;
char dir[MAXPATHLEN];
switch (c) {
case 'n':
dryrun++;
break;
case 'v':
verbose++;
break;
case 'd':
break;
case 'r':
break;
case 's':
/*
* save share path into group. Currently limit
* to one share per command.
*/
"supported\n"));
return (1);
}
break;
case 't':
break;
default:
case 'h':
case '?':
return (0);
}
}
} else {
}
} else {
ret = SA_BAD_PATH;
}
ret = SA_BAD_PATH;
} else {
}
}
/* check for valid syntax */
"space or '/' characters\n"));
ret = SA_BAD_PATH;
}
}
char *groupname;
"shared in group "
"\"%s\": %s\n"),
} else {
"shared: %s\n"),
}
} else {
"shared\n"),
}
} else {
/*
* need to check that resource name is unique
* at some point. Path checking should use the
* "normal" rules which don't check the repository.
*/
if (dryrun)
else
"%s\n"),
sa_errorstr(ret));
} else {
"resource",
resource);
}
}
}
/* now enable the share(s) */
}
switch (ret) {
case SA_DUPLICATE_NAME:
"use: %s\n"),
resource);
break;
default:
"attribute: %s\n"),
sa_errorstr(ret));
break;
case SA_OK:
break;
}
"%s\n"),
}
}
}
} else {
}
}
}
return (ret);
}
/*
* sa_moveshare(flags, argc, argv)
*
* implements move-share subcommand.
*/
int
{
int verbose = 0;
int dryrun = 0;
int c;
switch (c) {
case 'n':
dryrun++;
break;
case 'v':
verbose++;
break;
case 's':
/*
* remove share path from group. Currently limit
* to one share per command.
*/
"supported\n"));
return (SA_BAD_PATH);
}
break;
default:
case 'h':
case '?':
return (0);
}
}
} else {
ret = SA_SYNTAX_ERR;
} else
}
} else {
"the -s option\n"));
ret = SA_BAD_PATH;
} else {
} else {
char *zfsold;
char *zfsnew;
char *pname;
}
}
}
}
char *oldstate;
/*
* note that the share may need to be
* "unshared" if the new group is
* disabled and the old was enabled or
* it may need to be share to update
* if the new group is enabled.
*/
/* enable_share determines what to do */
}
}
sa_errorstr(ret));
}
verbose) {
}
}
} else {
}
}
}
return (ret);
}
/*
* sa_removeshare(flags, argc, argv)
*
* implements remove-share subcommand.
*/
int
{
int verbose = 0;
int dryrun = 0;
int force = 0;
int c;
char dir[MAXPATHLEN];
int auth;
switch (c) {
case 'n':
dryrun++;
break;
case 'v':
verbose++;
break;
case 'f':
force++;
break;
case 's':
/*
* remove share path from group. Currently limit
* to one share per command.
*/
"supported\n"));
return (SA_SYNTAX_ERR);
}
break;
default:
case 'h':
case '?':
return (0);
}
}
ret = SA_BAD_PATH;
} else {
}
}
"command\n"));
ret = SA_SYNTAX_ERR;
} else {
}
}
} else {
}
/*
* Lookup the path in the internal configuration. Care
* must be taken to handle the case where the
* underlying path has been removed since we need to
* be able to deal with that as well.
*/
else
/*
* If we didn't find the share with the provided path,
* it may be a symlink so attempt to resolve it using
* realpath and try again. Realpath will resolve any
* symlinks and place them in "dir". Note that
* sharepath is only used for the lookup the first
* time and later for error messages. dir will be used
* on the second attempt. Once a share is found, all
* operations are based off of the share variable.
*/
ret = SA_BAD_PATH;
} else {
else
}
}
}
/*
* If there hasn't been an error, there was likely a
* path found. If not, give the appropriate error
* message and set the return error. If it was found,
* then disable the share and then remove it from the
* configuration.
*/
" %s\n"),
else
} else {
if (!dryrun) {
/*
* we don't care if it fails since it
* could be disabled already. Some
* unexpected errors could occur that
* prevent removal, so also check for
* force being set.
*/
ret == SA_NOT_SUPPORTED ||
}
}
" %s\n"),
sa_errorstr(ret));
}
char *pname;
}
}
}
}
}
}
return (ret);
}
/*
* sa_set_share(flags, argc, argv)
*
* implements set-share subcommand.
*/
int
{
int dryrun = 0;
int c;
char *description = NULL;
int auth;
int verbose = 0;
switch (c) {
case 'n':
dryrun++;
break;
case 'd':
break;
case 'r':
break;
case 'v':
verbose++;
break;
case 's':
/*
* save share path into group. Currently limit
* to one share per command.
*/
"supported\n"));
return (SA_BAD_PATH);
}
break;
default:
case 'h':
case '?':
return (SA_OK);
}
}
ret = SA_BAD_PATH;
} else {
}
}
ret = SA_SYNTAX_ERR;
}
char *groupname;
} else {
}
"share %s\n"),
ret = SA_BAD_PATH;
} else {
int delgroupname = 0;
delgroupname = 1;
}
if (delgroupname) {
}
} else {
ret = SA_NO_MEMORY;
}
if (!dryrun) {
resource);
} else {
resource);
}
} else {
ret = SA_BAD_PATH;
"white space or '/'\n"));
}
}
}
}
}
switch (ret) {
case SA_DUPLICATE_NAME:
resource);
break;
default:
sa_errorstr(ret));
break;
case SA_OK:
}
break;
}
} else {
}
}
return (ret);
}
/*
* add_security(group, sectype, optlist, proto, *err)
*
* Helper function to add a security option (named optionset) to the
* group.
*/
static int
{
int result = 0;
}
/*
* add the property, but only if it is
* a non-NULL or non-zero length value
*/
(void) sa_remove_property(prop);
"property %s: %s\n"),
sa_errorstr(ret));
}
"property (%s=%s): %s\n"),
sa_errorstr(ret));
} else {
result = 1;
}
}
}
}
} else {
}
}
/*
* when done, properties may have all been removed but
* we need to keep the security type itself until
* explicitly removed.
*/
if (result)
}
return (result);
}
/*
* basic_set(groupname, optlist, protocol, sharepath, dryrun)
*
* This function implements "set" when a name space (-S) is not
* specified. It is a basic set. Options and other CLI parsing has
* already been done.
*/
static int
{
int change = 0;
}
}
/* group must exist */
&ret);
else
&ret);
}
}
}
} else {
}
/*
* we have a group and potentially legal additions
*/
/* commit to configuration if not a dryrun */
/* properties changed, so update all shares */
}
}
return (ret);
}
/*
* space_set(groupname, optlist, protocol, sharepath, dryrun)
*
* This function implements "set" when a name space (-S) is
* specified. It is a namespace set. Options and other CLI parsing has
* already been done.
*/
static int
{
int change = 0;
/*
* make sure protcol and sectype are valid
*/
"for protocol.\n"),
sectype);
return (SA_INVALID_SECURITY);
}
}
}
/* group must exist */
&ret);
else
&ret);
sa_errorstr(ret));
}
}
} else {
}
/*
* we have a group and potentially legal additions
*/
/* commit to configuration if not a dryrun */
/* properties changed, so update all shares */
}
}
return (ret);
}
/*
* sa_set(flags, argc, argv)
*
* Implements the set subcommand. It keys off of -S to determine which
* set of operations to actually do.
*/
int
{
char *groupname;
int verbose = 0;
int dryrun = 0;
int c;
int auth;
switch (c) {
case 'v':
verbose++;
break;
case 'n':
dryrun++;
break;
case 'P':
if (!sa_valid_protocol(protocol)) {
"%s\n"),
protocol);
return (SA_INVALID_PROTOCOL);
}
break;
case 'p':
switch (ret) {
case OPT_ADD_SYNTAX:
optarg);
return (SA_SYNTAX_ERR);
case OPT_ADD_MEMORY:
optarg);
return (SA_NO_MEMORY);
default:
break;
}
break;
case 's':
break;
case 'S':
break;
default:
case 'h':
case '?':
return (SA_OK);
}
}
ret != OPT_ADD_OK) {
char *sep = "\t";
sep = ", ";
}
" specified"), sep);
sep = ", ";
}
sep = ", ";
}
(void) printf("\n");
ret = SA_SYNTAX_ERR;
} else {
/*
* if a group already exists, we can only add a new
* protocol to it and not create a new one or add the
* same protocol again.
*/
else
}
}
return (ret);
}
/*
* remove_options(group, optlist, proto, *err)
*
* helper function to actually remove options from a group after all
* preprocessing is done.
*/
static int
{
int change = 0;
break;
change = 1;
}
}
}
return (change);
}
/*
* valid_unset(group, optlist, proto)
*
* Sanity check the optlist to make sure they can be removed. Issue an
* error if a property doesn't exist.
*/
static int
{
" not set\n"),
}
}
}
return (ret);
}
/*
* valid_unset_security(group, optlist, proto)
*
* Sanity check the optlist to make sure they can be removed. Issue an
* error if a property doesn't exist.
*/
static int
char *sectype)
{
char *sec;
" not set\n"),
}
}
} else {
sectype);
}
return (ret);
}
/*
* remove_security(group, optlist, proto)
*
* Remove the properties since they were checked as valid.
*/
static int
{
int change = 0;
break;
change = 1;
}
}
/*
* when done, properties may have all been removed but
* we need to keep the security type itself until
* explicitly removed.
*/
} else {
}
return (change);
}
/*
* basic_unset(groupname, optlist, protocol, sharepath, dryrun)
*
* unset non-named optionset properties.
*/
static int
{
int change = 0;
}
}
/* group must exist */
&ret);
/* if a share optionset is empty, remove it */
protocol);
(void) sa_destroy_optionset(optionset);
}
} else {
&ret);
}
"%s\n"),
sa_errorstr(ret));
}
} else {
}
}
/*
* we have a group and potentially legal additions
*/
/* commit to configuration if not a dryrun */
/* properties changed, so update all shares */
}
}
return (ret);
}
/*
* space_unset(groupname, optlist, protocol, sharepath, dryrun)
*
* unset named optionset properties.
*/
static int
{
int change = 0;
}
}
&ret);
/* if a share security is empty, remove it */
protocol);
}
} else {
&ret);
}
} else {
char *sec;
change = 1;
} else {
}
}
sa_errorstr(ret));
}
}
} else {
}
/*
* we have a group and potentially legal additions
*/
/* commit to configuration if not a dryrun */
/* properties changed, so update all shares */
}
}
return (ret);
}
/*
* sa_unset(flags, argc, argv)
*
* implements the unset subcommand. Parsing done here and then basic
* or space versions of the real code are called.
*/
int
{
char *groupname;
int verbose = 0;
int dryrun = 0;
int c;
int auth;
switch (c) {
case 'v':
verbose++;
break;
case 'n':
dryrun++;
break;
case 'P':
if (!sa_valid_protocol(protocol)) {
protocol);
return (SA_INVALID_PROTOCOL);
}
break;
case 'p':
switch (ret) {
case OPT_ADD_SYNTAX:
"property %s\n"),
optarg);
return (SA_SYNTAX_ERR);
case OPT_ADD_PROPERTY:
" with set command: %s\n"),
optarg);
return (SA_SYNTAX_ERR);
default:
break;
}
break;
case 's':
break;
case 'S':
break;
default:
case 'h':
case '?':
return (SA_OK);
}
}
char *sep = "\t";
sep = ", ";
}
"specified"),
sep);
sep = ", ";
}
sep = ", ";
}
(void) printf("\n");
ret = SA_SYNTAX_ERR;
} else {
/*
* if a group already exists, we can only add a new
* protocol to it and not create a new one or add the
* same protocol again.
*/
else
}
}
return (ret);
}
/*
* sa_enable_group(flags, argc, argv)
*
* Implements the enable subcommand
*/
int
{
int verbose = 0;
int dryrun = 0;
int all = 0;
int c;
char *state;
int auth = 1;
switch (c) {
case 'a':
all = 1;
break;
case 'n':
dryrun++;
break;
case 'P':
if (!sa_valid_protocol(protocol)) {
protocol);
return (SA_INVALID_PROTOCOL);
}
break;
case 'v':
verbose++;
break;
default:
case 'h':
case '?':
return (0);
}
}
} else {
if (!all) {
/* already enabled */
if (verbose)
"enabled\n"),
} else {
if (verbose)
"\"%s\"\n"),
}
} else {
}
optind++;
}
} else {
}
}
}
sa_errorstr(ret));
}
}
return (ret);
}
/*
* disable_group(group, setstate)
*
* disable all the shares in the specified group honoring the setstate
* argument. This is a helper for disable_all_groups in order to
* simplify regular and subgroup (zfs) disabling. Group has already
* been checked for non-NULL.
*/
static int
{
if (ret == SA_NO_SUCH_PATH) {
/*
* this is OK since the path is gone. we can't
* re-share it anyway so no error.
*/
}
}
return (ret);
}
/*
* disable_all_groups(work, setstate)
*
* helper function that disables the shares in the list of groups
* provided. It optionally marks the group as disabled. Used by both
* enable and start subcommands.
*/
static int
{
if (setstate)
char *name;
/* need to get the sub-groups for stopping */
}
} else {
}
/*
* we don't want to "disable" since it won't come
* up after a reboot. The SMF framework should do
* the right thing. On enable we do want to do
* something.
*/
}
}
return (ret);
}
/*
* sa_disable_group(flags, argc, argv)
*
* Implements the disable subcommand
*/
int
{
int verbose = 0;
int dryrun = 0;
int all = 0;
int c;
char *protocol;
char *state;
int auth = 1;
switch (c) {
case 'a':
all = 1;
break;
case 'n':
dryrun++;
break;
case 'P':
if (!sa_valid_protocol(protocol)) {
protocol);
return (SA_INVALID_PROTOCOL);
}
break;
case 'v':
verbose++;
break;
default:
case 'h':
case '?':
return (0);
}
}
} else {
if (!all) {
/* already disabled */
if (verbose)
"already disabled\n"),
} else {
if (verbose)
"\"%s\"\n"),
}
} else {
}
optind++;
}
} else {
}
}
}
sa_errorstr(ret));
}
}
return (ret);
}
/*
* sa_start_group(flags, argc, argv)
*
* Implements the start command.
* This is similar to enable except it doesn't change the state
* of the group(s) and only enables shares if the group is already
* enabled.
*/
int
{
int verbose = 0;
int all = 0;
int c;
int ret = SMF_EXIT_OK;
char *state;
#ifdef lint
#endif
switch (c) {
case 'a':
all = 1;
break;
case 'P':
if (!sa_valid_protocol(protocol)) {
protocol);
return (SA_INVALID_PROTOCOL);
}
break;
case 'v':
verbose++;
break;
default:
case 'h':
case '?':
return (SA_OK);
}
}
} else {
if (!all) {
if (verbose)
"\"%s\"\n"),
} else {
/*
* determine if there are any
* protocols. if there aren't any,
* then there isn't anything to do in
* any case so no error.
*/
ret = SMF_EXIT_OK;
}
}
}
optind++;
}
} else {
}
}
}
return (ret);
}
/*
* sa_stop_group(flags, argc, argv)
*
* Implements the stop command.
* This is similar to disable except it doesn't change the state
* of the group(s) and only disables shares if the group is already
* enabled.
*/
int
{
int verbose = 0;
int all = 0;
int c;
int ret = SMF_EXIT_OK;
char *state;
#ifdef lint
#endif
switch (c) {
case 'a':
all = 1;
break;
case 'P':
if (!sa_valid_protocol(protocol)) {
protocol);
return (SA_INVALID_PROTOCOL);
}
break;
case 'v':
verbose++;
break;
default:
case 'h':
case '?':
return (0);
}
}
} else {
if (!all) {
if (verbose)
"\"%s\"\n"),
} else {
ret = SMF_EXIT_OK;
}
}
optind++;
}
} else {
}
}
}
return (ret);
}
/*
* remove_all_options(share, proto)
*
* Removes all options on a share.
*/
static void
{
(void) sa_destroy_optionset(optionset);
char *type;
/*
* we walk through the list. prevsec keeps the
* previous security so we can delete it without
* destroying the list.
*/
/* remove the previously seen security */
(void) sa_destroy_security(prevsec);
/* set to NULL so we don't try multiple times */
}
/*
* if the security matches the specified protocol, we
* want to remove it. prevsec holds it until either
* the next pass or we fall out of the loop.
*/
}
}
/* in case there is one left */
(void) sa_destroy_security(prevsec);
}
/*
* for legacy support, we need to handle the old syntax. This is what
* we get if sharemgr is called with the name "share" rather than
* sharemgr.
*/
static int
{
int err;
return (-1);
return (0);
}
/*
* check_legacy_cmd(proto, cmd)
*
* executable.
*/
static int
check_legacy_cmd(char *path)
{
int ret = 0;
ret = 1;
}
return (ret);
}
/*
* run_legacy_command(proto, cmd, argv)
*
* we know the command exists, so attempt to execute it with all the
* arguments. This implements full legacy share support for those
* protocols that don't have plugin providers.
*/
static int
{
int ret;
if (ret < 0) {
switch (errno) {
case EACCES:
break;
default:
ret = SA_SYSTEM_ERR;
break;
}
}
return (ret);
}
/*
* out_share(out, group, proto)
*
* Display the share information in the format that the "share"
* command has traditionally used.
*/
static void
{
char resfmt[128];
char *path;
char *type;
char *resource;
char *description;
char *groupname;
char *sharedstate;
int shared = 1;
char *soptions;
}
/* want the sharetab version if it exists */
if (sharedstate == NULL)
shared = 0;
if (shared) {
/* only active shares go here */
path,
soptions : "rw",
}
if (description != NULL)
if (sharedstate != NULL)
}
}
/*
* output_legacy_file(out, proto)
*
* Walk all of the groups for the specified protocol and call
* out_share() to format and write in the format displayed by the
* "share" command with no arguments.
*/
static void
{
char *options;
char *zfs;
/*
* get default options preformated, being careful to
* handle legacy shares differently from new style
* shares. Legacy share have options on the share.
*/
/* got a group, so display it */
}
} else {
}
}
}
int
{
char *protocol = "nfs";
char *description = NULL;
char *groupstatus = NULL;
int persist = SA_SHARE_TRANSIENT;
int argsused = 0;
int c;
int zfs = 0;
int true_legacy = 0;
int curtype = SA_SHARE_TRANSIENT;
char cmd[MAXPATHLEN];
#ifdef lint
#endif
switch (c) {
case 'd':
argsused++;
break;
case 'F':
if (!sa_valid_protocol(protocol)) {
true_legacy++;
} else {
gettext("Invalid protocol specified:"
"%s\n"),
protocol);
return (SA_INVALID_PROTOCOL);
}
}
break;
case 'o':
argsused++;
break;
case 'p':
argsused++;
break;
case 'h':
case '?':
default:
return (SA_OK);
}
}
/* have the info so construct what is needed */
/* display current info in share format */
} else {
char dir[MAXPATHLEN];
/* we are modifying the configuration */
return (SA_LEGACY_ERR);
}
if (true_legacy) {
return (ret);
}
*groupname++ = '\0';
}
ret = SA_BAD_PATH;
else
} else {
}
char *legacygroup = "default";
/*
* the legacy group is always present and zfs groups
* come and go. zfs shares may be in sub-groups and
* the zfs share will already be in that group so it
* isn't an error.
*/
/*
* if the share exists, then make sure it is one we
* want to handle.
*/
} else {
}
/* could be a ZFS path being started */
/* this shouldn't happen */
ret = SA_CONFIG_ERR;
}
}
}
}
} else {
char *type;
/*
* may want to change persist state, but the
* important thing is to change options. We
* need to change them regardless of the
* source.
*/
zfs = 1;
}
}
"persist" : "transient");
}
}
/* have a group to hold this share path */
protocol);
}
if (!zfs) {
/*
* zfs shares never have resource or
* description and we can't store the values
* so don't try.
*/
resource);
}
}
}
} else {
ret = SA_SYSTEM_ERR;
}
}
}
ret = SA_LEGACY_ERR;
}
return (ret);
}
/*
* sa_legacy_unshare(flags, argc, argv)
*
* Implements the original unshare command.
*/
int
{
int persist = SA_SHARE_TRANSIENT;
int argsused = 0;
int c;
int true_legacy = 0;
char cmd[MAXPATHLEN];
#ifdef lint
#endif
switch (c) {
case 'h':
case '?':
break;
case 'F':
if (!sa_valid_protocol(protocol)) {
protocol, "unshare") == 0 &&
check_legacy_cmd(cmd)) {
true_legacy++;
} else {
return (SA_INVALID_PROTOCOL);
}
}
break;
case 'o':
argsused++;
break;
case 'p':
argsused++;
break;
default:
return (SA_OK);
}
}
/* have the info so construct what is needed */
ret = SA_SYNTAX_ERR;
} else {
char dir[MAXPATHLEN];
if (true_legacy) {
return (ret);
}
/*
* Find the path in the internal configuration. If it
* isn't found, attempt to resolve the path via
* realpath() and try again.
*/
} else {
}
}
/*
* Errors are ok and removal should still occur. The
* legacy unshare is more forgiving of errors than the
* remove-share subcommand which may need the force
* flag set for some error conditions. That is, the
* "unshare" command will always unshare if it can
* while "remove-share" might require the force option.
*/
if (persist == SA_SHARE_PERMANENT) {
}
} else {
ret = SA_NOT_SHARED;
}
}
switch (ret) {
default:
ret = SA_LEGACY_ERR;
break;
case SA_SYNTAX_ERR:
break;
case SA_OK:
break;
}
return (ret);
}
/*
* common commands that implement the sub-commands used by all
* protcols. The entries are found via the lookup command
*/
static sa_command_t commands[] = {
};
static char *
{
switch (index) {
case USAGE_ADD_SHARE:
"[-d \"description text\"] -s sharepath group");
break;
case USAGE_CREATE:
break;
case USAGE_DELETE:
break;
case USAGE_DISABLE:
break;
case USAGE_ENABLE:
break;
case USAGE_LIST:
break;
case USAGE_MOVE_SHARE:
break;
case USAGE_REMOVE_SHARE:
break;
case USAGE_SET:
"[-p property=value]* [-s sharepath] group");
break;
case USAGE_SET_SECURITY:
"[-p property=value]* group");
break;
case USAGE_SET_SHARE:
"[-d \"description text\"] -s sharepath group");
break;
case USAGE_SHOW:
break;
case USAGE_SHARE:
"[-d description] [pathname [resourcename]]");
break;
case USAGE_START:
break;
case USAGE_STOP:
break;
case USAGE_UNSET:
"[-p property]* group");
break;
case USAGE_UNSET_SECURITY:
"[-p property]* group");
break;
case USAGE_UNSHARE:
break;
}
return (ret);
}
/*
* sa_lookup(cmd, proto)
*
* Lookup the sub-command. proto isn't currently used, but it may
* eventually provide a way to provide protocol specific sub-commands.
*/
{
int i;
#ifdef lint
#endif
return (&commands[i]);
}
return (NULL);
}
void
sub_command_help(char *proto)
{
int i;
#ifdef lint
#endif
(void) printf("\t%s\n",
}
}