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 /* 235772Sas200622 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 243034Sdougm * Use is subject to license terms. 253034Sdougm */ 263034Sdougm 273034Sdougm #pragma ident "%Z%%M% %I% %E% SMI" 283034Sdougm 293034Sdougm /* 303034Sdougm * Share control API 313034Sdougm */ 323034Sdougm #include <stdio.h> 333034Sdougm #include <string.h> 343034Sdougm #include <ctype.h> 353034Sdougm #include <sys/types.h> 363034Sdougm #include <sys/stat.h> 373663Sdougm #include <fcntl.h> 383034Sdougm #include <unistd.h> 393034Sdougm #include <libxml/parser.h> 403034Sdougm #include <libxml/tree.h> 413034Sdougm #include "libshare.h" 423034Sdougm #include "libshare_impl.h" 433034Sdougm #include <libscf.h> 443034Sdougm #include "scfutil.h" 453034Sdougm #include <ctype.h> 463034Sdougm #include <libintl.h> 473910Sdougm #include <thread.h> 483910Sdougm #include <synch.h> 493034Sdougm 503663Sdougm #define DFS_LOCK_FILE "/etc/dfs/fstypes" 514327Sdougm #define SA_STRSIZE 256 /* max string size for names */ 523663Sdougm 533034Sdougm /* 545331Samw * internal object type values returned by sa_get_object_type() 555331Samw */ 565331Samw #define SA_TYPE_UNKNOWN 0 575331Samw #define SA_TYPE_GROUP 1 585331Samw #define SA_TYPE_SHARE 2 595331Samw #define SA_TYPE_RESOURCE 3 605331Samw #define SA_TYPE_OPTIONSET 4 615331Samw #define SA_TYPE_ALTSPACE 5 625331Samw 635331Samw /* 643034Sdougm * internal data structures 653034Sdougm */ 663034Sdougm 673034Sdougm extern struct sa_proto_plugin *sap_proto_list; 683034Sdougm 693034Sdougm /* current SMF/SVC repository handle */ 703910Sdougm extern void getlegacyconfig(sa_handle_t, char *, xmlNodePtr *); 713910Sdougm extern int gettransients(sa_handle_impl_t, xmlNodePtr *); 723034Sdougm extern int sa_valid_property(void *, char *, sa_property_t); 733034Sdougm extern char *sa_fstype(char *); 743034Sdougm extern int sa_is_share(void *); 755331Samw extern int sa_is_resource(void *); 763034Sdougm extern ssize_t scf_max_name_len; /* defined in scfutil during initialization */ 773034Sdougm extern int sa_group_is_zfs(sa_group_t); 783034Sdougm extern int sa_path_is_zfs(char *); 793034Sdougm extern int sa_zfs_set_sharenfs(sa_group_t, char *, int); 805331Samw extern int sa_zfs_set_sharesmb(sa_group_t, char *, int); 813910Sdougm extern void update_legacy_config(sa_handle_t); 823034Sdougm extern int issubdir(char *, char *); 834327Sdougm extern int sa_zfs_init(sa_handle_impl_t); 843910Sdougm extern void sa_zfs_fini(sa_handle_impl_t); 853663Sdougm extern void sablocksigs(sigset_t *); 863663Sdougm extern void saunblocksigs(sigset_t *); 875331Samw static sa_group_t sa_get_optionset_parent(sa_optionset_t); 885331Samw static char *get_node_attr(void *, char *); 89*5951Sdougm extern void sa_update_sharetab_ts(sa_handle_t); 903034Sdougm 913910Sdougm /* 923910Sdougm * Data structures for finding/managing the document root to access 933910Sdougm * handle mapping. The list isn't expected to grow very large so a 943910Sdougm * simple list is acceptable. The purpose is to provide a way to start 953910Sdougm * with a group or share and find the library handle needed for 963910Sdougm * various operations. 973910Sdougm */ 983910Sdougm mutex_t sa_global_lock; 993910Sdougm struct doc2handle { 1003910Sdougm struct doc2handle *next; 1013910Sdougm xmlNodePtr root; 1023910Sdougm sa_handle_impl_t handle; 1033910Sdougm }; 1043910Sdougm 1054327Sdougm /* definitions used in a couple of property functions */ 1064327Sdougm #define SA_PROP_OP_REMOVE 1 1074327Sdougm #define SA_PROP_OP_ADD 2 1084327Sdougm #define SA_PROP_OP_UPDATE 3 1094327Sdougm 1103910Sdougm static struct doc2handle *sa_global_handles = NULL; 1113034Sdougm 1123034Sdougm /* helper functions */ 1133034Sdougm 1143910Sdougm /* 1153910Sdougm * sa_errorstr(err) 1163910Sdougm * 1173910Sdougm * convert an error value to an error string 1183910Sdougm */ 1193910Sdougm 1203034Sdougm char * 1213034Sdougm sa_errorstr(int err) 1223034Sdougm { 1233034Sdougm static char errstr[32]; 1243034Sdougm char *ret = NULL; 1253034Sdougm 1263034Sdougm switch (err) { 1273034Sdougm case SA_OK: 1284327Sdougm ret = dgettext(TEXT_DOMAIN, "ok"); 1294327Sdougm break; 1303034Sdougm case SA_NO_SUCH_PATH: 1314327Sdougm ret = dgettext(TEXT_DOMAIN, "path doesn't exist"); 1324327Sdougm break; 1333034Sdougm case SA_NO_MEMORY: 1344327Sdougm ret = dgettext(TEXT_DOMAIN, "no memory"); 1354327Sdougm break; 1363034Sdougm case SA_DUPLICATE_NAME: 1374327Sdougm ret = dgettext(TEXT_DOMAIN, "name in use"); 1384327Sdougm break; 1393034Sdougm case SA_BAD_PATH: 1404327Sdougm ret = dgettext(TEXT_DOMAIN, "bad path"); 1414327Sdougm break; 1423034Sdougm case SA_NO_SUCH_GROUP: 1434327Sdougm ret = dgettext(TEXT_DOMAIN, "no such group"); 1444327Sdougm break; 1453034Sdougm case SA_CONFIG_ERR: 1464327Sdougm ret = dgettext(TEXT_DOMAIN, "configuration error"); 1474327Sdougm break; 1483034Sdougm case SA_SYSTEM_ERR: 1494327Sdougm ret = dgettext(TEXT_DOMAIN, "system error"); 1504327Sdougm break; 1513034Sdougm case SA_SYNTAX_ERR: 1524327Sdougm ret = dgettext(TEXT_DOMAIN, "syntax error"); 1534327Sdougm break; 1543034Sdougm case SA_NO_PERMISSION: 1554327Sdougm ret = dgettext(TEXT_DOMAIN, "no permission"); 1564327Sdougm break; 1573034Sdougm case SA_BUSY: 1584327Sdougm ret = dgettext(TEXT_DOMAIN, "busy"); 1594327Sdougm break; 1603034Sdougm case SA_NO_SUCH_PROP: 1614327Sdougm ret = dgettext(TEXT_DOMAIN, "no such property"); 1624327Sdougm break; 1633034Sdougm case SA_INVALID_NAME: 1644327Sdougm ret = dgettext(TEXT_DOMAIN, "invalid name"); 1654327Sdougm break; 1663034Sdougm case SA_INVALID_PROTOCOL: 1674327Sdougm ret = dgettext(TEXT_DOMAIN, "invalid protocol"); 1684327Sdougm break; 1693034Sdougm case SA_NOT_ALLOWED: 1704327Sdougm ret = dgettext(TEXT_DOMAIN, "operation not allowed"); 1714327Sdougm break; 1723034Sdougm case SA_BAD_VALUE: 1734327Sdougm ret = dgettext(TEXT_DOMAIN, "bad property value"); 1744327Sdougm break; 1753034Sdougm case SA_INVALID_SECURITY: 1764327Sdougm ret = dgettext(TEXT_DOMAIN, "invalid security type"); 1774327Sdougm break; 1783034Sdougm case SA_NO_SUCH_SECURITY: 1794327Sdougm ret = dgettext(TEXT_DOMAIN, "security type not found"); 1804327Sdougm break; 1813034Sdougm case SA_VALUE_CONFLICT: 1824327Sdougm ret = dgettext(TEXT_DOMAIN, "property value conflict"); 1834327Sdougm break; 1843034Sdougm case SA_NOT_IMPLEMENTED: 1854327Sdougm ret = dgettext(TEXT_DOMAIN, "not implemented"); 1864327Sdougm break; 1873034Sdougm case SA_INVALID_PATH: 1884327Sdougm ret = dgettext(TEXT_DOMAIN, "invalid path"); 1894327Sdougm break; 1903034Sdougm case SA_NOT_SUPPORTED: 1914327Sdougm ret = dgettext(TEXT_DOMAIN, "operation not supported"); 1924327Sdougm break; 1933034Sdougm case SA_PROP_SHARE_ONLY: 1944327Sdougm ret = dgettext(TEXT_DOMAIN, "property not valid for group"); 1954327Sdougm break; 1963034Sdougm case SA_NOT_SHARED: 1974327Sdougm ret = dgettext(TEXT_DOMAIN, "not shared"); 1984327Sdougm break; 1995331Samw case SA_NO_SUCH_RESOURCE: 2005331Samw ret = dgettext(TEXT_DOMAIN, "no such resource"); 2015331Samw break; 2025331Samw case SA_RESOURCE_REQUIRED: 2035331Samw ret = dgettext(TEXT_DOMAIN, "resource name required"); 2045331Samw break; 2055331Samw case SA_MULTIPLE_ERROR: 2065331Samw ret = dgettext(TEXT_DOMAIN, "errors from multiple protocols"); 2075331Samw break; 2085331Samw case SA_PATH_IS_SUBDIR: 2095331Samw ret = dgettext(TEXT_DOMAIN, "path is a subpath of share"); 2105331Samw break; 2115331Samw case SA_PATH_IS_PARENTDIR: 2125331Samw ret = dgettext(TEXT_DOMAIN, "path is parent of a share"); 2135331Samw break; 2143034Sdougm default: 2154327Sdougm (void) snprintf(errstr, sizeof (errstr), 2164327Sdougm dgettext(TEXT_DOMAIN, "unknown %d"), err); 2174327Sdougm ret = errstr; 2183034Sdougm } 2193034Sdougm return (ret); 2203034Sdougm } 2213034Sdougm 2223034Sdougm /* 2233910Sdougm * Document root to active handle mapping functions. These are only 2243910Sdougm * used internally. A mutex is used to prevent access while the list 2253910Sdougm * is changing. In general, the list will be relatively short - one 2263910Sdougm * item per thread that has called sa_init(). 2273910Sdougm */ 2283910Sdougm 2293910Sdougm sa_handle_impl_t 2303910Sdougm get_handle_for_root(xmlNodePtr root) 2313910Sdougm { 2323910Sdougm struct doc2handle *item; 2333910Sdougm 2343910Sdougm (void) mutex_lock(&sa_global_lock); 2353910Sdougm for (item = sa_global_handles; item != NULL; item = item->next) { 2364327Sdougm if (item->root == root) 2374327Sdougm break; 2383910Sdougm } 2393910Sdougm (void) mutex_unlock(&sa_global_lock); 2403910Sdougm if (item != NULL) 2414327Sdougm return (item->handle); 2423910Sdougm return (NULL); 2433910Sdougm } 2443910Sdougm 2453910Sdougm static int 2463910Sdougm add_handle_for_root(xmlNodePtr root, sa_handle_impl_t handle) 2473910Sdougm { 2483910Sdougm struct doc2handle *item; 2493910Sdougm int ret = SA_NO_MEMORY; 2503910Sdougm 2513910Sdougm item = (struct doc2handle *)calloc(sizeof (struct doc2handle), 1); 2523910Sdougm if (item != NULL) { 2534327Sdougm item->root = root; 2544327Sdougm item->handle = handle; 2554327Sdougm (void) mutex_lock(&sa_global_lock); 2564327Sdougm item->next = sa_global_handles; 2574327Sdougm sa_global_handles = item; 2584327Sdougm (void) mutex_unlock(&sa_global_lock); 2594327Sdougm ret = SA_OK; 2603910Sdougm } 2613910Sdougm return (ret); 2623910Sdougm } 2633910Sdougm 2643910Sdougm /* 2653910Sdougm * remove_handle_for_root(root) 2663910Sdougm * 2673910Sdougm * Walks the list of handles and removes the one for this "root" from 2683910Sdougm * the list. It is up to the caller to free the data. 2693910Sdougm */ 2703910Sdougm 2713910Sdougm static void 2723910Sdougm remove_handle_for_root(xmlNodePtr root) 2733910Sdougm { 2743910Sdougm struct doc2handle *item, *prev; 2753910Sdougm 2763910Sdougm (void) mutex_lock(&sa_global_lock); 2773910Sdougm for (prev = NULL, item = sa_global_handles; item != NULL; 2784327Sdougm item = item->next) { 2794327Sdougm if (item->root == root) { 2804327Sdougm /* first in the list */ 2814327Sdougm if (prev == NULL) 2824327Sdougm sa_global_handles = sa_global_handles->next; 2834327Sdougm else 2844327Sdougm prev->next = item->next; 2854327Sdougm /* Item is out of the list so free the list structure */ 2864327Sdougm free(item); 2874327Sdougm break; 2883910Sdougm } 2894327Sdougm prev = item; 2903910Sdougm } 2913910Sdougm (void) mutex_unlock(&sa_global_lock); 2923910Sdougm } 2933910Sdougm 2943910Sdougm /* 2953910Sdougm * sa_find_group_handle(sa_group_t group) 2963910Sdougm * 2973910Sdougm * Find the sa_handle_t for the configuration associated with this 2983910Sdougm * group. 2993910Sdougm */ 3003910Sdougm sa_handle_t 3013910Sdougm sa_find_group_handle(sa_group_t group) 3023910Sdougm { 3033910Sdougm xmlNodePtr node = (xmlNodePtr)group; 3043910Sdougm sa_handle_t handle; 3053910Sdougm 3063910Sdougm while (node != NULL) { 3074327Sdougm if (strcmp((char *)(node->name), "sharecfg") == 0) { 3084327Sdougm /* have the root so get the handle */ 3094327Sdougm handle = (sa_handle_t)get_handle_for_root(node); 3104327Sdougm return (handle); 3114327Sdougm } 3124327Sdougm node = node->parent; 3133910Sdougm } 3143910Sdougm return (NULL); 3153910Sdougm } 3163910Sdougm 3173910Sdougm /* 3183034Sdougm * set_legacy_timestamp(root, path, timevalue) 3193034Sdougm * 3203034Sdougm * add the current timestamp value to the configuration for use in 3213034Sdougm * determining when to update the legacy files. For SMF, this 3223034Sdougm * property is kept in default/operation/legacy_timestamp 3233034Sdougm */ 3243034Sdougm 3253034Sdougm static void 3263034Sdougm set_legacy_timestamp(xmlNodePtr root, char *path, uint64_t tval) 3273034Sdougm { 3283034Sdougm xmlNodePtr node; 3293034Sdougm xmlChar *lpath = NULL; 3303910Sdougm sa_handle_impl_t handle; 3313910Sdougm 3323910Sdougm /* Have to have a handle or else we weren't initialized. */ 3333910Sdougm handle = get_handle_for_root(root); 3343910Sdougm if (handle == NULL) 3354327Sdougm return; 3363034Sdougm 3373034Sdougm for (node = root->xmlChildrenNode; node != NULL; 3384327Sdougm node = node->next) { 3394327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"legacy") == 0) { 3404327Sdougm /* a possible legacy node for this path */ 3414327Sdougm lpath = xmlGetProp(node, (xmlChar *)"path"); 3424327Sdougm if (lpath != NULL && 3434327Sdougm xmlStrcmp(lpath, (xmlChar *)path) == 0) { 3444327Sdougm xmlFree(lpath); 3454327Sdougm break; 3464327Sdougm } 3474327Sdougm if (lpath != NULL) 3484327Sdougm xmlFree(lpath); 3493034Sdougm } 3503034Sdougm } 3513034Sdougm if (node == NULL) { 3524327Sdougm /* need to create the first legacy timestamp node */ 3534327Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"legacy", NULL); 3543034Sdougm } 3553034Sdougm if (node != NULL) { 3564327Sdougm char tstring[32]; 3574327Sdougm int ret; 3583034Sdougm 3594327Sdougm (void) snprintf(tstring, sizeof (tstring), "%lld", tval); 3604327Sdougm xmlSetProp(node, (xmlChar *)"timestamp", (xmlChar *)tstring); 3614327Sdougm xmlSetProp(node, (xmlChar *)"path", (xmlChar *)path); 3624327Sdougm /* now commit to SMF */ 3634327Sdougm ret = sa_get_instance(handle->scfhandle, "default"); 3643034Sdougm if (ret == SA_OK) { 3654327Sdougm ret = sa_start_transaction(handle->scfhandle, 3664327Sdougm "operation"); 3674327Sdougm if (ret == SA_OK) { 3684327Sdougm ret = sa_set_property(handle->scfhandle, 3694327Sdougm "legacy-timestamp", tstring); 3704327Sdougm if (ret == SA_OK) { 3714327Sdougm (void) sa_end_transaction( 372*5951Sdougm handle->scfhandle, handle); 3734327Sdougm } else { 3744327Sdougm sa_abort_transaction(handle->scfhandle); 3754327Sdougm } 3764327Sdougm } 3773034Sdougm } 3783034Sdougm } 3793034Sdougm } 3803034Sdougm 3813034Sdougm /* 3823034Sdougm * is_shared(share) 3833034Sdougm * 3843034Sdougm * determine if the specified share is currently shared or not. 3853034Sdougm */ 3863034Sdougm static int 3873034Sdougm is_shared(sa_share_t share) 3883034Sdougm { 3893034Sdougm char *shared; 3903034Sdougm int result = 0; /* assume not */ 3913034Sdougm 3923034Sdougm shared = sa_get_share_attr(share, "shared"); 3933034Sdougm if (shared != NULL) { 3944327Sdougm if (strcmp(shared, "true") == 0) 3954327Sdougm result = 1; 3964327Sdougm sa_free_attr_string(shared); 3973034Sdougm } 3983034Sdougm return (result); 3993034Sdougm } 4003034Sdougm 4013034Sdougm /* 4025331Samw * excluded_protocol(share, proto) 4035331Samw * 4045331Samw * Returns B_TRUE if the specified protocol appears in the "exclude" 4055331Samw * property. This is used to prevent sharing special case shares 4065331Samw * (e.g. subdirs when SMB wants a subdir and NFS doesn't. B_FALSE is 4075331Samw * returned if the protocol isn't in the list. 4085331Samw */ 4095331Samw static boolean_t 4105331Samw excluded_protocol(sa_share_t share, char *proto) 4115331Samw { 4125331Samw char *protolist; 4135331Samw char *str; 4145331Samw char *token; 4155331Samw 4165331Samw protolist = sa_get_share_attr(share, "exclude"); 4175331Samw if (protolist != NULL) { 4185331Samw str = protolist; 4195331Samw while ((token = strtok(str, ",")) != NULL) { 4205331Samw if (strcmp(token, proto) == 0) { 4215331Samw sa_free_attr_string(protolist); 4225331Samw return (B_TRUE); 4235331Samw } 4245331Samw str = NULL; 4255331Samw } 4265331Samw sa_free_attr_string(protolist); 4275331Samw } 4285331Samw return (B_FALSE); 4295331Samw } 4305331Samw 4315331Samw /* 4323663Sdougm * checksubdirgroup(group, newpath, strictness) 4333348Sdougm * 4343663Sdougm * check all the specified newpath against all the paths in the 4353663Sdougm * group. This is a helper function for checksubdir to make it easier 4363663Sdougm * to also check ZFS subgroups. 4373663Sdougm * The strictness values mean: 4383348Sdougm * SA_CHECK_NORMAL == only check newpath against shares that are active 4393348Sdougm * SA_CHECK_STRICT == check newpath against both active shares and those 4403348Sdougm * stored in the repository 4413034Sdougm */ 4423034Sdougm static int 4433663Sdougm checksubdirgroup(sa_group_t group, char *newpath, int strictness) 4443034Sdougm { 4453034Sdougm sa_share_t share; 4463663Sdougm char *path; 4473663Sdougm int issub = SA_OK; 4485331Samw int subdir; 4495331Samw int parent; 4505331Samw 4515331Samw if (newpath == NULL) 4525331Samw return (SA_INVALID_PATH); 4533034Sdougm 4543663Sdougm for (share = sa_get_share(group, NULL); share != NULL; 4553663Sdougm share = sa_get_next_share(share)) { 4563034Sdougm /* 4573034Sdougm * The original behavior of share never checked 4583034Sdougm * against the permanent configuration 4593034Sdougm * (/etc/dfs/dfstab). PIT has a number of cases where 4603034Sdougm * it depends on this older behavior even though it 4613034Sdougm * could be considered incorrect. We may tighten this 4623034Sdougm * up in the future. 4633034Sdougm */ 4644327Sdougm if (strictness == SA_CHECK_NORMAL && !is_shared(share)) 4654327Sdougm continue; 4663034Sdougm 4674327Sdougm path = sa_get_share_attr(share, "path"); 4683348Sdougm /* 4693348Sdougm * If path is NULL, then a share is in the process of 4703348Sdougm * construction or someone has modified the property 4713663Sdougm * group inappropriately. It should be 4723663Sdougm * ignored. issubdir() comes from the original share 4733663Sdougm * implementation and does the difficult part of 4743663Sdougm * checking subdirectories. 4753348Sdougm */ 4764327Sdougm if (path == NULL) 4774327Sdougm continue; 4785331Samw 4795331Samw if (strcmp(path, newpath) == 0) { 4804327Sdougm issub = SA_INVALID_PATH; 4815331Samw } else { 4825331Samw subdir = issubdir(newpath, path); 4835331Samw parent = issubdir(path, newpath); 4845331Samw if (subdir || parent) { 4855331Samw sa_free_attr_string(path); 4865331Samw path = NULL; 4875331Samw return (subdir ? 4885331Samw SA_PATH_IS_SUBDIR : SA_PATH_IS_PARENTDIR); 4895331Samw } 4904327Sdougm } 4913034Sdougm sa_free_attr_string(path); 4923034Sdougm path = NULL; 4933663Sdougm } 4943663Sdougm return (issub); 4953663Sdougm } 4963663Sdougm 4973663Sdougm /* 4983663Sdougm * checksubdir(newpath, strictness) 4993663Sdougm * 5003663Sdougm * checksubdir determines if the specified path (newpath) is a 5013663Sdougm * subdirectory of another share. It calls checksubdirgroup() to do 5023663Sdougm * the complicated work. The strictness parameter determines how 5033663Sdougm * strict a check to make against the path. The strictness values 5043663Sdougm * mean: SA_CHECK_NORMAL == only check newpath against shares that are 5053663Sdougm * active SA_CHECK_STRICT == check newpath against both active shares 5063663Sdougm * and those * stored in the repository 5073663Sdougm */ 5083663Sdougm static int 5093910Sdougm checksubdir(sa_handle_t handle, char *newpath, int strictness) 5103663Sdougm { 5113663Sdougm sa_group_t group; 5125331Samw int issub = SA_OK; 5133663Sdougm char *path = NULL; 5143663Sdougm 5155331Samw for (group = sa_get_group(handle, NULL); 5165331Samw group != NULL && issub == SA_OK; 5175331Samw group = sa_get_next_group(group)) { 5184327Sdougm if (sa_group_is_zfs(group)) { 5194327Sdougm sa_group_t subgroup; 5204327Sdougm for (subgroup = sa_get_sub_group(group); 5215331Samw subgroup != NULL && issub == SA_OK; 5224327Sdougm subgroup = sa_get_next_group(subgroup)) 5234327Sdougm issub = checksubdirgroup(subgroup, newpath, 5244327Sdougm strictness); 5254327Sdougm } else { 5264327Sdougm issub = checksubdirgroup(group, newpath, strictness); 5274327Sdougm } 5283034Sdougm } 5293034Sdougm if (path != NULL) 5304327Sdougm sa_free_attr_string(path); 5313034Sdougm return (issub); 5323034Sdougm } 5333034Sdougm 5343034Sdougm /* 5353348Sdougm * validpath(path, strictness) 5363034Sdougm * determine if the provided path is valid for a share. It shouldn't 5373034Sdougm * be a sub-dir of an already shared path or the parent directory of a 5383034Sdougm * share path. 5393034Sdougm */ 5403034Sdougm static int 5413910Sdougm validpath(sa_handle_t handle, char *path, int strictness) 5423034Sdougm { 5433034Sdougm int error = SA_OK; 5443034Sdougm struct stat st; 5453034Sdougm sa_share_t share; 5463034Sdougm char *fstype; 5473034Sdougm 5484327Sdougm if (*path != '/') 5494327Sdougm return (SA_BAD_PATH); 5504327Sdougm 5513034Sdougm if (stat(path, &st) < 0) { 5524327Sdougm error = SA_NO_SUCH_PATH; 5533034Sdougm } else { 5544327Sdougm share = sa_find_share(handle, path); 5554327Sdougm if (share != NULL) 5564327Sdougm error = SA_DUPLICATE_NAME; 5574327Sdougm 5584327Sdougm if (error == SA_OK) { 5594327Sdougm /* 5604327Sdougm * check for special case with file system 5614327Sdougm * that might have restrictions. For now, ZFS 5624327Sdougm * is the only case since it has its own idea 5634327Sdougm * of how to configure shares. We do this 5644327Sdougm * before subdir checking since things like 5654327Sdougm * ZFS will do that for us. This should also 5664327Sdougm * be done via plugin interface. 5674327Sdougm */ 5684327Sdougm fstype = sa_fstype(path); 5694327Sdougm if (fstype != NULL && strcmp(fstype, "zfs") == 0) { 5704327Sdougm if (sa_zfs_is_shared(handle, path)) 5714327Sdougm error = SA_INVALID_NAME; 5724327Sdougm } 5734327Sdougm if (fstype != NULL) 5744327Sdougm sa_free_fstype(fstype); 5753034Sdougm } 5764327Sdougm if (error == SA_OK) 5774327Sdougm error = checksubdir(handle, path, strictness); 5783034Sdougm } 5793034Sdougm return (error); 5803034Sdougm } 5813034Sdougm 5823034Sdougm /* 5833034Sdougm * check to see if group/share is persistent. 5845331Samw * 5855331Samw * "group" can be either an sa_group_t or an sa_share_t. (void *) 5865331Samw * works since both thse types are also void *. 5873034Sdougm */ 5885331Samw int 5895331Samw sa_is_persistent(void *group) 5903034Sdougm { 5913034Sdougm char *type; 5923034Sdougm int persist = 1; 5933034Sdougm 5945331Samw type = sa_get_group_attr((sa_group_t)group, "type"); 5953034Sdougm if (type != NULL && strcmp(type, "transient") == 0) 5964327Sdougm persist = 0; 5973034Sdougm if (type != NULL) 5984327Sdougm sa_free_attr_string(type); 5993034Sdougm return (persist); 6003034Sdougm } 6013034Sdougm 6023034Sdougm /* 6033034Sdougm * sa_valid_group_name(name) 6043034Sdougm * 6053034Sdougm * check that the "name" contains only valid characters and otherwise 6063034Sdougm * fits the required naming conventions. Valid names must start with 6073034Sdougm * an alphabetic and the remainder may consist of only alphanumeric 6083034Sdougm * plus the '-' and '_' characters. This name limitation comes from 6093034Sdougm * inherent limitations in SMF. 6103034Sdougm */ 6113034Sdougm 6123034Sdougm int 6133034Sdougm sa_valid_group_name(char *name) 6143034Sdougm { 6153034Sdougm int ret = 1; 6163034Sdougm ssize_t len; 6173034Sdougm 6183034Sdougm if (name != NULL && isalpha(*name)) { 6194327Sdougm char c; 6204327Sdougm len = strlen(name); 6214327Sdougm if (len < (scf_max_name_len - sizeof ("group:"))) { 6224327Sdougm for (c = *name++; c != '\0' && ret != 0; c = *name++) { 6234327Sdougm if (!isalnum(c) && c != '-' && c != '_') 6244327Sdougm ret = 0; 6254327Sdougm } 6264327Sdougm } else { 6273034Sdougm ret = 0; 6283034Sdougm } 6294327Sdougm } else { 6303034Sdougm ret = 0; 6313034Sdougm } 6323034Sdougm return (ret); 6333034Sdougm } 6343034Sdougm 6353034Sdougm 6363034Sdougm /* 6373034Sdougm * is_zfs_group(group) 6383034Sdougm * Determine if the specified group is a ZFS sharenfs group 6393034Sdougm */ 6403034Sdougm static int 6413034Sdougm is_zfs_group(sa_group_t group) 6423034Sdougm { 6433034Sdougm int ret = 0; 6443034Sdougm xmlNodePtr parent; 6453034Sdougm xmlChar *zfs; 6463034Sdougm 6474327Sdougm if (strcmp((char *)((xmlNodePtr)group)->name, "share") == 0) 6484327Sdougm parent = (xmlNodePtr)sa_get_parent_group(group); 6494327Sdougm else 6504327Sdougm parent = (xmlNodePtr)group; 6513034Sdougm zfs = xmlGetProp(parent, (xmlChar *)"zfs"); 6523034Sdougm if (zfs != NULL) { 6534327Sdougm xmlFree(zfs); 6544327Sdougm ret = 1; 6553034Sdougm } 6563034Sdougm return (ret); 6573034Sdougm } 6583034Sdougm 6593034Sdougm /* 6605331Samw * sa_get_object_type(object) 6615331Samw * 6625331Samw * This function returns a numeric value representing the object 6635331Samw * type. This allows using simpler checks when doing type specific 6645331Samw * operations. 6655331Samw */ 6665331Samw 6675331Samw static int 6685331Samw sa_get_object_type(void *object) 6695331Samw { 6705331Samw xmlNodePtr node = (xmlNodePtr)object; 6715331Samw int type; 6725331Samw 6735331Samw if (xmlStrcmp(node->name, (xmlChar *)"group") == 0) 6745331Samw type = SA_TYPE_GROUP; 6755331Samw else if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) 6765331Samw type = SA_TYPE_SHARE; 6775331Samw else if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0) 6785331Samw type = SA_TYPE_RESOURCE; 6795331Samw else if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) 6805331Samw type = SA_TYPE_OPTIONSET; 6815331Samw else if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) 6825331Samw type = SA_TYPE_ALTSPACE; 6835331Samw else 6845331Samw assert(0); 6855331Samw return (type); 6865331Samw } 6875331Samw 6885331Samw /* 6893034Sdougm * sa_optionset_name(optionset, oname, len, id) 6903034Sdougm * return the SMF name for the optionset. If id is not NULL, it 6913034Sdougm * will have the GUID value for a share and should be used 6923034Sdougm * instead of the keyword "optionset" which is used for 6933034Sdougm * groups. If the optionset doesn't have a protocol type 6943034Sdougm * associated with it, "default" is used. This shouldn't happen 6953034Sdougm * at this point but may be desirable in the future if there are 6963034Sdougm * protocol independent properties added. The name is returned in 6973034Sdougm * oname. 6983034Sdougm */ 6993034Sdougm 7003034Sdougm static int 7013034Sdougm sa_optionset_name(sa_optionset_t optionset, char *oname, size_t len, char *id) 7023034Sdougm { 7033034Sdougm char *proto; 7045331Samw void *parent; 7055331Samw int ptype; 7063034Sdougm 7073034Sdougm if (id == NULL) 7084327Sdougm id = "optionset"; 7093034Sdougm 7105331Samw parent = sa_get_optionset_parent(optionset); 7115331Samw if (parent != NULL) { 7125331Samw ptype = sa_get_object_type(parent); 7135331Samw proto = sa_get_optionset_attr(optionset, "type"); 7145331Samw if (ptype != SA_TYPE_RESOURCE) { 7155331Samw len = snprintf(oname, len, "%s_%s", id, 7165331Samw proto ? proto : "default"); 7175331Samw } else { 7185331Samw char *index; 7195331Samw index = get_node_attr((void *)parent, "id"); 7205331Samw if (index != NULL) 7215331Samw len = snprintf(oname, len, "%s_%s_%s", id, 7225331Samw proto ? proto : "default", index); 7235331Samw else 7245331Samw len = 0; 7255331Samw } 7265331Samw 7275331Samw if (proto != NULL) 7285331Samw sa_free_attr_string(proto); 7295331Samw } else { 7305331Samw len = 0; 7315331Samw } 7323034Sdougm return (len); 7333034Sdougm } 7343034Sdougm 7353034Sdougm /* 7363034Sdougm * sa_security_name(optionset, oname, len, id) 7373034Sdougm * 7383034Sdougm * return the SMF name for the security. If id is not NULL, it will 7393034Sdougm * have the GUID value for a share and should be used instead of the 7403034Sdougm * keyword "optionset" which is used for groups. If the optionset 7413034Sdougm * doesn't have a protocol type associated with it, "default" is 7423034Sdougm * used. This shouldn't happen at this point but may be desirable in 7433034Sdougm * the future if there are protocol independent properties added. The 7443034Sdougm * name is returned in oname. The security type is also encoded into 7453034Sdougm * the name. In the future, this wil *be handled a bit differently. 7463034Sdougm */ 7473034Sdougm 7483034Sdougm static int 7493034Sdougm sa_security_name(sa_security_t security, char *oname, size_t len, char *id) 7503034Sdougm { 7513034Sdougm char *proto; 7523034Sdougm char *sectype; 7533034Sdougm 7543034Sdougm if (id == NULL) 7554327Sdougm id = "optionset"; 7563034Sdougm 7573034Sdougm proto = sa_get_security_attr(security, "type"); 7583034Sdougm sectype = sa_get_security_attr(security, "sectype"); 7594327Sdougm len = snprintf(oname, len, "%s_%s_%s", id, proto ? proto : "default", 7604327Sdougm sectype ? sectype : "default"); 7613034Sdougm if (proto != NULL) 7624327Sdougm sa_free_attr_string(proto); 7633034Sdougm if (sectype != NULL) 7644327Sdougm sa_free_attr_string(sectype); 7653034Sdougm return (len); 7663034Sdougm } 7673034Sdougm 7683034Sdougm /* 7694327Sdougm * verifydefgroupopts(handle) 7704327Sdougm * 7714327Sdougm * Make sure a "default" group exists and has default protocols enabled. 7724327Sdougm */ 7734327Sdougm static void 7744327Sdougm verifydefgroupopts(sa_handle_t handle) 7754327Sdougm { 7764327Sdougm sa_group_t defgrp; 7774327Sdougm sa_optionset_t opt; 7785331Samw 7794327Sdougm defgrp = sa_get_group(handle, "default"); 7804327Sdougm if (defgrp != NULL) { 7814327Sdougm opt = sa_get_optionset(defgrp, NULL); 7824327Sdougm /* 7834327Sdougm * NFS is the default for default group 7844327Sdougm */ 7854327Sdougm if (opt == NULL) 7864327Sdougm opt = sa_create_optionset(defgrp, "nfs"); 7874327Sdougm } 7884327Sdougm } 7894327Sdougm 7904327Sdougm /* 7913348Sdougm * sa_init(init_service) 7923034Sdougm * Initialize the API 7933034Sdougm * find all the shared objects 7943034Sdougm * init the tables with all objects 7953034Sdougm * read in the current configuration 7963034Sdougm */ 7973034Sdougm 7984327Sdougm #define GETPROP(prop) scf_simple_prop_next_astring(prop) 7994327Sdougm #define CHECKTSTAMP(st, tval) stat(SA_LEGACY_DFSTAB, &st) >= 0 && \ 8004327Sdougm tval != TSTAMP(st.st_ctim) 8014327Sdougm 8023910Sdougm sa_handle_t 8033034Sdougm sa_init(int init_service) 8043034Sdougm { 8053034Sdougm struct stat st; 8063034Sdougm int legacy = 0; 8073034Sdougm uint64_t tval = 0; 8083663Sdougm int lockfd; 8093663Sdougm sigset_t old; 8103663Sdougm int updatelegacy = B_FALSE; 8113663Sdougm scf_simple_prop_t *prop; 8123910Sdougm sa_handle_impl_t handle; 8133910Sdougm int err; 8143034Sdougm 8153910Sdougm handle = calloc(sizeof (struct sa_handle_impl), 1); 8163910Sdougm 8173910Sdougm if (handle != NULL) { 8184327Sdougm /* get protocol specific structures */ 8194327Sdougm (void) proto_plugin_init(); 8204327Sdougm if (init_service & SA_INIT_SHARE_API) { 8213663Sdougm /* 8224327Sdougm * initialize access into libzfs. We use this 8234327Sdougm * when collecting info about ZFS datasets and 8244327Sdougm * shares. 8253663Sdougm */ 8264327Sdougm if (sa_zfs_init(handle) == B_FALSE) { 8274327Sdougm free(handle); 8284327Sdougm (void) proto_plugin_fini(); 8294327Sdougm return (NULL); 8304327Sdougm } 8313663Sdougm /* 8324327Sdougm * since we want to use SMF, initialize an svc handle 8334327Sdougm * and find out what is there. 8343663Sdougm */ 8354327Sdougm handle->scfhandle = sa_scf_init(handle); 8364327Sdougm if (handle->scfhandle != NULL) { 8374327Sdougm /* 8384327Sdougm * Need to lock the extraction of the 8394327Sdougm * configuration if the dfstab file has 8404327Sdougm * changed. Lock everything now and release if 8414327Sdougm * not needed. Use a file that isn't being 8424327Sdougm * manipulated by other parts of the system in 8434327Sdougm * order to not interfere with locking. Using 8444327Sdougm * dfstab doesn't work. 8454327Sdougm */ 8464327Sdougm sablocksigs(&old); 8474327Sdougm lockfd = open(DFS_LOCK_FILE, O_RDWR); 8484327Sdougm if (lockfd >= 0) { 8494327Sdougm extern int errno; 8504327Sdougm errno = 0; 8514327Sdougm (void) lockf(lockfd, F_LOCK, 0); 8524327Sdougm /* 8534327Sdougm * Check whether we are going to need 8544327Sdougm * to merge any dfstab changes. This 8554327Sdougm * is done by comparing the value of 8564327Sdougm * legacy-timestamp with the current 8574327Sdougm * st_ctim of the file. If they are 8584327Sdougm * different, an update is needed and 8594327Sdougm * the file must remain locked until 8604327Sdougm * the merge is done in order to 8614327Sdougm * prevent multiple startups from 8624327Sdougm * changing the SMF repository at the 8634327Sdougm * same time. The first to get the 8644327Sdougm * lock will make any changes before 8654327Sdougm * the others can read the repository. 8664327Sdougm */ 8674327Sdougm prop = scf_simple_prop_get 8684327Sdougm (handle->scfhandle->handle, 8694327Sdougm (const char *)SA_SVC_FMRI_BASE 8704327Sdougm ":default", "operation", 8714327Sdougm "legacy-timestamp"); 8724327Sdougm if (prop != NULL) { 8734327Sdougm char *i64; 8744327Sdougm i64 = GETPROP(prop); 8754327Sdougm if (i64 != NULL) 8764327Sdougm tval = strtoull(i64, 8774327Sdougm NULL, 0); 8784327Sdougm if (CHECKTSTAMP(st, tval)) 8794327Sdougm updatelegacy = B_TRUE; 8804327Sdougm scf_simple_prop_free(prop); 8814327Sdougm } else { 8824327Sdougm /* 8834327Sdougm * We haven't set the 8844327Sdougm * timestamp before so do it. 8854327Sdougm */ 8864327Sdougm updatelegacy = B_TRUE; 8874327Sdougm } 8884327Sdougm } 8894327Sdougm if (updatelegacy == B_FALSE) { 8904327Sdougm /* Don't need the lock anymore */ 8914327Sdougm (void) lockf(lockfd, F_ULOCK, 0); 8924327Sdougm (void) close(lockfd); 8934327Sdougm } 8943973Sdougm 8954327Sdougm /* 8964327Sdougm * It is essential that the document tree and 8974327Sdougm * the internal list of roots to handles be 8984327Sdougm * setup before anything that might try to 8994327Sdougm * create a new object is called. The document 9004327Sdougm * tree is the combination of handle->doc and 9014327Sdougm * handle->tree. This allows searches, 9024327Sdougm * etc. when all you have is an object in the 9034327Sdougm * tree. 9044327Sdougm */ 9054327Sdougm handle->doc = xmlNewDoc((xmlChar *)"1.0"); 9064327Sdougm handle->tree = xmlNewNode(NULL, 9074327Sdougm (xmlChar *)"sharecfg"); 9084327Sdougm if (handle->doc != NULL && 9094327Sdougm handle->tree != NULL) { 9104327Sdougm xmlDocSetRootElement(handle->doc, 9114327Sdougm handle->tree); 9124327Sdougm err = add_handle_for_root(handle->tree, 9134327Sdougm handle); 9144327Sdougm if (err == SA_OK) 9154327Sdougm err = sa_get_config( 9164327Sdougm handle->scfhandle, 9173973Sdougm handle->tree, handle); 9184327Sdougm } else { 9194327Sdougm if (handle->doc != NULL) 9204327Sdougm xmlFreeDoc(handle->doc); 9214327Sdougm if (handle->tree != NULL) 9224327Sdougm xmlFreeNode(handle->tree); 9234327Sdougm err = SA_NO_MEMORY; 9244327Sdougm } 9253973Sdougm 9264327Sdougm saunblocksigs(&old); 9273910Sdougm 9284327Sdougm if (err != SA_OK) { 9294327Sdougm /* 9304327Sdougm * If we couldn't add the tree handle 9314327Sdougm * to the list, then things are going 9324327Sdougm * to fail badly. Might as well undo 9334327Sdougm * everything now and fail the 9344327Sdougm * sa_init(). 9354327Sdougm */ 9364327Sdougm sa_fini(handle); 9374327Sdougm return (NULL); 9384327Sdougm } 9393910Sdougm 9404327Sdougm if (tval == 0) { 9414327Sdougm /* 9424327Sdougm * first time so make sure 9434327Sdougm * default is setup 9444327Sdougm */ 9454327Sdougm verifydefgroupopts(handle); 9464327Sdougm } 9473973Sdougm 9484524Sdougm if (updatelegacy == B_TRUE) { 9494524Sdougm sablocksigs(&old); 9504524Sdougm getlegacyconfig((sa_handle_t)handle, 9514524Sdougm SA_LEGACY_DFSTAB, &handle->tree); 9524524Sdougm if (stat(SA_LEGACY_DFSTAB, &st) >= 0) 9534524Sdougm set_legacy_timestamp( 9544524Sdougm handle->tree, 9554524Sdougm SA_LEGACY_DFSTAB, 9564524Sdougm TSTAMP(st.st_ctim)); 9574524Sdougm saunblocksigs(&old); 9584524Sdougm /* 9594524Sdougm * Safe to unlock now to allow 9604524Sdougm * others to run 9614524Sdougm */ 9624524Sdougm (void) lockf(lockfd, F_ULOCK, 0); 9634524Sdougm (void) close(lockfd); 9644524Sdougm } 965*5951Sdougm /* Get sharetab timestamp */ 966*5951Sdougm sa_update_sharetab_ts((sa_handle_t)handle); 967*5951Sdougm 968*5951Sdougm /* Get lastupdate (transaction) timestamp */ 969*5951Sdougm prop = scf_simple_prop_get( 970*5951Sdougm handle->scfhandle->handle, 971*5951Sdougm (const char *)SA_SVC_FMRI_BASE ":default", 972*5951Sdougm "state", "lastupdate"); 973*5951Sdougm if (prop != NULL) { 974*5951Sdougm char *str; 975*5951Sdougm str = 976*5951Sdougm scf_simple_prop_next_astring(prop); 977*5951Sdougm if (str != NULL) 978*5951Sdougm handle->tstrans = 979*5951Sdougm strtoull(str, NULL, 0); 980*5951Sdougm else 981*5951Sdougm handle->tstrans = 0; 982*5951Sdougm scf_simple_prop_free(prop); 983*5951Sdougm } 9844524Sdougm legacy |= sa_get_zfs_shares(handle, "zfs"); 9854524Sdougm legacy |= gettransients(handle, &handle->tree); 9864327Sdougm } 9874327Sdougm } 9883034Sdougm } 9893910Sdougm return ((sa_handle_t)handle); 9903034Sdougm } 9913034Sdougm 9923034Sdougm /* 9933910Sdougm * sa_fini(handle) 9943034Sdougm * Uninitialize the API structures including the configuration 9953218Sdougm * data structures and ZFS related data. 9963034Sdougm */ 9973034Sdougm 9983034Sdougm void 9993910Sdougm sa_fini(sa_handle_t handle) 10003034Sdougm { 10013910Sdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle; 10023910Sdougm 10033910Sdougm if (impl_handle != NULL) { 10043910Sdougm /* 10053910Sdougm * Free the config trees and any other data structures 10063910Sdougm * used in the handle. 10073910Sdougm */ 10083910Sdougm if (impl_handle->doc != NULL) 10093910Sdougm xmlFreeDoc(impl_handle->doc); 10103910Sdougm sa_scf_fini(impl_handle->scfhandle); 10113910Sdougm sa_zfs_fini(impl_handle); 10123910Sdougm 10133910Sdougm /* Remove and free the entry in the global list. */ 10143910Sdougm remove_handle_for_root(impl_handle->tree); 10153910Sdougm 10163910Sdougm /* Make sure we free the handle */ 10173910Sdougm free(impl_handle); 10183910Sdougm 10193910Sdougm /* 10203910Sdougm * If this was the last handle to release, unload the 10213910Sdougm * plugins that were loaded. 10223910Sdougm */ 10233910Sdougm if (sa_global_handles == NULL) 10244327Sdougm (void) proto_plugin_fini(); 10253910Sdougm 10263034Sdougm } 10273034Sdougm } 10283034Sdougm 10293034Sdougm /* 10303034Sdougm * sa_get_protocols(char **protocol) 10313034Sdougm * Get array of protocols that are supported 10323034Sdougm * Returns pointer to an allocated and NULL terminated 10333034Sdougm * array of strings. Caller must free. 10343034Sdougm * This really should be determined dynamically. 10353034Sdougm * If there aren't any defined, return -1. 10363034Sdougm * Use free() to return memory. 10373034Sdougm */ 10383034Sdougm 10393034Sdougm int 10403034Sdougm sa_get_protocols(char ***protocols) 10413034Sdougm { 10423034Sdougm int numproto = -1; 10433034Sdougm 10443034Sdougm if (protocols != NULL) { 10454327Sdougm struct sa_proto_plugin *plug; 10464327Sdougm for (numproto = 0, plug = sap_proto_list; plug != NULL; 10474327Sdougm plug = plug->plugin_next) { 10484327Sdougm numproto++; 10494327Sdougm } 10503034Sdougm 10514327Sdougm *protocols = calloc(numproto + 1, sizeof (char *)); 10524327Sdougm if (*protocols != NULL) { 10534327Sdougm int ret = 0; 10544327Sdougm for (plug = sap_proto_list; plug != NULL; 10554327Sdougm plug = plug->plugin_next) { 10564327Sdougm /* faking for now */ 10574327Sdougm (*protocols)[ret++] = 10584327Sdougm plug->plugin_ops->sa_protocol; 10594327Sdougm } 10604327Sdougm } else { 10614327Sdougm numproto = -1; 10623034Sdougm } 10633034Sdougm } 10643034Sdougm return (numproto); 10653034Sdougm } 10663034Sdougm 10673034Sdougm /* 10683034Sdougm * find_group_by_name(node, group) 10693034Sdougm * 10703034Sdougm * search the XML document subtree specified by node to find the group 10713034Sdougm * specified by group. Searching subtree allows subgroups to be 10723034Sdougm * searched for. 10733034Sdougm */ 10743034Sdougm 10753034Sdougm static xmlNodePtr 10763034Sdougm find_group_by_name(xmlNodePtr node, xmlChar *group) 10773034Sdougm { 10783034Sdougm xmlChar *name = NULL; 10793034Sdougm 10803034Sdougm for (node = node->xmlChildrenNode; node != NULL; 10813034Sdougm node = node->next) { 10824327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"group") == 0) { 10834327Sdougm /* if no groupname, return the first found */ 10844327Sdougm if (group == NULL) 10854327Sdougm break; 10864327Sdougm name = xmlGetProp(node, (xmlChar *)"name"); 10874327Sdougm if (name != NULL && xmlStrcmp(name, group) == 0) 10884327Sdougm break; 10894327Sdougm if (name != NULL) { 10904327Sdougm xmlFree(name); 10914327Sdougm name = NULL; 10924327Sdougm } 10933034Sdougm } 10943034Sdougm } 10953034Sdougm if (name != NULL) 10964327Sdougm xmlFree(name); 10973034Sdougm return (node); 10983034Sdougm } 10993034Sdougm 11003034Sdougm /* 11013034Sdougm * sa_get_group(groupname) 11023034Sdougm * Return the "group" specified. If groupname is NULL, 11033034Sdougm * return the first group of the list of groups. 11043034Sdougm */ 11053034Sdougm sa_group_t 11063910Sdougm sa_get_group(sa_handle_t handle, char *groupname) 11073034Sdougm { 11083034Sdougm xmlNodePtr node = NULL; 11093034Sdougm char *subgroup = NULL; 11103034Sdougm char *group = NULL; 11113910Sdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle; 11123034Sdougm 11133910Sdougm if (impl_handle != NULL && impl_handle->tree != NULL) { 11144327Sdougm if (groupname != NULL) { 11154327Sdougm group = strdup(groupname); 11164345Sdougm if (group != NULL) { 11174345Sdougm subgroup = strchr(group, '/'); 11184345Sdougm if (subgroup != NULL) 11194345Sdougm *subgroup++ = '\0'; 11204345Sdougm } 11214327Sdougm } 11224345Sdougm /* 11234345Sdougm * We want to find the, possibly, named group. If 11244345Sdougm * group is not NULL, then lookup the name. If it is 11254345Sdougm * NULL, we only do the find if groupname is also 11264345Sdougm * NULL. This allows lookup of the "first" group in 11274345Sdougm * the internal list. 11284345Sdougm */ 11294345Sdougm if (group != NULL || groupname == NULL) 11304345Sdougm node = find_group_by_name(impl_handle->tree, 11314345Sdougm (xmlChar *)group); 11324345Sdougm 11334327Sdougm /* if a subgroup, find it before returning */ 11344327Sdougm if (subgroup != NULL && node != NULL) 11354327Sdougm node = find_group_by_name(node, (xmlChar *)subgroup); 11363034Sdougm } 11373034Sdougm if (node != NULL && (char *)group != NULL) 11384327Sdougm (void) sa_get_instance(impl_handle->scfhandle, (char *)group); 11393034Sdougm if (group != NULL) 11404327Sdougm free(group); 11413034Sdougm return ((sa_group_t)(node)); 11423034Sdougm } 11433034Sdougm 11443034Sdougm /* 11453034Sdougm * sa_get_next_group(group) 11463034Sdougm * Return the "next" group after the specified group from 11473034Sdougm * the internal group list. NULL if there are no more. 11483034Sdougm */ 11493034Sdougm sa_group_t 11503034Sdougm sa_get_next_group(sa_group_t group) 11513034Sdougm { 11523034Sdougm xmlNodePtr ngroup = NULL; 11533034Sdougm if (group != NULL) { 11544327Sdougm for (ngroup = ((xmlNodePtr)group)->next; ngroup != NULL; 11553034Sdougm ngroup = ngroup->next) { 11564327Sdougm if (xmlStrcmp(ngroup->name, (xmlChar *)"group") == 0) 11574327Sdougm break; 11584327Sdougm } 11593034Sdougm } 11603034Sdougm return ((sa_group_t)ngroup); 11613034Sdougm } 11623034Sdougm 11633034Sdougm /* 11643034Sdougm * sa_get_share(group, sharepath) 11653034Sdougm * Return the share object for the share specified. The share 11663034Sdougm * must be in the specified group. Return NULL if not found. 11673034Sdougm */ 11683034Sdougm sa_share_t 11693034Sdougm sa_get_share(sa_group_t group, char *sharepath) 11703034Sdougm { 11713034Sdougm xmlNodePtr node = NULL; 11723034Sdougm xmlChar *path; 11733034Sdougm 11743034Sdougm /* 11753034Sdougm * For future scalability, this should end up building a cache 11763034Sdougm * since it will get called regularly by the mountd and info 11773034Sdougm * services. 11783034Sdougm */ 11793034Sdougm if (group != NULL) { 11804327Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 11813034Sdougm node = node->next) { 11824327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) { 11834327Sdougm if (sharepath == NULL) { 11844327Sdougm break; 11854327Sdougm } else { 11864327Sdougm /* is it the correct share? */ 11874327Sdougm path = xmlGetProp(node, 11884327Sdougm (xmlChar *)"path"); 11894327Sdougm if (path != NULL && 11904327Sdougm xmlStrcmp(path, 11914327Sdougm (xmlChar *)sharepath) == 0) { 11924327Sdougm xmlFree(path); 11934327Sdougm break; 11944327Sdougm } 11954327Sdougm xmlFree(path); 11964327Sdougm } 11973034Sdougm } 11983034Sdougm } 11993034Sdougm } 12003034Sdougm return ((sa_share_t)node); 12013034Sdougm } 12023034Sdougm 12033034Sdougm /* 12043034Sdougm * sa_get_next_share(share) 12053034Sdougm * Return the next share following the specified share 12063034Sdougm * from the internal list of shares. Returns NULL if there 12073034Sdougm * are no more shares. The list is relative to the same 12083034Sdougm * group. 12093034Sdougm */ 12103034Sdougm sa_share_t 12113034Sdougm sa_get_next_share(sa_share_t share) 12123034Sdougm { 12133034Sdougm xmlNodePtr node = NULL; 12143034Sdougm 12153034Sdougm if (share != NULL) { 12164327Sdougm for (node = ((xmlNodePtr)share)->next; node != NULL; 12173034Sdougm node = node->next) { 12184327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) { 12194327Sdougm break; 12204327Sdougm } 12213034Sdougm } 12223034Sdougm } 12233034Sdougm return ((sa_share_t)node); 12243034Sdougm } 12253034Sdougm 12263034Sdougm /* 12273034Sdougm * _sa_get_child_node(node, type) 12283034Sdougm * 12293034Sdougm * find the child node of the specified node that has "type". This is 12303034Sdougm * used to implement several internal functions. 12313034Sdougm */ 12323034Sdougm 12333034Sdougm static xmlNodePtr 12343034Sdougm _sa_get_child_node(xmlNodePtr node, xmlChar *type) 12353034Sdougm { 12363034Sdougm xmlNodePtr child; 12373034Sdougm for (child = node->xmlChildrenNode; child != NULL; 12383034Sdougm child = child->next) 12394327Sdougm if (xmlStrcmp(child->name, type) == 0) 12404327Sdougm return (child); 12413034Sdougm return ((xmlNodePtr)NULL); 12423034Sdougm } 12433034Sdougm 12443034Sdougm /* 12453034Sdougm * find_share(group, path) 12463034Sdougm * 12473034Sdougm * Search all the shares in the specified group for one that has the 12483034Sdougm * specified path. 12493034Sdougm */ 12503034Sdougm 12513034Sdougm static sa_share_t 12523034Sdougm find_share(sa_group_t group, char *sharepath) 12533034Sdougm { 12543034Sdougm sa_share_t share; 12553034Sdougm char *path; 12563034Sdougm 12573034Sdougm for (share = sa_get_share(group, NULL); share != NULL; 12583034Sdougm share = sa_get_next_share(share)) { 12594327Sdougm path = sa_get_share_attr(share, "path"); 12604327Sdougm if (path != NULL && strcmp(path, sharepath) == 0) { 12614327Sdougm sa_free_attr_string(path); 12624327Sdougm break; 12634327Sdougm } 12644327Sdougm if (path != NULL) 12654327Sdougm sa_free_attr_string(path); 12663034Sdougm } 12673034Sdougm return (share); 12683034Sdougm } 12693034Sdougm 12703034Sdougm /* 12713034Sdougm * sa_get_sub_group(group) 12723034Sdougm * 12733034Sdougm * Get the first sub-group of group. The sa_get_next_group() function 12743034Sdougm * can be used to get the rest. This is currently only used for ZFS 12753034Sdougm * sub-groups but could be used to implement a more general mechanism. 12763034Sdougm */ 12773034Sdougm 12783034Sdougm sa_group_t 12793034Sdougm sa_get_sub_group(sa_group_t group) 12803034Sdougm { 12813034Sdougm return ((sa_group_t)_sa_get_child_node((xmlNodePtr)group, 12824327Sdougm (xmlChar *)"group")); 12833034Sdougm } 12843034Sdougm 12853034Sdougm /* 12863034Sdougm * sa_find_share(sharepath) 12873034Sdougm * Finds a share regardless of group. In the future, this 12883034Sdougm * function should utilize a cache and hash table of some kind. 12893034Sdougm * The current assumption is that a path will only be shared 12903034Sdougm * once. In the future, this may change as implementation of 12913034Sdougm * resource names comes into being. 12923034Sdougm */ 12933034Sdougm sa_share_t 12943910Sdougm sa_find_share(sa_handle_t handle, char *sharepath) 12953034Sdougm { 12963034Sdougm sa_group_t group; 12973034Sdougm sa_group_t zgroup; 12983034Sdougm sa_share_t share = NULL; 12993034Sdougm int done = 0; 13003034Sdougm 13013910Sdougm for (group = sa_get_group(handle, NULL); group != NULL && !done; 13024327Sdougm group = sa_get_next_group(group)) { 13034327Sdougm if (is_zfs_group(group)) { 13044327Sdougm for (zgroup = 13054327Sdougm (sa_group_t)_sa_get_child_node((xmlNodePtr)group, 13064327Sdougm (xmlChar *)"group"); 13074327Sdougm zgroup != NULL; 13084327Sdougm zgroup = sa_get_next_group(zgroup)) { 13094327Sdougm share = find_share(zgroup, sharepath); 13104327Sdougm if (share != NULL) 13114327Sdougm break; 13124327Sdougm } 13134327Sdougm } else { 13144327Sdougm share = find_share(group, sharepath); 13154327Sdougm } 13164327Sdougm if (share != NULL) 13173034Sdougm break; 13183034Sdougm } 13193034Sdougm return (share); 13203034Sdougm } 13213034Sdougm 13223034Sdougm /* 13233348Sdougm * sa_check_path(group, path, strictness) 13243034Sdougm * 13255331Samw * Check that path is a valid path relative to the group. Currently, 13263034Sdougm * we are ignoring the group and checking only the NFS rules. Later, 13273034Sdougm * we may want to use the group to then check against the protocols 13283348Sdougm * enabled on the group. The strictness values mean: 13293348Sdougm * SA_CHECK_NORMAL == only check newpath against shares that are active 13303348Sdougm * SA_CHECK_STRICT == check newpath against both active shares and those 13313348Sdougm * stored in the repository 13323034Sdougm */ 13333034Sdougm 13343034Sdougm int 13353348Sdougm sa_check_path(sa_group_t group, char *path, int strictness) 13363034Sdougm { 13373910Sdougm sa_handle_t handle; 13383910Sdougm 13393910Sdougm handle = sa_find_group_handle(group); 13403910Sdougm return (validpath(handle, path, strictness)); 13413034Sdougm } 13423034Sdougm 13433034Sdougm /* 13445331Samw * mark_excluded_protos(group, share, flags) 13453034Sdougm * 13465331Samw * Walk through all the protocols enabled for the group and check to 13475331Samw * see if the share has any of them should be in the exclude list 13485331Samw * based on the featureset of the protocol. If there are any, add the 13495331Samw * "exclude" property to the share. 13505331Samw */ 13515331Samw static void 13525331Samw mark_excluded_protos(sa_group_t group, xmlNodePtr share, uint64_t flags) 13535331Samw { 13545331Samw sa_optionset_t optionset; 13555331Samw char exclude_list[SA_STRSIZE]; 13565331Samw char *sep = ""; 13575331Samw 13585331Samw exclude_list[0] = '\0'; 13595331Samw for (optionset = sa_get_optionset(group, NULL); 13605331Samw optionset != NULL; 13615331Samw optionset = sa_get_next_optionset(optionset)) { 13625331Samw char *value; 13635331Samw uint64_t features; 13645331Samw value = sa_get_optionset_attr(optionset, "type"); 13655331Samw if (value == NULL) 13665331Samw continue; 13675331Samw features = sa_proto_get_featureset(value); 13685331Samw sa_free_attr_string(value); 13695331Samw if (!(features & flags)) { 13705331Samw (void) strlcat(exclude_list, sep, 13715331Samw sizeof (exclude_list)); 13725331Samw (void) strlcat(exclude_list, value, 13735331Samw sizeof (exclude_list)); 13745331Samw sep = ","; 13755331Samw } 13765331Samw } 13775331Samw if (exclude_list[0] != '\0') 13785331Samw xmlSetProp(share, (xmlChar *)"exclude", 13795331Samw (xmlChar *)exclude_list); 13805331Samw } 13815331Samw 13825331Samw /* 13835331Samw * get_all_features(group) 13845331Samw * 13855331Samw * Walk through all the protocols on the group and collect all 13865331Samw * possible enabled features. This is the OR of all the featuresets. 13875331Samw */ 13885331Samw static uint64_t 13895331Samw get_all_features(sa_group_t group) 13905331Samw { 13915331Samw sa_optionset_t optionset; 13925331Samw uint64_t features = 0; 13935331Samw 13945331Samw for (optionset = sa_get_optionset(group, NULL); 13955331Samw optionset != NULL; 13965331Samw optionset = sa_get_next_optionset(optionset)) { 13975331Samw char *value; 13985331Samw value = sa_get_optionset_attr(optionset, "type"); 13995331Samw if (value == NULL) 14005331Samw continue; 14015331Samw features |= sa_proto_get_featureset(value); 14025331Samw sa_free_attr_string(value); 14035331Samw } 14045331Samw return (features); 14055331Samw } 14065331Samw 14075331Samw 14085331Samw /* 14095331Samw * _sa_add_share(group, sharepath, persist, *error, flags) 14105331Samw * 14115331Samw * Common code for all types of add_share. sa_add_share() is the 14123034Sdougm * public API, we also need to be able to do this when parsing legacy 14133034Sdougm * files and construction of the internal configuration while 14145331Samw * extracting config info from SMF. "flags" indicates if some 14155331Samw * protocols need relaxed rules while other don't. These values are 14165331Samw * the featureset values defined in libshare.h. 14173034Sdougm */ 14183034Sdougm 14193034Sdougm sa_share_t 14205331Samw _sa_add_share(sa_group_t group, char *sharepath, int persist, int *error, 14215331Samw uint64_t flags) 14223034Sdougm { 14233034Sdougm xmlNodePtr node = NULL; 14243034Sdougm int err; 14253034Sdougm 14263034Sdougm err = SA_OK; /* assume success */ 14273034Sdougm 14284327Sdougm node = xmlNewChild((xmlNodePtr)group, NULL, (xmlChar *)"share", NULL); 14295331Samw if (node == NULL) { 14305331Samw if (error != NULL) 14315331Samw *error = SA_NO_MEMORY; 14325331Samw return (node); 14335331Samw } 14345331Samw 14355331Samw xmlSetProp(node, (xmlChar *)"path", (xmlChar *)sharepath); 14365331Samw xmlSetProp(node, (xmlChar *)"type", 14375331Samw persist ? (xmlChar *)"persist" : (xmlChar *)"transient"); 14385331Samw if (flags != 0) 14395331Samw mark_excluded_protos(group, node, flags); 14405331Samw if (persist != SA_SHARE_TRANSIENT) { 14415331Samw /* 14425331Samw * persistent shares come in two flavors: SMF and 14435331Samw * ZFS. Sort this one out based on target group and 14445331Samw * path type. Both NFS and SMB are supported. First, 14455331Samw * check to see if the protocol is enabled on the 14465331Samw * subgroup and then setup the share appropriately. 14475331Samw */ 14485331Samw if (sa_group_is_zfs(group) && 14495331Samw sa_path_is_zfs(sharepath)) { 14505331Samw if (sa_get_optionset(group, "nfs") != NULL) 14514327Sdougm err = sa_zfs_set_sharenfs(group, sharepath, 1); 14525331Samw else if (sa_get_optionset(group, "smb") != NULL) 14535331Samw err = sa_zfs_set_sharesmb(group, sharepath, 1); 14545331Samw } else { 14555331Samw sa_handle_impl_t impl_handle; 14565331Samw impl_handle = 14575331Samw (sa_handle_impl_t)sa_find_group_handle(group); 14585331Samw if (impl_handle != NULL) { 14595331Samw err = sa_commit_share(impl_handle->scfhandle, 14605331Samw group, (sa_share_t)node); 14614327Sdougm } else { 14625331Samw err = SA_SYSTEM_ERR; 14634327Sdougm } 14643034Sdougm } 14653034Sdougm } 14665331Samw if (err == SA_NO_PERMISSION && persist & SA_SHARE_PARSER) 14675331Samw /* called by the dfstab parser so could be a show */ 14685331Samw err = SA_OK; 14695331Samw 14705331Samw if (err != SA_OK) { 14715331Samw /* 14725331Samw * we couldn't commit to the repository so undo 14735331Samw * our internal state to reflect reality. 14745331Samw */ 14755331Samw xmlUnlinkNode(node); 14765331Samw xmlFreeNode(node); 14775331Samw node = NULL; 14785331Samw } 14795331Samw 14803034Sdougm if (error != NULL) 14814327Sdougm *error = err; 14825331Samw 14833034Sdougm return (node); 14843034Sdougm } 14853034Sdougm 14863034Sdougm /* 14873034Sdougm * sa_add_share(group, sharepath, persist, *error) 14883034Sdougm * 14893034Sdougm * Add a new share object to the specified group. The share will 14903034Sdougm * have the specified sharepath and will only be constructed if 14913034Sdougm * it is a valid path to be shared. NULL is returned on error 14923034Sdougm * and a detailed error value will be returned via the error 14933034Sdougm * pointer. 14943034Sdougm */ 14953034Sdougm sa_share_t 14963034Sdougm sa_add_share(sa_group_t group, char *sharepath, int persist, int *error) 14973034Sdougm { 14983034Sdougm xmlNodePtr node = NULL; 14993348Sdougm int strictness = SA_CHECK_NORMAL; 15003910Sdougm sa_handle_t handle; 15015331Samw uint64_t special = 0; 15025331Samw uint64_t features; 15033348Sdougm 15043348Sdougm /* 15053348Sdougm * If the share is to be permanent, use strict checking so a 15063348Sdougm * bad config doesn't get created. Transient shares only need 15073348Sdougm * to check against the currently active 15083348Sdougm * shares. SA_SHARE_PARSER is a modifier used internally to 15093348Sdougm * indicate that we are being called by the dfstab parser and 15103348Sdougm * that we need strict checking in all cases. Normally persist 15113348Sdougm * is in integer value but SA_SHARE_PARSER may be or'd into 15123348Sdougm * it as an override. 15133348Sdougm */ 15143348Sdougm if (persist & SA_SHARE_PARSER || persist == SA_SHARE_PERMANENT) 15154327Sdougm strictness = SA_CHECK_STRICT; 15163034Sdougm 15173910Sdougm handle = sa_find_group_handle(group); 15183910Sdougm 15195331Samw /* 15205331Samw * need to determine if the share is valid. The rules are: 15215331Samw * - The path must not already exist 15225331Samw * - The path must not be a subdir or parent dir of an 15235331Samw * existing path unless at least one protocol allows it. 15245331Samw * The sub/parent check is done in sa_check_path(). 15255331Samw */ 15265331Samw 15275331Samw if (sa_find_share(handle, sharepath) == NULL) { 15285331Samw *error = sa_check_path(group, sharepath, strictness); 15295331Samw features = get_all_features(group); 15305331Samw switch (*error) { 15315331Samw case SA_PATH_IS_SUBDIR: 15325331Samw if (features & SA_FEATURE_ALLOWSUBDIRS) 15335331Samw special |= SA_FEATURE_ALLOWSUBDIRS; 15345331Samw break; 15355331Samw case SA_PATH_IS_PARENTDIR: 15365331Samw if (features & SA_FEATURE_ALLOWPARDIRS) 15375331Samw special |= SA_FEATURE_ALLOWPARDIRS; 15385331Samw break; 15395331Samw } 15405331Samw if (*error == SA_OK || special != SA_FEATURE_NONE) 15415331Samw node = _sa_add_share(group, sharepath, persist, 15425331Samw error, special); 15435331Samw } else { 15445331Samw *error = SA_DUPLICATE_NAME; 15453034Sdougm } 15463034Sdougm 15473034Sdougm return ((sa_share_t)node); 15483034Sdougm } 15493034Sdougm 15503034Sdougm /* 15513034Sdougm * sa_enable_share(share, protocol) 15523034Sdougm * Enable the specified share to the specified protocol. 15533034Sdougm * If protocol is NULL, then all protocols. 15543034Sdougm */ 15553034Sdougm int 15563034Sdougm sa_enable_share(sa_share_t share, char *protocol) 15573034Sdougm { 15583034Sdougm char *sharepath; 15593034Sdougm struct stat st; 15605331Samw int err = SA_OK; 15615331Samw int ret; 15623034Sdougm 15633034Sdougm sharepath = sa_get_share_attr(share, "path"); 15645331Samw if (sharepath == NULL) 15655331Samw return (SA_NO_MEMORY); 15663034Sdougm if (stat(sharepath, &st) < 0) { 15674327Sdougm err = SA_NO_SUCH_PATH; 15683034Sdougm } else { 15694327Sdougm /* tell the server about the share */ 15704327Sdougm if (protocol != NULL) { 15715331Samw if (excluded_protocol(share, protocol)) 15725331Samw goto done; 15735331Samw 15744327Sdougm /* lookup protocol specific handler */ 15754327Sdougm err = sa_proto_share(protocol, share); 15764327Sdougm if (err == SA_OK) 15775331Samw (void) sa_set_share_attr(share, 15785331Samw "shared", "true"); 15794327Sdougm } else { 15805331Samw /* Tell all protocols about the share */ 15815331Samw sa_group_t group; 15825331Samw sa_optionset_t optionset; 15835331Samw 15845331Samw group = sa_get_parent_group(share); 15855331Samw 15865331Samw for (optionset = sa_get_optionset(group, NULL); 15875331Samw optionset != NULL; 15885331Samw optionset = sa_get_next_optionset(optionset)) { 15895331Samw char *proto; 15905331Samw proto = sa_get_optionset_attr(optionset, 15915331Samw "type"); 15925331Samw if (proto != NULL) { 15935331Samw if (!excluded_protocol(share, proto)) { 15945331Samw ret = sa_proto_share(proto, 15955331Samw share); 15965331Samw if (ret != SA_OK) 15975331Samw err = ret; 15985331Samw } 15995331Samw sa_free_attr_string(proto); 16005331Samw } 16015331Samw } 16024327Sdougm (void) sa_set_share_attr(share, "shared", "true"); 16034327Sdougm } 16043034Sdougm } 16055331Samw done: 16063034Sdougm if (sharepath != NULL) 16074327Sdougm sa_free_attr_string(sharepath); 16083034Sdougm return (err); 16093034Sdougm } 16103034Sdougm 16113034Sdougm /* 16123034Sdougm * sa_disable_share(share, protocol) 16135331Samw * Disable the specified share to the specified protocol. If 16145331Samw * protocol is NULL, then all protocols that are enabled for the 16155331Samw * share should be disabled. 16163034Sdougm */ 16173034Sdougm int 16183034Sdougm sa_disable_share(sa_share_t share, char *protocol) 16193034Sdougm { 16203034Sdougm char *path; 16215331Samw int err = SA_OK; 16223034Sdougm int ret = SA_OK; 16233034Sdougm 16243034Sdougm path = sa_get_share_attr(share, "path"); 16253034Sdougm 16263034Sdougm if (protocol != NULL) { 16274543Smarks ret = sa_proto_unshare(share, protocol, path); 16283034Sdougm } else { 16294327Sdougm /* need to do all protocols */ 16305331Samw sa_group_t group; 16315331Samw sa_optionset_t optionset; 16325331Samw 16335331Samw group = sa_get_parent_group(share); 16345331Samw 16355331Samw /* Tell all protocols about the share */ 16365331Samw for (optionset = sa_get_optionset(group, NULL); 16375331Samw optionset != NULL; 16385331Samw optionset = sa_get_next_optionset(optionset)) { 16395331Samw char *proto; 16405331Samw 16415331Samw proto = sa_get_optionset_attr(optionset, "type"); 16425331Samw if (proto != NULL) { 16435331Samw err = sa_proto_unshare(share, proto, path); 16445331Samw if (err != SA_OK) 16455331Samw ret = err; 16465331Samw sa_free_attr_string(proto); 16475331Samw } 16485331Samw } 16493034Sdougm } 16503034Sdougm if (ret == SA_OK) 16513034Sdougm (void) sa_set_share_attr(share, "shared", NULL); 16523034Sdougm if (path != NULL) 16534327Sdougm sa_free_attr_string(path); 16543034Sdougm return (ret); 16553034Sdougm } 16563034Sdougm 16573034Sdougm /* 16583034Sdougm * sa_remove_share(share) 16593034Sdougm * 16603034Sdougm * remove the specified share from its containing group. 16613034Sdougm * Remove from the SMF or ZFS configuration space. 16623034Sdougm */ 16633034Sdougm 16643034Sdougm int 16653034Sdougm sa_remove_share(sa_share_t share) 16663034Sdougm { 16673034Sdougm sa_group_t group; 16683034Sdougm int ret = SA_OK; 16693034Sdougm char *type; 16703034Sdougm int transient = 0; 16713034Sdougm char *groupname; 16723034Sdougm char *zfs; 16733034Sdougm 16743034Sdougm type = sa_get_share_attr(share, "type"); 16753034Sdougm group = sa_get_parent_group(share); 16763034Sdougm zfs = sa_get_group_attr(group, "zfs"); 16773034Sdougm groupname = sa_get_group_attr(group, "name"); 16783034Sdougm if (type != NULL && strcmp(type, "persist") != 0) 16794327Sdougm transient = 1; 16803034Sdougm if (type != NULL) 16814327Sdougm sa_free_attr_string(type); 16823034Sdougm 16833034Sdougm /* remove the node from its group then free the memory */ 16843034Sdougm 16853034Sdougm /* 16863034Sdougm * need to test if "busy" 16873034Sdougm */ 16883034Sdougm /* only do SMF action if permanent */ 16893034Sdougm if (!transient || zfs != NULL) { 16904327Sdougm /* remove from legacy dfstab as well as possible SMF */ 16915331Samw ret = sa_delete_legacy(share, NULL); 16924327Sdougm if (ret == SA_OK) { 16934327Sdougm if (!sa_group_is_zfs(group)) { 16944327Sdougm sa_handle_impl_t impl_handle; 16954327Sdougm impl_handle = (sa_handle_impl_t) 16964327Sdougm sa_find_group_handle(group); 16974327Sdougm if (impl_handle != NULL) { 16984327Sdougm ret = sa_delete_share( 16994327Sdougm impl_handle->scfhandle, group, 17004327Sdougm share); 17014327Sdougm } else { 17024327Sdougm ret = SA_SYSTEM_ERR; 17034327Sdougm } 17044327Sdougm } else { 17054327Sdougm char *sharepath = sa_get_share_attr(share, 17064327Sdougm "path"); 17074327Sdougm if (sharepath != NULL) { 17084327Sdougm ret = sa_zfs_set_sharenfs(group, 17094327Sdougm sharepath, 0); 17104327Sdougm sa_free_attr_string(sharepath); 17114327Sdougm } 17124327Sdougm } 17133034Sdougm } 17143034Sdougm } 17153034Sdougm if (groupname != NULL) 17164327Sdougm sa_free_attr_string(groupname); 17173034Sdougm if (zfs != NULL) 17184327Sdougm sa_free_attr_string(zfs); 17193034Sdougm 17203034Sdougm xmlUnlinkNode((xmlNodePtr)share); 17213034Sdougm xmlFreeNode((xmlNodePtr)share); 17223034Sdougm return (ret); 17233034Sdougm } 17243034Sdougm 17253034Sdougm /* 17263034Sdougm * sa_move_share(group, share) 17273034Sdougm * 17283034Sdougm * move the specified share to the specified group. Update SMF 17293034Sdougm * appropriately. 17303034Sdougm */ 17313034Sdougm 17323034Sdougm int 17333034Sdougm sa_move_share(sa_group_t group, sa_share_t share) 17343034Sdougm { 17353034Sdougm sa_group_t oldgroup; 17363034Sdougm int ret = SA_OK; 17373034Sdougm 17383034Sdougm /* remove the node from its group then free the memory */ 17393034Sdougm 17403034Sdougm oldgroup = sa_get_parent_group(share); 17413034Sdougm if (oldgroup != group) { 17424327Sdougm sa_handle_impl_t impl_handle; 17434327Sdougm xmlUnlinkNode((xmlNodePtr)share); 17443034Sdougm /* 17454327Sdougm * now that the share isn't in its old group, add to 17464327Sdougm * the new one 17473034Sdougm */ 17484327Sdougm xmlAddChild((xmlNodePtr)group, (xmlNodePtr)share); 17494327Sdougm /* need to deal with SMF */ 17504327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 17514327Sdougm if (impl_handle != NULL) { 17524327Sdougm /* 17534327Sdougm * need to remove from old group first and then add to 17544327Sdougm * new group. Ideally, we would do the other order but 17554327Sdougm * need to avoid having the share in two groups at the 17564327Sdougm * same time. 17574327Sdougm */ 17584327Sdougm ret = sa_delete_share(impl_handle->scfhandle, oldgroup, 17594327Sdougm share); 17604327Sdougm if (ret == SA_OK) 17614327Sdougm ret = sa_commit_share(impl_handle->scfhandle, 17624327Sdougm group, share); 17634327Sdougm } else { 17644327Sdougm ret = SA_SYSTEM_ERR; 17654327Sdougm } 17663034Sdougm } 17673034Sdougm return (ret); 17683034Sdougm } 17693034Sdougm 17703034Sdougm /* 17713034Sdougm * sa_get_parent_group(share) 17723034Sdougm * 17735331Samw * Return the containing group for the share. If a group was actually 17743034Sdougm * passed in, we don't want a parent so return NULL. 17753034Sdougm */ 17763034Sdougm 17773034Sdougm sa_group_t 17783034Sdougm sa_get_parent_group(sa_share_t share) 17793034Sdougm { 17803034Sdougm xmlNodePtr node = NULL; 17813034Sdougm if (share != NULL) { 17824327Sdougm node = ((xmlNodePtr)share)->parent; 17833034Sdougm /* 17843034Sdougm * make sure parent is a group and not sharecfg since 17853034Sdougm * we may be cheating and passing in a group. 17863034Sdougm * Eventually, groups of groups might come into being. 17873034Sdougm */ 17884327Sdougm if (node == NULL || 17894327Sdougm xmlStrcmp(node->name, (xmlChar *)"sharecfg") == 0) 17904327Sdougm node = NULL; 17913034Sdougm } 17923034Sdougm return ((sa_group_t)node); 17933034Sdougm } 17943034Sdougm 17953034Sdougm /* 17963910Sdougm * _sa_create_group(impl_handle, groupname) 17973034Sdougm * 17983034Sdougm * Create a group in the document. The caller will need to deal with 17993034Sdougm * configuration store and activation. 18003034Sdougm */ 18013034Sdougm 18023034Sdougm sa_group_t 18033910Sdougm _sa_create_group(sa_handle_impl_t impl_handle, char *groupname) 18043034Sdougm { 18053034Sdougm xmlNodePtr node = NULL; 18063034Sdougm 18073034Sdougm if (sa_valid_group_name(groupname)) { 18084327Sdougm node = xmlNewChild(impl_handle->tree, NULL, (xmlChar *)"group", 18094327Sdougm NULL); 18104327Sdougm if (node != NULL) { 18114327Sdougm xmlSetProp(node, (xmlChar *)"name", 18124327Sdougm (xmlChar *)groupname); 18134327Sdougm xmlSetProp(node, (xmlChar *)"state", 18144327Sdougm (xmlChar *)"enabled"); 18154327Sdougm } 18163034Sdougm } 18173034Sdougm return ((sa_group_t)node); 18183034Sdougm } 18193034Sdougm 18203034Sdougm /* 18213034Sdougm * _sa_create_zfs_group(group, groupname) 18223034Sdougm * 18233034Sdougm * Create a ZFS subgroup under the specified group. This may 18243034Sdougm * eventually form the basis of general sub-groups, but is currently 18253034Sdougm * restricted to ZFS. 18263034Sdougm */ 18273034Sdougm sa_group_t 18283034Sdougm _sa_create_zfs_group(sa_group_t group, char *groupname) 18293034Sdougm { 18303034Sdougm xmlNodePtr node = NULL; 18313034Sdougm 18324327Sdougm node = xmlNewChild((xmlNodePtr)group, NULL, (xmlChar *)"group", NULL); 18333034Sdougm if (node != NULL) { 18343034Sdougm xmlSetProp(node, (xmlChar *)"name", (xmlChar *)groupname); 18353034Sdougm xmlSetProp(node, (xmlChar *)"state", (xmlChar *)"enabled"); 18363034Sdougm } 18373034Sdougm 18383034Sdougm return ((sa_group_t)node); 18393034Sdougm } 18403034Sdougm 18413034Sdougm /* 18423034Sdougm * sa_create_group(groupname, *error) 18433034Sdougm * 18443034Sdougm * Create a new group with groupname. Need to validate that it is a 18453034Sdougm * legal name for SMF and the construct the SMF service instance of 18463034Sdougm * svc:/network/shares/group to implement the group. All necessary 18473034Sdougm * operational properties must be added to the group at this point 18483034Sdougm * (via the SMF transaction model). 18493034Sdougm */ 18503034Sdougm sa_group_t 18513910Sdougm sa_create_group(sa_handle_t handle, char *groupname, int *error) 18523034Sdougm { 18533034Sdougm xmlNodePtr node = NULL; 18543034Sdougm sa_group_t group; 18553034Sdougm int ret; 18564327Sdougm char rbacstr[SA_STRSIZE]; 18573910Sdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle; 18583034Sdougm 18593034Sdougm ret = SA_OK; 18603034Sdougm 18613910Sdougm if (impl_handle == NULL || impl_handle->scfhandle == NULL) { 18624327Sdougm ret = SA_SYSTEM_ERR; 18634327Sdougm goto err; 18643034Sdougm } 18653034Sdougm 18663910Sdougm group = sa_get_group(handle, groupname); 18673034Sdougm if (group != NULL) { 18684327Sdougm ret = SA_DUPLICATE_NAME; 18693034Sdougm } else { 18704327Sdougm if (sa_valid_group_name(groupname)) { 18714327Sdougm node = xmlNewChild(impl_handle->tree, NULL, 18724327Sdougm (xmlChar *)"group", NULL); 18734327Sdougm if (node != NULL) { 18744327Sdougm xmlSetProp(node, (xmlChar *)"name", 18754327Sdougm (xmlChar *)groupname); 18764327Sdougm /* default to the group being enabled */ 18774327Sdougm xmlSetProp(node, (xmlChar *)"state", 18784327Sdougm (xmlChar *)"enabled"); 18794327Sdougm ret = sa_create_instance(impl_handle->scfhandle, 18804327Sdougm groupname); 18814327Sdougm if (ret == SA_OK) { 18824327Sdougm ret = sa_start_transaction( 18834327Sdougm impl_handle->scfhandle, 18844327Sdougm "operation"); 18854327Sdougm } 18864327Sdougm if (ret == SA_OK) { 18874327Sdougm ret = sa_set_property( 18884327Sdougm impl_handle->scfhandle, 18894327Sdougm "state", "enabled"); 18904327Sdougm if (ret == SA_OK) { 18914327Sdougm ret = sa_end_transaction( 1892*5951Sdougm impl_handle->scfhandle, 1893*5951Sdougm impl_handle); 18944327Sdougm } else { 18954327Sdougm sa_abort_transaction( 18964327Sdougm impl_handle->scfhandle); 18974327Sdougm } 18984327Sdougm } 18994327Sdougm if (ret == SA_OK) { 19004327Sdougm /* initialize the RBAC strings */ 19014327Sdougm ret = sa_start_transaction( 19024327Sdougm impl_handle->scfhandle, 19034327Sdougm "general"); 19044327Sdougm if (ret == SA_OK) { 19054327Sdougm (void) snprintf(rbacstr, 19064327Sdougm sizeof (rbacstr), "%s.%s", 19074327Sdougm SA_RBAC_MANAGE, groupname); 19084327Sdougm ret = sa_set_property( 19094327Sdougm impl_handle->scfhandle, 19103034Sdougm "action_authorization", 19113034Sdougm rbacstr); 19124327Sdougm } 19134327Sdougm if (ret == SA_OK) { 19144327Sdougm (void) snprintf(rbacstr, 19154327Sdougm sizeof (rbacstr), "%s.%s", 19164327Sdougm SA_RBAC_VALUE, groupname); 19174327Sdougm ret = sa_set_property( 19184327Sdougm impl_handle->scfhandle, 19193034Sdougm "value_authorization", 19203034Sdougm rbacstr); 19214327Sdougm } 19224327Sdougm if (ret == SA_OK) { 19234327Sdougm ret = sa_end_transaction( 1924*5951Sdougm impl_handle->scfhandle, 1925*5951Sdougm impl_handle); 19264327Sdougm } else { 19274327Sdougm sa_abort_transaction( 19284327Sdougm impl_handle->scfhandle); 19294327Sdougm } 19304327Sdougm } 19314327Sdougm if (ret != SA_OK) { 19324327Sdougm /* 19334327Sdougm * Couldn't commit the group 19344327Sdougm * so we need to undo 19354327Sdougm * internally. 19364327Sdougm */ 19374327Sdougm xmlUnlinkNode(node); 19384327Sdougm xmlFreeNode(node); 19394327Sdougm node = NULL; 19404327Sdougm } 19413034Sdougm } else { 19424327Sdougm ret = SA_NO_MEMORY; 19433034Sdougm } 19443034Sdougm } else { 19454327Sdougm ret = SA_INVALID_NAME; 19463034Sdougm } 19473034Sdougm } 19483034Sdougm err: 19493034Sdougm if (error != NULL) 19504327Sdougm *error = ret; 19513034Sdougm return ((sa_group_t)node); 19523034Sdougm } 19533034Sdougm 19543034Sdougm /* 19553034Sdougm * sa_remove_group(group) 19563034Sdougm * 19573034Sdougm * Remove the specified group. This deletes from the SMF repository. 19583034Sdougm * All property groups and properties are removed. 19593034Sdougm */ 19603034Sdougm 19613034Sdougm int 19623034Sdougm sa_remove_group(sa_group_t group) 19633034Sdougm { 19643034Sdougm char *name; 19653034Sdougm int ret = SA_OK; 19663910Sdougm sa_handle_impl_t impl_handle; 19673034Sdougm 19683910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 19693910Sdougm if (impl_handle != NULL) { 19704327Sdougm name = sa_get_group_attr(group, "name"); 19714327Sdougm if (name != NULL) { 19724327Sdougm ret = sa_delete_instance(impl_handle->scfhandle, name); 19734327Sdougm sa_free_attr_string(name); 19744327Sdougm } 19754327Sdougm xmlUnlinkNode((xmlNodePtr)group); /* make sure unlinked */ 19764327Sdougm xmlFreeNode((xmlNodePtr)group); /* now it is gone */ 19773910Sdougm } else { 19784327Sdougm ret = SA_SYSTEM_ERR; 19793034Sdougm } 19803034Sdougm return (ret); 19813034Sdougm } 19823034Sdougm 19833034Sdougm /* 19843034Sdougm * sa_update_config() 19853034Sdougm * 19863034Sdougm * Used to update legacy files that need to be updated in bulk 19873034Sdougm * Currently, this is a placeholder and will go away in a future 19883034Sdougm * release. 19893034Sdougm */ 19903034Sdougm 19913034Sdougm int 19923910Sdougm sa_update_config(sa_handle_t handle) 19933034Sdougm { 19943034Sdougm /* 19953034Sdougm * do legacy files first so we can tell when they change. 19963034Sdougm * This will go away when we start updating individual records 19973034Sdougm * rather than the whole file. 19983034Sdougm */ 19993910Sdougm update_legacy_config(handle); 20003034Sdougm return (SA_OK); 20013034Sdougm } 20023034Sdougm 20033034Sdougm /* 20043034Sdougm * get_node_attr(node, tag) 20053034Sdougm * 20065331Samw * Get the specified tag(attribute) if it exists on the node. This is 20073034Sdougm * used internally by a number of attribute oriented functions. 20083034Sdougm */ 20093034Sdougm 20103034Sdougm static char * 20113034Sdougm get_node_attr(void *nodehdl, char *tag) 20123034Sdougm { 20133034Sdougm xmlNodePtr node = (xmlNodePtr)nodehdl; 20143034Sdougm xmlChar *name = NULL; 20153034Sdougm 20164327Sdougm if (node != NULL) 20173034Sdougm name = xmlGetProp(node, (xmlChar *)tag); 20183034Sdougm return ((char *)name); 20193034Sdougm } 20203034Sdougm 20213034Sdougm /* 20223034Sdougm * get_node_attr(node, tag) 20233034Sdougm * 20245331Samw * Set the specified tag(attribute) to the specified value This is 20253034Sdougm * used internally by a number of attribute oriented functions. It 20263034Sdougm * doesn't update the repository, only the internal document state. 20273034Sdougm */ 20283034Sdougm 20293034Sdougm void 20303034Sdougm set_node_attr(void *nodehdl, char *tag, char *value) 20313034Sdougm { 20323034Sdougm xmlNodePtr node = (xmlNodePtr)nodehdl; 20333034Sdougm if (node != NULL && tag != NULL) { 20344327Sdougm if (value != NULL) 20353034Sdougm xmlSetProp(node, (xmlChar *)tag, (xmlChar *)value); 20364327Sdougm else 20373034Sdougm xmlUnsetProp(node, (xmlChar *)tag); 20383034Sdougm } 20393034Sdougm } 20403034Sdougm 20413034Sdougm /* 20423034Sdougm * sa_get_group_attr(group, tag) 20433034Sdougm * 20443034Sdougm * Get the specied attribute, if defined, for the group. 20453034Sdougm */ 20463034Sdougm 20473034Sdougm char * 20483034Sdougm sa_get_group_attr(sa_group_t group, char *tag) 20493034Sdougm { 20503034Sdougm return (get_node_attr((void *)group, tag)); 20513034Sdougm } 20523034Sdougm 20533034Sdougm /* 20543034Sdougm * sa_set_group_attr(group, tag, value) 20553034Sdougm * 20563034Sdougm * set the specified tag/attribute on the group using value as its 20573034Sdougm * value. 20583034Sdougm * 20593034Sdougm * This will result in setting the property in the SMF repository as 20603034Sdougm * well as in the internal document. 20613034Sdougm */ 20623034Sdougm 20633034Sdougm int 20643034Sdougm sa_set_group_attr(sa_group_t group, char *tag, char *value) 20653034Sdougm { 20663034Sdougm int ret; 20673034Sdougm char *groupname; 20683910Sdougm sa_handle_impl_t impl_handle; 20693034Sdougm 20705331Samw /* 20715331Samw * ZFS group/subgroup doesn't need the handle so shortcut. 20725331Samw */ 20735331Samw if (sa_group_is_zfs(group)) { 20745331Samw set_node_attr((void *)group, tag, value); 20755331Samw return (SA_OK); 20765331Samw } 20775331Samw 20783910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 20793910Sdougm if (impl_handle != NULL) { 20804327Sdougm groupname = sa_get_group_attr(group, "name"); 20814327Sdougm ret = sa_get_instance(impl_handle->scfhandle, groupname); 20823910Sdougm if (ret == SA_OK) { 20834327Sdougm set_node_attr((void *)group, tag, value); 20844327Sdougm ret = sa_start_transaction(impl_handle->scfhandle, 20854327Sdougm "operation"); 20864327Sdougm if (ret == SA_OK) { 20874327Sdougm ret = sa_set_property(impl_handle->scfhandle, 20884327Sdougm tag, value); 20894327Sdougm if (ret == SA_OK) 20905885Sdougm ret = sa_end_transaction( 2091*5951Sdougm impl_handle->scfhandle, 2092*5951Sdougm impl_handle); 20934327Sdougm else 20944327Sdougm sa_abort_transaction( 20954327Sdougm impl_handle->scfhandle); 20964327Sdougm } 20975885Sdougm if (ret == SA_SYSTEM_ERR) 20985885Sdougm ret = SA_NO_PERMISSION; 20993034Sdougm } 21004327Sdougm if (groupname != NULL) 21014327Sdougm sa_free_attr_string(groupname); 21023910Sdougm } else { 21034327Sdougm ret = SA_SYSTEM_ERR; 21043034Sdougm } 21053034Sdougm return (ret); 21063034Sdougm } 21073034Sdougm 21083034Sdougm /* 21093034Sdougm * sa_get_share_attr(share, tag) 21103034Sdougm * 21113034Sdougm * Return the value of the tag/attribute set on the specified 21123034Sdougm * share. Returns NULL if the tag doesn't exist. 21133034Sdougm */ 21143034Sdougm 21153034Sdougm char * 21163034Sdougm sa_get_share_attr(sa_share_t share, char *tag) 21173034Sdougm { 21183034Sdougm return (get_node_attr((void *)share, tag)); 21193034Sdougm } 21203034Sdougm 21213034Sdougm /* 21223034Sdougm * _sa_set_share_description(share, description) 21233034Sdougm * 21245331Samw * Add a description tag with text contents to the specified share. A 21255331Samw * separate XML tag is used rather than a property. This can also be 21265331Samw * used with resources. 21273034Sdougm */ 21283034Sdougm 21293034Sdougm xmlNodePtr 21305331Samw _sa_set_share_description(void *share, char *content) 21313034Sdougm { 21323034Sdougm xmlNodePtr node; 21334327Sdougm node = xmlNewChild((xmlNodePtr)share, NULL, (xmlChar *)"description", 21344327Sdougm NULL); 21353034Sdougm xmlNodeSetContent(node, (xmlChar *)content); 21363034Sdougm return (node); 21373034Sdougm } 21383034Sdougm 21393034Sdougm /* 21403034Sdougm * sa_set_share_attr(share, tag, value) 21413034Sdougm * 21423034Sdougm * Set the share attribute specified by tag to the specified value. In 21433034Sdougm * the case of "resource", enforce a no duplicates in a group rule. If 21443034Sdougm * the share is not transient, commit the changes to the repository 21453034Sdougm * else just update the share internally. 21463034Sdougm */ 21473034Sdougm 21483034Sdougm int 21493034Sdougm sa_set_share_attr(sa_share_t share, char *tag, char *value) 21503034Sdougm { 21513034Sdougm sa_group_t group; 21523034Sdougm sa_share_t resource; 21533034Sdougm int ret = SA_OK; 21543034Sdougm 21553034Sdougm group = sa_get_parent_group(share); 21563034Sdougm 21573034Sdougm /* 21583034Sdougm * There are some attributes that may have specific 21593034Sdougm * restrictions on them. Initially, only "resource" has 21603034Sdougm * special meaning that needs to be checked. Only one instance 21613034Sdougm * of a resource name may exist within a group. 21623034Sdougm */ 21633034Sdougm 21643034Sdougm if (strcmp(tag, "resource") == 0) { 21654327Sdougm resource = sa_get_resource(group, value); 21664327Sdougm if (resource != share && resource != NULL) 21674327Sdougm ret = SA_DUPLICATE_NAME; 21683034Sdougm } 21693034Sdougm if (ret == SA_OK) { 21704327Sdougm set_node_attr((void *)share, tag, value); 21714327Sdougm if (group != NULL) { 21724327Sdougm char *type; 21734327Sdougm /* we can probably optimize this some */ 21744327Sdougm type = sa_get_share_attr(share, "type"); 21754327Sdougm if (type == NULL || strcmp(type, "transient") != 0) { 21764327Sdougm sa_handle_impl_t impl_handle; 21774327Sdougm impl_handle = 21784327Sdougm (sa_handle_impl_t)sa_find_group_handle( 21794327Sdougm group); 21804327Sdougm if (impl_handle != NULL) { 21814327Sdougm ret = sa_commit_share( 21824327Sdougm impl_handle->scfhandle, group, 21834327Sdougm share); 21844327Sdougm } else { 21854327Sdougm ret = SA_SYSTEM_ERR; 21864327Sdougm } 21874327Sdougm } 21884327Sdougm if (type != NULL) 21894327Sdougm sa_free_attr_string(type); 21903910Sdougm } 21913034Sdougm } 21923034Sdougm return (ret); 21933034Sdougm } 21943034Sdougm 21953034Sdougm /* 21963034Sdougm * sa_get_property_attr(prop, tag) 21973034Sdougm * 21983034Sdougm * Get the value of the specified property attribute. Standard 21993034Sdougm * attributes are "type" and "value". 22003034Sdougm */ 22013034Sdougm 22023034Sdougm char * 22033034Sdougm sa_get_property_attr(sa_property_t prop, char *tag) 22043034Sdougm { 22053034Sdougm return (get_node_attr((void *)prop, tag)); 22063034Sdougm } 22073034Sdougm 22083034Sdougm /* 22093034Sdougm * sa_get_optionset_attr(prop, tag) 22103034Sdougm * 22113034Sdougm * Get the value of the specified property attribute. Standard 22123034Sdougm * attribute is "type". 22133034Sdougm */ 22143034Sdougm 22153034Sdougm char * 22163034Sdougm sa_get_optionset_attr(sa_property_t optionset, char *tag) 22173034Sdougm { 22183034Sdougm return (get_node_attr((void *)optionset, tag)); 22193034Sdougm 22203034Sdougm } 22213034Sdougm 22223034Sdougm /* 22233034Sdougm * sa_set_optionset_attr(optionset, tag, value) 22243034Sdougm * 22253034Sdougm * Set the specified attribute(tag) to the specified value on the 22263034Sdougm * optionset. 22273034Sdougm */ 22283034Sdougm 22293034Sdougm void 22303034Sdougm sa_set_optionset_attr(sa_group_t optionset, char *tag, char *value) 22313034Sdougm { 22323034Sdougm set_node_attr((void *)optionset, tag, value); 22333034Sdougm } 22343034Sdougm 22353034Sdougm /* 22363034Sdougm * sa_free_attr_string(string) 22373034Sdougm * 22383034Sdougm * Free the string that was returned in one of the sa_get_*_attr() 22393034Sdougm * functions. 22403034Sdougm */ 22413034Sdougm 22423034Sdougm void 22433034Sdougm sa_free_attr_string(char *string) 22443034Sdougm { 22453034Sdougm xmlFree((xmlChar *)string); 22463034Sdougm } 22473034Sdougm 22483034Sdougm /* 22493034Sdougm * sa_get_optionset(group, proto) 22503034Sdougm * 22513034Sdougm * Return the optionset, if it exists, that is associated with the 22523034Sdougm * specified protocol. 22533034Sdougm */ 22543034Sdougm 22553034Sdougm sa_optionset_t 22563034Sdougm sa_get_optionset(void *group, char *proto) 22573034Sdougm { 22583034Sdougm xmlNodePtr node; 22593034Sdougm xmlChar *value = NULL; 22603034Sdougm 22613034Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 22624327Sdougm node = node->next) { 22633034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) { 22644327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 22654327Sdougm if (proto != NULL) { 22664327Sdougm if (value != NULL && 22674327Sdougm xmlStrcmp(value, (xmlChar *)proto) == 0) { 22684327Sdougm break; 22694327Sdougm } 22704327Sdougm if (value != NULL) { 22714327Sdougm xmlFree(value); 22724327Sdougm value = NULL; 22734327Sdougm } 22744327Sdougm } else { 22754327Sdougm break; 22763034Sdougm } 22773034Sdougm } 22783034Sdougm } 22793034Sdougm if (value != NULL) 22804327Sdougm xmlFree(value); 22813034Sdougm return ((sa_optionset_t)node); 22823034Sdougm } 22833034Sdougm 22843034Sdougm /* 22853034Sdougm * sa_get_next_optionset(optionset) 22863034Sdougm * 22873034Sdougm * Return the next optionset in the group. NULL if this was the last. 22883034Sdougm */ 22893034Sdougm 22903034Sdougm sa_optionset_t 22913034Sdougm sa_get_next_optionset(sa_optionset_t optionset) 22923034Sdougm { 22933034Sdougm xmlNodePtr node; 22943034Sdougm 22953034Sdougm for (node = ((xmlNodePtr)optionset)->next; node != NULL; 22964327Sdougm node = node->next) { 22973034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) { 22983034Sdougm break; 22993034Sdougm } 23003034Sdougm } 23013034Sdougm return ((sa_optionset_t)node); 23023034Sdougm } 23033034Sdougm 23043034Sdougm /* 23053034Sdougm * sa_get_security(group, sectype, proto) 23063034Sdougm * 23073034Sdougm * Return the security optionset. The internal name is a hold over 23083034Sdougm * from the implementation and will be changed before the API is 23093034Sdougm * finalized. This is really a named optionset that can be negotiated 23103034Sdougm * as a group of properties (like NFS security options). 23113034Sdougm */ 23123034Sdougm 23133034Sdougm sa_security_t 23143034Sdougm sa_get_security(sa_group_t group, char *sectype, char *proto) 23153034Sdougm { 23163034Sdougm xmlNodePtr node; 23173034Sdougm xmlChar *value = NULL; 23183034Sdougm 23193034Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 23204327Sdougm node = node->next) { 23214327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) { 23224327Sdougm if (proto != NULL) { 23234327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 23244327Sdougm if (value == NULL || 23254327Sdougm (value != NULL && 23264327Sdougm xmlStrcmp(value, (xmlChar *)proto) != 0)) { 23274327Sdougm /* it doesn't match so continue */ 23284327Sdougm xmlFree(value); 23294327Sdougm value = NULL; 23304327Sdougm continue; 23314327Sdougm } 23324327Sdougm } 23334327Sdougm if (value != NULL) { 23344327Sdougm xmlFree(value); 23354327Sdougm value = NULL; 23364327Sdougm } 23374327Sdougm /* potential match */ 23384327Sdougm if (sectype != NULL) { 23394327Sdougm value = xmlGetProp(node, (xmlChar *)"sectype"); 23404327Sdougm if (value != NULL && 23414327Sdougm xmlStrcmp(value, (xmlChar *)sectype) == 0) { 23424327Sdougm break; 23434327Sdougm } 23444327Sdougm } else { 23454327Sdougm break; 23464327Sdougm } 23473034Sdougm } 23483034Sdougm if (value != NULL) { 23494327Sdougm xmlFree(value); 23504327Sdougm value = NULL; 23513034Sdougm } 23523034Sdougm } 23533034Sdougm if (value != NULL) 23544327Sdougm xmlFree(value); 23553034Sdougm return ((sa_security_t)node); 23563034Sdougm } 23573034Sdougm 23583034Sdougm /* 23593034Sdougm * sa_get_next_security(security) 23603034Sdougm * 23613034Sdougm * Get the next security optionset if one exists. 23623034Sdougm */ 23633034Sdougm 23643034Sdougm sa_security_t 23653034Sdougm sa_get_next_security(sa_security_t security) 23663034Sdougm { 23673034Sdougm xmlNodePtr node; 23683034Sdougm 23693034Sdougm for (node = ((xmlNodePtr)security)->next; node != NULL; 23704327Sdougm node = node->next) { 23713034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) { 23723034Sdougm break; 23733034Sdougm } 23743034Sdougm } 23753034Sdougm return ((sa_security_t)node); 23763034Sdougm } 23773034Sdougm 23783034Sdougm /* 23793034Sdougm * sa_get_property(optionset, prop) 23803034Sdougm * 23813034Sdougm * Get the property object with the name specified in prop from the 23823034Sdougm * optionset. 23833034Sdougm */ 23843034Sdougm 23853034Sdougm sa_property_t 23863034Sdougm sa_get_property(sa_optionset_t optionset, char *prop) 23873034Sdougm { 23883034Sdougm xmlNodePtr node = (xmlNodePtr)optionset; 23893034Sdougm xmlChar *value = NULL; 23903034Sdougm 23913034Sdougm if (optionset == NULL) 23924327Sdougm return (NULL); 23933034Sdougm 23943034Sdougm for (node = node->children; node != NULL; 23954327Sdougm node = node->next) { 23964327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 23974327Sdougm if (prop == NULL) 23984327Sdougm break; 23994327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 24004327Sdougm if (value != NULL && 24014327Sdougm xmlStrcmp(value, (xmlChar *)prop) == 0) { 24024327Sdougm break; 24034327Sdougm } 24044327Sdougm if (value != NULL) { 24054327Sdougm xmlFree(value); 24064327Sdougm value = NULL; 24074327Sdougm } 24083034Sdougm } 24093034Sdougm } 24103034Sdougm if (value != NULL) 24113034Sdougm xmlFree(value); 24123034Sdougm if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"option") != 0) { 24134327Sdougm /* 24144327Sdougm * avoid a non option node -- it is possible to be a 24154327Sdougm * text node 24164327Sdougm */ 24174327Sdougm node = NULL; 24183034Sdougm } 24193034Sdougm return ((sa_property_t)node); 24203034Sdougm } 24213034Sdougm 24223034Sdougm /* 24233034Sdougm * sa_get_next_property(property) 24243034Sdougm * 24253034Sdougm * Get the next property following the specified property. NULL if 24263034Sdougm * this was the last. 24273034Sdougm */ 24283034Sdougm 24293034Sdougm sa_property_t 24303034Sdougm sa_get_next_property(sa_property_t property) 24313034Sdougm { 24323034Sdougm xmlNodePtr node; 24333034Sdougm 24343034Sdougm for (node = ((xmlNodePtr)property)->next; node != NULL; 24354327Sdougm node = node->next) { 24363034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 24373034Sdougm break; 24383034Sdougm } 24393034Sdougm } 24403034Sdougm return ((sa_property_t)node); 24413034Sdougm } 24423034Sdougm 24433034Sdougm /* 24443034Sdougm * sa_set_share_description(share, content) 24453034Sdougm * 24463034Sdougm * Set the description of share to content. 24473034Sdougm */ 24483034Sdougm 24493034Sdougm int 24503034Sdougm sa_set_share_description(sa_share_t share, char *content) 24513034Sdougm { 24523034Sdougm xmlNodePtr node; 24533034Sdougm sa_group_t group; 24543034Sdougm int ret = SA_OK; 24553034Sdougm 24563034Sdougm for (node = ((xmlNodePtr)share)->children; node != NULL; 24574327Sdougm node = node->next) { 24583034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 24593034Sdougm break; 24603034Sdougm } 24613034Sdougm } 24623034Sdougm /* no existing description but want to add */ 24633034Sdougm if (node == NULL && content != NULL) { 24643034Sdougm /* add a description */ 24654327Sdougm node = _sa_set_share_description(share, content); 24663034Sdougm } else if (node != NULL && content != NULL) { 24673034Sdougm /* update a description */ 24683034Sdougm xmlNodeSetContent(node, (xmlChar *)content); 24693034Sdougm } else if (node != NULL && content == NULL) { 24703034Sdougm /* remove an existing description */ 24713034Sdougm xmlUnlinkNode(node); 24723034Sdougm xmlFreeNode(node); 24733034Sdougm } 24745331Samw group = sa_get_parent_group(share); 24755331Samw if (group != NULL && sa_is_persistent(share)) { 24764327Sdougm sa_handle_impl_t impl_handle; 24774327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 24784327Sdougm if (impl_handle != NULL) { 24794327Sdougm ret = sa_commit_share(impl_handle->scfhandle, group, 24804327Sdougm share); 24814327Sdougm } else { 24824327Sdougm ret = SA_SYSTEM_ERR; 24834327Sdougm } 24843910Sdougm } 24853034Sdougm return (ret); 24863034Sdougm } 24873034Sdougm 24883034Sdougm /* 24893034Sdougm * fixproblemchars(string) 24903034Sdougm * 24913034Sdougm * don't want any newline or tab characters in the text since these 24923034Sdougm * could break display of data and legacy file formats. 24933034Sdougm */ 24943034Sdougm static void 24953034Sdougm fixproblemchars(char *str) 24963034Sdougm { 24973034Sdougm int c; 24983034Sdougm for (c = *str; c != '\0'; c = *++str) { 24994327Sdougm if (c == '\t' || c == '\n') 25004327Sdougm *str = ' '; 25014327Sdougm else if (c == '"') 25024327Sdougm *str = '\''; 25033034Sdougm } 25043034Sdougm } 25053034Sdougm 25063034Sdougm /* 25073034Sdougm * sa_get_share_description(share) 25083034Sdougm * 25093034Sdougm * Return the description text for the specified share if it 25103034Sdougm * exists. NULL if no description exists. 25113034Sdougm */ 25123034Sdougm 25133034Sdougm char * 25143034Sdougm sa_get_share_description(sa_share_t share) 25153034Sdougm { 25163034Sdougm xmlChar *description = NULL; 25173034Sdougm xmlNodePtr node; 25183034Sdougm 25193034Sdougm for (node = ((xmlNodePtr)share)->children; node != NULL; 25204327Sdougm node = node->next) { 25214327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 25224327Sdougm break; 25234327Sdougm } 25243034Sdougm } 25253034Sdougm if (node != NULL) { 25265331Samw description = xmlNodeGetContent(node); 25274327Sdougm fixproblemchars((char *)description); 25283034Sdougm } 25293034Sdougm return ((char *)description); 25303034Sdougm } 25313034Sdougm 25323034Sdougm /* 25333034Sdougm * sa_free(share_description(description) 25343034Sdougm * 25353034Sdougm * Free the description string. 25363034Sdougm */ 25373034Sdougm 25383034Sdougm void 25393034Sdougm sa_free_share_description(char *description) 25403034Sdougm { 25413034Sdougm xmlFree((xmlChar *)description); 25423034Sdougm } 25433034Sdougm 25443034Sdougm /* 25453034Sdougm * sa_create_optionset(group, proto) 25463034Sdougm * 25473034Sdougm * Create an optionset for the specified protocol in the specied 25483034Sdougm * group. This is manifested as a property group within SMF. 25493034Sdougm */ 25503034Sdougm 25513034Sdougm sa_optionset_t 25523034Sdougm sa_create_optionset(sa_group_t group, char *proto) 25533034Sdougm { 25543034Sdougm sa_optionset_t optionset; 25553034Sdougm sa_group_t parent = group; 25565331Samw sa_share_t share = NULL; 25575331Samw int err = SA_OK; 25585331Samw char *id = NULL; 25593034Sdougm 25603034Sdougm optionset = sa_get_optionset(group, proto); 25613034Sdougm if (optionset != NULL) { 25623034Sdougm /* can't have a duplicate protocol */ 25634327Sdougm optionset = NULL; 25643034Sdougm } else { 25655331Samw /* 25665331Samw * Account for resource names being slightly 25675331Samw * different. 25685331Samw */ 25695331Samw if (sa_is_share(group)) { 25705331Samw /* 25715331Samw * Transient shares do not have an "id" so not an 25725331Samw * error to not find one. 25735331Samw */ 25745331Samw id = sa_get_share_attr((sa_share_t)group, "id"); 25755331Samw } else if (sa_is_resource(group)) { 25765331Samw share = sa_get_resource_parent( 25775331Samw (sa_resource_t)group); 25785331Samw id = sa_get_resource_attr(share, "id"); 25795331Samw 25805331Samw /* id can be NULL if the group is transient (ZFS) */ 25815331Samw if (id == NULL && sa_is_persistent(group)) 25825331Samw err = SA_NO_MEMORY; 25835331Samw } 25845331Samw if (err == SA_NO_MEMORY) { 25855331Samw /* 25865331Samw * Couldn't get the id for the share or 25875331Samw * resource. While this could be a 25885331Samw * configuration issue, it is most likely an 25895331Samw * out of memory. In any case, fail the create. 25905331Samw */ 25915331Samw return (NULL); 25925331Samw } 25935331Samw 25944327Sdougm optionset = (sa_optionset_t)xmlNewChild((xmlNodePtr)group, 25954327Sdougm NULL, (xmlChar *)"optionset", NULL); 25963034Sdougm /* 25973034Sdougm * only put to repository if on a group and we were 25983034Sdougm * able to create an optionset. 25993034Sdougm */ 26004327Sdougm if (optionset != NULL) { 26014327Sdougm char oname[SA_STRSIZE]; 26024327Sdougm char *groupname; 26035331Samw 26045331Samw /* 26055331Samw * Need to get parent group in all cases, but also get 26065331Samw * the share if this is a resource. 26075331Samw */ 26085331Samw if (sa_is_share(group)) { 26094327Sdougm parent = sa_get_parent_group((sa_share_t)group); 26105331Samw } else if (sa_is_resource(group)) { 26115331Samw share = sa_get_resource_parent( 26125331Samw (sa_resource_t)group); 26135331Samw parent = sa_get_parent_group(share); 26145331Samw } 26154327Sdougm 26164327Sdougm sa_set_optionset_attr(optionset, "type", proto); 26173034Sdougm 26184327Sdougm (void) sa_optionset_name(optionset, oname, 26194327Sdougm sizeof (oname), id); 26204327Sdougm groupname = sa_get_group_attr(parent, "name"); 26215331Samw if (groupname != NULL && sa_is_persistent(group)) { 26224327Sdougm sa_handle_impl_t impl_handle; 26235331Samw impl_handle = 26245331Samw (sa_handle_impl_t)sa_find_group_handle( 26255331Samw group); 26264327Sdougm assert(impl_handle != NULL); 26274327Sdougm if (impl_handle != NULL) { 26284327Sdougm (void) sa_get_instance( 26295331Samw impl_handle->scfhandle, groupname); 26304327Sdougm (void) sa_create_pgroup( 26314327Sdougm impl_handle->scfhandle, oname); 26324327Sdougm } 26334327Sdougm } 26344327Sdougm if (groupname != NULL) 26354327Sdougm sa_free_attr_string(groupname); 26363034Sdougm } 26373034Sdougm } 26385331Samw 26395331Samw if (id != NULL) 26405331Samw sa_free_attr_string(id); 26413034Sdougm return (optionset); 26423034Sdougm } 26433034Sdougm 26443034Sdougm /* 26453034Sdougm * sa_get_property_parent(property) 26463034Sdougm * 26473034Sdougm * Given a property, return the object it is a property of. This will 26483034Sdougm * be an optionset of some type. 26493034Sdougm */ 26503034Sdougm 26513034Sdougm static sa_optionset_t 26523034Sdougm sa_get_property_parent(sa_property_t property) 26533034Sdougm { 26543034Sdougm xmlNodePtr node = NULL; 26553034Sdougm 26564327Sdougm if (property != NULL) 26574327Sdougm node = ((xmlNodePtr)property)->parent; 26583034Sdougm return ((sa_optionset_t)node); 26593034Sdougm } 26603034Sdougm 26613034Sdougm /* 26623034Sdougm * sa_get_optionset_parent(optionset) 26633034Sdougm * 26643034Sdougm * Return the parent of the specified optionset. This could be a group 26653034Sdougm * or a share. 26663034Sdougm */ 26673034Sdougm 26683034Sdougm static sa_group_t 26693034Sdougm sa_get_optionset_parent(sa_optionset_t optionset) 26703034Sdougm { 26713034Sdougm xmlNodePtr node = NULL; 26723034Sdougm 26734327Sdougm if (optionset != NULL) 26744327Sdougm node = ((xmlNodePtr)optionset)->parent; 26753034Sdougm return ((sa_group_t)node); 26763034Sdougm } 26773034Sdougm 26783034Sdougm /* 26793034Sdougm * zfs_needs_update(share) 26803034Sdougm * 26813034Sdougm * In order to avoid making multiple updates to a ZFS share when 26823034Sdougm * setting properties, the share attribute "changed" will be set to 26835331Samw * true when a property is added or modified. When done adding 26843034Sdougm * properties, we can then detect that an update is needed. We then 26853034Sdougm * clear the state here to detect additional changes. 26863034Sdougm */ 26873034Sdougm 26883034Sdougm static int 26893034Sdougm zfs_needs_update(sa_share_t share) 26903034Sdougm { 26913034Sdougm char *attr; 26923034Sdougm int result = 0; 26933034Sdougm 26943034Sdougm attr = sa_get_share_attr(share, "changed"); 26953034Sdougm if (attr != NULL) { 26964327Sdougm sa_free_attr_string(attr); 26973034Sdougm result = 1; 26983034Sdougm } 26993034Sdougm set_node_attr((void *)share, "changed", NULL); 27003034Sdougm return (result); 27013034Sdougm } 27023034Sdougm 27033034Sdougm /* 27043034Sdougm * zfs_set_update(share) 27053034Sdougm * 27063034Sdougm * Set the changed attribute of the share to true. 27073034Sdougm */ 27083034Sdougm 27093034Sdougm static void 27103034Sdougm zfs_set_update(sa_share_t share) 27113034Sdougm { 27123034Sdougm set_node_attr((void *)share, "changed", "true"); 27133034Sdougm } 27143034Sdougm 27153034Sdougm /* 27163034Sdougm * sa_commit_properties(optionset, clear) 27173034Sdougm * 27183034Sdougm * Check if SMF or ZFS config and either update or abort the pending 27193034Sdougm * changes. 27203034Sdougm */ 27213034Sdougm 27223034Sdougm int 27233034Sdougm sa_commit_properties(sa_optionset_t optionset, int clear) 27243034Sdougm { 27253034Sdougm sa_group_t group; 27263034Sdougm sa_group_t parent; 27273034Sdougm int zfs = 0; 27283034Sdougm int needsupdate = 0; 27293034Sdougm int ret = SA_OK; 27303910Sdougm sa_handle_impl_t impl_handle; 27313034Sdougm 27323034Sdougm group = sa_get_optionset_parent(optionset); 27333034Sdougm if (group != NULL && (sa_is_share(group) || is_zfs_group(group))) { 27344327Sdougm /* only update ZFS if on a share */ 27354327Sdougm parent = sa_get_parent_group(group); 27364327Sdougm zfs++; 27374327Sdougm if (parent != NULL && is_zfs_group(parent)) 27384327Sdougm needsupdate = zfs_needs_update(group); 27394327Sdougm else 27404327Sdougm zfs = 0; 27413034Sdougm } 27423034Sdougm if (zfs) { 27434327Sdougm if (!clear && needsupdate) 27444327Sdougm ret = sa_zfs_update((sa_share_t)group); 27453034Sdougm } else { 27464327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 27474327Sdougm if (impl_handle != NULL) { 27484327Sdougm if (clear) { 27494327Sdougm (void) sa_abort_transaction( 27504327Sdougm impl_handle->scfhandle); 27514327Sdougm } else { 27524327Sdougm ret = sa_end_transaction( 2753*5951Sdougm impl_handle->scfhandle, impl_handle); 27544327Sdougm } 27554327Sdougm } else { 27564327Sdougm ret = SA_SYSTEM_ERR; 27574327Sdougm } 27583034Sdougm } 27593034Sdougm return (ret); 27603034Sdougm } 27613034Sdougm 27623034Sdougm /* 27633034Sdougm * sa_destroy_optionset(optionset) 27643034Sdougm * 27655331Samw * Remove the optionset from its group. Update the repository to 27663034Sdougm * reflect this change. 27673034Sdougm */ 27683034Sdougm 27693034Sdougm int 27703034Sdougm sa_destroy_optionset(sa_optionset_t optionset) 27713034Sdougm { 27724327Sdougm char name[SA_STRSIZE]; 27733034Sdougm int len; 27743034Sdougm int ret; 27753034Sdougm char *id = NULL; 27763034Sdougm sa_group_t group; 27773034Sdougm int ispersist = 1; 27783034Sdougm 27793034Sdougm /* now delete the prop group */ 27803034Sdougm group = sa_get_optionset_parent(optionset); 27815331Samw if (group != NULL) { 27825331Samw if (sa_is_resource(group)) { 27835331Samw sa_resource_t resource = group; 27845331Samw sa_share_t share = sa_get_resource_parent(resource); 27855331Samw group = sa_get_parent_group(share); 27865331Samw id = sa_get_share_attr(share, "id"); 27875331Samw } else if (sa_is_share(group)) { 27885331Samw id = sa_get_share_attr((sa_share_t)group, "id"); 27895331Samw } 27905331Samw ispersist = sa_is_persistent(group); 27913034Sdougm } 27923034Sdougm if (ispersist) { 27934327Sdougm sa_handle_impl_t impl_handle; 27944327Sdougm len = sa_optionset_name(optionset, name, sizeof (name), id); 27954327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 27964327Sdougm if (impl_handle != NULL) { 27974327Sdougm if (len > 0) { 27984327Sdougm ret = sa_delete_pgroup(impl_handle->scfhandle, 27994327Sdougm name); 28004327Sdougm } 28014327Sdougm } else { 28024327Sdougm ret = SA_SYSTEM_ERR; 28033910Sdougm } 28043034Sdougm } 28053034Sdougm xmlUnlinkNode((xmlNodePtr)optionset); 28063034Sdougm xmlFreeNode((xmlNodePtr)optionset); 28073034Sdougm if (id != NULL) 28084327Sdougm sa_free_attr_string(id); 28093034Sdougm return (ret); 28103034Sdougm } 28113034Sdougm 28123034Sdougm /* private to the implementation */ 28133034Sdougm int 28143034Sdougm _sa_remove_optionset(sa_optionset_t optionset) 28153034Sdougm { 28163034Sdougm int ret = SA_OK; 28173034Sdougm 28183034Sdougm xmlUnlinkNode((xmlNodePtr)optionset); 28193034Sdougm xmlFreeNode((xmlNodePtr)optionset); 28203034Sdougm return (ret); 28213034Sdougm } 28223034Sdougm 28233034Sdougm /* 28243034Sdougm * sa_create_security(group, sectype, proto) 28253034Sdougm * 28263034Sdougm * Create a security optionset (one that has a type name and a 28273034Sdougm * proto). Security is left over from a pure NFS implementation. The 28283034Sdougm * naming will change in the future when the API is released. 28293034Sdougm */ 28303034Sdougm sa_security_t 28313034Sdougm sa_create_security(sa_group_t group, char *sectype, char *proto) 28323034Sdougm { 28333034Sdougm sa_security_t security; 28343034Sdougm char *id = NULL; 28353034Sdougm sa_group_t parent; 28363034Sdougm char *groupname = NULL; 28373034Sdougm 28383034Sdougm if (group != NULL && sa_is_share(group)) { 28394327Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 28404327Sdougm parent = sa_get_parent_group(group); 28414327Sdougm if (parent != NULL) 28424327Sdougm groupname = sa_get_group_attr(parent, "name"); 28433034Sdougm } else if (group != NULL) { 28444327Sdougm groupname = sa_get_group_attr(group, "name"); 28453034Sdougm } 28463034Sdougm 28473034Sdougm security = sa_get_security(group, sectype, proto); 28483034Sdougm if (security != NULL) { 28493034Sdougm /* can't have a duplicate security option */ 28503034Sdougm security = NULL; 28513034Sdougm } else { 28523034Sdougm security = (sa_security_t)xmlNewChild((xmlNodePtr)group, 28534327Sdougm NULL, (xmlChar *)"security", NULL); 28543034Sdougm if (security != NULL) { 28554327Sdougm char oname[SA_STRSIZE]; 28563034Sdougm sa_set_security_attr(security, "type", proto); 28573034Sdougm 28583034Sdougm sa_set_security_attr(security, "sectype", sectype); 28593034Sdougm (void) sa_security_name(security, oname, 28604327Sdougm sizeof (oname), id); 28615331Samw if (groupname != NULL && sa_is_persistent(group)) { 28624327Sdougm sa_handle_impl_t impl_handle; 28634327Sdougm impl_handle = 28644327Sdougm (sa_handle_impl_t)sa_find_group_handle( 28654327Sdougm group); 28664327Sdougm if (impl_handle != NULL) { 28674327Sdougm (void) sa_get_instance( 28684327Sdougm impl_handle->scfhandle, groupname); 28694327Sdougm (void) sa_create_pgroup( 28704327Sdougm impl_handle->scfhandle, oname); 28714327Sdougm } 28723034Sdougm } 28733034Sdougm } 28743034Sdougm } 28753034Sdougm if (groupname != NULL) 28764327Sdougm sa_free_attr_string(groupname); 28773034Sdougm return (security); 28783034Sdougm } 28793034Sdougm 28803034Sdougm /* 28813034Sdougm * sa_destroy_security(security) 28823034Sdougm * 28833034Sdougm * Remove the specified optionset from the document and the 28843034Sdougm * configuration. 28853034Sdougm */ 28863034Sdougm 28873034Sdougm int 28883034Sdougm sa_destroy_security(sa_security_t security) 28893034Sdougm { 28904327Sdougm char name[SA_STRSIZE]; 28913034Sdougm int len; 28923034Sdougm int ret = SA_OK; 28933034Sdougm char *id = NULL; 28943034Sdougm sa_group_t group; 28953034Sdougm int iszfs = 0; 28963034Sdougm int ispersist = 1; 28973034Sdougm 28983034Sdougm group = sa_get_optionset_parent(security); 28993034Sdougm 29003034Sdougm if (group != NULL) 29014327Sdougm iszfs = sa_group_is_zfs(group); 29023034Sdougm 29033034Sdougm if (group != NULL && !iszfs) { 29044327Sdougm if (sa_is_share(group)) 29055331Samw ispersist = sa_is_persistent(group); 29064327Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 29073034Sdougm } 29083034Sdougm if (ispersist) { 29094327Sdougm len = sa_security_name(security, name, sizeof (name), id); 29104327Sdougm if (!iszfs && len > 0) { 29114327Sdougm sa_handle_impl_t impl_handle; 29124327Sdougm impl_handle = 29134327Sdougm (sa_handle_impl_t)sa_find_group_handle(group); 29144327Sdougm if (impl_handle != NULL) { 29154327Sdougm ret = sa_delete_pgroup(impl_handle->scfhandle, 29164327Sdougm name); 29174327Sdougm } else { 29184327Sdougm ret = SA_SYSTEM_ERR; 29194327Sdougm } 29203910Sdougm } 29213034Sdougm } 29223034Sdougm xmlUnlinkNode((xmlNodePtr)security); 29233034Sdougm xmlFreeNode((xmlNodePtr)security); 29244327Sdougm if (iszfs) 29254327Sdougm ret = sa_zfs_update(group); 29263034Sdougm if (id != NULL) 29274327Sdougm sa_free_attr_string(id); 29283034Sdougm return (ret); 29293034Sdougm } 29303034Sdougm 29313034Sdougm /* 29323034Sdougm * sa_get_security_attr(optionset, tag) 29333034Sdougm * 29343034Sdougm * Return the specified attribute value from the optionset. 29353034Sdougm */ 29363034Sdougm 29373034Sdougm char * 29383034Sdougm sa_get_security_attr(sa_property_t optionset, char *tag) 29393034Sdougm { 29403034Sdougm return (get_node_attr((void *)optionset, tag)); 29413034Sdougm 29423034Sdougm } 29433034Sdougm 29443034Sdougm /* 29453034Sdougm * sa_set_security_attr(optionset, tag, value) 29463034Sdougm * 29473034Sdougm * Set the optioset attribute specied by tag to the specified value. 29483034Sdougm */ 29493034Sdougm 29503034Sdougm void 29513034Sdougm sa_set_security_attr(sa_group_t optionset, char *tag, char *value) 29523034Sdougm { 29533034Sdougm set_node_attr((void *)optionset, tag, value); 29543034Sdougm } 29553034Sdougm 29563034Sdougm /* 29573034Sdougm * is_nodetype(node, type) 29583034Sdougm * 29593034Sdougm * Check to see if node is of the type specified. 29603034Sdougm */ 29613034Sdougm 29623034Sdougm static int 29633034Sdougm is_nodetype(void *node, char *type) 29643034Sdougm { 29653034Sdougm return (strcmp((char *)((xmlNodePtr)node)->name, type) == 0); 29663034Sdougm } 29673034Sdougm 29684327Sdougm /* 29694327Sdougm * add_or_update() 29704327Sdougm * 29714327Sdougm * Add or update a property. Pulled out of sa_set_prop_by_prop for 29724327Sdougm * readability. 29734327Sdougm */ 29744327Sdougm static int 29754327Sdougm add_or_update(scfutilhandle_t *scf_handle, int type, scf_value_t *value, 29764327Sdougm scf_transaction_entry_t *entry, char *name, char *valstr) 29774327Sdougm { 29784327Sdougm int ret = SA_SYSTEM_ERR; 29794327Sdougm 29804327Sdougm if (value != NULL) { 29814327Sdougm if (type == SA_PROP_OP_ADD) 29824327Sdougm ret = scf_transaction_property_new(scf_handle->trans, 29834327Sdougm entry, name, SCF_TYPE_ASTRING); 29844327Sdougm else 29854327Sdougm ret = scf_transaction_property_change(scf_handle->trans, 29864327Sdougm entry, name, SCF_TYPE_ASTRING); 29874327Sdougm if (ret == 0) { 29884327Sdougm ret = scf_value_set_astring(value, valstr); 29894327Sdougm if (ret == 0) 29904327Sdougm ret = scf_entry_add_value(entry, value); 29914327Sdougm if (ret == 0) 29924327Sdougm return (ret); 29934327Sdougm scf_value_destroy(value); 29944327Sdougm } else { 29954327Sdougm scf_entry_destroy(entry); 29964327Sdougm } 29974327Sdougm } 29984327Sdougm return (SA_SYSTEM_ERR); 29994327Sdougm } 30004327Sdougm 30013034Sdougm /* 30023034Sdougm * sa_set_prop_by_prop(optionset, group, prop, type) 30033034Sdougm * 30043034Sdougm * Add/remove/update the specified property prop into the optionset or 30053034Sdougm * share. If a share, sort out which property group based on GUID. In 30063034Sdougm * all cases, the appropriate transaction is set (or ZFS share is 30073034Sdougm * marked as needing an update) 30083034Sdougm */ 30093034Sdougm 30103034Sdougm static int 30113034Sdougm sa_set_prop_by_prop(sa_optionset_t optionset, sa_group_t group, 30123034Sdougm sa_property_t prop, int type) 30133034Sdougm { 30143034Sdougm char *name; 30153034Sdougm char *valstr; 30163034Sdougm int ret = SA_OK; 30173034Sdougm scf_transaction_entry_t *entry; 30183034Sdougm scf_value_t *value; 30193034Sdougm int opttype; /* 1 == optionset, 0 == security */ 30203034Sdougm char *id = NULL; 30213034Sdougm int iszfs = 0; 30223034Sdougm sa_group_t parent = NULL; 30235331Samw sa_share_t share = NULL; 30243910Sdougm sa_handle_impl_t impl_handle; 30253910Sdougm scfutilhandle_t *scf_handle; 30263034Sdougm 30275331Samw if (!sa_is_persistent(group)) { 30283034Sdougm /* 30293034Sdougm * if the group/share is not persistent we don't need 30303034Sdougm * to do anything here 30313034Sdougm */ 30324327Sdougm return (SA_OK); 30333034Sdougm } 30343910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 30354327Sdougm if (impl_handle == NULL || impl_handle->scfhandle == NULL) 30364327Sdougm return (SA_SYSTEM_ERR); 30373910Sdougm scf_handle = impl_handle->scfhandle; 30383034Sdougm name = sa_get_property_attr(prop, "type"); 30393034Sdougm valstr = sa_get_property_attr(prop, "value"); 30403034Sdougm entry = scf_entry_create(scf_handle->handle); 30413034Sdougm opttype = is_nodetype((void *)optionset, "optionset"); 30423034Sdougm 30435331Samw /* 30445331Samw * Check for share vs. resource since they need slightly 30455331Samw * different treatment given the hierarchy. 30465331Samw */ 30473034Sdougm if (valstr != NULL && entry != NULL) { 30484327Sdougm if (sa_is_share(group)) { 30494327Sdougm parent = sa_get_parent_group(group); 30505331Samw share = (sa_share_t)group; 30514327Sdougm if (parent != NULL) 30524327Sdougm iszfs = is_zfs_group(parent); 30535331Samw } else if (sa_is_resource(group)) { 30545331Samw share = sa_get_parent_group(group); 30555331Samw if (share != NULL) 30565331Samw parent = sa_get_parent_group(share); 30574327Sdougm } else { 30584327Sdougm iszfs = is_zfs_group(group); 30593034Sdougm } 30604327Sdougm if (!iszfs) { 30614327Sdougm if (scf_handle->trans == NULL) { 30624327Sdougm char oname[SA_STRSIZE]; 30634327Sdougm char *groupname = NULL; 30645331Samw if (share != NULL) { 30655331Samw if (parent != NULL) 30664327Sdougm groupname = 30674327Sdougm sa_get_group_attr(parent, 30684327Sdougm "name"); 30695331Samw id = sa_get_share_attr( 30705331Samw (sa_share_t)share, "id"); 30714327Sdougm } else { 30724327Sdougm groupname = sa_get_group_attr(group, 30734327Sdougm "name"); 30744327Sdougm } 30754327Sdougm if (groupname != NULL) { 30764327Sdougm ret = sa_get_instance(scf_handle, 30774327Sdougm groupname); 30784327Sdougm sa_free_attr_string(groupname); 30794327Sdougm } 30804327Sdougm if (opttype) 30814327Sdougm (void) sa_optionset_name(optionset, 30824327Sdougm oname, sizeof (oname), id); 30834327Sdougm else 30844327Sdougm (void) sa_security_name(optionset, 30854327Sdougm oname, sizeof (oname), id); 30864327Sdougm ret = sa_start_transaction(scf_handle, oname); 30873910Sdougm } 30884327Sdougm if (ret == SA_OK) { 30894327Sdougm switch (type) { 30904327Sdougm case SA_PROP_OP_REMOVE: 30914327Sdougm ret = scf_transaction_property_delete( 30924327Sdougm scf_handle->trans, entry, name); 30934327Sdougm break; 30944327Sdougm case SA_PROP_OP_ADD: 30954327Sdougm case SA_PROP_OP_UPDATE: 30964327Sdougm value = scf_value_create( 30974327Sdougm scf_handle->handle); 30984327Sdougm ret = add_or_update(scf_handle, type, 30994327Sdougm value, entry, name, valstr); 31004327Sdougm break; 31013034Sdougm } 31023034Sdougm } 31034327Sdougm } else { 31044327Sdougm /* 31054327Sdougm * ZFS update. The calling function would have updated 31064327Sdougm * the internal XML structure. Just need to flag it as 31074327Sdougm * changed for ZFS. 31084327Sdougm */ 31094327Sdougm zfs_set_update((sa_share_t)group); 31104327Sdougm } 31113034Sdougm } 31123034Sdougm 31133034Sdougm if (name != NULL) 31144327Sdougm sa_free_attr_string(name); 31153034Sdougm if (valstr != NULL) 31164327Sdougm sa_free_attr_string(valstr); 31173034Sdougm else if (entry != NULL) 31184327Sdougm scf_entry_destroy(entry); 31193034Sdougm 31203034Sdougm if (ret == -1) 31214327Sdougm ret = SA_SYSTEM_ERR; 31223034Sdougm 31233034Sdougm return (ret); 31243034Sdougm } 31253034Sdougm 31263034Sdougm /* 31273034Sdougm * sa_create_property(name, value) 31283034Sdougm * 31293034Sdougm * Create a new property with the specified name and value. 31303034Sdougm */ 31313034Sdougm 31323034Sdougm sa_property_t 31333034Sdougm sa_create_property(char *name, char *value) 31343034Sdougm { 31353034Sdougm xmlNodePtr node; 31363034Sdougm 31373034Sdougm node = xmlNewNode(NULL, (xmlChar *)"option"); 31383034Sdougm if (node != NULL) { 31393034Sdougm xmlSetProp(node, (xmlChar *)"type", (xmlChar *)name); 31403034Sdougm xmlSetProp(node, (xmlChar *)"value", (xmlChar *)value); 31413034Sdougm } 31423034Sdougm return ((sa_property_t)node); 31433034Sdougm } 31443034Sdougm 31453034Sdougm /* 31463034Sdougm * sa_add_property(object, property) 31473034Sdougm * 31483034Sdougm * Add the specified property to the object. Issue the appropriate 31493034Sdougm * transaction or mark a ZFS object as needing an update. 31503034Sdougm */ 31513034Sdougm 31523034Sdougm int 31533034Sdougm sa_add_property(void *object, sa_property_t property) 31543034Sdougm { 31553034Sdougm int ret = SA_OK; 31563034Sdougm sa_group_t parent; 31573034Sdougm sa_group_t group; 31583034Sdougm char *proto; 31593034Sdougm 31603034Sdougm proto = sa_get_optionset_attr(object, "type"); 31613034Sdougm if (property != NULL) { 31624327Sdougm if ((ret = sa_valid_property(object, proto, property)) == 31634327Sdougm SA_OK) { 31644327Sdougm property = (sa_property_t)xmlAddChild( 31654327Sdougm (xmlNodePtr)object, (xmlNodePtr)property); 31664327Sdougm } else { 31674327Sdougm if (proto != NULL) 31684327Sdougm sa_free_attr_string(proto); 31694327Sdougm return (ret); 31704327Sdougm } 31713034Sdougm } 31723034Sdougm 31733034Sdougm if (proto != NULL) 31744327Sdougm sa_free_attr_string(proto); 31753034Sdougm 31763034Sdougm parent = sa_get_parent_group(object); 31775331Samw if (!sa_is_persistent(parent)) 31784327Sdougm return (ret); 31795331Samw 31805331Samw if (sa_is_resource(parent)) { 31815331Samw /* 31825331Samw * Resources are children of share. Need to go up two 31835331Samw * levels to find the group but the parent needs to be 31845331Samw * the share at this point in order to get the "id". 31855331Samw */ 31865331Samw parent = sa_get_parent_group(parent); 31875331Samw group = sa_get_parent_group(parent); 31885331Samw } else if (sa_is_share(parent)) { 31895331Samw group = sa_get_parent_group(parent); 31905331Samw } else { 31915331Samw group = parent; 31923034Sdougm } 31933034Sdougm 31944327Sdougm if (property == NULL) { 31954327Sdougm ret = SA_NO_MEMORY; 31964327Sdougm } else { 31974327Sdougm char oname[SA_STRSIZE]; 31983034Sdougm 31994327Sdougm if (!is_zfs_group(group)) { 32004327Sdougm char *id = NULL; 32014327Sdougm sa_handle_impl_t impl_handle; 32024327Sdougm scfutilhandle_t *scf_handle; 32033910Sdougm 32044327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle( 32054327Sdougm group); 32064327Sdougm if (impl_handle == NULL || 32074327Sdougm impl_handle->scfhandle == NULL) 32084327Sdougm ret = SA_SYSTEM_ERR; 32094327Sdougm if (ret == SA_OK) { 32104327Sdougm scf_handle = impl_handle->scfhandle; 32114327Sdougm if (sa_is_share((sa_group_t)parent)) { 32124327Sdougm id = sa_get_share_attr( 32134327Sdougm (sa_share_t)parent, "id"); 32144327Sdougm } 32154327Sdougm if (scf_handle->trans == NULL) { 32164327Sdougm if (is_nodetype(object, "optionset")) { 32174327Sdougm (void) sa_optionset_name( 32184327Sdougm (sa_optionset_t)object, 32194327Sdougm oname, sizeof (oname), id); 32204327Sdougm } else { 32214327Sdougm (void) sa_security_name( 32224327Sdougm (sa_optionset_t)object, 32234327Sdougm oname, sizeof (oname), id); 32244327Sdougm } 32254327Sdougm ret = sa_start_transaction(scf_handle, 32264327Sdougm oname); 32274327Sdougm } 32284327Sdougm if (ret == SA_OK) { 32294327Sdougm char *name; 32304327Sdougm char *value; 32314327Sdougm name = sa_get_property_attr(property, 32324327Sdougm "type"); 32334327Sdougm value = sa_get_property_attr(property, 32344327Sdougm "value"); 32354327Sdougm if (name != NULL && value != NULL) { 32364327Sdougm if (scf_handle->scf_state == 32374327Sdougm SCH_STATE_INIT) { 32384327Sdougm ret = sa_set_property( 32394327Sdougm scf_handle, name, 32404327Sdougm value); 32414327Sdougm } 32424327Sdougm } else { 32434327Sdougm ret = SA_CONFIG_ERR; 32444327Sdougm } 32454327Sdougm if (name != NULL) 32464327Sdougm sa_free_attr_string( 32474327Sdougm name); 32484327Sdougm if (value != NULL) 32494327Sdougm sa_free_attr_string(value); 32504327Sdougm } 32514327Sdougm if (id != NULL) 32524327Sdougm sa_free_attr_string(id); 32534327Sdougm } 32544327Sdougm } else { 32554327Sdougm /* 32564327Sdougm * ZFS is a special case. We do want 32574327Sdougm * to allow editing property/security 32584327Sdougm * lists since we can have a better 32594327Sdougm * syntax and we also want to keep 32604327Sdougm * things consistent when possible. 32614327Sdougm * 32624327Sdougm * Right now, we defer until the 32634327Sdougm * sa_commit_properties so we can get 32644327Sdougm * them all at once. We do need to 32654327Sdougm * mark the share as "changed" 32664327Sdougm */ 32674327Sdougm zfs_set_update((sa_share_t)parent); 32683034Sdougm } 32693034Sdougm } 32703034Sdougm return (ret); 32713034Sdougm } 32723034Sdougm 32733034Sdougm /* 32743034Sdougm * sa_remove_property(property) 32753034Sdougm * 32763034Sdougm * Remove the specied property from its containing object. Update the 32773034Sdougm * repository as appropriate. 32783034Sdougm */ 32793034Sdougm 32803034Sdougm int 32813034Sdougm sa_remove_property(sa_property_t property) 32823034Sdougm { 32833034Sdougm int ret = SA_OK; 32843034Sdougm 32853034Sdougm if (property != NULL) { 32863034Sdougm sa_optionset_t optionset; 32873034Sdougm sa_group_t group; 32883034Sdougm optionset = sa_get_property_parent(property); 32893034Sdougm if (optionset != NULL) { 32904327Sdougm group = sa_get_optionset_parent(optionset); 32914327Sdougm if (group != NULL) { 32924327Sdougm ret = sa_set_prop_by_prop(optionset, group, 32934327Sdougm property, SA_PROP_OP_REMOVE); 32944327Sdougm } 32953034Sdougm } 32963034Sdougm xmlUnlinkNode((xmlNodePtr)property); 32973034Sdougm xmlFreeNode((xmlNodePtr)property); 32983034Sdougm } else { 32994327Sdougm ret = SA_NO_SUCH_PROP; 33003034Sdougm } 33013034Sdougm return (ret); 33023034Sdougm } 33033034Sdougm 33043034Sdougm /* 33053034Sdougm * sa_update_property(property, value) 33063034Sdougm * 33073034Sdougm * Update the specified property to the new value. If value is NULL, 33083034Sdougm * we currently treat this as a remove. 33093034Sdougm */ 33103034Sdougm 33113034Sdougm int 33123034Sdougm sa_update_property(sa_property_t property, char *value) 33133034Sdougm { 33143034Sdougm int ret = SA_OK; 33153034Sdougm if (value == NULL) { 33163034Sdougm return (sa_remove_property(property)); 33173034Sdougm } else { 33183034Sdougm sa_optionset_t optionset; 33193034Sdougm sa_group_t group; 33203034Sdougm set_node_attr((void *)property, "value", value); 33213034Sdougm optionset = sa_get_property_parent(property); 33223034Sdougm if (optionset != NULL) { 33234327Sdougm group = sa_get_optionset_parent(optionset); 33244327Sdougm if (group != NULL) { 33254327Sdougm ret = sa_set_prop_by_prop(optionset, group, 33264327Sdougm property, SA_PROP_OP_UPDATE); 33274327Sdougm } 33283034Sdougm } else { 33294327Sdougm ret = SA_NO_SUCH_PROP; 33303034Sdougm } 33313034Sdougm } 33323034Sdougm return (ret); 33333034Sdougm } 33343034Sdougm 33353034Sdougm /* 33363034Sdougm * sa_get_protocol_property(propset, prop) 33373034Sdougm * 33383034Sdougm * Get the specified protocol specific property. These are global to 33393034Sdougm * the protocol and not specific to a group or share. 33403034Sdougm */ 33413034Sdougm 33423034Sdougm sa_property_t 33433034Sdougm sa_get_protocol_property(sa_protocol_properties_t propset, char *prop) 33443034Sdougm { 33453034Sdougm xmlNodePtr node = (xmlNodePtr)propset; 33463034Sdougm xmlChar *value = NULL; 33473034Sdougm 33483034Sdougm for (node = node->children; node != NULL; 33494327Sdougm node = node->next) { 33504327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 33514327Sdougm if (prop == NULL) 33524327Sdougm break; 33534327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 33544327Sdougm if (value != NULL && 33554327Sdougm xmlStrcasecmp(value, (xmlChar *)prop) == 0) { 33564327Sdougm break; 33574327Sdougm } 33584327Sdougm if (value != NULL) { 33594327Sdougm xmlFree(value); 33604327Sdougm value = NULL; 33614327Sdougm } 33623034Sdougm } 33633034Sdougm } 33643034Sdougm if (value != NULL) 33653034Sdougm xmlFree(value); 33663034Sdougm if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"option") != 0) { 33674327Sdougm /* 33684327Sdougm * avoid a non option node -- it is possible to be a 33694327Sdougm * text node 33704327Sdougm */ 33714327Sdougm node = NULL; 33723034Sdougm } 33733034Sdougm return ((sa_property_t)node); 33743034Sdougm } 33753034Sdougm 33763034Sdougm /* 33773034Sdougm * sa_get_next_protocol_property(prop) 33783034Sdougm * 33793034Sdougm * Get the next protocol specific property in the list. 33803034Sdougm */ 33813034Sdougm 33823034Sdougm sa_property_t 33833034Sdougm sa_get_next_protocol_property(sa_property_t prop) 33843034Sdougm { 33853034Sdougm xmlNodePtr node; 33863034Sdougm 33873034Sdougm for (node = ((xmlNodePtr)prop)->next; node != NULL; 33884327Sdougm node = node->next) { 33893034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 33903034Sdougm break; 33913034Sdougm } 33923034Sdougm } 33933034Sdougm return ((sa_property_t)node); 33943034Sdougm } 33953034Sdougm 33963034Sdougm /* 33973034Sdougm * sa_set_protocol_property(prop, value) 33983034Sdougm * 33993034Sdougm * Set the specified property to have the new value. The protocol 34003034Sdougm * specific plugin will then be called to update the property. 34013034Sdougm */ 34023034Sdougm 34033034Sdougm int 34043034Sdougm sa_set_protocol_property(sa_property_t prop, char *value) 34053034Sdougm { 34063034Sdougm sa_protocol_properties_t propset; 34073034Sdougm char *proto; 34083034Sdougm int ret = SA_INVALID_PROTOCOL; 34093034Sdougm 34103034Sdougm propset = ((xmlNodePtr)prop)->parent; 34113034Sdougm if (propset != NULL) { 34124327Sdougm proto = sa_get_optionset_attr(propset, "type"); 34134327Sdougm if (proto != NULL) { 34144327Sdougm set_node_attr((xmlNodePtr)prop, "value", value); 34154327Sdougm ret = sa_proto_set_property(proto, prop); 34164327Sdougm sa_free_attr_string(proto); 34174327Sdougm } 34183034Sdougm } 34193034Sdougm return (ret); 34203034Sdougm } 34213034Sdougm 34223034Sdougm /* 34233034Sdougm * sa_add_protocol_property(propset, prop) 34243034Sdougm * 34255331Samw * Add a new property to the protocol specific property set. 34263034Sdougm */ 34273034Sdougm 34283034Sdougm int 34293034Sdougm sa_add_protocol_property(sa_protocol_properties_t propset, sa_property_t prop) 34303034Sdougm { 34313034Sdougm xmlNodePtr node; 34323034Sdougm 34333034Sdougm /* should check for legitimacy */ 34343034Sdougm node = xmlAddChild((xmlNodePtr)propset, (xmlNodePtr)prop); 34353034Sdougm if (node != NULL) 34364327Sdougm return (SA_OK); 34373034Sdougm return (SA_NO_MEMORY); 34383034Sdougm } 34393034Sdougm 34403034Sdougm /* 34413034Sdougm * sa_create_protocol_properties(proto) 34423034Sdougm * 34435331Samw * Create a protocol specific property set. 34443034Sdougm */ 34453034Sdougm 34463034Sdougm sa_protocol_properties_t 34473034Sdougm sa_create_protocol_properties(char *proto) 34483034Sdougm { 34493034Sdougm xmlNodePtr node; 34504327Sdougm 34513034Sdougm node = xmlNewNode(NULL, (xmlChar *)"propertyset"); 34524327Sdougm if (node != NULL) 34534327Sdougm xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto); 34543034Sdougm return (node); 34553034Sdougm } 34565331Samw 34575331Samw /* 34585331Samw * sa_get_share_resource(share, resource) 34595331Samw * 34605331Samw * Get the named resource from the share, if it exists. If resource is 34615331Samw * NULL, get the first resource. 34625331Samw */ 34635331Samw 34645331Samw sa_resource_t 34655331Samw sa_get_share_resource(sa_share_t share, char *resource) 34665331Samw { 34675331Samw xmlNodePtr node = NULL; 34685331Samw xmlChar *name; 34695331Samw 34705331Samw if (share != NULL) { 34715331Samw for (node = ((xmlNodePtr)share)->children; node != NULL; 34725331Samw node = node->next) { 34735331Samw if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0) { 34745331Samw if (resource == NULL) { 34755331Samw /* 34765331Samw * We are looking for the first 34775331Samw * resource node and not a names 34785331Samw * resource. 34795331Samw */ 34805331Samw break; 34815331Samw } else { 34825331Samw /* is it the correct share? */ 34835331Samw name = xmlGetProp(node, 34845331Samw (xmlChar *)"name"); 34855331Samw if (name != NULL && 34865331Samw xmlStrcasecmp(name, 34875331Samw (xmlChar *)resource) == 0) { 34885331Samw xmlFree(name); 34895331Samw break; 34905331Samw } 34915331Samw xmlFree(name); 34925331Samw } 34935331Samw } 34945331Samw } 34955331Samw } 34965331Samw return ((sa_resource_t)node); 34975331Samw } 34985331Samw 34995331Samw /* 35005331Samw * sa_get_next_resource(resource) 35015331Samw * Return the next share following the specified share 35025331Samw * from the internal list of shares. Returns NULL if there 35035331Samw * are no more shares. The list is relative to the same 35045331Samw * group. 35055331Samw */ 35065331Samw sa_share_t 35075331Samw sa_get_next_resource(sa_resource_t resource) 35085331Samw { 35095331Samw xmlNodePtr node = NULL; 35105331Samw 35115331Samw if (resource != NULL) { 35125331Samw for (node = ((xmlNodePtr)resource)->next; node != NULL; 35135331Samw node = node->next) { 35145331Samw if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0) 35155331Samw break; 35165331Samw } 35175331Samw } 35185331Samw return ((sa_share_t)node); 35195331Samw } 35205331Samw 35215331Samw /* 35225331Samw * _sa_get_next_resource_index(share) 35235331Samw * 35245331Samw * get the next resource index number (one greater then current largest) 35255331Samw */ 35265331Samw 35275331Samw static int 35285331Samw _sa_get_next_resource_index(sa_share_t share) 35295331Samw { 35305331Samw sa_resource_t resource; 35315331Samw int index = 0; 35325331Samw char *id; 35335331Samw 35345331Samw for (resource = sa_get_share_resource(share, NULL); 35355331Samw resource != NULL; 35365331Samw resource = sa_get_next_resource(resource)) { 35375331Samw id = get_node_attr((void *)resource, "id"); 35385331Samw if (id != NULL) { 35395331Samw int val; 35405331Samw val = atoi(id); 35415331Samw if (val > index) 35425331Samw index = val; 35435331Samw sa_free_attr_string(id); 35445331Samw } 35455331Samw } 35465331Samw return (index + 1); 35475331Samw } 35485331Samw 35495331Samw 35505331Samw /* 35515331Samw * sa_add_resource(share, resource, persist, &err) 35525331Samw * 35535331Samw * Adds a new resource name associated with share. The resource name 35545331Samw * must be unique in the system and will be case insensitive (eventually). 35555331Samw */ 35565331Samw 35575331Samw sa_resource_t 35585331Samw sa_add_resource(sa_share_t share, char *resource, int persist, int *error) 35595331Samw { 35605331Samw xmlNodePtr node; 35615331Samw int err = SA_OK; 35625331Samw sa_resource_t res; 35635331Samw sa_group_t group; 35645331Samw sa_handle_t handle; 35655331Samw char istring[8]; /* just big enough for an integer value */ 35665331Samw int index; 35675331Samw 35685331Samw group = sa_get_parent_group(share); 35695331Samw handle = sa_find_group_handle(group); 35705331Samw res = sa_find_resource(handle, resource); 35715331Samw if (res != NULL) { 35725331Samw err = SA_DUPLICATE_NAME; 35735331Samw res = NULL; 35745331Samw } else { 35755331Samw node = xmlNewChild((xmlNodePtr)share, NULL, 35765331Samw (xmlChar *)"resource", NULL); 35775331Samw if (node != NULL) { 35785331Samw xmlSetProp(node, (xmlChar *)"name", 35795331Samw (xmlChar *)resource); 35805331Samw xmlSetProp(node, (xmlChar *)"type", persist ? 35815331Samw (xmlChar *)"persist" : (xmlChar *)"transient"); 35825331Samw if (persist != SA_SHARE_TRANSIENT) { 35835331Samw index = _sa_get_next_resource_index(share); 35845331Samw (void) snprintf(istring, sizeof (istring), "%d", 35855331Samw index); 35865331Samw xmlSetProp(node, (xmlChar *)"id", 35875331Samw (xmlChar *)istring); 35885331Samw if (!sa_group_is_zfs(group) && 35895331Samw sa_is_persistent((sa_group_t)share)) { 35905331Samw /* ZFS doesn't use resource names */ 35915331Samw sa_handle_impl_t ihandle; 35925331Samw ihandle = (sa_handle_impl_t) 35935331Samw sa_find_group_handle( 35945331Samw group); 35955331Samw if (ihandle != NULL) 35965331Samw err = sa_commit_share( 35975331Samw ihandle->scfhandle, group, 35985331Samw share); 35995331Samw else 36005331Samw err = SA_SYSTEM_ERR; 36015331Samw } 36025331Samw } 36035331Samw } 36045331Samw } 36055331Samw if (error != NULL) 36065331Samw *error = err; 36075331Samw return ((sa_resource_t)node); 36085331Samw } 36095331Samw 36105331Samw /* 36115331Samw * sa_remove_resource(resource) 36125331Samw * 36135331Samw * Remove the resource name from the share (and the system) 36145331Samw */ 36155331Samw 36165331Samw int 36175331Samw sa_remove_resource(sa_resource_t resource) 36185331Samw { 36195331Samw sa_share_t share; 36205331Samw sa_group_t group; 36215331Samw char *type; 36225331Samw int ret = SA_OK; 36235331Samw int transient = 0; 36245521Sas200622 sa_optionset_t opt; 36255331Samw 36265331Samw share = sa_get_resource_parent(resource); 36275331Samw type = sa_get_share_attr(share, "type"); 36285331Samw group = sa_get_parent_group(share); 36295331Samw 36305331Samw 36315331Samw if (type != NULL) { 36325331Samw if (strcmp(type, "persist") != 0) 36335331Samw transient = 1; 36345331Samw sa_free_attr_string(type); 36355331Samw } 36365331Samw 36375521Sas200622 /* Disable the resource for all protocols. */ 36385521Sas200622 (void) sa_disable_resource(resource, NULL); 36395521Sas200622 36405521Sas200622 /* Remove any optionsets from the resource. */ 36415521Sas200622 for (opt = sa_get_optionset(resource, NULL); 36425521Sas200622 opt != NULL; 36435521Sas200622 opt = sa_get_next_optionset(opt)) 36445521Sas200622 (void) sa_destroy_optionset(opt); 36455521Sas200622 36465331Samw /* Remove from the share */ 36475331Samw xmlUnlinkNode((xmlNode *)resource); 36485331Samw xmlFreeNode((xmlNode *)resource); 36495331Samw 36505331Samw /* only do SMF action if permanent and not ZFS */ 36515331Samw if (!transient && !sa_group_is_zfs(group)) { 36525331Samw sa_handle_impl_t ihandle; 36535331Samw ihandle = (sa_handle_impl_t)sa_find_group_handle(group); 36545331Samw if (ihandle != NULL) 36555331Samw ret = sa_commit_share(ihandle->scfhandle, group, share); 36565331Samw else 36575331Samw ret = SA_SYSTEM_ERR; 36585331Samw } 36595331Samw return (ret); 36605331Samw } 36615331Samw 36625331Samw /* 36635331Samw * proto_resource_rename(handle, group, resource, newname) 36645331Samw * 36655331Samw * Helper function for sa_rename_resource that notifies the protocol 36665331Samw * of a resource name change prior to a config repository update. 36675331Samw */ 36685331Samw static int 36695331Samw proto_rename_resource(sa_handle_t handle, sa_group_t group, 36705331Samw sa_resource_t resource, char *newname) 36715331Samw { 36725331Samw sa_optionset_t optionset; 36735331Samw int ret = SA_OK; 36745331Samw int err; 36755331Samw 36765331Samw for (optionset = sa_get_optionset(group, NULL); 36775331Samw optionset != NULL; 36785331Samw optionset = sa_get_next_optionset(optionset)) { 36795331Samw char *type; 36805331Samw type = sa_get_optionset_attr(optionset, "type"); 36815331Samw if (type != NULL) { 36825331Samw err = sa_proto_rename_resource(handle, type, resource, 36835331Samw newname); 36845331Samw if (err != SA_OK) 36855331Samw ret = err; 36865331Samw sa_free_attr_string(type); 36875331Samw } 36885331Samw } 36895331Samw return (ret); 36905331Samw } 36915331Samw 36925331Samw /* 36935331Samw * sa_rename_resource(resource, newname) 36945331Samw * 36955331Samw * Rename the resource to the new name, if it is unique. 36965331Samw */ 36975331Samw 36985331Samw int 36995331Samw sa_rename_resource(sa_resource_t resource, char *newname) 37005331Samw { 37015331Samw sa_share_t share; 37025331Samw sa_group_t group = NULL; 37035331Samw sa_resource_t target; 37045331Samw int ret = SA_CONFIG_ERR; 37055331Samw sa_handle_t handle = NULL; 37065331Samw 37075331Samw share = sa_get_resource_parent(resource); 37085331Samw if (share == NULL) 37095331Samw return (ret); 37105331Samw 37115331Samw group = sa_get_parent_group(share); 37125331Samw if (group == NULL) 37135331Samw return (ret); 37145331Samw 37155331Samw handle = (sa_handle_impl_t)sa_find_group_handle(group); 37165331Samw if (handle == NULL) 37175331Samw return (ret); 37185331Samw 37195331Samw target = sa_find_resource(handle, newname); 37205331Samw if (target != NULL) { 37215331Samw ret = SA_DUPLICATE_NAME; 37225331Samw } else { 37235331Samw /* 37245331Samw * Everything appears to be valid at this 37255331Samw * point. Change the name of the active share and then 37265331Samw * update the share in the appropriate repository. 37275331Samw */ 37285331Samw ret = proto_rename_resource(handle, group, resource, newname); 37295331Samw set_node_attr(resource, "name", newname); 37305331Samw if (!sa_group_is_zfs(group) && 37315331Samw sa_is_persistent((sa_group_t)share)) { 37325331Samw sa_handle_impl_t ihandle = (sa_handle_impl_t)handle; 37335331Samw ret = sa_commit_share(ihandle->scfhandle, group, 37345331Samw share); 37355331Samw } 37365331Samw } 37375331Samw return (ret); 37385331Samw } 37395331Samw 37405331Samw /* 37415331Samw * sa_get_resource_attr(resource, tag) 37425331Samw * 37435331Samw * Get the named attribute of the resource. "name" and "id" are 37445331Samw * currently defined. NULL if tag not defined. 37455331Samw */ 37465331Samw 37475331Samw char * 37485331Samw sa_get_resource_attr(sa_resource_t resource, char *tag) 37495331Samw { 37505331Samw return (get_node_attr((void *)resource, tag)); 37515331Samw } 37525331Samw 37535331Samw /* 37545331Samw * sa_set_resource_attr(resource, tag, value) 37555331Samw * 37565331Samw * Get the named attribute of the resource. "name" and "id" are 37575331Samw * currently defined. NULL if tag not defined. Currently we don't do 37585331Samw * much, but additional checking may be needed in the future. 37595331Samw */ 37605331Samw 37615331Samw int 37625331Samw sa_set_resource_attr(sa_resource_t resource, char *tag, char *value) 37635331Samw { 37645331Samw set_node_attr((void *)resource, tag, value); 37655331Samw return (SA_OK); 37665331Samw } 37675331Samw 37685331Samw /* 37695331Samw * sa_get_resource_parent(resource_t) 37705331Samw * 37715331Samw * Returns the share associated with the resource. 37725331Samw */ 37735331Samw 37745331Samw sa_share_t 37755331Samw sa_get_resource_parent(sa_resource_t resource) 37765331Samw { 37775331Samw sa_share_t share = NULL; 37785331Samw 37795331Samw if (resource != NULL) 37805331Samw share = (sa_share_t)((xmlNodePtr)resource)->parent; 37815331Samw return (share); 37825331Samw } 37835331Samw 37845331Samw /* 37855331Samw * find_resource(group, name) 37865331Samw * 37875331Samw * Find the resource within the group. 37885331Samw */ 37895331Samw 37905331Samw static sa_resource_t 37915331Samw find_resource(sa_group_t group, char *resname) 37925331Samw { 37935331Samw sa_share_t share; 37945331Samw sa_resource_t resource = NULL; 37955331Samw char *name; 37965331Samw 37975331Samw /* Iterate over all the shares and resources in the group. */ 37985331Samw for (share = sa_get_share(group, NULL); 37995331Samw share != NULL && resource == NULL; 38005331Samw share = sa_get_next_share(share)) { 38015331Samw for (resource = sa_get_share_resource(share, NULL); 38025331Samw resource != NULL; 38035331Samw resource = sa_get_next_resource(resource)) { 38045331Samw name = sa_get_resource_attr(resource, "name"); 38055331Samw if (name != NULL && xmlStrcasecmp((xmlChar*)name, 38065331Samw (xmlChar*)resname) == 0) { 38075331Samw sa_free_attr_string(name); 38085331Samw break; 38095331Samw } 38105331Samw if (name != NULL) { 38115331Samw sa_free_attr_string(name); 38125331Samw } 38135331Samw } 38145331Samw } 38155331Samw return (resource); 38165331Samw } 38175331Samw 38185331Samw /* 38195331Samw * sa_find_resource(name) 38205331Samw * 38215331Samw * Find the named resource in the system. 38225331Samw */ 38235331Samw 38245331Samw sa_resource_t 38255331Samw sa_find_resource(sa_handle_t handle, char *name) 38265331Samw { 38275331Samw sa_group_t group; 38285331Samw sa_group_t zgroup; 38295331Samw sa_resource_t resource = NULL; 38305331Samw 38315331Samw /* 38325331Samw * Iterate over all groups and zfs subgroups and check for 38335331Samw * resource name in them. 38345331Samw */ 38355331Samw for (group = sa_get_group(handle, NULL); group != NULL; 38365331Samw group = sa_get_next_group(group)) { 38375331Samw 38385331Samw if (is_zfs_group(group)) { 38395331Samw for (zgroup = 38405331Samw (sa_group_t)_sa_get_child_node((xmlNodePtr)group, 38415331Samw (xmlChar *)"group"); 38425331Samw zgroup != NULL && resource == NULL; 38435331Samw zgroup = sa_get_next_group(zgroup)) { 38445331Samw resource = find_resource(zgroup, name); 38455331Samw } 38465331Samw } else { 38475331Samw resource = find_resource(group, name); 38485331Samw } 38495331Samw if (resource != NULL) 38505331Samw break; 38515331Samw } 38525331Samw return (resource); 38535331Samw } 38545331Samw 38555331Samw /* 38565331Samw * sa_get_resource(group, resource) 38575331Samw * 38585331Samw * Search all the shares in the specified group for a share with a 38595331Samw * resource name matching the one specified. 38605331Samw * 38615331Samw * In the future, it may be advantageous to allow group to be NULL and 38625331Samw * search all groups but that isn't needed at present. 38635331Samw */ 38645331Samw 38655331Samw sa_resource_t 38665331Samw sa_get_resource(sa_group_t group, char *resource) 38675331Samw { 38685331Samw sa_share_t share = NULL; 38695331Samw sa_resource_t res = NULL; 38705331Samw 38715331Samw if (resource != NULL) { 38725331Samw for (share = sa_get_share(group, NULL); 38735331Samw share != NULL && res == NULL; 38745331Samw share = sa_get_next_share(share)) { 38755331Samw res = sa_get_share_resource(share, resource); 38765331Samw } 38775331Samw } 38785331Samw return (res); 38795331Samw } 38805331Samw 38815331Samw /* 38825331Samw * sa_enable_resource, protocol) 38835331Samw * Disable the specified share to the specified protocol. 38845331Samw * If protocol is NULL, then all protocols. 38855331Samw */ 38865331Samw int 38875331Samw sa_enable_resource(sa_resource_t resource, char *protocol) 38885331Samw { 38895331Samw int ret = SA_OK; 38905331Samw char **protocols; 38915331Samw int numproto; 38925331Samw 38935331Samw if (protocol != NULL) { 38945331Samw ret = sa_proto_share_resource(protocol, resource); 38955331Samw } else { 38965331Samw /* need to do all protocols */ 38975331Samw if ((numproto = sa_get_protocols(&protocols)) >= 0) { 38985331Samw int i, err; 38995331Samw for (i = 0; i < numproto; i++) { 39005331Samw err = sa_proto_share_resource( 39015331Samw protocols[i], resource); 39025331Samw if (err != SA_OK) 39035331Samw ret = err; 39045331Samw } 39055331Samw free(protocols); 39065331Samw } 39075331Samw } 39085331Samw if (ret == SA_OK) 39095331Samw (void) sa_set_resource_attr(resource, "shared", NULL); 39105331Samw 39115331Samw return (ret); 39125331Samw } 39135331Samw 39145331Samw /* 39155331Samw * sa_disable_resource(resource, protocol) 39165331Samw * 39175331Samw * Disable the specified share for the specified protocol. If 39185331Samw * protocol is NULL, then all protocols. If the underlying 39195331Samw * protocol doesn't implement disable at the resource level, we 39205331Samw * disable at the share level. 39215331Samw */ 39225331Samw int 39235331Samw sa_disable_resource(sa_resource_t resource, char *protocol) 39245331Samw { 39255331Samw int ret = SA_OK; 39265331Samw char **protocols; 39275331Samw int numproto; 39285331Samw 39295331Samw if (protocol != NULL) { 39305331Samw ret = sa_proto_unshare_resource(protocol, resource); 39315331Samw if (ret == SA_NOT_IMPLEMENTED) { 39325331Samw sa_share_t parent; 39335331Samw /* 39345331Samw * The protocol doesn't implement unshare 39355331Samw * resource. That implies that resource names are 39365331Samw * simple aliases for this protocol so we need to 39375331Samw * unshare the share. 39385331Samw */ 39395331Samw parent = sa_get_resource_parent(resource); 39405331Samw if (parent != NULL) 39415331Samw ret = sa_disable_share(parent, protocol); 39425331Samw else 39435331Samw ret = SA_CONFIG_ERR; 39445331Samw } 39455331Samw } else { 39465331Samw /* need to do all protocols */ 39475331Samw if ((numproto = sa_get_protocols(&protocols)) >= 0) { 39485331Samw int i, err; 39495331Samw for (i = 0; i < numproto; i++) { 39505331Samw err = sa_proto_unshare_resource(protocols[i], 39515331Samw resource); 39525331Samw if (err == SA_NOT_SUPPORTED) { 39535331Samw sa_share_t parent; 39545331Samw parent = sa_get_resource_parent( 39555331Samw resource); 39565331Samw if (parent != NULL) 39575331Samw err = sa_disable_share(parent, 39585331Samw protocols[i]); 39595331Samw else 39605331Samw err = SA_CONFIG_ERR; 39615331Samw } 39625331Samw if (err != SA_OK) 39635331Samw ret = err; 39645331Samw } 39655331Samw free(protocols); 39665331Samw } 39675331Samw } 39685331Samw if (ret == SA_OK) 39695331Samw (void) sa_set_resource_attr(resource, "shared", NULL); 39705331Samw 39715331Samw return (ret); 39725331Samw } 39735331Samw 39745331Samw /* 39755331Samw * sa_set_resource_description(resource, content) 39765331Samw * 39775331Samw * Set the description of share to content. 39785331Samw */ 39795331Samw 39805331Samw int 39815331Samw sa_set_resource_description(sa_resource_t resource, char *content) 39825331Samw { 39835331Samw xmlNodePtr node; 39845331Samw sa_group_t group; 39855331Samw sa_share_t share; 39865331Samw int ret = SA_OK; 39875331Samw 39885331Samw for (node = ((xmlNodePtr)resource)->children; 39895331Samw node != NULL; 39905331Samw node = node->next) { 39915331Samw if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 39925331Samw break; 39935331Samw } 39945331Samw } 39955331Samw 39965331Samw /* no existing description but want to add */ 39975331Samw if (node == NULL && content != NULL) { 39985331Samw /* add a description */ 39995331Samw node = _sa_set_share_description(resource, content); 40005331Samw } else if (node != NULL && content != NULL) { 40015331Samw /* update a description */ 40025331Samw xmlNodeSetContent(node, (xmlChar *)content); 40035331Samw } else if (node != NULL && content == NULL) { 40045331Samw /* remove an existing description */ 40055331Samw xmlUnlinkNode(node); 40065331Samw xmlFreeNode(node); 40075331Samw } 40085331Samw share = sa_get_resource_parent(resource); 40095331Samw group = sa_get_parent_group(share); 40105331Samw if (group != NULL && sa_is_persistent(share)) { 40115331Samw sa_handle_impl_t impl_handle; 40125331Samw impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 40135331Samw if (impl_handle != NULL) 40145331Samw ret = sa_commit_share(impl_handle->scfhandle, 40155331Samw group, share); 40165331Samw else 40175331Samw ret = SA_SYSTEM_ERR; 40185331Samw } 40195331Samw return (ret); 40205331Samw } 40215331Samw 40225331Samw /* 40235331Samw * sa_get_resource_description(share) 40245331Samw * 40255331Samw * Return the description text for the specified share if it 40265331Samw * exists. NULL if no description exists. 40275331Samw */ 40285331Samw 40295331Samw char * 40305331Samw sa_get_resource_description(sa_resource_t resource) 40315331Samw { 40325331Samw xmlChar *description = NULL; 40335331Samw xmlNodePtr node; 40345331Samw 40355331Samw for (node = ((xmlNodePtr)resource)->children; node != NULL; 40365331Samw node = node->next) { 40375331Samw if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) 40385331Samw break; 40395331Samw } 40405331Samw if (node != NULL) { 40415331Samw description = xmlNodeGetContent(node); 40425331Samw fixproblemchars((char *)description); 40435331Samw } 40445331Samw return ((char *)description); 40455331Samw } 4046