13034Sdougm /* 23034Sdougm * CDDL HEADER START 33034Sdougm * 43034Sdougm * The contents of this file are subject to the terms of the 53034Sdougm * Common Development and Distribution License (the "License"). 63034Sdougm * You may not use this file except in compliance with the License. 73034Sdougm * 83034Sdougm * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 93034Sdougm * or http://www.opensolaris.org/os/licensing. 103034Sdougm * See the License for the specific language governing permissions 113034Sdougm * and limitations under the License. 123034Sdougm * 133034Sdougm * When distributing Covered Code, include this CDDL HEADER in each 143034Sdougm * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 153034Sdougm * If applicable, add the following below this CDDL HEADER, with the 163034Sdougm * fields enclosed by brackets "[]" replaced with your own identifying 173034Sdougm * information: Portions Copyright [yyyy] [name of copyright owner] 183034Sdougm * 193034Sdougm * CDDL HEADER END 203034Sdougm */ 213034Sdougm 223034Sdougm /* 235772Sas200622 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 243034Sdougm * Use is subject to license terms. 253034Sdougm */ 263034Sdougm 273034Sdougm #pragma ident "%Z%%M% %I% %E% SMI" 283034Sdougm 293034Sdougm /* 303034Sdougm * Share control API 313034Sdougm */ 323034Sdougm #include <stdio.h> 333034Sdougm #include <string.h> 343034Sdougm #include <ctype.h> 353034Sdougm #include <sys/types.h> 363034Sdougm #include <sys/stat.h> 373663Sdougm #include <fcntl.h> 383034Sdougm #include <unistd.h> 393034Sdougm #include <libxml/parser.h> 403034Sdougm #include <libxml/tree.h> 413034Sdougm #include "libshare.h" 423034Sdougm #include "libshare_impl.h" 433034Sdougm #include <libscf.h> 443034Sdougm #include "scfutil.h" 453034Sdougm #include <ctype.h> 463034Sdougm #include <libintl.h> 473910Sdougm #include <thread.h> 483910Sdougm #include <synch.h> 493034Sdougm 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; 2203034Sdougm default: 2214327Sdougm (void) snprintf(errstr, sizeof (errstr), 2224327Sdougm dgettext(TEXT_DOMAIN, "unknown %d"), err); 2234327Sdougm ret = errstr; 2243034Sdougm } 2253034Sdougm return (ret); 2263034Sdougm } 2273034Sdougm 2283034Sdougm /* 2293910Sdougm * Document root to active handle mapping functions. These are only 2303910Sdougm * used internally. A mutex is used to prevent access while the list 2313910Sdougm * is changing. In general, the list will be relatively short - one 2323910Sdougm * item per thread that has called sa_init(). 2333910Sdougm */ 2343910Sdougm 2353910Sdougm sa_handle_impl_t 2363910Sdougm get_handle_for_root(xmlNodePtr root) 2373910Sdougm { 2383910Sdougm struct doc2handle *item; 2393910Sdougm 2403910Sdougm (void) mutex_lock(&sa_global_lock); 2413910Sdougm for (item = sa_global_handles; item != NULL; item = item->next) { 2424327Sdougm if (item->root == root) 2434327Sdougm break; 2443910Sdougm } 2453910Sdougm (void) mutex_unlock(&sa_global_lock); 2463910Sdougm if (item != NULL) 2474327Sdougm return (item->handle); 2483910Sdougm return (NULL); 2493910Sdougm } 2503910Sdougm 2513910Sdougm static int 2523910Sdougm add_handle_for_root(xmlNodePtr root, sa_handle_impl_t handle) 2533910Sdougm { 2543910Sdougm struct doc2handle *item; 2553910Sdougm int ret = SA_NO_MEMORY; 2563910Sdougm 2573910Sdougm item = (struct doc2handle *)calloc(sizeof (struct doc2handle), 1); 2583910Sdougm if (item != NULL) { 2594327Sdougm item->root = root; 2604327Sdougm item->handle = handle; 2614327Sdougm (void) mutex_lock(&sa_global_lock); 2624327Sdougm item->next = sa_global_handles; 2634327Sdougm sa_global_handles = item; 2644327Sdougm (void) mutex_unlock(&sa_global_lock); 2654327Sdougm ret = SA_OK; 2663910Sdougm } 2673910Sdougm return (ret); 2683910Sdougm } 2693910Sdougm 2703910Sdougm /* 2713910Sdougm * remove_handle_for_root(root) 2723910Sdougm * 2733910Sdougm * Walks the list of handles and removes the one for this "root" from 2743910Sdougm * the list. It is up to the caller to free the data. 2753910Sdougm */ 2763910Sdougm 2773910Sdougm static void 2783910Sdougm remove_handle_for_root(xmlNodePtr root) 2793910Sdougm { 2803910Sdougm struct doc2handle *item, *prev; 2813910Sdougm 2823910Sdougm (void) mutex_lock(&sa_global_lock); 2833910Sdougm for (prev = NULL, item = sa_global_handles; item != NULL; 2844327Sdougm item = item->next) { 2854327Sdougm if (item->root == root) { 2864327Sdougm /* first in the list */ 2874327Sdougm if (prev == NULL) 2884327Sdougm sa_global_handles = sa_global_handles->next; 2894327Sdougm else 2904327Sdougm prev->next = item->next; 2914327Sdougm /* Item is out of the list so free the list structure */ 2924327Sdougm free(item); 2934327Sdougm break; 2943910Sdougm } 2954327Sdougm prev = item; 2963910Sdougm } 2973910Sdougm (void) mutex_unlock(&sa_global_lock); 2983910Sdougm } 2993910Sdougm 3003910Sdougm /* 3013910Sdougm * sa_find_group_handle(sa_group_t group) 3023910Sdougm * 3033910Sdougm * Find the sa_handle_t for the configuration associated with this 3043910Sdougm * group. 3053910Sdougm */ 3063910Sdougm sa_handle_t 3073910Sdougm sa_find_group_handle(sa_group_t group) 3083910Sdougm { 3093910Sdougm xmlNodePtr node = (xmlNodePtr)group; 3103910Sdougm sa_handle_t handle; 3113910Sdougm 3123910Sdougm while (node != NULL) { 3134327Sdougm if (strcmp((char *)(node->name), "sharecfg") == 0) { 3144327Sdougm /* have the root so get the handle */ 3154327Sdougm handle = (sa_handle_t)get_handle_for_root(node); 3164327Sdougm return (handle); 3174327Sdougm } 3184327Sdougm node = node->parent; 3193910Sdougm } 3203910Sdougm return (NULL); 3213910Sdougm } 3223910Sdougm 3233910Sdougm /* 3243034Sdougm * set_legacy_timestamp(root, path, timevalue) 3253034Sdougm * 3263034Sdougm * add the current timestamp value to the configuration for use in 3273034Sdougm * determining when to update the legacy files. For SMF, this 3283034Sdougm * property is kept in default/operation/legacy_timestamp 3293034Sdougm */ 3303034Sdougm 3313034Sdougm static void 3323034Sdougm set_legacy_timestamp(xmlNodePtr root, char *path, uint64_t tval) 3333034Sdougm { 3343034Sdougm xmlNodePtr node; 3353034Sdougm xmlChar *lpath = NULL; 3363910Sdougm sa_handle_impl_t handle; 3373910Sdougm 3383910Sdougm /* Have to have a handle or else we weren't initialized. */ 3393910Sdougm handle = get_handle_for_root(root); 3403910Sdougm if (handle == NULL) 3414327Sdougm return; 3423034Sdougm 3433034Sdougm for (node = root->xmlChildrenNode; node != NULL; 3444327Sdougm node = node->next) { 3454327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"legacy") == 0) { 3464327Sdougm /* a possible legacy node for this path */ 3474327Sdougm lpath = xmlGetProp(node, (xmlChar *)"path"); 3484327Sdougm if (lpath != NULL && 3494327Sdougm xmlStrcmp(lpath, (xmlChar *)path) == 0) { 3504327Sdougm xmlFree(lpath); 3514327Sdougm break; 3524327Sdougm } 3534327Sdougm if (lpath != NULL) 3544327Sdougm xmlFree(lpath); 3553034Sdougm } 3563034Sdougm } 3573034Sdougm if (node == NULL) { 3584327Sdougm /* need to create the first legacy timestamp node */ 3594327Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"legacy", NULL); 3603034Sdougm } 3613034Sdougm if (node != NULL) { 3624327Sdougm char tstring[32]; 3634327Sdougm int ret; 3643034Sdougm 3654327Sdougm (void) snprintf(tstring, sizeof (tstring), "%lld", tval); 3664327Sdougm xmlSetProp(node, (xmlChar *)"timestamp", (xmlChar *)tstring); 3674327Sdougm xmlSetProp(node, (xmlChar *)"path", (xmlChar *)path); 3684327Sdougm /* now commit to SMF */ 3694327Sdougm ret = sa_get_instance(handle->scfhandle, "default"); 3703034Sdougm if (ret == SA_OK) { 3714327Sdougm ret = sa_start_transaction(handle->scfhandle, 3724327Sdougm "operation"); 3734327Sdougm if (ret == SA_OK) { 3744327Sdougm ret = sa_set_property(handle->scfhandle, 3754327Sdougm "legacy-timestamp", tstring); 3764327Sdougm if (ret == SA_OK) { 3774327Sdougm (void) sa_end_transaction( 3784327Sdougm handle->scfhandle); 3794327Sdougm } else { 3804327Sdougm sa_abort_transaction(handle->scfhandle); 3814327Sdougm } 3824327Sdougm } 3833034Sdougm } 3843034Sdougm } 3853034Sdougm } 3863034Sdougm 3873034Sdougm /* 3883034Sdougm * is_shared(share) 3893034Sdougm * 3903034Sdougm * determine if the specified share is currently shared or not. 3913034Sdougm */ 3923034Sdougm static int 3933034Sdougm is_shared(sa_share_t share) 3943034Sdougm { 3953034Sdougm char *shared; 3963034Sdougm int result = 0; /* assume not */ 3973034Sdougm 3983034Sdougm shared = sa_get_share_attr(share, "shared"); 3993034Sdougm if (shared != NULL) { 4004327Sdougm if (strcmp(shared, "true") == 0) 4014327Sdougm result = 1; 4024327Sdougm sa_free_attr_string(shared); 4033034Sdougm } 4043034Sdougm return (result); 4053034Sdougm } 4063034Sdougm 4073034Sdougm /* 4085331Samw * excluded_protocol(share, proto) 4095331Samw * 4105331Samw * Returns B_TRUE if the specified protocol appears in the "exclude" 4115331Samw * property. This is used to prevent sharing special case shares 4125331Samw * (e.g. subdirs when SMB wants a subdir and NFS doesn't. B_FALSE is 4135331Samw * returned if the protocol isn't in the list. 4145331Samw */ 4155331Samw static boolean_t 4165331Samw excluded_protocol(sa_share_t share, char *proto) 4175331Samw { 4185331Samw char *protolist; 4195331Samw char *str; 4205331Samw char *token; 4215331Samw 4225331Samw protolist = sa_get_share_attr(share, "exclude"); 4235331Samw if (protolist != NULL) { 4245331Samw str = protolist; 4255331Samw while ((token = strtok(str, ",")) != NULL) { 4265331Samw if (strcmp(token, proto) == 0) { 4275331Samw sa_free_attr_string(protolist); 4285331Samw return (B_TRUE); 4295331Samw } 4305331Samw str = NULL; 4315331Samw } 4325331Samw sa_free_attr_string(protolist); 4335331Samw } 4345331Samw return (B_FALSE); 4355331Samw } 4365331Samw 4375331Samw /* 4383663Sdougm * checksubdirgroup(group, newpath, strictness) 4393348Sdougm * 4403663Sdougm * check all the specified newpath against all the paths in the 4413663Sdougm * group. This is a helper function for checksubdir to make it easier 4423663Sdougm * to also check ZFS subgroups. 4433663Sdougm * The strictness values mean: 4443348Sdougm * SA_CHECK_NORMAL == only check newpath against shares that are active 4453348Sdougm * SA_CHECK_STRICT == check newpath against both active shares and those 4463348Sdougm * stored in the repository 4473034Sdougm */ 4483034Sdougm static int 4493663Sdougm checksubdirgroup(sa_group_t group, char *newpath, int strictness) 4503034Sdougm { 4513034Sdougm sa_share_t share; 4523663Sdougm char *path; 4533663Sdougm int issub = SA_OK; 4545331Samw int subdir; 4555331Samw int parent; 4565331Samw 4575331Samw if (newpath == NULL) 4585331Samw return (SA_INVALID_PATH); 4593034Sdougm 4603663Sdougm for (share = sa_get_share(group, NULL); share != NULL; 4613663Sdougm share = sa_get_next_share(share)) { 4623034Sdougm /* 4633034Sdougm * The original behavior of share never checked 4643034Sdougm * against the permanent configuration 4653034Sdougm * (/etc/dfs/dfstab). PIT has a number of cases where 4663034Sdougm * it depends on this older behavior even though it 4673034Sdougm * could be considered incorrect. We may tighten this 4683034Sdougm * up in the future. 4693034Sdougm */ 4704327Sdougm if (strictness == SA_CHECK_NORMAL && !is_shared(share)) 4714327Sdougm continue; 4723034Sdougm 4734327Sdougm path = sa_get_share_attr(share, "path"); 4743348Sdougm /* 4753348Sdougm * If path is NULL, then a share is in the process of 4763348Sdougm * construction or someone has modified the property 4773663Sdougm * group inappropriately. It should be 4783663Sdougm * ignored. issubdir() comes from the original share 4793663Sdougm * implementation and does the difficult part of 4803663Sdougm * checking subdirectories. 4813348Sdougm */ 4824327Sdougm if (path == NULL) 4834327Sdougm continue; 4845331Samw 4855331Samw if (strcmp(path, newpath) == 0) { 4864327Sdougm issub = SA_INVALID_PATH; 4875331Samw } else { 4885331Samw subdir = issubdir(newpath, path); 4895331Samw parent = issubdir(path, newpath); 4905331Samw if (subdir || parent) { 4915331Samw sa_free_attr_string(path); 4925331Samw path = NULL; 4935331Samw return (subdir ? 4945331Samw SA_PATH_IS_SUBDIR : SA_PATH_IS_PARENTDIR); 4955331Samw } 4964327Sdougm } 4973034Sdougm sa_free_attr_string(path); 4983034Sdougm path = NULL; 4993663Sdougm } 5003663Sdougm return (issub); 5013663Sdougm } 5023663Sdougm 5033663Sdougm /* 5043663Sdougm * checksubdir(newpath, strictness) 5053663Sdougm * 5063663Sdougm * checksubdir determines if the specified path (newpath) is a 5073663Sdougm * subdirectory of another share. It calls checksubdirgroup() to do 5083663Sdougm * the complicated work. The strictness parameter determines how 5093663Sdougm * strict a check to make against the path. The strictness values 5103663Sdougm * mean: SA_CHECK_NORMAL == only check newpath against shares that are 5113663Sdougm * active SA_CHECK_STRICT == check newpath against both active shares 5123663Sdougm * and those * stored in the repository 5133663Sdougm */ 5143663Sdougm static int 5153910Sdougm checksubdir(sa_handle_t handle, char *newpath, int strictness) 5163663Sdougm { 5173663Sdougm sa_group_t group; 5185331Samw int issub = SA_OK; 5193663Sdougm char *path = NULL; 5203663Sdougm 5215331Samw for (group = sa_get_group(handle, NULL); 5225331Samw group != NULL && issub == SA_OK; 5235331Samw group = sa_get_next_group(group)) { 5244327Sdougm if (sa_group_is_zfs(group)) { 5254327Sdougm sa_group_t subgroup; 5264327Sdougm for (subgroup = sa_get_sub_group(group); 5275331Samw subgroup != NULL && issub == SA_OK; 5284327Sdougm subgroup = sa_get_next_group(subgroup)) 5294327Sdougm issub = checksubdirgroup(subgroup, newpath, 5304327Sdougm strictness); 5314327Sdougm } else { 5324327Sdougm issub = checksubdirgroup(group, newpath, strictness); 5334327Sdougm } 5343034Sdougm } 5353034Sdougm if (path != NULL) 5364327Sdougm sa_free_attr_string(path); 5373034Sdougm return (issub); 5383034Sdougm } 5393034Sdougm 5403034Sdougm /* 5413348Sdougm * validpath(path, strictness) 5423034Sdougm * determine if the provided path is valid for a share. It shouldn't 5433034Sdougm * be a sub-dir of an already shared path or the parent directory of a 5443034Sdougm * share path. 5453034Sdougm */ 5463034Sdougm static int 5473910Sdougm validpath(sa_handle_t handle, char *path, int strictness) 5483034Sdougm { 5493034Sdougm int error = SA_OK; 5503034Sdougm struct stat st; 5513034Sdougm sa_share_t share; 5523034Sdougm char *fstype; 5533034Sdougm 5544327Sdougm if (*path != '/') 5554327Sdougm return (SA_BAD_PATH); 5564327Sdougm 5573034Sdougm if (stat(path, &st) < 0) { 5584327Sdougm error = SA_NO_SUCH_PATH; 5593034Sdougm } else { 5604327Sdougm share = sa_find_share(handle, path); 5614327Sdougm if (share != NULL) 5624327Sdougm error = SA_DUPLICATE_NAME; 5634327Sdougm 5644327Sdougm if (error == SA_OK) { 5654327Sdougm /* 5664327Sdougm * check for special case with file system 5674327Sdougm * that might have restrictions. For now, ZFS 5684327Sdougm * is the only case since it has its own idea 5694327Sdougm * of how to configure shares. We do this 5704327Sdougm * before subdir checking since things like 5714327Sdougm * ZFS will do that for us. This should also 5724327Sdougm * be done via plugin interface. 5734327Sdougm */ 5744327Sdougm fstype = sa_fstype(path); 5754327Sdougm if (fstype != NULL && strcmp(fstype, "zfs") == 0) { 5764327Sdougm if (sa_zfs_is_shared(handle, path)) 5774327Sdougm error = SA_INVALID_NAME; 5784327Sdougm } 5794327Sdougm if (fstype != NULL) 5804327Sdougm sa_free_fstype(fstype); 5813034Sdougm } 5824327Sdougm if (error == SA_OK) 5834327Sdougm error = checksubdir(handle, path, strictness); 5843034Sdougm } 5853034Sdougm return (error); 5863034Sdougm } 5873034Sdougm 5883034Sdougm /* 5893034Sdougm * check to see if group/share is persistent. 5905331Samw * 5915331Samw * "group" can be either an sa_group_t or an sa_share_t. (void *) 5925331Samw * works since both thse types are also void *. 5933034Sdougm */ 5945331Samw int 5955331Samw sa_is_persistent(void *group) 5963034Sdougm { 5973034Sdougm char *type; 5983034Sdougm int persist = 1; 5993034Sdougm 6005331Samw type = sa_get_group_attr((sa_group_t)group, "type"); 6013034Sdougm if (type != NULL && strcmp(type, "transient") == 0) 6024327Sdougm persist = 0; 6033034Sdougm if (type != NULL) 6044327Sdougm sa_free_attr_string(type); 6053034Sdougm return (persist); 6063034Sdougm } 6073034Sdougm 6083034Sdougm /* 6093034Sdougm * sa_valid_group_name(name) 6103034Sdougm * 6113034Sdougm * check that the "name" contains only valid characters and otherwise 6123034Sdougm * fits the required naming conventions. Valid names must start with 6133034Sdougm * an alphabetic and the remainder may consist of only alphanumeric 6143034Sdougm * plus the '-' and '_' characters. This name limitation comes from 6153034Sdougm * inherent limitations in SMF. 6163034Sdougm */ 6173034Sdougm 6183034Sdougm int 6193034Sdougm sa_valid_group_name(char *name) 6203034Sdougm { 6213034Sdougm int ret = 1; 6223034Sdougm ssize_t len; 6233034Sdougm 6243034Sdougm if (name != NULL && isalpha(*name)) { 6254327Sdougm char c; 6264327Sdougm len = strlen(name); 6274327Sdougm if (len < (scf_max_name_len - sizeof ("group:"))) { 6284327Sdougm for (c = *name++; c != '\0' && ret != 0; c = *name++) { 6294327Sdougm if (!isalnum(c) && c != '-' && c != '_') 6304327Sdougm ret = 0; 6314327Sdougm } 6324327Sdougm } else { 6333034Sdougm ret = 0; 6343034Sdougm } 6354327Sdougm } else { 6363034Sdougm ret = 0; 6373034Sdougm } 6383034Sdougm return (ret); 6393034Sdougm } 6403034Sdougm 6413034Sdougm 6423034Sdougm /* 6433034Sdougm * is_zfs_group(group) 6443034Sdougm * Determine if the specified group is a ZFS sharenfs group 6453034Sdougm */ 6463034Sdougm static int 6473034Sdougm is_zfs_group(sa_group_t group) 6483034Sdougm { 6493034Sdougm int ret = 0; 6503034Sdougm xmlNodePtr parent; 6513034Sdougm xmlChar *zfs; 6523034Sdougm 6534327Sdougm if (strcmp((char *)((xmlNodePtr)group)->name, "share") == 0) 6544327Sdougm parent = (xmlNodePtr)sa_get_parent_group(group); 6554327Sdougm else 6564327Sdougm parent = (xmlNodePtr)group; 6573034Sdougm zfs = xmlGetProp(parent, (xmlChar *)"zfs"); 6583034Sdougm if (zfs != NULL) { 6594327Sdougm xmlFree(zfs); 6604327Sdougm ret = 1; 6613034Sdougm } 6623034Sdougm return (ret); 6633034Sdougm } 6643034Sdougm 6653034Sdougm /* 6665331Samw * sa_get_object_type(object) 6675331Samw * 6685331Samw * This function returns a numeric value representing the object 6695331Samw * type. This allows using simpler checks when doing type specific 6705331Samw * operations. 6715331Samw */ 6725331Samw 6735331Samw static int 6745331Samw sa_get_object_type(void *object) 6755331Samw { 6765331Samw xmlNodePtr node = (xmlNodePtr)object; 6775331Samw int type; 6785331Samw 6795331Samw if (xmlStrcmp(node->name, (xmlChar *)"group") == 0) 6805331Samw type = SA_TYPE_GROUP; 6815331Samw else if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) 6825331Samw type = SA_TYPE_SHARE; 6835331Samw else if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0) 6845331Samw type = SA_TYPE_RESOURCE; 6855331Samw else if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) 6865331Samw type = SA_TYPE_OPTIONSET; 6875331Samw else if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) 6885331Samw type = SA_TYPE_ALTSPACE; 6895331Samw else 6905331Samw assert(0); 6915331Samw return (type); 6925331Samw } 6935331Samw 6945331Samw /* 6953034Sdougm * sa_optionset_name(optionset, oname, len, id) 6963034Sdougm * return the SMF name for the optionset. If id is not NULL, it 6973034Sdougm * will have the GUID value for a share and should be used 6983034Sdougm * instead of the keyword "optionset" which is used for 6993034Sdougm * groups. If the optionset doesn't have a protocol type 7003034Sdougm * associated with it, "default" is used. This shouldn't happen 7013034Sdougm * at this point but may be desirable in the future if there are 7023034Sdougm * protocol independent properties added. The name is returned in 7033034Sdougm * oname. 7043034Sdougm */ 7053034Sdougm 7063034Sdougm static int 7073034Sdougm sa_optionset_name(sa_optionset_t optionset, char *oname, size_t len, char *id) 7083034Sdougm { 7093034Sdougm char *proto; 7105331Samw void *parent; 7115331Samw int ptype; 7123034Sdougm 7133034Sdougm if (id == NULL) 7144327Sdougm id = "optionset"; 7153034Sdougm 7165331Samw parent = sa_get_optionset_parent(optionset); 7175331Samw if (parent != NULL) { 7185331Samw ptype = sa_get_object_type(parent); 7195331Samw proto = sa_get_optionset_attr(optionset, "type"); 7205331Samw if (ptype != SA_TYPE_RESOURCE) { 7215331Samw len = snprintf(oname, len, "%s_%s", id, 7225331Samw proto ? proto : "default"); 7235331Samw } else { 7245331Samw char *index; 7255331Samw index = get_node_attr((void *)parent, "id"); 7265331Samw if (index != NULL) 7275331Samw len = snprintf(oname, len, "%s_%s_%s", id, 7285331Samw proto ? proto : "default", index); 7295331Samw else 7305331Samw len = 0; 7315331Samw } 7325331Samw 7335331Samw if (proto != NULL) 7345331Samw sa_free_attr_string(proto); 7355331Samw } else { 7365331Samw len = 0; 7375331Samw } 7383034Sdougm return (len); 7393034Sdougm } 7403034Sdougm 7413034Sdougm /* 7423034Sdougm * sa_security_name(optionset, oname, len, id) 7433034Sdougm * 7443034Sdougm * return the SMF name for the security. If id is not NULL, it will 7453034Sdougm * have the GUID value for a share and should be used instead of the 7463034Sdougm * keyword "optionset" which is used for groups. If the optionset 7473034Sdougm * doesn't have a protocol type associated with it, "default" is 7483034Sdougm * used. This shouldn't happen at this point but may be desirable in 7493034Sdougm * the future if there are protocol independent properties added. The 7503034Sdougm * name is returned in oname. The security type is also encoded into 7513034Sdougm * the name. In the future, this wil *be handled a bit differently. 7523034Sdougm */ 7533034Sdougm 7543034Sdougm static int 7553034Sdougm sa_security_name(sa_security_t security, char *oname, size_t len, char *id) 7563034Sdougm { 7573034Sdougm char *proto; 7583034Sdougm char *sectype; 7593034Sdougm 7603034Sdougm if (id == NULL) 7614327Sdougm id = "optionset"; 7623034Sdougm 7633034Sdougm proto = sa_get_security_attr(security, "type"); 7643034Sdougm sectype = sa_get_security_attr(security, "sectype"); 7654327Sdougm len = snprintf(oname, len, "%s_%s_%s", id, proto ? proto : "default", 7664327Sdougm sectype ? sectype : "default"); 7673034Sdougm if (proto != NULL) 7684327Sdougm sa_free_attr_string(proto); 7693034Sdougm if (sectype != NULL) 7704327Sdougm sa_free_attr_string(sectype); 7713034Sdougm return (len); 7723034Sdougm } 7733034Sdougm 7743034Sdougm /* 7754327Sdougm * verifydefgroupopts(handle) 7764327Sdougm * 7774327Sdougm * Make sure a "default" group exists and has default protocols enabled. 7784327Sdougm */ 7794327Sdougm static void 7804327Sdougm verifydefgroupopts(sa_handle_t handle) 7814327Sdougm { 7824327Sdougm sa_group_t defgrp; 7834327Sdougm sa_optionset_t opt; 7845331Samw 7854327Sdougm defgrp = sa_get_group(handle, "default"); 7864327Sdougm if (defgrp != NULL) { 7874327Sdougm opt = sa_get_optionset(defgrp, NULL); 7884327Sdougm /* 7894327Sdougm * NFS is the default for default group 7904327Sdougm */ 7914327Sdougm if (opt == NULL) 7924327Sdougm opt = sa_create_optionset(defgrp, "nfs"); 7934327Sdougm } 7944327Sdougm } 7954327Sdougm 7964327Sdougm /* 7973348Sdougm * sa_init(init_service) 7983034Sdougm * Initialize the API 7993034Sdougm * find all the shared objects 8003034Sdougm * init the tables with all objects 8013034Sdougm * read in the current configuration 8023034Sdougm */ 8033034Sdougm 8044327Sdougm #define GETPROP(prop) scf_simple_prop_next_astring(prop) 8054327Sdougm #define CHECKTSTAMP(st, tval) stat(SA_LEGACY_DFSTAB, &st) >= 0 && \ 8064327Sdougm tval != TSTAMP(st.st_ctim) 8074327Sdougm 8083910Sdougm sa_handle_t 8093034Sdougm sa_init(int init_service) 8103034Sdougm { 8113034Sdougm struct stat st; 8123034Sdougm int legacy = 0; 8133034Sdougm uint64_t tval = 0; 8143663Sdougm int lockfd; 8153663Sdougm sigset_t old; 8163663Sdougm int updatelegacy = B_FALSE; 8173663Sdougm scf_simple_prop_t *prop; 8183910Sdougm sa_handle_impl_t handle; 8193910Sdougm int err; 8203034Sdougm 8213910Sdougm handle = calloc(sizeof (struct sa_handle_impl), 1); 8223910Sdougm 8233910Sdougm if (handle != NULL) { 8244327Sdougm /* get protocol specific structures */ 8254327Sdougm (void) proto_plugin_init(); 8264327Sdougm if (init_service & SA_INIT_SHARE_API) { 8273663Sdougm /* 8284327Sdougm * initialize access into libzfs. We use this 8294327Sdougm * when collecting info about ZFS datasets and 8304327Sdougm * shares. 8313663Sdougm */ 8324327Sdougm if (sa_zfs_init(handle) == B_FALSE) { 8334327Sdougm free(handle); 8344327Sdougm (void) proto_plugin_fini(); 8354327Sdougm return (NULL); 8364327Sdougm } 8373663Sdougm /* 8384327Sdougm * since we want to use SMF, initialize an svc handle 8394327Sdougm * and find out what is there. 8403663Sdougm */ 8414327Sdougm handle->scfhandle = sa_scf_init(handle); 8424327Sdougm if (handle->scfhandle != NULL) { 8434327Sdougm /* 8444327Sdougm * Need to lock the extraction of the 8454327Sdougm * configuration if the dfstab file has 8464327Sdougm * changed. Lock everything now and release if 8474327Sdougm * not needed. Use a file that isn't being 8484327Sdougm * manipulated by other parts of the system in 8494327Sdougm * order to not interfere with locking. Using 8504327Sdougm * dfstab doesn't work. 8514327Sdougm */ 8524327Sdougm sablocksigs(&old); 8534327Sdougm lockfd = open(DFS_LOCK_FILE, O_RDWR); 8544327Sdougm if (lockfd >= 0) { 8554327Sdougm extern int errno; 8564327Sdougm errno = 0; 8574327Sdougm (void) lockf(lockfd, F_LOCK, 0); 8584327Sdougm /* 8594327Sdougm * Check whether we are going to need 8604327Sdougm * to merge any dfstab changes. This 8614327Sdougm * is done by comparing the value of 8624327Sdougm * legacy-timestamp with the current 8634327Sdougm * st_ctim of the file. If they are 8644327Sdougm * different, an update is needed and 8654327Sdougm * the file must remain locked until 8664327Sdougm * the merge is done in order to 8674327Sdougm * prevent multiple startups from 8684327Sdougm * changing the SMF repository at the 8694327Sdougm * same time. The first to get the 8704327Sdougm * lock will make any changes before 8714327Sdougm * the others can read the repository. 8724327Sdougm */ 8734327Sdougm prop = scf_simple_prop_get 8744327Sdougm (handle->scfhandle->handle, 8754327Sdougm (const char *)SA_SVC_FMRI_BASE 8764327Sdougm ":default", "operation", 8774327Sdougm "legacy-timestamp"); 8784327Sdougm if (prop != NULL) { 8794327Sdougm char *i64; 8804327Sdougm i64 = GETPROP(prop); 8814327Sdougm if (i64 != NULL) 8824327Sdougm tval = strtoull(i64, 8834327Sdougm NULL, 0); 8844327Sdougm if (CHECKTSTAMP(st, tval)) 8854327Sdougm updatelegacy = B_TRUE; 8864327Sdougm scf_simple_prop_free(prop); 8874327Sdougm } else { 8884327Sdougm /* 8894327Sdougm * We haven't set the 8904327Sdougm * timestamp before so do it. 8914327Sdougm */ 8924327Sdougm updatelegacy = B_TRUE; 8934327Sdougm } 8944327Sdougm } 8954327Sdougm if (updatelegacy == B_FALSE) { 8964327Sdougm /* Don't need the lock anymore */ 8974327Sdougm (void) lockf(lockfd, F_ULOCK, 0); 8984327Sdougm (void) close(lockfd); 8994327Sdougm } 9003973Sdougm 9014327Sdougm /* 9024327Sdougm * It is essential that the document tree and 9034327Sdougm * the internal list of roots to handles be 9044327Sdougm * setup before anything that might try to 9054327Sdougm * create a new object is called. The document 9064327Sdougm * tree is the combination of handle->doc and 9074327Sdougm * handle->tree. This allows searches, 9084327Sdougm * etc. when all you have is an object in the 9094327Sdougm * tree. 9104327Sdougm */ 9114327Sdougm handle->doc = xmlNewDoc((xmlChar *)"1.0"); 9124327Sdougm handle->tree = xmlNewNode(NULL, 9134327Sdougm (xmlChar *)"sharecfg"); 9144327Sdougm if (handle->doc != NULL && 9154327Sdougm handle->tree != NULL) { 9164327Sdougm xmlDocSetRootElement(handle->doc, 9174327Sdougm handle->tree); 9184327Sdougm err = add_handle_for_root(handle->tree, 9194327Sdougm handle); 9204327Sdougm if (err == SA_OK) 9214327Sdougm err = sa_get_config( 9224327Sdougm handle->scfhandle, 9233973Sdougm handle->tree, handle); 9244327Sdougm } else { 9254327Sdougm if (handle->doc != NULL) 9264327Sdougm xmlFreeDoc(handle->doc); 9274327Sdougm if (handle->tree != NULL) 9284327Sdougm xmlFreeNode(handle->tree); 9294327Sdougm err = SA_NO_MEMORY; 9304327Sdougm } 9313973Sdougm 9324327Sdougm saunblocksigs(&old); 9333910Sdougm 9344327Sdougm if (err != SA_OK) { 9354327Sdougm /* 9364327Sdougm * If we couldn't add the tree handle 9374327Sdougm * to the list, then things are going 9384327Sdougm * to fail badly. Might as well undo 9394327Sdougm * everything now and fail the 9404327Sdougm * sa_init(). 9414327Sdougm */ 9424327Sdougm sa_fini(handle); 9434327Sdougm return (NULL); 9444327Sdougm } 9453910Sdougm 9464327Sdougm if (tval == 0) { 9474327Sdougm /* 9484327Sdougm * first time so make sure 9494327Sdougm * default is setup 9504327Sdougm */ 9514327Sdougm verifydefgroupopts(handle); 9524327Sdougm } 9533973Sdougm 9544524Sdougm if (updatelegacy == B_TRUE) { 9554524Sdougm sablocksigs(&old); 9564524Sdougm getlegacyconfig((sa_handle_t)handle, 9574524Sdougm SA_LEGACY_DFSTAB, &handle->tree); 9584524Sdougm if (stat(SA_LEGACY_DFSTAB, &st) >= 0) 9594524Sdougm set_legacy_timestamp( 9604524Sdougm handle->tree, 9614524Sdougm SA_LEGACY_DFSTAB, 9624524Sdougm TSTAMP(st.st_ctim)); 9634524Sdougm saunblocksigs(&old); 9644524Sdougm /* 9654524Sdougm * Safe to unlock now to allow 9664524Sdougm * others to run 9674524Sdougm */ 9684524Sdougm (void) lockf(lockfd, F_ULOCK, 0); 9694524Sdougm (void) close(lockfd); 9704524Sdougm } 9714524Sdougm legacy |= sa_get_zfs_shares(handle, "zfs"); 9724524Sdougm legacy |= gettransients(handle, &handle->tree); 9734327Sdougm } 9744327Sdougm } 9753034Sdougm } 9763910Sdougm return ((sa_handle_t)handle); 9773034Sdougm } 9783034Sdougm 9793034Sdougm /* 9803910Sdougm * sa_fini(handle) 9813034Sdougm * Uninitialize the API structures including the configuration 9823218Sdougm * data structures and ZFS related data. 9833034Sdougm */ 9843034Sdougm 9853034Sdougm void 9863910Sdougm sa_fini(sa_handle_t handle) 9873034Sdougm { 9883910Sdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle; 9893910Sdougm 9903910Sdougm if (impl_handle != NULL) { 9913910Sdougm /* 9923910Sdougm * Free the config trees and any other data structures 9933910Sdougm * used in the handle. 9943910Sdougm */ 9953910Sdougm if (impl_handle->doc != NULL) 9963910Sdougm xmlFreeDoc(impl_handle->doc); 9973910Sdougm sa_scf_fini(impl_handle->scfhandle); 9983910Sdougm sa_zfs_fini(impl_handle); 9993910Sdougm 10003910Sdougm /* Remove and free the entry in the global list. */ 10013910Sdougm remove_handle_for_root(impl_handle->tree); 10023910Sdougm 10033910Sdougm /* Make sure we free the handle */ 10043910Sdougm free(impl_handle); 10053910Sdougm 10063910Sdougm /* 10073910Sdougm * If this was the last handle to release, unload the 10083910Sdougm * plugins that were loaded. 10093910Sdougm */ 10103910Sdougm if (sa_global_handles == NULL) 10114327Sdougm (void) proto_plugin_fini(); 10123910Sdougm 10133034Sdougm } 10143034Sdougm } 10153034Sdougm 10163034Sdougm /* 10173034Sdougm * sa_get_protocols(char **protocol) 10183034Sdougm * Get array of protocols that are supported 10193034Sdougm * Returns pointer to an allocated and NULL terminated 10203034Sdougm * array of strings. Caller must free. 10213034Sdougm * This really should be determined dynamically. 10223034Sdougm * If there aren't any defined, return -1. 10233034Sdougm * Use free() to return memory. 10243034Sdougm */ 10253034Sdougm 10263034Sdougm int 10273034Sdougm sa_get_protocols(char ***protocols) 10283034Sdougm { 10293034Sdougm int numproto = -1; 10303034Sdougm 10313034Sdougm if (protocols != NULL) { 10324327Sdougm struct sa_proto_plugin *plug; 10334327Sdougm for (numproto = 0, plug = sap_proto_list; plug != NULL; 10344327Sdougm plug = plug->plugin_next) { 10354327Sdougm numproto++; 10364327Sdougm } 10373034Sdougm 10384327Sdougm *protocols = calloc(numproto + 1, sizeof (char *)); 10394327Sdougm if (*protocols != NULL) { 10404327Sdougm int ret = 0; 10414327Sdougm for (plug = sap_proto_list; plug != NULL; 10424327Sdougm plug = plug->plugin_next) { 10434327Sdougm /* faking for now */ 10444327Sdougm (*protocols)[ret++] = 10454327Sdougm plug->plugin_ops->sa_protocol; 10464327Sdougm } 10474327Sdougm } else { 10484327Sdougm numproto = -1; 10493034Sdougm } 10503034Sdougm } 10513034Sdougm return (numproto); 10523034Sdougm } 10533034Sdougm 10543034Sdougm /* 10553034Sdougm * find_group_by_name(node, group) 10563034Sdougm * 10573034Sdougm * search the XML document subtree specified by node to find the group 10583034Sdougm * specified by group. Searching subtree allows subgroups to be 10593034Sdougm * searched for. 10603034Sdougm */ 10613034Sdougm 10623034Sdougm static xmlNodePtr 10633034Sdougm find_group_by_name(xmlNodePtr node, xmlChar *group) 10643034Sdougm { 10653034Sdougm xmlChar *name = NULL; 10663034Sdougm 10673034Sdougm for (node = node->xmlChildrenNode; node != NULL; 10683034Sdougm node = node->next) { 10694327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"group") == 0) { 10704327Sdougm /* if no groupname, return the first found */ 10714327Sdougm if (group == NULL) 10724327Sdougm break; 10734327Sdougm name = xmlGetProp(node, (xmlChar *)"name"); 10744327Sdougm if (name != NULL && xmlStrcmp(name, group) == 0) 10754327Sdougm break; 10764327Sdougm if (name != NULL) { 10774327Sdougm xmlFree(name); 10784327Sdougm name = NULL; 10794327Sdougm } 10803034Sdougm } 10813034Sdougm } 10823034Sdougm if (name != NULL) 10834327Sdougm xmlFree(name); 10843034Sdougm return (node); 10853034Sdougm } 10863034Sdougm 10873034Sdougm /* 10883034Sdougm * sa_get_group(groupname) 10893034Sdougm * Return the "group" specified. If groupname is NULL, 10903034Sdougm * return the first group of the list of groups. 10913034Sdougm */ 10923034Sdougm sa_group_t 10933910Sdougm sa_get_group(sa_handle_t handle, char *groupname) 10943034Sdougm { 10953034Sdougm xmlNodePtr node = NULL; 10963034Sdougm char *subgroup = NULL; 10973034Sdougm char *group = NULL; 10983910Sdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle; 10993034Sdougm 11003910Sdougm if (impl_handle != NULL && impl_handle->tree != NULL) { 11014327Sdougm if (groupname != NULL) { 11024327Sdougm group = strdup(groupname); 11034345Sdougm if (group != NULL) { 11044345Sdougm subgroup = strchr(group, '/'); 11054345Sdougm if (subgroup != NULL) 11064345Sdougm *subgroup++ = '\0'; 11074345Sdougm } 11084327Sdougm } 11094345Sdougm /* 11104345Sdougm * We want to find the, possibly, named group. If 11114345Sdougm * group is not NULL, then lookup the name. If it is 11124345Sdougm * NULL, we only do the find if groupname is also 11134345Sdougm * NULL. This allows lookup of the "first" group in 11144345Sdougm * the internal list. 11154345Sdougm */ 11164345Sdougm if (group != NULL || groupname == NULL) 11174345Sdougm node = find_group_by_name(impl_handle->tree, 11184345Sdougm (xmlChar *)group); 11194345Sdougm 11204327Sdougm /* if a subgroup, find it before returning */ 11214327Sdougm if (subgroup != NULL && node != NULL) 11224327Sdougm node = find_group_by_name(node, (xmlChar *)subgroup); 11233034Sdougm } 11243034Sdougm if (node != NULL && (char *)group != NULL) 11254327Sdougm (void) sa_get_instance(impl_handle->scfhandle, (char *)group); 11263034Sdougm if (group != NULL) 11274327Sdougm free(group); 11283034Sdougm return ((sa_group_t)(node)); 11293034Sdougm } 11303034Sdougm 11313034Sdougm /* 11323034Sdougm * sa_get_next_group(group) 11333034Sdougm * Return the "next" group after the specified group from 11343034Sdougm * the internal group list. NULL if there are no more. 11353034Sdougm */ 11363034Sdougm sa_group_t 11373034Sdougm sa_get_next_group(sa_group_t group) 11383034Sdougm { 11393034Sdougm xmlNodePtr ngroup = NULL; 11403034Sdougm if (group != NULL) { 11414327Sdougm for (ngroup = ((xmlNodePtr)group)->next; ngroup != NULL; 11423034Sdougm ngroup = ngroup->next) { 11434327Sdougm if (xmlStrcmp(ngroup->name, (xmlChar *)"group") == 0) 11444327Sdougm break; 11454327Sdougm } 11463034Sdougm } 11473034Sdougm return ((sa_group_t)ngroup); 11483034Sdougm } 11493034Sdougm 11503034Sdougm /* 11513034Sdougm * sa_get_share(group, sharepath) 11523034Sdougm * Return the share object for the share specified. The share 11533034Sdougm * must be in the specified group. Return NULL if not found. 11543034Sdougm */ 11553034Sdougm sa_share_t 11563034Sdougm sa_get_share(sa_group_t group, char *sharepath) 11573034Sdougm { 11583034Sdougm xmlNodePtr node = NULL; 11593034Sdougm xmlChar *path; 11603034Sdougm 11613034Sdougm /* 11623034Sdougm * For future scalability, this should end up building a cache 11633034Sdougm * since it will get called regularly by the mountd and info 11643034Sdougm * services. 11653034Sdougm */ 11663034Sdougm if (group != NULL) { 11674327Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 11683034Sdougm node = node->next) { 11694327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) { 11704327Sdougm if (sharepath == NULL) { 11714327Sdougm break; 11724327Sdougm } else { 11734327Sdougm /* is it the correct share? */ 11744327Sdougm path = xmlGetProp(node, 11754327Sdougm (xmlChar *)"path"); 11764327Sdougm if (path != NULL && 11774327Sdougm xmlStrcmp(path, 11784327Sdougm (xmlChar *)sharepath) == 0) { 11794327Sdougm xmlFree(path); 11804327Sdougm break; 11814327Sdougm } 11824327Sdougm xmlFree(path); 11834327Sdougm } 11843034Sdougm } 11853034Sdougm } 11863034Sdougm } 11873034Sdougm return ((sa_share_t)node); 11883034Sdougm } 11893034Sdougm 11903034Sdougm /* 11913034Sdougm * sa_get_next_share(share) 11923034Sdougm * Return the next share following the specified share 11933034Sdougm * from the internal list of shares. Returns NULL if there 11943034Sdougm * are no more shares. The list is relative to the same 11953034Sdougm * group. 11963034Sdougm */ 11973034Sdougm sa_share_t 11983034Sdougm sa_get_next_share(sa_share_t share) 11993034Sdougm { 12003034Sdougm xmlNodePtr node = NULL; 12013034Sdougm 12023034Sdougm if (share != NULL) { 12034327Sdougm for (node = ((xmlNodePtr)share)->next; node != NULL; 12043034Sdougm node = node->next) { 12054327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) { 12064327Sdougm break; 12074327Sdougm } 12083034Sdougm } 12093034Sdougm } 12103034Sdougm return ((sa_share_t)node); 12113034Sdougm } 12123034Sdougm 12133034Sdougm /* 12143034Sdougm * _sa_get_child_node(node, type) 12153034Sdougm * 12163034Sdougm * find the child node of the specified node that has "type". This is 12173034Sdougm * used to implement several internal functions. 12183034Sdougm */ 12193034Sdougm 12203034Sdougm static xmlNodePtr 12213034Sdougm _sa_get_child_node(xmlNodePtr node, xmlChar *type) 12223034Sdougm { 12233034Sdougm xmlNodePtr child; 12243034Sdougm for (child = node->xmlChildrenNode; child != NULL; 12253034Sdougm child = child->next) 12264327Sdougm if (xmlStrcmp(child->name, type) == 0) 12274327Sdougm return (child); 12283034Sdougm return ((xmlNodePtr)NULL); 12293034Sdougm } 12303034Sdougm 12313034Sdougm /* 12323034Sdougm * find_share(group, path) 12333034Sdougm * 12343034Sdougm * Search all the shares in the specified group for one that has the 12353034Sdougm * specified path. 12363034Sdougm */ 12373034Sdougm 12383034Sdougm static sa_share_t 12393034Sdougm find_share(sa_group_t group, char *sharepath) 12403034Sdougm { 12413034Sdougm sa_share_t share; 12423034Sdougm char *path; 12433034Sdougm 12443034Sdougm for (share = sa_get_share(group, NULL); share != NULL; 12453034Sdougm share = sa_get_next_share(share)) { 12464327Sdougm path = sa_get_share_attr(share, "path"); 12474327Sdougm if (path != NULL && strcmp(path, sharepath) == 0) { 12484327Sdougm sa_free_attr_string(path); 12494327Sdougm break; 12504327Sdougm } 12514327Sdougm if (path != NULL) 12524327Sdougm sa_free_attr_string(path); 12533034Sdougm } 12543034Sdougm return (share); 12553034Sdougm } 12563034Sdougm 12573034Sdougm /* 12583034Sdougm * sa_get_sub_group(group) 12593034Sdougm * 12603034Sdougm * Get the first sub-group of group. The sa_get_next_group() function 12613034Sdougm * can be used to get the rest. This is currently only used for ZFS 12623034Sdougm * sub-groups but could be used to implement a more general mechanism. 12633034Sdougm */ 12643034Sdougm 12653034Sdougm sa_group_t 12663034Sdougm sa_get_sub_group(sa_group_t group) 12673034Sdougm { 12683034Sdougm return ((sa_group_t)_sa_get_child_node((xmlNodePtr)group, 12694327Sdougm (xmlChar *)"group")); 12703034Sdougm } 12713034Sdougm 12723034Sdougm /* 12733034Sdougm * sa_find_share(sharepath) 12743034Sdougm * Finds a share regardless of group. In the future, this 12753034Sdougm * function should utilize a cache and hash table of some kind. 12763034Sdougm * The current assumption is that a path will only be shared 12773034Sdougm * once. In the future, this may change as implementation of 12783034Sdougm * resource names comes into being. 12793034Sdougm */ 12803034Sdougm sa_share_t 12813910Sdougm sa_find_share(sa_handle_t handle, char *sharepath) 12823034Sdougm { 12833034Sdougm sa_group_t group; 12843034Sdougm sa_group_t zgroup; 12853034Sdougm sa_share_t share = NULL; 12863034Sdougm int done = 0; 12873034Sdougm 12883910Sdougm for (group = sa_get_group(handle, NULL); group != NULL && !done; 12894327Sdougm group = sa_get_next_group(group)) { 12904327Sdougm if (is_zfs_group(group)) { 12914327Sdougm for (zgroup = 12924327Sdougm (sa_group_t)_sa_get_child_node((xmlNodePtr)group, 12934327Sdougm (xmlChar *)"group"); 12944327Sdougm zgroup != NULL; 12954327Sdougm zgroup = sa_get_next_group(zgroup)) { 12964327Sdougm share = find_share(zgroup, sharepath); 12974327Sdougm if (share != NULL) 12984327Sdougm break; 12994327Sdougm } 13004327Sdougm } else { 13014327Sdougm share = find_share(group, sharepath); 13024327Sdougm } 13034327Sdougm if (share != NULL) 13043034Sdougm break; 13053034Sdougm } 13063034Sdougm return (share); 13073034Sdougm } 13083034Sdougm 13093034Sdougm /* 13103348Sdougm * sa_check_path(group, path, strictness) 13113034Sdougm * 13125331Samw * Check that path is a valid path relative to the group. Currently, 13133034Sdougm * we are ignoring the group and checking only the NFS rules. Later, 13143034Sdougm * we may want to use the group to then check against the protocols 13153348Sdougm * enabled on the group. The strictness values mean: 13163348Sdougm * SA_CHECK_NORMAL == only check newpath against shares that are active 13173348Sdougm * SA_CHECK_STRICT == check newpath against both active shares and those 13183348Sdougm * stored in the repository 13193034Sdougm */ 13203034Sdougm 13213034Sdougm int 13223348Sdougm sa_check_path(sa_group_t group, char *path, int strictness) 13233034Sdougm { 13243910Sdougm sa_handle_t handle; 13253910Sdougm 13263910Sdougm handle = sa_find_group_handle(group); 13273910Sdougm return (validpath(handle, path, strictness)); 13283034Sdougm } 13293034Sdougm 13303034Sdougm /* 13315331Samw * mark_excluded_protos(group, share, flags) 13323034Sdougm * 13335331Samw * Walk through all the protocols enabled for the group and check to 13345331Samw * see if the share has any of them should be in the exclude list 13355331Samw * based on the featureset of the protocol. If there are any, add the 13365331Samw * "exclude" property to the share. 13375331Samw */ 13385331Samw static void 13395331Samw mark_excluded_protos(sa_group_t group, xmlNodePtr share, uint64_t flags) 13405331Samw { 13415331Samw sa_optionset_t optionset; 13425331Samw char exclude_list[SA_STRSIZE]; 13435331Samw char *sep = ""; 13445331Samw 13455331Samw exclude_list[0] = '\0'; 13465331Samw for (optionset = sa_get_optionset(group, NULL); 13475331Samw optionset != NULL; 13485331Samw optionset = sa_get_next_optionset(optionset)) { 13495331Samw char *value; 13505331Samw uint64_t features; 13515331Samw value = sa_get_optionset_attr(optionset, "type"); 13525331Samw if (value == NULL) 13535331Samw continue; 13545331Samw features = sa_proto_get_featureset(value); 13555331Samw sa_free_attr_string(value); 13565331Samw if (!(features & flags)) { 13575331Samw (void) strlcat(exclude_list, sep, 13585331Samw sizeof (exclude_list)); 13595331Samw (void) strlcat(exclude_list, value, 13605331Samw sizeof (exclude_list)); 13615331Samw sep = ","; 13625331Samw } 13635331Samw } 13645331Samw if (exclude_list[0] != '\0') 13655331Samw xmlSetProp(share, (xmlChar *)"exclude", 13665331Samw (xmlChar *)exclude_list); 13675331Samw } 13685331Samw 13695331Samw /* 13705331Samw * get_all_features(group) 13715331Samw * 13725331Samw * Walk through all the protocols on the group and collect all 13735331Samw * possible enabled features. This is the OR of all the featuresets. 13745331Samw */ 13755331Samw static uint64_t 13765331Samw get_all_features(sa_group_t group) 13775331Samw { 13785331Samw sa_optionset_t optionset; 13795331Samw uint64_t features = 0; 13805331Samw 13815331Samw for (optionset = sa_get_optionset(group, NULL); 13825331Samw optionset != NULL; 13835331Samw optionset = sa_get_next_optionset(optionset)) { 13845331Samw char *value; 13855331Samw value = sa_get_optionset_attr(optionset, "type"); 13865331Samw if (value == NULL) 13875331Samw continue; 13885331Samw features |= sa_proto_get_featureset(value); 13895331Samw sa_free_attr_string(value); 13905331Samw } 13915331Samw return (features); 13925331Samw } 13935331Samw 13945331Samw 13955331Samw /* 13965331Samw * _sa_add_share(group, sharepath, persist, *error, flags) 13975331Samw * 13985331Samw * Common code for all types of add_share. sa_add_share() is the 13993034Sdougm * public API, we also need to be able to do this when parsing legacy 14003034Sdougm * files and construction of the internal configuration while 14015331Samw * extracting config info from SMF. "flags" indicates if some 14025331Samw * protocols need relaxed rules while other don't. These values are 14035331Samw * the featureset values defined in libshare.h. 14043034Sdougm */ 14053034Sdougm 14063034Sdougm sa_share_t 14075331Samw _sa_add_share(sa_group_t group, char *sharepath, int persist, int *error, 14085331Samw uint64_t flags) 14093034Sdougm { 14103034Sdougm xmlNodePtr node = NULL; 14113034Sdougm int err; 14123034Sdougm 14133034Sdougm err = SA_OK; /* assume success */ 14143034Sdougm 14154327Sdougm node = xmlNewChild((xmlNodePtr)group, NULL, (xmlChar *)"share", NULL); 14165331Samw if (node == NULL) { 14175331Samw if (error != NULL) 14185331Samw *error = SA_NO_MEMORY; 14195331Samw return (node); 14205331Samw } 14215331Samw 14225331Samw xmlSetProp(node, (xmlChar *)"path", (xmlChar *)sharepath); 14235331Samw xmlSetProp(node, (xmlChar *)"type", 14245331Samw persist ? (xmlChar *)"persist" : (xmlChar *)"transient"); 14255331Samw if (flags != 0) 14265331Samw mark_excluded_protos(group, node, flags); 14275331Samw if (persist != SA_SHARE_TRANSIENT) { 14285331Samw /* 14295331Samw * persistent shares come in two flavors: SMF and 14305331Samw * ZFS. Sort this one out based on target group and 14315331Samw * path type. Both NFS and SMB are supported. First, 14325331Samw * check to see if the protocol is enabled on the 14335331Samw * subgroup and then setup the share appropriately. 14345331Samw */ 14355331Samw if (sa_group_is_zfs(group) && 14365331Samw sa_path_is_zfs(sharepath)) { 14375331Samw if (sa_get_optionset(group, "nfs") != NULL) 14384327Sdougm err = sa_zfs_set_sharenfs(group, sharepath, 1); 14395331Samw else if (sa_get_optionset(group, "smb") != NULL) 14405331Samw err = sa_zfs_set_sharesmb(group, sharepath, 1); 14415331Samw } else { 14425331Samw sa_handle_impl_t impl_handle; 14435331Samw impl_handle = 14445331Samw (sa_handle_impl_t)sa_find_group_handle(group); 14455331Samw if (impl_handle != NULL) { 14465331Samw err = sa_commit_share(impl_handle->scfhandle, 14475331Samw group, (sa_share_t)node); 14484327Sdougm } else { 14495331Samw err = SA_SYSTEM_ERR; 14504327Sdougm } 14513034Sdougm } 14523034Sdougm } 14535331Samw if (err == SA_NO_PERMISSION && persist & SA_SHARE_PARSER) 14545331Samw /* called by the dfstab parser so could be a show */ 14555331Samw err = SA_OK; 14565331Samw 14575331Samw if (err != SA_OK) { 14585331Samw /* 14595331Samw * we couldn't commit to the repository so undo 14605331Samw * our internal state to reflect reality. 14615331Samw */ 14625331Samw xmlUnlinkNode(node); 14635331Samw xmlFreeNode(node); 14645331Samw node = NULL; 14655331Samw } 14665331Samw 14673034Sdougm if (error != NULL) 14684327Sdougm *error = err; 14695331Samw 14703034Sdougm return (node); 14713034Sdougm } 14723034Sdougm 14733034Sdougm /* 14743034Sdougm * sa_add_share(group, sharepath, persist, *error) 14753034Sdougm * 14763034Sdougm * Add a new share object to the specified group. The share will 14773034Sdougm * have the specified sharepath and will only be constructed if 14783034Sdougm * it is a valid path to be shared. NULL is returned on error 14793034Sdougm * and a detailed error value will be returned via the error 14803034Sdougm * pointer. 14813034Sdougm */ 14823034Sdougm sa_share_t 14833034Sdougm sa_add_share(sa_group_t group, char *sharepath, int persist, int *error) 14843034Sdougm { 14853034Sdougm xmlNodePtr node = NULL; 14863348Sdougm int strictness = SA_CHECK_NORMAL; 14873910Sdougm sa_handle_t handle; 14885331Samw uint64_t special = 0; 14895331Samw uint64_t features; 14903348Sdougm 14913348Sdougm /* 14923348Sdougm * If the share is to be permanent, use strict checking so a 14933348Sdougm * bad config doesn't get created. Transient shares only need 14943348Sdougm * to check against the currently active 14953348Sdougm * shares. SA_SHARE_PARSER is a modifier used internally to 14963348Sdougm * indicate that we are being called by the dfstab parser and 14973348Sdougm * that we need strict checking in all cases. Normally persist 14983348Sdougm * is in integer value but SA_SHARE_PARSER may be or'd into 14993348Sdougm * it as an override. 15003348Sdougm */ 15013348Sdougm if (persist & SA_SHARE_PARSER || persist == SA_SHARE_PERMANENT) 15024327Sdougm strictness = SA_CHECK_STRICT; 15033034Sdougm 15043910Sdougm handle = sa_find_group_handle(group); 15053910Sdougm 15065331Samw /* 15075331Samw * need to determine if the share is valid. The rules are: 15085331Samw * - The path must not already exist 15095331Samw * - The path must not be a subdir or parent dir of an 15105331Samw * existing path unless at least one protocol allows it. 15115331Samw * The sub/parent check is done in sa_check_path(). 15125331Samw */ 15135331Samw 15145331Samw if (sa_find_share(handle, sharepath) == NULL) { 15155331Samw *error = sa_check_path(group, sharepath, strictness); 15165331Samw features = get_all_features(group); 15175331Samw switch (*error) { 15185331Samw case SA_PATH_IS_SUBDIR: 15195331Samw if (features & SA_FEATURE_ALLOWSUBDIRS) 15205331Samw special |= SA_FEATURE_ALLOWSUBDIRS; 15215331Samw break; 15225331Samw case SA_PATH_IS_PARENTDIR: 15235331Samw if (features & SA_FEATURE_ALLOWPARDIRS) 15245331Samw special |= SA_FEATURE_ALLOWPARDIRS; 15255331Samw break; 15265331Samw } 15275331Samw if (*error == SA_OK || special != SA_FEATURE_NONE) 15285331Samw node = _sa_add_share(group, sharepath, persist, 15295331Samw error, special); 15305331Samw } else { 15315331Samw *error = SA_DUPLICATE_NAME; 15323034Sdougm } 15333034Sdougm 15343034Sdougm return ((sa_share_t)node); 15353034Sdougm } 15363034Sdougm 15373034Sdougm /* 15383034Sdougm * sa_enable_share(share, protocol) 15393034Sdougm * Enable the specified share to the specified protocol. 15403034Sdougm * If protocol is NULL, then all protocols. 15413034Sdougm */ 15423034Sdougm int 15433034Sdougm sa_enable_share(sa_share_t share, char *protocol) 15443034Sdougm { 15453034Sdougm char *sharepath; 15463034Sdougm struct stat st; 15475331Samw int err = SA_OK; 15485331Samw int ret; 15493034Sdougm 15503034Sdougm sharepath = sa_get_share_attr(share, "path"); 15515331Samw if (sharepath == NULL) 15525331Samw return (SA_NO_MEMORY); 15533034Sdougm if (stat(sharepath, &st) < 0) { 15544327Sdougm err = SA_NO_SUCH_PATH; 15553034Sdougm } else { 15564327Sdougm /* tell the server about the share */ 15574327Sdougm if (protocol != NULL) { 15585331Samw if (excluded_protocol(share, protocol)) 15595331Samw goto done; 15605331Samw 15614327Sdougm /* lookup protocol specific handler */ 15624327Sdougm err = sa_proto_share(protocol, share); 15634327Sdougm if (err == SA_OK) 15645331Samw (void) sa_set_share_attr(share, 15655331Samw "shared", "true"); 15664327Sdougm } else { 15675331Samw /* Tell all protocols about the share */ 15685331Samw sa_group_t group; 15695331Samw sa_optionset_t optionset; 15705331Samw 15715331Samw group = sa_get_parent_group(share); 15725331Samw 15735331Samw for (optionset = sa_get_optionset(group, NULL); 15745331Samw optionset != NULL; 15755331Samw optionset = sa_get_next_optionset(optionset)) { 15765331Samw char *proto; 15775331Samw proto = sa_get_optionset_attr(optionset, 15785331Samw "type"); 15795331Samw if (proto != NULL) { 15805331Samw if (!excluded_protocol(share, proto)) { 15815331Samw ret = sa_proto_share(proto, 15825331Samw share); 15835331Samw if (ret != SA_OK) 15845331Samw err = ret; 15855331Samw } 15865331Samw sa_free_attr_string(proto); 15875331Samw } 15885331Samw } 15894327Sdougm (void) sa_set_share_attr(share, "shared", "true"); 15904327Sdougm } 15913034Sdougm } 15925331Samw done: 15933034Sdougm if (sharepath != NULL) 15944327Sdougm sa_free_attr_string(sharepath); 15953034Sdougm return (err); 15963034Sdougm } 15973034Sdougm 15983034Sdougm /* 15993034Sdougm * sa_disable_share(share, protocol) 16005331Samw * Disable the specified share to the specified protocol. If 16015331Samw * protocol is NULL, then all protocols that are enabled for the 16025331Samw * share should be disabled. 16033034Sdougm */ 16043034Sdougm int 16053034Sdougm sa_disable_share(sa_share_t share, char *protocol) 16063034Sdougm { 16073034Sdougm char *path; 16085331Samw int err = SA_OK; 16093034Sdougm int ret = SA_OK; 16103034Sdougm 16113034Sdougm path = sa_get_share_attr(share, "path"); 16123034Sdougm 16133034Sdougm if (protocol != NULL) { 16144543Smarks ret = sa_proto_unshare(share, protocol, path); 16153034Sdougm } else { 16164327Sdougm /* need to do all protocols */ 16175331Samw sa_group_t group; 16185331Samw sa_optionset_t optionset; 16195331Samw 16205331Samw group = sa_get_parent_group(share); 16215331Samw 16225331Samw /* Tell all protocols about the share */ 16235331Samw for (optionset = sa_get_optionset(group, NULL); 16245331Samw optionset != NULL; 16255331Samw optionset = sa_get_next_optionset(optionset)) { 16265331Samw char *proto; 16275331Samw 16285331Samw proto = sa_get_optionset_attr(optionset, "type"); 16295331Samw if (proto != NULL) { 16305331Samw err = sa_proto_unshare(share, proto, path); 16315331Samw if (err != SA_OK) 16325331Samw ret = err; 16335331Samw sa_free_attr_string(proto); 16345331Samw } 16355331Samw } 16363034Sdougm } 16373034Sdougm if (ret == SA_OK) 16383034Sdougm (void) sa_set_share_attr(share, "shared", NULL); 16393034Sdougm if (path != NULL) 16404327Sdougm sa_free_attr_string(path); 16413034Sdougm return (ret); 16423034Sdougm } 16433034Sdougm 16443034Sdougm /* 16453034Sdougm * sa_remove_share(share) 16463034Sdougm * 16473034Sdougm * remove the specified share from its containing group. 16483034Sdougm * Remove from the SMF or ZFS configuration space. 16493034Sdougm */ 16503034Sdougm 16513034Sdougm int 16523034Sdougm sa_remove_share(sa_share_t share) 16533034Sdougm { 16543034Sdougm sa_group_t group; 16553034Sdougm int ret = SA_OK; 16563034Sdougm char *type; 16573034Sdougm int transient = 0; 16583034Sdougm char *groupname; 16593034Sdougm char *zfs; 16603034Sdougm 16613034Sdougm type = sa_get_share_attr(share, "type"); 16623034Sdougm group = sa_get_parent_group(share); 16633034Sdougm zfs = sa_get_group_attr(group, "zfs"); 16643034Sdougm groupname = sa_get_group_attr(group, "name"); 16653034Sdougm if (type != NULL && strcmp(type, "persist") != 0) 16664327Sdougm transient = 1; 16673034Sdougm if (type != NULL) 16684327Sdougm sa_free_attr_string(type); 16693034Sdougm 16703034Sdougm /* remove the node from its group then free the memory */ 16713034Sdougm 16723034Sdougm /* 16733034Sdougm * need to test if "busy" 16743034Sdougm */ 16753034Sdougm /* only do SMF action if permanent */ 16763034Sdougm if (!transient || zfs != NULL) { 16774327Sdougm /* remove from legacy dfstab as well as possible SMF */ 16785331Samw ret = sa_delete_legacy(share, NULL); 16794327Sdougm if (ret == SA_OK) { 16804327Sdougm if (!sa_group_is_zfs(group)) { 16814327Sdougm sa_handle_impl_t impl_handle; 16824327Sdougm impl_handle = (sa_handle_impl_t) 16834327Sdougm sa_find_group_handle(group); 16844327Sdougm if (impl_handle != NULL) { 16854327Sdougm ret = sa_delete_share( 16864327Sdougm impl_handle->scfhandle, group, 16874327Sdougm share); 16884327Sdougm } else { 16894327Sdougm ret = SA_SYSTEM_ERR; 16904327Sdougm } 16914327Sdougm } else { 16924327Sdougm char *sharepath = sa_get_share_attr(share, 16934327Sdougm "path"); 16944327Sdougm if (sharepath != NULL) { 16954327Sdougm ret = sa_zfs_set_sharenfs(group, 16964327Sdougm sharepath, 0); 16974327Sdougm sa_free_attr_string(sharepath); 16984327Sdougm } 16994327Sdougm } 17003034Sdougm } 17013034Sdougm } 17023034Sdougm if (groupname != NULL) 17034327Sdougm sa_free_attr_string(groupname); 17043034Sdougm if (zfs != NULL) 17054327Sdougm sa_free_attr_string(zfs); 17063034Sdougm 17073034Sdougm xmlUnlinkNode((xmlNodePtr)share); 17083034Sdougm xmlFreeNode((xmlNodePtr)share); 17093034Sdougm return (ret); 17103034Sdougm } 17113034Sdougm 17123034Sdougm /* 17133034Sdougm * sa_move_share(group, share) 17143034Sdougm * 17153034Sdougm * move the specified share to the specified group. Update SMF 17163034Sdougm * appropriately. 17173034Sdougm */ 17183034Sdougm 17193034Sdougm int 17203034Sdougm sa_move_share(sa_group_t group, sa_share_t share) 17213034Sdougm { 17223034Sdougm sa_group_t oldgroup; 17233034Sdougm int ret = SA_OK; 17243034Sdougm 17253034Sdougm /* remove the node from its group then free the memory */ 17263034Sdougm 17273034Sdougm oldgroup = sa_get_parent_group(share); 17283034Sdougm if (oldgroup != group) { 17294327Sdougm sa_handle_impl_t impl_handle; 17304327Sdougm xmlUnlinkNode((xmlNodePtr)share); 17313034Sdougm /* 17324327Sdougm * now that the share isn't in its old group, add to 17334327Sdougm * the new one 17343034Sdougm */ 17354327Sdougm xmlAddChild((xmlNodePtr)group, (xmlNodePtr)share); 17364327Sdougm /* need to deal with SMF */ 17374327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 17384327Sdougm if (impl_handle != NULL) { 17394327Sdougm /* 17404327Sdougm * need to remove from old group first and then add to 17414327Sdougm * new group. Ideally, we would do the other order but 17424327Sdougm * need to avoid having the share in two groups at the 17434327Sdougm * same time. 17444327Sdougm */ 17454327Sdougm ret = sa_delete_share(impl_handle->scfhandle, oldgroup, 17464327Sdougm share); 17474327Sdougm if (ret == SA_OK) 17484327Sdougm ret = sa_commit_share(impl_handle->scfhandle, 17494327Sdougm group, share); 17504327Sdougm } else { 17514327Sdougm ret = SA_SYSTEM_ERR; 17524327Sdougm } 17533034Sdougm } 17543034Sdougm return (ret); 17553034Sdougm } 17563034Sdougm 17573034Sdougm /* 17583034Sdougm * sa_get_parent_group(share) 17593034Sdougm * 17605331Samw * Return the containing group for the share. If a group was actually 17613034Sdougm * passed in, we don't want a parent so return NULL. 17623034Sdougm */ 17633034Sdougm 17643034Sdougm sa_group_t 17653034Sdougm sa_get_parent_group(sa_share_t share) 17663034Sdougm { 17673034Sdougm xmlNodePtr node = NULL; 17683034Sdougm if (share != NULL) { 17694327Sdougm node = ((xmlNodePtr)share)->parent; 17703034Sdougm /* 17713034Sdougm * make sure parent is a group and not sharecfg since 17723034Sdougm * we may be cheating and passing in a group. 17733034Sdougm * Eventually, groups of groups might come into being. 17743034Sdougm */ 17754327Sdougm if (node == NULL || 17764327Sdougm xmlStrcmp(node->name, (xmlChar *)"sharecfg") == 0) 17774327Sdougm node = NULL; 17783034Sdougm } 17793034Sdougm return ((sa_group_t)node); 17803034Sdougm } 17813034Sdougm 17823034Sdougm /* 17833910Sdougm * _sa_create_group(impl_handle, groupname) 17843034Sdougm * 17853034Sdougm * Create a group in the document. The caller will need to deal with 17863034Sdougm * configuration store and activation. 17873034Sdougm */ 17883034Sdougm 17893034Sdougm sa_group_t 17903910Sdougm _sa_create_group(sa_handle_impl_t impl_handle, char *groupname) 17913034Sdougm { 17923034Sdougm xmlNodePtr node = NULL; 17933034Sdougm 17943034Sdougm if (sa_valid_group_name(groupname)) { 17954327Sdougm node = xmlNewChild(impl_handle->tree, NULL, (xmlChar *)"group", 17964327Sdougm NULL); 17974327Sdougm if (node != NULL) { 17984327Sdougm xmlSetProp(node, (xmlChar *)"name", 17994327Sdougm (xmlChar *)groupname); 18004327Sdougm xmlSetProp(node, (xmlChar *)"state", 18014327Sdougm (xmlChar *)"enabled"); 18024327Sdougm } 18033034Sdougm } 18043034Sdougm return ((sa_group_t)node); 18053034Sdougm } 18063034Sdougm 18073034Sdougm /* 18083034Sdougm * _sa_create_zfs_group(group, groupname) 18093034Sdougm * 18103034Sdougm * Create a ZFS subgroup under the specified group. This may 18113034Sdougm * eventually form the basis of general sub-groups, but is currently 18123034Sdougm * restricted to ZFS. 18133034Sdougm */ 18143034Sdougm sa_group_t 18153034Sdougm _sa_create_zfs_group(sa_group_t group, char *groupname) 18163034Sdougm { 18173034Sdougm xmlNodePtr node = NULL; 18183034Sdougm 18194327Sdougm node = xmlNewChild((xmlNodePtr)group, NULL, (xmlChar *)"group", NULL); 18203034Sdougm if (node != NULL) { 18213034Sdougm xmlSetProp(node, (xmlChar *)"name", (xmlChar *)groupname); 18223034Sdougm xmlSetProp(node, (xmlChar *)"state", (xmlChar *)"enabled"); 18233034Sdougm } 18243034Sdougm 18253034Sdougm return ((sa_group_t)node); 18263034Sdougm } 18273034Sdougm 18283034Sdougm /* 18293034Sdougm * sa_create_group(groupname, *error) 18303034Sdougm * 18313034Sdougm * Create a new group with groupname. Need to validate that it is a 18323034Sdougm * legal name for SMF and the construct the SMF service instance of 18333034Sdougm * svc:/network/shares/group to implement the group. All necessary 18343034Sdougm * operational properties must be added to the group at this point 18353034Sdougm * (via the SMF transaction model). 18363034Sdougm */ 18373034Sdougm sa_group_t 18383910Sdougm sa_create_group(sa_handle_t handle, char *groupname, int *error) 18393034Sdougm { 18403034Sdougm xmlNodePtr node = NULL; 18413034Sdougm sa_group_t group; 18423034Sdougm int ret; 18434327Sdougm char rbacstr[SA_STRSIZE]; 18443910Sdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle; 18453034Sdougm 18463034Sdougm ret = SA_OK; 18473034Sdougm 18483910Sdougm if (impl_handle == NULL || impl_handle->scfhandle == NULL) { 18494327Sdougm ret = SA_SYSTEM_ERR; 18504327Sdougm goto err; 18513034Sdougm } 18523034Sdougm 18533910Sdougm group = sa_get_group(handle, groupname); 18543034Sdougm if (group != NULL) { 18554327Sdougm ret = SA_DUPLICATE_NAME; 18563034Sdougm } else { 18574327Sdougm if (sa_valid_group_name(groupname)) { 18584327Sdougm node = xmlNewChild(impl_handle->tree, NULL, 18594327Sdougm (xmlChar *)"group", NULL); 18604327Sdougm if (node != NULL) { 18614327Sdougm xmlSetProp(node, (xmlChar *)"name", 18624327Sdougm (xmlChar *)groupname); 18634327Sdougm /* default to the group being enabled */ 18644327Sdougm xmlSetProp(node, (xmlChar *)"state", 18654327Sdougm (xmlChar *)"enabled"); 18664327Sdougm ret = sa_create_instance(impl_handle->scfhandle, 18674327Sdougm groupname); 18684327Sdougm if (ret == SA_OK) { 18694327Sdougm ret = sa_start_transaction( 18704327Sdougm impl_handle->scfhandle, 18714327Sdougm "operation"); 18724327Sdougm } 18734327Sdougm if (ret == SA_OK) { 18744327Sdougm ret = sa_set_property( 18754327Sdougm impl_handle->scfhandle, 18764327Sdougm "state", "enabled"); 18774327Sdougm if (ret == SA_OK) { 18784327Sdougm ret = sa_end_transaction( 18794327Sdougm impl_handle->scfhandle); 18804327Sdougm } else { 18814327Sdougm sa_abort_transaction( 18824327Sdougm impl_handle->scfhandle); 18834327Sdougm } 18844327Sdougm } 18854327Sdougm if (ret == SA_OK) { 18864327Sdougm /* initialize the RBAC strings */ 18874327Sdougm ret = sa_start_transaction( 18884327Sdougm impl_handle->scfhandle, 18894327Sdougm "general"); 18904327Sdougm if (ret == SA_OK) { 18914327Sdougm (void) snprintf(rbacstr, 18924327Sdougm sizeof (rbacstr), "%s.%s", 18934327Sdougm SA_RBAC_MANAGE, groupname); 18944327Sdougm ret = sa_set_property( 18954327Sdougm impl_handle->scfhandle, 18963034Sdougm "action_authorization", 18973034Sdougm rbacstr); 18984327Sdougm } 18994327Sdougm if (ret == SA_OK) { 19004327Sdougm (void) snprintf(rbacstr, 19014327Sdougm sizeof (rbacstr), "%s.%s", 19024327Sdougm SA_RBAC_VALUE, groupname); 19034327Sdougm ret = sa_set_property( 19044327Sdougm impl_handle->scfhandle, 19053034Sdougm "value_authorization", 19063034Sdougm rbacstr); 19074327Sdougm } 19084327Sdougm if (ret == SA_OK) { 19094327Sdougm ret = sa_end_transaction( 19104327Sdougm impl_handle->scfhandle); 19114327Sdougm } else { 19124327Sdougm sa_abort_transaction( 19134327Sdougm impl_handle->scfhandle); 19144327Sdougm } 19154327Sdougm } 19164327Sdougm if (ret != SA_OK) { 19174327Sdougm /* 19184327Sdougm * Couldn't commit the group 19194327Sdougm * so we need to undo 19204327Sdougm * internally. 19214327Sdougm */ 19224327Sdougm xmlUnlinkNode(node); 19234327Sdougm xmlFreeNode(node); 19244327Sdougm node = NULL; 19254327Sdougm } 19263034Sdougm } else { 19274327Sdougm ret = SA_NO_MEMORY; 19283034Sdougm } 19293034Sdougm } else { 19304327Sdougm ret = SA_INVALID_NAME; 19313034Sdougm } 19323034Sdougm } 19333034Sdougm err: 19343034Sdougm if (error != NULL) 19354327Sdougm *error = ret; 19363034Sdougm return ((sa_group_t)node); 19373034Sdougm } 19383034Sdougm 19393034Sdougm /* 19403034Sdougm * sa_remove_group(group) 19413034Sdougm * 19423034Sdougm * Remove the specified group. This deletes from the SMF repository. 19433034Sdougm * All property groups and properties are removed. 19443034Sdougm */ 19453034Sdougm 19463034Sdougm int 19473034Sdougm sa_remove_group(sa_group_t group) 19483034Sdougm { 19493034Sdougm char *name; 19503034Sdougm int ret = SA_OK; 19513910Sdougm sa_handle_impl_t impl_handle; 19523034Sdougm 19533910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 19543910Sdougm if (impl_handle != NULL) { 19554327Sdougm name = sa_get_group_attr(group, "name"); 19564327Sdougm if (name != NULL) { 19574327Sdougm ret = sa_delete_instance(impl_handle->scfhandle, name); 19584327Sdougm sa_free_attr_string(name); 19594327Sdougm } 19604327Sdougm xmlUnlinkNode((xmlNodePtr)group); /* make sure unlinked */ 19614327Sdougm xmlFreeNode((xmlNodePtr)group); /* now it is gone */ 19623910Sdougm } else { 19634327Sdougm ret = SA_SYSTEM_ERR; 19643034Sdougm } 19653034Sdougm return (ret); 19663034Sdougm } 19673034Sdougm 19683034Sdougm /* 19693034Sdougm * sa_update_config() 19703034Sdougm * 19713034Sdougm * Used to update legacy files that need to be updated in bulk 19723034Sdougm * Currently, this is a placeholder and will go away in a future 19733034Sdougm * release. 19743034Sdougm */ 19753034Sdougm 19763034Sdougm int 19773910Sdougm sa_update_config(sa_handle_t handle) 19783034Sdougm { 19793034Sdougm /* 19803034Sdougm * do legacy files first so we can tell when they change. 19813034Sdougm * This will go away when we start updating individual records 19823034Sdougm * rather than the whole file. 19833034Sdougm */ 19843910Sdougm update_legacy_config(handle); 19853034Sdougm return (SA_OK); 19863034Sdougm } 19873034Sdougm 19883034Sdougm /* 19893034Sdougm * get_node_attr(node, tag) 19903034Sdougm * 19915331Samw * Get the specified tag(attribute) if it exists on the node. This is 19923034Sdougm * used internally by a number of attribute oriented functions. 19933034Sdougm */ 19943034Sdougm 19953034Sdougm static char * 19963034Sdougm get_node_attr(void *nodehdl, char *tag) 19973034Sdougm { 19983034Sdougm xmlNodePtr node = (xmlNodePtr)nodehdl; 19993034Sdougm xmlChar *name = NULL; 20003034Sdougm 20014327Sdougm if (node != NULL) 20023034Sdougm name = xmlGetProp(node, (xmlChar *)tag); 20033034Sdougm return ((char *)name); 20043034Sdougm } 20053034Sdougm 20063034Sdougm /* 20073034Sdougm * get_node_attr(node, tag) 20083034Sdougm * 20095331Samw * Set the specified tag(attribute) to the specified value This is 20103034Sdougm * used internally by a number of attribute oriented functions. It 20113034Sdougm * doesn't update the repository, only the internal document state. 20123034Sdougm */ 20133034Sdougm 20143034Sdougm void 20153034Sdougm set_node_attr(void *nodehdl, char *tag, char *value) 20163034Sdougm { 20173034Sdougm xmlNodePtr node = (xmlNodePtr)nodehdl; 20183034Sdougm if (node != NULL && tag != NULL) { 20194327Sdougm if (value != NULL) 20203034Sdougm xmlSetProp(node, (xmlChar *)tag, (xmlChar *)value); 20214327Sdougm else 20223034Sdougm xmlUnsetProp(node, (xmlChar *)tag); 20233034Sdougm } 20243034Sdougm } 20253034Sdougm 20263034Sdougm /* 20273034Sdougm * sa_get_group_attr(group, tag) 20283034Sdougm * 20293034Sdougm * Get the specied attribute, if defined, for the group. 20303034Sdougm */ 20313034Sdougm 20323034Sdougm char * 20333034Sdougm sa_get_group_attr(sa_group_t group, char *tag) 20343034Sdougm { 20353034Sdougm return (get_node_attr((void *)group, tag)); 20363034Sdougm } 20373034Sdougm 20383034Sdougm /* 20393034Sdougm * sa_set_group_attr(group, tag, value) 20403034Sdougm * 20413034Sdougm * set the specified tag/attribute on the group using value as its 20423034Sdougm * value. 20433034Sdougm * 20443034Sdougm * This will result in setting the property in the SMF repository as 20453034Sdougm * well as in the internal document. 20463034Sdougm */ 20473034Sdougm 20483034Sdougm int 20493034Sdougm sa_set_group_attr(sa_group_t group, char *tag, char *value) 20503034Sdougm { 20513034Sdougm int ret; 20523034Sdougm char *groupname; 20533910Sdougm sa_handle_impl_t impl_handle; 20543034Sdougm 20555331Samw /* 20565331Samw * ZFS group/subgroup doesn't need the handle so shortcut. 20575331Samw */ 20585331Samw if (sa_group_is_zfs(group)) { 20595331Samw set_node_attr((void *)group, tag, value); 20605331Samw return (SA_OK); 20615331Samw } 20625331Samw 20633910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 20643910Sdougm if (impl_handle != NULL) { 20654327Sdougm groupname = sa_get_group_attr(group, "name"); 20664327Sdougm ret = sa_get_instance(impl_handle->scfhandle, groupname); 20673910Sdougm if (ret == SA_OK) { 20684327Sdougm set_node_attr((void *)group, tag, value); 20694327Sdougm ret = sa_start_transaction(impl_handle->scfhandle, 20704327Sdougm "operation"); 20714327Sdougm if (ret == SA_OK) { 20724327Sdougm ret = sa_set_property(impl_handle->scfhandle, 20734327Sdougm tag, value); 20744327Sdougm if (ret == SA_OK) 2075*5885Sdougm ret = sa_end_transaction( 20764327Sdougm impl_handle->scfhandle); 20774327Sdougm else 20784327Sdougm sa_abort_transaction( 20794327Sdougm impl_handle->scfhandle); 20804327Sdougm } 2081*5885Sdougm if (ret == SA_SYSTEM_ERR) 2082*5885Sdougm ret = SA_NO_PERMISSION; 20833034Sdougm } 20844327Sdougm if (groupname != NULL) 20854327Sdougm sa_free_attr_string(groupname); 20863910Sdougm } else { 20874327Sdougm ret = SA_SYSTEM_ERR; 20883034Sdougm } 20893034Sdougm return (ret); 20903034Sdougm } 20913034Sdougm 20923034Sdougm /* 20933034Sdougm * sa_get_share_attr(share, tag) 20943034Sdougm * 20953034Sdougm * Return the value of the tag/attribute set on the specified 20963034Sdougm * share. Returns NULL if the tag doesn't exist. 20973034Sdougm */ 20983034Sdougm 20993034Sdougm char * 21003034Sdougm sa_get_share_attr(sa_share_t share, char *tag) 21013034Sdougm { 21023034Sdougm return (get_node_attr((void *)share, tag)); 21033034Sdougm } 21043034Sdougm 21053034Sdougm /* 21063034Sdougm * _sa_set_share_description(share, description) 21073034Sdougm * 21085331Samw * Add a description tag with text contents to the specified share. A 21095331Samw * separate XML tag is used rather than a property. This can also be 21105331Samw * used with resources. 21113034Sdougm */ 21123034Sdougm 21133034Sdougm xmlNodePtr 21145331Samw _sa_set_share_description(void *share, char *content) 21153034Sdougm { 21163034Sdougm xmlNodePtr node; 21174327Sdougm node = xmlNewChild((xmlNodePtr)share, NULL, (xmlChar *)"description", 21184327Sdougm NULL); 21193034Sdougm xmlNodeSetContent(node, (xmlChar *)content); 21203034Sdougm return (node); 21213034Sdougm } 21223034Sdougm 21233034Sdougm /* 21243034Sdougm * sa_set_share_attr(share, tag, value) 21253034Sdougm * 21263034Sdougm * Set the share attribute specified by tag to the specified value. In 21273034Sdougm * the case of "resource", enforce a no duplicates in a group rule. If 21283034Sdougm * the share is not transient, commit the changes to the repository 21293034Sdougm * else just update the share internally. 21303034Sdougm */ 21313034Sdougm 21323034Sdougm int 21333034Sdougm sa_set_share_attr(sa_share_t share, char *tag, char *value) 21343034Sdougm { 21353034Sdougm sa_group_t group; 21363034Sdougm sa_share_t resource; 21373034Sdougm int ret = SA_OK; 21383034Sdougm 21393034Sdougm group = sa_get_parent_group(share); 21403034Sdougm 21413034Sdougm /* 21423034Sdougm * There are some attributes that may have specific 21433034Sdougm * restrictions on them. Initially, only "resource" has 21443034Sdougm * special meaning that needs to be checked. Only one instance 21453034Sdougm * of a resource name may exist within a group. 21463034Sdougm */ 21473034Sdougm 21483034Sdougm if (strcmp(tag, "resource") == 0) { 21494327Sdougm resource = sa_get_resource(group, value); 21504327Sdougm if (resource != share && resource != NULL) 21514327Sdougm ret = SA_DUPLICATE_NAME; 21523034Sdougm } 21533034Sdougm if (ret == SA_OK) { 21544327Sdougm set_node_attr((void *)share, tag, value); 21554327Sdougm if (group != NULL) { 21564327Sdougm char *type; 21574327Sdougm /* we can probably optimize this some */ 21584327Sdougm type = sa_get_share_attr(share, "type"); 21594327Sdougm if (type == NULL || strcmp(type, "transient") != 0) { 21604327Sdougm sa_handle_impl_t impl_handle; 21614327Sdougm impl_handle = 21624327Sdougm (sa_handle_impl_t)sa_find_group_handle( 21634327Sdougm group); 21644327Sdougm if (impl_handle != NULL) { 21654327Sdougm ret = sa_commit_share( 21664327Sdougm impl_handle->scfhandle, group, 21674327Sdougm share); 21684327Sdougm } else { 21694327Sdougm ret = SA_SYSTEM_ERR; 21704327Sdougm } 21714327Sdougm } 21724327Sdougm if (type != NULL) 21734327Sdougm sa_free_attr_string(type); 21743910Sdougm } 21753034Sdougm } 21763034Sdougm return (ret); 21773034Sdougm } 21783034Sdougm 21793034Sdougm /* 21803034Sdougm * sa_get_property_attr(prop, tag) 21813034Sdougm * 21823034Sdougm * Get the value of the specified property attribute. Standard 21833034Sdougm * attributes are "type" and "value". 21843034Sdougm */ 21853034Sdougm 21863034Sdougm char * 21873034Sdougm sa_get_property_attr(sa_property_t prop, char *tag) 21883034Sdougm { 21893034Sdougm return (get_node_attr((void *)prop, tag)); 21903034Sdougm } 21913034Sdougm 21923034Sdougm /* 21933034Sdougm * sa_get_optionset_attr(prop, tag) 21943034Sdougm * 21953034Sdougm * Get the value of the specified property attribute. Standard 21963034Sdougm * attribute is "type". 21973034Sdougm */ 21983034Sdougm 21993034Sdougm char * 22003034Sdougm sa_get_optionset_attr(sa_property_t optionset, char *tag) 22013034Sdougm { 22023034Sdougm return (get_node_attr((void *)optionset, tag)); 22033034Sdougm 22043034Sdougm } 22053034Sdougm 22063034Sdougm /* 22073034Sdougm * sa_set_optionset_attr(optionset, tag, value) 22083034Sdougm * 22093034Sdougm * Set the specified attribute(tag) to the specified value on the 22103034Sdougm * optionset. 22113034Sdougm */ 22123034Sdougm 22133034Sdougm void 22143034Sdougm sa_set_optionset_attr(sa_group_t optionset, char *tag, char *value) 22153034Sdougm { 22163034Sdougm set_node_attr((void *)optionset, tag, value); 22173034Sdougm } 22183034Sdougm 22193034Sdougm /* 22203034Sdougm * sa_free_attr_string(string) 22213034Sdougm * 22223034Sdougm * Free the string that was returned in one of the sa_get_*_attr() 22233034Sdougm * functions. 22243034Sdougm */ 22253034Sdougm 22263034Sdougm void 22273034Sdougm sa_free_attr_string(char *string) 22283034Sdougm { 22293034Sdougm xmlFree((xmlChar *)string); 22303034Sdougm } 22313034Sdougm 22323034Sdougm /* 22333034Sdougm * sa_get_optionset(group, proto) 22343034Sdougm * 22353034Sdougm * Return the optionset, if it exists, that is associated with the 22363034Sdougm * specified protocol. 22373034Sdougm */ 22383034Sdougm 22393034Sdougm sa_optionset_t 22403034Sdougm sa_get_optionset(void *group, char *proto) 22413034Sdougm { 22423034Sdougm xmlNodePtr node; 22433034Sdougm xmlChar *value = NULL; 22443034Sdougm 22453034Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 22464327Sdougm node = node->next) { 22473034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) { 22484327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 22494327Sdougm if (proto != NULL) { 22504327Sdougm if (value != NULL && 22514327Sdougm xmlStrcmp(value, (xmlChar *)proto) == 0) { 22524327Sdougm break; 22534327Sdougm } 22544327Sdougm if (value != NULL) { 22554327Sdougm xmlFree(value); 22564327Sdougm value = NULL; 22574327Sdougm } 22584327Sdougm } else { 22594327Sdougm break; 22603034Sdougm } 22613034Sdougm } 22623034Sdougm } 22633034Sdougm if (value != NULL) 22644327Sdougm xmlFree(value); 22653034Sdougm return ((sa_optionset_t)node); 22663034Sdougm } 22673034Sdougm 22683034Sdougm /* 22693034Sdougm * sa_get_next_optionset(optionset) 22703034Sdougm * 22713034Sdougm * Return the next optionset in the group. NULL if this was the last. 22723034Sdougm */ 22733034Sdougm 22743034Sdougm sa_optionset_t 22753034Sdougm sa_get_next_optionset(sa_optionset_t optionset) 22763034Sdougm { 22773034Sdougm xmlNodePtr node; 22783034Sdougm 22793034Sdougm for (node = ((xmlNodePtr)optionset)->next; node != NULL; 22804327Sdougm node = node->next) { 22813034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) { 22823034Sdougm break; 22833034Sdougm } 22843034Sdougm } 22853034Sdougm return ((sa_optionset_t)node); 22863034Sdougm } 22873034Sdougm 22883034Sdougm /* 22893034Sdougm * sa_get_security(group, sectype, proto) 22903034Sdougm * 22913034Sdougm * Return the security optionset. The internal name is a hold over 22923034Sdougm * from the implementation and will be changed before the API is 22933034Sdougm * finalized. This is really a named optionset that can be negotiated 22943034Sdougm * as a group of properties (like NFS security options). 22953034Sdougm */ 22963034Sdougm 22973034Sdougm sa_security_t 22983034Sdougm sa_get_security(sa_group_t group, char *sectype, char *proto) 22993034Sdougm { 23003034Sdougm xmlNodePtr node; 23013034Sdougm xmlChar *value = NULL; 23023034Sdougm 23033034Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 23044327Sdougm node = node->next) { 23054327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) { 23064327Sdougm if (proto != NULL) { 23074327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 23084327Sdougm if (value == NULL || 23094327Sdougm (value != NULL && 23104327Sdougm xmlStrcmp(value, (xmlChar *)proto) != 0)) { 23114327Sdougm /* it doesn't match so continue */ 23124327Sdougm xmlFree(value); 23134327Sdougm value = NULL; 23144327Sdougm continue; 23154327Sdougm } 23164327Sdougm } 23174327Sdougm if (value != NULL) { 23184327Sdougm xmlFree(value); 23194327Sdougm value = NULL; 23204327Sdougm } 23214327Sdougm /* potential match */ 23224327Sdougm if (sectype != NULL) { 23234327Sdougm value = xmlGetProp(node, (xmlChar *)"sectype"); 23244327Sdougm if (value != NULL && 23254327Sdougm xmlStrcmp(value, (xmlChar *)sectype) == 0) { 23264327Sdougm break; 23274327Sdougm } 23284327Sdougm } else { 23294327Sdougm break; 23304327Sdougm } 23313034Sdougm } 23323034Sdougm if (value != NULL) { 23334327Sdougm xmlFree(value); 23344327Sdougm value = NULL; 23353034Sdougm } 23363034Sdougm } 23373034Sdougm if (value != NULL) 23384327Sdougm xmlFree(value); 23393034Sdougm return ((sa_security_t)node); 23403034Sdougm } 23413034Sdougm 23423034Sdougm /* 23433034Sdougm * sa_get_next_security(security) 23443034Sdougm * 23453034Sdougm * Get the next security optionset if one exists. 23463034Sdougm */ 23473034Sdougm 23483034Sdougm sa_security_t 23493034Sdougm sa_get_next_security(sa_security_t security) 23503034Sdougm { 23513034Sdougm xmlNodePtr node; 23523034Sdougm 23533034Sdougm for (node = ((xmlNodePtr)security)->next; node != NULL; 23544327Sdougm node = node->next) { 23553034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) { 23563034Sdougm break; 23573034Sdougm } 23583034Sdougm } 23593034Sdougm return ((sa_security_t)node); 23603034Sdougm } 23613034Sdougm 23623034Sdougm /* 23633034Sdougm * sa_get_property(optionset, prop) 23643034Sdougm * 23653034Sdougm * Get the property object with the name specified in prop from the 23663034Sdougm * optionset. 23673034Sdougm */ 23683034Sdougm 23693034Sdougm sa_property_t 23703034Sdougm sa_get_property(sa_optionset_t optionset, char *prop) 23713034Sdougm { 23723034Sdougm xmlNodePtr node = (xmlNodePtr)optionset; 23733034Sdougm xmlChar *value = NULL; 23743034Sdougm 23753034Sdougm if (optionset == NULL) 23764327Sdougm return (NULL); 23773034Sdougm 23783034Sdougm for (node = node->children; node != NULL; 23794327Sdougm node = node->next) { 23804327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 23814327Sdougm if (prop == NULL) 23824327Sdougm break; 23834327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 23844327Sdougm if (value != NULL && 23854327Sdougm xmlStrcmp(value, (xmlChar *)prop) == 0) { 23864327Sdougm break; 23874327Sdougm } 23884327Sdougm if (value != NULL) { 23894327Sdougm xmlFree(value); 23904327Sdougm value = NULL; 23914327Sdougm } 23923034Sdougm } 23933034Sdougm } 23943034Sdougm if (value != NULL) 23953034Sdougm xmlFree(value); 23963034Sdougm if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"option") != 0) { 23974327Sdougm /* 23984327Sdougm * avoid a non option node -- it is possible to be a 23994327Sdougm * text node 24004327Sdougm */ 24014327Sdougm node = NULL; 24023034Sdougm } 24033034Sdougm return ((sa_property_t)node); 24043034Sdougm } 24053034Sdougm 24063034Sdougm /* 24073034Sdougm * sa_get_next_property(property) 24083034Sdougm * 24093034Sdougm * Get the next property following the specified property. NULL if 24103034Sdougm * this was the last. 24113034Sdougm */ 24123034Sdougm 24133034Sdougm sa_property_t 24143034Sdougm sa_get_next_property(sa_property_t property) 24153034Sdougm { 24163034Sdougm xmlNodePtr node; 24173034Sdougm 24183034Sdougm for (node = ((xmlNodePtr)property)->next; node != NULL; 24194327Sdougm node = node->next) { 24203034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 24213034Sdougm break; 24223034Sdougm } 24233034Sdougm } 24243034Sdougm return ((sa_property_t)node); 24253034Sdougm } 24263034Sdougm 24273034Sdougm /* 24283034Sdougm * sa_set_share_description(share, content) 24293034Sdougm * 24303034Sdougm * Set the description of share to content. 24313034Sdougm */ 24323034Sdougm 24333034Sdougm int 24343034Sdougm sa_set_share_description(sa_share_t share, char *content) 24353034Sdougm { 24363034Sdougm xmlNodePtr node; 24373034Sdougm sa_group_t group; 24383034Sdougm int ret = SA_OK; 24393034Sdougm 24403034Sdougm for (node = ((xmlNodePtr)share)->children; node != NULL; 24414327Sdougm node = node->next) { 24423034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 24433034Sdougm break; 24443034Sdougm } 24453034Sdougm } 24463034Sdougm /* no existing description but want to add */ 24473034Sdougm if (node == NULL && content != NULL) { 24483034Sdougm /* add a description */ 24494327Sdougm node = _sa_set_share_description(share, content); 24503034Sdougm } else if (node != NULL && content != NULL) { 24513034Sdougm /* update a description */ 24523034Sdougm xmlNodeSetContent(node, (xmlChar *)content); 24533034Sdougm } else if (node != NULL && content == NULL) { 24543034Sdougm /* remove an existing description */ 24553034Sdougm xmlUnlinkNode(node); 24563034Sdougm xmlFreeNode(node); 24573034Sdougm } 24585331Samw group = sa_get_parent_group(share); 24595331Samw if (group != NULL && sa_is_persistent(share)) { 24604327Sdougm sa_handle_impl_t impl_handle; 24614327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 24624327Sdougm if (impl_handle != NULL) { 24634327Sdougm ret = sa_commit_share(impl_handle->scfhandle, group, 24644327Sdougm share); 24654327Sdougm } else { 24664327Sdougm ret = SA_SYSTEM_ERR; 24674327Sdougm } 24683910Sdougm } 24693034Sdougm return (ret); 24703034Sdougm } 24713034Sdougm 24723034Sdougm /* 24733034Sdougm * fixproblemchars(string) 24743034Sdougm * 24753034Sdougm * don't want any newline or tab characters in the text since these 24763034Sdougm * could break display of data and legacy file formats. 24773034Sdougm */ 24783034Sdougm static void 24793034Sdougm fixproblemchars(char *str) 24803034Sdougm { 24813034Sdougm int c; 24823034Sdougm for (c = *str; c != '\0'; c = *++str) { 24834327Sdougm if (c == '\t' || c == '\n') 24844327Sdougm *str = ' '; 24854327Sdougm else if (c == '"') 24864327Sdougm *str = '\''; 24873034Sdougm } 24883034Sdougm } 24893034Sdougm 24903034Sdougm /* 24913034Sdougm * sa_get_share_description(share) 24923034Sdougm * 24933034Sdougm * Return the description text for the specified share if it 24943034Sdougm * exists. NULL if no description exists. 24953034Sdougm */ 24963034Sdougm 24973034Sdougm char * 24983034Sdougm sa_get_share_description(sa_share_t share) 24993034Sdougm { 25003034Sdougm xmlChar *description = NULL; 25013034Sdougm xmlNodePtr node; 25023034Sdougm 25033034Sdougm for (node = ((xmlNodePtr)share)->children; node != NULL; 25044327Sdougm node = node->next) { 25054327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 25064327Sdougm break; 25074327Sdougm } 25083034Sdougm } 25093034Sdougm if (node != NULL) { 25105331Samw description = xmlNodeGetContent(node); 25114327Sdougm fixproblemchars((char *)description); 25123034Sdougm } 25133034Sdougm return ((char *)description); 25143034Sdougm } 25153034Sdougm 25163034Sdougm /* 25173034Sdougm * sa_free(share_description(description) 25183034Sdougm * 25193034Sdougm * Free the description string. 25203034Sdougm */ 25213034Sdougm 25223034Sdougm void 25233034Sdougm sa_free_share_description(char *description) 25243034Sdougm { 25253034Sdougm xmlFree((xmlChar *)description); 25263034Sdougm } 25273034Sdougm 25283034Sdougm /* 25293034Sdougm * sa_create_optionset(group, proto) 25303034Sdougm * 25313034Sdougm * Create an optionset for the specified protocol in the specied 25323034Sdougm * group. This is manifested as a property group within SMF. 25333034Sdougm */ 25343034Sdougm 25353034Sdougm sa_optionset_t 25363034Sdougm sa_create_optionset(sa_group_t group, char *proto) 25373034Sdougm { 25383034Sdougm sa_optionset_t optionset; 25393034Sdougm sa_group_t parent = group; 25405331Samw sa_share_t share = NULL; 25415331Samw int err = SA_OK; 25425331Samw char *id = NULL; 25433034Sdougm 25443034Sdougm optionset = sa_get_optionset(group, proto); 25453034Sdougm if (optionset != NULL) { 25463034Sdougm /* can't have a duplicate protocol */ 25474327Sdougm optionset = NULL; 25483034Sdougm } else { 25495331Samw /* 25505331Samw * Account for resource names being slightly 25515331Samw * different. 25525331Samw */ 25535331Samw if (sa_is_share(group)) { 25545331Samw /* 25555331Samw * Transient shares do not have an "id" so not an 25565331Samw * error to not find one. 25575331Samw */ 25585331Samw id = sa_get_share_attr((sa_share_t)group, "id"); 25595331Samw } else if (sa_is_resource(group)) { 25605331Samw share = sa_get_resource_parent( 25615331Samw (sa_resource_t)group); 25625331Samw id = sa_get_resource_attr(share, "id"); 25635331Samw 25645331Samw /* id can be NULL if the group is transient (ZFS) */ 25655331Samw if (id == NULL && sa_is_persistent(group)) 25665331Samw err = SA_NO_MEMORY; 25675331Samw } 25685331Samw if (err == SA_NO_MEMORY) { 25695331Samw /* 25705331Samw * Couldn't get the id for the share or 25715331Samw * resource. While this could be a 25725331Samw * configuration issue, it is most likely an 25735331Samw * out of memory. In any case, fail the create. 25745331Samw */ 25755331Samw return (NULL); 25765331Samw } 25775331Samw 25784327Sdougm optionset = (sa_optionset_t)xmlNewChild((xmlNodePtr)group, 25794327Sdougm NULL, (xmlChar *)"optionset", NULL); 25803034Sdougm /* 25813034Sdougm * only put to repository if on a group and we were 25823034Sdougm * able to create an optionset. 25833034Sdougm */ 25844327Sdougm if (optionset != NULL) { 25854327Sdougm char oname[SA_STRSIZE]; 25864327Sdougm char *groupname; 25875331Samw 25885331Samw /* 25895331Samw * Need to get parent group in all cases, but also get 25905331Samw * the share if this is a resource. 25915331Samw */ 25925331Samw if (sa_is_share(group)) { 25934327Sdougm parent = sa_get_parent_group((sa_share_t)group); 25945331Samw } else if (sa_is_resource(group)) { 25955331Samw share = sa_get_resource_parent( 25965331Samw (sa_resource_t)group); 25975331Samw parent = sa_get_parent_group(share); 25985331Samw } 25994327Sdougm 26004327Sdougm sa_set_optionset_attr(optionset, "type", proto); 26013034Sdougm 26024327Sdougm (void) sa_optionset_name(optionset, oname, 26034327Sdougm sizeof (oname), id); 26044327Sdougm groupname = sa_get_group_attr(parent, "name"); 26055331Samw if (groupname != NULL && sa_is_persistent(group)) { 26064327Sdougm sa_handle_impl_t impl_handle; 26075331Samw impl_handle = 26085331Samw (sa_handle_impl_t)sa_find_group_handle( 26095331Samw group); 26104327Sdougm assert(impl_handle != NULL); 26114327Sdougm if (impl_handle != NULL) { 26124327Sdougm (void) sa_get_instance( 26135331Samw impl_handle->scfhandle, groupname); 26144327Sdougm (void) sa_create_pgroup( 26154327Sdougm impl_handle->scfhandle, oname); 26164327Sdougm } 26174327Sdougm } 26184327Sdougm if (groupname != NULL) 26194327Sdougm sa_free_attr_string(groupname); 26203034Sdougm } 26213034Sdougm } 26225331Samw 26235331Samw if (id != NULL) 26245331Samw sa_free_attr_string(id); 26253034Sdougm return (optionset); 26263034Sdougm } 26273034Sdougm 26283034Sdougm /* 26293034Sdougm * sa_get_property_parent(property) 26303034Sdougm * 26313034Sdougm * Given a property, return the object it is a property of. This will 26323034Sdougm * be an optionset of some type. 26333034Sdougm */ 26343034Sdougm 26353034Sdougm static sa_optionset_t 26363034Sdougm sa_get_property_parent(sa_property_t property) 26373034Sdougm { 26383034Sdougm xmlNodePtr node = NULL; 26393034Sdougm 26404327Sdougm if (property != NULL) 26414327Sdougm node = ((xmlNodePtr)property)->parent; 26423034Sdougm return ((sa_optionset_t)node); 26433034Sdougm } 26443034Sdougm 26453034Sdougm /* 26463034Sdougm * sa_get_optionset_parent(optionset) 26473034Sdougm * 26483034Sdougm * Return the parent of the specified optionset. This could be a group 26493034Sdougm * or a share. 26503034Sdougm */ 26513034Sdougm 26523034Sdougm static sa_group_t 26533034Sdougm sa_get_optionset_parent(sa_optionset_t optionset) 26543034Sdougm { 26553034Sdougm xmlNodePtr node = NULL; 26563034Sdougm 26574327Sdougm if (optionset != NULL) 26584327Sdougm node = ((xmlNodePtr)optionset)->parent; 26593034Sdougm return ((sa_group_t)node); 26603034Sdougm } 26613034Sdougm 26623034Sdougm /* 26633034Sdougm * zfs_needs_update(share) 26643034Sdougm * 26653034Sdougm * In order to avoid making multiple updates to a ZFS share when 26663034Sdougm * setting properties, the share attribute "changed" will be set to 26675331Samw * true when a property is added or modified. When done adding 26683034Sdougm * properties, we can then detect that an update is needed. We then 26693034Sdougm * clear the state here to detect additional changes. 26703034Sdougm */ 26713034Sdougm 26723034Sdougm static int 26733034Sdougm zfs_needs_update(sa_share_t share) 26743034Sdougm { 26753034Sdougm char *attr; 26763034Sdougm int result = 0; 26773034Sdougm 26783034Sdougm attr = sa_get_share_attr(share, "changed"); 26793034Sdougm if (attr != NULL) { 26804327Sdougm sa_free_attr_string(attr); 26813034Sdougm result = 1; 26823034Sdougm } 26833034Sdougm set_node_attr((void *)share, "changed", NULL); 26843034Sdougm return (result); 26853034Sdougm } 26863034Sdougm 26873034Sdougm /* 26883034Sdougm * zfs_set_update(share) 26893034Sdougm * 26903034Sdougm * Set the changed attribute of the share to true. 26913034Sdougm */ 26923034Sdougm 26933034Sdougm static void 26943034Sdougm zfs_set_update(sa_share_t share) 26953034Sdougm { 26963034Sdougm set_node_attr((void *)share, "changed", "true"); 26973034Sdougm } 26983034Sdougm 26993034Sdougm /* 27003034Sdougm * sa_commit_properties(optionset, clear) 27013034Sdougm * 27023034Sdougm * Check if SMF or ZFS config and either update or abort the pending 27033034Sdougm * changes. 27043034Sdougm */ 27053034Sdougm 27063034Sdougm int 27073034Sdougm sa_commit_properties(sa_optionset_t optionset, int clear) 27083034Sdougm { 27093034Sdougm sa_group_t group; 27103034Sdougm sa_group_t parent; 27113034Sdougm int zfs = 0; 27123034Sdougm int needsupdate = 0; 27133034Sdougm int ret = SA_OK; 27143910Sdougm sa_handle_impl_t impl_handle; 27153034Sdougm 27163034Sdougm group = sa_get_optionset_parent(optionset); 27173034Sdougm if (group != NULL && (sa_is_share(group) || is_zfs_group(group))) { 27184327Sdougm /* only update ZFS if on a share */ 27194327Sdougm parent = sa_get_parent_group(group); 27204327Sdougm zfs++; 27214327Sdougm if (parent != NULL && is_zfs_group(parent)) 27224327Sdougm needsupdate = zfs_needs_update(group); 27234327Sdougm else 27244327Sdougm zfs = 0; 27253034Sdougm } 27263034Sdougm if (zfs) { 27274327Sdougm if (!clear && needsupdate) 27284327Sdougm ret = sa_zfs_update((sa_share_t)group); 27293034Sdougm } else { 27304327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 27314327Sdougm if (impl_handle != NULL) { 27324327Sdougm if (clear) { 27334327Sdougm (void) sa_abort_transaction( 27344327Sdougm impl_handle->scfhandle); 27354327Sdougm } else { 27364327Sdougm ret = sa_end_transaction( 27374327Sdougm impl_handle->scfhandle); 27384327Sdougm } 27394327Sdougm } else { 27404327Sdougm ret = SA_SYSTEM_ERR; 27414327Sdougm } 27423034Sdougm } 27433034Sdougm return (ret); 27443034Sdougm } 27453034Sdougm 27463034Sdougm /* 27473034Sdougm * sa_destroy_optionset(optionset) 27483034Sdougm * 27495331Samw * Remove the optionset from its group. Update the repository to 27503034Sdougm * reflect this change. 27513034Sdougm */ 27523034Sdougm 27533034Sdougm int 27543034Sdougm sa_destroy_optionset(sa_optionset_t optionset) 27553034Sdougm { 27564327Sdougm char name[SA_STRSIZE]; 27573034Sdougm int len; 27583034Sdougm int ret; 27593034Sdougm char *id = NULL; 27603034Sdougm sa_group_t group; 27613034Sdougm int ispersist = 1; 27623034Sdougm 27633034Sdougm /* now delete the prop group */ 27643034Sdougm group = sa_get_optionset_parent(optionset); 27655331Samw if (group != NULL) { 27665331Samw if (sa_is_resource(group)) { 27675331Samw sa_resource_t resource = group; 27685331Samw sa_share_t share = sa_get_resource_parent(resource); 27695331Samw group = sa_get_parent_group(share); 27705331Samw id = sa_get_share_attr(share, "id"); 27715331Samw } else if (sa_is_share(group)) { 27725331Samw id = sa_get_share_attr((sa_share_t)group, "id"); 27735331Samw } 27745331Samw ispersist = sa_is_persistent(group); 27753034Sdougm } 27763034Sdougm if (ispersist) { 27774327Sdougm sa_handle_impl_t impl_handle; 27784327Sdougm len = sa_optionset_name(optionset, name, sizeof (name), id); 27794327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 27804327Sdougm if (impl_handle != NULL) { 27814327Sdougm if (len > 0) { 27824327Sdougm ret = sa_delete_pgroup(impl_handle->scfhandle, 27834327Sdougm name); 27844327Sdougm } 27854327Sdougm } else { 27864327Sdougm ret = SA_SYSTEM_ERR; 27873910Sdougm } 27883034Sdougm } 27893034Sdougm xmlUnlinkNode((xmlNodePtr)optionset); 27903034Sdougm xmlFreeNode((xmlNodePtr)optionset); 27913034Sdougm if (id != NULL) 27924327Sdougm sa_free_attr_string(id); 27933034Sdougm return (ret); 27943034Sdougm } 27953034Sdougm 27963034Sdougm /* private to the implementation */ 27973034Sdougm int 27983034Sdougm _sa_remove_optionset(sa_optionset_t optionset) 27993034Sdougm { 28003034Sdougm int ret = SA_OK; 28013034Sdougm 28023034Sdougm xmlUnlinkNode((xmlNodePtr)optionset); 28033034Sdougm xmlFreeNode((xmlNodePtr)optionset); 28043034Sdougm return (ret); 28053034Sdougm } 28063034Sdougm 28073034Sdougm /* 28083034Sdougm * sa_create_security(group, sectype, proto) 28093034Sdougm * 28103034Sdougm * Create a security optionset (one that has a type name and a 28113034Sdougm * proto). Security is left over from a pure NFS implementation. The 28123034Sdougm * naming will change in the future when the API is released. 28133034Sdougm */ 28143034Sdougm sa_security_t 28153034Sdougm sa_create_security(sa_group_t group, char *sectype, char *proto) 28163034Sdougm { 28173034Sdougm sa_security_t security; 28183034Sdougm char *id = NULL; 28193034Sdougm sa_group_t parent; 28203034Sdougm char *groupname = NULL; 28213034Sdougm 28223034Sdougm if (group != NULL && sa_is_share(group)) { 28234327Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 28244327Sdougm parent = sa_get_parent_group(group); 28254327Sdougm if (parent != NULL) 28264327Sdougm groupname = sa_get_group_attr(parent, "name"); 28273034Sdougm } else if (group != NULL) { 28284327Sdougm groupname = sa_get_group_attr(group, "name"); 28293034Sdougm } 28303034Sdougm 28313034Sdougm security = sa_get_security(group, sectype, proto); 28323034Sdougm if (security != NULL) { 28333034Sdougm /* can't have a duplicate security option */ 28343034Sdougm security = NULL; 28353034Sdougm } else { 28363034Sdougm security = (sa_security_t)xmlNewChild((xmlNodePtr)group, 28374327Sdougm NULL, (xmlChar *)"security", NULL); 28383034Sdougm if (security != NULL) { 28394327Sdougm char oname[SA_STRSIZE]; 28403034Sdougm sa_set_security_attr(security, "type", proto); 28413034Sdougm 28423034Sdougm sa_set_security_attr(security, "sectype", sectype); 28433034Sdougm (void) sa_security_name(security, oname, 28444327Sdougm sizeof (oname), id); 28455331Samw if (groupname != NULL && sa_is_persistent(group)) { 28464327Sdougm sa_handle_impl_t impl_handle; 28474327Sdougm impl_handle = 28484327Sdougm (sa_handle_impl_t)sa_find_group_handle( 28494327Sdougm group); 28504327Sdougm if (impl_handle != NULL) { 28514327Sdougm (void) sa_get_instance( 28524327Sdougm impl_handle->scfhandle, groupname); 28534327Sdougm (void) sa_create_pgroup( 28544327Sdougm impl_handle->scfhandle, oname); 28554327Sdougm } 28563034Sdougm } 28573034Sdougm } 28583034Sdougm } 28593034Sdougm if (groupname != NULL) 28604327Sdougm sa_free_attr_string(groupname); 28613034Sdougm return (security); 28623034Sdougm } 28633034Sdougm 28643034Sdougm /* 28653034Sdougm * sa_destroy_security(security) 28663034Sdougm * 28673034Sdougm * Remove the specified optionset from the document and the 28683034Sdougm * configuration. 28693034Sdougm */ 28703034Sdougm 28713034Sdougm int 28723034Sdougm sa_destroy_security(sa_security_t security) 28733034Sdougm { 28744327Sdougm char name[SA_STRSIZE]; 28753034Sdougm int len; 28763034Sdougm int ret = SA_OK; 28773034Sdougm char *id = NULL; 28783034Sdougm sa_group_t group; 28793034Sdougm int iszfs = 0; 28803034Sdougm int ispersist = 1; 28813034Sdougm 28823034Sdougm group = sa_get_optionset_parent(security); 28833034Sdougm 28843034Sdougm if (group != NULL) 28854327Sdougm iszfs = sa_group_is_zfs(group); 28863034Sdougm 28873034Sdougm if (group != NULL && !iszfs) { 28884327Sdougm if (sa_is_share(group)) 28895331Samw ispersist = sa_is_persistent(group); 28904327Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 28913034Sdougm } 28923034Sdougm if (ispersist) { 28934327Sdougm len = sa_security_name(security, name, sizeof (name), id); 28944327Sdougm if (!iszfs && len > 0) { 28954327Sdougm sa_handle_impl_t impl_handle; 28964327Sdougm impl_handle = 28974327Sdougm (sa_handle_impl_t)sa_find_group_handle(group); 28984327Sdougm if (impl_handle != NULL) { 28994327Sdougm ret = sa_delete_pgroup(impl_handle->scfhandle, 29004327Sdougm name); 29014327Sdougm } else { 29024327Sdougm ret = SA_SYSTEM_ERR; 29034327Sdougm } 29043910Sdougm } 29053034Sdougm } 29063034Sdougm xmlUnlinkNode((xmlNodePtr)security); 29073034Sdougm xmlFreeNode((xmlNodePtr)security); 29084327Sdougm if (iszfs) 29094327Sdougm ret = sa_zfs_update(group); 29103034Sdougm if (id != NULL) 29114327Sdougm sa_free_attr_string(id); 29123034Sdougm return (ret); 29133034Sdougm } 29143034Sdougm 29153034Sdougm /* 29163034Sdougm * sa_get_security_attr(optionset, tag) 29173034Sdougm * 29183034Sdougm * Return the specified attribute value from the optionset. 29193034Sdougm */ 29203034Sdougm 29213034Sdougm char * 29223034Sdougm sa_get_security_attr(sa_property_t optionset, char *tag) 29233034Sdougm { 29243034Sdougm return (get_node_attr((void *)optionset, tag)); 29253034Sdougm 29263034Sdougm } 29273034Sdougm 29283034Sdougm /* 29293034Sdougm * sa_set_security_attr(optionset, tag, value) 29303034Sdougm * 29313034Sdougm * Set the optioset attribute specied by tag to the specified value. 29323034Sdougm */ 29333034Sdougm 29343034Sdougm void 29353034Sdougm sa_set_security_attr(sa_group_t optionset, char *tag, char *value) 29363034Sdougm { 29373034Sdougm set_node_attr((void *)optionset, tag, value); 29383034Sdougm } 29393034Sdougm 29403034Sdougm /* 29413034Sdougm * is_nodetype(node, type) 29423034Sdougm * 29433034Sdougm * Check to see if node is of the type specified. 29443034Sdougm */ 29453034Sdougm 29463034Sdougm static int 29473034Sdougm is_nodetype(void *node, char *type) 29483034Sdougm { 29493034Sdougm return (strcmp((char *)((xmlNodePtr)node)->name, type) == 0); 29503034Sdougm } 29513034Sdougm 29524327Sdougm /* 29534327Sdougm * add_or_update() 29544327Sdougm * 29554327Sdougm * Add or update a property. Pulled out of sa_set_prop_by_prop for 29564327Sdougm * readability. 29574327Sdougm */ 29584327Sdougm static int 29594327Sdougm add_or_update(scfutilhandle_t *scf_handle, int type, scf_value_t *value, 29604327Sdougm scf_transaction_entry_t *entry, char *name, char *valstr) 29614327Sdougm { 29624327Sdougm int ret = SA_SYSTEM_ERR; 29634327Sdougm 29644327Sdougm if (value != NULL) { 29654327Sdougm if (type == SA_PROP_OP_ADD) 29664327Sdougm ret = scf_transaction_property_new(scf_handle->trans, 29674327Sdougm entry, name, SCF_TYPE_ASTRING); 29684327Sdougm else 29694327Sdougm ret = scf_transaction_property_change(scf_handle->trans, 29704327Sdougm entry, name, SCF_TYPE_ASTRING); 29714327Sdougm if (ret == 0) { 29724327Sdougm ret = scf_value_set_astring(value, valstr); 29734327Sdougm if (ret == 0) 29744327Sdougm ret = scf_entry_add_value(entry, value); 29754327Sdougm if (ret == 0) 29764327Sdougm return (ret); 29774327Sdougm scf_value_destroy(value); 29784327Sdougm } else { 29794327Sdougm scf_entry_destroy(entry); 29804327Sdougm } 29814327Sdougm } 29824327Sdougm return (SA_SYSTEM_ERR); 29834327Sdougm } 29844327Sdougm 29853034Sdougm /* 29863034Sdougm * sa_set_prop_by_prop(optionset, group, prop, type) 29873034Sdougm * 29883034Sdougm * Add/remove/update the specified property prop into the optionset or 29893034Sdougm * share. If a share, sort out which property group based on GUID. In 29903034Sdougm * all cases, the appropriate transaction is set (or ZFS share is 29913034Sdougm * marked as needing an update) 29923034Sdougm */ 29933034Sdougm 29943034Sdougm static int 29953034Sdougm sa_set_prop_by_prop(sa_optionset_t optionset, sa_group_t group, 29963034Sdougm sa_property_t prop, int type) 29973034Sdougm { 29983034Sdougm char *name; 29993034Sdougm char *valstr; 30003034Sdougm int ret = SA_OK; 30013034Sdougm scf_transaction_entry_t *entry; 30023034Sdougm scf_value_t *value; 30033034Sdougm int opttype; /* 1 == optionset, 0 == security */ 30043034Sdougm char *id = NULL; 30053034Sdougm int iszfs = 0; 30063034Sdougm sa_group_t parent = NULL; 30075331Samw sa_share_t share = NULL; 30083910Sdougm sa_handle_impl_t impl_handle; 30093910Sdougm scfutilhandle_t *scf_handle; 30103034Sdougm 30115331Samw if (!sa_is_persistent(group)) { 30123034Sdougm /* 30133034Sdougm * if the group/share is not persistent we don't need 30143034Sdougm * to do anything here 30153034Sdougm */ 30164327Sdougm return (SA_OK); 30173034Sdougm } 30183910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 30194327Sdougm if (impl_handle == NULL || impl_handle->scfhandle == NULL) 30204327Sdougm return (SA_SYSTEM_ERR); 30213910Sdougm scf_handle = impl_handle->scfhandle; 30223034Sdougm name = sa_get_property_attr(prop, "type"); 30233034Sdougm valstr = sa_get_property_attr(prop, "value"); 30243034Sdougm entry = scf_entry_create(scf_handle->handle); 30253034Sdougm opttype = is_nodetype((void *)optionset, "optionset"); 30263034Sdougm 30275331Samw /* 30285331Samw * Check for share vs. resource since they need slightly 30295331Samw * different treatment given the hierarchy. 30305331Samw */ 30313034Sdougm if (valstr != NULL && entry != NULL) { 30324327Sdougm if (sa_is_share(group)) { 30334327Sdougm parent = sa_get_parent_group(group); 30345331Samw share = (sa_share_t)group; 30354327Sdougm if (parent != NULL) 30364327Sdougm iszfs = is_zfs_group(parent); 30375331Samw } else if (sa_is_resource(group)) { 30385331Samw share = sa_get_parent_group(group); 30395331Samw if (share != NULL) 30405331Samw parent = sa_get_parent_group(share); 30414327Sdougm } else { 30424327Sdougm iszfs = is_zfs_group(group); 30433034Sdougm } 30444327Sdougm if (!iszfs) { 30454327Sdougm if (scf_handle->trans == NULL) { 30464327Sdougm char oname[SA_STRSIZE]; 30474327Sdougm char *groupname = NULL; 30485331Samw if (share != NULL) { 30495331Samw if (parent != NULL) 30504327Sdougm groupname = 30514327Sdougm sa_get_group_attr(parent, 30524327Sdougm "name"); 30535331Samw id = sa_get_share_attr( 30545331Samw (sa_share_t)share, "id"); 30554327Sdougm } else { 30564327Sdougm groupname = sa_get_group_attr(group, 30574327Sdougm "name"); 30584327Sdougm } 30594327Sdougm if (groupname != NULL) { 30604327Sdougm ret = sa_get_instance(scf_handle, 30614327Sdougm groupname); 30624327Sdougm sa_free_attr_string(groupname); 30634327Sdougm } 30644327Sdougm if (opttype) 30654327Sdougm (void) sa_optionset_name(optionset, 30664327Sdougm oname, sizeof (oname), id); 30674327Sdougm else 30684327Sdougm (void) sa_security_name(optionset, 30694327Sdougm oname, sizeof (oname), id); 30704327Sdougm ret = sa_start_transaction(scf_handle, oname); 30713910Sdougm } 30724327Sdougm if (ret == SA_OK) { 30734327Sdougm switch (type) { 30744327Sdougm case SA_PROP_OP_REMOVE: 30754327Sdougm ret = scf_transaction_property_delete( 30764327Sdougm scf_handle->trans, entry, name); 30774327Sdougm break; 30784327Sdougm case SA_PROP_OP_ADD: 30794327Sdougm case SA_PROP_OP_UPDATE: 30804327Sdougm value = scf_value_create( 30814327Sdougm scf_handle->handle); 30824327Sdougm ret = add_or_update(scf_handle, type, 30834327Sdougm value, entry, name, valstr); 30844327Sdougm break; 30853034Sdougm } 30863034Sdougm } 30874327Sdougm } else { 30884327Sdougm /* 30894327Sdougm * ZFS update. The calling function would have updated 30904327Sdougm * the internal XML structure. Just need to flag it as 30914327Sdougm * changed for ZFS. 30924327Sdougm */ 30934327Sdougm zfs_set_update((sa_share_t)group); 30944327Sdougm } 30953034Sdougm } 30963034Sdougm 30973034Sdougm if (name != NULL) 30984327Sdougm sa_free_attr_string(name); 30993034Sdougm if (valstr != NULL) 31004327Sdougm sa_free_attr_string(valstr); 31013034Sdougm else if (entry != NULL) 31024327Sdougm scf_entry_destroy(entry); 31033034Sdougm 31043034Sdougm if (ret == -1) 31054327Sdougm ret = SA_SYSTEM_ERR; 31063034Sdougm 31073034Sdougm return (ret); 31083034Sdougm } 31093034Sdougm 31103034Sdougm /* 31113034Sdougm * sa_create_property(name, value) 31123034Sdougm * 31133034Sdougm * Create a new property with the specified name and value. 31143034Sdougm */ 31153034Sdougm 31163034Sdougm sa_property_t 31173034Sdougm sa_create_property(char *name, char *value) 31183034Sdougm { 31193034Sdougm xmlNodePtr node; 31203034Sdougm 31213034Sdougm node = xmlNewNode(NULL, (xmlChar *)"option"); 31223034Sdougm if (node != NULL) { 31233034Sdougm xmlSetProp(node, (xmlChar *)"type", (xmlChar *)name); 31243034Sdougm xmlSetProp(node, (xmlChar *)"value", (xmlChar *)value); 31253034Sdougm } 31263034Sdougm return ((sa_property_t)node); 31273034Sdougm } 31283034Sdougm 31293034Sdougm /* 31303034Sdougm * sa_add_property(object, property) 31313034Sdougm * 31323034Sdougm * Add the specified property to the object. Issue the appropriate 31333034Sdougm * transaction or mark a ZFS object as needing an update. 31343034Sdougm */ 31353034Sdougm 31363034Sdougm int 31373034Sdougm sa_add_property(void *object, sa_property_t property) 31383034Sdougm { 31393034Sdougm int ret = SA_OK; 31403034Sdougm sa_group_t parent; 31413034Sdougm sa_group_t group; 31423034Sdougm char *proto; 31433034Sdougm 31443034Sdougm proto = sa_get_optionset_attr(object, "type"); 31453034Sdougm if (property != NULL) { 31464327Sdougm if ((ret = sa_valid_property(object, proto, property)) == 31474327Sdougm SA_OK) { 31484327Sdougm property = (sa_property_t)xmlAddChild( 31494327Sdougm (xmlNodePtr)object, (xmlNodePtr)property); 31504327Sdougm } else { 31514327Sdougm if (proto != NULL) 31524327Sdougm sa_free_attr_string(proto); 31534327Sdougm return (ret); 31544327Sdougm } 31553034Sdougm } 31563034Sdougm 31573034Sdougm if (proto != NULL) 31584327Sdougm sa_free_attr_string(proto); 31593034Sdougm 31603034Sdougm parent = sa_get_parent_group(object); 31615331Samw if (!sa_is_persistent(parent)) 31624327Sdougm return (ret); 31635331Samw 31645331Samw if (sa_is_resource(parent)) { 31655331Samw /* 31665331Samw * Resources are children of share. Need to go up two 31675331Samw * levels to find the group but the parent needs to be 31685331Samw * the share at this point in order to get the "id". 31695331Samw */ 31705331Samw parent = sa_get_parent_group(parent); 31715331Samw group = sa_get_parent_group(parent); 31725331Samw } else if (sa_is_share(parent)) { 31735331Samw group = sa_get_parent_group(parent); 31745331Samw } else { 31755331Samw group = parent; 31763034Sdougm } 31773034Sdougm 31784327Sdougm if (property == NULL) { 31794327Sdougm ret = SA_NO_MEMORY; 31804327Sdougm } else { 31814327Sdougm char oname[SA_STRSIZE]; 31823034Sdougm 31834327Sdougm if (!is_zfs_group(group)) { 31844327Sdougm char *id = NULL; 31854327Sdougm sa_handle_impl_t impl_handle; 31864327Sdougm scfutilhandle_t *scf_handle; 31873910Sdougm 31884327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle( 31894327Sdougm group); 31904327Sdougm if (impl_handle == NULL || 31914327Sdougm impl_handle->scfhandle == NULL) 31924327Sdougm ret = SA_SYSTEM_ERR; 31934327Sdougm if (ret == SA_OK) { 31944327Sdougm scf_handle = impl_handle->scfhandle; 31954327Sdougm if (sa_is_share((sa_group_t)parent)) { 31964327Sdougm id = sa_get_share_attr( 31974327Sdougm (sa_share_t)parent, "id"); 31984327Sdougm } 31994327Sdougm if (scf_handle->trans == NULL) { 32004327Sdougm if (is_nodetype(object, "optionset")) { 32014327Sdougm (void) sa_optionset_name( 32024327Sdougm (sa_optionset_t)object, 32034327Sdougm oname, sizeof (oname), id); 32044327Sdougm } else { 32054327Sdougm (void) sa_security_name( 32064327Sdougm (sa_optionset_t)object, 32074327Sdougm oname, sizeof (oname), id); 32084327Sdougm } 32094327Sdougm ret = sa_start_transaction(scf_handle, 32104327Sdougm oname); 32114327Sdougm } 32124327Sdougm if (ret == SA_OK) { 32134327Sdougm char *name; 32144327Sdougm char *value; 32154327Sdougm name = sa_get_property_attr(property, 32164327Sdougm "type"); 32174327Sdougm value = sa_get_property_attr(property, 32184327Sdougm "value"); 32194327Sdougm if (name != NULL && value != NULL) { 32204327Sdougm if (scf_handle->scf_state == 32214327Sdougm SCH_STATE_INIT) { 32224327Sdougm ret = sa_set_property( 32234327Sdougm scf_handle, name, 32244327Sdougm value); 32254327Sdougm } 32264327Sdougm } else { 32274327Sdougm ret = SA_CONFIG_ERR; 32284327Sdougm } 32294327Sdougm if (name != NULL) 32304327Sdougm sa_free_attr_string( 32314327Sdougm name); 32324327Sdougm if (value != NULL) 32334327Sdougm sa_free_attr_string(value); 32344327Sdougm } 32354327Sdougm if (id != NULL) 32364327Sdougm sa_free_attr_string(id); 32374327Sdougm } 32384327Sdougm } else { 32394327Sdougm /* 32404327Sdougm * ZFS is a special case. We do want 32414327Sdougm * to allow editing property/security 32424327Sdougm * lists since we can have a better 32434327Sdougm * syntax and we also want to keep 32444327Sdougm * things consistent when possible. 32454327Sdougm * 32464327Sdougm * Right now, we defer until the 32474327Sdougm * sa_commit_properties so we can get 32484327Sdougm * them all at once. We do need to 32494327Sdougm * mark the share as "changed" 32504327Sdougm */ 32514327Sdougm zfs_set_update((sa_share_t)parent); 32523034Sdougm } 32533034Sdougm } 32543034Sdougm return (ret); 32553034Sdougm } 32563034Sdougm 32573034Sdougm /* 32583034Sdougm * sa_remove_property(property) 32593034Sdougm * 32603034Sdougm * Remove the specied property from its containing object. Update the 32613034Sdougm * repository as appropriate. 32623034Sdougm */ 32633034Sdougm 32643034Sdougm int 32653034Sdougm sa_remove_property(sa_property_t property) 32663034Sdougm { 32673034Sdougm int ret = SA_OK; 32683034Sdougm 32693034Sdougm if (property != NULL) { 32703034Sdougm sa_optionset_t optionset; 32713034Sdougm sa_group_t group; 32723034Sdougm optionset = sa_get_property_parent(property); 32733034Sdougm if (optionset != NULL) { 32744327Sdougm group = sa_get_optionset_parent(optionset); 32754327Sdougm if (group != NULL) { 32764327Sdougm ret = sa_set_prop_by_prop(optionset, group, 32774327Sdougm property, SA_PROP_OP_REMOVE); 32784327Sdougm } 32793034Sdougm } 32803034Sdougm xmlUnlinkNode((xmlNodePtr)property); 32813034Sdougm xmlFreeNode((xmlNodePtr)property); 32823034Sdougm } else { 32834327Sdougm ret = SA_NO_SUCH_PROP; 32843034Sdougm } 32853034Sdougm return (ret); 32863034Sdougm } 32873034Sdougm 32883034Sdougm /* 32893034Sdougm * sa_update_property(property, value) 32903034Sdougm * 32913034Sdougm * Update the specified property to the new value. If value is NULL, 32923034Sdougm * we currently treat this as a remove. 32933034Sdougm */ 32943034Sdougm 32953034Sdougm int 32963034Sdougm sa_update_property(sa_property_t property, char *value) 32973034Sdougm { 32983034Sdougm int ret = SA_OK; 32993034Sdougm if (value == NULL) { 33003034Sdougm return (sa_remove_property(property)); 33013034Sdougm } else { 33023034Sdougm sa_optionset_t optionset; 33033034Sdougm sa_group_t group; 33043034Sdougm set_node_attr((void *)property, "value", value); 33053034Sdougm optionset = sa_get_property_parent(property); 33063034Sdougm if (optionset != NULL) { 33074327Sdougm group = sa_get_optionset_parent(optionset); 33084327Sdougm if (group != NULL) { 33094327Sdougm ret = sa_set_prop_by_prop(optionset, group, 33104327Sdougm property, SA_PROP_OP_UPDATE); 33114327Sdougm } 33123034Sdougm } else { 33134327Sdougm ret = SA_NO_SUCH_PROP; 33143034Sdougm } 33153034Sdougm } 33163034Sdougm return (ret); 33173034Sdougm } 33183034Sdougm 33193034Sdougm /* 33203034Sdougm * sa_get_protocol_property(propset, prop) 33213034Sdougm * 33223034Sdougm * Get the specified protocol specific property. These are global to 33233034Sdougm * the protocol and not specific to a group or share. 33243034Sdougm */ 33253034Sdougm 33263034Sdougm sa_property_t 33273034Sdougm sa_get_protocol_property(sa_protocol_properties_t propset, char *prop) 33283034Sdougm { 33293034Sdougm xmlNodePtr node = (xmlNodePtr)propset; 33303034Sdougm xmlChar *value = NULL; 33313034Sdougm 33323034Sdougm for (node = node->children; node != NULL; 33334327Sdougm node = node->next) { 33344327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 33354327Sdougm if (prop == NULL) 33364327Sdougm break; 33374327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 33384327Sdougm if (value != NULL && 33394327Sdougm xmlStrcasecmp(value, (xmlChar *)prop) == 0) { 33404327Sdougm break; 33414327Sdougm } 33424327Sdougm if (value != NULL) { 33434327Sdougm xmlFree(value); 33444327Sdougm value = NULL; 33454327Sdougm } 33463034Sdougm } 33473034Sdougm } 33483034Sdougm if (value != NULL) 33493034Sdougm xmlFree(value); 33503034Sdougm if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"option") != 0) { 33514327Sdougm /* 33524327Sdougm * avoid a non option node -- it is possible to be a 33534327Sdougm * text node 33544327Sdougm */ 33554327Sdougm node = NULL; 33563034Sdougm } 33573034Sdougm return ((sa_property_t)node); 33583034Sdougm } 33593034Sdougm 33603034Sdougm /* 33613034Sdougm * sa_get_next_protocol_property(prop) 33623034Sdougm * 33633034Sdougm * Get the next protocol specific property in the list. 33643034Sdougm */ 33653034Sdougm 33663034Sdougm sa_property_t 33673034Sdougm sa_get_next_protocol_property(sa_property_t prop) 33683034Sdougm { 33693034Sdougm xmlNodePtr node; 33703034Sdougm 33713034Sdougm for (node = ((xmlNodePtr)prop)->next; node != NULL; 33724327Sdougm node = node->next) { 33733034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 33743034Sdougm break; 33753034Sdougm } 33763034Sdougm } 33773034Sdougm return ((sa_property_t)node); 33783034Sdougm } 33793034Sdougm 33803034Sdougm /* 33813034Sdougm * sa_set_protocol_property(prop, value) 33823034Sdougm * 33833034Sdougm * Set the specified property to have the new value. The protocol 33843034Sdougm * specific plugin will then be called to update the property. 33853034Sdougm */ 33863034Sdougm 33873034Sdougm int 33883034Sdougm sa_set_protocol_property(sa_property_t prop, char *value) 33893034Sdougm { 33903034Sdougm sa_protocol_properties_t propset; 33913034Sdougm char *proto; 33923034Sdougm int ret = SA_INVALID_PROTOCOL; 33933034Sdougm 33943034Sdougm propset = ((xmlNodePtr)prop)->parent; 33953034Sdougm if (propset != NULL) { 33964327Sdougm proto = sa_get_optionset_attr(propset, "type"); 33974327Sdougm if (proto != NULL) { 33984327Sdougm set_node_attr((xmlNodePtr)prop, "value", value); 33994327Sdougm ret = sa_proto_set_property(proto, prop); 34004327Sdougm sa_free_attr_string(proto); 34014327Sdougm } 34023034Sdougm } 34033034Sdougm return (ret); 34043034Sdougm } 34053034Sdougm 34063034Sdougm /* 34073034Sdougm * sa_add_protocol_property(propset, prop) 34083034Sdougm * 34095331Samw * Add a new property to the protocol specific property set. 34103034Sdougm */ 34113034Sdougm 34123034Sdougm int 34133034Sdougm sa_add_protocol_property(sa_protocol_properties_t propset, sa_property_t prop) 34143034Sdougm { 34153034Sdougm xmlNodePtr node; 34163034Sdougm 34173034Sdougm /* should check for legitimacy */ 34183034Sdougm node = xmlAddChild((xmlNodePtr)propset, (xmlNodePtr)prop); 34193034Sdougm if (node != NULL) 34204327Sdougm return (SA_OK); 34213034Sdougm return (SA_NO_MEMORY); 34223034Sdougm } 34233034Sdougm 34243034Sdougm /* 34253034Sdougm * sa_create_protocol_properties(proto) 34263034Sdougm * 34275331Samw * Create a protocol specific property set. 34283034Sdougm */ 34293034Sdougm 34303034Sdougm sa_protocol_properties_t 34313034Sdougm sa_create_protocol_properties(char *proto) 34323034Sdougm { 34333034Sdougm xmlNodePtr node; 34344327Sdougm 34353034Sdougm node = xmlNewNode(NULL, (xmlChar *)"propertyset"); 34364327Sdougm if (node != NULL) 34374327Sdougm xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto); 34383034Sdougm return (node); 34393034Sdougm } 34405331Samw 34415331Samw /* 34425331Samw * sa_get_share_resource(share, resource) 34435331Samw * 34445331Samw * Get the named resource from the share, if it exists. If resource is 34455331Samw * NULL, get the first resource. 34465331Samw */ 34475331Samw 34485331Samw sa_resource_t 34495331Samw sa_get_share_resource(sa_share_t share, char *resource) 34505331Samw { 34515331Samw xmlNodePtr node = NULL; 34525331Samw xmlChar *name; 34535331Samw 34545331Samw if (share != NULL) { 34555331Samw for (node = ((xmlNodePtr)share)->children; node != NULL; 34565331Samw node = node->next) { 34575331Samw if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0) { 34585331Samw if (resource == NULL) { 34595331Samw /* 34605331Samw * We are looking for the first 34615331Samw * resource node and not a names 34625331Samw * resource. 34635331Samw */ 34645331Samw break; 34655331Samw } else { 34665331Samw /* is it the correct share? */ 34675331Samw name = xmlGetProp(node, 34685331Samw (xmlChar *)"name"); 34695331Samw if (name != NULL && 34705331Samw xmlStrcasecmp(name, 34715331Samw (xmlChar *)resource) == 0) { 34725331Samw xmlFree(name); 34735331Samw break; 34745331Samw } 34755331Samw xmlFree(name); 34765331Samw } 34775331Samw } 34785331Samw } 34795331Samw } 34805331Samw return ((sa_resource_t)node); 34815331Samw } 34825331Samw 34835331Samw /* 34845331Samw * sa_get_next_resource(resource) 34855331Samw * Return the next share following the specified share 34865331Samw * from the internal list of shares. Returns NULL if there 34875331Samw * are no more shares. The list is relative to the same 34885331Samw * group. 34895331Samw */ 34905331Samw sa_share_t 34915331Samw sa_get_next_resource(sa_resource_t resource) 34925331Samw { 34935331Samw xmlNodePtr node = NULL; 34945331Samw 34955331Samw if (resource != NULL) { 34965331Samw for (node = ((xmlNodePtr)resource)->next; node != NULL; 34975331Samw node = node->next) { 34985331Samw if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0) 34995331Samw break; 35005331Samw } 35015331Samw } 35025331Samw return ((sa_share_t)node); 35035331Samw } 35045331Samw 35055331Samw /* 35065331Samw * _sa_get_next_resource_index(share) 35075331Samw * 35085331Samw * get the next resource index number (one greater then current largest) 35095331Samw */ 35105331Samw 35115331Samw static int 35125331Samw _sa_get_next_resource_index(sa_share_t share) 35135331Samw { 35145331Samw sa_resource_t resource; 35155331Samw int index = 0; 35165331Samw char *id; 35175331Samw 35185331Samw for (resource = sa_get_share_resource(share, NULL); 35195331Samw resource != NULL; 35205331Samw resource = sa_get_next_resource(resource)) { 35215331Samw id = get_node_attr((void *)resource, "id"); 35225331Samw if (id != NULL) { 35235331Samw int val; 35245331Samw val = atoi(id); 35255331Samw if (val > index) 35265331Samw index = val; 35275331Samw sa_free_attr_string(id); 35285331Samw } 35295331Samw } 35305331Samw return (index + 1); 35315331Samw } 35325331Samw 35335331Samw 35345331Samw /* 35355331Samw * sa_add_resource(share, resource, persist, &err) 35365331Samw * 35375331Samw * Adds a new resource name associated with share. The resource name 35385331Samw * must be unique in the system and will be case insensitive (eventually). 35395331Samw */ 35405331Samw 35415331Samw sa_resource_t 35425331Samw sa_add_resource(sa_share_t share, char *resource, int persist, int *error) 35435331Samw { 35445331Samw xmlNodePtr node; 35455331Samw int err = SA_OK; 35465331Samw sa_resource_t res; 35475331Samw sa_group_t group; 35485331Samw sa_handle_t handle; 35495331Samw char istring[8]; /* just big enough for an integer value */ 35505331Samw int index; 35515331Samw 35525331Samw group = sa_get_parent_group(share); 35535331Samw handle = sa_find_group_handle(group); 35545331Samw res = sa_find_resource(handle, resource); 35555331Samw if (res != NULL) { 35565331Samw err = SA_DUPLICATE_NAME; 35575331Samw res = NULL; 35585331Samw } else { 35595331Samw node = xmlNewChild((xmlNodePtr)share, NULL, 35605331Samw (xmlChar *)"resource", NULL); 35615331Samw if (node != NULL) { 35625331Samw xmlSetProp(node, (xmlChar *)"name", 35635331Samw (xmlChar *)resource); 35645331Samw xmlSetProp(node, (xmlChar *)"type", persist ? 35655331Samw (xmlChar *)"persist" : (xmlChar *)"transient"); 35665331Samw if (persist != SA_SHARE_TRANSIENT) { 35675331Samw index = _sa_get_next_resource_index(share); 35685331Samw (void) snprintf(istring, sizeof (istring), "%d", 35695331Samw index); 35705331Samw xmlSetProp(node, (xmlChar *)"id", 35715331Samw (xmlChar *)istring); 35725331Samw if (!sa_group_is_zfs(group) && 35735331Samw sa_is_persistent((sa_group_t)share)) { 35745331Samw /* ZFS doesn't use resource names */ 35755331Samw sa_handle_impl_t ihandle; 35765331Samw ihandle = (sa_handle_impl_t) 35775331Samw sa_find_group_handle( 35785331Samw group); 35795331Samw if (ihandle != NULL) 35805331Samw err = sa_commit_share( 35815331Samw ihandle->scfhandle, group, 35825331Samw share); 35835331Samw else 35845331Samw err = SA_SYSTEM_ERR; 35855331Samw } 35865331Samw } 35875331Samw } 35885331Samw } 35895331Samw if (error != NULL) 35905331Samw *error = err; 35915331Samw return ((sa_resource_t)node); 35925331Samw } 35935331Samw 35945331Samw /* 35955331Samw * sa_remove_resource(resource) 35965331Samw * 35975331Samw * Remove the resource name from the share (and the system) 35985331Samw */ 35995331Samw 36005331Samw int 36015331Samw sa_remove_resource(sa_resource_t resource) 36025331Samw { 36035331Samw sa_share_t share; 36045331Samw sa_group_t group; 36055331Samw char *type; 36065331Samw int ret = SA_OK; 36075331Samw int transient = 0; 36085521Sas200622 sa_optionset_t opt; 36095331Samw 36105331Samw share = sa_get_resource_parent(resource); 36115331Samw type = sa_get_share_attr(share, "type"); 36125331Samw group = sa_get_parent_group(share); 36135331Samw 36145331Samw 36155331Samw if (type != NULL) { 36165331Samw if (strcmp(type, "persist") != 0) 36175331Samw transient = 1; 36185331Samw sa_free_attr_string(type); 36195331Samw } 36205331Samw 36215521Sas200622 /* Disable the resource for all protocols. */ 36225521Sas200622 (void) sa_disable_resource(resource, NULL); 36235521Sas200622 36245521Sas200622 /* Remove any optionsets from the resource. */ 36255521Sas200622 for (opt = sa_get_optionset(resource, NULL); 36265521Sas200622 opt != NULL; 36275521Sas200622 opt = sa_get_next_optionset(opt)) 36285521Sas200622 (void) sa_destroy_optionset(opt); 36295521Sas200622 36305331Samw /* Remove from the share */ 36315331Samw xmlUnlinkNode((xmlNode *)resource); 36325331Samw xmlFreeNode((xmlNode *)resource); 36335331Samw 36345331Samw /* only do SMF action if permanent and not ZFS */ 36355331Samw if (!transient && !sa_group_is_zfs(group)) { 36365331Samw sa_handle_impl_t ihandle; 36375331Samw ihandle = (sa_handle_impl_t)sa_find_group_handle(group); 36385331Samw if (ihandle != NULL) 36395331Samw ret = sa_commit_share(ihandle->scfhandle, group, share); 36405331Samw else 36415331Samw ret = SA_SYSTEM_ERR; 36425331Samw } 36435331Samw return (ret); 36445331Samw } 36455331Samw 36465331Samw /* 36475331Samw * proto_resource_rename(handle, group, resource, newname) 36485331Samw * 36495331Samw * Helper function for sa_rename_resource that notifies the protocol 36505331Samw * of a resource name change prior to a config repository update. 36515331Samw */ 36525331Samw static int 36535331Samw proto_rename_resource(sa_handle_t handle, sa_group_t group, 36545331Samw sa_resource_t resource, char *newname) 36555331Samw { 36565331Samw sa_optionset_t optionset; 36575331Samw int ret = SA_OK; 36585331Samw int err; 36595331Samw 36605331Samw for (optionset = sa_get_optionset(group, NULL); 36615331Samw optionset != NULL; 36625331Samw optionset = sa_get_next_optionset(optionset)) { 36635331Samw char *type; 36645331Samw type = sa_get_optionset_attr(optionset, "type"); 36655331Samw if (type != NULL) { 36665331Samw err = sa_proto_rename_resource(handle, type, resource, 36675331Samw newname); 36685331Samw if (err != SA_OK) 36695331Samw ret = err; 36705331Samw sa_free_attr_string(type); 36715331Samw } 36725331Samw } 36735331Samw return (ret); 36745331Samw } 36755331Samw 36765331Samw /* 36775331Samw * sa_rename_resource(resource, newname) 36785331Samw * 36795331Samw * Rename the resource to the new name, if it is unique. 36805331Samw */ 36815331Samw 36825331Samw int 36835331Samw sa_rename_resource(sa_resource_t resource, char *newname) 36845331Samw { 36855331Samw sa_share_t share; 36865331Samw sa_group_t group = NULL; 36875331Samw sa_resource_t target; 36885331Samw int ret = SA_CONFIG_ERR; 36895331Samw sa_handle_t handle = NULL; 36905331Samw 36915331Samw share = sa_get_resource_parent(resource); 36925331Samw if (share == NULL) 36935331Samw return (ret); 36945331Samw 36955331Samw group = sa_get_parent_group(share); 36965331Samw if (group == NULL) 36975331Samw return (ret); 36985331Samw 36995331Samw handle = (sa_handle_impl_t)sa_find_group_handle(group); 37005331Samw if (handle == NULL) 37015331Samw return (ret); 37025331Samw 37035331Samw target = sa_find_resource(handle, newname); 37045331Samw if (target != NULL) { 37055331Samw ret = SA_DUPLICATE_NAME; 37065331Samw } else { 37075331Samw /* 37085331Samw * Everything appears to be valid at this 37095331Samw * point. Change the name of the active share and then 37105331Samw * update the share in the appropriate repository. 37115331Samw */ 37125331Samw ret = proto_rename_resource(handle, group, resource, newname); 37135331Samw set_node_attr(resource, "name", newname); 37145331Samw if (!sa_group_is_zfs(group) && 37155331Samw sa_is_persistent((sa_group_t)share)) { 37165331Samw sa_handle_impl_t ihandle = (sa_handle_impl_t)handle; 37175331Samw ret = sa_commit_share(ihandle->scfhandle, group, 37185331Samw share); 37195331Samw } 37205331Samw } 37215331Samw return (ret); 37225331Samw } 37235331Samw 37245331Samw /* 37255331Samw * sa_get_resource_attr(resource, tag) 37265331Samw * 37275331Samw * Get the named attribute of the resource. "name" and "id" are 37285331Samw * currently defined. NULL if tag not defined. 37295331Samw */ 37305331Samw 37315331Samw char * 37325331Samw sa_get_resource_attr(sa_resource_t resource, char *tag) 37335331Samw { 37345331Samw return (get_node_attr((void *)resource, tag)); 37355331Samw } 37365331Samw 37375331Samw /* 37385331Samw * sa_set_resource_attr(resource, tag, value) 37395331Samw * 37405331Samw * Get the named attribute of the resource. "name" and "id" are 37415331Samw * currently defined. NULL if tag not defined. Currently we don't do 37425331Samw * much, but additional checking may be needed in the future. 37435331Samw */ 37445331Samw 37455331Samw int 37465331Samw sa_set_resource_attr(sa_resource_t resource, char *tag, char *value) 37475331Samw { 37485331Samw set_node_attr((void *)resource, tag, value); 37495331Samw return (SA_OK); 37505331Samw } 37515331Samw 37525331Samw /* 37535331Samw * sa_get_resource_parent(resource_t) 37545331Samw * 37555331Samw * Returns the share associated with the resource. 37565331Samw */ 37575331Samw 37585331Samw sa_share_t 37595331Samw sa_get_resource_parent(sa_resource_t resource) 37605331Samw { 37615331Samw sa_share_t share = NULL; 37625331Samw 37635331Samw if (resource != NULL) 37645331Samw share = (sa_share_t)((xmlNodePtr)resource)->parent; 37655331Samw return (share); 37665331Samw } 37675331Samw 37685331Samw /* 37695331Samw * find_resource(group, name) 37705331Samw * 37715331Samw * Find the resource within the group. 37725331Samw */ 37735331Samw 37745331Samw static sa_resource_t 37755331Samw find_resource(sa_group_t group, char *resname) 37765331Samw { 37775331Samw sa_share_t share; 37785331Samw sa_resource_t resource = NULL; 37795331Samw char *name; 37805331Samw 37815331Samw /* Iterate over all the shares and resources in the group. */ 37825331Samw for (share = sa_get_share(group, NULL); 37835331Samw share != NULL && resource == NULL; 37845331Samw share = sa_get_next_share(share)) { 37855331Samw for (resource = sa_get_share_resource(share, NULL); 37865331Samw resource != NULL; 37875331Samw resource = sa_get_next_resource(resource)) { 37885331Samw name = sa_get_resource_attr(resource, "name"); 37895331Samw if (name != NULL && xmlStrcasecmp((xmlChar*)name, 37905331Samw (xmlChar*)resname) == 0) { 37915331Samw sa_free_attr_string(name); 37925331Samw break; 37935331Samw } 37945331Samw if (name != NULL) { 37955331Samw sa_free_attr_string(name); 37965331Samw } 37975331Samw } 37985331Samw } 37995331Samw return (resource); 38005331Samw } 38015331Samw 38025331Samw /* 38035331Samw * sa_find_resource(name) 38045331Samw * 38055331Samw * Find the named resource in the system. 38065331Samw */ 38075331Samw 38085331Samw sa_resource_t 38095331Samw sa_find_resource(sa_handle_t handle, char *name) 38105331Samw { 38115331Samw sa_group_t group; 38125331Samw sa_group_t zgroup; 38135331Samw sa_resource_t resource = NULL; 38145331Samw 38155331Samw /* 38165331Samw * Iterate over all groups and zfs subgroups and check for 38175331Samw * resource name in them. 38185331Samw */ 38195331Samw for (group = sa_get_group(handle, NULL); group != NULL; 38205331Samw group = sa_get_next_group(group)) { 38215331Samw 38225331Samw if (is_zfs_group(group)) { 38235331Samw for (zgroup = 38245331Samw (sa_group_t)_sa_get_child_node((xmlNodePtr)group, 38255331Samw (xmlChar *)"group"); 38265331Samw zgroup != NULL && resource == NULL; 38275331Samw zgroup = sa_get_next_group(zgroup)) { 38285331Samw resource = find_resource(zgroup, name); 38295331Samw } 38305331Samw } else { 38315331Samw resource = find_resource(group, name); 38325331Samw } 38335331Samw if (resource != NULL) 38345331Samw break; 38355331Samw } 38365331Samw return (resource); 38375331Samw } 38385331Samw 38395331Samw /* 38405331Samw * sa_get_resource(group, resource) 38415331Samw * 38425331Samw * Search all the shares in the specified group for a share with a 38435331Samw * resource name matching the one specified. 38445331Samw * 38455331Samw * In the future, it may be advantageous to allow group to be NULL and 38465331Samw * search all groups but that isn't needed at present. 38475331Samw */ 38485331Samw 38495331Samw sa_resource_t 38505331Samw sa_get_resource(sa_group_t group, char *resource) 38515331Samw { 38525331Samw sa_share_t share = NULL; 38535331Samw sa_resource_t res = NULL; 38545331Samw 38555331Samw if (resource != NULL) { 38565331Samw for (share = sa_get_share(group, NULL); 38575331Samw share != NULL && res == NULL; 38585331Samw share = sa_get_next_share(share)) { 38595331Samw res = sa_get_share_resource(share, resource); 38605331Samw } 38615331Samw } 38625331Samw return (res); 38635331Samw } 38645331Samw 38655331Samw /* 38665331Samw * sa_enable_resource, protocol) 38675331Samw * Disable the specified share to the specified protocol. 38685331Samw * If protocol is NULL, then all protocols. 38695331Samw */ 38705331Samw int 38715331Samw sa_enable_resource(sa_resource_t resource, char *protocol) 38725331Samw { 38735331Samw int ret = SA_OK; 38745331Samw char **protocols; 38755331Samw int numproto; 38765331Samw 38775331Samw if (protocol != NULL) { 38785331Samw ret = sa_proto_share_resource(protocol, resource); 38795331Samw } else { 38805331Samw /* need to do all protocols */ 38815331Samw if ((numproto = sa_get_protocols(&protocols)) >= 0) { 38825331Samw int i, err; 38835331Samw for (i = 0; i < numproto; i++) { 38845331Samw err = sa_proto_share_resource( 38855331Samw protocols[i], resource); 38865331Samw if (err != SA_OK) 38875331Samw ret = err; 38885331Samw } 38895331Samw free(protocols); 38905331Samw } 38915331Samw } 38925331Samw if (ret == SA_OK) 38935331Samw (void) sa_set_resource_attr(resource, "shared", NULL); 38945331Samw 38955331Samw return (ret); 38965331Samw } 38975331Samw 38985331Samw /* 38995331Samw * sa_disable_resource(resource, protocol) 39005331Samw * 39015331Samw * Disable the specified share for the specified protocol. If 39025331Samw * protocol is NULL, then all protocols. If the underlying 39035331Samw * protocol doesn't implement disable at the resource level, we 39045331Samw * disable at the share level. 39055331Samw */ 39065331Samw int 39075331Samw sa_disable_resource(sa_resource_t resource, char *protocol) 39085331Samw { 39095331Samw int ret = SA_OK; 39105331Samw char **protocols; 39115331Samw int numproto; 39125331Samw 39135331Samw if (protocol != NULL) { 39145331Samw ret = sa_proto_unshare_resource(protocol, resource); 39155331Samw if (ret == SA_NOT_IMPLEMENTED) { 39165331Samw sa_share_t parent; 39175331Samw /* 39185331Samw * The protocol doesn't implement unshare 39195331Samw * resource. That implies that resource names are 39205331Samw * simple aliases for this protocol so we need to 39215331Samw * unshare the share. 39225331Samw */ 39235331Samw parent = sa_get_resource_parent(resource); 39245331Samw if (parent != NULL) 39255331Samw ret = sa_disable_share(parent, protocol); 39265331Samw else 39275331Samw ret = SA_CONFIG_ERR; 39285331Samw } 39295331Samw } else { 39305331Samw /* need to do all protocols */ 39315331Samw if ((numproto = sa_get_protocols(&protocols)) >= 0) { 39325331Samw int i, err; 39335331Samw for (i = 0; i < numproto; i++) { 39345331Samw err = sa_proto_unshare_resource(protocols[i], 39355331Samw resource); 39365331Samw if (err == SA_NOT_SUPPORTED) { 39375331Samw sa_share_t parent; 39385331Samw parent = sa_get_resource_parent( 39395331Samw resource); 39405331Samw if (parent != NULL) 39415331Samw err = sa_disable_share(parent, 39425331Samw protocols[i]); 39435331Samw else 39445331Samw err = SA_CONFIG_ERR; 39455331Samw } 39465331Samw if (err != SA_OK) 39475331Samw ret = err; 39485331Samw } 39495331Samw free(protocols); 39505331Samw } 39515331Samw } 39525331Samw if (ret == SA_OK) 39535331Samw (void) sa_set_resource_attr(resource, "shared", NULL); 39545331Samw 39555331Samw return (ret); 39565331Samw } 39575331Samw 39585331Samw /* 39595331Samw * sa_set_resource_description(resource, content) 39605331Samw * 39615331Samw * Set the description of share to content. 39625331Samw */ 39635331Samw 39645331Samw int 39655331Samw sa_set_resource_description(sa_resource_t resource, char *content) 39665331Samw { 39675331Samw xmlNodePtr node; 39685331Samw sa_group_t group; 39695331Samw sa_share_t share; 39705331Samw int ret = SA_OK; 39715331Samw 39725331Samw for (node = ((xmlNodePtr)resource)->children; 39735331Samw node != NULL; 39745331Samw node = node->next) { 39755331Samw if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 39765331Samw break; 39775331Samw } 39785331Samw } 39795331Samw 39805331Samw /* no existing description but want to add */ 39815331Samw if (node == NULL && content != NULL) { 39825331Samw /* add a description */ 39835331Samw node = _sa_set_share_description(resource, content); 39845331Samw } else if (node != NULL && content != NULL) { 39855331Samw /* update a description */ 39865331Samw xmlNodeSetContent(node, (xmlChar *)content); 39875331Samw } else if (node != NULL && content == NULL) { 39885331Samw /* remove an existing description */ 39895331Samw xmlUnlinkNode(node); 39905331Samw xmlFreeNode(node); 39915331Samw } 39925331Samw share = sa_get_resource_parent(resource); 39935331Samw group = sa_get_parent_group(share); 39945331Samw if (group != NULL && sa_is_persistent(share)) { 39955331Samw sa_handle_impl_t impl_handle; 39965331Samw impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 39975331Samw if (impl_handle != NULL) 39985331Samw ret = sa_commit_share(impl_handle->scfhandle, 39995331Samw group, share); 40005331Samw else 40015331Samw ret = SA_SYSTEM_ERR; 40025331Samw } 40035331Samw return (ret); 40045331Samw } 40055331Samw 40065331Samw /* 40075331Samw * sa_get_resource_description(share) 40085331Samw * 40095331Samw * Return the description text for the specified share if it 40105331Samw * exists. NULL if no description exists. 40115331Samw */ 40125331Samw 40135331Samw char * 40145331Samw sa_get_resource_description(sa_resource_t resource) 40155331Samw { 40165331Samw xmlChar *description = NULL; 40175331Samw xmlNodePtr node; 40185331Samw 40195331Samw for (node = ((xmlNodePtr)resource)->children; node != NULL; 40205331Samw node = node->next) { 40215331Samw if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) 40225331Samw break; 40235331Samw } 40245331Samw if (node != NULL) { 40255331Samw description = xmlNodeGetContent(node); 40265331Samw fixproblemchars((char *)description); 40275331Samw } 40285331Samw return ((char *)description); 40295331Samw } 4030