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 /* 233348Sdougm * Copyright 2007 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 503034Sdougm #if _NOT_SMF 513034Sdougm #define CONFIG_FILE "/var/tmp/share.cfg" 523034Sdougm #define CONFIG_FILE_TMP "/var/tmp/share.cfg.tmp" 533034Sdougm #endif 543034Sdougm #define TSTAMP(tm) (uint64_t)(((uint64_t)tm.tv_sec << 32) | \ 553034Sdougm (tm.tv_nsec & 0xffffffff)) 563034Sdougm 573663Sdougm #define DFS_LOCK_FILE "/etc/dfs/fstypes" 584327Sdougm #define SA_STRSIZE 256 /* max string size for names */ 593663Sdougm 603034Sdougm /* 615331Samw * internal object type values returned by sa_get_object_type() 625331Samw */ 635331Samw #define SA_TYPE_UNKNOWN 0 645331Samw #define SA_TYPE_GROUP 1 655331Samw #define SA_TYPE_SHARE 2 665331Samw #define SA_TYPE_RESOURCE 3 675331Samw #define SA_TYPE_OPTIONSET 4 685331Samw #define SA_TYPE_ALTSPACE 5 695331Samw 705331Samw /* 713034Sdougm * internal data structures 723034Sdougm */ 733034Sdougm 743034Sdougm extern struct sa_proto_plugin *sap_proto_list; 753034Sdougm 763034Sdougm /* current SMF/SVC repository handle */ 773910Sdougm extern void getlegacyconfig(sa_handle_t, char *, xmlNodePtr *); 783910Sdougm extern int gettransients(sa_handle_impl_t, xmlNodePtr *); 793034Sdougm extern int sa_valid_property(void *, char *, sa_property_t); 803034Sdougm extern char *sa_fstype(char *); 813034Sdougm extern int sa_is_share(void *); 825331Samw extern int sa_is_resource(void *); 833034Sdougm extern ssize_t scf_max_name_len; /* defined in scfutil during initialization */ 843034Sdougm extern int sa_group_is_zfs(sa_group_t); 853034Sdougm extern int sa_path_is_zfs(char *); 863034Sdougm extern int sa_zfs_set_sharenfs(sa_group_t, char *, int); 875331Samw extern int sa_zfs_set_sharesmb(sa_group_t, char *, int); 883910Sdougm extern void update_legacy_config(sa_handle_t); 893034Sdougm extern int issubdir(char *, char *); 904327Sdougm extern int sa_zfs_init(sa_handle_impl_t); 913910Sdougm extern void sa_zfs_fini(sa_handle_impl_t); 923663Sdougm extern void sablocksigs(sigset_t *); 933663Sdougm extern void saunblocksigs(sigset_t *); 945331Samw static sa_group_t sa_get_optionset_parent(sa_optionset_t); 955331Samw static char *get_node_attr(void *, char *); 963034Sdougm 973910Sdougm /* 983910Sdougm * Data structures for finding/managing the document root to access 993910Sdougm * handle mapping. The list isn't expected to grow very large so a 1003910Sdougm * simple list is acceptable. The purpose is to provide a way to start 1013910Sdougm * with a group or share and find the library handle needed for 1023910Sdougm * various operations. 1033910Sdougm */ 1043910Sdougm mutex_t sa_global_lock; 1053910Sdougm struct doc2handle { 1063910Sdougm struct doc2handle *next; 1073910Sdougm xmlNodePtr root; 1083910Sdougm sa_handle_impl_t handle; 1093910Sdougm }; 1103910Sdougm 1114327Sdougm /* definitions used in a couple of property functions */ 1124327Sdougm #define SA_PROP_OP_REMOVE 1 1134327Sdougm #define SA_PROP_OP_ADD 2 1144327Sdougm #define SA_PROP_OP_UPDATE 3 1154327Sdougm 1163910Sdougm static struct doc2handle *sa_global_handles = NULL; 1173034Sdougm 1183034Sdougm /* helper functions */ 1193034Sdougm 1203910Sdougm /* 1213910Sdougm * sa_errorstr(err) 1223910Sdougm * 1233910Sdougm * convert an error value to an error string 1243910Sdougm */ 1253910Sdougm 1263034Sdougm char * 1273034Sdougm sa_errorstr(int err) 1283034Sdougm { 1293034Sdougm static char errstr[32]; 1303034Sdougm char *ret = NULL; 1313034Sdougm 1323034Sdougm switch (err) { 1333034Sdougm case SA_OK: 1344327Sdougm ret = dgettext(TEXT_DOMAIN, "ok"); 1354327Sdougm break; 1363034Sdougm case SA_NO_SUCH_PATH: 1374327Sdougm ret = dgettext(TEXT_DOMAIN, "path doesn't exist"); 1384327Sdougm break; 1393034Sdougm case SA_NO_MEMORY: 1404327Sdougm ret = dgettext(TEXT_DOMAIN, "no memory"); 1414327Sdougm break; 1423034Sdougm case SA_DUPLICATE_NAME: 1434327Sdougm ret = dgettext(TEXT_DOMAIN, "name in use"); 1444327Sdougm break; 1453034Sdougm case SA_BAD_PATH: 1464327Sdougm ret = dgettext(TEXT_DOMAIN, "bad path"); 1474327Sdougm break; 1483034Sdougm case SA_NO_SUCH_GROUP: 1494327Sdougm ret = dgettext(TEXT_DOMAIN, "no such group"); 1504327Sdougm break; 1513034Sdougm case SA_CONFIG_ERR: 1524327Sdougm ret = dgettext(TEXT_DOMAIN, "configuration error"); 1534327Sdougm break; 1543034Sdougm case SA_SYSTEM_ERR: 1554327Sdougm ret = dgettext(TEXT_DOMAIN, "system error"); 1564327Sdougm break; 1573034Sdougm case SA_SYNTAX_ERR: 1584327Sdougm ret = dgettext(TEXT_DOMAIN, "syntax error"); 1594327Sdougm break; 1603034Sdougm case SA_NO_PERMISSION: 1614327Sdougm ret = dgettext(TEXT_DOMAIN, "no permission"); 1624327Sdougm break; 1633034Sdougm case SA_BUSY: 1644327Sdougm ret = dgettext(TEXT_DOMAIN, "busy"); 1654327Sdougm break; 1663034Sdougm case SA_NO_SUCH_PROP: 1674327Sdougm ret = dgettext(TEXT_DOMAIN, "no such property"); 1684327Sdougm break; 1693034Sdougm case SA_INVALID_NAME: 1704327Sdougm ret = dgettext(TEXT_DOMAIN, "invalid name"); 1714327Sdougm break; 1723034Sdougm case SA_INVALID_PROTOCOL: 1734327Sdougm ret = dgettext(TEXT_DOMAIN, "invalid protocol"); 1744327Sdougm break; 1753034Sdougm case SA_NOT_ALLOWED: 1764327Sdougm ret = dgettext(TEXT_DOMAIN, "operation not allowed"); 1774327Sdougm break; 1783034Sdougm case SA_BAD_VALUE: 1794327Sdougm ret = dgettext(TEXT_DOMAIN, "bad property value"); 1804327Sdougm break; 1813034Sdougm case SA_INVALID_SECURITY: 1824327Sdougm ret = dgettext(TEXT_DOMAIN, "invalid security type"); 1834327Sdougm break; 1843034Sdougm case SA_NO_SUCH_SECURITY: 1854327Sdougm ret = dgettext(TEXT_DOMAIN, "security type not found"); 1864327Sdougm break; 1873034Sdougm case SA_VALUE_CONFLICT: 1884327Sdougm ret = dgettext(TEXT_DOMAIN, "property value conflict"); 1894327Sdougm break; 1903034Sdougm case SA_NOT_IMPLEMENTED: 1914327Sdougm ret = dgettext(TEXT_DOMAIN, "not implemented"); 1924327Sdougm break; 1933034Sdougm case SA_INVALID_PATH: 1944327Sdougm ret = dgettext(TEXT_DOMAIN, "invalid path"); 1954327Sdougm break; 1963034Sdougm case SA_NOT_SUPPORTED: 1974327Sdougm ret = dgettext(TEXT_DOMAIN, "operation not supported"); 1984327Sdougm break; 1993034Sdougm case SA_PROP_SHARE_ONLY: 2004327Sdougm ret = dgettext(TEXT_DOMAIN, "property not valid for group"); 2014327Sdougm break; 2023034Sdougm case SA_NOT_SHARED: 2034327Sdougm ret = dgettext(TEXT_DOMAIN, "not shared"); 2044327Sdougm break; 2055331Samw case SA_NO_SUCH_RESOURCE: 2065331Samw ret = dgettext(TEXT_DOMAIN, "no such resource"); 2075331Samw break; 2085331Samw case SA_RESOURCE_REQUIRED: 2095331Samw ret = dgettext(TEXT_DOMAIN, "resource name required"); 2105331Samw break; 2115331Samw case SA_MULTIPLE_ERROR: 2125331Samw ret = dgettext(TEXT_DOMAIN, "errors from multiple protocols"); 2135331Samw break; 2145331Samw case SA_PATH_IS_SUBDIR: 2155331Samw ret = dgettext(TEXT_DOMAIN, "path is a subpath of share"); 2165331Samw break; 2175331Samw case SA_PATH_IS_PARENTDIR: 2185331Samw ret = dgettext(TEXT_DOMAIN, "path is parent of a share"); 2195331Samw break; 220*5521Sas200622 case SA_KRB_KEYTAB_ERR: 221*5521Sas200622 ret = dgettext(TEXT_DOMAIN, "unable to remove the old keys" 222*5521Sas200622 " from the Kerberos keytab. Please manually remove" 223*5521Sas200622 " the old keys for your host principal prior to setting" 224*5521Sas200622 " the ads_domain property"); 225*5521Sas200622 break; 226*5521Sas200622 case SA_NO_SERVICE: 227*5521Sas200622 ret = dgettext(TEXT_DOMAIN, "service is not running"); 228*5521Sas200622 break; 2293034Sdougm default: 2304327Sdougm (void) snprintf(errstr, sizeof (errstr), 2314327Sdougm dgettext(TEXT_DOMAIN, "unknown %d"), err); 2324327Sdougm ret = errstr; 2333034Sdougm } 2343034Sdougm return (ret); 2353034Sdougm } 2363034Sdougm 2373034Sdougm /* 2383910Sdougm * Document root to active handle mapping functions. These are only 2393910Sdougm * used internally. A mutex is used to prevent access while the list 2403910Sdougm * is changing. In general, the list will be relatively short - one 2413910Sdougm * item per thread that has called sa_init(). 2423910Sdougm */ 2433910Sdougm 2443910Sdougm sa_handle_impl_t 2453910Sdougm get_handle_for_root(xmlNodePtr root) 2463910Sdougm { 2473910Sdougm struct doc2handle *item; 2483910Sdougm 2493910Sdougm (void) mutex_lock(&sa_global_lock); 2503910Sdougm for (item = sa_global_handles; item != NULL; item = item->next) { 2514327Sdougm if (item->root == root) 2524327Sdougm break; 2533910Sdougm } 2543910Sdougm (void) mutex_unlock(&sa_global_lock); 2553910Sdougm if (item != NULL) 2564327Sdougm return (item->handle); 2573910Sdougm return (NULL); 2583910Sdougm } 2593910Sdougm 2603910Sdougm static int 2613910Sdougm add_handle_for_root(xmlNodePtr root, sa_handle_impl_t handle) 2623910Sdougm { 2633910Sdougm struct doc2handle *item; 2643910Sdougm int ret = SA_NO_MEMORY; 2653910Sdougm 2663910Sdougm item = (struct doc2handle *)calloc(sizeof (struct doc2handle), 1); 2673910Sdougm if (item != NULL) { 2684327Sdougm item->root = root; 2694327Sdougm item->handle = handle; 2704327Sdougm (void) mutex_lock(&sa_global_lock); 2714327Sdougm item->next = sa_global_handles; 2724327Sdougm sa_global_handles = item; 2734327Sdougm (void) mutex_unlock(&sa_global_lock); 2744327Sdougm ret = SA_OK; 2753910Sdougm } 2763910Sdougm return (ret); 2773910Sdougm } 2783910Sdougm 2793910Sdougm /* 2803910Sdougm * remove_handle_for_root(root) 2813910Sdougm * 2823910Sdougm * Walks the list of handles and removes the one for this "root" from 2833910Sdougm * the list. It is up to the caller to free the data. 2843910Sdougm */ 2853910Sdougm 2863910Sdougm static void 2873910Sdougm remove_handle_for_root(xmlNodePtr root) 2883910Sdougm { 2893910Sdougm struct doc2handle *item, *prev; 2903910Sdougm 2913910Sdougm (void) mutex_lock(&sa_global_lock); 2923910Sdougm for (prev = NULL, item = sa_global_handles; item != NULL; 2934327Sdougm item = item->next) { 2944327Sdougm if (item->root == root) { 2954327Sdougm /* first in the list */ 2964327Sdougm if (prev == NULL) 2974327Sdougm sa_global_handles = sa_global_handles->next; 2984327Sdougm else 2994327Sdougm prev->next = item->next; 3004327Sdougm /* Item is out of the list so free the list structure */ 3014327Sdougm free(item); 3024327Sdougm break; 3033910Sdougm } 3044327Sdougm prev = item; 3053910Sdougm } 3063910Sdougm (void) mutex_unlock(&sa_global_lock); 3073910Sdougm } 3083910Sdougm 3093910Sdougm /* 3103910Sdougm * sa_find_group_handle(sa_group_t group) 3113910Sdougm * 3123910Sdougm * Find the sa_handle_t for the configuration associated with this 3133910Sdougm * group. 3143910Sdougm */ 3153910Sdougm sa_handle_t 3163910Sdougm sa_find_group_handle(sa_group_t group) 3173910Sdougm { 3183910Sdougm xmlNodePtr node = (xmlNodePtr)group; 3193910Sdougm sa_handle_t handle; 3203910Sdougm 3213910Sdougm while (node != NULL) { 3224327Sdougm if (strcmp((char *)(node->name), "sharecfg") == 0) { 3234327Sdougm /* have the root so get the handle */ 3244327Sdougm handle = (sa_handle_t)get_handle_for_root(node); 3254327Sdougm return (handle); 3264327Sdougm } 3274327Sdougm node = node->parent; 3283910Sdougm } 3293910Sdougm return (NULL); 3303910Sdougm } 3313910Sdougm 3323910Sdougm /* 3333034Sdougm * set_legacy_timestamp(root, path, timevalue) 3343034Sdougm * 3353034Sdougm * add the current timestamp value to the configuration for use in 3363034Sdougm * determining when to update the legacy files. For SMF, this 3373034Sdougm * property is kept in default/operation/legacy_timestamp 3383034Sdougm */ 3393034Sdougm 3403034Sdougm static void 3413034Sdougm set_legacy_timestamp(xmlNodePtr root, char *path, uint64_t tval) 3423034Sdougm { 3433034Sdougm xmlNodePtr node; 3443034Sdougm xmlChar *lpath = NULL; 3453910Sdougm sa_handle_impl_t handle; 3463910Sdougm 3473910Sdougm /* Have to have a handle or else we weren't initialized. */ 3483910Sdougm handle = get_handle_for_root(root); 3493910Sdougm if (handle == NULL) 3504327Sdougm return; 3513034Sdougm 3523034Sdougm for (node = root->xmlChildrenNode; node != NULL; 3534327Sdougm node = node->next) { 3544327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"legacy") == 0) { 3554327Sdougm /* a possible legacy node for this path */ 3564327Sdougm lpath = xmlGetProp(node, (xmlChar *)"path"); 3574327Sdougm if (lpath != NULL && 3584327Sdougm xmlStrcmp(lpath, (xmlChar *)path) == 0) { 3594327Sdougm xmlFree(lpath); 3604327Sdougm break; 3614327Sdougm } 3624327Sdougm if (lpath != NULL) 3634327Sdougm xmlFree(lpath); 3643034Sdougm } 3653034Sdougm } 3663034Sdougm if (node == NULL) { 3674327Sdougm /* need to create the first legacy timestamp node */ 3684327Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"legacy", NULL); 3693034Sdougm } 3703034Sdougm if (node != NULL) { 3714327Sdougm char tstring[32]; 3724327Sdougm int ret; 3733034Sdougm 3744327Sdougm (void) snprintf(tstring, sizeof (tstring), "%lld", tval); 3754327Sdougm xmlSetProp(node, (xmlChar *)"timestamp", (xmlChar *)tstring); 3764327Sdougm xmlSetProp(node, (xmlChar *)"path", (xmlChar *)path); 3774327Sdougm /* now commit to SMF */ 3784327Sdougm ret = sa_get_instance(handle->scfhandle, "default"); 3793034Sdougm if (ret == SA_OK) { 3804327Sdougm ret = sa_start_transaction(handle->scfhandle, 3814327Sdougm "operation"); 3824327Sdougm if (ret == SA_OK) { 3834327Sdougm ret = sa_set_property(handle->scfhandle, 3844327Sdougm "legacy-timestamp", tstring); 3854327Sdougm if (ret == SA_OK) { 3864327Sdougm (void) sa_end_transaction( 3874327Sdougm handle->scfhandle); 3884327Sdougm } else { 3894327Sdougm sa_abort_transaction(handle->scfhandle); 3904327Sdougm } 3914327Sdougm } 3923034Sdougm } 3933034Sdougm } 3943034Sdougm } 3953034Sdougm 3963034Sdougm /* 3973034Sdougm * is_shared(share) 3983034Sdougm * 3993034Sdougm * determine if the specified share is currently shared or not. 4003034Sdougm */ 4013034Sdougm static int 4023034Sdougm is_shared(sa_share_t share) 4033034Sdougm { 4043034Sdougm char *shared; 4053034Sdougm int result = 0; /* assume not */ 4063034Sdougm 4073034Sdougm shared = sa_get_share_attr(share, "shared"); 4083034Sdougm if (shared != NULL) { 4094327Sdougm if (strcmp(shared, "true") == 0) 4104327Sdougm result = 1; 4114327Sdougm sa_free_attr_string(shared); 4123034Sdougm } 4133034Sdougm return (result); 4143034Sdougm } 4153034Sdougm 4163034Sdougm /* 4175331Samw * excluded_protocol(share, proto) 4185331Samw * 4195331Samw * Returns B_TRUE if the specified protocol appears in the "exclude" 4205331Samw * property. This is used to prevent sharing special case shares 4215331Samw * (e.g. subdirs when SMB wants a subdir and NFS doesn't. B_FALSE is 4225331Samw * returned if the protocol isn't in the list. 4235331Samw */ 4245331Samw static boolean_t 4255331Samw excluded_protocol(sa_share_t share, char *proto) 4265331Samw { 4275331Samw char *protolist; 4285331Samw char *str; 4295331Samw char *token; 4305331Samw 4315331Samw protolist = sa_get_share_attr(share, "exclude"); 4325331Samw if (protolist != NULL) { 4335331Samw str = protolist; 4345331Samw while ((token = strtok(str, ",")) != NULL) { 4355331Samw if (strcmp(token, proto) == 0) { 4365331Samw sa_free_attr_string(protolist); 4375331Samw return (B_TRUE); 4385331Samw } 4395331Samw str = NULL; 4405331Samw } 4415331Samw sa_free_attr_string(protolist); 4425331Samw } 4435331Samw return (B_FALSE); 4445331Samw } 4455331Samw 4465331Samw /* 4473663Sdougm * checksubdirgroup(group, newpath, strictness) 4483348Sdougm * 4493663Sdougm * check all the specified newpath against all the paths in the 4503663Sdougm * group. This is a helper function for checksubdir to make it easier 4513663Sdougm * to also check ZFS subgroups. 4523663Sdougm * The strictness values mean: 4533348Sdougm * SA_CHECK_NORMAL == only check newpath against shares that are active 4543348Sdougm * SA_CHECK_STRICT == check newpath against both active shares and those 4553348Sdougm * stored in the repository 4563034Sdougm */ 4573034Sdougm static int 4583663Sdougm checksubdirgroup(sa_group_t group, char *newpath, int strictness) 4593034Sdougm { 4603034Sdougm sa_share_t share; 4613663Sdougm char *path; 4623663Sdougm int issub = SA_OK; 4635331Samw int subdir; 4645331Samw int parent; 4655331Samw 4665331Samw if (newpath == NULL) 4675331Samw return (SA_INVALID_PATH); 4683034Sdougm 4693663Sdougm for (share = sa_get_share(group, NULL); share != NULL; 4703663Sdougm share = sa_get_next_share(share)) { 4713034Sdougm /* 4723034Sdougm * The original behavior of share never checked 4733034Sdougm * against the permanent configuration 4743034Sdougm * (/etc/dfs/dfstab). PIT has a number of cases where 4753034Sdougm * it depends on this older behavior even though it 4763034Sdougm * could be considered incorrect. We may tighten this 4773034Sdougm * up in the future. 4783034Sdougm */ 4794327Sdougm if (strictness == SA_CHECK_NORMAL && !is_shared(share)) 4804327Sdougm continue; 4813034Sdougm 4824327Sdougm path = sa_get_share_attr(share, "path"); 4833348Sdougm /* 4843348Sdougm * If path is NULL, then a share is in the process of 4853348Sdougm * construction or someone has modified the property 4863663Sdougm * group inappropriately. It should be 4873663Sdougm * ignored. issubdir() comes from the original share 4883663Sdougm * implementation and does the difficult part of 4893663Sdougm * checking subdirectories. 4903348Sdougm */ 4914327Sdougm if (path == NULL) 4924327Sdougm continue; 4935331Samw 4945331Samw if (strcmp(path, newpath) == 0) { 4954327Sdougm issub = SA_INVALID_PATH; 4965331Samw } else { 4975331Samw subdir = issubdir(newpath, path); 4985331Samw parent = issubdir(path, newpath); 4995331Samw if (subdir || parent) { 5005331Samw sa_free_attr_string(path); 5015331Samw path = NULL; 5025331Samw return (subdir ? 5035331Samw SA_PATH_IS_SUBDIR : SA_PATH_IS_PARENTDIR); 5045331Samw } 5054327Sdougm } 5063034Sdougm sa_free_attr_string(path); 5073034Sdougm path = NULL; 5083663Sdougm } 5093663Sdougm return (issub); 5103663Sdougm } 5113663Sdougm 5123663Sdougm /* 5133663Sdougm * checksubdir(newpath, strictness) 5143663Sdougm * 5153663Sdougm * checksubdir determines if the specified path (newpath) is a 5163663Sdougm * subdirectory of another share. It calls checksubdirgroup() to do 5173663Sdougm * the complicated work. The strictness parameter determines how 5183663Sdougm * strict a check to make against the path. The strictness values 5193663Sdougm * mean: SA_CHECK_NORMAL == only check newpath against shares that are 5203663Sdougm * active SA_CHECK_STRICT == check newpath against both active shares 5213663Sdougm * and those * stored in the repository 5223663Sdougm */ 5233663Sdougm static int 5243910Sdougm checksubdir(sa_handle_t handle, char *newpath, int strictness) 5253663Sdougm { 5263663Sdougm sa_group_t group; 5275331Samw int issub = SA_OK; 5283663Sdougm char *path = NULL; 5293663Sdougm 5305331Samw for (group = sa_get_group(handle, NULL); 5315331Samw group != NULL && issub == SA_OK; 5325331Samw group = sa_get_next_group(group)) { 5334327Sdougm if (sa_group_is_zfs(group)) { 5344327Sdougm sa_group_t subgroup; 5354327Sdougm for (subgroup = sa_get_sub_group(group); 5365331Samw subgroup != NULL && issub == SA_OK; 5374327Sdougm subgroup = sa_get_next_group(subgroup)) 5384327Sdougm issub = checksubdirgroup(subgroup, newpath, 5394327Sdougm strictness); 5404327Sdougm } else { 5414327Sdougm issub = checksubdirgroup(group, newpath, strictness); 5424327Sdougm } 5433034Sdougm } 5443034Sdougm if (path != NULL) 5454327Sdougm sa_free_attr_string(path); 5463034Sdougm return (issub); 5473034Sdougm } 5483034Sdougm 5493034Sdougm /* 5503348Sdougm * validpath(path, strictness) 5513034Sdougm * determine if the provided path is valid for a share. It shouldn't 5523034Sdougm * be a sub-dir of an already shared path or the parent directory of a 5533034Sdougm * share path. 5543034Sdougm */ 5553034Sdougm static int 5563910Sdougm validpath(sa_handle_t handle, char *path, int strictness) 5573034Sdougm { 5583034Sdougm int error = SA_OK; 5593034Sdougm struct stat st; 5603034Sdougm sa_share_t share; 5613034Sdougm char *fstype; 5623034Sdougm 5634327Sdougm if (*path != '/') 5644327Sdougm return (SA_BAD_PATH); 5654327Sdougm 5663034Sdougm if (stat(path, &st) < 0) { 5674327Sdougm error = SA_NO_SUCH_PATH; 5683034Sdougm } else { 5694327Sdougm share = sa_find_share(handle, path); 5704327Sdougm if (share != NULL) 5714327Sdougm error = SA_DUPLICATE_NAME; 5724327Sdougm 5734327Sdougm if (error == SA_OK) { 5744327Sdougm /* 5754327Sdougm * check for special case with file system 5764327Sdougm * that might have restrictions. For now, ZFS 5774327Sdougm * is the only case since it has its own idea 5784327Sdougm * of how to configure shares. We do this 5794327Sdougm * before subdir checking since things like 5804327Sdougm * ZFS will do that for us. This should also 5814327Sdougm * be done via plugin interface. 5824327Sdougm */ 5834327Sdougm fstype = sa_fstype(path); 5844327Sdougm if (fstype != NULL && strcmp(fstype, "zfs") == 0) { 5854327Sdougm if (sa_zfs_is_shared(handle, path)) 5864327Sdougm error = SA_INVALID_NAME; 5874327Sdougm } 5884327Sdougm if (fstype != NULL) 5894327Sdougm sa_free_fstype(fstype); 5903034Sdougm } 5914327Sdougm if (error == SA_OK) 5924327Sdougm error = checksubdir(handle, path, strictness); 5933034Sdougm } 5943034Sdougm return (error); 5953034Sdougm } 5963034Sdougm 5973034Sdougm /* 5983034Sdougm * check to see if group/share is persistent. 5995331Samw * 6005331Samw * "group" can be either an sa_group_t or an sa_share_t. (void *) 6015331Samw * works since both thse types are also void *. 6023034Sdougm */ 6035331Samw int 6045331Samw sa_is_persistent(void *group) 6053034Sdougm { 6063034Sdougm char *type; 6073034Sdougm int persist = 1; 6083034Sdougm 6095331Samw type = sa_get_group_attr((sa_group_t)group, "type"); 6103034Sdougm if (type != NULL && strcmp(type, "transient") == 0) 6114327Sdougm persist = 0; 6123034Sdougm if (type != NULL) 6134327Sdougm sa_free_attr_string(type); 6143034Sdougm return (persist); 6153034Sdougm } 6163034Sdougm 6173034Sdougm /* 6183034Sdougm * sa_valid_group_name(name) 6193034Sdougm * 6203034Sdougm * check that the "name" contains only valid characters and otherwise 6213034Sdougm * fits the required naming conventions. Valid names must start with 6223034Sdougm * an alphabetic and the remainder may consist of only alphanumeric 6233034Sdougm * plus the '-' and '_' characters. This name limitation comes from 6243034Sdougm * inherent limitations in SMF. 6253034Sdougm */ 6263034Sdougm 6273034Sdougm int 6283034Sdougm sa_valid_group_name(char *name) 6293034Sdougm { 6303034Sdougm int ret = 1; 6313034Sdougm ssize_t len; 6323034Sdougm 6333034Sdougm if (name != NULL && isalpha(*name)) { 6344327Sdougm char c; 6354327Sdougm len = strlen(name); 6364327Sdougm if (len < (scf_max_name_len - sizeof ("group:"))) { 6374327Sdougm for (c = *name++; c != '\0' && ret != 0; c = *name++) { 6384327Sdougm if (!isalnum(c) && c != '-' && c != '_') 6394327Sdougm ret = 0; 6404327Sdougm } 6414327Sdougm } else { 6423034Sdougm ret = 0; 6433034Sdougm } 6444327Sdougm } else { 6453034Sdougm ret = 0; 6463034Sdougm } 6473034Sdougm return (ret); 6483034Sdougm } 6493034Sdougm 6503034Sdougm 6513034Sdougm /* 6523034Sdougm * is_zfs_group(group) 6533034Sdougm * Determine if the specified group is a ZFS sharenfs group 6543034Sdougm */ 6553034Sdougm static int 6563034Sdougm is_zfs_group(sa_group_t group) 6573034Sdougm { 6583034Sdougm int ret = 0; 6593034Sdougm xmlNodePtr parent; 6603034Sdougm xmlChar *zfs; 6613034Sdougm 6624327Sdougm if (strcmp((char *)((xmlNodePtr)group)->name, "share") == 0) 6634327Sdougm parent = (xmlNodePtr)sa_get_parent_group(group); 6644327Sdougm else 6654327Sdougm parent = (xmlNodePtr)group; 6663034Sdougm zfs = xmlGetProp(parent, (xmlChar *)"zfs"); 6673034Sdougm if (zfs != NULL) { 6684327Sdougm xmlFree(zfs); 6694327Sdougm ret = 1; 6703034Sdougm } 6713034Sdougm return (ret); 6723034Sdougm } 6733034Sdougm 6743034Sdougm /* 6755331Samw * sa_get_object_type(object) 6765331Samw * 6775331Samw * This function returns a numeric value representing the object 6785331Samw * type. This allows using simpler checks when doing type specific 6795331Samw * operations. 6805331Samw */ 6815331Samw 6825331Samw static int 6835331Samw sa_get_object_type(void *object) 6845331Samw { 6855331Samw xmlNodePtr node = (xmlNodePtr)object; 6865331Samw int type; 6875331Samw 6885331Samw if (xmlStrcmp(node->name, (xmlChar *)"group") == 0) 6895331Samw type = SA_TYPE_GROUP; 6905331Samw else if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) 6915331Samw type = SA_TYPE_SHARE; 6925331Samw else if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0) 6935331Samw type = SA_TYPE_RESOURCE; 6945331Samw else if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) 6955331Samw type = SA_TYPE_OPTIONSET; 6965331Samw else if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) 6975331Samw type = SA_TYPE_ALTSPACE; 6985331Samw else 6995331Samw assert(0); 7005331Samw return (type); 7015331Samw } 7025331Samw 7035331Samw /* 7043034Sdougm * sa_optionset_name(optionset, oname, len, id) 7053034Sdougm * return the SMF name for the optionset. If id is not NULL, it 7063034Sdougm * will have the GUID value for a share and should be used 7073034Sdougm * instead of the keyword "optionset" which is used for 7083034Sdougm * groups. If the optionset doesn't have a protocol type 7093034Sdougm * associated with it, "default" is used. This shouldn't happen 7103034Sdougm * at this point but may be desirable in the future if there are 7113034Sdougm * protocol independent properties added. The name is returned in 7123034Sdougm * oname. 7133034Sdougm */ 7143034Sdougm 7153034Sdougm static int 7163034Sdougm sa_optionset_name(sa_optionset_t optionset, char *oname, size_t len, char *id) 7173034Sdougm { 7183034Sdougm char *proto; 7195331Samw void *parent; 7205331Samw int ptype; 7213034Sdougm 7223034Sdougm if (id == NULL) 7234327Sdougm id = "optionset"; 7243034Sdougm 7255331Samw parent = sa_get_optionset_parent(optionset); 7265331Samw if (parent != NULL) { 7275331Samw ptype = sa_get_object_type(parent); 7285331Samw proto = sa_get_optionset_attr(optionset, "type"); 7295331Samw if (ptype != SA_TYPE_RESOURCE) { 7305331Samw len = snprintf(oname, len, "%s_%s", id, 7315331Samw proto ? proto : "default"); 7325331Samw } else { 7335331Samw char *index; 7345331Samw index = get_node_attr((void *)parent, "id"); 7355331Samw if (index != NULL) 7365331Samw len = snprintf(oname, len, "%s_%s_%s", id, 7375331Samw proto ? proto : "default", index); 7385331Samw else 7395331Samw len = 0; 7405331Samw } 7415331Samw 7425331Samw if (proto != NULL) 7435331Samw sa_free_attr_string(proto); 7445331Samw } else { 7455331Samw len = 0; 7465331Samw } 7473034Sdougm return (len); 7483034Sdougm } 7493034Sdougm 7503034Sdougm /* 7513034Sdougm * sa_security_name(optionset, oname, len, id) 7523034Sdougm * 7533034Sdougm * return the SMF name for the security. If id is not NULL, it will 7543034Sdougm * have the GUID value for a share and should be used instead of the 7553034Sdougm * keyword "optionset" which is used for groups. If the optionset 7563034Sdougm * doesn't have a protocol type associated with it, "default" is 7573034Sdougm * used. This shouldn't happen at this point but may be desirable in 7583034Sdougm * the future if there are protocol independent properties added. The 7593034Sdougm * name is returned in oname. The security type is also encoded into 7603034Sdougm * the name. In the future, this wil *be handled a bit differently. 7613034Sdougm */ 7623034Sdougm 7633034Sdougm static int 7643034Sdougm sa_security_name(sa_security_t security, char *oname, size_t len, char *id) 7653034Sdougm { 7663034Sdougm char *proto; 7673034Sdougm char *sectype; 7683034Sdougm 7693034Sdougm if (id == NULL) 7704327Sdougm id = "optionset"; 7713034Sdougm 7723034Sdougm proto = sa_get_security_attr(security, "type"); 7733034Sdougm sectype = sa_get_security_attr(security, "sectype"); 7744327Sdougm len = snprintf(oname, len, "%s_%s_%s", id, proto ? proto : "default", 7754327Sdougm sectype ? sectype : "default"); 7763034Sdougm if (proto != NULL) 7774327Sdougm sa_free_attr_string(proto); 7783034Sdougm if (sectype != NULL) 7794327Sdougm sa_free_attr_string(sectype); 7803034Sdougm return (len); 7813034Sdougm } 7823034Sdougm 7833034Sdougm /* 7844327Sdougm * verifydefgroupopts(handle) 7854327Sdougm * 7864327Sdougm * Make sure a "default" group exists and has default protocols enabled. 7874327Sdougm */ 7884327Sdougm static void 7894327Sdougm verifydefgroupopts(sa_handle_t handle) 7904327Sdougm { 7914327Sdougm sa_group_t defgrp; 7924327Sdougm sa_optionset_t opt; 7935331Samw 7944327Sdougm defgrp = sa_get_group(handle, "default"); 7954327Sdougm if (defgrp != NULL) { 7964327Sdougm opt = sa_get_optionset(defgrp, NULL); 7974327Sdougm /* 7984327Sdougm * NFS is the default for default group 7994327Sdougm */ 8004327Sdougm if (opt == NULL) 8014327Sdougm opt = sa_create_optionset(defgrp, "nfs"); 8024327Sdougm } 8034327Sdougm } 8044327Sdougm 8054327Sdougm /* 8063348Sdougm * sa_init(init_service) 8073034Sdougm * Initialize the API 8083034Sdougm * find all the shared objects 8093034Sdougm * init the tables with all objects 8103034Sdougm * read in the current configuration 8113034Sdougm */ 8123034Sdougm 8134327Sdougm #define GETPROP(prop) scf_simple_prop_next_astring(prop) 8144327Sdougm #define CHECKTSTAMP(st, tval) stat(SA_LEGACY_DFSTAB, &st) >= 0 && \ 8154327Sdougm tval != TSTAMP(st.st_ctim) 8164327Sdougm 8173910Sdougm sa_handle_t 8183034Sdougm sa_init(int init_service) 8193034Sdougm { 8203034Sdougm struct stat st; 8213034Sdougm int legacy = 0; 8223034Sdougm uint64_t tval = 0; 8233663Sdougm int lockfd; 8243663Sdougm sigset_t old; 8253663Sdougm int updatelegacy = B_FALSE; 8263663Sdougm scf_simple_prop_t *prop; 8273910Sdougm sa_handle_impl_t handle; 8283910Sdougm int err; 8293034Sdougm 8303910Sdougm handle = calloc(sizeof (struct sa_handle_impl), 1); 8313910Sdougm 8323910Sdougm if (handle != NULL) { 8334327Sdougm /* get protocol specific structures */ 8344327Sdougm (void) proto_plugin_init(); 8354327Sdougm if (init_service & SA_INIT_SHARE_API) { 8363663Sdougm /* 8374327Sdougm * initialize access into libzfs. We use this 8384327Sdougm * when collecting info about ZFS datasets and 8394327Sdougm * shares. 8403663Sdougm */ 8414327Sdougm if (sa_zfs_init(handle) == B_FALSE) { 8424327Sdougm free(handle); 8434327Sdougm (void) proto_plugin_fini(); 8444327Sdougm return (NULL); 8454327Sdougm } 8463663Sdougm /* 8474327Sdougm * since we want to use SMF, initialize an svc handle 8484327Sdougm * and find out what is there. 8493663Sdougm */ 8504327Sdougm handle->scfhandle = sa_scf_init(handle); 8514327Sdougm if (handle->scfhandle != NULL) { 8524327Sdougm /* 8534327Sdougm * Need to lock the extraction of the 8544327Sdougm * configuration if the dfstab file has 8554327Sdougm * changed. Lock everything now and release if 8564327Sdougm * not needed. Use a file that isn't being 8574327Sdougm * manipulated by other parts of the system in 8584327Sdougm * order to not interfere with locking. Using 8594327Sdougm * dfstab doesn't work. 8604327Sdougm */ 8614327Sdougm sablocksigs(&old); 8624327Sdougm lockfd = open(DFS_LOCK_FILE, O_RDWR); 8634327Sdougm if (lockfd >= 0) { 8644327Sdougm extern int errno; 8654327Sdougm errno = 0; 8664327Sdougm (void) lockf(lockfd, F_LOCK, 0); 8674327Sdougm /* 8684327Sdougm * Check whether we are going to need 8694327Sdougm * to merge any dfstab changes. This 8704327Sdougm * is done by comparing the value of 8714327Sdougm * legacy-timestamp with the current 8724327Sdougm * st_ctim of the file. If they are 8734327Sdougm * different, an update is needed and 8744327Sdougm * the file must remain locked until 8754327Sdougm * the merge is done in order to 8764327Sdougm * prevent multiple startups from 8774327Sdougm * changing the SMF repository at the 8784327Sdougm * same time. The first to get the 8794327Sdougm * lock will make any changes before 8804327Sdougm * the others can read the repository. 8814327Sdougm */ 8824327Sdougm prop = scf_simple_prop_get 8834327Sdougm (handle->scfhandle->handle, 8844327Sdougm (const char *)SA_SVC_FMRI_BASE 8854327Sdougm ":default", "operation", 8864327Sdougm "legacy-timestamp"); 8874327Sdougm if (prop != NULL) { 8884327Sdougm char *i64; 8894327Sdougm i64 = GETPROP(prop); 8904327Sdougm if (i64 != NULL) 8914327Sdougm tval = strtoull(i64, 8924327Sdougm NULL, 0); 8934327Sdougm if (CHECKTSTAMP(st, tval)) 8944327Sdougm updatelegacy = B_TRUE; 8954327Sdougm scf_simple_prop_free(prop); 8964327Sdougm } else { 8974327Sdougm /* 8984327Sdougm * We haven't set the 8994327Sdougm * timestamp before so do it. 9004327Sdougm */ 9014327Sdougm updatelegacy = B_TRUE; 9024327Sdougm } 9034327Sdougm } 9044327Sdougm if (updatelegacy == B_FALSE) { 9054327Sdougm /* Don't need the lock anymore */ 9064327Sdougm (void) lockf(lockfd, F_ULOCK, 0); 9074327Sdougm (void) close(lockfd); 9084327Sdougm } 9093973Sdougm 9104327Sdougm /* 9114327Sdougm * It is essential that the document tree and 9124327Sdougm * the internal list of roots to handles be 9134327Sdougm * setup before anything that might try to 9144327Sdougm * create a new object is called. The document 9154327Sdougm * tree is the combination of handle->doc and 9164327Sdougm * handle->tree. This allows searches, 9174327Sdougm * etc. when all you have is an object in the 9184327Sdougm * tree. 9194327Sdougm */ 9204327Sdougm handle->doc = xmlNewDoc((xmlChar *)"1.0"); 9214327Sdougm handle->tree = xmlNewNode(NULL, 9224327Sdougm (xmlChar *)"sharecfg"); 9234327Sdougm if (handle->doc != NULL && 9244327Sdougm handle->tree != NULL) { 9254327Sdougm xmlDocSetRootElement(handle->doc, 9264327Sdougm handle->tree); 9274327Sdougm err = add_handle_for_root(handle->tree, 9284327Sdougm handle); 9294327Sdougm if (err == SA_OK) 9304327Sdougm err = sa_get_config( 9314327Sdougm handle->scfhandle, 9323973Sdougm handle->tree, handle); 9334327Sdougm } else { 9344327Sdougm if (handle->doc != NULL) 9354327Sdougm xmlFreeDoc(handle->doc); 9364327Sdougm if (handle->tree != NULL) 9374327Sdougm xmlFreeNode(handle->tree); 9384327Sdougm err = SA_NO_MEMORY; 9394327Sdougm } 9403973Sdougm 9414327Sdougm saunblocksigs(&old); 9423910Sdougm 9434327Sdougm if (err != SA_OK) { 9444327Sdougm /* 9454327Sdougm * If we couldn't add the tree handle 9464327Sdougm * to the list, then things are going 9474327Sdougm * to fail badly. Might as well undo 9484327Sdougm * everything now and fail the 9494327Sdougm * sa_init(). 9504327Sdougm */ 9514327Sdougm sa_fini(handle); 9524327Sdougm return (NULL); 9534327Sdougm } 9543910Sdougm 9554327Sdougm if (tval == 0) { 9564327Sdougm /* 9574327Sdougm * first time so make sure 9584327Sdougm * default is setup 9594327Sdougm */ 9604327Sdougm verifydefgroupopts(handle); 9614327Sdougm } 9623973Sdougm 9634524Sdougm if (updatelegacy == B_TRUE) { 9644524Sdougm sablocksigs(&old); 9654524Sdougm getlegacyconfig((sa_handle_t)handle, 9664524Sdougm SA_LEGACY_DFSTAB, &handle->tree); 9674524Sdougm if (stat(SA_LEGACY_DFSTAB, &st) >= 0) 9684524Sdougm set_legacy_timestamp( 9694524Sdougm handle->tree, 9704524Sdougm SA_LEGACY_DFSTAB, 9714524Sdougm TSTAMP(st.st_ctim)); 9724524Sdougm saunblocksigs(&old); 9734524Sdougm /* 9744524Sdougm * Safe to unlock now to allow 9754524Sdougm * others to run 9764524Sdougm */ 9774524Sdougm (void) lockf(lockfd, F_ULOCK, 0); 9784524Sdougm (void) close(lockfd); 9794524Sdougm } 9804524Sdougm legacy |= sa_get_zfs_shares(handle, "zfs"); 9814524Sdougm legacy |= gettransients(handle, &handle->tree); 9824327Sdougm } 9834327Sdougm } 9843034Sdougm } 9853910Sdougm return ((sa_handle_t)handle); 9863034Sdougm } 9873034Sdougm 9883034Sdougm /* 9893910Sdougm * sa_fini(handle) 9903034Sdougm * Uninitialize the API structures including the configuration 9913218Sdougm * data structures and ZFS related data. 9923034Sdougm */ 9933034Sdougm 9943034Sdougm void 9953910Sdougm sa_fini(sa_handle_t handle) 9963034Sdougm { 9973910Sdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle; 9983910Sdougm 9993910Sdougm if (impl_handle != NULL) { 10003910Sdougm /* 10013910Sdougm * Free the config trees and any other data structures 10023910Sdougm * used in the handle. 10033910Sdougm */ 10043910Sdougm if (impl_handle->doc != NULL) 10053910Sdougm xmlFreeDoc(impl_handle->doc); 10063910Sdougm sa_scf_fini(impl_handle->scfhandle); 10073910Sdougm sa_zfs_fini(impl_handle); 10083910Sdougm 10093910Sdougm /* Remove and free the entry in the global list. */ 10103910Sdougm remove_handle_for_root(impl_handle->tree); 10113910Sdougm 10123910Sdougm /* Make sure we free the handle */ 10133910Sdougm free(impl_handle); 10143910Sdougm 10153910Sdougm /* 10163910Sdougm * If this was the last handle to release, unload the 10173910Sdougm * plugins that were loaded. 10183910Sdougm */ 10193910Sdougm if (sa_global_handles == NULL) 10204327Sdougm (void) proto_plugin_fini(); 10213910Sdougm 10223034Sdougm } 10233034Sdougm } 10243034Sdougm 10253034Sdougm /* 10263034Sdougm * sa_get_protocols(char **protocol) 10273034Sdougm * Get array of protocols that are supported 10283034Sdougm * Returns pointer to an allocated and NULL terminated 10293034Sdougm * array of strings. Caller must free. 10303034Sdougm * This really should be determined dynamically. 10313034Sdougm * If there aren't any defined, return -1. 10323034Sdougm * Use free() to return memory. 10333034Sdougm */ 10343034Sdougm 10353034Sdougm int 10363034Sdougm sa_get_protocols(char ***protocols) 10373034Sdougm { 10383034Sdougm int numproto = -1; 10393034Sdougm 10403034Sdougm if (protocols != NULL) { 10414327Sdougm struct sa_proto_plugin *plug; 10424327Sdougm for (numproto = 0, plug = sap_proto_list; plug != NULL; 10434327Sdougm plug = plug->plugin_next) { 10444327Sdougm numproto++; 10454327Sdougm } 10463034Sdougm 10474327Sdougm *protocols = calloc(numproto + 1, sizeof (char *)); 10484327Sdougm if (*protocols != NULL) { 10494327Sdougm int ret = 0; 10504327Sdougm for (plug = sap_proto_list; plug != NULL; 10514327Sdougm plug = plug->plugin_next) { 10524327Sdougm /* faking for now */ 10534327Sdougm (*protocols)[ret++] = 10544327Sdougm plug->plugin_ops->sa_protocol; 10554327Sdougm } 10564327Sdougm } else { 10574327Sdougm numproto = -1; 10583034Sdougm } 10593034Sdougm } 10603034Sdougm return (numproto); 10613034Sdougm } 10623034Sdougm 10633034Sdougm /* 10643034Sdougm * find_group_by_name(node, group) 10653034Sdougm * 10663034Sdougm * search the XML document subtree specified by node to find the group 10673034Sdougm * specified by group. Searching subtree allows subgroups to be 10683034Sdougm * searched for. 10693034Sdougm */ 10703034Sdougm 10713034Sdougm static xmlNodePtr 10723034Sdougm find_group_by_name(xmlNodePtr node, xmlChar *group) 10733034Sdougm { 10743034Sdougm xmlChar *name = NULL; 10753034Sdougm 10763034Sdougm for (node = node->xmlChildrenNode; node != NULL; 10773034Sdougm node = node->next) { 10784327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"group") == 0) { 10794327Sdougm /* if no groupname, return the first found */ 10804327Sdougm if (group == NULL) 10814327Sdougm break; 10824327Sdougm name = xmlGetProp(node, (xmlChar *)"name"); 10834327Sdougm if (name != NULL && xmlStrcmp(name, group) == 0) 10844327Sdougm break; 10854327Sdougm if (name != NULL) { 10864327Sdougm xmlFree(name); 10874327Sdougm name = NULL; 10884327Sdougm } 10893034Sdougm } 10903034Sdougm } 10913034Sdougm if (name != NULL) 10924327Sdougm xmlFree(name); 10933034Sdougm return (node); 10943034Sdougm } 10953034Sdougm 10963034Sdougm /* 10973034Sdougm * sa_get_group(groupname) 10983034Sdougm * Return the "group" specified. If groupname is NULL, 10993034Sdougm * return the first group of the list of groups. 11003034Sdougm */ 11013034Sdougm sa_group_t 11023910Sdougm sa_get_group(sa_handle_t handle, char *groupname) 11033034Sdougm { 11043034Sdougm xmlNodePtr node = NULL; 11053034Sdougm char *subgroup = NULL; 11063034Sdougm char *group = NULL; 11073910Sdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle; 11083034Sdougm 11093910Sdougm if (impl_handle != NULL && impl_handle->tree != NULL) { 11104327Sdougm if (groupname != NULL) { 11114327Sdougm group = strdup(groupname); 11124345Sdougm if (group != NULL) { 11134345Sdougm subgroup = strchr(group, '/'); 11144345Sdougm if (subgroup != NULL) 11154345Sdougm *subgroup++ = '\0'; 11164345Sdougm } 11174327Sdougm } 11184345Sdougm /* 11194345Sdougm * We want to find the, possibly, named group. If 11204345Sdougm * group is not NULL, then lookup the name. If it is 11214345Sdougm * NULL, we only do the find if groupname is also 11224345Sdougm * NULL. This allows lookup of the "first" group in 11234345Sdougm * the internal list. 11244345Sdougm */ 11254345Sdougm if (group != NULL || groupname == NULL) 11264345Sdougm node = find_group_by_name(impl_handle->tree, 11274345Sdougm (xmlChar *)group); 11284345Sdougm 11294327Sdougm /* if a subgroup, find it before returning */ 11304327Sdougm if (subgroup != NULL && node != NULL) 11314327Sdougm node = find_group_by_name(node, (xmlChar *)subgroup); 11323034Sdougm } 11333034Sdougm if (node != NULL && (char *)group != NULL) 11344327Sdougm (void) sa_get_instance(impl_handle->scfhandle, (char *)group); 11353034Sdougm if (group != NULL) 11364327Sdougm free(group); 11373034Sdougm return ((sa_group_t)(node)); 11383034Sdougm } 11393034Sdougm 11403034Sdougm /* 11413034Sdougm * sa_get_next_group(group) 11423034Sdougm * Return the "next" group after the specified group from 11433034Sdougm * the internal group list. NULL if there are no more. 11443034Sdougm */ 11453034Sdougm sa_group_t 11463034Sdougm sa_get_next_group(sa_group_t group) 11473034Sdougm { 11483034Sdougm xmlNodePtr ngroup = NULL; 11493034Sdougm if (group != NULL) { 11504327Sdougm for (ngroup = ((xmlNodePtr)group)->next; ngroup != NULL; 11513034Sdougm ngroup = ngroup->next) { 11524327Sdougm if (xmlStrcmp(ngroup->name, (xmlChar *)"group") == 0) 11534327Sdougm break; 11544327Sdougm } 11553034Sdougm } 11563034Sdougm return ((sa_group_t)ngroup); 11573034Sdougm } 11583034Sdougm 11593034Sdougm /* 11603034Sdougm * sa_get_share(group, sharepath) 11613034Sdougm * Return the share object for the share specified. The share 11623034Sdougm * must be in the specified group. Return NULL if not found. 11633034Sdougm */ 11643034Sdougm sa_share_t 11653034Sdougm sa_get_share(sa_group_t group, char *sharepath) 11663034Sdougm { 11673034Sdougm xmlNodePtr node = NULL; 11683034Sdougm xmlChar *path; 11693034Sdougm 11703034Sdougm /* 11713034Sdougm * For future scalability, this should end up building a cache 11723034Sdougm * since it will get called regularly by the mountd and info 11733034Sdougm * services. 11743034Sdougm */ 11753034Sdougm if (group != NULL) { 11764327Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 11773034Sdougm node = node->next) { 11784327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) { 11794327Sdougm if (sharepath == NULL) { 11804327Sdougm break; 11814327Sdougm } else { 11824327Sdougm /* is it the correct share? */ 11834327Sdougm path = xmlGetProp(node, 11844327Sdougm (xmlChar *)"path"); 11854327Sdougm if (path != NULL && 11864327Sdougm xmlStrcmp(path, 11874327Sdougm (xmlChar *)sharepath) == 0) { 11884327Sdougm xmlFree(path); 11894327Sdougm break; 11904327Sdougm } 11914327Sdougm xmlFree(path); 11924327Sdougm } 11933034Sdougm } 11943034Sdougm } 11953034Sdougm } 11963034Sdougm return ((sa_share_t)node); 11973034Sdougm } 11983034Sdougm 11993034Sdougm /* 12003034Sdougm * sa_get_next_share(share) 12013034Sdougm * Return the next share following the specified share 12023034Sdougm * from the internal list of shares. Returns NULL if there 12033034Sdougm * are no more shares. The list is relative to the same 12043034Sdougm * group. 12053034Sdougm */ 12063034Sdougm sa_share_t 12073034Sdougm sa_get_next_share(sa_share_t share) 12083034Sdougm { 12093034Sdougm xmlNodePtr node = NULL; 12103034Sdougm 12113034Sdougm if (share != NULL) { 12124327Sdougm for (node = ((xmlNodePtr)share)->next; node != NULL; 12133034Sdougm node = node->next) { 12144327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) { 12154327Sdougm break; 12164327Sdougm } 12173034Sdougm } 12183034Sdougm } 12193034Sdougm return ((sa_share_t)node); 12203034Sdougm } 12213034Sdougm 12223034Sdougm /* 12233034Sdougm * _sa_get_child_node(node, type) 12243034Sdougm * 12253034Sdougm * find the child node of the specified node that has "type". This is 12263034Sdougm * used to implement several internal functions. 12273034Sdougm */ 12283034Sdougm 12293034Sdougm static xmlNodePtr 12303034Sdougm _sa_get_child_node(xmlNodePtr node, xmlChar *type) 12313034Sdougm { 12323034Sdougm xmlNodePtr child; 12333034Sdougm for (child = node->xmlChildrenNode; child != NULL; 12343034Sdougm child = child->next) 12354327Sdougm if (xmlStrcmp(child->name, type) == 0) 12364327Sdougm return (child); 12373034Sdougm return ((xmlNodePtr)NULL); 12383034Sdougm } 12393034Sdougm 12403034Sdougm /* 12413034Sdougm * find_share(group, path) 12423034Sdougm * 12433034Sdougm * Search all the shares in the specified group for one that has the 12443034Sdougm * specified path. 12453034Sdougm */ 12463034Sdougm 12473034Sdougm static sa_share_t 12483034Sdougm find_share(sa_group_t group, char *sharepath) 12493034Sdougm { 12503034Sdougm sa_share_t share; 12513034Sdougm char *path; 12523034Sdougm 12533034Sdougm for (share = sa_get_share(group, NULL); share != NULL; 12543034Sdougm share = sa_get_next_share(share)) { 12554327Sdougm path = sa_get_share_attr(share, "path"); 12564327Sdougm if (path != NULL && strcmp(path, sharepath) == 0) { 12574327Sdougm sa_free_attr_string(path); 12584327Sdougm break; 12594327Sdougm } 12604327Sdougm if (path != NULL) 12614327Sdougm sa_free_attr_string(path); 12623034Sdougm } 12633034Sdougm return (share); 12643034Sdougm } 12653034Sdougm 12663034Sdougm /* 12673034Sdougm * sa_get_sub_group(group) 12683034Sdougm * 12693034Sdougm * Get the first sub-group of group. The sa_get_next_group() function 12703034Sdougm * can be used to get the rest. This is currently only used for ZFS 12713034Sdougm * sub-groups but could be used to implement a more general mechanism. 12723034Sdougm */ 12733034Sdougm 12743034Sdougm sa_group_t 12753034Sdougm sa_get_sub_group(sa_group_t group) 12763034Sdougm { 12773034Sdougm return ((sa_group_t)_sa_get_child_node((xmlNodePtr)group, 12784327Sdougm (xmlChar *)"group")); 12793034Sdougm } 12803034Sdougm 12813034Sdougm /* 12823034Sdougm * sa_find_share(sharepath) 12833034Sdougm * Finds a share regardless of group. In the future, this 12843034Sdougm * function should utilize a cache and hash table of some kind. 12853034Sdougm * The current assumption is that a path will only be shared 12863034Sdougm * once. In the future, this may change as implementation of 12873034Sdougm * resource names comes into being. 12883034Sdougm */ 12893034Sdougm sa_share_t 12903910Sdougm sa_find_share(sa_handle_t handle, char *sharepath) 12913034Sdougm { 12923034Sdougm sa_group_t group; 12933034Sdougm sa_group_t zgroup; 12943034Sdougm sa_share_t share = NULL; 12953034Sdougm int done = 0; 12963034Sdougm 12973910Sdougm for (group = sa_get_group(handle, NULL); group != NULL && !done; 12984327Sdougm group = sa_get_next_group(group)) { 12994327Sdougm if (is_zfs_group(group)) { 13004327Sdougm for (zgroup = 13014327Sdougm (sa_group_t)_sa_get_child_node((xmlNodePtr)group, 13024327Sdougm (xmlChar *)"group"); 13034327Sdougm zgroup != NULL; 13044327Sdougm zgroup = sa_get_next_group(zgroup)) { 13054327Sdougm share = find_share(zgroup, sharepath); 13064327Sdougm if (share != NULL) 13074327Sdougm break; 13084327Sdougm } 13094327Sdougm } else { 13104327Sdougm share = find_share(group, sharepath); 13114327Sdougm } 13124327Sdougm if (share != NULL) 13133034Sdougm break; 13143034Sdougm } 13153034Sdougm return (share); 13163034Sdougm } 13173034Sdougm 13183034Sdougm /* 13193348Sdougm * sa_check_path(group, path, strictness) 13203034Sdougm * 13215331Samw * Check that path is a valid path relative to the group. Currently, 13223034Sdougm * we are ignoring the group and checking only the NFS rules. Later, 13233034Sdougm * we may want to use the group to then check against the protocols 13243348Sdougm * enabled on the group. The strictness values mean: 13253348Sdougm * SA_CHECK_NORMAL == only check newpath against shares that are active 13263348Sdougm * SA_CHECK_STRICT == check newpath against both active shares and those 13273348Sdougm * stored in the repository 13283034Sdougm */ 13293034Sdougm 13303034Sdougm int 13313348Sdougm sa_check_path(sa_group_t group, char *path, int strictness) 13323034Sdougm { 13333910Sdougm sa_handle_t handle; 13343910Sdougm 13353910Sdougm handle = sa_find_group_handle(group); 13363910Sdougm return (validpath(handle, path, strictness)); 13373034Sdougm } 13383034Sdougm 13393034Sdougm /* 13405331Samw * mark_excluded_protos(group, share, flags) 13413034Sdougm * 13425331Samw * Walk through all the protocols enabled for the group and check to 13435331Samw * see if the share has any of them should be in the exclude list 13445331Samw * based on the featureset of the protocol. If there are any, add the 13455331Samw * "exclude" property to the share. 13465331Samw */ 13475331Samw static void 13485331Samw mark_excluded_protos(sa_group_t group, xmlNodePtr share, uint64_t flags) 13495331Samw { 13505331Samw sa_optionset_t optionset; 13515331Samw char exclude_list[SA_STRSIZE]; 13525331Samw char *sep = ""; 13535331Samw 13545331Samw exclude_list[0] = '\0'; 13555331Samw for (optionset = sa_get_optionset(group, NULL); 13565331Samw optionset != NULL; 13575331Samw optionset = sa_get_next_optionset(optionset)) { 13585331Samw char *value; 13595331Samw uint64_t features; 13605331Samw value = sa_get_optionset_attr(optionset, "type"); 13615331Samw if (value == NULL) 13625331Samw continue; 13635331Samw features = sa_proto_get_featureset(value); 13645331Samw sa_free_attr_string(value); 13655331Samw if (!(features & flags)) { 13665331Samw (void) strlcat(exclude_list, sep, 13675331Samw sizeof (exclude_list)); 13685331Samw (void) strlcat(exclude_list, value, 13695331Samw sizeof (exclude_list)); 13705331Samw sep = ","; 13715331Samw } 13725331Samw } 13735331Samw if (exclude_list[0] != '\0') 13745331Samw xmlSetProp(share, (xmlChar *)"exclude", 13755331Samw (xmlChar *)exclude_list); 13765331Samw } 13775331Samw 13785331Samw /* 13795331Samw * get_all_features(group) 13805331Samw * 13815331Samw * Walk through all the protocols on the group and collect all 13825331Samw * possible enabled features. This is the OR of all the featuresets. 13835331Samw */ 13845331Samw static uint64_t 13855331Samw get_all_features(sa_group_t group) 13865331Samw { 13875331Samw sa_optionset_t optionset; 13885331Samw uint64_t features = 0; 13895331Samw 13905331Samw for (optionset = sa_get_optionset(group, NULL); 13915331Samw optionset != NULL; 13925331Samw optionset = sa_get_next_optionset(optionset)) { 13935331Samw char *value; 13945331Samw value = sa_get_optionset_attr(optionset, "type"); 13955331Samw if (value == NULL) 13965331Samw continue; 13975331Samw features |= sa_proto_get_featureset(value); 13985331Samw sa_free_attr_string(value); 13995331Samw } 14005331Samw return (features); 14015331Samw } 14025331Samw 14035331Samw 14045331Samw /* 14055331Samw * _sa_add_share(group, sharepath, persist, *error, flags) 14065331Samw * 14075331Samw * Common code for all types of add_share. sa_add_share() is the 14083034Sdougm * public API, we also need to be able to do this when parsing legacy 14093034Sdougm * files and construction of the internal configuration while 14105331Samw * extracting config info from SMF. "flags" indicates if some 14115331Samw * protocols need relaxed rules while other don't. These values are 14125331Samw * the featureset values defined in libshare.h. 14133034Sdougm */ 14143034Sdougm 14153034Sdougm sa_share_t 14165331Samw _sa_add_share(sa_group_t group, char *sharepath, int persist, int *error, 14175331Samw uint64_t flags) 14183034Sdougm { 14193034Sdougm xmlNodePtr node = NULL; 14203034Sdougm int err; 14213034Sdougm 14223034Sdougm err = SA_OK; /* assume success */ 14233034Sdougm 14244327Sdougm node = xmlNewChild((xmlNodePtr)group, NULL, (xmlChar *)"share", NULL); 14255331Samw if (node == NULL) { 14265331Samw if (error != NULL) 14275331Samw *error = SA_NO_MEMORY; 14285331Samw return (node); 14295331Samw } 14305331Samw 14315331Samw xmlSetProp(node, (xmlChar *)"path", (xmlChar *)sharepath); 14325331Samw xmlSetProp(node, (xmlChar *)"type", 14335331Samw persist ? (xmlChar *)"persist" : (xmlChar *)"transient"); 14345331Samw if (flags != 0) 14355331Samw mark_excluded_protos(group, node, flags); 14365331Samw if (persist != SA_SHARE_TRANSIENT) { 14375331Samw /* 14385331Samw * persistent shares come in two flavors: SMF and 14395331Samw * ZFS. Sort this one out based on target group and 14405331Samw * path type. Both NFS and SMB are supported. First, 14415331Samw * check to see if the protocol is enabled on the 14425331Samw * subgroup and then setup the share appropriately. 14435331Samw */ 14445331Samw if (sa_group_is_zfs(group) && 14455331Samw sa_path_is_zfs(sharepath)) { 14465331Samw if (sa_get_optionset(group, "nfs") != NULL) 14474327Sdougm err = sa_zfs_set_sharenfs(group, sharepath, 1); 14485331Samw else if (sa_get_optionset(group, "smb") != NULL) 14495331Samw err = sa_zfs_set_sharesmb(group, sharepath, 1); 14505331Samw } else { 14515331Samw sa_handle_impl_t impl_handle; 14525331Samw impl_handle = 14535331Samw (sa_handle_impl_t)sa_find_group_handle(group); 14545331Samw if (impl_handle != NULL) { 14555331Samw err = sa_commit_share(impl_handle->scfhandle, 14565331Samw group, (sa_share_t)node); 14574327Sdougm } else { 14585331Samw err = SA_SYSTEM_ERR; 14594327Sdougm } 14603034Sdougm } 14613034Sdougm } 14625331Samw if (err == SA_NO_PERMISSION && persist & SA_SHARE_PARSER) 14635331Samw /* called by the dfstab parser so could be a show */ 14645331Samw err = SA_OK; 14655331Samw 14665331Samw if (err != SA_OK) { 14675331Samw /* 14685331Samw * we couldn't commit to the repository so undo 14695331Samw * our internal state to reflect reality. 14705331Samw */ 14715331Samw xmlUnlinkNode(node); 14725331Samw xmlFreeNode(node); 14735331Samw node = NULL; 14745331Samw } 14755331Samw 14763034Sdougm if (error != NULL) 14774327Sdougm *error = err; 14785331Samw 14793034Sdougm return (node); 14803034Sdougm } 14813034Sdougm 14823034Sdougm /* 14833034Sdougm * sa_add_share(group, sharepath, persist, *error) 14843034Sdougm * 14853034Sdougm * Add a new share object to the specified group. The share will 14863034Sdougm * have the specified sharepath and will only be constructed if 14873034Sdougm * it is a valid path to be shared. NULL is returned on error 14883034Sdougm * and a detailed error value will be returned via the error 14893034Sdougm * pointer. 14903034Sdougm */ 14913034Sdougm sa_share_t 14923034Sdougm sa_add_share(sa_group_t group, char *sharepath, int persist, int *error) 14933034Sdougm { 14943034Sdougm xmlNodePtr node = NULL; 14953348Sdougm int strictness = SA_CHECK_NORMAL; 14963910Sdougm sa_handle_t handle; 14975331Samw uint64_t special = 0; 14985331Samw uint64_t features; 14993348Sdougm 15003348Sdougm /* 15013348Sdougm * If the share is to be permanent, use strict checking so a 15023348Sdougm * bad config doesn't get created. Transient shares only need 15033348Sdougm * to check against the currently active 15043348Sdougm * shares. SA_SHARE_PARSER is a modifier used internally to 15053348Sdougm * indicate that we are being called by the dfstab parser and 15063348Sdougm * that we need strict checking in all cases. Normally persist 15073348Sdougm * is in integer value but SA_SHARE_PARSER may be or'd into 15083348Sdougm * it as an override. 15093348Sdougm */ 15103348Sdougm if (persist & SA_SHARE_PARSER || persist == SA_SHARE_PERMANENT) 15114327Sdougm strictness = SA_CHECK_STRICT; 15123034Sdougm 15133910Sdougm handle = sa_find_group_handle(group); 15143910Sdougm 15155331Samw /* 15165331Samw * need to determine if the share is valid. The rules are: 15175331Samw * - The path must not already exist 15185331Samw * - The path must not be a subdir or parent dir of an 15195331Samw * existing path unless at least one protocol allows it. 15205331Samw * The sub/parent check is done in sa_check_path(). 15215331Samw */ 15225331Samw 15235331Samw if (sa_find_share(handle, sharepath) == NULL) { 15245331Samw *error = sa_check_path(group, sharepath, strictness); 15255331Samw features = get_all_features(group); 15265331Samw switch (*error) { 15275331Samw case SA_PATH_IS_SUBDIR: 15285331Samw if (features & SA_FEATURE_ALLOWSUBDIRS) 15295331Samw special |= SA_FEATURE_ALLOWSUBDIRS; 15305331Samw break; 15315331Samw case SA_PATH_IS_PARENTDIR: 15325331Samw if (features & SA_FEATURE_ALLOWPARDIRS) 15335331Samw special |= SA_FEATURE_ALLOWPARDIRS; 15345331Samw break; 15355331Samw } 15365331Samw if (*error == SA_OK || special != SA_FEATURE_NONE) 15375331Samw node = _sa_add_share(group, sharepath, persist, 15385331Samw error, special); 15395331Samw } else { 15405331Samw *error = SA_DUPLICATE_NAME; 15413034Sdougm } 15423034Sdougm 15433034Sdougm return ((sa_share_t)node); 15443034Sdougm } 15453034Sdougm 15463034Sdougm /* 15473034Sdougm * sa_enable_share(share, protocol) 15483034Sdougm * Enable the specified share to the specified protocol. 15493034Sdougm * If protocol is NULL, then all protocols. 15503034Sdougm */ 15513034Sdougm int 15523034Sdougm sa_enable_share(sa_share_t share, char *protocol) 15533034Sdougm { 15543034Sdougm char *sharepath; 15553034Sdougm struct stat st; 15565331Samw int err = SA_OK; 15575331Samw int ret; 15583034Sdougm 15593034Sdougm sharepath = sa_get_share_attr(share, "path"); 15605331Samw if (sharepath == NULL) 15615331Samw return (SA_NO_MEMORY); 15623034Sdougm if (stat(sharepath, &st) < 0) { 15634327Sdougm err = SA_NO_SUCH_PATH; 15643034Sdougm } else { 15654327Sdougm /* tell the server about the share */ 15664327Sdougm if (protocol != NULL) { 15675331Samw if (excluded_protocol(share, protocol)) 15685331Samw goto done; 15695331Samw 15704327Sdougm /* lookup protocol specific handler */ 15714327Sdougm err = sa_proto_share(protocol, share); 15724327Sdougm if (err == SA_OK) 15735331Samw (void) sa_set_share_attr(share, 15745331Samw "shared", "true"); 15754327Sdougm } else { 15765331Samw /* Tell all protocols about the share */ 15775331Samw sa_group_t group; 15785331Samw sa_optionset_t optionset; 15795331Samw 15805331Samw group = sa_get_parent_group(share); 15815331Samw 15825331Samw for (optionset = sa_get_optionset(group, NULL); 15835331Samw optionset != NULL; 15845331Samw optionset = sa_get_next_optionset(optionset)) { 15855331Samw char *proto; 15865331Samw proto = sa_get_optionset_attr(optionset, 15875331Samw "type"); 15885331Samw if (proto != NULL) { 15895331Samw if (!excluded_protocol(share, proto)) { 15905331Samw ret = sa_proto_share(proto, 15915331Samw share); 15925331Samw if (ret != SA_OK) 15935331Samw err = ret; 15945331Samw } 15955331Samw sa_free_attr_string(proto); 15965331Samw } 15975331Samw } 15984327Sdougm (void) sa_set_share_attr(share, "shared", "true"); 15994327Sdougm } 16003034Sdougm } 16015331Samw done: 16023034Sdougm if (sharepath != NULL) 16034327Sdougm sa_free_attr_string(sharepath); 16043034Sdougm return (err); 16053034Sdougm } 16063034Sdougm 16073034Sdougm /* 16083034Sdougm * sa_disable_share(share, protocol) 16095331Samw * Disable the specified share to the specified protocol. If 16105331Samw * protocol is NULL, then all protocols that are enabled for the 16115331Samw * share should be disabled. 16123034Sdougm */ 16133034Sdougm int 16143034Sdougm sa_disable_share(sa_share_t share, char *protocol) 16153034Sdougm { 16163034Sdougm char *path; 16175331Samw int err = SA_OK; 16183034Sdougm int ret = SA_OK; 16193034Sdougm 16203034Sdougm path = sa_get_share_attr(share, "path"); 16213034Sdougm 16223034Sdougm if (protocol != NULL) { 16234543Smarks ret = sa_proto_unshare(share, protocol, path); 16243034Sdougm } else { 16254327Sdougm /* need to do all protocols */ 16265331Samw sa_group_t group; 16275331Samw sa_optionset_t optionset; 16285331Samw 16295331Samw group = sa_get_parent_group(share); 16305331Samw 16315331Samw /* Tell all protocols about the share */ 16325331Samw for (optionset = sa_get_optionset(group, NULL); 16335331Samw optionset != NULL; 16345331Samw optionset = sa_get_next_optionset(optionset)) { 16355331Samw char *proto; 16365331Samw 16375331Samw proto = sa_get_optionset_attr(optionset, "type"); 16385331Samw if (proto != NULL) { 16395331Samw err = sa_proto_unshare(share, proto, path); 16405331Samw if (err != SA_OK) 16415331Samw ret = err; 16425331Samw sa_free_attr_string(proto); 16435331Samw } 16445331Samw } 16453034Sdougm } 16463034Sdougm if (ret == SA_OK) 16473034Sdougm (void) sa_set_share_attr(share, "shared", NULL); 16483034Sdougm if (path != NULL) 16494327Sdougm sa_free_attr_string(path); 16503034Sdougm return (ret); 16513034Sdougm } 16523034Sdougm 16533034Sdougm /* 16543034Sdougm * sa_remove_share(share) 16553034Sdougm * 16563034Sdougm * remove the specified share from its containing group. 16573034Sdougm * Remove from the SMF or ZFS configuration space. 16583034Sdougm */ 16593034Sdougm 16603034Sdougm int 16613034Sdougm sa_remove_share(sa_share_t share) 16623034Sdougm { 16633034Sdougm sa_group_t group; 16643034Sdougm int ret = SA_OK; 16653034Sdougm char *type; 16663034Sdougm int transient = 0; 16673034Sdougm char *groupname; 16683034Sdougm char *zfs; 16693034Sdougm 16703034Sdougm type = sa_get_share_attr(share, "type"); 16713034Sdougm group = sa_get_parent_group(share); 16723034Sdougm zfs = sa_get_group_attr(group, "zfs"); 16733034Sdougm groupname = sa_get_group_attr(group, "name"); 16743034Sdougm if (type != NULL && strcmp(type, "persist") != 0) 16754327Sdougm transient = 1; 16763034Sdougm if (type != NULL) 16774327Sdougm sa_free_attr_string(type); 16783034Sdougm 16793034Sdougm /* remove the node from its group then free the memory */ 16803034Sdougm 16813034Sdougm /* 16823034Sdougm * need to test if "busy" 16833034Sdougm */ 16843034Sdougm /* only do SMF action if permanent */ 16853034Sdougm if (!transient || zfs != NULL) { 16864327Sdougm /* remove from legacy dfstab as well as possible SMF */ 16875331Samw ret = sa_delete_legacy(share, NULL); 16884327Sdougm if (ret == SA_OK) { 16894327Sdougm if (!sa_group_is_zfs(group)) { 16904327Sdougm sa_handle_impl_t impl_handle; 16914327Sdougm impl_handle = (sa_handle_impl_t) 16924327Sdougm sa_find_group_handle(group); 16934327Sdougm if (impl_handle != NULL) { 16944327Sdougm ret = sa_delete_share( 16954327Sdougm impl_handle->scfhandle, group, 16964327Sdougm share); 16974327Sdougm } else { 16984327Sdougm ret = SA_SYSTEM_ERR; 16994327Sdougm } 17004327Sdougm } else { 17014327Sdougm char *sharepath = sa_get_share_attr(share, 17024327Sdougm "path"); 17034327Sdougm if (sharepath != NULL) { 17044327Sdougm ret = sa_zfs_set_sharenfs(group, 17054327Sdougm sharepath, 0); 17064327Sdougm sa_free_attr_string(sharepath); 17074327Sdougm } 17084327Sdougm } 17093034Sdougm } 17103034Sdougm } 17113034Sdougm if (groupname != NULL) 17124327Sdougm sa_free_attr_string(groupname); 17133034Sdougm if (zfs != NULL) 17144327Sdougm sa_free_attr_string(zfs); 17153034Sdougm 17163034Sdougm xmlUnlinkNode((xmlNodePtr)share); 17173034Sdougm xmlFreeNode((xmlNodePtr)share); 17183034Sdougm return (ret); 17193034Sdougm } 17203034Sdougm 17213034Sdougm /* 17223034Sdougm * sa_move_share(group, share) 17233034Sdougm * 17243034Sdougm * move the specified share to the specified group. Update SMF 17253034Sdougm * appropriately. 17263034Sdougm */ 17273034Sdougm 17283034Sdougm int 17293034Sdougm sa_move_share(sa_group_t group, sa_share_t share) 17303034Sdougm { 17313034Sdougm sa_group_t oldgroup; 17323034Sdougm int ret = SA_OK; 17333034Sdougm 17343034Sdougm /* remove the node from its group then free the memory */ 17353034Sdougm 17363034Sdougm oldgroup = sa_get_parent_group(share); 17373034Sdougm if (oldgroup != group) { 17384327Sdougm sa_handle_impl_t impl_handle; 17394327Sdougm xmlUnlinkNode((xmlNodePtr)share); 17403034Sdougm /* 17414327Sdougm * now that the share isn't in its old group, add to 17424327Sdougm * the new one 17433034Sdougm */ 17444327Sdougm xmlAddChild((xmlNodePtr)group, (xmlNodePtr)share); 17454327Sdougm /* need to deal with SMF */ 17464327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 17474327Sdougm if (impl_handle != NULL) { 17484327Sdougm /* 17494327Sdougm * need to remove from old group first and then add to 17504327Sdougm * new group. Ideally, we would do the other order but 17514327Sdougm * need to avoid having the share in two groups at the 17524327Sdougm * same time. 17534327Sdougm */ 17544327Sdougm ret = sa_delete_share(impl_handle->scfhandle, oldgroup, 17554327Sdougm share); 17564327Sdougm if (ret == SA_OK) 17574327Sdougm ret = sa_commit_share(impl_handle->scfhandle, 17584327Sdougm group, share); 17594327Sdougm } else { 17604327Sdougm ret = SA_SYSTEM_ERR; 17614327Sdougm } 17623034Sdougm } 17633034Sdougm return (ret); 17643034Sdougm } 17653034Sdougm 17663034Sdougm /* 17673034Sdougm * sa_get_parent_group(share) 17683034Sdougm * 17695331Samw * Return the containing group for the share. If a group was actually 17703034Sdougm * passed in, we don't want a parent so return NULL. 17713034Sdougm */ 17723034Sdougm 17733034Sdougm sa_group_t 17743034Sdougm sa_get_parent_group(sa_share_t share) 17753034Sdougm { 17763034Sdougm xmlNodePtr node = NULL; 17773034Sdougm if (share != NULL) { 17784327Sdougm node = ((xmlNodePtr)share)->parent; 17793034Sdougm /* 17803034Sdougm * make sure parent is a group and not sharecfg since 17813034Sdougm * we may be cheating and passing in a group. 17823034Sdougm * Eventually, groups of groups might come into being. 17833034Sdougm */ 17844327Sdougm if (node == NULL || 17854327Sdougm xmlStrcmp(node->name, (xmlChar *)"sharecfg") == 0) 17864327Sdougm node = NULL; 17873034Sdougm } 17883034Sdougm return ((sa_group_t)node); 17893034Sdougm } 17903034Sdougm 17913034Sdougm /* 17923910Sdougm * _sa_create_group(impl_handle, groupname) 17933034Sdougm * 17943034Sdougm * Create a group in the document. The caller will need to deal with 17953034Sdougm * configuration store and activation. 17963034Sdougm */ 17973034Sdougm 17983034Sdougm sa_group_t 17993910Sdougm _sa_create_group(sa_handle_impl_t impl_handle, char *groupname) 18003034Sdougm { 18013034Sdougm xmlNodePtr node = NULL; 18023034Sdougm 18033034Sdougm if (sa_valid_group_name(groupname)) { 18044327Sdougm node = xmlNewChild(impl_handle->tree, NULL, (xmlChar *)"group", 18054327Sdougm NULL); 18064327Sdougm if (node != NULL) { 18074327Sdougm xmlSetProp(node, (xmlChar *)"name", 18084327Sdougm (xmlChar *)groupname); 18094327Sdougm xmlSetProp(node, (xmlChar *)"state", 18104327Sdougm (xmlChar *)"enabled"); 18114327Sdougm } 18123034Sdougm } 18133034Sdougm return ((sa_group_t)node); 18143034Sdougm } 18153034Sdougm 18163034Sdougm /* 18173034Sdougm * _sa_create_zfs_group(group, groupname) 18183034Sdougm * 18193034Sdougm * Create a ZFS subgroup under the specified group. This may 18203034Sdougm * eventually form the basis of general sub-groups, but is currently 18213034Sdougm * restricted to ZFS. 18223034Sdougm */ 18233034Sdougm sa_group_t 18243034Sdougm _sa_create_zfs_group(sa_group_t group, char *groupname) 18253034Sdougm { 18263034Sdougm xmlNodePtr node = NULL; 18273034Sdougm 18284327Sdougm node = xmlNewChild((xmlNodePtr)group, NULL, (xmlChar *)"group", NULL); 18293034Sdougm if (node != NULL) { 18303034Sdougm xmlSetProp(node, (xmlChar *)"name", (xmlChar *)groupname); 18313034Sdougm xmlSetProp(node, (xmlChar *)"state", (xmlChar *)"enabled"); 18323034Sdougm } 18333034Sdougm 18343034Sdougm return ((sa_group_t)node); 18353034Sdougm } 18363034Sdougm 18373034Sdougm /* 18383034Sdougm * sa_create_group(groupname, *error) 18393034Sdougm * 18403034Sdougm * Create a new group with groupname. Need to validate that it is a 18413034Sdougm * legal name for SMF and the construct the SMF service instance of 18423034Sdougm * svc:/network/shares/group to implement the group. All necessary 18433034Sdougm * operational properties must be added to the group at this point 18443034Sdougm * (via the SMF transaction model). 18453034Sdougm */ 18463034Sdougm sa_group_t 18473910Sdougm sa_create_group(sa_handle_t handle, char *groupname, int *error) 18483034Sdougm { 18493034Sdougm xmlNodePtr node = NULL; 18503034Sdougm sa_group_t group; 18513034Sdougm int ret; 18524327Sdougm char rbacstr[SA_STRSIZE]; 18533910Sdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle; 18543034Sdougm 18553034Sdougm ret = SA_OK; 18563034Sdougm 18573910Sdougm if (impl_handle == NULL || impl_handle->scfhandle == NULL) { 18584327Sdougm ret = SA_SYSTEM_ERR; 18594327Sdougm goto err; 18603034Sdougm } 18613034Sdougm 18623910Sdougm group = sa_get_group(handle, groupname); 18633034Sdougm if (group != NULL) { 18644327Sdougm ret = SA_DUPLICATE_NAME; 18653034Sdougm } else { 18664327Sdougm if (sa_valid_group_name(groupname)) { 18674327Sdougm node = xmlNewChild(impl_handle->tree, NULL, 18684327Sdougm (xmlChar *)"group", NULL); 18694327Sdougm if (node != NULL) { 18704327Sdougm xmlSetProp(node, (xmlChar *)"name", 18714327Sdougm (xmlChar *)groupname); 18724327Sdougm /* default to the group being enabled */ 18734327Sdougm xmlSetProp(node, (xmlChar *)"state", 18744327Sdougm (xmlChar *)"enabled"); 18754327Sdougm ret = sa_create_instance(impl_handle->scfhandle, 18764327Sdougm groupname); 18774327Sdougm if (ret == SA_OK) { 18784327Sdougm ret = sa_start_transaction( 18794327Sdougm impl_handle->scfhandle, 18804327Sdougm "operation"); 18814327Sdougm } 18824327Sdougm if (ret == SA_OK) { 18834327Sdougm ret = sa_set_property( 18844327Sdougm impl_handle->scfhandle, 18854327Sdougm "state", "enabled"); 18864327Sdougm if (ret == SA_OK) { 18874327Sdougm ret = sa_end_transaction( 18884327Sdougm impl_handle->scfhandle); 18894327Sdougm } else { 18904327Sdougm sa_abort_transaction( 18914327Sdougm impl_handle->scfhandle); 18924327Sdougm } 18934327Sdougm } 18944327Sdougm if (ret == SA_OK) { 18954327Sdougm /* initialize the RBAC strings */ 18964327Sdougm ret = sa_start_transaction( 18974327Sdougm impl_handle->scfhandle, 18984327Sdougm "general"); 18994327Sdougm if (ret == SA_OK) { 19004327Sdougm (void) snprintf(rbacstr, 19014327Sdougm sizeof (rbacstr), "%s.%s", 19024327Sdougm SA_RBAC_MANAGE, groupname); 19034327Sdougm ret = sa_set_property( 19044327Sdougm impl_handle->scfhandle, 19053034Sdougm "action_authorization", 19063034Sdougm rbacstr); 19074327Sdougm } 19084327Sdougm if (ret == SA_OK) { 19094327Sdougm (void) snprintf(rbacstr, 19104327Sdougm sizeof (rbacstr), "%s.%s", 19114327Sdougm SA_RBAC_VALUE, groupname); 19124327Sdougm ret = sa_set_property( 19134327Sdougm impl_handle->scfhandle, 19143034Sdougm "value_authorization", 19153034Sdougm rbacstr); 19164327Sdougm } 19174327Sdougm if (ret == SA_OK) { 19184327Sdougm ret = sa_end_transaction( 19194327Sdougm impl_handle->scfhandle); 19204327Sdougm } else { 19214327Sdougm sa_abort_transaction( 19224327Sdougm impl_handle->scfhandle); 19234327Sdougm } 19244327Sdougm } 19254327Sdougm if (ret != SA_OK) { 19264327Sdougm /* 19274327Sdougm * Couldn't commit the group 19284327Sdougm * so we need to undo 19294327Sdougm * internally. 19304327Sdougm */ 19314327Sdougm xmlUnlinkNode(node); 19324327Sdougm xmlFreeNode(node); 19334327Sdougm node = NULL; 19344327Sdougm } 19353034Sdougm } else { 19364327Sdougm ret = SA_NO_MEMORY; 19373034Sdougm } 19383034Sdougm } else { 19394327Sdougm ret = SA_INVALID_NAME; 19403034Sdougm } 19413034Sdougm } 19423034Sdougm err: 19433034Sdougm if (error != NULL) 19444327Sdougm *error = ret; 19453034Sdougm return ((sa_group_t)node); 19463034Sdougm } 19473034Sdougm 19483034Sdougm /* 19493034Sdougm * sa_remove_group(group) 19503034Sdougm * 19513034Sdougm * Remove the specified group. This deletes from the SMF repository. 19523034Sdougm * All property groups and properties are removed. 19533034Sdougm */ 19543034Sdougm 19553034Sdougm int 19563034Sdougm sa_remove_group(sa_group_t group) 19573034Sdougm { 19583034Sdougm char *name; 19593034Sdougm int ret = SA_OK; 19603910Sdougm sa_handle_impl_t impl_handle; 19613034Sdougm 19623910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 19633910Sdougm if (impl_handle != NULL) { 19644327Sdougm name = sa_get_group_attr(group, "name"); 19654327Sdougm if (name != NULL) { 19664327Sdougm ret = sa_delete_instance(impl_handle->scfhandle, name); 19674327Sdougm sa_free_attr_string(name); 19684327Sdougm } 19694327Sdougm xmlUnlinkNode((xmlNodePtr)group); /* make sure unlinked */ 19704327Sdougm xmlFreeNode((xmlNodePtr)group); /* now it is gone */ 19713910Sdougm } else { 19724327Sdougm ret = SA_SYSTEM_ERR; 19733034Sdougm } 19743034Sdougm return (ret); 19753034Sdougm } 19763034Sdougm 19773034Sdougm /* 19783034Sdougm * sa_update_config() 19793034Sdougm * 19803034Sdougm * Used to update legacy files that need to be updated in bulk 19813034Sdougm * Currently, this is a placeholder and will go away in a future 19823034Sdougm * release. 19833034Sdougm */ 19843034Sdougm 19853034Sdougm int 19863910Sdougm sa_update_config(sa_handle_t handle) 19873034Sdougm { 19883034Sdougm /* 19893034Sdougm * do legacy files first so we can tell when they change. 19903034Sdougm * This will go away when we start updating individual records 19913034Sdougm * rather than the whole file. 19923034Sdougm */ 19933910Sdougm update_legacy_config(handle); 19943034Sdougm return (SA_OK); 19953034Sdougm } 19963034Sdougm 19973034Sdougm /* 19983034Sdougm * get_node_attr(node, tag) 19993034Sdougm * 20005331Samw * Get the specified tag(attribute) if it exists on the node. This is 20013034Sdougm * used internally by a number of attribute oriented functions. 20023034Sdougm */ 20033034Sdougm 20043034Sdougm static char * 20053034Sdougm get_node_attr(void *nodehdl, char *tag) 20063034Sdougm { 20073034Sdougm xmlNodePtr node = (xmlNodePtr)nodehdl; 20083034Sdougm xmlChar *name = NULL; 20093034Sdougm 20104327Sdougm if (node != NULL) 20113034Sdougm name = xmlGetProp(node, (xmlChar *)tag); 20123034Sdougm return ((char *)name); 20133034Sdougm } 20143034Sdougm 20153034Sdougm /* 20163034Sdougm * get_node_attr(node, tag) 20173034Sdougm * 20185331Samw * Set the specified tag(attribute) to the specified value This is 20193034Sdougm * used internally by a number of attribute oriented functions. It 20203034Sdougm * doesn't update the repository, only the internal document state. 20213034Sdougm */ 20223034Sdougm 20233034Sdougm void 20243034Sdougm set_node_attr(void *nodehdl, char *tag, char *value) 20253034Sdougm { 20263034Sdougm xmlNodePtr node = (xmlNodePtr)nodehdl; 20273034Sdougm if (node != NULL && tag != NULL) { 20284327Sdougm if (value != NULL) 20293034Sdougm xmlSetProp(node, (xmlChar *)tag, (xmlChar *)value); 20304327Sdougm else 20313034Sdougm xmlUnsetProp(node, (xmlChar *)tag); 20323034Sdougm } 20333034Sdougm } 20343034Sdougm 20353034Sdougm /* 20363034Sdougm * sa_get_group_attr(group, tag) 20373034Sdougm * 20383034Sdougm * Get the specied attribute, if defined, for the group. 20393034Sdougm */ 20403034Sdougm 20413034Sdougm char * 20423034Sdougm sa_get_group_attr(sa_group_t group, char *tag) 20433034Sdougm { 20443034Sdougm return (get_node_attr((void *)group, tag)); 20453034Sdougm } 20463034Sdougm 20473034Sdougm /* 20483034Sdougm * sa_set_group_attr(group, tag, value) 20493034Sdougm * 20503034Sdougm * set the specified tag/attribute on the group using value as its 20513034Sdougm * value. 20523034Sdougm * 20533034Sdougm * This will result in setting the property in the SMF repository as 20543034Sdougm * well as in the internal document. 20553034Sdougm */ 20563034Sdougm 20573034Sdougm int 20583034Sdougm sa_set_group_attr(sa_group_t group, char *tag, char *value) 20593034Sdougm { 20603034Sdougm int ret; 20613034Sdougm char *groupname; 20623910Sdougm sa_handle_impl_t impl_handle; 20633034Sdougm 20645331Samw /* 20655331Samw * ZFS group/subgroup doesn't need the handle so shortcut. 20665331Samw */ 20675331Samw if (sa_group_is_zfs(group)) { 20685331Samw set_node_attr((void *)group, tag, value); 20695331Samw return (SA_OK); 20705331Samw } 20715331Samw 20723910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 20733910Sdougm if (impl_handle != NULL) { 20744327Sdougm groupname = sa_get_group_attr(group, "name"); 20754327Sdougm ret = sa_get_instance(impl_handle->scfhandle, groupname); 20763910Sdougm if (ret == SA_OK) { 20774327Sdougm set_node_attr((void *)group, tag, value); 20784327Sdougm ret = sa_start_transaction(impl_handle->scfhandle, 20794327Sdougm "operation"); 20804327Sdougm if (ret == SA_OK) { 20814327Sdougm ret = sa_set_property(impl_handle->scfhandle, 20824327Sdougm tag, value); 20834327Sdougm if (ret == SA_OK) 20844327Sdougm (void) sa_end_transaction( 20854327Sdougm impl_handle->scfhandle); 20864327Sdougm else 20874327Sdougm sa_abort_transaction( 20884327Sdougm impl_handle->scfhandle); 20894327Sdougm } 20903034Sdougm } 20914327Sdougm if (groupname != NULL) 20924327Sdougm sa_free_attr_string(groupname); 20933910Sdougm } else { 20944327Sdougm ret = SA_SYSTEM_ERR; 20953034Sdougm } 20963034Sdougm return (ret); 20973034Sdougm } 20983034Sdougm 20993034Sdougm /* 21003034Sdougm * sa_get_share_attr(share, tag) 21013034Sdougm * 21023034Sdougm * Return the value of the tag/attribute set on the specified 21033034Sdougm * share. Returns NULL if the tag doesn't exist. 21043034Sdougm */ 21053034Sdougm 21063034Sdougm char * 21073034Sdougm sa_get_share_attr(sa_share_t share, char *tag) 21083034Sdougm { 21093034Sdougm return (get_node_attr((void *)share, tag)); 21103034Sdougm } 21113034Sdougm 21123034Sdougm /* 21133034Sdougm * _sa_set_share_description(share, description) 21143034Sdougm * 21155331Samw * Add a description tag with text contents to the specified share. A 21165331Samw * separate XML tag is used rather than a property. This can also be 21175331Samw * used with resources. 21183034Sdougm */ 21193034Sdougm 21203034Sdougm xmlNodePtr 21215331Samw _sa_set_share_description(void *share, char *content) 21223034Sdougm { 21233034Sdougm xmlNodePtr node; 21244327Sdougm node = xmlNewChild((xmlNodePtr)share, NULL, (xmlChar *)"description", 21254327Sdougm NULL); 21263034Sdougm xmlNodeSetContent(node, (xmlChar *)content); 21273034Sdougm return (node); 21283034Sdougm } 21293034Sdougm 21303034Sdougm /* 21313034Sdougm * sa_set_share_attr(share, tag, value) 21323034Sdougm * 21333034Sdougm * Set the share attribute specified by tag to the specified value. In 21343034Sdougm * the case of "resource", enforce a no duplicates in a group rule. If 21353034Sdougm * the share is not transient, commit the changes to the repository 21363034Sdougm * else just update the share internally. 21373034Sdougm */ 21383034Sdougm 21393034Sdougm int 21403034Sdougm sa_set_share_attr(sa_share_t share, char *tag, char *value) 21413034Sdougm { 21423034Sdougm sa_group_t group; 21433034Sdougm sa_share_t resource; 21443034Sdougm int ret = SA_OK; 21453034Sdougm 21463034Sdougm group = sa_get_parent_group(share); 21473034Sdougm 21483034Sdougm /* 21493034Sdougm * There are some attributes that may have specific 21503034Sdougm * restrictions on them. Initially, only "resource" has 21513034Sdougm * special meaning that needs to be checked. Only one instance 21523034Sdougm * of a resource name may exist within a group. 21533034Sdougm */ 21543034Sdougm 21553034Sdougm if (strcmp(tag, "resource") == 0) { 21564327Sdougm resource = sa_get_resource(group, value); 21574327Sdougm if (resource != share && resource != NULL) 21584327Sdougm ret = SA_DUPLICATE_NAME; 21593034Sdougm } 21603034Sdougm if (ret == SA_OK) { 21614327Sdougm set_node_attr((void *)share, tag, value); 21624327Sdougm if (group != NULL) { 21634327Sdougm char *type; 21644327Sdougm /* we can probably optimize this some */ 21654327Sdougm type = sa_get_share_attr(share, "type"); 21664327Sdougm if (type == NULL || strcmp(type, "transient") != 0) { 21674327Sdougm sa_handle_impl_t impl_handle; 21684327Sdougm impl_handle = 21694327Sdougm (sa_handle_impl_t)sa_find_group_handle( 21704327Sdougm group); 21714327Sdougm if (impl_handle != NULL) { 21724327Sdougm ret = sa_commit_share( 21734327Sdougm impl_handle->scfhandle, group, 21744327Sdougm share); 21754327Sdougm } else { 21764327Sdougm ret = SA_SYSTEM_ERR; 21774327Sdougm } 21784327Sdougm } 21794327Sdougm if (type != NULL) 21804327Sdougm sa_free_attr_string(type); 21813910Sdougm } 21823034Sdougm } 21833034Sdougm return (ret); 21843034Sdougm } 21853034Sdougm 21863034Sdougm /* 21873034Sdougm * sa_get_property_attr(prop, tag) 21883034Sdougm * 21893034Sdougm * Get the value of the specified property attribute. Standard 21903034Sdougm * attributes are "type" and "value". 21913034Sdougm */ 21923034Sdougm 21933034Sdougm char * 21943034Sdougm sa_get_property_attr(sa_property_t prop, char *tag) 21953034Sdougm { 21963034Sdougm return (get_node_attr((void *)prop, tag)); 21973034Sdougm } 21983034Sdougm 21993034Sdougm /* 22003034Sdougm * sa_get_optionset_attr(prop, tag) 22013034Sdougm * 22023034Sdougm * Get the value of the specified property attribute. Standard 22033034Sdougm * attribute is "type". 22043034Sdougm */ 22053034Sdougm 22063034Sdougm char * 22073034Sdougm sa_get_optionset_attr(sa_property_t optionset, char *tag) 22083034Sdougm { 22093034Sdougm return (get_node_attr((void *)optionset, tag)); 22103034Sdougm 22113034Sdougm } 22123034Sdougm 22133034Sdougm /* 22143034Sdougm * sa_set_optionset_attr(optionset, tag, value) 22153034Sdougm * 22163034Sdougm * Set the specified attribute(tag) to the specified value on the 22173034Sdougm * optionset. 22183034Sdougm */ 22193034Sdougm 22203034Sdougm void 22213034Sdougm sa_set_optionset_attr(sa_group_t optionset, char *tag, char *value) 22223034Sdougm { 22233034Sdougm set_node_attr((void *)optionset, tag, value); 22243034Sdougm } 22253034Sdougm 22263034Sdougm /* 22273034Sdougm * sa_free_attr_string(string) 22283034Sdougm * 22293034Sdougm * Free the string that was returned in one of the sa_get_*_attr() 22303034Sdougm * functions. 22313034Sdougm */ 22323034Sdougm 22333034Sdougm void 22343034Sdougm sa_free_attr_string(char *string) 22353034Sdougm { 22363034Sdougm xmlFree((xmlChar *)string); 22373034Sdougm } 22383034Sdougm 22393034Sdougm /* 22403034Sdougm * sa_get_optionset(group, proto) 22413034Sdougm * 22423034Sdougm * Return the optionset, if it exists, that is associated with the 22433034Sdougm * specified protocol. 22443034Sdougm */ 22453034Sdougm 22463034Sdougm sa_optionset_t 22473034Sdougm sa_get_optionset(void *group, char *proto) 22483034Sdougm { 22493034Sdougm xmlNodePtr node; 22503034Sdougm xmlChar *value = NULL; 22513034Sdougm 22523034Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 22534327Sdougm node = node->next) { 22543034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) { 22554327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 22564327Sdougm if (proto != NULL) { 22574327Sdougm if (value != NULL && 22584327Sdougm xmlStrcmp(value, (xmlChar *)proto) == 0) { 22594327Sdougm break; 22604327Sdougm } 22614327Sdougm if (value != NULL) { 22624327Sdougm xmlFree(value); 22634327Sdougm value = NULL; 22644327Sdougm } 22654327Sdougm } else { 22664327Sdougm break; 22673034Sdougm } 22683034Sdougm } 22693034Sdougm } 22703034Sdougm if (value != NULL) 22714327Sdougm xmlFree(value); 22723034Sdougm return ((sa_optionset_t)node); 22733034Sdougm } 22743034Sdougm 22753034Sdougm /* 22763034Sdougm * sa_get_next_optionset(optionset) 22773034Sdougm * 22783034Sdougm * Return the next optionset in the group. NULL if this was the last. 22793034Sdougm */ 22803034Sdougm 22813034Sdougm sa_optionset_t 22823034Sdougm sa_get_next_optionset(sa_optionset_t optionset) 22833034Sdougm { 22843034Sdougm xmlNodePtr node; 22853034Sdougm 22863034Sdougm for (node = ((xmlNodePtr)optionset)->next; node != NULL; 22874327Sdougm node = node->next) { 22883034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) { 22893034Sdougm break; 22903034Sdougm } 22913034Sdougm } 22923034Sdougm return ((sa_optionset_t)node); 22933034Sdougm } 22943034Sdougm 22953034Sdougm /* 22963034Sdougm * sa_get_security(group, sectype, proto) 22973034Sdougm * 22983034Sdougm * Return the security optionset. The internal name is a hold over 22993034Sdougm * from the implementation and will be changed before the API is 23003034Sdougm * finalized. This is really a named optionset that can be negotiated 23013034Sdougm * as a group of properties (like NFS security options). 23023034Sdougm */ 23033034Sdougm 23043034Sdougm sa_security_t 23053034Sdougm sa_get_security(sa_group_t group, char *sectype, char *proto) 23063034Sdougm { 23073034Sdougm xmlNodePtr node; 23083034Sdougm xmlChar *value = NULL; 23093034Sdougm 23103034Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 23114327Sdougm node = node->next) { 23124327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) { 23134327Sdougm if (proto != NULL) { 23144327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 23154327Sdougm if (value == NULL || 23164327Sdougm (value != NULL && 23174327Sdougm xmlStrcmp(value, (xmlChar *)proto) != 0)) { 23184327Sdougm /* it doesn't match so continue */ 23194327Sdougm xmlFree(value); 23204327Sdougm value = NULL; 23214327Sdougm continue; 23224327Sdougm } 23234327Sdougm } 23244327Sdougm if (value != NULL) { 23254327Sdougm xmlFree(value); 23264327Sdougm value = NULL; 23274327Sdougm } 23284327Sdougm /* potential match */ 23294327Sdougm if (sectype != NULL) { 23304327Sdougm value = xmlGetProp(node, (xmlChar *)"sectype"); 23314327Sdougm if (value != NULL && 23324327Sdougm xmlStrcmp(value, (xmlChar *)sectype) == 0) { 23334327Sdougm break; 23344327Sdougm } 23354327Sdougm } else { 23364327Sdougm break; 23374327Sdougm } 23383034Sdougm } 23393034Sdougm if (value != NULL) { 23404327Sdougm xmlFree(value); 23414327Sdougm value = NULL; 23423034Sdougm } 23433034Sdougm } 23443034Sdougm if (value != NULL) 23454327Sdougm xmlFree(value); 23463034Sdougm return ((sa_security_t)node); 23473034Sdougm } 23483034Sdougm 23493034Sdougm /* 23503034Sdougm * sa_get_next_security(security) 23513034Sdougm * 23523034Sdougm * Get the next security optionset if one exists. 23533034Sdougm */ 23543034Sdougm 23553034Sdougm sa_security_t 23563034Sdougm sa_get_next_security(sa_security_t security) 23573034Sdougm { 23583034Sdougm xmlNodePtr node; 23593034Sdougm 23603034Sdougm for (node = ((xmlNodePtr)security)->next; node != NULL; 23614327Sdougm node = node->next) { 23623034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) { 23633034Sdougm break; 23643034Sdougm } 23653034Sdougm } 23663034Sdougm return ((sa_security_t)node); 23673034Sdougm } 23683034Sdougm 23693034Sdougm /* 23703034Sdougm * sa_get_property(optionset, prop) 23713034Sdougm * 23723034Sdougm * Get the property object with the name specified in prop from the 23733034Sdougm * optionset. 23743034Sdougm */ 23753034Sdougm 23763034Sdougm sa_property_t 23773034Sdougm sa_get_property(sa_optionset_t optionset, char *prop) 23783034Sdougm { 23793034Sdougm xmlNodePtr node = (xmlNodePtr)optionset; 23803034Sdougm xmlChar *value = NULL; 23813034Sdougm 23823034Sdougm if (optionset == NULL) 23834327Sdougm return (NULL); 23843034Sdougm 23853034Sdougm for (node = node->children; node != NULL; 23864327Sdougm node = node->next) { 23874327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 23884327Sdougm if (prop == NULL) 23894327Sdougm break; 23904327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 23914327Sdougm if (value != NULL && 23924327Sdougm xmlStrcmp(value, (xmlChar *)prop) == 0) { 23934327Sdougm break; 23944327Sdougm } 23954327Sdougm if (value != NULL) { 23964327Sdougm xmlFree(value); 23974327Sdougm value = NULL; 23984327Sdougm } 23993034Sdougm } 24003034Sdougm } 24013034Sdougm if (value != NULL) 24023034Sdougm xmlFree(value); 24033034Sdougm if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"option") != 0) { 24044327Sdougm /* 24054327Sdougm * avoid a non option node -- it is possible to be a 24064327Sdougm * text node 24074327Sdougm */ 24084327Sdougm node = NULL; 24093034Sdougm } 24103034Sdougm return ((sa_property_t)node); 24113034Sdougm } 24123034Sdougm 24133034Sdougm /* 24143034Sdougm * sa_get_next_property(property) 24153034Sdougm * 24163034Sdougm * Get the next property following the specified property. NULL if 24173034Sdougm * this was the last. 24183034Sdougm */ 24193034Sdougm 24203034Sdougm sa_property_t 24213034Sdougm sa_get_next_property(sa_property_t property) 24223034Sdougm { 24233034Sdougm xmlNodePtr node; 24243034Sdougm 24253034Sdougm for (node = ((xmlNodePtr)property)->next; node != NULL; 24264327Sdougm node = node->next) { 24273034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 24283034Sdougm break; 24293034Sdougm } 24303034Sdougm } 24313034Sdougm return ((sa_property_t)node); 24323034Sdougm } 24333034Sdougm 24343034Sdougm /* 24353034Sdougm * sa_set_share_description(share, content) 24363034Sdougm * 24373034Sdougm * Set the description of share to content. 24383034Sdougm */ 24393034Sdougm 24403034Sdougm int 24413034Sdougm sa_set_share_description(sa_share_t share, char *content) 24423034Sdougm { 24433034Sdougm xmlNodePtr node; 24443034Sdougm sa_group_t group; 24453034Sdougm int ret = SA_OK; 24463034Sdougm 24473034Sdougm for (node = ((xmlNodePtr)share)->children; node != NULL; 24484327Sdougm node = node->next) { 24493034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 24503034Sdougm break; 24513034Sdougm } 24523034Sdougm } 24533034Sdougm /* no existing description but want to add */ 24543034Sdougm if (node == NULL && content != NULL) { 24553034Sdougm /* add a description */ 24564327Sdougm node = _sa_set_share_description(share, content); 24573034Sdougm } else if (node != NULL && content != NULL) { 24583034Sdougm /* update a description */ 24593034Sdougm xmlNodeSetContent(node, (xmlChar *)content); 24603034Sdougm } else if (node != NULL && content == NULL) { 24613034Sdougm /* remove an existing description */ 24623034Sdougm xmlUnlinkNode(node); 24633034Sdougm xmlFreeNode(node); 24643034Sdougm } 24655331Samw group = sa_get_parent_group(share); 24665331Samw if (group != NULL && sa_is_persistent(share)) { 24674327Sdougm sa_handle_impl_t impl_handle; 24684327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 24694327Sdougm if (impl_handle != NULL) { 24704327Sdougm ret = sa_commit_share(impl_handle->scfhandle, group, 24714327Sdougm share); 24724327Sdougm } else { 24734327Sdougm ret = SA_SYSTEM_ERR; 24744327Sdougm } 24753910Sdougm } 24763034Sdougm return (ret); 24773034Sdougm } 24783034Sdougm 24793034Sdougm /* 24803034Sdougm * fixproblemchars(string) 24813034Sdougm * 24823034Sdougm * don't want any newline or tab characters in the text since these 24833034Sdougm * could break display of data and legacy file formats. 24843034Sdougm */ 24853034Sdougm static void 24863034Sdougm fixproblemchars(char *str) 24873034Sdougm { 24883034Sdougm int c; 24893034Sdougm for (c = *str; c != '\0'; c = *++str) { 24904327Sdougm if (c == '\t' || c == '\n') 24914327Sdougm *str = ' '; 24924327Sdougm else if (c == '"') 24934327Sdougm *str = '\''; 24943034Sdougm } 24953034Sdougm } 24963034Sdougm 24973034Sdougm /* 24983034Sdougm * sa_get_share_description(share) 24993034Sdougm * 25003034Sdougm * Return the description text for the specified share if it 25013034Sdougm * exists. NULL if no description exists. 25023034Sdougm */ 25033034Sdougm 25043034Sdougm char * 25053034Sdougm sa_get_share_description(sa_share_t share) 25063034Sdougm { 25073034Sdougm xmlChar *description = NULL; 25083034Sdougm xmlNodePtr node; 25093034Sdougm 25103034Sdougm for (node = ((xmlNodePtr)share)->children; node != NULL; 25114327Sdougm node = node->next) { 25124327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 25134327Sdougm break; 25144327Sdougm } 25153034Sdougm } 25163034Sdougm if (node != NULL) { 25175331Samw description = xmlNodeGetContent(node); 25184327Sdougm fixproblemchars((char *)description); 25193034Sdougm } 25203034Sdougm return ((char *)description); 25213034Sdougm } 25223034Sdougm 25233034Sdougm /* 25243034Sdougm * sa_free(share_description(description) 25253034Sdougm * 25263034Sdougm * Free the description string. 25273034Sdougm */ 25283034Sdougm 25293034Sdougm void 25303034Sdougm sa_free_share_description(char *description) 25313034Sdougm { 25323034Sdougm xmlFree((xmlChar *)description); 25333034Sdougm } 25343034Sdougm 25353034Sdougm /* 25363034Sdougm * sa_create_optionset(group, proto) 25373034Sdougm * 25383034Sdougm * Create an optionset for the specified protocol in the specied 25393034Sdougm * group. This is manifested as a property group within SMF. 25403034Sdougm */ 25413034Sdougm 25423034Sdougm sa_optionset_t 25433034Sdougm sa_create_optionset(sa_group_t group, char *proto) 25443034Sdougm { 25453034Sdougm sa_optionset_t optionset; 25463034Sdougm sa_group_t parent = group; 25475331Samw sa_share_t share = NULL; 25485331Samw int err = SA_OK; 25495331Samw char *id = NULL; 25503034Sdougm 25513034Sdougm optionset = sa_get_optionset(group, proto); 25523034Sdougm if (optionset != NULL) { 25533034Sdougm /* can't have a duplicate protocol */ 25544327Sdougm optionset = NULL; 25553034Sdougm } else { 25565331Samw /* 25575331Samw * Account for resource names being slightly 25585331Samw * different. 25595331Samw */ 25605331Samw if (sa_is_share(group)) { 25615331Samw /* 25625331Samw * Transient shares do not have an "id" so not an 25635331Samw * error to not find one. 25645331Samw */ 25655331Samw id = sa_get_share_attr((sa_share_t)group, "id"); 25665331Samw } else if (sa_is_resource(group)) { 25675331Samw share = sa_get_resource_parent( 25685331Samw (sa_resource_t)group); 25695331Samw id = sa_get_resource_attr(share, "id"); 25705331Samw 25715331Samw /* id can be NULL if the group is transient (ZFS) */ 25725331Samw if (id == NULL && sa_is_persistent(group)) 25735331Samw err = SA_NO_MEMORY; 25745331Samw } 25755331Samw if (err == SA_NO_MEMORY) { 25765331Samw /* 25775331Samw * Couldn't get the id for the share or 25785331Samw * resource. While this could be a 25795331Samw * configuration issue, it is most likely an 25805331Samw * out of memory. In any case, fail the create. 25815331Samw */ 25825331Samw return (NULL); 25835331Samw } 25845331Samw 25854327Sdougm optionset = (sa_optionset_t)xmlNewChild((xmlNodePtr)group, 25864327Sdougm NULL, (xmlChar *)"optionset", NULL); 25873034Sdougm /* 25883034Sdougm * only put to repository if on a group and we were 25893034Sdougm * able to create an optionset. 25903034Sdougm */ 25914327Sdougm if (optionset != NULL) { 25924327Sdougm char oname[SA_STRSIZE]; 25934327Sdougm char *groupname; 25945331Samw 25955331Samw /* 25965331Samw * Need to get parent group in all cases, but also get 25975331Samw * the share if this is a resource. 25985331Samw */ 25995331Samw if (sa_is_share(group)) { 26004327Sdougm parent = sa_get_parent_group((sa_share_t)group); 26015331Samw } else if (sa_is_resource(group)) { 26025331Samw share = sa_get_resource_parent( 26035331Samw (sa_resource_t)group); 26045331Samw parent = sa_get_parent_group(share); 26055331Samw } 26064327Sdougm 26074327Sdougm sa_set_optionset_attr(optionset, "type", proto); 26083034Sdougm 26094327Sdougm (void) sa_optionset_name(optionset, oname, 26104327Sdougm sizeof (oname), id); 26114327Sdougm groupname = sa_get_group_attr(parent, "name"); 26125331Samw if (groupname != NULL && sa_is_persistent(group)) { 26134327Sdougm sa_handle_impl_t impl_handle; 26145331Samw impl_handle = 26155331Samw (sa_handle_impl_t)sa_find_group_handle( 26165331Samw group); 26174327Sdougm assert(impl_handle != NULL); 26184327Sdougm if (impl_handle != NULL) { 26194327Sdougm (void) sa_get_instance( 26205331Samw impl_handle->scfhandle, groupname); 26214327Sdougm (void) sa_create_pgroup( 26224327Sdougm impl_handle->scfhandle, oname); 26234327Sdougm } 26244327Sdougm } 26254327Sdougm if (groupname != NULL) 26264327Sdougm sa_free_attr_string(groupname); 26273034Sdougm } 26283034Sdougm } 26295331Samw 26305331Samw if (id != NULL) 26315331Samw sa_free_attr_string(id); 26323034Sdougm return (optionset); 26333034Sdougm } 26343034Sdougm 26353034Sdougm /* 26363034Sdougm * sa_get_property_parent(property) 26373034Sdougm * 26383034Sdougm * Given a property, return the object it is a property of. This will 26393034Sdougm * be an optionset of some type. 26403034Sdougm */ 26413034Sdougm 26423034Sdougm static sa_optionset_t 26433034Sdougm sa_get_property_parent(sa_property_t property) 26443034Sdougm { 26453034Sdougm xmlNodePtr node = NULL; 26463034Sdougm 26474327Sdougm if (property != NULL) 26484327Sdougm node = ((xmlNodePtr)property)->parent; 26493034Sdougm return ((sa_optionset_t)node); 26503034Sdougm } 26513034Sdougm 26523034Sdougm /* 26533034Sdougm * sa_get_optionset_parent(optionset) 26543034Sdougm * 26553034Sdougm * Return the parent of the specified optionset. This could be a group 26563034Sdougm * or a share. 26573034Sdougm */ 26583034Sdougm 26593034Sdougm static sa_group_t 26603034Sdougm sa_get_optionset_parent(sa_optionset_t optionset) 26613034Sdougm { 26623034Sdougm xmlNodePtr node = NULL; 26633034Sdougm 26644327Sdougm if (optionset != NULL) 26654327Sdougm node = ((xmlNodePtr)optionset)->parent; 26663034Sdougm return ((sa_group_t)node); 26673034Sdougm } 26683034Sdougm 26693034Sdougm /* 26703034Sdougm * zfs_needs_update(share) 26713034Sdougm * 26723034Sdougm * In order to avoid making multiple updates to a ZFS share when 26733034Sdougm * setting properties, the share attribute "changed" will be set to 26745331Samw * true when a property is added or modified. When done adding 26753034Sdougm * properties, we can then detect that an update is needed. We then 26763034Sdougm * clear the state here to detect additional changes. 26773034Sdougm */ 26783034Sdougm 26793034Sdougm static int 26803034Sdougm zfs_needs_update(sa_share_t share) 26813034Sdougm { 26823034Sdougm char *attr; 26833034Sdougm int result = 0; 26843034Sdougm 26853034Sdougm attr = sa_get_share_attr(share, "changed"); 26863034Sdougm if (attr != NULL) { 26874327Sdougm sa_free_attr_string(attr); 26883034Sdougm result = 1; 26893034Sdougm } 26903034Sdougm set_node_attr((void *)share, "changed", NULL); 26913034Sdougm return (result); 26923034Sdougm } 26933034Sdougm 26943034Sdougm /* 26953034Sdougm * zfs_set_update(share) 26963034Sdougm * 26973034Sdougm * Set the changed attribute of the share to true. 26983034Sdougm */ 26993034Sdougm 27003034Sdougm static void 27013034Sdougm zfs_set_update(sa_share_t share) 27023034Sdougm { 27033034Sdougm set_node_attr((void *)share, "changed", "true"); 27043034Sdougm } 27053034Sdougm 27063034Sdougm /* 27073034Sdougm * sa_commit_properties(optionset, clear) 27083034Sdougm * 27093034Sdougm * Check if SMF or ZFS config and either update or abort the pending 27103034Sdougm * changes. 27113034Sdougm */ 27123034Sdougm 27133034Sdougm int 27143034Sdougm sa_commit_properties(sa_optionset_t optionset, int clear) 27153034Sdougm { 27163034Sdougm sa_group_t group; 27173034Sdougm sa_group_t parent; 27183034Sdougm int zfs = 0; 27193034Sdougm int needsupdate = 0; 27203034Sdougm int ret = SA_OK; 27213910Sdougm sa_handle_impl_t impl_handle; 27223034Sdougm 27233034Sdougm group = sa_get_optionset_parent(optionset); 27243034Sdougm if (group != NULL && (sa_is_share(group) || is_zfs_group(group))) { 27254327Sdougm /* only update ZFS if on a share */ 27264327Sdougm parent = sa_get_parent_group(group); 27274327Sdougm zfs++; 27284327Sdougm if (parent != NULL && is_zfs_group(parent)) 27294327Sdougm needsupdate = zfs_needs_update(group); 27304327Sdougm else 27314327Sdougm zfs = 0; 27323034Sdougm } 27333034Sdougm if (zfs) { 27344327Sdougm if (!clear && needsupdate) 27354327Sdougm ret = sa_zfs_update((sa_share_t)group); 27363034Sdougm } else { 27374327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 27384327Sdougm if (impl_handle != NULL) { 27394327Sdougm if (clear) { 27404327Sdougm (void) sa_abort_transaction( 27414327Sdougm impl_handle->scfhandle); 27424327Sdougm } else { 27434327Sdougm ret = sa_end_transaction( 27444327Sdougm impl_handle->scfhandle); 27454327Sdougm } 27464327Sdougm } else { 27474327Sdougm ret = SA_SYSTEM_ERR; 27484327Sdougm } 27493034Sdougm } 27503034Sdougm return (ret); 27513034Sdougm } 27523034Sdougm 27533034Sdougm /* 27543034Sdougm * sa_destroy_optionset(optionset) 27553034Sdougm * 27565331Samw * Remove the optionset from its group. Update the repository to 27573034Sdougm * reflect this change. 27583034Sdougm */ 27593034Sdougm 27603034Sdougm int 27613034Sdougm sa_destroy_optionset(sa_optionset_t optionset) 27623034Sdougm { 27634327Sdougm char name[SA_STRSIZE]; 27643034Sdougm int len; 27653034Sdougm int ret; 27663034Sdougm char *id = NULL; 27673034Sdougm sa_group_t group; 27683034Sdougm int ispersist = 1; 27693034Sdougm 27703034Sdougm /* now delete the prop group */ 27713034Sdougm group = sa_get_optionset_parent(optionset); 27725331Samw if (group != NULL) { 27735331Samw if (sa_is_resource(group)) { 27745331Samw sa_resource_t resource = group; 27755331Samw sa_share_t share = sa_get_resource_parent(resource); 27765331Samw group = sa_get_parent_group(share); 27775331Samw id = sa_get_share_attr(share, "id"); 27785331Samw } else if (sa_is_share(group)) { 27795331Samw id = sa_get_share_attr((sa_share_t)group, "id"); 27805331Samw } 27815331Samw ispersist = sa_is_persistent(group); 27823034Sdougm } 27833034Sdougm if (ispersist) { 27844327Sdougm sa_handle_impl_t impl_handle; 27854327Sdougm len = sa_optionset_name(optionset, name, sizeof (name), id); 27864327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 27874327Sdougm if (impl_handle != NULL) { 27884327Sdougm if (len > 0) { 27894327Sdougm ret = sa_delete_pgroup(impl_handle->scfhandle, 27904327Sdougm name); 27914327Sdougm } 27924327Sdougm } else { 27934327Sdougm ret = SA_SYSTEM_ERR; 27943910Sdougm } 27953034Sdougm } 27963034Sdougm xmlUnlinkNode((xmlNodePtr)optionset); 27973034Sdougm xmlFreeNode((xmlNodePtr)optionset); 27983034Sdougm if (id != NULL) 27994327Sdougm sa_free_attr_string(id); 28003034Sdougm return (ret); 28013034Sdougm } 28023034Sdougm 28033034Sdougm /* private to the implementation */ 28043034Sdougm int 28053034Sdougm _sa_remove_optionset(sa_optionset_t optionset) 28063034Sdougm { 28073034Sdougm int ret = SA_OK; 28083034Sdougm 28093034Sdougm xmlUnlinkNode((xmlNodePtr)optionset); 28103034Sdougm xmlFreeNode((xmlNodePtr)optionset); 28113034Sdougm return (ret); 28123034Sdougm } 28133034Sdougm 28143034Sdougm /* 28153034Sdougm * sa_create_security(group, sectype, proto) 28163034Sdougm * 28173034Sdougm * Create a security optionset (one that has a type name and a 28183034Sdougm * proto). Security is left over from a pure NFS implementation. The 28193034Sdougm * naming will change in the future when the API is released. 28203034Sdougm */ 28213034Sdougm sa_security_t 28223034Sdougm sa_create_security(sa_group_t group, char *sectype, char *proto) 28233034Sdougm { 28243034Sdougm sa_security_t security; 28253034Sdougm char *id = NULL; 28263034Sdougm sa_group_t parent; 28273034Sdougm char *groupname = NULL; 28283034Sdougm 28293034Sdougm if (group != NULL && sa_is_share(group)) { 28304327Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 28314327Sdougm parent = sa_get_parent_group(group); 28324327Sdougm if (parent != NULL) 28334327Sdougm groupname = sa_get_group_attr(parent, "name"); 28343034Sdougm } else if (group != NULL) { 28354327Sdougm groupname = sa_get_group_attr(group, "name"); 28363034Sdougm } 28373034Sdougm 28383034Sdougm security = sa_get_security(group, sectype, proto); 28393034Sdougm if (security != NULL) { 28403034Sdougm /* can't have a duplicate security option */ 28413034Sdougm security = NULL; 28423034Sdougm } else { 28433034Sdougm security = (sa_security_t)xmlNewChild((xmlNodePtr)group, 28444327Sdougm NULL, (xmlChar *)"security", NULL); 28453034Sdougm if (security != NULL) { 28464327Sdougm char oname[SA_STRSIZE]; 28473034Sdougm sa_set_security_attr(security, "type", proto); 28483034Sdougm 28493034Sdougm sa_set_security_attr(security, "sectype", sectype); 28503034Sdougm (void) sa_security_name(security, oname, 28514327Sdougm sizeof (oname), id); 28525331Samw if (groupname != NULL && sa_is_persistent(group)) { 28534327Sdougm sa_handle_impl_t impl_handle; 28544327Sdougm impl_handle = 28554327Sdougm (sa_handle_impl_t)sa_find_group_handle( 28564327Sdougm group); 28574327Sdougm if (impl_handle != NULL) { 28584327Sdougm (void) sa_get_instance( 28594327Sdougm impl_handle->scfhandle, groupname); 28604327Sdougm (void) sa_create_pgroup( 28614327Sdougm impl_handle->scfhandle, oname); 28624327Sdougm } 28633034Sdougm } 28643034Sdougm } 28653034Sdougm } 28663034Sdougm if (groupname != NULL) 28674327Sdougm sa_free_attr_string(groupname); 28683034Sdougm return (security); 28693034Sdougm } 28703034Sdougm 28713034Sdougm /* 28723034Sdougm * sa_destroy_security(security) 28733034Sdougm * 28743034Sdougm * Remove the specified optionset from the document and the 28753034Sdougm * configuration. 28763034Sdougm */ 28773034Sdougm 28783034Sdougm int 28793034Sdougm sa_destroy_security(sa_security_t security) 28803034Sdougm { 28814327Sdougm char name[SA_STRSIZE]; 28823034Sdougm int len; 28833034Sdougm int ret = SA_OK; 28843034Sdougm char *id = NULL; 28853034Sdougm sa_group_t group; 28863034Sdougm int iszfs = 0; 28873034Sdougm int ispersist = 1; 28883034Sdougm 28893034Sdougm group = sa_get_optionset_parent(security); 28903034Sdougm 28913034Sdougm if (group != NULL) 28924327Sdougm iszfs = sa_group_is_zfs(group); 28933034Sdougm 28943034Sdougm if (group != NULL && !iszfs) { 28954327Sdougm if (sa_is_share(group)) 28965331Samw ispersist = sa_is_persistent(group); 28974327Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 28983034Sdougm } 28993034Sdougm if (ispersist) { 29004327Sdougm len = sa_security_name(security, name, sizeof (name), id); 29014327Sdougm if (!iszfs && len > 0) { 29024327Sdougm sa_handle_impl_t impl_handle; 29034327Sdougm impl_handle = 29044327Sdougm (sa_handle_impl_t)sa_find_group_handle(group); 29054327Sdougm if (impl_handle != NULL) { 29064327Sdougm ret = sa_delete_pgroup(impl_handle->scfhandle, 29074327Sdougm name); 29084327Sdougm } else { 29094327Sdougm ret = SA_SYSTEM_ERR; 29104327Sdougm } 29113910Sdougm } 29123034Sdougm } 29133034Sdougm xmlUnlinkNode((xmlNodePtr)security); 29143034Sdougm xmlFreeNode((xmlNodePtr)security); 29154327Sdougm if (iszfs) 29164327Sdougm ret = sa_zfs_update(group); 29173034Sdougm if (id != NULL) 29184327Sdougm sa_free_attr_string(id); 29193034Sdougm return (ret); 29203034Sdougm } 29213034Sdougm 29223034Sdougm /* 29233034Sdougm * sa_get_security_attr(optionset, tag) 29243034Sdougm * 29253034Sdougm * Return the specified attribute value from the optionset. 29263034Sdougm */ 29273034Sdougm 29283034Sdougm char * 29293034Sdougm sa_get_security_attr(sa_property_t optionset, char *tag) 29303034Sdougm { 29313034Sdougm return (get_node_attr((void *)optionset, tag)); 29323034Sdougm 29333034Sdougm } 29343034Sdougm 29353034Sdougm /* 29363034Sdougm * sa_set_security_attr(optionset, tag, value) 29373034Sdougm * 29383034Sdougm * Set the optioset attribute specied by tag to the specified value. 29393034Sdougm */ 29403034Sdougm 29413034Sdougm void 29423034Sdougm sa_set_security_attr(sa_group_t optionset, char *tag, char *value) 29433034Sdougm { 29443034Sdougm set_node_attr((void *)optionset, tag, value); 29453034Sdougm } 29463034Sdougm 29473034Sdougm /* 29483034Sdougm * is_nodetype(node, type) 29493034Sdougm * 29503034Sdougm * Check to see if node is of the type specified. 29513034Sdougm */ 29523034Sdougm 29533034Sdougm static int 29543034Sdougm is_nodetype(void *node, char *type) 29553034Sdougm { 29563034Sdougm return (strcmp((char *)((xmlNodePtr)node)->name, type) == 0); 29573034Sdougm } 29583034Sdougm 29594327Sdougm /* 29604327Sdougm * add_or_update() 29614327Sdougm * 29624327Sdougm * Add or update a property. Pulled out of sa_set_prop_by_prop for 29634327Sdougm * readability. 29644327Sdougm */ 29654327Sdougm static int 29664327Sdougm add_or_update(scfutilhandle_t *scf_handle, int type, scf_value_t *value, 29674327Sdougm scf_transaction_entry_t *entry, char *name, char *valstr) 29684327Sdougm { 29694327Sdougm int ret = SA_SYSTEM_ERR; 29704327Sdougm 29714327Sdougm if (value != NULL) { 29724327Sdougm if (type == SA_PROP_OP_ADD) 29734327Sdougm ret = scf_transaction_property_new(scf_handle->trans, 29744327Sdougm entry, name, SCF_TYPE_ASTRING); 29754327Sdougm else 29764327Sdougm ret = scf_transaction_property_change(scf_handle->trans, 29774327Sdougm entry, name, SCF_TYPE_ASTRING); 29784327Sdougm if (ret == 0) { 29794327Sdougm ret = scf_value_set_astring(value, valstr); 29804327Sdougm if (ret == 0) 29814327Sdougm ret = scf_entry_add_value(entry, value); 29824327Sdougm if (ret == 0) 29834327Sdougm return (ret); 29844327Sdougm scf_value_destroy(value); 29854327Sdougm } else { 29864327Sdougm scf_entry_destroy(entry); 29874327Sdougm } 29884327Sdougm } 29894327Sdougm return (SA_SYSTEM_ERR); 29904327Sdougm } 29914327Sdougm 29923034Sdougm /* 29933034Sdougm * sa_set_prop_by_prop(optionset, group, prop, type) 29943034Sdougm * 29953034Sdougm * Add/remove/update the specified property prop into the optionset or 29963034Sdougm * share. If a share, sort out which property group based on GUID. In 29973034Sdougm * all cases, the appropriate transaction is set (or ZFS share is 29983034Sdougm * marked as needing an update) 29993034Sdougm */ 30003034Sdougm 30013034Sdougm static int 30023034Sdougm sa_set_prop_by_prop(sa_optionset_t optionset, sa_group_t group, 30033034Sdougm sa_property_t prop, int type) 30043034Sdougm { 30053034Sdougm char *name; 30063034Sdougm char *valstr; 30073034Sdougm int ret = SA_OK; 30083034Sdougm scf_transaction_entry_t *entry; 30093034Sdougm scf_value_t *value; 30103034Sdougm int opttype; /* 1 == optionset, 0 == security */ 30113034Sdougm char *id = NULL; 30123034Sdougm int iszfs = 0; 30133034Sdougm sa_group_t parent = NULL; 30145331Samw sa_share_t share = NULL; 30153910Sdougm sa_handle_impl_t impl_handle; 30163910Sdougm scfutilhandle_t *scf_handle; 30173034Sdougm 30185331Samw if (!sa_is_persistent(group)) { 30193034Sdougm /* 30203034Sdougm * if the group/share is not persistent we don't need 30213034Sdougm * to do anything here 30223034Sdougm */ 30234327Sdougm return (SA_OK); 30243034Sdougm } 30253910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 30264327Sdougm if (impl_handle == NULL || impl_handle->scfhandle == NULL) 30274327Sdougm return (SA_SYSTEM_ERR); 30283910Sdougm scf_handle = impl_handle->scfhandle; 30293034Sdougm name = sa_get_property_attr(prop, "type"); 30303034Sdougm valstr = sa_get_property_attr(prop, "value"); 30313034Sdougm entry = scf_entry_create(scf_handle->handle); 30323034Sdougm opttype = is_nodetype((void *)optionset, "optionset"); 30333034Sdougm 30345331Samw /* 30355331Samw * Check for share vs. resource since they need slightly 30365331Samw * different treatment given the hierarchy. 30375331Samw */ 30383034Sdougm if (valstr != NULL && entry != NULL) { 30394327Sdougm if (sa_is_share(group)) { 30404327Sdougm parent = sa_get_parent_group(group); 30415331Samw share = (sa_share_t)group; 30424327Sdougm if (parent != NULL) 30434327Sdougm iszfs = is_zfs_group(parent); 30445331Samw } else if (sa_is_resource(group)) { 30455331Samw share = sa_get_parent_group(group); 30465331Samw if (share != NULL) 30475331Samw parent = sa_get_parent_group(share); 30484327Sdougm } else { 30494327Sdougm iszfs = is_zfs_group(group); 30503034Sdougm } 30514327Sdougm if (!iszfs) { 30524327Sdougm if (scf_handle->trans == NULL) { 30534327Sdougm char oname[SA_STRSIZE]; 30544327Sdougm char *groupname = NULL; 30555331Samw if (share != NULL) { 30565331Samw if (parent != NULL) 30574327Sdougm groupname = 30584327Sdougm sa_get_group_attr(parent, 30594327Sdougm "name"); 30605331Samw id = sa_get_share_attr( 30615331Samw (sa_share_t)share, "id"); 30624327Sdougm } else { 30634327Sdougm groupname = sa_get_group_attr(group, 30644327Sdougm "name"); 30654327Sdougm } 30664327Sdougm if (groupname != NULL) { 30674327Sdougm ret = sa_get_instance(scf_handle, 30684327Sdougm groupname); 30694327Sdougm sa_free_attr_string(groupname); 30704327Sdougm } 30714327Sdougm if (opttype) 30724327Sdougm (void) sa_optionset_name(optionset, 30734327Sdougm oname, sizeof (oname), id); 30744327Sdougm else 30754327Sdougm (void) sa_security_name(optionset, 30764327Sdougm oname, sizeof (oname), id); 30774327Sdougm ret = sa_start_transaction(scf_handle, oname); 30783910Sdougm } 30794327Sdougm if (ret == SA_OK) { 30804327Sdougm switch (type) { 30814327Sdougm case SA_PROP_OP_REMOVE: 30824327Sdougm ret = scf_transaction_property_delete( 30834327Sdougm scf_handle->trans, entry, name); 30844327Sdougm break; 30854327Sdougm case SA_PROP_OP_ADD: 30864327Sdougm case SA_PROP_OP_UPDATE: 30874327Sdougm value = scf_value_create( 30884327Sdougm scf_handle->handle); 30894327Sdougm ret = add_or_update(scf_handle, type, 30904327Sdougm value, entry, name, valstr); 30914327Sdougm break; 30923034Sdougm } 30933034Sdougm } 30944327Sdougm } else { 30954327Sdougm /* 30964327Sdougm * ZFS update. The calling function would have updated 30974327Sdougm * the internal XML structure. Just need to flag it as 30984327Sdougm * changed for ZFS. 30994327Sdougm */ 31004327Sdougm zfs_set_update((sa_share_t)group); 31014327Sdougm } 31023034Sdougm } 31033034Sdougm 31043034Sdougm if (name != NULL) 31054327Sdougm sa_free_attr_string(name); 31063034Sdougm if (valstr != NULL) 31074327Sdougm sa_free_attr_string(valstr); 31083034Sdougm else if (entry != NULL) 31094327Sdougm scf_entry_destroy(entry); 31103034Sdougm 31113034Sdougm if (ret == -1) 31124327Sdougm ret = SA_SYSTEM_ERR; 31133034Sdougm 31143034Sdougm return (ret); 31153034Sdougm } 31163034Sdougm 31173034Sdougm /* 31183034Sdougm * sa_create_property(name, value) 31193034Sdougm * 31203034Sdougm * Create a new property with the specified name and value. 31213034Sdougm */ 31223034Sdougm 31233034Sdougm sa_property_t 31243034Sdougm sa_create_property(char *name, char *value) 31253034Sdougm { 31263034Sdougm xmlNodePtr node; 31273034Sdougm 31283034Sdougm node = xmlNewNode(NULL, (xmlChar *)"option"); 31293034Sdougm if (node != NULL) { 31303034Sdougm xmlSetProp(node, (xmlChar *)"type", (xmlChar *)name); 31313034Sdougm xmlSetProp(node, (xmlChar *)"value", (xmlChar *)value); 31323034Sdougm } 31333034Sdougm return ((sa_property_t)node); 31343034Sdougm } 31353034Sdougm 31363034Sdougm /* 31373034Sdougm * sa_add_property(object, property) 31383034Sdougm * 31393034Sdougm * Add the specified property to the object. Issue the appropriate 31403034Sdougm * transaction or mark a ZFS object as needing an update. 31413034Sdougm */ 31423034Sdougm 31433034Sdougm int 31443034Sdougm sa_add_property(void *object, sa_property_t property) 31453034Sdougm { 31463034Sdougm int ret = SA_OK; 31473034Sdougm sa_group_t parent; 31483034Sdougm sa_group_t group; 31493034Sdougm char *proto; 31503034Sdougm 31513034Sdougm proto = sa_get_optionset_attr(object, "type"); 31523034Sdougm if (property != NULL) { 31534327Sdougm if ((ret = sa_valid_property(object, proto, property)) == 31544327Sdougm SA_OK) { 31554327Sdougm property = (sa_property_t)xmlAddChild( 31564327Sdougm (xmlNodePtr)object, (xmlNodePtr)property); 31574327Sdougm } else { 31584327Sdougm if (proto != NULL) 31594327Sdougm sa_free_attr_string(proto); 31604327Sdougm return (ret); 31614327Sdougm } 31623034Sdougm } 31633034Sdougm 31643034Sdougm if (proto != NULL) 31654327Sdougm sa_free_attr_string(proto); 31663034Sdougm 31673034Sdougm parent = sa_get_parent_group(object); 31685331Samw if (!sa_is_persistent(parent)) 31694327Sdougm return (ret); 31705331Samw 31715331Samw if (sa_is_resource(parent)) { 31725331Samw /* 31735331Samw * Resources are children of share. Need to go up two 31745331Samw * levels to find the group but the parent needs to be 31755331Samw * the share at this point in order to get the "id". 31765331Samw */ 31775331Samw parent = sa_get_parent_group(parent); 31785331Samw group = sa_get_parent_group(parent); 31795331Samw } else if (sa_is_share(parent)) { 31805331Samw group = sa_get_parent_group(parent); 31815331Samw } else { 31825331Samw group = parent; 31833034Sdougm } 31843034Sdougm 31854327Sdougm if (property == NULL) { 31864327Sdougm ret = SA_NO_MEMORY; 31874327Sdougm } else { 31884327Sdougm char oname[SA_STRSIZE]; 31893034Sdougm 31904327Sdougm if (!is_zfs_group(group)) { 31914327Sdougm char *id = NULL; 31924327Sdougm sa_handle_impl_t impl_handle; 31934327Sdougm scfutilhandle_t *scf_handle; 31943910Sdougm 31954327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle( 31964327Sdougm group); 31974327Sdougm if (impl_handle == NULL || 31984327Sdougm impl_handle->scfhandle == NULL) 31994327Sdougm ret = SA_SYSTEM_ERR; 32004327Sdougm if (ret == SA_OK) { 32014327Sdougm scf_handle = impl_handle->scfhandle; 32024327Sdougm if (sa_is_share((sa_group_t)parent)) { 32034327Sdougm id = sa_get_share_attr( 32044327Sdougm (sa_share_t)parent, "id"); 32054327Sdougm } 32064327Sdougm if (scf_handle->trans == NULL) { 32074327Sdougm if (is_nodetype(object, "optionset")) { 32084327Sdougm (void) sa_optionset_name( 32094327Sdougm (sa_optionset_t)object, 32104327Sdougm oname, sizeof (oname), id); 32114327Sdougm } else { 32124327Sdougm (void) sa_security_name( 32134327Sdougm (sa_optionset_t)object, 32144327Sdougm oname, sizeof (oname), id); 32154327Sdougm } 32164327Sdougm ret = sa_start_transaction(scf_handle, 32174327Sdougm oname); 32184327Sdougm } 32194327Sdougm if (ret == SA_OK) { 32204327Sdougm char *name; 32214327Sdougm char *value; 32224327Sdougm name = sa_get_property_attr(property, 32234327Sdougm "type"); 32244327Sdougm value = sa_get_property_attr(property, 32254327Sdougm "value"); 32264327Sdougm if (name != NULL && value != NULL) { 32274327Sdougm if (scf_handle->scf_state == 32284327Sdougm SCH_STATE_INIT) { 32294327Sdougm ret = sa_set_property( 32304327Sdougm scf_handle, name, 32314327Sdougm value); 32324327Sdougm } 32334327Sdougm } else { 32344327Sdougm ret = SA_CONFIG_ERR; 32354327Sdougm } 32364327Sdougm if (name != NULL) 32374327Sdougm sa_free_attr_string( 32384327Sdougm name); 32394327Sdougm if (value != NULL) 32404327Sdougm sa_free_attr_string(value); 32414327Sdougm } 32424327Sdougm if (id != NULL) 32434327Sdougm sa_free_attr_string(id); 32444327Sdougm } 32454327Sdougm } else { 32464327Sdougm /* 32474327Sdougm * ZFS is a special case. We do want 32484327Sdougm * to allow editing property/security 32494327Sdougm * lists since we can have a better 32504327Sdougm * syntax and we also want to keep 32514327Sdougm * things consistent when possible. 32524327Sdougm * 32534327Sdougm * Right now, we defer until the 32544327Sdougm * sa_commit_properties so we can get 32554327Sdougm * them all at once. We do need to 32564327Sdougm * mark the share as "changed" 32574327Sdougm */ 32584327Sdougm zfs_set_update((sa_share_t)parent); 32593034Sdougm } 32603034Sdougm } 32613034Sdougm return (ret); 32623034Sdougm } 32633034Sdougm 32643034Sdougm /* 32653034Sdougm * sa_remove_property(property) 32663034Sdougm * 32673034Sdougm * Remove the specied property from its containing object. Update the 32683034Sdougm * repository as appropriate. 32693034Sdougm */ 32703034Sdougm 32713034Sdougm int 32723034Sdougm sa_remove_property(sa_property_t property) 32733034Sdougm { 32743034Sdougm int ret = SA_OK; 32753034Sdougm 32763034Sdougm if (property != NULL) { 32773034Sdougm sa_optionset_t optionset; 32783034Sdougm sa_group_t group; 32793034Sdougm optionset = sa_get_property_parent(property); 32803034Sdougm if (optionset != NULL) { 32814327Sdougm group = sa_get_optionset_parent(optionset); 32824327Sdougm if (group != NULL) { 32834327Sdougm ret = sa_set_prop_by_prop(optionset, group, 32844327Sdougm property, SA_PROP_OP_REMOVE); 32854327Sdougm } 32863034Sdougm } 32873034Sdougm xmlUnlinkNode((xmlNodePtr)property); 32883034Sdougm xmlFreeNode((xmlNodePtr)property); 32893034Sdougm } else { 32904327Sdougm ret = SA_NO_SUCH_PROP; 32913034Sdougm } 32923034Sdougm return (ret); 32933034Sdougm } 32943034Sdougm 32953034Sdougm /* 32963034Sdougm * sa_update_property(property, value) 32973034Sdougm * 32983034Sdougm * Update the specified property to the new value. If value is NULL, 32993034Sdougm * we currently treat this as a remove. 33003034Sdougm */ 33013034Sdougm 33023034Sdougm int 33033034Sdougm sa_update_property(sa_property_t property, char *value) 33043034Sdougm { 33053034Sdougm int ret = SA_OK; 33063034Sdougm if (value == NULL) { 33073034Sdougm return (sa_remove_property(property)); 33083034Sdougm } else { 33093034Sdougm sa_optionset_t optionset; 33103034Sdougm sa_group_t group; 33113034Sdougm set_node_attr((void *)property, "value", value); 33123034Sdougm optionset = sa_get_property_parent(property); 33133034Sdougm if (optionset != NULL) { 33144327Sdougm group = sa_get_optionset_parent(optionset); 33154327Sdougm if (group != NULL) { 33164327Sdougm ret = sa_set_prop_by_prop(optionset, group, 33174327Sdougm property, SA_PROP_OP_UPDATE); 33184327Sdougm } 33193034Sdougm } else { 33204327Sdougm ret = SA_NO_SUCH_PROP; 33213034Sdougm } 33223034Sdougm } 33233034Sdougm return (ret); 33243034Sdougm } 33253034Sdougm 33263034Sdougm /* 33273034Sdougm * sa_get_protocol_property(propset, prop) 33283034Sdougm * 33293034Sdougm * Get the specified protocol specific property. These are global to 33303034Sdougm * the protocol and not specific to a group or share. 33313034Sdougm */ 33323034Sdougm 33333034Sdougm sa_property_t 33343034Sdougm sa_get_protocol_property(sa_protocol_properties_t propset, char *prop) 33353034Sdougm { 33363034Sdougm xmlNodePtr node = (xmlNodePtr)propset; 33373034Sdougm xmlChar *value = NULL; 33383034Sdougm 33393034Sdougm for (node = node->children; node != NULL; 33404327Sdougm node = node->next) { 33414327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 33424327Sdougm if (prop == NULL) 33434327Sdougm break; 33444327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 33454327Sdougm if (value != NULL && 33464327Sdougm xmlStrcasecmp(value, (xmlChar *)prop) == 0) { 33474327Sdougm break; 33484327Sdougm } 33494327Sdougm if (value != NULL) { 33504327Sdougm xmlFree(value); 33514327Sdougm value = NULL; 33524327Sdougm } 33533034Sdougm } 33543034Sdougm } 33553034Sdougm if (value != NULL) 33563034Sdougm xmlFree(value); 33573034Sdougm if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"option") != 0) { 33584327Sdougm /* 33594327Sdougm * avoid a non option node -- it is possible to be a 33604327Sdougm * text node 33614327Sdougm */ 33624327Sdougm node = NULL; 33633034Sdougm } 33643034Sdougm return ((sa_property_t)node); 33653034Sdougm } 33663034Sdougm 33673034Sdougm /* 33683034Sdougm * sa_get_next_protocol_property(prop) 33693034Sdougm * 33703034Sdougm * Get the next protocol specific property in the list. 33713034Sdougm */ 33723034Sdougm 33733034Sdougm sa_property_t 33743034Sdougm sa_get_next_protocol_property(sa_property_t prop) 33753034Sdougm { 33763034Sdougm xmlNodePtr node; 33773034Sdougm 33783034Sdougm for (node = ((xmlNodePtr)prop)->next; node != NULL; 33794327Sdougm node = node->next) { 33803034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 33813034Sdougm break; 33823034Sdougm } 33833034Sdougm } 33843034Sdougm return ((sa_property_t)node); 33853034Sdougm } 33863034Sdougm 33873034Sdougm /* 33883034Sdougm * sa_set_protocol_property(prop, value) 33893034Sdougm * 33903034Sdougm * Set the specified property to have the new value. The protocol 33913034Sdougm * specific plugin will then be called to update the property. 33923034Sdougm */ 33933034Sdougm 33943034Sdougm int 33953034Sdougm sa_set_protocol_property(sa_property_t prop, char *value) 33963034Sdougm { 33973034Sdougm sa_protocol_properties_t propset; 33983034Sdougm char *proto; 33993034Sdougm int ret = SA_INVALID_PROTOCOL; 34003034Sdougm 34013034Sdougm propset = ((xmlNodePtr)prop)->parent; 34023034Sdougm if (propset != NULL) { 34034327Sdougm proto = sa_get_optionset_attr(propset, "type"); 34044327Sdougm if (proto != NULL) { 34054327Sdougm set_node_attr((xmlNodePtr)prop, "value", value); 34064327Sdougm ret = sa_proto_set_property(proto, prop); 34074327Sdougm sa_free_attr_string(proto); 34084327Sdougm } 34093034Sdougm } 34103034Sdougm return (ret); 34113034Sdougm } 34123034Sdougm 34133034Sdougm /* 34143034Sdougm * sa_add_protocol_property(propset, prop) 34153034Sdougm * 34165331Samw * Add a new property to the protocol specific property set. 34173034Sdougm */ 34183034Sdougm 34193034Sdougm int 34203034Sdougm sa_add_protocol_property(sa_protocol_properties_t propset, sa_property_t prop) 34213034Sdougm { 34223034Sdougm xmlNodePtr node; 34233034Sdougm 34243034Sdougm /* should check for legitimacy */ 34253034Sdougm node = xmlAddChild((xmlNodePtr)propset, (xmlNodePtr)prop); 34263034Sdougm if (node != NULL) 34274327Sdougm return (SA_OK); 34283034Sdougm return (SA_NO_MEMORY); 34293034Sdougm } 34303034Sdougm 34313034Sdougm /* 34323034Sdougm * sa_create_protocol_properties(proto) 34333034Sdougm * 34345331Samw * Create a protocol specific property set. 34353034Sdougm */ 34363034Sdougm 34373034Sdougm sa_protocol_properties_t 34383034Sdougm sa_create_protocol_properties(char *proto) 34393034Sdougm { 34403034Sdougm xmlNodePtr node; 34414327Sdougm 34423034Sdougm node = xmlNewNode(NULL, (xmlChar *)"propertyset"); 34434327Sdougm if (node != NULL) 34444327Sdougm xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto); 34453034Sdougm return (node); 34463034Sdougm } 34475331Samw 34485331Samw /* 34495331Samw * sa_get_share_resource(share, resource) 34505331Samw * 34515331Samw * Get the named resource from the share, if it exists. If resource is 34525331Samw * NULL, get the first resource. 34535331Samw */ 34545331Samw 34555331Samw sa_resource_t 34565331Samw sa_get_share_resource(sa_share_t share, char *resource) 34575331Samw { 34585331Samw xmlNodePtr node = NULL; 34595331Samw xmlChar *name; 34605331Samw 34615331Samw if (share != NULL) { 34625331Samw for (node = ((xmlNodePtr)share)->children; node != NULL; 34635331Samw node = node->next) { 34645331Samw if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0) { 34655331Samw if (resource == NULL) { 34665331Samw /* 34675331Samw * We are looking for the first 34685331Samw * resource node and not a names 34695331Samw * resource. 34705331Samw */ 34715331Samw break; 34725331Samw } else { 34735331Samw /* is it the correct share? */ 34745331Samw name = xmlGetProp(node, 34755331Samw (xmlChar *)"name"); 34765331Samw if (name != NULL && 34775331Samw xmlStrcasecmp(name, 34785331Samw (xmlChar *)resource) == 0) { 34795331Samw xmlFree(name); 34805331Samw break; 34815331Samw } 34825331Samw xmlFree(name); 34835331Samw } 34845331Samw } 34855331Samw } 34865331Samw } 34875331Samw return ((sa_resource_t)node); 34885331Samw } 34895331Samw 34905331Samw /* 34915331Samw * sa_get_next_resource(resource) 34925331Samw * Return the next share following the specified share 34935331Samw * from the internal list of shares. Returns NULL if there 34945331Samw * are no more shares. The list is relative to the same 34955331Samw * group. 34965331Samw */ 34975331Samw sa_share_t 34985331Samw sa_get_next_resource(sa_resource_t resource) 34995331Samw { 35005331Samw xmlNodePtr node = NULL; 35015331Samw 35025331Samw if (resource != NULL) { 35035331Samw for (node = ((xmlNodePtr)resource)->next; node != NULL; 35045331Samw node = node->next) { 35055331Samw if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0) 35065331Samw break; 35075331Samw } 35085331Samw } 35095331Samw return ((sa_share_t)node); 35105331Samw } 35115331Samw 35125331Samw /* 35135331Samw * _sa_get_next_resource_index(share) 35145331Samw * 35155331Samw * get the next resource index number (one greater then current largest) 35165331Samw */ 35175331Samw 35185331Samw static int 35195331Samw _sa_get_next_resource_index(sa_share_t share) 35205331Samw { 35215331Samw sa_resource_t resource; 35225331Samw int index = 0; 35235331Samw char *id; 35245331Samw 35255331Samw for (resource = sa_get_share_resource(share, NULL); 35265331Samw resource != NULL; 35275331Samw resource = sa_get_next_resource(resource)) { 35285331Samw id = get_node_attr((void *)resource, "id"); 35295331Samw if (id != NULL) { 35305331Samw int val; 35315331Samw val = atoi(id); 35325331Samw if (val > index) 35335331Samw index = val; 35345331Samw sa_free_attr_string(id); 35355331Samw } 35365331Samw } 35375331Samw return (index + 1); 35385331Samw } 35395331Samw 35405331Samw 35415331Samw /* 35425331Samw * sa_add_resource(share, resource, persist, &err) 35435331Samw * 35445331Samw * Adds a new resource name associated with share. The resource name 35455331Samw * must be unique in the system and will be case insensitive (eventually). 35465331Samw */ 35475331Samw 35485331Samw sa_resource_t 35495331Samw sa_add_resource(sa_share_t share, char *resource, int persist, int *error) 35505331Samw { 35515331Samw xmlNodePtr node; 35525331Samw int err = SA_OK; 35535331Samw sa_resource_t res; 35545331Samw sa_group_t group; 35555331Samw sa_handle_t handle; 35565331Samw char istring[8]; /* just big enough for an integer value */ 35575331Samw int index; 35585331Samw 35595331Samw group = sa_get_parent_group(share); 35605331Samw handle = sa_find_group_handle(group); 35615331Samw res = sa_find_resource(handle, resource); 35625331Samw if (res != NULL) { 35635331Samw err = SA_DUPLICATE_NAME; 35645331Samw res = NULL; 35655331Samw } else { 35665331Samw node = xmlNewChild((xmlNodePtr)share, NULL, 35675331Samw (xmlChar *)"resource", NULL); 35685331Samw if (node != NULL) { 35695331Samw xmlSetProp(node, (xmlChar *)"name", 35705331Samw (xmlChar *)resource); 35715331Samw xmlSetProp(node, (xmlChar *)"type", persist ? 35725331Samw (xmlChar *)"persist" : (xmlChar *)"transient"); 35735331Samw if (persist != SA_SHARE_TRANSIENT) { 35745331Samw index = _sa_get_next_resource_index(share); 35755331Samw (void) snprintf(istring, sizeof (istring), "%d", 35765331Samw index); 35775331Samw xmlSetProp(node, (xmlChar *)"id", 35785331Samw (xmlChar *)istring); 35795331Samw if (!sa_group_is_zfs(group) && 35805331Samw sa_is_persistent((sa_group_t)share)) { 35815331Samw /* ZFS doesn't use resource names */ 35825331Samw sa_handle_impl_t ihandle; 35835331Samw ihandle = (sa_handle_impl_t) 35845331Samw sa_find_group_handle( 35855331Samw group); 35865331Samw if (ihandle != NULL) 35875331Samw err = sa_commit_share( 35885331Samw ihandle->scfhandle, group, 35895331Samw share); 35905331Samw else 35915331Samw err = SA_SYSTEM_ERR; 35925331Samw } 35935331Samw } 35945331Samw } 35955331Samw } 35965331Samw if (error != NULL) 35975331Samw *error = err; 35985331Samw return ((sa_resource_t)node); 35995331Samw } 36005331Samw 36015331Samw /* 36025331Samw * sa_remove_resource(resource) 36035331Samw * 36045331Samw * Remove the resource name from the share (and the system) 36055331Samw */ 36065331Samw 36075331Samw int 36085331Samw sa_remove_resource(sa_resource_t resource) 36095331Samw { 36105331Samw sa_share_t share; 36115331Samw sa_group_t group; 36125331Samw char *type; 36135331Samw int ret = SA_OK; 36145331Samw int transient = 0; 3615*5521Sas200622 sa_optionset_t opt; 36165331Samw 36175331Samw share = sa_get_resource_parent(resource); 36185331Samw type = sa_get_share_attr(share, "type"); 36195331Samw group = sa_get_parent_group(share); 36205331Samw 36215331Samw 36225331Samw if (type != NULL) { 36235331Samw if (strcmp(type, "persist") != 0) 36245331Samw transient = 1; 36255331Samw sa_free_attr_string(type); 36265331Samw } 36275331Samw 3628*5521Sas200622 /* Disable the resource for all protocols. */ 3629*5521Sas200622 (void) sa_disable_resource(resource, NULL); 3630*5521Sas200622 3631*5521Sas200622 /* Remove any optionsets from the resource. */ 3632*5521Sas200622 for (opt = sa_get_optionset(resource, NULL); 3633*5521Sas200622 opt != NULL; 3634*5521Sas200622 opt = sa_get_next_optionset(opt)) 3635*5521Sas200622 (void) sa_destroy_optionset(opt); 3636*5521Sas200622 36375331Samw /* Remove from the share */ 36385331Samw xmlUnlinkNode((xmlNode *)resource); 36395331Samw xmlFreeNode((xmlNode *)resource); 36405331Samw 36415331Samw /* only do SMF action if permanent and not ZFS */ 36425331Samw if (!transient && !sa_group_is_zfs(group)) { 36435331Samw sa_handle_impl_t ihandle; 36445331Samw ihandle = (sa_handle_impl_t)sa_find_group_handle(group); 36455331Samw if (ihandle != NULL) 36465331Samw ret = sa_commit_share(ihandle->scfhandle, group, share); 36475331Samw else 36485331Samw ret = SA_SYSTEM_ERR; 36495331Samw } 36505331Samw return (ret); 36515331Samw } 36525331Samw 36535331Samw /* 36545331Samw * proto_resource_rename(handle, group, resource, newname) 36555331Samw * 36565331Samw * Helper function for sa_rename_resource that notifies the protocol 36575331Samw * of a resource name change prior to a config repository update. 36585331Samw */ 36595331Samw static int 36605331Samw proto_rename_resource(sa_handle_t handle, sa_group_t group, 36615331Samw sa_resource_t resource, char *newname) 36625331Samw { 36635331Samw sa_optionset_t optionset; 36645331Samw int ret = SA_OK; 36655331Samw int err; 36665331Samw 36675331Samw for (optionset = sa_get_optionset(group, NULL); 36685331Samw optionset != NULL; 36695331Samw optionset = sa_get_next_optionset(optionset)) { 36705331Samw char *type; 36715331Samw type = sa_get_optionset_attr(optionset, "type"); 36725331Samw if (type != NULL) { 36735331Samw err = sa_proto_rename_resource(handle, type, resource, 36745331Samw newname); 36755331Samw if (err != SA_OK) 36765331Samw ret = err; 36775331Samw sa_free_attr_string(type); 36785331Samw } 36795331Samw } 36805331Samw return (ret); 36815331Samw } 36825331Samw 36835331Samw /* 36845331Samw * sa_rename_resource(resource, newname) 36855331Samw * 36865331Samw * Rename the resource to the new name, if it is unique. 36875331Samw */ 36885331Samw 36895331Samw int 36905331Samw sa_rename_resource(sa_resource_t resource, char *newname) 36915331Samw { 36925331Samw sa_share_t share; 36935331Samw sa_group_t group = NULL; 36945331Samw sa_resource_t target; 36955331Samw int ret = SA_CONFIG_ERR; 36965331Samw sa_handle_t handle = NULL; 36975331Samw 36985331Samw share = sa_get_resource_parent(resource); 36995331Samw if (share == NULL) 37005331Samw return (ret); 37015331Samw 37025331Samw group = sa_get_parent_group(share); 37035331Samw if (group == NULL) 37045331Samw return (ret); 37055331Samw 37065331Samw handle = (sa_handle_impl_t)sa_find_group_handle(group); 37075331Samw if (handle == NULL) 37085331Samw return (ret); 37095331Samw 37105331Samw target = sa_find_resource(handle, newname); 37115331Samw if (target != NULL) { 37125331Samw ret = SA_DUPLICATE_NAME; 37135331Samw } else { 37145331Samw /* 37155331Samw * Everything appears to be valid at this 37165331Samw * point. Change the name of the active share and then 37175331Samw * update the share in the appropriate repository. 37185331Samw */ 37195331Samw ret = proto_rename_resource(handle, group, resource, newname); 37205331Samw set_node_attr(resource, "name", newname); 37215331Samw if (!sa_group_is_zfs(group) && 37225331Samw sa_is_persistent((sa_group_t)share)) { 37235331Samw sa_handle_impl_t ihandle = (sa_handle_impl_t)handle; 37245331Samw ret = sa_commit_share(ihandle->scfhandle, group, 37255331Samw share); 37265331Samw } 37275331Samw } 37285331Samw return (ret); 37295331Samw } 37305331Samw 37315331Samw /* 37325331Samw * sa_get_resource_attr(resource, tag) 37335331Samw * 37345331Samw * Get the named attribute of the resource. "name" and "id" are 37355331Samw * currently defined. NULL if tag not defined. 37365331Samw */ 37375331Samw 37385331Samw char * 37395331Samw sa_get_resource_attr(sa_resource_t resource, char *tag) 37405331Samw { 37415331Samw return (get_node_attr((void *)resource, tag)); 37425331Samw } 37435331Samw 37445331Samw /* 37455331Samw * sa_set_resource_attr(resource, tag, value) 37465331Samw * 37475331Samw * Get the named attribute of the resource. "name" and "id" are 37485331Samw * currently defined. NULL if tag not defined. Currently we don't do 37495331Samw * much, but additional checking may be needed in the future. 37505331Samw */ 37515331Samw 37525331Samw int 37535331Samw sa_set_resource_attr(sa_resource_t resource, char *tag, char *value) 37545331Samw { 37555331Samw set_node_attr((void *)resource, tag, value); 37565331Samw return (SA_OK); 37575331Samw } 37585331Samw 37595331Samw /* 37605331Samw * sa_get_resource_parent(resource_t) 37615331Samw * 37625331Samw * Returns the share associated with the resource. 37635331Samw */ 37645331Samw 37655331Samw sa_share_t 37665331Samw sa_get_resource_parent(sa_resource_t resource) 37675331Samw { 37685331Samw sa_share_t share = NULL; 37695331Samw 37705331Samw if (resource != NULL) 37715331Samw share = (sa_share_t)((xmlNodePtr)resource)->parent; 37725331Samw return (share); 37735331Samw } 37745331Samw 37755331Samw /* 37765331Samw * find_resource(group, name) 37775331Samw * 37785331Samw * Find the resource within the group. 37795331Samw */ 37805331Samw 37815331Samw static sa_resource_t 37825331Samw find_resource(sa_group_t group, char *resname) 37835331Samw { 37845331Samw sa_share_t share; 37855331Samw sa_resource_t resource = NULL; 37865331Samw char *name; 37875331Samw 37885331Samw /* Iterate over all the shares and resources in the group. */ 37895331Samw for (share = sa_get_share(group, NULL); 37905331Samw share != NULL && resource == NULL; 37915331Samw share = sa_get_next_share(share)) { 37925331Samw for (resource = sa_get_share_resource(share, NULL); 37935331Samw resource != NULL; 37945331Samw resource = sa_get_next_resource(resource)) { 37955331Samw name = sa_get_resource_attr(resource, "name"); 37965331Samw if (name != NULL && xmlStrcasecmp((xmlChar*)name, 37975331Samw (xmlChar*)resname) == 0) { 37985331Samw sa_free_attr_string(name); 37995331Samw break; 38005331Samw } 38015331Samw if (name != NULL) { 38025331Samw sa_free_attr_string(name); 38035331Samw } 38045331Samw } 38055331Samw } 38065331Samw return (resource); 38075331Samw } 38085331Samw 38095331Samw /* 38105331Samw * sa_find_resource(name) 38115331Samw * 38125331Samw * Find the named resource in the system. 38135331Samw */ 38145331Samw 38155331Samw sa_resource_t 38165331Samw sa_find_resource(sa_handle_t handle, char *name) 38175331Samw { 38185331Samw sa_group_t group; 38195331Samw sa_group_t zgroup; 38205331Samw sa_resource_t resource = NULL; 38215331Samw 38225331Samw /* 38235331Samw * Iterate over all groups and zfs subgroups and check for 38245331Samw * resource name in them. 38255331Samw */ 38265331Samw for (group = sa_get_group(handle, NULL); group != NULL; 38275331Samw group = sa_get_next_group(group)) { 38285331Samw 38295331Samw if (is_zfs_group(group)) { 38305331Samw for (zgroup = 38315331Samw (sa_group_t)_sa_get_child_node((xmlNodePtr)group, 38325331Samw (xmlChar *)"group"); 38335331Samw zgroup != NULL && resource == NULL; 38345331Samw zgroup = sa_get_next_group(zgroup)) { 38355331Samw resource = find_resource(zgroup, name); 38365331Samw } 38375331Samw } else { 38385331Samw resource = find_resource(group, name); 38395331Samw } 38405331Samw if (resource != NULL) 38415331Samw break; 38425331Samw } 38435331Samw return (resource); 38445331Samw } 38455331Samw 38465331Samw /* 38475331Samw * sa_get_resource(group, resource) 38485331Samw * 38495331Samw * Search all the shares in the specified group for a share with a 38505331Samw * resource name matching the one specified. 38515331Samw * 38525331Samw * In the future, it may be advantageous to allow group to be NULL and 38535331Samw * search all groups but that isn't needed at present. 38545331Samw */ 38555331Samw 38565331Samw sa_resource_t 38575331Samw sa_get_resource(sa_group_t group, char *resource) 38585331Samw { 38595331Samw sa_share_t share = NULL; 38605331Samw sa_resource_t res = NULL; 38615331Samw 38625331Samw if (resource != NULL) { 38635331Samw for (share = sa_get_share(group, NULL); 38645331Samw share != NULL && res == NULL; 38655331Samw share = sa_get_next_share(share)) { 38665331Samw res = sa_get_share_resource(share, resource); 38675331Samw } 38685331Samw } 38695331Samw return (res); 38705331Samw } 38715331Samw 38725331Samw /* 38735331Samw * sa_enable_resource, protocol) 38745331Samw * Disable the specified share to the specified protocol. 38755331Samw * If protocol is NULL, then all protocols. 38765331Samw */ 38775331Samw int 38785331Samw sa_enable_resource(sa_resource_t resource, char *protocol) 38795331Samw { 38805331Samw int ret = SA_OK; 38815331Samw char **protocols; 38825331Samw int numproto; 38835331Samw 38845331Samw if (protocol != NULL) { 38855331Samw ret = sa_proto_share_resource(protocol, resource); 38865331Samw } else { 38875331Samw /* need to do all protocols */ 38885331Samw if ((numproto = sa_get_protocols(&protocols)) >= 0) { 38895331Samw int i, err; 38905331Samw for (i = 0; i < numproto; i++) { 38915331Samw err = sa_proto_share_resource( 38925331Samw protocols[i], resource); 38935331Samw if (err != SA_OK) 38945331Samw ret = err; 38955331Samw } 38965331Samw free(protocols); 38975331Samw } 38985331Samw } 38995331Samw if (ret == SA_OK) 39005331Samw (void) sa_set_resource_attr(resource, "shared", NULL); 39015331Samw 39025331Samw return (ret); 39035331Samw } 39045331Samw 39055331Samw /* 39065331Samw * sa_disable_resource(resource, protocol) 39075331Samw * 39085331Samw * Disable the specified share for the specified protocol. If 39095331Samw * protocol is NULL, then all protocols. If the underlying 39105331Samw * protocol doesn't implement disable at the resource level, we 39115331Samw * disable at the share level. 39125331Samw */ 39135331Samw int 39145331Samw sa_disable_resource(sa_resource_t resource, char *protocol) 39155331Samw { 39165331Samw int ret = SA_OK; 39175331Samw char **protocols; 39185331Samw int numproto; 39195331Samw 39205331Samw if (protocol != NULL) { 39215331Samw ret = sa_proto_unshare_resource(protocol, resource); 39225331Samw if (ret == SA_NOT_IMPLEMENTED) { 39235331Samw sa_share_t parent; 39245331Samw /* 39255331Samw * The protocol doesn't implement unshare 39265331Samw * resource. That implies that resource names are 39275331Samw * simple aliases for this protocol so we need to 39285331Samw * unshare the share. 39295331Samw */ 39305331Samw parent = sa_get_resource_parent(resource); 39315331Samw if (parent != NULL) 39325331Samw ret = sa_disable_share(parent, protocol); 39335331Samw else 39345331Samw ret = SA_CONFIG_ERR; 39355331Samw } 39365331Samw } else { 39375331Samw /* need to do all protocols */ 39385331Samw if ((numproto = sa_get_protocols(&protocols)) >= 0) { 39395331Samw int i, err; 39405331Samw for (i = 0; i < numproto; i++) { 39415331Samw err = sa_proto_unshare_resource(protocols[i], 39425331Samw resource); 39435331Samw if (err == SA_NOT_SUPPORTED) { 39445331Samw sa_share_t parent; 39455331Samw parent = sa_get_resource_parent( 39465331Samw resource); 39475331Samw if (parent != NULL) 39485331Samw err = sa_disable_share(parent, 39495331Samw protocols[i]); 39505331Samw else 39515331Samw err = SA_CONFIG_ERR; 39525331Samw } 39535331Samw if (err != SA_OK) 39545331Samw ret = err; 39555331Samw } 39565331Samw free(protocols); 39575331Samw } 39585331Samw } 39595331Samw if (ret == SA_OK) 39605331Samw (void) sa_set_resource_attr(resource, "shared", NULL); 39615331Samw 39625331Samw return (ret); 39635331Samw } 39645331Samw 39655331Samw /* 39665331Samw * sa_set_resource_description(resource, content) 39675331Samw * 39685331Samw * Set the description of share to content. 39695331Samw */ 39705331Samw 39715331Samw int 39725331Samw sa_set_resource_description(sa_resource_t resource, char *content) 39735331Samw { 39745331Samw xmlNodePtr node; 39755331Samw sa_group_t group; 39765331Samw sa_share_t share; 39775331Samw int ret = SA_OK; 39785331Samw 39795331Samw for (node = ((xmlNodePtr)resource)->children; 39805331Samw node != NULL; 39815331Samw node = node->next) { 39825331Samw if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 39835331Samw break; 39845331Samw } 39855331Samw } 39865331Samw 39875331Samw /* no existing description but want to add */ 39885331Samw if (node == NULL && content != NULL) { 39895331Samw /* add a description */ 39905331Samw node = _sa_set_share_description(resource, content); 39915331Samw } else if (node != NULL && content != NULL) { 39925331Samw /* update a description */ 39935331Samw xmlNodeSetContent(node, (xmlChar *)content); 39945331Samw } else if (node != NULL && content == NULL) { 39955331Samw /* remove an existing description */ 39965331Samw xmlUnlinkNode(node); 39975331Samw xmlFreeNode(node); 39985331Samw } 39995331Samw share = sa_get_resource_parent(resource); 40005331Samw group = sa_get_parent_group(share); 40015331Samw if (group != NULL && sa_is_persistent(share)) { 40025331Samw sa_handle_impl_t impl_handle; 40035331Samw impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 40045331Samw if (impl_handle != NULL) 40055331Samw ret = sa_commit_share(impl_handle->scfhandle, 40065331Samw group, share); 40075331Samw else 40085331Samw ret = SA_SYSTEM_ERR; 40095331Samw } 40105331Samw return (ret); 40115331Samw } 40125331Samw 40135331Samw /* 40145331Samw * sa_get_resource_description(share) 40155331Samw * 40165331Samw * Return the description text for the specified share if it 40175331Samw * exists. NULL if no description exists. 40185331Samw */ 40195331Samw 40205331Samw char * 40215331Samw sa_get_resource_description(sa_resource_t resource) 40225331Samw { 40235331Samw xmlChar *description = NULL; 40245331Samw xmlNodePtr node; 40255331Samw 40265331Samw for (node = ((xmlNodePtr)resource)->children; node != NULL; 40275331Samw node = node->next) { 40285331Samw if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) 40295331Samw break; 40305331Samw } 40315331Samw if (node != NULL) { 40325331Samw description = xmlNodeGetContent(node); 40335331Samw fixproblemchars((char *)description); 40345331Samw } 40355331Samw return ((char *)description); 40365331Samw } 4037