13034Sdougm /*
23034Sdougm * CDDL HEADER START
33034Sdougm *
43034Sdougm * The contents of this file are subject to the terms of the
53034Sdougm * Common Development and Distribution License (the "License").
63034Sdougm * You may not use this file except in compliance with the License.
73034Sdougm *
83034Sdougm * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93034Sdougm * or http://www.opensolaris.org/os/licensing.
103034Sdougm * See the License for the specific language governing permissions
113034Sdougm * and limitations under the License.
123034Sdougm *
133034Sdougm * When distributing Covered Code, include this CDDL HEADER in each
143034Sdougm * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153034Sdougm * If applicable, add the following below this CDDL HEADER, with the
163034Sdougm * fields enclosed by brackets "[]" replaced with your own identifying
173034Sdougm * information: Portions Copyright [yyyy] [name of copyright owner]
183034Sdougm *
193034Sdougm * CDDL HEADER END
203034Sdougm */
213034Sdougm
223034Sdougm /*
2312508Samw@Sun.COM * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
243034Sdougm */
253034Sdougm
263034Sdougm /*
273034Sdougm * Share control API
283034Sdougm */
293034Sdougm #include <stdio.h>
303034Sdougm #include <string.h>
313034Sdougm #include <ctype.h>
323034Sdougm #include <sys/types.h>
333034Sdougm #include <sys/stat.h>
343663Sdougm #include <fcntl.h>
353034Sdougm #include <unistd.h>
363034Sdougm #include <libxml/parser.h>
373034Sdougm #include <libxml/tree.h>
383034Sdougm #include "libshare.h"
393034Sdougm #include "libshare_impl.h"
403034Sdougm #include <libscf.h>
413034Sdougm #include "scfutil.h"
423034Sdougm #include <ctype.h>
433034Sdougm #include <libintl.h>
443910Sdougm #include <thread.h>
453910Sdougm #include <synch.h>
463034Sdougm
473663Sdougm #define DFS_LOCK_FILE "/etc/dfs/fstypes"
484327Sdougm #define SA_STRSIZE 256 /* max string size for names */
493663Sdougm
503034Sdougm /*
515331Samw * internal object type values returned by sa_get_object_type()
525331Samw */
535331Samw #define SA_TYPE_UNKNOWN 0
545331Samw #define SA_TYPE_GROUP 1
555331Samw #define SA_TYPE_SHARE 2
565331Samw #define SA_TYPE_RESOURCE 3
575331Samw #define SA_TYPE_OPTIONSET 4
585331Samw #define SA_TYPE_ALTSPACE 5
595331Samw
605331Samw /*
613034Sdougm * internal data structures
623034Sdougm */
633034Sdougm
643034Sdougm extern struct sa_proto_plugin *sap_proto_list;
653034Sdougm
663034Sdougm /* current SMF/SVC repository handle */
673910Sdougm extern void getlegacyconfig(sa_handle_t, char *, xmlNodePtr *);
683910Sdougm extern int gettransients(sa_handle_impl_t, xmlNodePtr *);
693034Sdougm extern char *sa_fstype(char *);
703034Sdougm extern int sa_is_share(void *);
715331Samw extern int sa_is_resource(void *);
723034Sdougm extern ssize_t scf_max_name_len; /* defined in scfutil during initialization */
733034Sdougm extern int sa_group_is_zfs(sa_group_t);
743034Sdougm extern int sa_path_is_zfs(char *);
753034Sdougm extern int sa_zfs_set_sharenfs(sa_group_t, char *, int);
765331Samw extern int sa_zfs_set_sharesmb(sa_group_t, char *, int);
773910Sdougm extern void update_legacy_config(sa_handle_t);
783034Sdougm extern int issubdir(char *, char *);
794327Sdougm extern int sa_zfs_init(sa_handle_impl_t);
803910Sdougm extern void sa_zfs_fini(sa_handle_impl_t);
813663Sdougm extern void sablocksigs(sigset_t *);
823663Sdougm extern void saunblocksigs(sigset_t *);
835331Samw static sa_group_t sa_get_optionset_parent(sa_optionset_t);
845331Samw static char *get_node_attr(void *, char *);
855951Sdougm extern void sa_update_sharetab_ts(sa_handle_t);
863034Sdougm
873910Sdougm /*
883910Sdougm * Data structures for finding/managing the document root to access
893910Sdougm * handle mapping. The list isn't expected to grow very large so a
903910Sdougm * simple list is acceptable. The purpose is to provide a way to start
913910Sdougm * with a group or share and find the library handle needed for
923910Sdougm * various operations.
933910Sdougm */
943910Sdougm mutex_t sa_global_lock;
953910Sdougm struct doc2handle {
963910Sdougm struct doc2handle *next;
973910Sdougm xmlNodePtr root;
983910Sdougm sa_handle_impl_t handle;
993910Sdougm };
1003910Sdougm
10112508Samw@Sun.COM mutex_t sa_dfstab_lock;
10212508Samw@Sun.COM
1034327Sdougm /* definitions used in a couple of property functions */
1044327Sdougm #define SA_PROP_OP_REMOVE 1
1054327Sdougm #define SA_PROP_OP_ADD 2
1064327Sdougm #define SA_PROP_OP_UPDATE 3
1074327Sdougm
1083910Sdougm static struct doc2handle *sa_global_handles = NULL;
1093034Sdougm
1103034Sdougm /* helper functions */
1113034Sdougm
1123910Sdougm /*
1133910Sdougm * sa_errorstr(err)
1143910Sdougm *
1153910Sdougm * convert an error value to an error string
1163910Sdougm */
1173910Sdougm
1183034Sdougm char *
sa_errorstr(int err)1193034Sdougm sa_errorstr(int err)
1203034Sdougm {
1213034Sdougm static char errstr[32];
1223034Sdougm char *ret = NULL;
1233034Sdougm
1243034Sdougm switch (err) {
1253034Sdougm case SA_OK:
1264327Sdougm ret = dgettext(TEXT_DOMAIN, "ok");
1274327Sdougm break;
1283034Sdougm case SA_NO_SUCH_PATH:
1294327Sdougm ret = dgettext(TEXT_DOMAIN, "path doesn't exist");
1304327Sdougm break;
1313034Sdougm case SA_NO_MEMORY:
1324327Sdougm ret = dgettext(TEXT_DOMAIN, "no memory");
1334327Sdougm break;
1343034Sdougm case SA_DUPLICATE_NAME:
1354327Sdougm ret = dgettext(TEXT_DOMAIN, "name in use");
1364327Sdougm break;
1373034Sdougm case SA_BAD_PATH:
1384327Sdougm ret = dgettext(TEXT_DOMAIN, "bad path");
1394327Sdougm break;
1403034Sdougm case SA_NO_SUCH_GROUP:
1414327Sdougm ret = dgettext(TEXT_DOMAIN, "no such group");
1424327Sdougm break;
1433034Sdougm case SA_CONFIG_ERR:
1444327Sdougm ret = dgettext(TEXT_DOMAIN, "configuration error");
1454327Sdougm break;
1463034Sdougm case SA_SYSTEM_ERR:
1474327Sdougm ret = dgettext(TEXT_DOMAIN, "system error");
1484327Sdougm break;
1493034Sdougm case SA_SYNTAX_ERR:
1504327Sdougm ret = dgettext(TEXT_DOMAIN, "syntax error");
1514327Sdougm break;
1523034Sdougm case SA_NO_PERMISSION:
1534327Sdougm ret = dgettext(TEXT_DOMAIN, "no permission");
1544327Sdougm break;
1553034Sdougm case SA_BUSY:
1564327Sdougm ret = dgettext(TEXT_DOMAIN, "busy");
1574327Sdougm break;
1583034Sdougm case SA_NO_SUCH_PROP:
1594327Sdougm ret = dgettext(TEXT_DOMAIN, "no such property");
1604327Sdougm break;
1613034Sdougm case SA_INVALID_NAME:
1624327Sdougm ret = dgettext(TEXT_DOMAIN, "invalid name");
1634327Sdougm break;
1643034Sdougm case SA_INVALID_PROTOCOL:
1654327Sdougm ret = dgettext(TEXT_DOMAIN, "invalid protocol");
1664327Sdougm break;
1673034Sdougm case SA_NOT_ALLOWED:
1684327Sdougm ret = dgettext(TEXT_DOMAIN, "operation not allowed");
1694327Sdougm break;
1703034Sdougm case SA_BAD_VALUE:
1714327Sdougm ret = dgettext(TEXT_DOMAIN, "bad property value");
1724327Sdougm break;
1733034Sdougm case SA_INVALID_SECURITY:
1744327Sdougm ret = dgettext(TEXT_DOMAIN, "invalid security type");
1754327Sdougm break;
1763034Sdougm case SA_NO_SUCH_SECURITY:
1774327Sdougm ret = dgettext(TEXT_DOMAIN, "security type not found");
1784327Sdougm break;
1793034Sdougm case SA_VALUE_CONFLICT:
1804327Sdougm ret = dgettext(TEXT_DOMAIN, "property value conflict");
1814327Sdougm break;
1823034Sdougm case SA_NOT_IMPLEMENTED:
1834327Sdougm ret = dgettext(TEXT_DOMAIN, "not implemented");
1844327Sdougm break;
1853034Sdougm case SA_INVALID_PATH:
1864327Sdougm ret = dgettext(TEXT_DOMAIN, "invalid path");
1874327Sdougm break;
1883034Sdougm case SA_NOT_SUPPORTED:
1894327Sdougm ret = dgettext(TEXT_DOMAIN, "operation not supported");
1904327Sdougm break;
1913034Sdougm case SA_PROP_SHARE_ONLY:
1924327Sdougm ret = dgettext(TEXT_DOMAIN, "property not valid for group");
1934327Sdougm break;
1943034Sdougm case SA_NOT_SHARED:
1954327Sdougm ret = dgettext(TEXT_DOMAIN, "not shared");
1964327Sdougm break;
1975331Samw case SA_NO_SUCH_RESOURCE:
1985331Samw ret = dgettext(TEXT_DOMAIN, "no such resource");
1995331Samw break;
2005331Samw case SA_RESOURCE_REQUIRED:
2015331Samw ret = dgettext(TEXT_DOMAIN, "resource name required");
2025331Samw break;
2035331Samw case SA_MULTIPLE_ERROR:
2045331Samw ret = dgettext(TEXT_DOMAIN, "errors from multiple protocols");
2055331Samw break;
2065331Samw case SA_PATH_IS_SUBDIR:
2075331Samw ret = dgettext(TEXT_DOMAIN, "path is a subpath of share");
2085331Samw break;
2095331Samw case SA_PATH_IS_PARENTDIR:
2105331Samw ret = dgettext(TEXT_DOMAIN, "path is parent of a share");
2115331Samw break;
2126007Sthurlow case SA_NO_SECTION:
2136007Sthurlow ret = dgettext(TEXT_DOMAIN, "protocol requires a section");
2146007Sthurlow break;
2156007Sthurlow case SA_NO_PROPERTIES:
2166007Sthurlow ret = dgettext(TEXT_DOMAIN, "properties not found");
2176007Sthurlow break;
2186007Sthurlow case SA_NO_SUCH_SECTION:
2196007Sthurlow ret = dgettext(TEXT_DOMAIN, "section not found");
2206007Sthurlow break;
2216007Sthurlow case SA_PASSWORD_ENC:
2226007Sthurlow ret = dgettext(TEXT_DOMAIN, "passwords must be encrypted");
2236007Sthurlow break;
224*12679SPavel.Filipensky@Sun.COM case SA_SHARE_EXISTS:
225*12679SPavel.Filipensky@Sun.COM ret = dgettext(TEXT_DOMAIN, "path or file is already shared");
226*12679SPavel.Filipensky@Sun.COM break;
2273034Sdougm default:
2284327Sdougm (void) snprintf(errstr, sizeof (errstr),
2294327Sdougm dgettext(TEXT_DOMAIN, "unknown %d"), err);
2304327Sdougm ret = errstr;
2313034Sdougm }
2323034Sdougm return (ret);
2333034Sdougm }
2343034Sdougm
2353034Sdougm /*
2363910Sdougm * Document root to active handle mapping functions. These are only
2373910Sdougm * used internally. A mutex is used to prevent access while the list
2383910Sdougm * is changing. In general, the list will be relatively short - one
2393910Sdougm * item per thread that has called sa_init().
2403910Sdougm */
2413910Sdougm
2423910Sdougm sa_handle_impl_t
get_handle_for_root(xmlNodePtr root)2433910Sdougm get_handle_for_root(xmlNodePtr root)
2443910Sdougm {
2453910Sdougm struct doc2handle *item;
2463910Sdougm
2473910Sdougm (void) mutex_lock(&sa_global_lock);
2483910Sdougm for (item = sa_global_handles; item != NULL; item = item->next) {
2494327Sdougm if (item->root == root)
2504327Sdougm break;
2513910Sdougm }
2523910Sdougm (void) mutex_unlock(&sa_global_lock);
2533910Sdougm if (item != NULL)
2544327Sdougm return (item->handle);
2553910Sdougm return (NULL);
2563910Sdougm }
2573910Sdougm
2583910Sdougm static int
add_handle_for_root(xmlNodePtr root,sa_handle_impl_t handle)2593910Sdougm add_handle_for_root(xmlNodePtr root, sa_handle_impl_t handle)
2603910Sdougm {
2613910Sdougm struct doc2handle *item;
2623910Sdougm int ret = SA_NO_MEMORY;
2633910Sdougm
2643910Sdougm item = (struct doc2handle *)calloc(sizeof (struct doc2handle), 1);
2653910Sdougm if (item != NULL) {
2664327Sdougm item->root = root;
2674327Sdougm item->handle = handle;
2684327Sdougm (void) mutex_lock(&sa_global_lock);
2694327Sdougm item->next = sa_global_handles;
2704327Sdougm sa_global_handles = item;
2714327Sdougm (void) mutex_unlock(&sa_global_lock);
2724327Sdougm ret = SA_OK;
2733910Sdougm }
2743910Sdougm return (ret);
2753910Sdougm }
2763910Sdougm
2773910Sdougm /*
2783910Sdougm * remove_handle_for_root(root)
2793910Sdougm *
2803910Sdougm * Walks the list of handles and removes the one for this "root" from
2813910Sdougm * the list. It is up to the caller to free the data.
2823910Sdougm */
2833910Sdougm
2843910Sdougm static void
remove_handle_for_root(xmlNodePtr root)2853910Sdougm remove_handle_for_root(xmlNodePtr root)
2863910Sdougm {
2873910Sdougm struct doc2handle *item, *prev;
2883910Sdougm
2893910Sdougm (void) mutex_lock(&sa_global_lock);
2903910Sdougm for (prev = NULL, item = sa_global_handles; item != NULL;
2914327Sdougm item = item->next) {
2924327Sdougm if (item->root == root) {
2934327Sdougm /* first in the list */
2944327Sdougm if (prev == NULL)
2954327Sdougm sa_global_handles = sa_global_handles->next;
2964327Sdougm else
2974327Sdougm prev->next = item->next;
2984327Sdougm /* Item is out of the list so free the list structure */
2994327Sdougm free(item);
3004327Sdougm break;
3013910Sdougm }
3024327Sdougm prev = item;
3033910Sdougm }
3043910Sdougm (void) mutex_unlock(&sa_global_lock);
3053910Sdougm }
3063910Sdougm
3073910Sdougm /*
3083910Sdougm * sa_find_group_handle(sa_group_t group)
3093910Sdougm *
3103910Sdougm * Find the sa_handle_t for the configuration associated with this
3113910Sdougm * group.
3123910Sdougm */
3133910Sdougm sa_handle_t
sa_find_group_handle(sa_group_t group)3143910Sdougm sa_find_group_handle(sa_group_t group)
3153910Sdougm {
3163910Sdougm xmlNodePtr node = (xmlNodePtr)group;
3173910Sdougm sa_handle_t handle;
3183910Sdougm
3193910Sdougm while (node != NULL) {
3204327Sdougm if (strcmp((char *)(node->name), "sharecfg") == 0) {
3214327Sdougm /* have the root so get the handle */
3224327Sdougm handle = (sa_handle_t)get_handle_for_root(node);
3234327Sdougm return (handle);
3244327Sdougm }
3254327Sdougm node = node->parent;
3263910Sdougm }
3273910Sdougm return (NULL);
3283910Sdougm }
3293910Sdougm
3303910Sdougm /*
3313034Sdougm * set_legacy_timestamp(root, path, timevalue)
3323034Sdougm *
3333034Sdougm * add the current timestamp value to the configuration for use in
3343034Sdougm * determining when to update the legacy files. For SMF, this
3353034Sdougm * property is kept in default/operation/legacy_timestamp
3363034Sdougm */
3373034Sdougm
3383034Sdougm static void
set_legacy_timestamp(xmlNodePtr root,char * path,uint64_t tval)3393034Sdougm set_legacy_timestamp(xmlNodePtr root, char *path, uint64_t tval)
3403034Sdougm {
3413034Sdougm xmlNodePtr node;
3423034Sdougm xmlChar *lpath = NULL;
3433910Sdougm sa_handle_impl_t handle;
3443910Sdougm
3453910Sdougm /* Have to have a handle or else we weren't initialized. */
3463910Sdougm handle = get_handle_for_root(root);
3473910Sdougm if (handle == NULL)
3484327Sdougm return;
3493034Sdougm
3503034Sdougm for (node = root->xmlChildrenNode; node != NULL;
3514327Sdougm node = node->next) {
3524327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"legacy") == 0) {
3534327Sdougm /* a possible legacy node for this path */
3544327Sdougm lpath = xmlGetProp(node, (xmlChar *)"path");
3554327Sdougm if (lpath != NULL &&
3564327Sdougm xmlStrcmp(lpath, (xmlChar *)path) == 0) {
3574327Sdougm xmlFree(lpath);
3584327Sdougm break;
3594327Sdougm }
3604327Sdougm if (lpath != NULL)
3614327Sdougm xmlFree(lpath);
3623034Sdougm }
3633034Sdougm }
3643034Sdougm if (node == NULL) {
3654327Sdougm /* need to create the first legacy timestamp node */
3664327Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"legacy", NULL);
3673034Sdougm }
3683034Sdougm if (node != NULL) {
3694327Sdougm char tstring[32];
3704327Sdougm int ret;
3713034Sdougm
3724327Sdougm (void) snprintf(tstring, sizeof (tstring), "%lld", tval);
3736007Sthurlow (void) xmlSetProp(node, (xmlChar *)"timestamp",
3746007Sthurlow (xmlChar *)tstring);
3756007Sthurlow (void) xmlSetProp(node, (xmlChar *)"path", (xmlChar *)path);
3764327Sdougm /* now commit to SMF */
3774327Sdougm ret = sa_get_instance(handle->scfhandle, "default");
3783034Sdougm if (ret == SA_OK) {
3794327Sdougm ret = sa_start_transaction(handle->scfhandle,
3804327Sdougm "operation");
3814327Sdougm if (ret == SA_OK) {
3824327Sdougm ret = sa_set_property(handle->scfhandle,
3834327Sdougm "legacy-timestamp", tstring);
3844327Sdougm if (ret == SA_OK) {
3854327Sdougm (void) sa_end_transaction(
3865951Sdougm handle->scfhandle, handle);
3874327Sdougm } else {
3884327Sdougm sa_abort_transaction(handle->scfhandle);
3894327Sdougm }
3904327Sdougm }
3913034Sdougm }
3923034Sdougm }
3933034Sdougm }
3943034Sdougm
3953034Sdougm /*
3963034Sdougm * is_shared(share)
3973034Sdougm *
3983034Sdougm * determine if the specified share is currently shared or not.
3993034Sdougm */
4003034Sdougm static int
is_shared(sa_share_t share)4013034Sdougm is_shared(sa_share_t share)
4023034Sdougm {
4033034Sdougm char *shared;
4043034Sdougm int result = 0; /* assume not */
4053034Sdougm
4063034Sdougm shared = sa_get_share_attr(share, "shared");
4073034Sdougm if (shared != NULL) {
4084327Sdougm if (strcmp(shared, "true") == 0)
4094327Sdougm result = 1;
4104327Sdougm sa_free_attr_string(shared);
4113034Sdougm }
4123034Sdougm return (result);
4133034Sdougm }
4143034Sdougm
4153034Sdougm /*
4165331Samw * excluded_protocol(share, proto)
4175331Samw *
4185331Samw * Returns B_TRUE if the specified protocol appears in the "exclude"
4195331Samw * property. This is used to prevent sharing special case shares
4205331Samw * (e.g. subdirs when SMB wants a subdir and NFS doesn't. B_FALSE is
4215331Samw * returned if the protocol isn't in the list.
4225331Samw */
4235331Samw static boolean_t
excluded_protocol(sa_share_t share,char * proto)4245331Samw excluded_protocol(sa_share_t share, char *proto)
4255331Samw {
4265331Samw char *protolist;
4275331Samw char *str;
4285331Samw char *token;
4295331Samw
4305331Samw protolist = sa_get_share_attr(share, "exclude");
4315331Samw if (protolist != NULL) {
4325331Samw str = protolist;
4335331Samw while ((token = strtok(str, ",")) != NULL) {
4345331Samw if (strcmp(token, proto) == 0) {
4355331Samw sa_free_attr_string(protolist);
4365331Samw return (B_TRUE);
4375331Samw }
4385331Samw str = NULL;
4395331Samw }
4405331Samw sa_free_attr_string(protolist);
4415331Samw }
4425331Samw return (B_FALSE);
4435331Samw }
4445331Samw
4455331Samw /*
4463663Sdougm * checksubdirgroup(group, newpath, strictness)
4473348Sdougm *
4483663Sdougm * check all the specified newpath against all the paths in the
4493663Sdougm * group. This is a helper function for checksubdir to make it easier
4503663Sdougm * to also check ZFS subgroups.
4513663Sdougm * The strictness values mean:
4523348Sdougm * SA_CHECK_NORMAL == only check newpath against shares that are active
4533348Sdougm * SA_CHECK_STRICT == check newpath against both active shares and those
4543348Sdougm * stored in the repository
4553034Sdougm */
4563034Sdougm static int
checksubdirgroup(sa_group_t group,char * newpath,int strictness)4573663Sdougm checksubdirgroup(sa_group_t group, char *newpath, int strictness)
4583034Sdougm {
4593034Sdougm sa_share_t share;
4603663Sdougm char *path;
4613663Sdougm int issub = SA_OK;
4625331Samw int subdir;
4635331Samw int parent;
4645331Samw
4655331Samw if (newpath == NULL)
4665331Samw return (SA_INVALID_PATH);
4673034Sdougm
4683663Sdougm for (share = sa_get_share(group, NULL); share != NULL;
4693663Sdougm share = sa_get_next_share(share)) {
4703034Sdougm /*
4713034Sdougm * The original behavior of share never checked
4723034Sdougm * against the permanent configuration
4733034Sdougm * (/etc/dfs/dfstab). PIT has a number of cases where
4743034Sdougm * it depends on this older behavior even though it
4753034Sdougm * could be considered incorrect. We may tighten this
4763034Sdougm * up in the future.
4773034Sdougm */
4784327Sdougm if (strictness == SA_CHECK_NORMAL && !is_shared(share))
4794327Sdougm continue;
4803034Sdougm
4814327Sdougm path = sa_get_share_attr(share, "path");
4823348Sdougm /*
4833348Sdougm * If path is NULL, then a share is in the process of
4843348Sdougm * construction or someone has modified the property
4853663Sdougm * group inappropriately. It should be
4863663Sdougm * ignored. issubdir() comes from the original share
4873663Sdougm * implementation and does the difficult part of
4883663Sdougm * checking subdirectories.
4893348Sdougm */
4904327Sdougm if (path == NULL)
4914327Sdougm continue;
4925331Samw
4935331Samw if (strcmp(path, newpath) == 0) {
4944327Sdougm issub = SA_INVALID_PATH;
4955331Samw } else {
4965331Samw subdir = issubdir(newpath, path);
4975331Samw parent = issubdir(path, newpath);
4985331Samw if (subdir || parent) {
4995331Samw sa_free_attr_string(path);
5005331Samw path = NULL;
5015331Samw return (subdir ?
5025331Samw SA_PATH_IS_SUBDIR : SA_PATH_IS_PARENTDIR);
5035331Samw }
5044327Sdougm }
5053034Sdougm sa_free_attr_string(path);
5063034Sdougm path = NULL;
5073663Sdougm }
5083663Sdougm return (issub);
5093663Sdougm }
5103663Sdougm
5113663Sdougm /*
5123663Sdougm * checksubdir(newpath, strictness)
5133663Sdougm *
5143663Sdougm * checksubdir determines if the specified path (newpath) is a
5153663Sdougm * subdirectory of another share. It calls checksubdirgroup() to do
5163663Sdougm * the complicated work. The strictness parameter determines how
5173663Sdougm * strict a check to make against the path. The strictness values
5183663Sdougm * mean: SA_CHECK_NORMAL == only check newpath against shares that are
5193663Sdougm * active SA_CHECK_STRICT == check newpath against both active shares
5203663Sdougm * and those * stored in the repository
5213663Sdougm */
5223663Sdougm static int
checksubdir(sa_handle_t handle,char * newpath,int strictness)5233910Sdougm checksubdir(sa_handle_t handle, char *newpath, int strictness)
5243663Sdougm {
5253663Sdougm sa_group_t group;
5265331Samw int issub = SA_OK;
5273663Sdougm char *path = NULL;
5283663Sdougm
5295331Samw for (group = sa_get_group(handle, NULL);
5305331Samw group != NULL && issub == SA_OK;
5315331Samw group = sa_get_next_group(group)) {
5324327Sdougm if (sa_group_is_zfs(group)) {
5334327Sdougm sa_group_t subgroup;
5344327Sdougm for (subgroup = sa_get_sub_group(group);
5355331Samw subgroup != NULL && issub == SA_OK;
5364327Sdougm subgroup = sa_get_next_group(subgroup))
5374327Sdougm issub = checksubdirgroup(subgroup, newpath,
5384327Sdougm strictness);
5394327Sdougm } else {
5404327Sdougm issub = checksubdirgroup(group, newpath, strictness);
5414327Sdougm }
5423034Sdougm }
5433034Sdougm if (path != NULL)
5444327Sdougm sa_free_attr_string(path);
5453034Sdougm return (issub);
5463034Sdougm }
5473034Sdougm
5483034Sdougm /*
5493348Sdougm * validpath(path, strictness)
5503034Sdougm * determine if the provided path is valid for a share. It shouldn't
5513034Sdougm * be a sub-dir of an already shared path or the parent directory of a
5523034Sdougm * share path.
5533034Sdougm */
5543034Sdougm static int
validpath(sa_handle_t handle,char * path,int strictness)5553910Sdougm validpath(sa_handle_t handle, char *path, int strictness)
5563034Sdougm {
5573034Sdougm int error = SA_OK;
5583034Sdougm struct stat st;
5593034Sdougm sa_share_t share;
5603034Sdougm char *fstype;
5613034Sdougm
5624327Sdougm if (*path != '/')
5634327Sdougm return (SA_BAD_PATH);
5644327Sdougm
5653034Sdougm if (stat(path, &st) < 0) {
5664327Sdougm error = SA_NO_SUCH_PATH;
5673034Sdougm } else {
5684327Sdougm share = sa_find_share(handle, path);
5694327Sdougm if (share != NULL)
5704327Sdougm error = SA_DUPLICATE_NAME;
5714327Sdougm
5724327Sdougm if (error == SA_OK) {
5734327Sdougm /*
5744327Sdougm * check for special case with file system
5754327Sdougm * that might have restrictions. For now, ZFS
5764327Sdougm * is the only case since it has its own idea
5774327Sdougm * of how to configure shares. We do this
5784327Sdougm * before subdir checking since things like
5794327Sdougm * ZFS will do that for us. This should also
5804327Sdougm * be done via plugin interface.
5814327Sdougm */
5824327Sdougm fstype = sa_fstype(path);
5834327Sdougm if (fstype != NULL && strcmp(fstype, "zfs") == 0) {
5844327Sdougm if (sa_zfs_is_shared(handle, path))
5854327Sdougm error = SA_INVALID_NAME;
5864327Sdougm }
5874327Sdougm if (fstype != NULL)
5884327Sdougm sa_free_fstype(fstype);
5893034Sdougm }
5904327Sdougm if (error == SA_OK)
5914327Sdougm error = checksubdir(handle, path, strictness);
5923034Sdougm }
5933034Sdougm return (error);
5943034Sdougm }
5953034Sdougm
5963034Sdougm /*
5973034Sdougm * check to see if group/share is persistent.
5985331Samw *
5995331Samw * "group" can be either an sa_group_t or an sa_share_t. (void *)
6005331Samw * works since both thse types are also void *.
60112508Samw@Sun.COM * If the share is a ZFS share, mark it as persistent.
6023034Sdougm */
6035331Samw int
sa_is_persistent(void * group)6045331Samw sa_is_persistent(void *group)
6053034Sdougm {
6063034Sdougm char *type;
6073034Sdougm int persist = 1;
60812508Samw@Sun.COM sa_group_t grp;
6093034Sdougm
6105331Samw type = sa_get_group_attr((sa_group_t)group, "type");
61112508Samw@Sun.COM if (type != NULL) {
61212508Samw@Sun.COM if (strcmp(type, "transient") == 0)
61312508Samw@Sun.COM persist = 0;
6144327Sdougm sa_free_attr_string(type);
61512508Samw@Sun.COM }
61612508Samw@Sun.COM
61712508Samw@Sun.COM grp = (sa_is_share(group)) ? sa_get_parent_group(group) : group;
61812508Samw@Sun.COM if (sa_group_is_zfs(grp))
61912508Samw@Sun.COM persist = 1;
62012508Samw@Sun.COM
6213034Sdougm return (persist);
6223034Sdougm }
6233034Sdougm
6243034Sdougm /*
6253034Sdougm * sa_valid_group_name(name)
6263034Sdougm *
6273034Sdougm * check that the "name" contains only valid characters and otherwise
6283034Sdougm * fits the required naming conventions. Valid names must start with
6293034Sdougm * an alphabetic and the remainder may consist of only alphanumeric
6303034Sdougm * plus the '-' and '_' characters. This name limitation comes from
6313034Sdougm * inherent limitations in SMF.
6323034Sdougm */
6333034Sdougm
6343034Sdougm int
sa_valid_group_name(char * name)6353034Sdougm sa_valid_group_name(char *name)
6363034Sdougm {
6373034Sdougm int ret = 1;
6383034Sdougm ssize_t len;
6393034Sdougm
6403034Sdougm if (name != NULL && isalpha(*name)) {
6414327Sdougm char c;
6424327Sdougm len = strlen(name);
6434327Sdougm if (len < (scf_max_name_len - sizeof ("group:"))) {
6444327Sdougm for (c = *name++; c != '\0' && ret != 0; c = *name++) {
6454327Sdougm if (!isalnum(c) && c != '-' && c != '_')
6464327Sdougm ret = 0;
6474327Sdougm }
6484327Sdougm } else {
6493034Sdougm ret = 0;
6503034Sdougm }
6514327Sdougm } else {
6523034Sdougm ret = 0;
6533034Sdougm }
6543034Sdougm return (ret);
6553034Sdougm }
6563034Sdougm
6573034Sdougm
6583034Sdougm /*
6593034Sdougm * is_zfs_group(group)
6603034Sdougm * Determine if the specified group is a ZFS sharenfs group
6613034Sdougm */
6623034Sdougm static int
is_zfs_group(sa_group_t group)6633034Sdougm is_zfs_group(sa_group_t group)
6643034Sdougm {
6653034Sdougm int ret = 0;
6663034Sdougm xmlNodePtr parent;
6673034Sdougm xmlChar *zfs;
6683034Sdougm
6694327Sdougm if (strcmp((char *)((xmlNodePtr)group)->name, "share") == 0)
6704327Sdougm parent = (xmlNodePtr)sa_get_parent_group(group);
6714327Sdougm else
6724327Sdougm parent = (xmlNodePtr)group;
6733034Sdougm zfs = xmlGetProp(parent, (xmlChar *)"zfs");
6743034Sdougm if (zfs != NULL) {
6754327Sdougm xmlFree(zfs);
6764327Sdougm ret = 1;
6773034Sdougm }
6783034Sdougm return (ret);
6793034Sdougm }
6803034Sdougm
6813034Sdougm /*
6825331Samw * sa_get_object_type(object)
6835331Samw *
6845331Samw * This function returns a numeric value representing the object
6855331Samw * type. This allows using simpler checks when doing type specific
6865331Samw * operations.
6875331Samw */
6885331Samw
6895331Samw static int
sa_get_object_type(void * object)6905331Samw sa_get_object_type(void *object)
6915331Samw {
6925331Samw xmlNodePtr node = (xmlNodePtr)object;
6935331Samw int type;
6945331Samw
6955331Samw if (xmlStrcmp(node->name, (xmlChar *)"group") == 0)
6965331Samw type = SA_TYPE_GROUP;
6975331Samw else if (xmlStrcmp(node->name, (xmlChar *)"share") == 0)
6985331Samw type = SA_TYPE_SHARE;
6995331Samw else if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0)
7005331Samw type = SA_TYPE_RESOURCE;
7015331Samw else if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0)
7025331Samw type = SA_TYPE_OPTIONSET;
7035331Samw else if (xmlStrcmp(node->name, (xmlChar *)"security") == 0)
7045331Samw type = SA_TYPE_ALTSPACE;
7055331Samw else
7065331Samw assert(0);
7075331Samw return (type);
7085331Samw }
7095331Samw
7105331Samw /*
7113034Sdougm * sa_optionset_name(optionset, oname, len, id)
7123034Sdougm * return the SMF name for the optionset. If id is not NULL, it
7133034Sdougm * will have the GUID value for a share and should be used
7143034Sdougm * instead of the keyword "optionset" which is used for
7153034Sdougm * groups. If the optionset doesn't have a protocol type
7163034Sdougm * associated with it, "default" is used. This shouldn't happen
7173034Sdougm * at this point but may be desirable in the future if there are
7183034Sdougm * protocol independent properties added. The name is returned in
7193034Sdougm * oname.
7203034Sdougm */
7213034Sdougm
7223034Sdougm static int
sa_optionset_name(sa_optionset_t optionset,char * oname,size_t len,char * id)7233034Sdougm sa_optionset_name(sa_optionset_t optionset, char *oname, size_t len, char *id)
7243034Sdougm {
7253034Sdougm char *proto;
7265331Samw void *parent;
7275331Samw int ptype;
7283034Sdougm
7293034Sdougm if (id == NULL)
7304327Sdougm id = "optionset";
7313034Sdougm
7325331Samw parent = sa_get_optionset_parent(optionset);
7335331Samw if (parent != NULL) {
7345331Samw ptype = sa_get_object_type(parent);
7355331Samw proto = sa_get_optionset_attr(optionset, "type");
7365331Samw if (ptype != SA_TYPE_RESOURCE) {
7375331Samw len = snprintf(oname, len, "%s_%s", id,
7385331Samw proto ? proto : "default");
7395331Samw } else {
7405331Samw char *index;
7415331Samw index = get_node_attr((void *)parent, "id");
74211337SWilliam.Krier@Sun.COM if (index != NULL) {
7435331Samw len = snprintf(oname, len, "%s_%s_%s", id,
7445331Samw proto ? proto : "default", index);
74511337SWilliam.Krier@Sun.COM sa_free_attr_string(index);
74611337SWilliam.Krier@Sun.COM } else {
7475331Samw len = 0;
74811337SWilliam.Krier@Sun.COM }
7495331Samw }
7505331Samw
7515331Samw if (proto != NULL)
7525331Samw sa_free_attr_string(proto);
7535331Samw } else {
7545331Samw len = 0;
7555331Samw }
7563034Sdougm return (len);
7573034Sdougm }
7583034Sdougm
7593034Sdougm /*
7603034Sdougm * sa_security_name(optionset, oname, len, id)
7613034Sdougm *
7623034Sdougm * return the SMF name for the security. If id is not NULL, it will
7633034Sdougm * have the GUID value for a share and should be used instead of the
7643034Sdougm * keyword "optionset" which is used for groups. If the optionset
7653034Sdougm * doesn't have a protocol type associated with it, "default" is
7663034Sdougm * used. This shouldn't happen at this point but may be desirable in
7673034Sdougm * the future if there are protocol independent properties added. The
7683034Sdougm * name is returned in oname. The security type is also encoded into
7693034Sdougm * the name. In the future, this wil *be handled a bit differently.
7703034Sdougm */
7713034Sdougm
7723034Sdougm static int
sa_security_name(sa_security_t security,char * oname,size_t len,char * id)7733034Sdougm sa_security_name(sa_security_t security, char *oname, size_t len, char *id)
7743034Sdougm {
7753034Sdougm char *proto;
7763034Sdougm char *sectype;
7773034Sdougm
7783034Sdougm if (id == NULL)
7794327Sdougm id = "optionset";
7803034Sdougm
7813034Sdougm proto = sa_get_security_attr(security, "type");
7823034Sdougm sectype = sa_get_security_attr(security, "sectype");
7834327Sdougm len = snprintf(oname, len, "%s_%s_%s", id, proto ? proto : "default",
7844327Sdougm sectype ? sectype : "default");
7853034Sdougm if (proto != NULL)
7864327Sdougm sa_free_attr_string(proto);
7873034Sdougm if (sectype != NULL)
7884327Sdougm sa_free_attr_string(sectype);
7893034Sdougm return (len);
7903034Sdougm }
7913034Sdougm
7923034Sdougm /*
7934327Sdougm * verifydefgroupopts(handle)
7944327Sdougm *
7954327Sdougm * Make sure a "default" group exists and has default protocols enabled.
7964327Sdougm */
7974327Sdougm static void
verifydefgroupopts(sa_handle_t handle)7984327Sdougm verifydefgroupopts(sa_handle_t handle)
7994327Sdougm {
8004327Sdougm sa_group_t defgrp;
8014327Sdougm sa_optionset_t opt;
8025331Samw
8034327Sdougm defgrp = sa_get_group(handle, "default");
8044327Sdougm if (defgrp != NULL) {
8054327Sdougm opt = sa_get_optionset(defgrp, NULL);
8064327Sdougm /*
8074327Sdougm * NFS is the default for default group
8084327Sdougm */
8094327Sdougm if (opt == NULL)
8104327Sdougm opt = sa_create_optionset(defgrp, "nfs");
8114327Sdougm }
8124327Sdougm }
8134327Sdougm
8144327Sdougm /*
8153348Sdougm * sa_init(init_service)
8163034Sdougm * Initialize the API
8173034Sdougm * find all the shared objects
8183034Sdougm * init the tables with all objects
8193034Sdougm * read in the current configuration
8203034Sdougm */
8213034Sdougm
8224327Sdougm #define GETPROP(prop) scf_simple_prop_next_astring(prop)
8234327Sdougm #define CHECKTSTAMP(st, tval) stat(SA_LEGACY_DFSTAB, &st) >= 0 && \
8244327Sdougm tval != TSTAMP(st.st_ctim)
8254327Sdougm
8263910Sdougm sa_handle_t
sa_init(int init_service)8273034Sdougm sa_init(int init_service)
8283034Sdougm {
8293034Sdougm struct stat st;
8303034Sdougm int legacy = 0;
8313034Sdougm uint64_t tval = 0;
8323663Sdougm int lockfd;
8333663Sdougm sigset_t old;
8343663Sdougm int updatelegacy = B_FALSE;
8353663Sdougm scf_simple_prop_t *prop;
8363910Sdougm sa_handle_impl_t handle;
8373910Sdougm int err;
8383034Sdougm
8393910Sdougm handle = calloc(sizeof (struct sa_handle_impl), 1);
8403910Sdougm
8413910Sdougm if (handle != NULL) {
8426304Sdougm /*
8436304Sdougm * Get protocol specific structures, but only if this
8446304Sdougm * is the only handle.
8456304Sdougm */
8466304Sdougm (void) mutex_lock(&sa_global_lock);
8476304Sdougm if (sa_global_handles == NULL)
8486304Sdougm (void) proto_plugin_init();
8496304Sdougm (void) mutex_unlock(&sa_global_lock);
8504327Sdougm if (init_service & SA_INIT_SHARE_API) {
8513663Sdougm /*
8524327Sdougm * initialize access into libzfs. We use this
8534327Sdougm * when collecting info about ZFS datasets and
8544327Sdougm * shares.
8553663Sdougm */
8564327Sdougm if (sa_zfs_init(handle) == B_FALSE) {
8574327Sdougm free(handle);
8588474SJose.Borrego@Sun.COM (void) mutex_lock(&sa_global_lock);
8594327Sdougm (void) proto_plugin_fini();
8608474SJose.Borrego@Sun.COM (void) mutex_unlock(&sa_global_lock);
8614327Sdougm return (NULL);
8624327Sdougm }
8633663Sdougm /*
8644327Sdougm * since we want to use SMF, initialize an svc handle
8654327Sdougm * and find out what is there.
8663663Sdougm */
8674327Sdougm handle->scfhandle = sa_scf_init(handle);
8684327Sdougm if (handle->scfhandle != NULL) {
8694327Sdougm /*
8704327Sdougm * Need to lock the extraction of the
8714327Sdougm * configuration if the dfstab file has
8724327Sdougm * changed. Lock everything now and release if
8734327Sdougm * not needed. Use a file that isn't being
8744327Sdougm * manipulated by other parts of the system in
8754327Sdougm * order to not interfere with locking. Using
8764327Sdougm * dfstab doesn't work.
8774327Sdougm */
8784327Sdougm sablocksigs(&old);
8794327Sdougm lockfd = open(DFS_LOCK_FILE, O_RDWR);
8804327Sdougm if (lockfd >= 0) {
8814327Sdougm extern int errno;
8824327Sdougm errno = 0;
8834327Sdougm (void) lockf(lockfd, F_LOCK, 0);
88412508Samw@Sun.COM (void) mutex_lock(&sa_dfstab_lock);
8854327Sdougm /*
8864327Sdougm * Check whether we are going to need
8874327Sdougm * to merge any dfstab changes. This
8884327Sdougm * is done by comparing the value of
8894327Sdougm * legacy-timestamp with the current
8904327Sdougm * st_ctim of the file. If they are
8914327Sdougm * different, an update is needed and
8924327Sdougm * the file must remain locked until
8934327Sdougm * the merge is done in order to
8944327Sdougm * prevent multiple startups from
8954327Sdougm * changing the SMF repository at the
8964327Sdougm * same time. The first to get the
8974327Sdougm * lock will make any changes before
8984327Sdougm * the others can read the repository.
8994327Sdougm */
9004327Sdougm prop = scf_simple_prop_get
9014327Sdougm (handle->scfhandle->handle,
9024327Sdougm (const char *)SA_SVC_FMRI_BASE
9034327Sdougm ":default", "operation",
9044327Sdougm "legacy-timestamp");
9054327Sdougm if (prop != NULL) {
9064327Sdougm char *i64;
9074327Sdougm i64 = GETPROP(prop);
9084327Sdougm if (i64 != NULL)
9094327Sdougm tval = strtoull(i64,
9104327Sdougm NULL, 0);
9114327Sdougm if (CHECKTSTAMP(st, tval))
9124327Sdougm updatelegacy = B_TRUE;
9134327Sdougm scf_simple_prop_free(prop);
9144327Sdougm } else {
9154327Sdougm /*
9164327Sdougm * We haven't set the
9174327Sdougm * timestamp before so do it.
9184327Sdougm */
9194327Sdougm updatelegacy = B_TRUE;
9204327Sdougm }
92112508Samw@Sun.COM if (updatelegacy == B_FALSE) {
92212508Samw@Sun.COM (void) mutex_unlock(
92312508Samw@Sun.COM &sa_dfstab_lock);
92412508Samw@Sun.COM (void) lockf(lockfd, F_ULOCK,
92512508Samw@Sun.COM 0);
92612508Samw@Sun.COM (void) close(lockfd);
92712508Samw@Sun.COM }
92812508Samw@Sun.COM
9294327Sdougm }
9304327Sdougm /*
9314327Sdougm * It is essential that the document tree and
9324327Sdougm * the internal list of roots to handles be
9334327Sdougm * setup before anything that might try to
9344327Sdougm * create a new object is called. The document
9354327Sdougm * tree is the combination of handle->doc and
9364327Sdougm * handle->tree. This allows searches,
9374327Sdougm * etc. when all you have is an object in the
9384327Sdougm * tree.
9394327Sdougm */
9404327Sdougm handle->doc = xmlNewDoc((xmlChar *)"1.0");
9414327Sdougm handle->tree = xmlNewNode(NULL,
9424327Sdougm (xmlChar *)"sharecfg");
9434327Sdougm if (handle->doc != NULL &&
9444327Sdougm handle->tree != NULL) {
9456007Sthurlow (void) xmlDocSetRootElement(handle->doc,
9464327Sdougm handle->tree);
9474327Sdougm err = add_handle_for_root(handle->tree,
9484327Sdougm handle);
9494327Sdougm if (err == SA_OK)
9504327Sdougm err = sa_get_config(
9514327Sdougm handle->scfhandle,
9523973Sdougm handle->tree, handle);
9534327Sdougm } else {
9544327Sdougm if (handle->doc != NULL)
9554327Sdougm xmlFreeDoc(handle->doc);
9564327Sdougm if (handle->tree != NULL)
9574327Sdougm xmlFreeNode(handle->tree);
9584327Sdougm err = SA_NO_MEMORY;
9594327Sdougm }
9603973Sdougm
9614327Sdougm saunblocksigs(&old);
9623910Sdougm
9634327Sdougm if (err != SA_OK) {
9644327Sdougm /*
9654327Sdougm * If we couldn't add the tree handle
9664327Sdougm * to the list, then things are going
9674327Sdougm * to fail badly. Might as well undo
9684327Sdougm * everything now and fail the
9694327Sdougm * sa_init().
9704327Sdougm */
9714327Sdougm sa_fini(handle);
97212508Samw@Sun.COM if (updatelegacy == B_TRUE) {
97312508Samw@Sun.COM (void) mutex_unlock(
97412508Samw@Sun.COM &sa_dfstab_lock);
97512508Samw@Sun.COM (void) lockf(lockfd,
97612508Samw@Sun.COM F_ULOCK, 0);
97712508Samw@Sun.COM (void) close(lockfd);
97812508Samw@Sun.COM }
9794327Sdougm return (NULL);
9804327Sdougm }
9813910Sdougm
9824327Sdougm if (tval == 0) {
9834327Sdougm /*
9844327Sdougm * first time so make sure
9854327Sdougm * default is setup
9864327Sdougm */
9874327Sdougm verifydefgroupopts(handle);
9884327Sdougm }
9893973Sdougm
9904524Sdougm if (updatelegacy == B_TRUE) {
9914524Sdougm sablocksigs(&old);
9924524Sdougm getlegacyconfig((sa_handle_t)handle,
9934524Sdougm SA_LEGACY_DFSTAB, &handle->tree);
9944524Sdougm if (stat(SA_LEGACY_DFSTAB, &st) >= 0)
9954524Sdougm set_legacy_timestamp(
9964524Sdougm handle->tree,
9974524Sdougm SA_LEGACY_DFSTAB,
9984524Sdougm TSTAMP(st.st_ctim));
9994524Sdougm saunblocksigs(&old);
10004524Sdougm /*
10014524Sdougm * Safe to unlock now to allow
10024524Sdougm * others to run
10034524Sdougm */
100412508Samw@Sun.COM (void) mutex_unlock(&sa_dfstab_lock);
10054524Sdougm (void) lockf(lockfd, F_ULOCK, 0);
10064524Sdougm (void) close(lockfd);
10074524Sdougm }
10085951Sdougm /* Get sharetab timestamp */
10095951Sdougm sa_update_sharetab_ts((sa_handle_t)handle);
10105951Sdougm
10115951Sdougm /* Get lastupdate (transaction) timestamp */
10125951Sdougm prop = scf_simple_prop_get(
10135951Sdougm handle->scfhandle->handle,
10145951Sdougm (const char *)SA_SVC_FMRI_BASE ":default",
10155951Sdougm "state", "lastupdate");
10165951Sdougm if (prop != NULL) {
10175951Sdougm char *str;
10185951Sdougm str =
10195951Sdougm scf_simple_prop_next_astring(prop);
10205951Sdougm if (str != NULL)
10215951Sdougm handle->tstrans =
10225951Sdougm strtoull(str, NULL, 0);
10235951Sdougm else
10245951Sdougm handle->tstrans = 0;
10255951Sdougm scf_simple_prop_free(prop);
10265951Sdougm }
10274524Sdougm legacy |= sa_get_zfs_shares(handle, "zfs");
10284524Sdougm legacy |= gettransients(handle, &handle->tree);
10294327Sdougm }
10304327Sdougm }
10313034Sdougm }
10323910Sdougm return ((sa_handle_t)handle);
10333034Sdougm }
10343034Sdougm
10353034Sdougm /*
10363910Sdougm * sa_fini(handle)
10373034Sdougm * Uninitialize the API structures including the configuration
10383218Sdougm * data structures and ZFS related data.
10393034Sdougm */
10403034Sdougm
10413034Sdougm void
sa_fini(sa_handle_t handle)10423910Sdougm sa_fini(sa_handle_t handle)
10433034Sdougm {
10443910Sdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle;
10453910Sdougm
10463910Sdougm if (impl_handle != NULL) {
10473910Sdougm /*
10483910Sdougm * Free the config trees and any other data structures
10493910Sdougm * used in the handle.
10503910Sdougm */
10513910Sdougm if (impl_handle->doc != NULL)
10523910Sdougm xmlFreeDoc(impl_handle->doc);
10533910Sdougm
10543910Sdougm /* Remove and free the entry in the global list. */
10553910Sdougm remove_handle_for_root(impl_handle->tree);
10563910Sdougm
10573910Sdougm /*
10583910Sdougm * If this was the last handle to release, unload the
10596304Sdougm * plugins that were loaded. Use a mutex in case
10606304Sdougm * another thread is reinitializing.
10613910Sdougm */
10626304Sdougm (void) mutex_lock(&sa_global_lock);
10633910Sdougm if (sa_global_handles == NULL)
10644327Sdougm (void) proto_plugin_fini();
10656304Sdougm (void) mutex_unlock(&sa_global_lock);
10663910Sdougm
10677010Sgwr sa_scf_fini(impl_handle->scfhandle);
10687010Sgwr sa_zfs_fini(impl_handle);
10697010Sgwr
10707010Sgwr /* Make sure we free the handle */
10717010Sgwr free(impl_handle);
10727010Sgwr
10733034Sdougm }
10743034Sdougm }
10753034Sdougm
10763034Sdougm /*
10773034Sdougm * sa_get_protocols(char **protocol)
10783034Sdougm * Get array of protocols that are supported
10793034Sdougm * Returns pointer to an allocated and NULL terminated
10803034Sdougm * array of strings. Caller must free.
10813034Sdougm * This really should be determined dynamically.
10823034Sdougm * If there aren't any defined, return -1.
10833034Sdougm * Use free() to return memory.
10843034Sdougm */
10853034Sdougm
10863034Sdougm int
sa_get_protocols(char *** protocols)10873034Sdougm sa_get_protocols(char ***protocols)
10883034Sdougm {
10893034Sdougm int numproto = -1;
10903034Sdougm
10913034Sdougm if (protocols != NULL) {
10924327Sdougm struct sa_proto_plugin *plug;
10934327Sdougm for (numproto = 0, plug = sap_proto_list; plug != NULL;
10944327Sdougm plug = plug->plugin_next) {
10954327Sdougm numproto++;
10964327Sdougm }
10973034Sdougm
10984327Sdougm *protocols = calloc(numproto + 1, sizeof (char *));
10994327Sdougm if (*protocols != NULL) {
11004327Sdougm int ret = 0;
11014327Sdougm for (plug = sap_proto_list; plug != NULL;
11024327Sdougm plug = plug->plugin_next) {
11034327Sdougm /* faking for now */
11044327Sdougm (*protocols)[ret++] =
11054327Sdougm plug->plugin_ops->sa_protocol;
11064327Sdougm }
11074327Sdougm } else {
11084327Sdougm numproto = -1;
11093034Sdougm }
11103034Sdougm }
11113034Sdougm return (numproto);
11123034Sdougm }
11133034Sdougm
11143034Sdougm /*
11153034Sdougm * find_group_by_name(node, group)
11163034Sdougm *
11173034Sdougm * search the XML document subtree specified by node to find the group
11183034Sdougm * specified by group. Searching subtree allows subgroups to be
11193034Sdougm * searched for.
11203034Sdougm */
11213034Sdougm
11223034Sdougm static xmlNodePtr
find_group_by_name(xmlNodePtr node,xmlChar * group)11233034Sdougm find_group_by_name(xmlNodePtr node, xmlChar *group)
11243034Sdougm {
11253034Sdougm xmlChar *name = NULL;
11263034Sdougm
11273034Sdougm for (node = node->xmlChildrenNode; node != NULL;
11283034Sdougm node = node->next) {
11294327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"group") == 0) {
11304327Sdougm /* if no groupname, return the first found */
11314327Sdougm if (group == NULL)
11324327Sdougm break;
11334327Sdougm name = xmlGetProp(node, (xmlChar *)"name");
11344327Sdougm if (name != NULL && xmlStrcmp(name, group) == 0)
11354327Sdougm break;
11364327Sdougm if (name != NULL) {
11374327Sdougm xmlFree(name);
11384327Sdougm name = NULL;
11394327Sdougm }
11403034Sdougm }
11413034Sdougm }
11423034Sdougm if (name != NULL)
11434327Sdougm xmlFree(name);
11443034Sdougm return (node);
11453034Sdougm }
11463034Sdougm
11473034Sdougm /*
11483034Sdougm * sa_get_group(groupname)
11493034Sdougm * Return the "group" specified. If groupname is NULL,
11503034Sdougm * return the first group of the list of groups.
11513034Sdougm */
11523034Sdougm sa_group_t
sa_get_group(sa_handle_t handle,char * groupname)11533910Sdougm sa_get_group(sa_handle_t handle, char *groupname)
11543034Sdougm {
11553034Sdougm xmlNodePtr node = NULL;
11563034Sdougm char *subgroup = NULL;
11573034Sdougm char *group = NULL;
11583910Sdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle;
11593034Sdougm
11603910Sdougm if (impl_handle != NULL && impl_handle->tree != NULL) {
11614327Sdougm if (groupname != NULL) {
11624327Sdougm group = strdup(groupname);
11634345Sdougm if (group != NULL) {
11644345Sdougm subgroup = strchr(group, '/');
11654345Sdougm if (subgroup != NULL)
11664345Sdougm *subgroup++ = '\0';
11674345Sdougm }
11684327Sdougm }
11694345Sdougm /*
11704345Sdougm * We want to find the, possibly, named group. If
11714345Sdougm * group is not NULL, then lookup the name. If it is
11724345Sdougm * NULL, we only do the find if groupname is also
11734345Sdougm * NULL. This allows lookup of the "first" group in
11744345Sdougm * the internal list.
11754345Sdougm */
11764345Sdougm if (group != NULL || groupname == NULL)
11774345Sdougm node = find_group_by_name(impl_handle->tree,
11784345Sdougm (xmlChar *)group);
11794345Sdougm
11804327Sdougm /* if a subgroup, find it before returning */
11814327Sdougm if (subgroup != NULL && node != NULL)
11824327Sdougm node = find_group_by_name(node, (xmlChar *)subgroup);
11833034Sdougm }
11843034Sdougm if (node != NULL && (char *)group != NULL)
11854327Sdougm (void) sa_get_instance(impl_handle->scfhandle, (char *)group);
11863034Sdougm if (group != NULL)
11874327Sdougm free(group);
11883034Sdougm return ((sa_group_t)(node));
11893034Sdougm }
11903034Sdougm
11913034Sdougm /*
11923034Sdougm * sa_get_next_group(group)
11933034Sdougm * Return the "next" group after the specified group from
11943034Sdougm * the internal group list. NULL if there are no more.
11953034Sdougm */
11963034Sdougm sa_group_t
sa_get_next_group(sa_group_t group)11973034Sdougm sa_get_next_group(sa_group_t group)
11983034Sdougm {
11993034Sdougm xmlNodePtr ngroup = NULL;
12003034Sdougm if (group != NULL) {
12014327Sdougm for (ngroup = ((xmlNodePtr)group)->next; ngroup != NULL;
12023034Sdougm ngroup = ngroup->next) {
12034327Sdougm if (xmlStrcmp(ngroup->name, (xmlChar *)"group") == 0)
12044327Sdougm break;
12054327Sdougm }
12063034Sdougm }
12073034Sdougm return ((sa_group_t)ngroup);
12083034Sdougm }
12093034Sdougm
12103034Sdougm /*
12113034Sdougm * sa_get_share(group, sharepath)
12123034Sdougm * Return the share object for the share specified. The share
12133034Sdougm * must be in the specified group. Return NULL if not found.
12143034Sdougm */
12153034Sdougm sa_share_t
sa_get_share(sa_group_t group,char * sharepath)12163034Sdougm sa_get_share(sa_group_t group, char *sharepath)
12173034Sdougm {
12183034Sdougm xmlNodePtr node = NULL;
12193034Sdougm xmlChar *path;
12203034Sdougm
12213034Sdougm /*
12223034Sdougm * For future scalability, this should end up building a cache
12233034Sdougm * since it will get called regularly by the mountd and info
12243034Sdougm * services.
12253034Sdougm */
12263034Sdougm if (group != NULL) {
12274327Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL;
12283034Sdougm node = node->next) {
12294327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) {
12304327Sdougm if (sharepath == NULL) {
12314327Sdougm break;
12324327Sdougm } else {
12334327Sdougm /* is it the correct share? */
12344327Sdougm path = xmlGetProp(node,
12354327Sdougm (xmlChar *)"path");
12364327Sdougm if (path != NULL &&
12374327Sdougm xmlStrcmp(path,
12384327Sdougm (xmlChar *)sharepath) == 0) {
12394327Sdougm xmlFree(path);
12404327Sdougm break;
12414327Sdougm }
12424327Sdougm xmlFree(path);
12434327Sdougm }
12443034Sdougm }
12453034Sdougm }
12463034Sdougm }
12473034Sdougm return ((sa_share_t)node);
12483034Sdougm }
12493034Sdougm
12503034Sdougm /*
12513034Sdougm * sa_get_next_share(share)
12523034Sdougm * Return the next share following the specified share
12533034Sdougm * from the internal list of shares. Returns NULL if there
12543034Sdougm * are no more shares. The list is relative to the same
12553034Sdougm * group.
12563034Sdougm */
12573034Sdougm sa_share_t
sa_get_next_share(sa_share_t share)12583034Sdougm sa_get_next_share(sa_share_t share)
12593034Sdougm {
12603034Sdougm xmlNodePtr node = NULL;
12613034Sdougm
12623034Sdougm if (share != NULL) {
12634327Sdougm for (node = ((xmlNodePtr)share)->next; node != NULL;
12643034Sdougm node = node->next) {
12654327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) {
12664327Sdougm break;
12674327Sdougm }
12683034Sdougm }
12693034Sdougm }
12703034Sdougm return ((sa_share_t)node);
12713034Sdougm }
12723034Sdougm
12733034Sdougm /*
12743034Sdougm * _sa_get_child_node(node, type)
12753034Sdougm *
12763034Sdougm * find the child node of the specified node that has "type". This is
12773034Sdougm * used to implement several internal functions.
12783034Sdougm */
12793034Sdougm
12803034Sdougm static xmlNodePtr
_sa_get_child_node(xmlNodePtr node,xmlChar * type)12813034Sdougm _sa_get_child_node(xmlNodePtr node, xmlChar *type)
12823034Sdougm {
12833034Sdougm xmlNodePtr child;
12843034Sdougm for (child = node->xmlChildrenNode; child != NULL;
12853034Sdougm child = child->next)
12864327Sdougm if (xmlStrcmp(child->name, type) == 0)
12874327Sdougm return (child);
12883034Sdougm return ((xmlNodePtr)NULL);
12893034Sdougm }
12903034Sdougm
12913034Sdougm /*
12923034Sdougm * find_share(group, path)
12933034Sdougm *
12943034Sdougm * Search all the shares in the specified group for one that has the
12953034Sdougm * specified path.
12963034Sdougm */
12973034Sdougm
12983034Sdougm static sa_share_t
find_share(sa_group_t group,char * sharepath)12993034Sdougm find_share(sa_group_t group, char *sharepath)
13003034Sdougm {
13013034Sdougm sa_share_t share;
13023034Sdougm char *path;
13033034Sdougm
13043034Sdougm for (share = sa_get_share(group, NULL); share != NULL;
13053034Sdougm share = sa_get_next_share(share)) {
13064327Sdougm path = sa_get_share_attr(share, "path");
13074327Sdougm if (path != NULL && strcmp(path, sharepath) == 0) {
13084327Sdougm sa_free_attr_string(path);
13094327Sdougm break;
13104327Sdougm }
13114327Sdougm if (path != NULL)
13124327Sdougm sa_free_attr_string(path);
13133034Sdougm }
13143034Sdougm return (share);
13153034Sdougm }
13163034Sdougm
13173034Sdougm /*
13183034Sdougm * sa_get_sub_group(group)
13193034Sdougm *
13203034Sdougm * Get the first sub-group of group. The sa_get_next_group() function
13213034Sdougm * can be used to get the rest. This is currently only used for ZFS
13223034Sdougm * sub-groups but could be used to implement a more general mechanism.
13233034Sdougm */
13243034Sdougm
13253034Sdougm sa_group_t
sa_get_sub_group(sa_group_t group)13263034Sdougm sa_get_sub_group(sa_group_t group)
13273034Sdougm {
13283034Sdougm return ((sa_group_t)_sa_get_child_node((xmlNodePtr)group,
13294327Sdougm (xmlChar *)"group"));
13303034Sdougm }
13313034Sdougm
13323034Sdougm /*
13333034Sdougm * sa_find_share(sharepath)
13343034Sdougm * Finds a share regardless of group. In the future, this
13353034Sdougm * function should utilize a cache and hash table of some kind.
13363034Sdougm * The current assumption is that a path will only be shared
13373034Sdougm * once. In the future, this may change as implementation of
13383034Sdougm * resource names comes into being.
13393034Sdougm */
13403034Sdougm sa_share_t
sa_find_share(sa_handle_t handle,char * sharepath)13413910Sdougm sa_find_share(sa_handle_t handle, char *sharepath)
13423034Sdougm {
13433034Sdougm sa_group_t group;
13443034Sdougm sa_group_t zgroup;
13453034Sdougm sa_share_t share = NULL;
13463034Sdougm int done = 0;
13473034Sdougm
13483910Sdougm for (group = sa_get_group(handle, NULL); group != NULL && !done;
13494327Sdougm group = sa_get_next_group(group)) {
13504327Sdougm if (is_zfs_group(group)) {
13514327Sdougm for (zgroup =
13524327Sdougm (sa_group_t)_sa_get_child_node((xmlNodePtr)group,
13534327Sdougm (xmlChar *)"group");
13544327Sdougm zgroup != NULL;
13554327Sdougm zgroup = sa_get_next_group(zgroup)) {
13564327Sdougm share = find_share(zgroup, sharepath);
13574327Sdougm if (share != NULL)
13584327Sdougm break;
13594327Sdougm }
13604327Sdougm } else {
13614327Sdougm share = find_share(group, sharepath);
13624327Sdougm }
13634327Sdougm if (share != NULL)
13643034Sdougm break;
13653034Sdougm }
13663034Sdougm return (share);
13673034Sdougm }
13683034Sdougm
13693034Sdougm /*
13703348Sdougm * sa_check_path(group, path, strictness)
13713034Sdougm *
13725331Samw * Check that path is a valid path relative to the group. Currently,
13733034Sdougm * we are ignoring the group and checking only the NFS rules. Later,
13743034Sdougm * we may want to use the group to then check against the protocols
13753348Sdougm * enabled on the group. The strictness values mean:
13763348Sdougm * SA_CHECK_NORMAL == only check newpath against shares that are active
13773348Sdougm * SA_CHECK_STRICT == check newpath against both active shares and those
13783348Sdougm * stored in the repository
13793034Sdougm */
13803034Sdougm
13813034Sdougm int
sa_check_path(sa_group_t group,char * path,int strictness)13823348Sdougm sa_check_path(sa_group_t group, char *path, int strictness)
13833034Sdougm {
13843910Sdougm sa_handle_t handle;
13853910Sdougm
13863910Sdougm handle = sa_find_group_handle(group);
138711963SAfshin.Ardakani@Sun.COM if (handle == NULL)
138811963SAfshin.Ardakani@Sun.COM return (SA_BAD_PATH);
138911963SAfshin.Ardakani@Sun.COM
13903910Sdougm return (validpath(handle, path, strictness));
13913034Sdougm }
13923034Sdougm
13933034Sdougm /*
13945331Samw * mark_excluded_protos(group, share, flags)
13953034Sdougm *
13965331Samw * Walk through all the protocols enabled for the group and check to
13975331Samw * see if the share has any of them should be in the exclude list
13985331Samw * based on the featureset of the protocol. If there are any, add the
13995331Samw * "exclude" property to the share.
14005331Samw */
14015331Samw static void
mark_excluded_protos(sa_group_t group,xmlNodePtr share,uint64_t flags)14025331Samw mark_excluded_protos(sa_group_t group, xmlNodePtr share, uint64_t flags)
14035331Samw {
14045331Samw sa_optionset_t optionset;
14055331Samw char exclude_list[SA_STRSIZE];
14065331Samw char *sep = "";
14075331Samw
14085331Samw exclude_list[0] = '\0';
14095331Samw for (optionset = sa_get_optionset(group, NULL);
14105331Samw optionset != NULL;
14115331Samw optionset = sa_get_next_optionset(optionset)) {
14125331Samw char *value;
14135331Samw uint64_t features;
14145331Samw value = sa_get_optionset_attr(optionset, "type");
14155331Samw if (value == NULL)
14165331Samw continue;
14175331Samw features = sa_proto_get_featureset(value);
14185331Samw if (!(features & flags)) {
14195331Samw (void) strlcat(exclude_list, sep,
14205331Samw sizeof (exclude_list));
14215331Samw (void) strlcat(exclude_list, value,
14225331Samw sizeof (exclude_list));
14235331Samw sep = ",";
14245331Samw }
142511337SWilliam.Krier@Sun.COM sa_free_attr_string(value);
14265331Samw }
14275331Samw if (exclude_list[0] != '\0')
14286007Sthurlow (void) xmlSetProp(share, (xmlChar *)"exclude",
14295331Samw (xmlChar *)exclude_list);
14305331Samw }
14315331Samw
14325331Samw /*
14335331Samw * get_all_features(group)
14345331Samw *
14355331Samw * Walk through all the protocols on the group and collect all
14365331Samw * possible enabled features. This is the OR of all the featuresets.
14375331Samw */
14385331Samw static uint64_t
get_all_features(sa_group_t group)14395331Samw get_all_features(sa_group_t group)
14405331Samw {
14415331Samw sa_optionset_t optionset;
14425331Samw uint64_t features = 0;
14435331Samw
14445331Samw for (optionset = sa_get_optionset(group, NULL);
14455331Samw optionset != NULL;
14465331Samw optionset = sa_get_next_optionset(optionset)) {
14475331Samw char *value;
14485331Samw value = sa_get_optionset_attr(optionset, "type");
14495331Samw if (value == NULL)
14505331Samw continue;
14515331Samw features |= sa_proto_get_featureset(value);
14525331Samw sa_free_attr_string(value);
14535331Samw }
14545331Samw return (features);
14555331Samw }
14565331Samw
14575331Samw
14585331Samw /*
14595331Samw * _sa_add_share(group, sharepath, persist, *error, flags)
14605331Samw *
14615331Samw * Common code for all types of add_share. sa_add_share() is the
14623034Sdougm * public API, we also need to be able to do this when parsing legacy
14633034Sdougm * files and construction of the internal configuration while
14645331Samw * extracting config info from SMF. "flags" indicates if some
14655331Samw * protocols need relaxed rules while other don't. These values are
14665331Samw * the featureset values defined in libshare.h.
14673034Sdougm */
14683034Sdougm
14693034Sdougm sa_share_t
_sa_add_share(sa_group_t group,char * sharepath,int persist,int * error,uint64_t flags)14705331Samw _sa_add_share(sa_group_t group, char *sharepath, int persist, int *error,
14715331Samw uint64_t flags)
14723034Sdougm {
14733034Sdougm xmlNodePtr node = NULL;
14743034Sdougm int err;
14753034Sdougm
14763034Sdougm err = SA_OK; /* assume success */
14773034Sdougm
14784327Sdougm node = xmlNewChild((xmlNodePtr)group, NULL, (xmlChar *)"share", NULL);
14795331Samw if (node == NULL) {
14805331Samw if (error != NULL)
14815331Samw *error = SA_NO_MEMORY;
14825331Samw return (node);
14835331Samw }
14845331Samw
14856007Sthurlow (void) xmlSetProp(node, (xmlChar *)"path", (xmlChar *)sharepath);
14866007Sthurlow (void) xmlSetProp(node, (xmlChar *)"type",
14875331Samw persist ? (xmlChar *)"persist" : (xmlChar *)"transient");
14885331Samw if (flags != 0)
14895331Samw mark_excluded_protos(group, node, flags);
14905331Samw if (persist != SA_SHARE_TRANSIENT) {
14915331Samw /*
14925331Samw * persistent shares come in two flavors: SMF and
14935331Samw * ZFS. Sort this one out based on target group and
14945331Samw * path type. Both NFS and SMB are supported. First,
14955331Samw * check to see if the protocol is enabled on the
14965331Samw * subgroup and then setup the share appropriately.
14975331Samw */
14985331Samw if (sa_group_is_zfs(group) &&
14995331Samw sa_path_is_zfs(sharepath)) {
15005331Samw if (sa_get_optionset(group, "nfs") != NULL)
15014327Sdougm err = sa_zfs_set_sharenfs(group, sharepath, 1);
15025331Samw else if (sa_get_optionset(group, "smb") != NULL)
15035331Samw err = sa_zfs_set_sharesmb(group, sharepath, 1);
15045331Samw } else {
15055331Samw sa_handle_impl_t impl_handle;
15065331Samw impl_handle =
15075331Samw (sa_handle_impl_t)sa_find_group_handle(group);
15085331Samw if (impl_handle != NULL) {
15095331Samw err = sa_commit_share(impl_handle->scfhandle,
15105331Samw group, (sa_share_t)node);
15114327Sdougm } else {
15125331Samw err = SA_SYSTEM_ERR;
15134327Sdougm }
15143034Sdougm }
15153034Sdougm }
15165331Samw if (err == SA_NO_PERMISSION && persist & SA_SHARE_PARSER)
15175331Samw /* called by the dfstab parser so could be a show */
15185331Samw err = SA_OK;
15195331Samw
15205331Samw if (err != SA_OK) {
15215331Samw /*
15225331Samw * we couldn't commit to the repository so undo
15235331Samw * our internal state to reflect reality.
15245331Samw */
15255331Samw xmlUnlinkNode(node);
15265331Samw xmlFreeNode(node);
15275331Samw node = NULL;
15285331Samw }
15295331Samw
15303034Sdougm if (error != NULL)
15314327Sdougm *error = err;
15325331Samw
15333034Sdougm return (node);
15343034Sdougm }
15353034Sdougm
15363034Sdougm /*
15373034Sdougm * sa_add_share(group, sharepath, persist, *error)
15383034Sdougm *
15393034Sdougm * Add a new share object to the specified group. The share will
15403034Sdougm * have the specified sharepath and will only be constructed if
15413034Sdougm * it is a valid path to be shared. NULL is returned on error
15423034Sdougm * and a detailed error value will be returned via the error
15433034Sdougm * pointer.
15443034Sdougm */
15453034Sdougm sa_share_t
sa_add_share(sa_group_t group,char * sharepath,int persist,int * error)15463034Sdougm sa_add_share(sa_group_t group, char *sharepath, int persist, int *error)
15473034Sdougm {
15483034Sdougm xmlNodePtr node = NULL;
15493348Sdougm int strictness = SA_CHECK_NORMAL;
15503910Sdougm sa_handle_t handle;
15515331Samw uint64_t special = 0;
15525331Samw uint64_t features;
15533348Sdougm
15543348Sdougm /*
15553348Sdougm * If the share is to be permanent, use strict checking so a
15563348Sdougm * bad config doesn't get created. Transient shares only need
15573348Sdougm * to check against the currently active
15583348Sdougm * shares. SA_SHARE_PARSER is a modifier used internally to
15593348Sdougm * indicate that we are being called by the dfstab parser and
15603348Sdougm * that we need strict checking in all cases. Normally persist
15613348Sdougm * is in integer value but SA_SHARE_PARSER may be or'd into
15623348Sdougm * it as an override.
15633348Sdougm */
15643348Sdougm if (persist & SA_SHARE_PARSER || persist == SA_SHARE_PERMANENT)
15654327Sdougm strictness = SA_CHECK_STRICT;
15663034Sdougm
15673910Sdougm handle = sa_find_group_handle(group);
15683910Sdougm
15695331Samw /*
15705331Samw * need to determine if the share is valid. The rules are:
15715331Samw * - The path must not already exist
15725331Samw * - The path must not be a subdir or parent dir of an
15735331Samw * existing path unless at least one protocol allows it.
15745331Samw * The sub/parent check is done in sa_check_path().
15755331Samw */
15765331Samw
15775331Samw if (sa_find_share(handle, sharepath) == NULL) {
15785331Samw *error = sa_check_path(group, sharepath, strictness);
15795331Samw features = get_all_features(group);
15805331Samw switch (*error) {
15815331Samw case SA_PATH_IS_SUBDIR:
15825331Samw if (features & SA_FEATURE_ALLOWSUBDIRS)
15835331Samw special |= SA_FEATURE_ALLOWSUBDIRS;
15845331Samw break;
15855331Samw case SA_PATH_IS_PARENTDIR:
15865331Samw if (features & SA_FEATURE_ALLOWPARDIRS)
15875331Samw special |= SA_FEATURE_ALLOWPARDIRS;
15885331Samw break;
15895331Samw }
15905331Samw if (*error == SA_OK || special != SA_FEATURE_NONE)
15915331Samw node = _sa_add_share(group, sharepath, persist,
15925331Samw error, special);
15935331Samw } else {
15945331Samw *error = SA_DUPLICATE_NAME;
15953034Sdougm }
15963034Sdougm
15973034Sdougm return ((sa_share_t)node);
15983034Sdougm }
15993034Sdougm
16003034Sdougm /*
16013034Sdougm * sa_enable_share(share, protocol)
16023034Sdougm * Enable the specified share to the specified protocol.
16033034Sdougm * If protocol is NULL, then all protocols.
16043034Sdougm */
16053034Sdougm int
sa_enable_share(sa_share_t share,char * protocol)16063034Sdougm sa_enable_share(sa_share_t share, char *protocol)
16073034Sdougm {
16083034Sdougm char *sharepath;
16093034Sdougm struct stat st;
16105331Samw int err = SA_OK;
16115331Samw int ret;
16123034Sdougm
16133034Sdougm sharepath = sa_get_share_attr(share, "path");
16145331Samw if (sharepath == NULL)
16155331Samw return (SA_NO_MEMORY);
16163034Sdougm if (stat(sharepath, &st) < 0) {
16174327Sdougm err = SA_NO_SUCH_PATH;
16183034Sdougm } else {
16194327Sdougm /* tell the server about the share */
16204327Sdougm if (protocol != NULL) {
16215331Samw if (excluded_protocol(share, protocol))
16225331Samw goto done;
16235331Samw
16244327Sdougm /* lookup protocol specific handler */
16254327Sdougm err = sa_proto_share(protocol, share);
16264327Sdougm if (err == SA_OK)
16275331Samw (void) sa_set_share_attr(share,
16285331Samw "shared", "true");
16294327Sdougm } else {
16305331Samw /* Tell all protocols about the share */
16315331Samw sa_group_t group;
16325331Samw sa_optionset_t optionset;
16335331Samw
16345331Samw group = sa_get_parent_group(share);
16355331Samw
16365331Samw for (optionset = sa_get_optionset(group, NULL);
16375331Samw optionset != NULL;
16385331Samw optionset = sa_get_next_optionset(optionset)) {
16395331Samw char *proto;
16405331Samw proto = sa_get_optionset_attr(optionset,
16415331Samw "type");
16425331Samw if (proto != NULL) {
16435331Samw if (!excluded_protocol(share, proto)) {
16445331Samw ret = sa_proto_share(proto,
16455331Samw share);
16465331Samw if (ret != SA_OK)
16475331Samw err = ret;
16485331Samw }
16495331Samw sa_free_attr_string(proto);
16505331Samw }
16515331Samw }
16524327Sdougm (void) sa_set_share_attr(share, "shared", "true");
16534327Sdougm }
16543034Sdougm }
16555331Samw done:
16563034Sdougm if (sharepath != NULL)
16574327Sdougm sa_free_attr_string(sharepath);
16583034Sdougm return (err);
16593034Sdougm }
16603034Sdougm
16613034Sdougm /*
16623034Sdougm * sa_disable_share(share, protocol)
16635331Samw * Disable the specified share to the specified protocol. If
16645331Samw * protocol is NULL, then all protocols that are enabled for the
16655331Samw * share should be disabled.
16663034Sdougm */
16673034Sdougm int
sa_disable_share(sa_share_t share,char * protocol)16683034Sdougm sa_disable_share(sa_share_t share, char *protocol)
16693034Sdougm {
16703034Sdougm char *path;
16715331Samw int err = SA_OK;
16723034Sdougm int ret = SA_OK;
16733034Sdougm
16743034Sdougm path = sa_get_share_attr(share, "path");
16753034Sdougm
16763034Sdougm if (protocol != NULL) {
16774543Smarks ret = sa_proto_unshare(share, protocol, path);
16783034Sdougm } else {
16794327Sdougm /* need to do all protocols */
16805331Samw sa_group_t group;
16815331Samw sa_optionset_t optionset;
16825331Samw
16835331Samw group = sa_get_parent_group(share);
16845331Samw
16855331Samw /* Tell all protocols about the share */
16865331Samw for (optionset = sa_get_optionset(group, NULL);
16875331Samw optionset != NULL;
16885331Samw optionset = sa_get_next_optionset(optionset)) {
16895331Samw char *proto;
16905331Samw
16915331Samw proto = sa_get_optionset_attr(optionset, "type");
16925331Samw if (proto != NULL) {
16935331Samw err = sa_proto_unshare(share, proto, path);
16945331Samw if (err != SA_OK)
16955331Samw ret = err;
16965331Samw sa_free_attr_string(proto);
16975331Samw }
16985331Samw }
16993034Sdougm }
17003034Sdougm if (ret == SA_OK)
17013034Sdougm (void) sa_set_share_attr(share, "shared", NULL);
17023034Sdougm if (path != NULL)
17034327Sdougm sa_free_attr_string(path);
17043034Sdougm return (ret);
17053034Sdougm }
17063034Sdougm
17073034Sdougm /*
17083034Sdougm * sa_remove_share(share)
17093034Sdougm *
17103034Sdougm * remove the specified share from its containing group.
17113034Sdougm * Remove from the SMF or ZFS configuration space.
17123034Sdougm */
17133034Sdougm
17143034Sdougm int
sa_remove_share(sa_share_t share)17153034Sdougm sa_remove_share(sa_share_t share)
17163034Sdougm {
17173034Sdougm sa_group_t group;
17183034Sdougm int ret = SA_OK;
17193034Sdougm char *type;
17203034Sdougm int transient = 0;
17213034Sdougm char *groupname;
17223034Sdougm char *zfs;
17233034Sdougm
17243034Sdougm type = sa_get_share_attr(share, "type");
17253034Sdougm group = sa_get_parent_group(share);
17263034Sdougm zfs = sa_get_group_attr(group, "zfs");
17273034Sdougm groupname = sa_get_group_attr(group, "name");
17283034Sdougm if (type != NULL && strcmp(type, "persist") != 0)
17294327Sdougm transient = 1;
17303034Sdougm if (type != NULL)
17314327Sdougm sa_free_attr_string(type);
17323034Sdougm
17333034Sdougm /* remove the node from its group then free the memory */
17343034Sdougm
17353034Sdougm /*
17363034Sdougm * need to test if "busy"
17373034Sdougm */
17383034Sdougm /* only do SMF action if permanent */
17393034Sdougm if (!transient || zfs != NULL) {
17404327Sdougm /* remove from legacy dfstab as well as possible SMF */
17415331Samw ret = sa_delete_legacy(share, NULL);
17424327Sdougm if (ret == SA_OK) {
17434327Sdougm if (!sa_group_is_zfs(group)) {
17444327Sdougm sa_handle_impl_t impl_handle;
17454327Sdougm impl_handle = (sa_handle_impl_t)
17464327Sdougm sa_find_group_handle(group);
17474327Sdougm if (impl_handle != NULL) {
17484327Sdougm ret = sa_delete_share(
17494327Sdougm impl_handle->scfhandle, group,
17504327Sdougm share);
17514327Sdougm } else {
17524327Sdougm ret = SA_SYSTEM_ERR;
17534327Sdougm }
17544327Sdougm } else {
17554327Sdougm char *sharepath = sa_get_share_attr(share,
17564327Sdougm "path");
17574327Sdougm if (sharepath != NULL) {
17584327Sdougm ret = sa_zfs_set_sharenfs(group,
17594327Sdougm sharepath, 0);
17604327Sdougm sa_free_attr_string(sharepath);
17614327Sdougm }
17624327Sdougm }
17633034Sdougm }
17643034Sdougm }
17653034Sdougm if (groupname != NULL)
17664327Sdougm sa_free_attr_string(groupname);
17673034Sdougm if (zfs != NULL)
17684327Sdougm sa_free_attr_string(zfs);
17693034Sdougm
17703034Sdougm xmlUnlinkNode((xmlNodePtr)share);
17713034Sdougm xmlFreeNode((xmlNodePtr)share);
17723034Sdougm return (ret);
17733034Sdougm }
17743034Sdougm
17753034Sdougm /*
17763034Sdougm * sa_move_share(group, share)
17773034Sdougm *
17783034Sdougm * move the specified share to the specified group. Update SMF
17793034Sdougm * appropriately.
17803034Sdougm */
17813034Sdougm
17823034Sdougm int
sa_move_share(sa_group_t group,sa_share_t share)17833034Sdougm sa_move_share(sa_group_t group, sa_share_t share)
17843034Sdougm {
17853034Sdougm sa_group_t oldgroup;
17863034Sdougm int ret = SA_OK;
17873034Sdougm
17883034Sdougm /* remove the node from its group then free the memory */
17893034Sdougm
17903034Sdougm oldgroup = sa_get_parent_group(share);
17913034Sdougm if (oldgroup != group) {
17924327Sdougm sa_handle_impl_t impl_handle;
17934327Sdougm xmlUnlinkNode((xmlNodePtr)share);
17943034Sdougm /*
17954327Sdougm * now that the share isn't in its old group, add to
17964327Sdougm * the new one
17973034Sdougm */
17986007Sthurlow (void) xmlAddChild((xmlNodePtr)group, (xmlNodePtr)share);
17994327Sdougm /* need to deal with SMF */
18004327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
18014327Sdougm if (impl_handle != NULL) {
18024327Sdougm /*
18034327Sdougm * need to remove from old group first and then add to
18044327Sdougm * new group. Ideally, we would do the other order but
18054327Sdougm * need to avoid having the share in two groups at the
18064327Sdougm * same time.
18074327Sdougm */
18084327Sdougm ret = sa_delete_share(impl_handle->scfhandle, oldgroup,
18094327Sdougm share);
18104327Sdougm if (ret == SA_OK)
18114327Sdougm ret = sa_commit_share(impl_handle->scfhandle,
18124327Sdougm group, share);
18134327Sdougm } else {
18144327Sdougm ret = SA_SYSTEM_ERR;
18154327Sdougm }
18163034Sdougm }
18173034Sdougm return (ret);
18183034Sdougm }
18193034Sdougm
18203034Sdougm /*
18213034Sdougm * sa_get_parent_group(share)
18223034Sdougm *
18235331Samw * Return the containing group for the share. If a group was actually
18243034Sdougm * passed in, we don't want a parent so return NULL.
18253034Sdougm */
18263034Sdougm
18273034Sdougm sa_group_t
sa_get_parent_group(sa_share_t share)18283034Sdougm sa_get_parent_group(sa_share_t share)
18293034Sdougm {
18303034Sdougm xmlNodePtr node = NULL;
18313034Sdougm if (share != NULL) {
18324327Sdougm node = ((xmlNodePtr)share)->parent;
18333034Sdougm /*
18343034Sdougm * make sure parent is a group and not sharecfg since
18353034Sdougm * we may be cheating and passing in a group.
18363034Sdougm * Eventually, groups of groups might come into being.
18373034Sdougm */
18384327Sdougm if (node == NULL ||
18394327Sdougm xmlStrcmp(node->name, (xmlChar *)"sharecfg") == 0)
18404327Sdougm node = NULL;
18413034Sdougm }
18423034Sdougm return ((sa_group_t)node);
18433034Sdougm }
18443034Sdougm
18453034Sdougm /*
18463910Sdougm * _sa_create_group(impl_handle, groupname)
18473034Sdougm *
18483034Sdougm * Create a group in the document. The caller will need to deal with
18493034Sdougm * configuration store and activation.
18503034Sdougm */
18513034Sdougm
18523034Sdougm sa_group_t
_sa_create_group(sa_handle_impl_t impl_handle,char * groupname)18533910Sdougm _sa_create_group(sa_handle_impl_t impl_handle, char *groupname)
18543034Sdougm {
18553034Sdougm xmlNodePtr node = NULL;
18563034Sdougm
18573034Sdougm if (sa_valid_group_name(groupname)) {
18584327Sdougm node = xmlNewChild(impl_handle->tree, NULL, (xmlChar *)"group",
18594327Sdougm NULL);
18604327Sdougm if (node != NULL) {
18616007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name",
18624327Sdougm (xmlChar *)groupname);
18636007Sthurlow (void) xmlSetProp(node, (xmlChar *)"state",
18644327Sdougm (xmlChar *)"enabled");
18654327Sdougm }
18663034Sdougm }
18673034Sdougm return ((sa_group_t)node);
18683034Sdougm }
18693034Sdougm
18703034Sdougm /*
18713034Sdougm * _sa_create_zfs_group(group, groupname)
18723034Sdougm *
18733034Sdougm * Create a ZFS subgroup under the specified group. This may
18743034Sdougm * eventually form the basis of general sub-groups, but is currently
18753034Sdougm * restricted to ZFS.
18763034Sdougm */
18773034Sdougm sa_group_t
_sa_create_zfs_group(sa_group_t group,char * groupname)18783034Sdougm _sa_create_zfs_group(sa_group_t group, char *groupname)
18793034Sdougm {
18803034Sdougm xmlNodePtr node = NULL;
18813034Sdougm
18824327Sdougm node = xmlNewChild((xmlNodePtr)group, NULL, (xmlChar *)"group", NULL);
18833034Sdougm if (node != NULL) {
18846007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name",
18856007Sthurlow (xmlChar *)groupname);
18866007Sthurlow (void) xmlSetProp(node, (xmlChar *)"state",
18876007Sthurlow (xmlChar *)"enabled");
18883034Sdougm }
18893034Sdougm
18903034Sdougm return ((sa_group_t)node);
18913034Sdougm }
18923034Sdougm
18933034Sdougm /*
18943034Sdougm * sa_create_group(groupname, *error)
18953034Sdougm *
18963034Sdougm * Create a new group with groupname. Need to validate that it is a
18973034Sdougm * legal name for SMF and the construct the SMF service instance of
18983034Sdougm * svc:/network/shares/group to implement the group. All necessary
18993034Sdougm * operational properties must be added to the group at this point
19003034Sdougm * (via the SMF transaction model).
19013034Sdougm */
19023034Sdougm sa_group_t
sa_create_group(sa_handle_t handle,char * groupname,int * error)19033910Sdougm sa_create_group(sa_handle_t handle, char *groupname, int *error)
19043034Sdougm {
19053034Sdougm xmlNodePtr node = NULL;
19063034Sdougm sa_group_t group;
19073034Sdougm int ret;
19084327Sdougm char rbacstr[SA_STRSIZE];
19093910Sdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle;
19103034Sdougm
19113034Sdougm ret = SA_OK;
19123034Sdougm
19133910Sdougm if (impl_handle == NULL || impl_handle->scfhandle == NULL) {
19144327Sdougm ret = SA_SYSTEM_ERR;
19154327Sdougm goto err;
19163034Sdougm }
19173034Sdougm
19183910Sdougm group = sa_get_group(handle, groupname);
19193034Sdougm if (group != NULL) {
19204327Sdougm ret = SA_DUPLICATE_NAME;
19213034Sdougm } else {
19224327Sdougm if (sa_valid_group_name(groupname)) {
19234327Sdougm node = xmlNewChild(impl_handle->tree, NULL,
19244327Sdougm (xmlChar *)"group", NULL);
19254327Sdougm if (node != NULL) {
19266007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name",
19274327Sdougm (xmlChar *)groupname);
19284327Sdougm /* default to the group being enabled */
19296007Sthurlow (void) xmlSetProp(node, (xmlChar *)"state",
19304327Sdougm (xmlChar *)"enabled");
19314327Sdougm ret = sa_create_instance(impl_handle->scfhandle,
19324327Sdougm groupname);
19334327Sdougm if (ret == SA_OK) {
19344327Sdougm ret = sa_start_transaction(
19354327Sdougm impl_handle->scfhandle,
19364327Sdougm "operation");
19374327Sdougm }
19384327Sdougm if (ret == SA_OK) {
19394327Sdougm ret = sa_set_property(
19404327Sdougm impl_handle->scfhandle,
19414327Sdougm "state", "enabled");
19424327Sdougm if (ret == SA_OK) {
19434327Sdougm ret = sa_end_transaction(
19445951Sdougm impl_handle->scfhandle,
19455951Sdougm impl_handle);
19464327Sdougm } else {
19474327Sdougm sa_abort_transaction(
19484327Sdougm impl_handle->scfhandle);
19494327Sdougm }
19504327Sdougm }
19514327Sdougm if (ret == SA_OK) {
19524327Sdougm /* initialize the RBAC strings */
19534327Sdougm ret = sa_start_transaction(
19544327Sdougm impl_handle->scfhandle,
19554327Sdougm "general");
19564327Sdougm if (ret == SA_OK) {
19574327Sdougm (void) snprintf(rbacstr,
19584327Sdougm sizeof (rbacstr), "%s.%s",
19594327Sdougm SA_RBAC_MANAGE, groupname);
19604327Sdougm ret = sa_set_property(
19614327Sdougm impl_handle->scfhandle,
19623034Sdougm "action_authorization",
19633034Sdougm rbacstr);
19644327Sdougm }
19654327Sdougm if (ret == SA_OK) {
19664327Sdougm (void) snprintf(rbacstr,
19674327Sdougm sizeof (rbacstr), "%s.%s",
19684327Sdougm SA_RBAC_VALUE, groupname);
19694327Sdougm ret = sa_set_property(
19704327Sdougm impl_handle->scfhandle,
19713034Sdougm "value_authorization",
19723034Sdougm rbacstr);
19734327Sdougm }
19744327Sdougm if (ret == SA_OK) {
19754327Sdougm ret = sa_end_transaction(
19765951Sdougm impl_handle->scfhandle,
19775951Sdougm impl_handle);
19784327Sdougm } else {
19794327Sdougm sa_abort_transaction(
19804327Sdougm impl_handle->scfhandle);
19814327Sdougm }
19824327Sdougm }
19834327Sdougm if (ret != SA_OK) {
19844327Sdougm /*
19854327Sdougm * Couldn't commit the group
19864327Sdougm * so we need to undo
19874327Sdougm * internally.
19884327Sdougm */
19894327Sdougm xmlUnlinkNode(node);
19904327Sdougm xmlFreeNode(node);
19914327Sdougm node = NULL;
19924327Sdougm }
19933034Sdougm } else {
19944327Sdougm ret = SA_NO_MEMORY;
19953034Sdougm }
19963034Sdougm } else {
19974327Sdougm ret = SA_INVALID_NAME;
19983034Sdougm }
19993034Sdougm }
20003034Sdougm err:
20013034Sdougm if (error != NULL)
20024327Sdougm *error = ret;
20033034Sdougm return ((sa_group_t)node);
20043034Sdougm }
20053034Sdougm
20063034Sdougm /*
20073034Sdougm * sa_remove_group(group)
20083034Sdougm *
20093034Sdougm * Remove the specified group. This deletes from the SMF repository.
20103034Sdougm * All property groups and properties are removed.
20113034Sdougm */
20123034Sdougm
20133034Sdougm int
sa_remove_group(sa_group_t group)20143034Sdougm sa_remove_group(sa_group_t group)
20153034Sdougm {
20163034Sdougm char *name;
20173034Sdougm int ret = SA_OK;
20183910Sdougm sa_handle_impl_t impl_handle;
20193034Sdougm
20203910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
20213910Sdougm if (impl_handle != NULL) {
20224327Sdougm name = sa_get_group_attr(group, "name");
20234327Sdougm if (name != NULL) {
20244327Sdougm ret = sa_delete_instance(impl_handle->scfhandle, name);
20254327Sdougm sa_free_attr_string(name);
20264327Sdougm }
20274327Sdougm xmlUnlinkNode((xmlNodePtr)group); /* make sure unlinked */
20284327Sdougm xmlFreeNode((xmlNodePtr)group); /* now it is gone */
20293910Sdougm } else {
20304327Sdougm ret = SA_SYSTEM_ERR;
20313034Sdougm }
20323034Sdougm return (ret);
20333034Sdougm }
20343034Sdougm
20353034Sdougm /*
20363034Sdougm * sa_update_config()
20373034Sdougm *
20383034Sdougm * Used to update legacy files that need to be updated in bulk
20393034Sdougm * Currently, this is a placeholder and will go away in a future
20403034Sdougm * release.
20413034Sdougm */
20423034Sdougm
20433034Sdougm int
sa_update_config(sa_handle_t handle)20443910Sdougm sa_update_config(sa_handle_t handle)
20453034Sdougm {
20463034Sdougm /*
20473034Sdougm * do legacy files first so we can tell when they change.
20483034Sdougm * This will go away when we start updating individual records
20493034Sdougm * rather than the whole file.
20503034Sdougm */
20513910Sdougm update_legacy_config(handle);
20523034Sdougm return (SA_OK);
20533034Sdougm }
20543034Sdougm
20553034Sdougm /*
20563034Sdougm * get_node_attr(node, tag)
20573034Sdougm *
20585331Samw * Get the specified tag(attribute) if it exists on the node. This is
20593034Sdougm * used internally by a number of attribute oriented functions.
20603034Sdougm */
20613034Sdougm
20623034Sdougm static char *
get_node_attr(void * nodehdl,char * tag)20633034Sdougm get_node_attr(void *nodehdl, char *tag)
20643034Sdougm {
20653034Sdougm xmlNodePtr node = (xmlNodePtr)nodehdl;
20663034Sdougm xmlChar *name = NULL;
20673034Sdougm
20684327Sdougm if (node != NULL)
20693034Sdougm name = xmlGetProp(node, (xmlChar *)tag);
20703034Sdougm return ((char *)name);
20713034Sdougm }
20723034Sdougm
20733034Sdougm /*
207411337SWilliam.Krier@Sun.COM * set_node_attr(node, tag)
20753034Sdougm *
20765331Samw * Set the specified tag(attribute) to the specified value This is
20773034Sdougm * used internally by a number of attribute oriented functions. It
20783034Sdougm * doesn't update the repository, only the internal document state.
20793034Sdougm */
20803034Sdougm
20813034Sdougm void
set_node_attr(void * nodehdl,char * tag,char * value)20823034Sdougm set_node_attr(void *nodehdl, char *tag, char *value)
20833034Sdougm {
20843034Sdougm xmlNodePtr node = (xmlNodePtr)nodehdl;
20853034Sdougm if (node != NULL && tag != NULL) {
20864327Sdougm if (value != NULL)
20876007Sthurlow (void) xmlSetProp(node, (xmlChar *)tag,
20886007Sthurlow (xmlChar *)value);
20894327Sdougm else
20906007Sthurlow (void) xmlUnsetProp(node, (xmlChar *)tag);
20913034Sdougm }
20923034Sdougm }
20933034Sdougm
20943034Sdougm /*
20953034Sdougm * sa_get_group_attr(group, tag)
20963034Sdougm *
20973034Sdougm * Get the specied attribute, if defined, for the group.
20983034Sdougm */
20993034Sdougm
21003034Sdougm char *
sa_get_group_attr(sa_group_t group,char * tag)21013034Sdougm sa_get_group_attr(sa_group_t group, char *tag)
21023034Sdougm {
21033034Sdougm return (get_node_attr((void *)group, tag));
21043034Sdougm }
21053034Sdougm
21063034Sdougm /*
21073034Sdougm * sa_set_group_attr(group, tag, value)
21083034Sdougm *
21093034Sdougm * set the specified tag/attribute on the group using value as its
21103034Sdougm * value.
21113034Sdougm *
21123034Sdougm * This will result in setting the property in the SMF repository as
21133034Sdougm * well as in the internal document.
21143034Sdougm */
21153034Sdougm
21163034Sdougm int
sa_set_group_attr(sa_group_t group,char * tag,char * value)21173034Sdougm sa_set_group_attr(sa_group_t group, char *tag, char *value)
21183034Sdougm {
21193034Sdougm int ret;
21203034Sdougm char *groupname;
21213910Sdougm sa_handle_impl_t impl_handle;
21223034Sdougm
21235331Samw /*
21245331Samw * ZFS group/subgroup doesn't need the handle so shortcut.
21255331Samw */
21265331Samw if (sa_group_is_zfs(group)) {
21275331Samw set_node_attr((void *)group, tag, value);
21285331Samw return (SA_OK);
21295331Samw }
21305331Samw
21313910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
21323910Sdougm if (impl_handle != NULL) {
21334327Sdougm groupname = sa_get_group_attr(group, "name");
21344327Sdougm ret = sa_get_instance(impl_handle->scfhandle, groupname);
21353910Sdougm if (ret == SA_OK) {
21364327Sdougm set_node_attr((void *)group, tag, value);
21374327Sdougm ret = sa_start_transaction(impl_handle->scfhandle,
21384327Sdougm "operation");
21394327Sdougm if (ret == SA_OK) {
21404327Sdougm ret = sa_set_property(impl_handle->scfhandle,
21414327Sdougm tag, value);
21424327Sdougm if (ret == SA_OK)
21435885Sdougm ret = sa_end_transaction(
21445951Sdougm impl_handle->scfhandle,
21455951Sdougm impl_handle);
21464327Sdougm else
21474327Sdougm sa_abort_transaction(
21484327Sdougm impl_handle->scfhandle);
21494327Sdougm }
21505885Sdougm if (ret == SA_SYSTEM_ERR)
21515885Sdougm ret = SA_NO_PERMISSION;
21523034Sdougm }
21534327Sdougm if (groupname != NULL)
21544327Sdougm sa_free_attr_string(groupname);
21553910Sdougm } else {
21564327Sdougm ret = SA_SYSTEM_ERR;
21573034Sdougm }
21583034Sdougm return (ret);
21593034Sdougm }
21603034Sdougm
21613034Sdougm /*
21623034Sdougm * sa_get_share_attr(share, tag)
21633034Sdougm *
21643034Sdougm * Return the value of the tag/attribute set on the specified
21653034Sdougm * share. Returns NULL if the tag doesn't exist.
21663034Sdougm */
21673034Sdougm
21683034Sdougm char *
sa_get_share_attr(sa_share_t share,char * tag)21693034Sdougm sa_get_share_attr(sa_share_t share, char *tag)
21703034Sdougm {
21713034Sdougm return (get_node_attr((void *)share, tag));
21723034Sdougm }
21733034Sdougm
21743034Sdougm /*
21753034Sdougm * _sa_set_share_description(share, description)
21763034Sdougm *
21775331Samw * Add a description tag with text contents to the specified share. A
21785331Samw * separate XML tag is used rather than a property. This can also be
21795331Samw * used with resources.
21803034Sdougm */
21813034Sdougm
21823034Sdougm xmlNodePtr
_sa_set_share_description(void * share,char * content)21835331Samw _sa_set_share_description(void *share, char *content)
21843034Sdougm {
21853034Sdougm xmlNodePtr node;
21864327Sdougm node = xmlNewChild((xmlNodePtr)share, NULL, (xmlChar *)"description",
21874327Sdougm NULL);
21883034Sdougm xmlNodeSetContent(node, (xmlChar *)content);
21893034Sdougm return (node);
21903034Sdougm }
21913034Sdougm
21923034Sdougm /*
21933034Sdougm * sa_set_share_attr(share, tag, value)
21943034Sdougm *
21953034Sdougm * Set the share attribute specified by tag to the specified value. In
21963034Sdougm * the case of "resource", enforce a no duplicates in a group rule. If
21973034Sdougm * the share is not transient, commit the changes to the repository
21983034Sdougm * else just update the share internally.
21993034Sdougm */
22003034Sdougm
22013034Sdougm int
sa_set_share_attr(sa_share_t share,char * tag,char * value)22023034Sdougm sa_set_share_attr(sa_share_t share, char *tag, char *value)
22033034Sdougm {
22043034Sdougm sa_group_t group;
22053034Sdougm sa_share_t resource;
22063034Sdougm int ret = SA_OK;
22073034Sdougm
22083034Sdougm group = sa_get_parent_group(share);
22093034Sdougm
22103034Sdougm /*
22113034Sdougm * There are some attributes that may have specific
22123034Sdougm * restrictions on them. Initially, only "resource" has
22133034Sdougm * special meaning that needs to be checked. Only one instance
22143034Sdougm * of a resource name may exist within a group.
22153034Sdougm */
22163034Sdougm
22173034Sdougm if (strcmp(tag, "resource") == 0) {
22184327Sdougm resource = sa_get_resource(group, value);
22194327Sdougm if (resource != share && resource != NULL)
22204327Sdougm ret = SA_DUPLICATE_NAME;
22213034Sdougm }
22223034Sdougm if (ret == SA_OK) {
22234327Sdougm set_node_attr((void *)share, tag, value);
22244327Sdougm if (group != NULL) {
22254327Sdougm char *type;
22264327Sdougm /* we can probably optimize this some */
22274327Sdougm type = sa_get_share_attr(share, "type");
22284327Sdougm if (type == NULL || strcmp(type, "transient") != 0) {
22294327Sdougm sa_handle_impl_t impl_handle;
22304327Sdougm impl_handle =
22314327Sdougm (sa_handle_impl_t)sa_find_group_handle(
22324327Sdougm group);
22334327Sdougm if (impl_handle != NULL) {
22344327Sdougm ret = sa_commit_share(
22354327Sdougm impl_handle->scfhandle, group,
22364327Sdougm share);
22374327Sdougm } else {
22384327Sdougm ret = SA_SYSTEM_ERR;
22394327Sdougm }
22404327Sdougm }
22414327Sdougm if (type != NULL)
22424327Sdougm sa_free_attr_string(type);
22433910Sdougm }
22443034Sdougm }
22453034Sdougm return (ret);
22463034Sdougm }
22473034Sdougm
22483034Sdougm /*
22493034Sdougm * sa_get_property_attr(prop, tag)
22503034Sdougm *
22513034Sdougm * Get the value of the specified property attribute. Standard
22523034Sdougm * attributes are "type" and "value".
22533034Sdougm */
22543034Sdougm
22553034Sdougm char *
sa_get_property_attr(sa_property_t prop,char * tag)22563034Sdougm sa_get_property_attr(sa_property_t prop, char *tag)
22573034Sdougm {
22583034Sdougm return (get_node_attr((void *)prop, tag));
22593034Sdougm }
22603034Sdougm
22613034Sdougm /*
22623034Sdougm * sa_get_optionset_attr(prop, tag)
22633034Sdougm *
22643034Sdougm * Get the value of the specified property attribute. Standard
22653034Sdougm * attribute is "type".
22663034Sdougm */
22673034Sdougm
22683034Sdougm char *
sa_get_optionset_attr(sa_property_t optionset,char * tag)22693034Sdougm sa_get_optionset_attr(sa_property_t optionset, char *tag)
22703034Sdougm {
22713034Sdougm return (get_node_attr((void *)optionset, tag));
22723034Sdougm
22733034Sdougm }
22743034Sdougm
22753034Sdougm /*
22763034Sdougm * sa_set_optionset_attr(optionset, tag, value)
22773034Sdougm *
22783034Sdougm * Set the specified attribute(tag) to the specified value on the
22793034Sdougm * optionset.
22803034Sdougm */
22813034Sdougm
22823034Sdougm void
sa_set_optionset_attr(sa_group_t optionset,char * tag,char * value)22833034Sdougm sa_set_optionset_attr(sa_group_t optionset, char *tag, char *value)
22843034Sdougm {
22853034Sdougm set_node_attr((void *)optionset, tag, value);
22863034Sdougm }
22873034Sdougm
22883034Sdougm /*
22893034Sdougm * sa_free_attr_string(string)
22903034Sdougm *
22913034Sdougm * Free the string that was returned in one of the sa_get_*_attr()
22923034Sdougm * functions.
22933034Sdougm */
22943034Sdougm
22953034Sdougm void
sa_free_attr_string(char * string)22963034Sdougm sa_free_attr_string(char *string)
22973034Sdougm {
22983034Sdougm xmlFree((xmlChar *)string);
22993034Sdougm }
23003034Sdougm
23013034Sdougm /*
23023034Sdougm * sa_get_optionset(group, proto)
23033034Sdougm *
23043034Sdougm * Return the optionset, if it exists, that is associated with the
23053034Sdougm * specified protocol.
23063034Sdougm */
23073034Sdougm
23083034Sdougm sa_optionset_t
sa_get_optionset(void * group,char * proto)23093034Sdougm sa_get_optionset(void *group, char *proto)
23103034Sdougm {
23113034Sdougm xmlNodePtr node;
23123034Sdougm xmlChar *value = NULL;
23133034Sdougm
23143034Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL;
23154327Sdougm node = node->next) {
23163034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) {
23174327Sdougm value = xmlGetProp(node, (xmlChar *)"type");
23184327Sdougm if (proto != NULL) {
23194327Sdougm if (value != NULL &&
23204327Sdougm xmlStrcmp(value, (xmlChar *)proto) == 0) {
23214327Sdougm break;
23224327Sdougm }
23234327Sdougm if (value != NULL) {
23244327Sdougm xmlFree(value);
23254327Sdougm value = NULL;
23264327Sdougm }
23274327Sdougm } else {
23284327Sdougm break;
23293034Sdougm }
23303034Sdougm }
23313034Sdougm }
23323034Sdougm if (value != NULL)
23334327Sdougm xmlFree(value);
23343034Sdougm return ((sa_optionset_t)node);
23353034Sdougm }
23363034Sdougm
23373034Sdougm /*
23383034Sdougm * sa_get_next_optionset(optionset)
23393034Sdougm *
23403034Sdougm * Return the next optionset in the group. NULL if this was the last.
23413034Sdougm */
23423034Sdougm
23433034Sdougm sa_optionset_t
sa_get_next_optionset(sa_optionset_t optionset)23443034Sdougm sa_get_next_optionset(sa_optionset_t optionset)
23453034Sdougm {
23463034Sdougm xmlNodePtr node;
23473034Sdougm
23483034Sdougm for (node = ((xmlNodePtr)optionset)->next; node != NULL;
23494327Sdougm node = node->next) {
23503034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) {
23513034Sdougm break;
23523034Sdougm }
23533034Sdougm }
23543034Sdougm return ((sa_optionset_t)node);
23553034Sdougm }
23563034Sdougm
23573034Sdougm /*
23583034Sdougm * sa_get_security(group, sectype, proto)
23593034Sdougm *
23603034Sdougm * Return the security optionset. The internal name is a hold over
23613034Sdougm * from the implementation and will be changed before the API is
23623034Sdougm * finalized. This is really a named optionset that can be negotiated
23633034Sdougm * as a group of properties (like NFS security options).
23643034Sdougm */
23653034Sdougm
23663034Sdougm sa_security_t
sa_get_security(sa_group_t group,char * sectype,char * proto)23673034Sdougm sa_get_security(sa_group_t group, char *sectype, char *proto)
23683034Sdougm {
23693034Sdougm xmlNodePtr node;
23703034Sdougm xmlChar *value = NULL;
23713034Sdougm
23723034Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL;
23734327Sdougm node = node->next) {
23744327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) {
23754327Sdougm if (proto != NULL) {
23764327Sdougm value = xmlGetProp(node, (xmlChar *)"type");
23774327Sdougm if (value == NULL ||
23784327Sdougm (value != NULL &&
23794327Sdougm xmlStrcmp(value, (xmlChar *)proto) != 0)) {
23804327Sdougm /* it doesn't match so continue */
23814327Sdougm xmlFree(value);
23824327Sdougm value = NULL;
23834327Sdougm continue;
23844327Sdougm }
23854327Sdougm }
23864327Sdougm if (value != NULL) {
23874327Sdougm xmlFree(value);
23884327Sdougm value = NULL;
23894327Sdougm }
23904327Sdougm /* potential match */
23914327Sdougm if (sectype != NULL) {
23924327Sdougm value = xmlGetProp(node, (xmlChar *)"sectype");
23934327Sdougm if (value != NULL &&
23944327Sdougm xmlStrcmp(value, (xmlChar *)sectype) == 0) {
23954327Sdougm break;
23964327Sdougm }
23974327Sdougm } else {
23984327Sdougm break;
23994327Sdougm }
24003034Sdougm }
24013034Sdougm if (value != NULL) {
24024327Sdougm xmlFree(value);
24034327Sdougm value = NULL;
24043034Sdougm }
24053034Sdougm }
24063034Sdougm if (value != NULL)
24074327Sdougm xmlFree(value);
24083034Sdougm return ((sa_security_t)node);
24093034Sdougm }
24103034Sdougm
24113034Sdougm /*
24123034Sdougm * sa_get_next_security(security)
24133034Sdougm *
24143034Sdougm * Get the next security optionset if one exists.
24153034Sdougm */
24163034Sdougm
24173034Sdougm sa_security_t
sa_get_next_security(sa_security_t security)24183034Sdougm sa_get_next_security(sa_security_t security)
24193034Sdougm {
24203034Sdougm xmlNodePtr node;
24213034Sdougm
24223034Sdougm for (node = ((xmlNodePtr)security)->next; node != NULL;
24234327Sdougm node = node->next) {
24243034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) {
24253034Sdougm break;
24263034Sdougm }
24273034Sdougm }
24283034Sdougm return ((sa_security_t)node);
24293034Sdougm }
24303034Sdougm
24313034Sdougm /*
24323034Sdougm * sa_get_property(optionset, prop)
24333034Sdougm *
24343034Sdougm * Get the property object with the name specified in prop from the
24353034Sdougm * optionset.
24363034Sdougm */
24373034Sdougm
24383034Sdougm sa_property_t
sa_get_property(sa_optionset_t optionset,char * prop)24393034Sdougm sa_get_property(sa_optionset_t optionset, char *prop)
24403034Sdougm {
24413034Sdougm xmlNodePtr node = (xmlNodePtr)optionset;
24423034Sdougm xmlChar *value = NULL;
24433034Sdougm
24443034Sdougm if (optionset == NULL)
24454327Sdougm return (NULL);
24463034Sdougm
24473034Sdougm for (node = node->children; node != NULL;
24484327Sdougm node = node->next) {
24494327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) {
24504327Sdougm if (prop == NULL)
24514327Sdougm break;
24524327Sdougm value = xmlGetProp(node, (xmlChar *)"type");
24534327Sdougm if (value != NULL &&
24544327Sdougm xmlStrcmp(value, (xmlChar *)prop) == 0) {
24554327Sdougm break;
24564327Sdougm }
24574327Sdougm if (value != NULL) {
24584327Sdougm xmlFree(value);
24594327Sdougm value = NULL;
24604327Sdougm }
24613034Sdougm }
24623034Sdougm }
24633034Sdougm if (value != NULL)
24643034Sdougm xmlFree(value);
24653034Sdougm if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"option") != 0) {
24664327Sdougm /*
24674327Sdougm * avoid a non option node -- it is possible to be a
24684327Sdougm * text node
24694327Sdougm */
24704327Sdougm node = NULL;
24713034Sdougm }
24723034Sdougm return ((sa_property_t)node);
24733034Sdougm }
24743034Sdougm
24753034Sdougm /*
24763034Sdougm * sa_get_next_property(property)
24773034Sdougm *
24783034Sdougm * Get the next property following the specified property. NULL if
24793034Sdougm * this was the last.
24803034Sdougm */
24813034Sdougm
24823034Sdougm sa_property_t
sa_get_next_property(sa_property_t property)24833034Sdougm sa_get_next_property(sa_property_t property)
24843034Sdougm {
24853034Sdougm xmlNodePtr node;
24863034Sdougm
24873034Sdougm for (node = ((xmlNodePtr)property)->next; node != NULL;
24884327Sdougm node = node->next) {
24893034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) {
24903034Sdougm break;
24913034Sdougm }
24923034Sdougm }
24933034Sdougm return ((sa_property_t)node);
24943034Sdougm }
24953034Sdougm
24963034Sdougm /*
24973034Sdougm * sa_set_share_description(share, content)
24983034Sdougm *
24993034Sdougm * Set the description of share to content.
25003034Sdougm */
25013034Sdougm
25023034Sdougm int
sa_set_share_description(sa_share_t share,char * content)25033034Sdougm sa_set_share_description(sa_share_t share, char *content)
25043034Sdougm {
25053034Sdougm xmlNodePtr node;
25063034Sdougm sa_group_t group;
25073034Sdougm int ret = SA_OK;
25083034Sdougm
25093034Sdougm for (node = ((xmlNodePtr)share)->children; node != NULL;
25104327Sdougm node = node->next) {
25113034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) {
25123034Sdougm break;
25133034Sdougm }
25143034Sdougm }
25153034Sdougm /* no existing description but want to add */
25163034Sdougm if (node == NULL && content != NULL) {
25173034Sdougm /* add a description */
25184327Sdougm node = _sa_set_share_description(share, content);
25193034Sdougm } else if (node != NULL && content != NULL) {
25203034Sdougm /* update a description */
25213034Sdougm xmlNodeSetContent(node, (xmlChar *)content);
25223034Sdougm } else if (node != NULL && content == NULL) {
25233034Sdougm /* remove an existing description */
25243034Sdougm xmlUnlinkNode(node);
25253034Sdougm xmlFreeNode(node);
25263034Sdougm }
25275331Samw group = sa_get_parent_group(share);
252812508Samw@Sun.COM if (group != NULL &&
252912508Samw@Sun.COM sa_is_persistent(share) && (!sa_group_is_zfs(group))) {
25304327Sdougm sa_handle_impl_t impl_handle;
25314327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
25324327Sdougm if (impl_handle != NULL) {
25334327Sdougm ret = sa_commit_share(impl_handle->scfhandle, group,
25344327Sdougm share);
25354327Sdougm } else {
25364327Sdougm ret = SA_SYSTEM_ERR;
25374327Sdougm }
25383910Sdougm }
25393034Sdougm return (ret);
25403034Sdougm }
25413034Sdougm
25423034Sdougm /*
25433034Sdougm * fixproblemchars(string)
25443034Sdougm *
25453034Sdougm * don't want any newline or tab characters in the text since these
25463034Sdougm * could break display of data and legacy file formats.
25473034Sdougm */
25483034Sdougm static void
fixproblemchars(char * str)25493034Sdougm fixproblemchars(char *str)
25503034Sdougm {
25513034Sdougm int c;
25523034Sdougm for (c = *str; c != '\0'; c = *++str) {
25534327Sdougm if (c == '\t' || c == '\n')
25544327Sdougm *str = ' ';
25554327Sdougm else if (c == '"')
25564327Sdougm *str = '\'';
25573034Sdougm }
25583034Sdougm }
25593034Sdougm
25603034Sdougm /*
25613034Sdougm * sa_get_share_description(share)
25623034Sdougm *
25633034Sdougm * Return the description text for the specified share if it
25643034Sdougm * exists. NULL if no description exists.
25653034Sdougm */
25663034Sdougm
25673034Sdougm char *
sa_get_share_description(sa_share_t share)25683034Sdougm sa_get_share_description(sa_share_t share)
25693034Sdougm {
25703034Sdougm xmlChar *description = NULL;
25713034Sdougm xmlNodePtr node;
25723034Sdougm
25733034Sdougm for (node = ((xmlNodePtr)share)->children; node != NULL;
25744327Sdougm node = node->next) {
25754327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) {
25764327Sdougm break;
25774327Sdougm }
25783034Sdougm }
25793034Sdougm if (node != NULL) {
25805331Samw description = xmlNodeGetContent(node);
25814327Sdougm fixproblemchars((char *)description);
25823034Sdougm }
25833034Sdougm return ((char *)description);
25843034Sdougm }
25853034Sdougm
25863034Sdougm /*
25873034Sdougm * sa_free(share_description(description)
25883034Sdougm *
25893034Sdougm * Free the description string.
25903034Sdougm */
25913034Sdougm
25923034Sdougm void
sa_free_share_description(char * description)25933034Sdougm sa_free_share_description(char *description)
25943034Sdougm {
25953034Sdougm xmlFree((xmlChar *)description);
25963034Sdougm }
25973034Sdougm
25983034Sdougm /*
25993034Sdougm * sa_create_optionset(group, proto)
26003034Sdougm *
26013034Sdougm * Create an optionset for the specified protocol in the specied
26023034Sdougm * group. This is manifested as a property group within SMF.
26033034Sdougm */
26043034Sdougm
26053034Sdougm sa_optionset_t
sa_create_optionset(sa_group_t group,char * proto)26063034Sdougm sa_create_optionset(sa_group_t group, char *proto)
26073034Sdougm {
26083034Sdougm sa_optionset_t optionset;
26093034Sdougm sa_group_t parent = group;
26105331Samw sa_share_t share = NULL;
26115331Samw int err = SA_OK;
26125331Samw char *id = NULL;
26133034Sdougm
26143034Sdougm optionset = sa_get_optionset(group, proto);
26153034Sdougm if (optionset != NULL) {
26163034Sdougm /* can't have a duplicate protocol */
26174327Sdougm optionset = NULL;
26183034Sdougm } else {
26195331Samw /*
26205331Samw * Account for resource names being slightly
26215331Samw * different.
26225331Samw */
26235331Samw if (sa_is_share(group)) {
26245331Samw /*
26255331Samw * Transient shares do not have an "id" so not an
26265331Samw * error to not find one.
26275331Samw */
26285331Samw id = sa_get_share_attr((sa_share_t)group, "id");
26295331Samw } else if (sa_is_resource(group)) {
26305331Samw share = sa_get_resource_parent(
26315331Samw (sa_resource_t)group);
26325331Samw id = sa_get_resource_attr(share, "id");
26335331Samw
26345331Samw /* id can be NULL if the group is transient (ZFS) */
26355331Samw if (id == NULL && sa_is_persistent(group))
26365331Samw err = SA_NO_MEMORY;
26375331Samw }
26385331Samw if (err == SA_NO_MEMORY) {
26395331Samw /*
26405331Samw * Couldn't get the id for the share or
26415331Samw * resource. While this could be a
26425331Samw * configuration issue, it is most likely an
26435331Samw * out of memory. In any case, fail the create.
26445331Samw */
26455331Samw return (NULL);
26465331Samw }
26475331Samw
26484327Sdougm optionset = (sa_optionset_t)xmlNewChild((xmlNodePtr)group,
26494327Sdougm NULL, (xmlChar *)"optionset", NULL);
26503034Sdougm /*
26513034Sdougm * only put to repository if on a group and we were
26523034Sdougm * able to create an optionset.
26533034Sdougm */
26544327Sdougm if (optionset != NULL) {
26554327Sdougm char oname[SA_STRSIZE];
26564327Sdougm char *groupname;
26575331Samw
26585331Samw /*
26595331Samw * Need to get parent group in all cases, but also get
26605331Samw * the share if this is a resource.
26615331Samw */
26625331Samw if (sa_is_share(group)) {
26634327Sdougm parent = sa_get_parent_group((sa_share_t)group);
26645331Samw } else if (sa_is_resource(group)) {
26655331Samw share = sa_get_resource_parent(
26665331Samw (sa_resource_t)group);
26675331Samw parent = sa_get_parent_group(share);
26685331Samw }
26694327Sdougm
26704327Sdougm sa_set_optionset_attr(optionset, "type", proto);
26713034Sdougm
26724327Sdougm (void) sa_optionset_name(optionset, oname,
26734327Sdougm sizeof (oname), id);
26744327Sdougm groupname = sa_get_group_attr(parent, "name");
26755331Samw if (groupname != NULL && sa_is_persistent(group)) {
26764327Sdougm sa_handle_impl_t impl_handle;
26775331Samw impl_handle =
26785331Samw (sa_handle_impl_t)sa_find_group_handle(
26795331Samw group);
26804327Sdougm assert(impl_handle != NULL);
26814327Sdougm if (impl_handle != NULL) {
26824327Sdougm (void) sa_get_instance(
26835331Samw impl_handle->scfhandle, groupname);
26844327Sdougm (void) sa_create_pgroup(
26854327Sdougm impl_handle->scfhandle, oname);
26864327Sdougm }
26874327Sdougm }
26884327Sdougm if (groupname != NULL)
26894327Sdougm sa_free_attr_string(groupname);
26903034Sdougm }
26913034Sdougm }
26925331Samw
26935331Samw if (id != NULL)
26945331Samw sa_free_attr_string(id);
26953034Sdougm return (optionset);
26963034Sdougm }
26973034Sdougm
26983034Sdougm /*
26993034Sdougm * sa_get_property_parent(property)
27003034Sdougm *
27013034Sdougm * Given a property, return the object it is a property of. This will
27023034Sdougm * be an optionset of some type.
27033034Sdougm */
27043034Sdougm
27053034Sdougm static sa_optionset_t
sa_get_property_parent(sa_property_t property)27063034Sdougm sa_get_property_parent(sa_property_t property)
27073034Sdougm {
27083034Sdougm xmlNodePtr node = NULL;
27093034Sdougm
27104327Sdougm if (property != NULL)
27114327Sdougm node = ((xmlNodePtr)property)->parent;
27123034Sdougm return ((sa_optionset_t)node);
27133034Sdougm }
27143034Sdougm
27153034Sdougm /*
27163034Sdougm * sa_get_optionset_parent(optionset)
27173034Sdougm *
27183034Sdougm * Return the parent of the specified optionset. This could be a group
27193034Sdougm * or a share.
27203034Sdougm */
27213034Sdougm
27223034Sdougm static sa_group_t
sa_get_optionset_parent(sa_optionset_t optionset)27233034Sdougm sa_get_optionset_parent(sa_optionset_t optionset)
27243034Sdougm {
27253034Sdougm xmlNodePtr node = NULL;
27263034Sdougm
27274327Sdougm if (optionset != NULL)
27284327Sdougm node = ((xmlNodePtr)optionset)->parent;
27293034Sdougm return ((sa_group_t)node);
27303034Sdougm }
27313034Sdougm
27323034Sdougm /*
27333034Sdougm * zfs_needs_update(share)
27343034Sdougm *
27353034Sdougm * In order to avoid making multiple updates to a ZFS share when
27363034Sdougm * setting properties, the share attribute "changed" will be set to
27375331Samw * true when a property is added or modified. When done adding
27383034Sdougm * properties, we can then detect that an update is needed. We then
27393034Sdougm * clear the state here to detect additional changes.
27403034Sdougm */
27413034Sdougm
27423034Sdougm static int
zfs_needs_update(sa_share_t share)27433034Sdougm zfs_needs_update(sa_share_t share)
27443034Sdougm {
27453034Sdougm char *attr;
27463034Sdougm int result = 0;
27473034Sdougm
27483034Sdougm attr = sa_get_share_attr(share, "changed");
27493034Sdougm if (attr != NULL) {
27504327Sdougm sa_free_attr_string(attr);
27513034Sdougm result = 1;
27523034Sdougm }
27533034Sdougm set_node_attr((void *)share, "changed", NULL);
27543034Sdougm return (result);
27553034Sdougm }
27563034Sdougm
27573034Sdougm /*
27583034Sdougm * zfs_set_update(share)
27593034Sdougm *
27603034Sdougm * Set the changed attribute of the share to true.
27613034Sdougm */
27623034Sdougm
27633034Sdougm static void
zfs_set_update(sa_share_t share)27643034Sdougm zfs_set_update(sa_share_t share)
27653034Sdougm {
27663034Sdougm set_node_attr((void *)share, "changed", "true");
27673034Sdougm }
27683034Sdougm
27693034Sdougm /*
27703034Sdougm * sa_commit_properties(optionset, clear)
27713034Sdougm *
27723034Sdougm * Check if SMF or ZFS config and either update or abort the pending
27733034Sdougm * changes.
27743034Sdougm */
27753034Sdougm
27763034Sdougm int
sa_commit_properties(sa_optionset_t optionset,int clear)27773034Sdougm sa_commit_properties(sa_optionset_t optionset, int clear)
27783034Sdougm {
27793034Sdougm sa_group_t group;
27803034Sdougm sa_group_t parent;
27813034Sdougm int zfs = 0;
27823034Sdougm int needsupdate = 0;
27833034Sdougm int ret = SA_OK;
27843910Sdougm sa_handle_impl_t impl_handle;
27853034Sdougm
27863034Sdougm group = sa_get_optionset_parent(optionset);
27873034Sdougm if (group != NULL && (sa_is_share(group) || is_zfs_group(group))) {
27884327Sdougm /* only update ZFS if on a share */
27894327Sdougm parent = sa_get_parent_group(group);
27904327Sdougm zfs++;
27914327Sdougm if (parent != NULL && is_zfs_group(parent))
27924327Sdougm needsupdate = zfs_needs_update(group);
27934327Sdougm else
27944327Sdougm zfs = 0;
27953034Sdougm }
27963034Sdougm if (zfs) {
27974327Sdougm if (!clear && needsupdate)
27984327Sdougm ret = sa_zfs_update((sa_share_t)group);
27993034Sdougm } else {
28004327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
28014327Sdougm if (impl_handle != NULL) {
28024327Sdougm if (clear) {
28034327Sdougm (void) sa_abort_transaction(
28044327Sdougm impl_handle->scfhandle);
28054327Sdougm } else {
28064327Sdougm ret = sa_end_transaction(
28075951Sdougm impl_handle->scfhandle, impl_handle);
28084327Sdougm }
28094327Sdougm } else {
28104327Sdougm ret = SA_SYSTEM_ERR;
28114327Sdougm }
28123034Sdougm }
28133034Sdougm return (ret);
28143034Sdougm }
28153034Sdougm
28163034Sdougm /*
28173034Sdougm * sa_destroy_optionset(optionset)
28183034Sdougm *
28195331Samw * Remove the optionset from its group. Update the repository to
28203034Sdougm * reflect this change.
28213034Sdougm */
28223034Sdougm
28233034Sdougm int
sa_destroy_optionset(sa_optionset_t optionset)28243034Sdougm sa_destroy_optionset(sa_optionset_t optionset)
28253034Sdougm {
28264327Sdougm char name[SA_STRSIZE];
28273034Sdougm int len;
28283034Sdougm int ret;
28293034Sdougm char *id = NULL;
28303034Sdougm sa_group_t group;
28313034Sdougm int ispersist = 1;
28323034Sdougm
28333034Sdougm /* now delete the prop group */
28343034Sdougm group = sa_get_optionset_parent(optionset);
28355331Samw if (group != NULL) {
28365331Samw if (sa_is_resource(group)) {
28375331Samw sa_resource_t resource = group;
28385331Samw sa_share_t share = sa_get_resource_parent(resource);
28395331Samw group = sa_get_parent_group(share);
28405331Samw id = sa_get_share_attr(share, "id");
28415331Samw } else if (sa_is_share(group)) {
28425331Samw id = sa_get_share_attr((sa_share_t)group, "id");
28435331Samw }
28445331Samw ispersist = sa_is_persistent(group);
28453034Sdougm }
28463034Sdougm if (ispersist) {
28474327Sdougm sa_handle_impl_t impl_handle;
28484327Sdougm len = sa_optionset_name(optionset, name, sizeof (name), id);
28494327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
28504327Sdougm if (impl_handle != NULL) {
28514327Sdougm if (len > 0) {
28524327Sdougm ret = sa_delete_pgroup(impl_handle->scfhandle,
28534327Sdougm name);
28544327Sdougm }
28554327Sdougm } else {
28564327Sdougm ret = SA_SYSTEM_ERR;
28573910Sdougm }
28583034Sdougm }
28593034Sdougm xmlUnlinkNode((xmlNodePtr)optionset);
28603034Sdougm xmlFreeNode((xmlNodePtr)optionset);
28613034Sdougm if (id != NULL)
28624327Sdougm sa_free_attr_string(id);
28633034Sdougm return (ret);
28643034Sdougm }
28653034Sdougm
28663034Sdougm /* private to the implementation */
28673034Sdougm int
_sa_remove_optionset(sa_optionset_t optionset)28683034Sdougm _sa_remove_optionset(sa_optionset_t optionset)
28693034Sdougm {
28703034Sdougm int ret = SA_OK;
28713034Sdougm
28723034Sdougm xmlUnlinkNode((xmlNodePtr)optionset);
28733034Sdougm xmlFreeNode((xmlNodePtr)optionset);
28743034Sdougm return (ret);
28753034Sdougm }
28763034Sdougm
28773034Sdougm /*
28783034Sdougm * sa_create_security(group, sectype, proto)
28793034Sdougm *
28803034Sdougm * Create a security optionset (one that has a type name and a
28813034Sdougm * proto). Security is left over from a pure NFS implementation. The
28823034Sdougm * naming will change in the future when the API is released.
28833034Sdougm */
28843034Sdougm sa_security_t
sa_create_security(sa_group_t group,char * sectype,char * proto)28853034Sdougm sa_create_security(sa_group_t group, char *sectype, char *proto)
28863034Sdougm {
28873034Sdougm sa_security_t security;
28883034Sdougm char *id = NULL;
28893034Sdougm sa_group_t parent;
28903034Sdougm char *groupname = NULL;
28913034Sdougm
28923034Sdougm if (group != NULL && sa_is_share(group)) {
28934327Sdougm id = sa_get_share_attr((sa_share_t)group, "id");
28944327Sdougm parent = sa_get_parent_group(group);
28954327Sdougm if (parent != NULL)
28964327Sdougm groupname = sa_get_group_attr(parent, "name");
28973034Sdougm } else if (group != NULL) {
28984327Sdougm groupname = sa_get_group_attr(group, "name");
28993034Sdougm }
29003034Sdougm
29013034Sdougm security = sa_get_security(group, sectype, proto);
29023034Sdougm if (security != NULL) {
29033034Sdougm /* can't have a duplicate security option */
29043034Sdougm security = NULL;
29053034Sdougm } else {
29063034Sdougm security = (sa_security_t)xmlNewChild((xmlNodePtr)group,
29074327Sdougm NULL, (xmlChar *)"security", NULL);
29083034Sdougm if (security != NULL) {
29094327Sdougm char oname[SA_STRSIZE];
29103034Sdougm sa_set_security_attr(security, "type", proto);
29113034Sdougm
29123034Sdougm sa_set_security_attr(security, "sectype", sectype);
29133034Sdougm (void) sa_security_name(security, oname,
29144327Sdougm sizeof (oname), id);
29155331Samw if (groupname != NULL && sa_is_persistent(group)) {
29164327Sdougm sa_handle_impl_t impl_handle;
29174327Sdougm impl_handle =
29184327Sdougm (sa_handle_impl_t)sa_find_group_handle(
29194327Sdougm group);
29204327Sdougm if (impl_handle != NULL) {
29214327Sdougm (void) sa_get_instance(
29224327Sdougm impl_handle->scfhandle, groupname);
29234327Sdougm (void) sa_create_pgroup(
29244327Sdougm impl_handle->scfhandle, oname);
29254327Sdougm }
29263034Sdougm }
29273034Sdougm }
29283034Sdougm }
292911337SWilliam.Krier@Sun.COM if (id != NULL)
293011337SWilliam.Krier@Sun.COM sa_free_attr_string(id);
29313034Sdougm if (groupname != NULL)
29324327Sdougm sa_free_attr_string(groupname);
29333034Sdougm return (security);
29343034Sdougm }
29353034Sdougm
29363034Sdougm /*
29373034Sdougm * sa_destroy_security(security)
29383034Sdougm *
29393034Sdougm * Remove the specified optionset from the document and the
29403034Sdougm * configuration.
29413034Sdougm */
29423034Sdougm
29433034Sdougm int
sa_destroy_security(sa_security_t security)29443034Sdougm sa_destroy_security(sa_security_t security)
29453034Sdougm {
29464327Sdougm char name[SA_STRSIZE];
29473034Sdougm int len;
29483034Sdougm int ret = SA_OK;
29493034Sdougm char *id = NULL;
29503034Sdougm sa_group_t group;
29513034Sdougm int iszfs = 0;
29523034Sdougm int ispersist = 1;
29533034Sdougm
29543034Sdougm group = sa_get_optionset_parent(security);
29553034Sdougm
29563034Sdougm if (group != NULL)
29574327Sdougm iszfs = sa_group_is_zfs(group);
29583034Sdougm
29593034Sdougm if (group != NULL && !iszfs) {
29604327Sdougm if (sa_is_share(group))
29615331Samw ispersist = sa_is_persistent(group);
29624327Sdougm id = sa_get_share_attr((sa_share_t)group, "id");
29633034Sdougm }
29643034Sdougm if (ispersist) {
29654327Sdougm len = sa_security_name(security, name, sizeof (name), id);
29664327Sdougm if (!iszfs && len > 0) {
29674327Sdougm sa_handle_impl_t impl_handle;
29684327Sdougm impl_handle =
29694327Sdougm (sa_handle_impl_t)sa_find_group_handle(group);
29704327Sdougm if (impl_handle != NULL) {
29714327Sdougm ret = sa_delete_pgroup(impl_handle->scfhandle,
29724327Sdougm name);
29734327Sdougm } else {
29744327Sdougm ret = SA_SYSTEM_ERR;
29754327Sdougm }
29763910Sdougm }
29773034Sdougm }
29783034Sdougm xmlUnlinkNode((xmlNodePtr)security);
29793034Sdougm xmlFreeNode((xmlNodePtr)security);
29804327Sdougm if (iszfs)
29814327Sdougm ret = sa_zfs_update(group);
29823034Sdougm if (id != NULL)
29834327Sdougm sa_free_attr_string(id);
29843034Sdougm return (ret);
29853034Sdougm }
29863034Sdougm
29873034Sdougm /*
29883034Sdougm * sa_get_security_attr(optionset, tag)
29893034Sdougm *
29903034Sdougm * Return the specified attribute value from the optionset.
29913034Sdougm */
29923034Sdougm
29933034Sdougm char *
sa_get_security_attr(sa_property_t optionset,char * tag)29943034Sdougm sa_get_security_attr(sa_property_t optionset, char *tag)
29953034Sdougm {
29963034Sdougm return (get_node_attr((void *)optionset, tag));
29973034Sdougm
29983034Sdougm }
29993034Sdougm
30003034Sdougm /*
30013034Sdougm * sa_set_security_attr(optionset, tag, value)
30023034Sdougm *
30033034Sdougm * Set the optioset attribute specied by tag to the specified value.
30043034Sdougm */
30053034Sdougm
30063034Sdougm void
sa_set_security_attr(sa_group_t optionset,char * tag,char * value)30073034Sdougm sa_set_security_attr(sa_group_t optionset, char *tag, char *value)
30083034Sdougm {
30093034Sdougm set_node_attr((void *)optionset, tag, value);
30103034Sdougm }
30113034Sdougm
30123034Sdougm /*
30133034Sdougm * is_nodetype(node, type)
30143034Sdougm *
30153034Sdougm * Check to see if node is of the type specified.
30163034Sdougm */
30173034Sdougm
30183034Sdougm static int
is_nodetype(void * node,char * type)30193034Sdougm is_nodetype(void *node, char *type)
30203034Sdougm {
30213034Sdougm return (strcmp((char *)((xmlNodePtr)node)->name, type) == 0);
30223034Sdougm }
30233034Sdougm
30244327Sdougm /*
30254327Sdougm * add_or_update()
30264327Sdougm *
30274327Sdougm * Add or update a property. Pulled out of sa_set_prop_by_prop for
30284327Sdougm * readability.
30294327Sdougm */
30304327Sdougm static int
add_or_update(scfutilhandle_t * scf_handle,int type,scf_value_t * value,scf_transaction_entry_t * entry,char * name,char * valstr)30314327Sdougm add_or_update(scfutilhandle_t *scf_handle, int type, scf_value_t *value,
30324327Sdougm scf_transaction_entry_t *entry, char *name, char *valstr)
30334327Sdougm {
30344327Sdougm int ret = SA_SYSTEM_ERR;
30354327Sdougm
30364327Sdougm if (value != NULL) {
30374327Sdougm if (type == SA_PROP_OP_ADD)
30384327Sdougm ret = scf_transaction_property_new(scf_handle->trans,
30394327Sdougm entry, name, SCF_TYPE_ASTRING);
30404327Sdougm else
30414327Sdougm ret = scf_transaction_property_change(scf_handle->trans,
30424327Sdougm entry, name, SCF_TYPE_ASTRING);
30434327Sdougm if (ret == 0) {
30444327Sdougm ret = scf_value_set_astring(value, valstr);
30454327Sdougm if (ret == 0)
30464327Sdougm ret = scf_entry_add_value(entry, value);
30474327Sdougm if (ret == 0)
30484327Sdougm return (ret);
30494327Sdougm scf_value_destroy(value);
30504327Sdougm } else {
30514327Sdougm scf_entry_destroy(entry);
30524327Sdougm }
30534327Sdougm }
30544327Sdougm return (SA_SYSTEM_ERR);
30554327Sdougm }
30564327Sdougm
30573034Sdougm /*
30583034Sdougm * sa_set_prop_by_prop(optionset, group, prop, type)
30593034Sdougm *
30603034Sdougm * Add/remove/update the specified property prop into the optionset or
30613034Sdougm * share. If a share, sort out which property group based on GUID. In
30623034Sdougm * all cases, the appropriate transaction is set (or ZFS share is
30633034Sdougm * marked as needing an update)
30643034Sdougm */
30653034Sdougm
30663034Sdougm static int
sa_set_prop_by_prop(sa_optionset_t optionset,sa_group_t group,sa_property_t prop,int type)30673034Sdougm sa_set_prop_by_prop(sa_optionset_t optionset, sa_group_t group,
30683034Sdougm sa_property_t prop, int type)
30693034Sdougm {
30703034Sdougm char *name;
30713034Sdougm char *valstr;
30723034Sdougm int ret = SA_OK;
30733034Sdougm scf_transaction_entry_t *entry;
30743034Sdougm scf_value_t *value;
30753034Sdougm int opttype; /* 1 == optionset, 0 == security */
30763034Sdougm char *id = NULL;
30773034Sdougm int iszfs = 0;
30783034Sdougm sa_group_t parent = NULL;
30795331Samw sa_share_t share = NULL;
30803910Sdougm sa_handle_impl_t impl_handle;
30813910Sdougm scfutilhandle_t *scf_handle;
30823034Sdougm
30835331Samw if (!sa_is_persistent(group)) {
30843034Sdougm /*
30853034Sdougm * if the group/share is not persistent we don't need
30863034Sdougm * to do anything here
30873034Sdougm */
30884327Sdougm return (SA_OK);
30893034Sdougm }
30903910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
30914327Sdougm if (impl_handle == NULL || impl_handle->scfhandle == NULL)
30924327Sdougm return (SA_SYSTEM_ERR);
30933910Sdougm scf_handle = impl_handle->scfhandle;
30943034Sdougm name = sa_get_property_attr(prop, "type");
30953034Sdougm valstr = sa_get_property_attr(prop, "value");
30963034Sdougm entry = scf_entry_create(scf_handle->handle);
30973034Sdougm opttype = is_nodetype((void *)optionset, "optionset");
30983034Sdougm
30995331Samw /*
31005331Samw * Check for share vs. resource since they need slightly
31015331Samw * different treatment given the hierarchy.
31025331Samw */
31033034Sdougm if (valstr != NULL && entry != NULL) {
31044327Sdougm if (sa_is_share(group)) {
31054327Sdougm parent = sa_get_parent_group(group);
31065331Samw share = (sa_share_t)group;
31074327Sdougm if (parent != NULL)
31084327Sdougm iszfs = is_zfs_group(parent);
31095331Samw } else if (sa_is_resource(group)) {
31105331Samw share = sa_get_parent_group(group);
31115331Samw if (share != NULL)
31125331Samw parent = sa_get_parent_group(share);
31134327Sdougm } else {
31144327Sdougm iszfs = is_zfs_group(group);
31153034Sdougm }
31164327Sdougm if (!iszfs) {
31174327Sdougm if (scf_handle->trans == NULL) {
31184327Sdougm char oname[SA_STRSIZE];
31194327Sdougm char *groupname = NULL;
31205331Samw if (share != NULL) {
31215331Samw if (parent != NULL)
31224327Sdougm groupname =
31234327Sdougm sa_get_group_attr(parent,
31244327Sdougm "name");
31255331Samw id = sa_get_share_attr(
31265331Samw (sa_share_t)share, "id");
31274327Sdougm } else {
31284327Sdougm groupname = sa_get_group_attr(group,
31294327Sdougm "name");
31304327Sdougm }
31314327Sdougm if (groupname != NULL) {
31324327Sdougm ret = sa_get_instance(scf_handle,
31334327Sdougm groupname);
31344327Sdougm sa_free_attr_string(groupname);
31354327Sdougm }
31364327Sdougm if (opttype)
31374327Sdougm (void) sa_optionset_name(optionset,
31384327Sdougm oname, sizeof (oname), id);
31394327Sdougm else
31404327Sdougm (void) sa_security_name(optionset,
31414327Sdougm oname, sizeof (oname), id);
31424327Sdougm ret = sa_start_transaction(scf_handle, oname);
314311337SWilliam.Krier@Sun.COM if (id != NULL)
314411337SWilliam.Krier@Sun.COM sa_free_attr_string(id);
31453910Sdougm }
31464327Sdougm if (ret == SA_OK) {
31474327Sdougm switch (type) {
31484327Sdougm case SA_PROP_OP_REMOVE:
31494327Sdougm ret = scf_transaction_property_delete(
31504327Sdougm scf_handle->trans, entry, name);
31514327Sdougm break;
31524327Sdougm case SA_PROP_OP_ADD:
31534327Sdougm case SA_PROP_OP_UPDATE:
31544327Sdougm value = scf_value_create(
31554327Sdougm scf_handle->handle);
31564327Sdougm ret = add_or_update(scf_handle, type,
31574327Sdougm value, entry, name, valstr);
31584327Sdougm break;
31593034Sdougm }
31603034Sdougm }
31614327Sdougm } else {
31624327Sdougm /*
31634327Sdougm * ZFS update. The calling function would have updated
31644327Sdougm * the internal XML structure. Just need to flag it as
31654327Sdougm * changed for ZFS.
31664327Sdougm */
31674327Sdougm zfs_set_update((sa_share_t)group);
31684327Sdougm }
31693034Sdougm }
31703034Sdougm
31713034Sdougm if (name != NULL)
31724327Sdougm sa_free_attr_string(name);
31733034Sdougm if (valstr != NULL)
31744327Sdougm sa_free_attr_string(valstr);
31753034Sdougm else if (entry != NULL)
31764327Sdougm scf_entry_destroy(entry);
31773034Sdougm
31783034Sdougm if (ret == -1)
31794327Sdougm ret = SA_SYSTEM_ERR;
31803034Sdougm
31813034Sdougm return (ret);
31823034Sdougm }
31833034Sdougm
31843034Sdougm /*
31856007Sthurlow * sa_create_section(name, value)
31866007Sthurlow *
31876007Sthurlow * Create a new section with the specified name and extra data.
31886007Sthurlow */
31896007Sthurlow
31906007Sthurlow sa_property_t
sa_create_section(char * name,char * extra)31916007Sthurlow sa_create_section(char *name, char *extra)
31926007Sthurlow {
31936007Sthurlow xmlNodePtr node;
31946007Sthurlow
31956007Sthurlow node = xmlNewNode(NULL, (xmlChar *)"section");
31966007Sthurlow if (node != NULL) {
31976007Sthurlow if (name != NULL)
31986007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name",
31996007Sthurlow (xmlChar *)name);
32006007Sthurlow if (extra != NULL)
32016007Sthurlow (void) xmlSetProp(node, (xmlChar *)"extra",
32026007Sthurlow (xmlChar *)extra);
32036007Sthurlow }
32046007Sthurlow return ((sa_property_t)node);
32056007Sthurlow }
32066007Sthurlow
32076007Sthurlow void
sa_set_section_attr(sa_property_t sect,char * name,char * value)32086007Sthurlow sa_set_section_attr(sa_property_t sect, char *name, char *value)
32096007Sthurlow {
32106007Sthurlow (void) xmlSetProp(sect, (xmlChar *)name, (xmlChar *)value);
32116007Sthurlow }
32126007Sthurlow
32136007Sthurlow /*
32146007Sthurlow * sa_create_property(section, name, value)
32153034Sdougm *
32163034Sdougm * Create a new property with the specified name and value.
32173034Sdougm */
32183034Sdougm
32193034Sdougm sa_property_t
sa_create_property(char * name,char * value)32203034Sdougm sa_create_property(char *name, char *value)
32213034Sdougm {
32223034Sdougm xmlNodePtr node;
32233034Sdougm
32243034Sdougm node = xmlNewNode(NULL, (xmlChar *)"option");
32253034Sdougm if (node != NULL) {
32266007Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", (xmlChar *)name);
32276007Sthurlow (void) xmlSetProp(node, (xmlChar *)"value", (xmlChar *)value);
32283034Sdougm }
32293034Sdougm return ((sa_property_t)node);
32303034Sdougm }
32313034Sdougm
32323034Sdougm /*
32333034Sdougm * sa_add_property(object, property)
32343034Sdougm *
32353034Sdougm * Add the specified property to the object. Issue the appropriate
32363034Sdougm * transaction or mark a ZFS object as needing an update.
32373034Sdougm */
32383034Sdougm
32393034Sdougm int
sa_add_property(void * object,sa_property_t property)32403034Sdougm sa_add_property(void *object, sa_property_t property)
32413034Sdougm {
32423034Sdougm int ret = SA_OK;
32433034Sdougm sa_group_t parent;
32443034Sdougm sa_group_t group;
32453034Sdougm char *proto;
32466214Sdougm
32473034Sdougm if (property != NULL) {
32486271Sdougm sa_handle_t handle;
32496214Sdougm handle = sa_find_group_handle((sa_group_t)object);
32506271Sdougm /* It is legitimate to not find a handle */
32516214Sdougm proto = sa_get_optionset_attr(object, "type");
32526214Sdougm if ((ret = sa_valid_property(handle, object, proto,
32536214Sdougm property)) == SA_OK) {
32544327Sdougm property = (sa_property_t)xmlAddChild(
32554327Sdougm (xmlNodePtr)object, (xmlNodePtr)property);
32564327Sdougm } else {
32574327Sdougm if (proto != NULL)
32584327Sdougm sa_free_attr_string(proto);
32594327Sdougm return (ret);
32604327Sdougm }
32616214Sdougm if (proto != NULL)
32626214Sdougm sa_free_attr_string(proto);
32633034Sdougm }
32643034Sdougm
32653034Sdougm
32663034Sdougm parent = sa_get_parent_group(object);
32675331Samw if (!sa_is_persistent(parent))
32684327Sdougm return (ret);
32695331Samw
32705331Samw if (sa_is_resource(parent)) {
32715331Samw /*
32725331Samw * Resources are children of share. Need to go up two
32735331Samw * levels to find the group but the parent needs to be
32745331Samw * the share at this point in order to get the "id".
32755331Samw */
32765331Samw parent = sa_get_parent_group(parent);
32775331Samw group = sa_get_parent_group(parent);
32785331Samw } else if (sa_is_share(parent)) {
32795331Samw group = sa_get_parent_group(parent);
32805331Samw } else {
32815331Samw group = parent;
32823034Sdougm }
32833034Sdougm
32844327Sdougm if (property == NULL) {
32854327Sdougm ret = SA_NO_MEMORY;
32864327Sdougm } else {
32874327Sdougm char oname[SA_STRSIZE];
32883034Sdougm
32894327Sdougm if (!is_zfs_group(group)) {
32904327Sdougm char *id = NULL;
32914327Sdougm sa_handle_impl_t impl_handle;
32924327Sdougm scfutilhandle_t *scf_handle;
32933910Sdougm
32944327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(
32954327Sdougm group);
32964327Sdougm if (impl_handle == NULL ||
32974327Sdougm impl_handle->scfhandle == NULL)
32984327Sdougm ret = SA_SYSTEM_ERR;
32994327Sdougm if (ret == SA_OK) {
33004327Sdougm scf_handle = impl_handle->scfhandle;
33014327Sdougm if (sa_is_share((sa_group_t)parent)) {
33024327Sdougm id = sa_get_share_attr(
33034327Sdougm (sa_share_t)parent, "id");
33044327Sdougm }
33054327Sdougm if (scf_handle->trans == NULL) {
33064327Sdougm if (is_nodetype(object, "optionset")) {
33074327Sdougm (void) sa_optionset_name(
33084327Sdougm (sa_optionset_t)object,
33094327Sdougm oname, sizeof (oname), id);
33104327Sdougm } else {
33114327Sdougm (void) sa_security_name(
33124327Sdougm (sa_optionset_t)object,
33134327Sdougm oname, sizeof (oname), id);
33144327Sdougm }
33154327Sdougm ret = sa_start_transaction(scf_handle,
33164327Sdougm oname);
33174327Sdougm }
33184327Sdougm if (ret == SA_OK) {
33194327Sdougm char *name;
33204327Sdougm char *value;
33214327Sdougm name = sa_get_property_attr(property,
33224327Sdougm "type");
33234327Sdougm value = sa_get_property_attr(property,
33244327Sdougm "value");
33254327Sdougm if (name != NULL && value != NULL) {
33264327Sdougm if (scf_handle->scf_state ==
33274327Sdougm SCH_STATE_INIT) {
33284327Sdougm ret = sa_set_property(
33294327Sdougm scf_handle, name,
33304327Sdougm value);
33314327Sdougm }
33324327Sdougm } else {
33334327Sdougm ret = SA_CONFIG_ERR;
33344327Sdougm }
33354327Sdougm if (name != NULL)
33364327Sdougm sa_free_attr_string(
33374327Sdougm name);
33384327Sdougm if (value != NULL)
33394327Sdougm sa_free_attr_string(value);
33404327Sdougm }
33414327Sdougm if (id != NULL)
33424327Sdougm sa_free_attr_string(id);
33434327Sdougm }
33444327Sdougm } else {
33454327Sdougm /*
33464327Sdougm * ZFS is a special case. We do want
33474327Sdougm * to allow editing property/security
33484327Sdougm * lists since we can have a better
33494327Sdougm * syntax and we also want to keep
33504327Sdougm * things consistent when possible.
33514327Sdougm *
33524327Sdougm * Right now, we defer until the
33534327Sdougm * sa_commit_properties so we can get
33544327Sdougm * them all at once. We do need to
33554327Sdougm * mark the share as "changed"
33564327Sdougm */
33574327Sdougm zfs_set_update((sa_share_t)parent);
33583034Sdougm }
33593034Sdougm }
33603034Sdougm return (ret);
33613034Sdougm }
33623034Sdougm
33633034Sdougm /*
33643034Sdougm * sa_remove_property(property)
33653034Sdougm *
33663034Sdougm * Remove the specied property from its containing object. Update the
33673034Sdougm * repository as appropriate.
33683034Sdougm */
33693034Sdougm
33703034Sdougm int
sa_remove_property(sa_property_t property)33713034Sdougm sa_remove_property(sa_property_t property)
33723034Sdougm {
33733034Sdougm int ret = SA_OK;
33743034Sdougm
33753034Sdougm if (property != NULL) {
33763034Sdougm sa_optionset_t optionset;
33773034Sdougm sa_group_t group;
33783034Sdougm optionset = sa_get_property_parent(property);
33793034Sdougm if (optionset != NULL) {
33804327Sdougm group = sa_get_optionset_parent(optionset);
33814327Sdougm if (group != NULL) {
33824327Sdougm ret = sa_set_prop_by_prop(optionset, group,
33834327Sdougm property, SA_PROP_OP_REMOVE);
33844327Sdougm }
33853034Sdougm }
33863034Sdougm xmlUnlinkNode((xmlNodePtr)property);
33873034Sdougm xmlFreeNode((xmlNodePtr)property);
33883034Sdougm } else {
33894327Sdougm ret = SA_NO_SUCH_PROP;
33903034Sdougm }
33913034Sdougm return (ret);
33923034Sdougm }
33933034Sdougm
33943034Sdougm /*
33953034Sdougm * sa_update_property(property, value)
33963034Sdougm *
33973034Sdougm * Update the specified property to the new value. If value is NULL,
33983034Sdougm * we currently treat this as a remove.
33993034Sdougm */
34003034Sdougm
34013034Sdougm int
sa_update_property(sa_property_t property,char * value)34023034Sdougm sa_update_property(sa_property_t property, char *value)
34033034Sdougm {
34043034Sdougm int ret = SA_OK;
34053034Sdougm if (value == NULL) {
34063034Sdougm return (sa_remove_property(property));
34073034Sdougm } else {
34083034Sdougm sa_optionset_t optionset;
34093034Sdougm sa_group_t group;
34103034Sdougm set_node_attr((void *)property, "value", value);
34113034Sdougm optionset = sa_get_property_parent(property);
34123034Sdougm if (optionset != NULL) {
34134327Sdougm group = sa_get_optionset_parent(optionset);
34144327Sdougm if (group != NULL) {
34154327Sdougm ret = sa_set_prop_by_prop(optionset, group,
34164327Sdougm property, SA_PROP_OP_UPDATE);
34174327Sdougm }
34183034Sdougm } else {
34194327Sdougm ret = SA_NO_SUCH_PROP;
34203034Sdougm }
34213034Sdougm }
34223034Sdougm return (ret);
34233034Sdougm }
34243034Sdougm
34253034Sdougm /*
34266007Sthurlow * sa_get_protocol_section(propset, prop)
34276007Sthurlow *
34286007Sthurlow * Get the specified protocol specific section. These are global to
34296007Sthurlow * the protocol and not specific to a group or share.
34306007Sthurlow */
34316007Sthurlow
34326007Sthurlow sa_protocol_properties_t
sa_get_protocol_section(sa_protocol_properties_t propset,char * section)34336007Sthurlow sa_get_protocol_section(sa_protocol_properties_t propset, char *section)
34346007Sthurlow {
34356007Sthurlow xmlNodePtr node = (xmlNodePtr)propset;
34366007Sthurlow xmlChar *value = NULL;
34376007Sthurlow char *proto;
34386007Sthurlow
34396007Sthurlow proto = sa_get_optionset_attr(propset, "type");
34408271SGordon.Ross@Sun.COM if ((sa_proto_get_featureset(proto) & SA_FEATURE_HAS_SECTIONS) == 0) {
34418271SGordon.Ross@Sun.COM if (proto != NULL)
34428271SGordon.Ross@Sun.COM sa_free_attr_string(proto);
34436007Sthurlow return (propset);
34448271SGordon.Ross@Sun.COM }
34456007Sthurlow
34466007Sthurlow for (node = node->children; node != NULL;
34476007Sthurlow node = node->next) {
34486007Sthurlow if (xmlStrcmp(node->name, (xmlChar *)"section") == 0) {
34496007Sthurlow if (section == NULL)
34506007Sthurlow break;
34516007Sthurlow value = xmlGetProp(node, (xmlChar *)"name");
34526007Sthurlow if (value != NULL &&
34536007Sthurlow xmlStrcasecmp(value, (xmlChar *)section) == 0) {
34546007Sthurlow break;
34556007Sthurlow }
34566007Sthurlow if (value != NULL) {
34576007Sthurlow xmlFree(value);
34586007Sthurlow value = NULL;
34596007Sthurlow }
34606007Sthurlow }
34616007Sthurlow }
34626007Sthurlow if (value != NULL)
34636007Sthurlow xmlFree(value);
34648271SGordon.Ross@Sun.COM if (proto != NULL)
34658271SGordon.Ross@Sun.COM sa_free_attr_string(proto);
34666007Sthurlow if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"section") != 0) {
34676007Sthurlow /*
34686007Sthurlow * avoid a non option node -- it is possible to be a
34696007Sthurlow * text node
34706007Sthurlow */
34716007Sthurlow node = NULL;
34726007Sthurlow }
34736007Sthurlow return ((sa_protocol_properties_t)node);
34746007Sthurlow }
34756007Sthurlow
34766007Sthurlow /*
34776007Sthurlow * sa_get_next_protocol_section(prop, find)
34786007Sthurlow *
34796007Sthurlow * Get the next protocol specific section in the list.
34806007Sthurlow */
34816007Sthurlow
34826007Sthurlow sa_property_t
sa_get_next_protocol_section(sa_property_t prop,char * find)34836007Sthurlow sa_get_next_protocol_section(sa_property_t prop, char *find)
34846007Sthurlow {
34856007Sthurlow xmlNodePtr node;
34866007Sthurlow xmlChar *value = NULL;
34876007Sthurlow char *proto;
34886007Sthurlow
34896007Sthurlow proto = sa_get_optionset_attr(prop, "type");
34908271SGordon.Ross@Sun.COM if ((sa_proto_get_featureset(proto) & SA_FEATURE_HAS_SECTIONS) == 0) {
34918271SGordon.Ross@Sun.COM if (proto != NULL)
34928271SGordon.Ross@Sun.COM sa_free_attr_string(proto);
34936007Sthurlow return ((sa_property_t)NULL);
34948271SGordon.Ross@Sun.COM }
34956007Sthurlow
34966007Sthurlow for (node = ((xmlNodePtr)prop)->next; node != NULL;
34976007Sthurlow node = node->next) {
34986007Sthurlow if (xmlStrcmp(node->name, (xmlChar *)"section") == 0) {
34996007Sthurlow if (find == NULL)
35006007Sthurlow break;
35016007Sthurlow value = xmlGetProp(node, (xmlChar *)"name");
35026007Sthurlow if (value != NULL &&
35036007Sthurlow xmlStrcasecmp(value, (xmlChar *)find) == 0) {
35046007Sthurlow break;
35056007Sthurlow }
35066007Sthurlow if (value != NULL) {
35076007Sthurlow xmlFree(value);
35086007Sthurlow value = NULL;
35096007Sthurlow }
35106007Sthurlow
35116007Sthurlow }
35126007Sthurlow }
35136007Sthurlow if (value != NULL)
35146007Sthurlow xmlFree(value);
35158271SGordon.Ross@Sun.COM if (proto != NULL)
35168271SGordon.Ross@Sun.COM sa_free_attr_string(proto);
35176007Sthurlow return ((sa_property_t)node);
35186007Sthurlow }
35196007Sthurlow
35206007Sthurlow /*
35213034Sdougm * sa_get_protocol_property(propset, prop)
35223034Sdougm *
35233034Sdougm * Get the specified protocol specific property. These are global to
35243034Sdougm * the protocol and not specific to a group or share.
35253034Sdougm */
35263034Sdougm
35273034Sdougm sa_property_t
sa_get_protocol_property(sa_protocol_properties_t propset,char * prop)35283034Sdougm sa_get_protocol_property(sa_protocol_properties_t propset, char *prop)
35293034Sdougm {
35303034Sdougm xmlNodePtr node = (xmlNodePtr)propset;
35313034Sdougm xmlChar *value = NULL;
35323034Sdougm
35336007Sthurlow if (propset == NULL)
35346007Sthurlow return (NULL);
35356007Sthurlow
35363034Sdougm for (node = node->children; node != NULL;
35374327Sdougm node = node->next) {
35384327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) {
35394327Sdougm if (prop == NULL)
35404327Sdougm break;
35414327Sdougm value = xmlGetProp(node, (xmlChar *)"type");
35424327Sdougm if (value != NULL &&
35434327Sdougm xmlStrcasecmp(value, (xmlChar *)prop) == 0) {
35444327Sdougm break;
35454327Sdougm }
35464327Sdougm if (value != NULL) {
35474327Sdougm xmlFree(value);
35484327Sdougm value = NULL;
35494327Sdougm }
35503034Sdougm }
35513034Sdougm }
35523034Sdougm if (value != NULL)
35533034Sdougm xmlFree(value);
35543034Sdougm if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"option") != 0) {
35554327Sdougm /*
35564327Sdougm * avoid a non option node -- it is possible to be a
35574327Sdougm * text node
35584327Sdougm */
35594327Sdougm node = NULL;
35603034Sdougm }
35613034Sdougm return ((sa_property_t)node);
35623034Sdougm }
35633034Sdougm
35643034Sdougm /*
35653034Sdougm * sa_get_next_protocol_property(prop)
35663034Sdougm *
35673034Sdougm * Get the next protocol specific property in the list.
35683034Sdougm */
35693034Sdougm
35703034Sdougm sa_property_t
sa_get_next_protocol_property(sa_property_t prop,char * find)35716007Sthurlow sa_get_next_protocol_property(sa_property_t prop, char *find)
35723034Sdougm {
35733034Sdougm xmlNodePtr node;
35746007Sthurlow xmlChar *value = NULL;
35753034Sdougm
35763034Sdougm for (node = ((xmlNodePtr)prop)->next; node != NULL;
35774327Sdougm node = node->next) {
35783034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) {
35796007Sthurlow if (find == NULL)
35806007Sthurlow break;
35816007Sthurlow value = xmlGetProp(node, (xmlChar *)"type");
35826007Sthurlow if (value != NULL &&
35836007Sthurlow xmlStrcasecmp(value, (xmlChar *)find) == 0) {
35846007Sthurlow break;
35856007Sthurlow }
35866007Sthurlow if (value != NULL) {
35876007Sthurlow xmlFree(value);
35886007Sthurlow value = NULL;
35896007Sthurlow }
35906007Sthurlow
35913034Sdougm }
35923034Sdougm }
35936007Sthurlow if (value != NULL)
35946007Sthurlow xmlFree(value);
35953034Sdougm return ((sa_property_t)node);
35963034Sdougm }
35973034Sdougm
35983034Sdougm /*
35993034Sdougm * sa_set_protocol_property(prop, value)
36003034Sdougm *
36013034Sdougm * Set the specified property to have the new value. The protocol
36023034Sdougm * specific plugin will then be called to update the property.
36033034Sdougm */
36043034Sdougm
36053034Sdougm int
sa_set_protocol_property(sa_property_t prop,char * section,char * value)36066007Sthurlow sa_set_protocol_property(sa_property_t prop, char *section, char *value)
36073034Sdougm {
36083034Sdougm sa_protocol_properties_t propset;
36093034Sdougm char *proto;
36103034Sdougm int ret = SA_INVALID_PROTOCOL;
36113034Sdougm
36123034Sdougm propset = ((xmlNodePtr)prop)->parent;
36133034Sdougm if (propset != NULL) {
36144327Sdougm proto = sa_get_optionset_attr(propset, "type");
36154327Sdougm if (proto != NULL) {
36166007Sthurlow if (section != NULL)
36176007Sthurlow set_node_attr((xmlNodePtr)prop, "section",
36186007Sthurlow section);
36194327Sdougm set_node_attr((xmlNodePtr)prop, "value", value);
36204327Sdougm ret = sa_proto_set_property(proto, prop);
36214327Sdougm sa_free_attr_string(proto);
36224327Sdougm }
36233034Sdougm }
36243034Sdougm return (ret);
36253034Sdougm }
36263034Sdougm
36273034Sdougm /*
36283034Sdougm * sa_add_protocol_property(propset, prop)
36293034Sdougm *
36305331Samw * Add a new property to the protocol specific property set.
36313034Sdougm */
36323034Sdougm
36333034Sdougm int
sa_add_protocol_property(sa_protocol_properties_t propset,sa_property_t prop)36343034Sdougm sa_add_protocol_property(sa_protocol_properties_t propset, sa_property_t prop)
36353034Sdougm {
36363034Sdougm xmlNodePtr node;
36373034Sdougm
36383034Sdougm /* should check for legitimacy */
36393034Sdougm node = xmlAddChild((xmlNodePtr)propset, (xmlNodePtr)prop);
36403034Sdougm if (node != NULL)
36414327Sdougm return (SA_OK);
36423034Sdougm return (SA_NO_MEMORY);
36433034Sdougm }
36443034Sdougm
36453034Sdougm /*
36463034Sdougm * sa_create_protocol_properties(proto)
36473034Sdougm *
36485331Samw * Create a protocol specific property set.
36493034Sdougm */
36503034Sdougm
36513034Sdougm sa_protocol_properties_t
sa_create_protocol_properties(char * proto)36523034Sdougm sa_create_protocol_properties(char *proto)
36533034Sdougm {
36543034Sdougm xmlNodePtr node;
36554327Sdougm
36563034Sdougm node = xmlNewNode(NULL, (xmlChar *)"propertyset");
36574327Sdougm if (node != NULL)
36586007Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto);
36593034Sdougm return (node);
36603034Sdougm }
36615331Samw
36625331Samw /*
36635331Samw * sa_get_share_resource(share, resource)
36645331Samw *
36655331Samw * Get the named resource from the share, if it exists. If resource is
36665331Samw * NULL, get the first resource.
36675331Samw */
36685331Samw
36695331Samw sa_resource_t
sa_get_share_resource(sa_share_t share,char * resource)36705331Samw sa_get_share_resource(sa_share_t share, char *resource)
36715331Samw {
36725331Samw xmlNodePtr node = NULL;
36735331Samw xmlChar *name;
36745331Samw
36755331Samw if (share != NULL) {
36765331Samw for (node = ((xmlNodePtr)share)->children; node != NULL;
36775331Samw node = node->next) {
36785331Samw if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0) {
36795331Samw if (resource == NULL) {
36805331Samw /*
36815331Samw * We are looking for the first
36825331Samw * resource node and not a names
36835331Samw * resource.
36845331Samw */
36855331Samw break;
36865331Samw } else {
36875331Samw /* is it the correct share? */
36885331Samw name = xmlGetProp(node,
36895331Samw (xmlChar *)"name");
36905331Samw if (name != NULL &&
36915331Samw xmlStrcasecmp(name,
36925331Samw (xmlChar *)resource) == 0) {
36935331Samw xmlFree(name);
36945331Samw break;
36955331Samw }
36965331Samw xmlFree(name);
36975331Samw }
36985331Samw }
36995331Samw }
37005331Samw }
37015331Samw return ((sa_resource_t)node);
37025331Samw }
37035331Samw
37045331Samw /*
37055331Samw * sa_get_next_resource(resource)
37065331Samw * Return the next share following the specified share
37075331Samw * from the internal list of shares. Returns NULL if there
37085331Samw * are no more shares. The list is relative to the same
37095331Samw * group.
37105331Samw */
37115331Samw sa_share_t
sa_get_next_resource(sa_resource_t resource)37125331Samw sa_get_next_resource(sa_resource_t resource)
37135331Samw {
37145331Samw xmlNodePtr node = NULL;
37155331Samw
37165331Samw if (resource != NULL) {
37175331Samw for (node = ((xmlNodePtr)resource)->next; node != NULL;
37185331Samw node = node->next) {
37195331Samw if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0)
37205331Samw break;
37215331Samw }
37225331Samw }
37235331Samw return ((sa_share_t)node);
37245331Samw }
37255331Samw
37265331Samw /*
37275331Samw * _sa_get_next_resource_index(share)
37285331Samw *
37295331Samw * get the next resource index number (one greater then current largest)
37305331Samw */
37315331Samw
37325331Samw static int
_sa_get_next_resource_index(sa_share_t share)37335331Samw _sa_get_next_resource_index(sa_share_t share)
37345331Samw {
37355331Samw sa_resource_t resource;
37365331Samw int index = 0;
37375331Samw char *id;
37385331Samw
37395331Samw for (resource = sa_get_share_resource(share, NULL);
37405331Samw resource != NULL;
37415331Samw resource = sa_get_next_resource(resource)) {
37425331Samw id = get_node_attr((void *)resource, "id");
37435331Samw if (id != NULL) {
37445331Samw int val;
37455331Samw val = atoi(id);
37465331Samw if (val > index)
37475331Samw index = val;
37485331Samw sa_free_attr_string(id);
37495331Samw }
37505331Samw }
37515331Samw return (index + 1);
37525331Samw }
37535331Samw
37545331Samw
37555331Samw /*
37565331Samw * sa_add_resource(share, resource, persist, &err)
37575331Samw *
37585331Samw * Adds a new resource name associated with share. The resource name
37595331Samw * must be unique in the system and will be case insensitive (eventually).
37605331Samw */
37615331Samw
37625331Samw sa_resource_t
sa_add_resource(sa_share_t share,char * resource,int persist,int * error)37635331Samw sa_add_resource(sa_share_t share, char *resource, int persist, int *error)
37645331Samw {
37655331Samw xmlNodePtr node;
37665331Samw int err = SA_OK;
37675331Samw sa_resource_t res;
37685331Samw sa_group_t group;
37695331Samw sa_handle_t handle;
37705331Samw char istring[8]; /* just big enough for an integer value */
37715331Samw int index;
37725331Samw
37735331Samw group = sa_get_parent_group(share);
37745331Samw handle = sa_find_group_handle(group);
37755331Samw res = sa_find_resource(handle, resource);
37765331Samw if (res != NULL) {
37775331Samw err = SA_DUPLICATE_NAME;
37785331Samw res = NULL;
37795331Samw } else {
37805331Samw node = xmlNewChild((xmlNodePtr)share, NULL,
37815331Samw (xmlChar *)"resource", NULL);
37825331Samw if (node != NULL) {
37836007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name",
37845331Samw (xmlChar *)resource);
37856007Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", persist ?
37865331Samw (xmlChar *)"persist" : (xmlChar *)"transient");
37875331Samw if (persist != SA_SHARE_TRANSIENT) {
37885331Samw index = _sa_get_next_resource_index(share);
37895331Samw (void) snprintf(istring, sizeof (istring), "%d",
37905331Samw index);
37916007Sthurlow (void) xmlSetProp(node, (xmlChar *)"id",
37925331Samw (xmlChar *)istring);
37937483SDoug.McCallum@Sun.COM
37947483SDoug.McCallum@Sun.COM if (!sa_is_persistent((sa_group_t)share))
37957483SDoug.McCallum@Sun.COM goto done;
37967483SDoug.McCallum@Sun.COM
37977483SDoug.McCallum@Sun.COM if (!sa_group_is_zfs(group)) {
37985331Samw /* ZFS doesn't use resource names */
37995331Samw sa_handle_impl_t ihandle;
38007483SDoug.McCallum@Sun.COM
38015331Samw ihandle = (sa_handle_impl_t)
38025331Samw sa_find_group_handle(
38035331Samw group);
38045331Samw if (ihandle != NULL)
38055331Samw err = sa_commit_share(
38065331Samw ihandle->scfhandle, group,
38075331Samw share);
38085331Samw else
38095331Samw err = SA_SYSTEM_ERR;
38107483SDoug.McCallum@Sun.COM } else {
38117483SDoug.McCallum@Sun.COM err = sa_zfs_update((sa_share_t)group);
38125331Samw }
38135331Samw }
38145331Samw }
38155331Samw }
38167483SDoug.McCallum@Sun.COM done:
38175331Samw if (error != NULL)
38185331Samw *error = err;
38195331Samw return ((sa_resource_t)node);
38205331Samw }
38215331Samw
38225331Samw /*
38235331Samw * sa_remove_resource(resource)
38245331Samw *
38255331Samw * Remove the resource name from the share (and the system)
38265331Samw */
38275331Samw
38285331Samw int
sa_remove_resource(sa_resource_t resource)38295331Samw sa_remove_resource(sa_resource_t resource)
38305331Samw {
38315331Samw sa_share_t share;
38325331Samw sa_group_t group;
38335331Samw char *type;
38345331Samw int ret = SA_OK;
38357483SDoug.McCallum@Sun.COM boolean_t transient = B_FALSE;
38365521Sas200622 sa_optionset_t opt;
38375331Samw
38385331Samw share = sa_get_resource_parent(resource);
38395331Samw type = sa_get_share_attr(share, "type");
38405331Samw group = sa_get_parent_group(share);
38415331Samw
38425331Samw
38435331Samw if (type != NULL) {
38445331Samw if (strcmp(type, "persist") != 0)
38457483SDoug.McCallum@Sun.COM transient = B_TRUE;
38465331Samw sa_free_attr_string(type);
38475331Samw }
38485331Samw
38495521Sas200622 /* Disable the resource for all protocols. */
38505521Sas200622 (void) sa_disable_resource(resource, NULL);
38515521Sas200622
38525521Sas200622 /* Remove any optionsets from the resource. */
38535521Sas200622 for (opt = sa_get_optionset(resource, NULL);
38545521Sas200622 opt != NULL;
38555521Sas200622 opt = sa_get_next_optionset(opt))
38565521Sas200622 (void) sa_destroy_optionset(opt);
38575521Sas200622
38585331Samw /* Remove from the share */
38595331Samw xmlUnlinkNode((xmlNode *)resource);
38605331Samw xmlFreeNode((xmlNode *)resource);
38615331Samw
38625331Samw /* only do SMF action if permanent and not ZFS */
38637483SDoug.McCallum@Sun.COM if (transient)
38647483SDoug.McCallum@Sun.COM return (ret);
38657483SDoug.McCallum@Sun.COM
38667483SDoug.McCallum@Sun.COM if (!sa_group_is_zfs(group)) {
38675331Samw sa_handle_impl_t ihandle;
38685331Samw ihandle = (sa_handle_impl_t)sa_find_group_handle(group);
38695331Samw if (ihandle != NULL)
38705331Samw ret = sa_commit_share(ihandle->scfhandle, group, share);
38715331Samw else
38725331Samw ret = SA_SYSTEM_ERR;
38737483SDoug.McCallum@Sun.COM } else {
38747483SDoug.McCallum@Sun.COM ret = sa_zfs_update((sa_share_t)group);
38755331Samw }
38768845Samw@Sun.COM
38775331Samw return (ret);
38785331Samw }
38795331Samw
38805331Samw /*
38818845Samw@Sun.COM * proto_rename_resource(handle, group, resource, newname)
38825331Samw *
38835331Samw * Helper function for sa_rename_resource that notifies the protocol
38845331Samw * of a resource name change prior to a config repository update.
38855331Samw */
38865331Samw static int
proto_rename_resource(sa_handle_t handle,sa_group_t group,sa_resource_t resource,char * newname)38875331Samw proto_rename_resource(sa_handle_t handle, sa_group_t group,
38885331Samw sa_resource_t resource, char *newname)
38895331Samw {
38905331Samw sa_optionset_t optionset;
38915331Samw int ret = SA_OK;
38925331Samw int err;
38935331Samw
38945331Samw for (optionset = sa_get_optionset(group, NULL);
38955331Samw optionset != NULL;
38965331Samw optionset = sa_get_next_optionset(optionset)) {
38975331Samw char *type;
38985331Samw type = sa_get_optionset_attr(optionset, "type");
38995331Samw if (type != NULL) {
39005331Samw err = sa_proto_rename_resource(handle, type, resource,
39015331Samw newname);
39025331Samw if (err != SA_OK)
39035331Samw ret = err;
39045331Samw sa_free_attr_string(type);
39055331Samw }
39065331Samw }
39075331Samw return (ret);
39085331Samw }
39095331Samw
39105331Samw /*
39115331Samw * sa_rename_resource(resource, newname)
39125331Samw *
39135331Samw * Rename the resource to the new name, if it is unique.
39145331Samw */
39155331Samw
39165331Samw int
sa_rename_resource(sa_resource_t resource,char * newname)39175331Samw sa_rename_resource(sa_resource_t resource, char *newname)
39185331Samw {
39195331Samw sa_share_t share;
39205331Samw sa_group_t group = NULL;
39215331Samw sa_resource_t target;
39225331Samw int ret = SA_CONFIG_ERR;
39235331Samw sa_handle_t handle = NULL;
39245331Samw
39255331Samw share = sa_get_resource_parent(resource);
39265331Samw if (share == NULL)
39275331Samw return (ret);
39285331Samw
39295331Samw group = sa_get_parent_group(share);
39305331Samw if (group == NULL)
39315331Samw return (ret);
39325331Samw
39335331Samw handle = (sa_handle_impl_t)sa_find_group_handle(group);
39345331Samw if (handle == NULL)
39355331Samw return (ret);
39365331Samw
39375331Samw target = sa_find_resource(handle, newname);
39385331Samw if (target != NULL) {
39395331Samw ret = SA_DUPLICATE_NAME;
39405331Samw } else {
39415331Samw /*
39425331Samw * Everything appears to be valid at this
39435331Samw * point. Change the name of the active share and then
39445331Samw * update the share in the appropriate repository.
39455331Samw */
39465331Samw ret = proto_rename_resource(handle, group, resource, newname);
39475331Samw set_node_attr(resource, "name", newname);
39487483SDoug.McCallum@Sun.COM
39497483SDoug.McCallum@Sun.COM if (!sa_is_persistent((sa_group_t)share))
39507483SDoug.McCallum@Sun.COM return (ret);
39517483SDoug.McCallum@Sun.COM
39527483SDoug.McCallum@Sun.COM if (!sa_group_is_zfs(group)) {
39535331Samw sa_handle_impl_t ihandle = (sa_handle_impl_t)handle;
39545331Samw ret = sa_commit_share(ihandle->scfhandle, group,
39555331Samw share);
39567483SDoug.McCallum@Sun.COM } else {
39577483SDoug.McCallum@Sun.COM ret = sa_zfs_update((sa_share_t)group);
39585331Samw }
39595331Samw }
39605331Samw return (ret);
39615331Samw }
39625331Samw
39635331Samw /*
39645331Samw * sa_get_resource_attr(resource, tag)
39655331Samw *
39665331Samw * Get the named attribute of the resource. "name" and "id" are
39675331Samw * currently defined. NULL if tag not defined.
39685331Samw */
39695331Samw
39705331Samw char *
sa_get_resource_attr(sa_resource_t resource,char * tag)39715331Samw sa_get_resource_attr(sa_resource_t resource, char *tag)
39725331Samw {
39735331Samw return (get_node_attr((void *)resource, tag));
39745331Samw }
39755331Samw
39765331Samw /*
39775331Samw * sa_set_resource_attr(resource, tag, value)
39785331Samw *
39795331Samw * Get the named attribute of the resource. "name" and "id" are
39805331Samw * currently defined. NULL if tag not defined. Currently we don't do
39815331Samw * much, but additional checking may be needed in the future.
39825331Samw */
39835331Samw
39845331Samw int
sa_set_resource_attr(sa_resource_t resource,char * tag,char * value)39855331Samw sa_set_resource_attr(sa_resource_t resource, char *tag, char *value)
39865331Samw {
39875331Samw set_node_attr((void *)resource, tag, value);
39885331Samw return (SA_OK);
39895331Samw }
39905331Samw
39915331Samw /*
39925331Samw * sa_get_resource_parent(resource_t)
39935331Samw *
39945331Samw * Returns the share associated with the resource.
39955331Samw */
39965331Samw
39975331Samw sa_share_t
sa_get_resource_parent(sa_resource_t resource)39985331Samw sa_get_resource_parent(sa_resource_t resource)
39995331Samw {
40005331Samw sa_share_t share = NULL;
40015331Samw
40025331Samw if (resource != NULL)
40035331Samw share = (sa_share_t)((xmlNodePtr)resource)->parent;
40045331Samw return (share);
40055331Samw }
40065331Samw
40075331Samw /*
40085331Samw * find_resource(group, name)
40095331Samw *
40105331Samw * Find the resource within the group.
40115331Samw */
40125331Samw
40135331Samw static sa_resource_t
find_resource(sa_group_t group,char * resname)40145331Samw find_resource(sa_group_t group, char *resname)
40155331Samw {
40165331Samw sa_share_t share;
40175331Samw sa_resource_t resource = NULL;
40185331Samw char *name;
40195331Samw
40205331Samw /* Iterate over all the shares and resources in the group. */
40215331Samw for (share = sa_get_share(group, NULL);
40225331Samw share != NULL && resource == NULL;
40235331Samw share = sa_get_next_share(share)) {
40245331Samw for (resource = sa_get_share_resource(share, NULL);
40255331Samw resource != NULL;
40265331Samw resource = sa_get_next_resource(resource)) {
40275331Samw name = sa_get_resource_attr(resource, "name");
40285331Samw if (name != NULL && xmlStrcasecmp((xmlChar*)name,
40295331Samw (xmlChar*)resname) == 0) {
40305331Samw sa_free_attr_string(name);
40315331Samw break;
40325331Samw }
40335331Samw if (name != NULL) {
40345331Samw sa_free_attr_string(name);
40355331Samw }
40365331Samw }
40375331Samw }
40385331Samw return (resource);
40395331Samw }
40405331Samw
40415331Samw /*
40425331Samw * sa_find_resource(name)
40435331Samw *
40445331Samw * Find the named resource in the system.
40455331Samw */
40465331Samw
40475331Samw sa_resource_t
sa_find_resource(sa_handle_t handle,char * name)40485331Samw sa_find_resource(sa_handle_t handle, char *name)
40495331Samw {
40505331Samw sa_group_t group;
40515331Samw sa_group_t zgroup;
40525331Samw sa_resource_t resource = NULL;
40535331Samw
40545331Samw /*
40555331Samw * Iterate over all groups and zfs subgroups and check for
40565331Samw * resource name in them.
40575331Samw */
40585331Samw for (group = sa_get_group(handle, NULL); group != NULL;
40595331Samw group = sa_get_next_group(group)) {
40605331Samw
40615331Samw if (is_zfs_group(group)) {
40625331Samw for (zgroup =
40635331Samw (sa_group_t)_sa_get_child_node((xmlNodePtr)group,
40645331Samw (xmlChar *)"group");
40655331Samw zgroup != NULL && resource == NULL;
40665331Samw zgroup = sa_get_next_group(zgroup)) {
40675331Samw resource = find_resource(zgroup, name);
40685331Samw }
40695331Samw } else {
40705331Samw resource = find_resource(group, name);
40715331Samw }
40725331Samw if (resource != NULL)
40735331Samw break;
40745331Samw }
40755331Samw return (resource);
40765331Samw }
40775331Samw
40785331Samw /*
40795331Samw * sa_get_resource(group, resource)
40805331Samw *
40815331Samw * Search all the shares in the specified group for a share with a
40825331Samw * resource name matching the one specified.
40835331Samw *
40845331Samw * In the future, it may be advantageous to allow group to be NULL and
40855331Samw * search all groups but that isn't needed at present.
40865331Samw */
40875331Samw
40885331Samw sa_resource_t
sa_get_resource(sa_group_t group,char * resource)40895331Samw sa_get_resource(sa_group_t group, char *resource)
40905331Samw {
40915331Samw sa_share_t share = NULL;
40925331Samw sa_resource_t res = NULL;
40935331Samw
40945331Samw if (resource != NULL) {
40955331Samw for (share = sa_get_share(group, NULL);
40965331Samw share != NULL && res == NULL;
40975331Samw share = sa_get_next_share(share)) {
40985331Samw res = sa_get_share_resource(share, resource);
40995331Samw }
41005331Samw }
41015331Samw return (res);
41025331Samw }
41035331Samw
41045331Samw /*
41056270Sdougm * get_protocol_list(optionset, object)
41066270Sdougm *
41076270Sdougm * Get the protocol optionset list for the object and add them as
41086270Sdougm * properties to optionset.
41096270Sdougm */
41106270Sdougm static int
get_protocol_list(sa_optionset_t optionset,void * object)41116270Sdougm get_protocol_list(sa_optionset_t optionset, void *object)
41126270Sdougm {
41136270Sdougm sa_property_t prop;
41146270Sdougm sa_optionset_t opts;
41156270Sdougm int ret = SA_OK;
41166270Sdougm
41176270Sdougm for (opts = sa_get_optionset(object, NULL);
41186270Sdougm opts != NULL;
41196270Sdougm opts = sa_get_next_optionset(opts)) {
41206270Sdougm char *type;
41216270Sdougm type = sa_get_optionset_attr(opts, "type");
41226270Sdougm /*
41236270Sdougm * It is possible to have a non-protocol optionset. We
41246270Sdougm * skip any of those found.
41256270Sdougm */
41266270Sdougm if (type == NULL)
41276270Sdougm continue;
41286270Sdougm prop = sa_create_property(type, "true");
41296270Sdougm sa_free_attr_string(type);
41306270Sdougm if (prop != NULL)
41316270Sdougm prop = (sa_property_t)xmlAddChild((xmlNodePtr)optionset,
41326270Sdougm (xmlNodePtr)prop);
41336270Sdougm /* If prop is NULL, don't bother continuing */
41346270Sdougm if (prop == NULL) {
41356270Sdougm ret = SA_NO_MEMORY;
41366270Sdougm break;
41376270Sdougm }
41386270Sdougm }
41396270Sdougm return (ret);
41406270Sdougm }
41416270Sdougm
41426270Sdougm /*
41436270Sdougm * sa_free_protoset(optionset)
41446270Sdougm *
41456270Sdougm * Free the protocol property optionset.
41466270Sdougm */
41476270Sdougm static void
sa_free_protoset(sa_optionset_t optionset)41486270Sdougm sa_free_protoset(sa_optionset_t optionset)
41496270Sdougm {
41506270Sdougm if (optionset != NULL) {
41516270Sdougm xmlUnlinkNode((xmlNodePtr) optionset);
41526270Sdougm xmlFreeNode((xmlNodePtr) optionset);
41536270Sdougm }
41546270Sdougm }
41556270Sdougm
41566270Sdougm /*
41576270Sdougm * sa_optionset_t sa_get_active_protocols(object)
41586270Sdougm *
41596270Sdougm * Return a list of the protocols that are active for the object.
41606270Sdougm * This is currently an internal helper function, but could be
41616270Sdougm * made visible if there is enough demand for it.
41626270Sdougm *
41636270Sdougm * The function finds the parent group and extracts the protocol
41646270Sdougm * optionsets creating a new optionset with the protocols as properties.
41656270Sdougm *
41666270Sdougm * The caller must free the returned optionset.
41676270Sdougm */
41686270Sdougm
41696270Sdougm static sa_optionset_t
sa_get_active_protocols(void * object)41706270Sdougm sa_get_active_protocols(void *object)
41716270Sdougm {
41726270Sdougm sa_optionset_t options;
41736270Sdougm sa_share_t share = NULL;
41746270Sdougm sa_group_t group = NULL;
41756270Sdougm sa_resource_t resource = NULL;
41766270Sdougm int ret = SA_OK;
41776270Sdougm
41786270Sdougm if (object == NULL)
41796270Sdougm return (NULL);
41806270Sdougm options = (sa_optionset_t)xmlNewNode(NULL, (xmlChar *)"optionset");
41816270Sdougm if (options == NULL)
41826270Sdougm return (NULL);
41836270Sdougm
41846270Sdougm /*
41856270Sdougm * Find the objects up the tree that might have protocols
41866270Sdougm * enabled on them.
41876270Sdougm */
41886270Sdougm if (sa_is_resource(object)) {
41896270Sdougm resource = (sa_resource_t)object;
41906270Sdougm share = sa_get_resource_parent(resource);
41916270Sdougm group = sa_get_parent_group(share);
41926270Sdougm } else if (sa_is_share(object)) {
41936270Sdougm share = (sa_share_t)object;
41946270Sdougm group = sa_get_parent_group(share);
41956270Sdougm } else {
41966270Sdougm group = (sa_group_t)group;
41976270Sdougm }
41986270Sdougm if (resource != NULL)
41996270Sdougm ret = get_protocol_list(options, resource);
42006270Sdougm if (ret == SA_OK && share != NULL)
42016270Sdougm ret = get_protocol_list(options, share);
42026270Sdougm if (ret == SA_OK && group != NULL)
42036270Sdougm ret = get_protocol_list(options, group);
42046270Sdougm
42056270Sdougm /*
42066270Sdougm * If there was an error, we won't have a complete list so
42076270Sdougm * abandon everything. The caller will have to deal with the
42086270Sdougm * issue.
42096270Sdougm */
42106270Sdougm if (ret != SA_OK) {
42116270Sdougm sa_free_protoset(options);
42126270Sdougm options = NULL;
42136270Sdougm }
42146270Sdougm return (options);
42156270Sdougm }
42166270Sdougm
42176270Sdougm /*
42185331Samw * sa_enable_resource, protocol)
42195331Samw * Disable the specified share to the specified protocol.
42205331Samw * If protocol is NULL, then all protocols.
42215331Samw */
42225331Samw int
sa_enable_resource(sa_resource_t resource,char * protocol)42235331Samw sa_enable_resource(sa_resource_t resource, char *protocol)
42245331Samw {
42255331Samw int ret = SA_OK;
42265331Samw
42275331Samw if (protocol != NULL) {
42285331Samw ret = sa_proto_share_resource(protocol, resource);
42295331Samw } else {
42306270Sdougm sa_optionset_t protoset;
42316270Sdougm sa_property_t prop;
42326270Sdougm char *proto;
42336270Sdougm int err;
42346270Sdougm
42355331Samw /* need to do all protocols */
42366270Sdougm protoset = sa_get_active_protocols(resource);
42376270Sdougm if (protoset == NULL)
42386270Sdougm return (SA_NO_MEMORY);
42396270Sdougm for (prop = sa_get_property(protoset, NULL);
42406270Sdougm prop != NULL;
42416270Sdougm prop = sa_get_next_property(prop)) {
42426270Sdougm proto = sa_get_property_attr(prop, "type");
42436270Sdougm if (proto == NULL) {
42446270Sdougm ret = SA_NO_MEMORY;
42456270Sdougm continue;
42465331Samw }
42476270Sdougm err = sa_proto_share_resource(proto, resource);
42486270Sdougm if (err != SA_OK)
42496270Sdougm ret = err;
42506270Sdougm sa_free_attr_string(proto);
42515331Samw }
42526270Sdougm sa_free_protoset(protoset);
42535331Samw }
42545331Samw if (ret == SA_OK)
42555331Samw (void) sa_set_resource_attr(resource, "shared", NULL);
42565331Samw
42575331Samw return (ret);
42585331Samw }
42595331Samw
42605331Samw /*
42615331Samw * sa_disable_resource(resource, protocol)
42625331Samw *
42635331Samw * Disable the specified share for the specified protocol. If
42645331Samw * protocol is NULL, then all protocols. If the underlying
42655331Samw * protocol doesn't implement disable at the resource level, we
42665331Samw * disable at the share level.
42675331Samw */
42685331Samw int
sa_disable_resource(sa_resource_t resource,char * protocol)42695331Samw sa_disable_resource(sa_resource_t resource, char *protocol)
42705331Samw {
42715331Samw int ret = SA_OK;
42725331Samw
42735331Samw if (protocol != NULL) {
42745331Samw ret = sa_proto_unshare_resource(protocol, resource);
42755331Samw if (ret == SA_NOT_IMPLEMENTED) {
42765331Samw sa_share_t parent;
42775331Samw /*
42785331Samw * The protocol doesn't implement unshare
42795331Samw * resource. That implies that resource names are
42805331Samw * simple aliases for this protocol so we need to
42815331Samw * unshare the share.
42825331Samw */
42835331Samw parent = sa_get_resource_parent(resource);
42845331Samw if (parent != NULL)
42855331Samw ret = sa_disable_share(parent, protocol);
42865331Samw else
42875331Samw ret = SA_CONFIG_ERR;
42885331Samw }
42895331Samw } else {
42906270Sdougm sa_optionset_t protoset;
42916270Sdougm sa_property_t prop;
42926270Sdougm char *proto;
42936270Sdougm int err;
42946270Sdougm
42955331Samw /* need to do all protocols */
42966270Sdougm protoset = sa_get_active_protocols(resource);
42976270Sdougm if (protoset == NULL)
42986270Sdougm return (SA_NO_MEMORY);
42996270Sdougm for (prop = sa_get_property(protoset, NULL);
43006270Sdougm prop != NULL;
43016270Sdougm prop = sa_get_next_property(prop)) {
43026270Sdougm proto = sa_get_property_attr(prop, "type");
43036270Sdougm if (proto == NULL) {
43046270Sdougm ret = SA_NO_MEMORY;
43056270Sdougm continue;
43065331Samw }
43076270Sdougm err = sa_proto_unshare_resource(proto, resource);
43086270Sdougm if (err == SA_NOT_SUPPORTED) {
43096270Sdougm sa_share_t parent;
43106270Sdougm parent = sa_get_resource_parent(resource);
43116270Sdougm if (parent != NULL)
43126270Sdougm err = sa_disable_share(parent, proto);
43136270Sdougm else
43146270Sdougm err = SA_CONFIG_ERR;
43156270Sdougm }
43166270Sdougm if (err != SA_OK)
43176270Sdougm ret = err;
43186270Sdougm sa_free_attr_string(proto);
43195331Samw }
43206270Sdougm sa_free_protoset(protoset);
43215331Samw }
43225331Samw if (ret == SA_OK)
43235331Samw (void) sa_set_resource_attr(resource, "shared", NULL);
43245331Samw
43255331Samw return (ret);
43265331Samw }
43275331Samw
43285331Samw /*
43295331Samw * sa_set_resource_description(resource, content)
43305331Samw *
43315331Samw * Set the description of share to content.
43325331Samw */
43335331Samw
43345331Samw int
sa_set_resource_description(sa_resource_t resource,char * content)43355331Samw sa_set_resource_description(sa_resource_t resource, char *content)
43365331Samw {
43375331Samw xmlNodePtr node;
43385331Samw sa_group_t group;
43395331Samw sa_share_t share;
43405331Samw int ret = SA_OK;
43415331Samw
43425331Samw for (node = ((xmlNodePtr)resource)->children;
43435331Samw node != NULL;
43445331Samw node = node->next) {
43455331Samw if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) {
43465331Samw break;
43475331Samw }
43485331Samw }
43495331Samw
43505331Samw /* no existing description but want to add */
43515331Samw if (node == NULL && content != NULL) {
43525331Samw /* add a description */
43535331Samw node = _sa_set_share_description(resource, content);
43545331Samw } else if (node != NULL && content != NULL) {
43555331Samw /* update a description */
43565331Samw xmlNodeSetContent(node, (xmlChar *)content);
43575331Samw } else if (node != NULL && content == NULL) {
43585331Samw /* remove an existing description */
43595331Samw xmlUnlinkNode(node);
43605331Samw xmlFreeNode(node);
43615331Samw }
436212508Samw@Sun.COM
43635331Samw share = sa_get_resource_parent(resource);
43645331Samw group = sa_get_parent_group(share);
436512508Samw@Sun.COM if (group != NULL &&
436612508Samw@Sun.COM sa_is_persistent(share) && (!sa_group_is_zfs(group))) {
43675331Samw sa_handle_impl_t impl_handle;
43685331Samw impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
43695331Samw if (impl_handle != NULL)
43705331Samw ret = sa_commit_share(impl_handle->scfhandle,
43715331Samw group, share);
43725331Samw else
43735331Samw ret = SA_SYSTEM_ERR;
43745331Samw }
43755331Samw return (ret);
43765331Samw }
43775331Samw
43785331Samw /*
43795331Samw * sa_get_resource_description(share)
43805331Samw *
43815331Samw * Return the description text for the specified share if it
43825331Samw * exists. NULL if no description exists.
43835331Samw */
43845331Samw
43855331Samw char *
sa_get_resource_description(sa_resource_t resource)43865331Samw sa_get_resource_description(sa_resource_t resource)
43875331Samw {
43885331Samw xmlChar *description = NULL;
43895331Samw xmlNodePtr node;
43905331Samw
43915331Samw for (node = ((xmlNodePtr)resource)->children; node != NULL;
43925331Samw node = node->next) {
43935331Samw if (xmlStrcmp(node->name, (xmlChar *)"description") == 0)
43945331Samw break;
43955331Samw }
43965331Samw if (node != NULL) {
43975331Samw description = xmlNodeGetContent(node);
43985331Samw fixproblemchars((char *)description);
43995331Samw }
44005331Samw return ((char *)description);
44015331Samw }
4402