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 /* 238474SJose.Borrego@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 243034Sdougm * Use is subject to license terms. 253034Sdougm */ 263034Sdougm 273034Sdougm /* 283034Sdougm * Share control API 293034Sdougm */ 303034Sdougm #include <stdio.h> 313034Sdougm #include <string.h> 323034Sdougm #include <ctype.h> 333034Sdougm #include <sys/types.h> 343034Sdougm #include <sys/stat.h> 353663Sdougm #include <fcntl.h> 363034Sdougm #include <unistd.h> 373034Sdougm #include <libxml/parser.h> 383034Sdougm #include <libxml/tree.h> 393034Sdougm #include "libshare.h" 403034Sdougm #include "libshare_impl.h" 413034Sdougm #include <libscf.h> 423034Sdougm #include "scfutil.h" 433034Sdougm #include <ctype.h> 443034Sdougm #include <libintl.h> 453910Sdougm #include <thread.h> 463910Sdougm #include <synch.h> 473034Sdougm 483663Sdougm #define DFS_LOCK_FILE "/etc/dfs/fstypes" 494327Sdougm #define SA_STRSIZE 256 /* max string size for names */ 503663Sdougm 513034Sdougm /* 525331Samw * internal object type values returned by sa_get_object_type() 535331Samw */ 545331Samw #define SA_TYPE_UNKNOWN 0 555331Samw #define SA_TYPE_GROUP 1 565331Samw #define SA_TYPE_SHARE 2 575331Samw #define SA_TYPE_RESOURCE 3 585331Samw #define SA_TYPE_OPTIONSET 4 595331Samw #define SA_TYPE_ALTSPACE 5 605331Samw 615331Samw /* 623034Sdougm * internal data structures 633034Sdougm */ 643034Sdougm 653034Sdougm extern struct sa_proto_plugin *sap_proto_list; 663034Sdougm 673034Sdougm /* current SMF/SVC repository handle */ 683910Sdougm extern void getlegacyconfig(sa_handle_t, char *, xmlNodePtr *); 693910Sdougm extern int gettransients(sa_handle_impl_t, xmlNodePtr *); 703034Sdougm extern char *sa_fstype(char *); 713034Sdougm extern int sa_is_share(void *); 725331Samw extern int sa_is_resource(void *); 733034Sdougm extern ssize_t scf_max_name_len; /* defined in scfutil during initialization */ 743034Sdougm extern int sa_group_is_zfs(sa_group_t); 753034Sdougm extern int sa_path_is_zfs(char *); 763034Sdougm extern int sa_zfs_set_sharenfs(sa_group_t, char *, int); 775331Samw extern int sa_zfs_set_sharesmb(sa_group_t, char *, int); 783910Sdougm extern void update_legacy_config(sa_handle_t); 793034Sdougm extern int issubdir(char *, char *); 804327Sdougm extern int sa_zfs_init(sa_handle_impl_t); 813910Sdougm extern void sa_zfs_fini(sa_handle_impl_t); 823663Sdougm extern void sablocksigs(sigset_t *); 833663Sdougm extern void saunblocksigs(sigset_t *); 845331Samw static sa_group_t sa_get_optionset_parent(sa_optionset_t); 855331Samw static char *get_node_attr(void *, char *); 865951Sdougm extern void sa_update_sharetab_ts(sa_handle_t); 873034Sdougm 883910Sdougm /* 893910Sdougm * Data structures for finding/managing the document root to access 903910Sdougm * handle mapping. The list isn't expected to grow very large so a 913910Sdougm * simple list is acceptable. The purpose is to provide a way to start 923910Sdougm * with a group or share and find the library handle needed for 933910Sdougm * various operations. 943910Sdougm */ 953910Sdougm mutex_t sa_global_lock; 963910Sdougm struct doc2handle { 973910Sdougm struct doc2handle *next; 983910Sdougm xmlNodePtr root; 993910Sdougm sa_handle_impl_t handle; 1003910Sdougm }; 1013910Sdougm 1024327Sdougm /* definitions used in a couple of property functions */ 1034327Sdougm #define SA_PROP_OP_REMOVE 1 1044327Sdougm #define SA_PROP_OP_ADD 2 1054327Sdougm #define SA_PROP_OP_UPDATE 3 1064327Sdougm 1073910Sdougm static struct doc2handle *sa_global_handles = NULL; 1083034Sdougm 1093034Sdougm /* helper functions */ 1103034Sdougm 1113910Sdougm /* 1123910Sdougm * sa_errorstr(err) 1133910Sdougm * 1143910Sdougm * convert an error value to an error string 1153910Sdougm */ 1163910Sdougm 1173034Sdougm char * 1183034Sdougm sa_errorstr(int err) 1193034Sdougm { 1203034Sdougm static char errstr[32]; 1213034Sdougm char *ret = NULL; 1223034Sdougm 1233034Sdougm switch (err) { 1243034Sdougm case SA_OK: 1254327Sdougm ret = dgettext(TEXT_DOMAIN, "ok"); 1264327Sdougm break; 1273034Sdougm case SA_NO_SUCH_PATH: 1284327Sdougm ret = dgettext(TEXT_DOMAIN, "path doesn't exist"); 1294327Sdougm break; 1303034Sdougm case SA_NO_MEMORY: 1314327Sdougm ret = dgettext(TEXT_DOMAIN, "no memory"); 1324327Sdougm break; 1333034Sdougm case SA_DUPLICATE_NAME: 1344327Sdougm ret = dgettext(TEXT_DOMAIN, "name in use"); 1354327Sdougm break; 1363034Sdougm case SA_BAD_PATH: 1374327Sdougm ret = dgettext(TEXT_DOMAIN, "bad path"); 1384327Sdougm break; 1393034Sdougm case SA_NO_SUCH_GROUP: 1404327Sdougm ret = dgettext(TEXT_DOMAIN, "no such group"); 1414327Sdougm break; 1423034Sdougm case SA_CONFIG_ERR: 1434327Sdougm ret = dgettext(TEXT_DOMAIN, "configuration error"); 1444327Sdougm break; 1453034Sdougm case SA_SYSTEM_ERR: 1464327Sdougm ret = dgettext(TEXT_DOMAIN, "system error"); 1474327Sdougm break; 1483034Sdougm case SA_SYNTAX_ERR: 1494327Sdougm ret = dgettext(TEXT_DOMAIN, "syntax error"); 1504327Sdougm break; 1513034Sdougm case SA_NO_PERMISSION: 1524327Sdougm ret = dgettext(TEXT_DOMAIN, "no permission"); 1534327Sdougm break; 1543034Sdougm case SA_BUSY: 1554327Sdougm ret = dgettext(TEXT_DOMAIN, "busy"); 1564327Sdougm break; 1573034Sdougm case SA_NO_SUCH_PROP: 1584327Sdougm ret = dgettext(TEXT_DOMAIN, "no such property"); 1594327Sdougm break; 1603034Sdougm case SA_INVALID_NAME: 1614327Sdougm ret = dgettext(TEXT_DOMAIN, "invalid name"); 1624327Sdougm break; 1633034Sdougm case SA_INVALID_PROTOCOL: 1644327Sdougm ret = dgettext(TEXT_DOMAIN, "invalid protocol"); 1654327Sdougm break; 1663034Sdougm case SA_NOT_ALLOWED: 1674327Sdougm ret = dgettext(TEXT_DOMAIN, "operation not allowed"); 1684327Sdougm break; 1693034Sdougm case SA_BAD_VALUE: 1704327Sdougm ret = dgettext(TEXT_DOMAIN, "bad property value"); 1714327Sdougm break; 1723034Sdougm case SA_INVALID_SECURITY: 1734327Sdougm ret = dgettext(TEXT_DOMAIN, "invalid security type"); 1744327Sdougm break; 1753034Sdougm case SA_NO_SUCH_SECURITY: 1764327Sdougm ret = dgettext(TEXT_DOMAIN, "security type not found"); 1774327Sdougm break; 1783034Sdougm case SA_VALUE_CONFLICT: 1794327Sdougm ret = dgettext(TEXT_DOMAIN, "property value conflict"); 1804327Sdougm break; 1813034Sdougm case SA_NOT_IMPLEMENTED: 1824327Sdougm ret = dgettext(TEXT_DOMAIN, "not implemented"); 1834327Sdougm break; 1843034Sdougm case SA_INVALID_PATH: 1854327Sdougm ret = dgettext(TEXT_DOMAIN, "invalid path"); 1864327Sdougm break; 1873034Sdougm case SA_NOT_SUPPORTED: 1884327Sdougm ret = dgettext(TEXT_DOMAIN, "operation not supported"); 1894327Sdougm break; 1903034Sdougm case SA_PROP_SHARE_ONLY: 1914327Sdougm ret = dgettext(TEXT_DOMAIN, "property not valid for group"); 1924327Sdougm break; 1933034Sdougm case SA_NOT_SHARED: 1944327Sdougm ret = dgettext(TEXT_DOMAIN, "not shared"); 1954327Sdougm break; 1965331Samw case SA_NO_SUCH_RESOURCE: 1975331Samw ret = dgettext(TEXT_DOMAIN, "no such resource"); 1985331Samw break; 1995331Samw case SA_RESOURCE_REQUIRED: 2005331Samw ret = dgettext(TEXT_DOMAIN, "resource name required"); 2015331Samw break; 2025331Samw case SA_MULTIPLE_ERROR: 2035331Samw ret = dgettext(TEXT_DOMAIN, "errors from multiple protocols"); 2045331Samw break; 2055331Samw case SA_PATH_IS_SUBDIR: 2065331Samw ret = dgettext(TEXT_DOMAIN, "path is a subpath of share"); 2075331Samw break; 2085331Samw case SA_PATH_IS_PARENTDIR: 2095331Samw ret = dgettext(TEXT_DOMAIN, "path is parent of a share"); 2105331Samw break; 2116007Sthurlow case SA_NO_SECTION: 2126007Sthurlow ret = dgettext(TEXT_DOMAIN, "protocol requires a section"); 2136007Sthurlow break; 2146007Sthurlow case SA_NO_PROPERTIES: 2156007Sthurlow ret = dgettext(TEXT_DOMAIN, "properties not found"); 2166007Sthurlow break; 2176007Sthurlow case SA_NO_SUCH_SECTION: 2186007Sthurlow ret = dgettext(TEXT_DOMAIN, "section not found"); 2196007Sthurlow break; 2206007Sthurlow case SA_PASSWORD_ENC: 2216007Sthurlow ret = dgettext(TEXT_DOMAIN, "passwords must be encrypted"); 2226007Sthurlow break; 2233034Sdougm default: 2244327Sdougm (void) snprintf(errstr, sizeof (errstr), 2254327Sdougm dgettext(TEXT_DOMAIN, "unknown %d"), err); 2264327Sdougm ret = errstr; 2273034Sdougm } 2283034Sdougm return (ret); 2293034Sdougm } 2303034Sdougm 2313034Sdougm /* 2323910Sdougm * Document root to active handle mapping functions. These are only 2333910Sdougm * used internally. A mutex is used to prevent access while the list 2343910Sdougm * is changing. In general, the list will be relatively short - one 2353910Sdougm * item per thread that has called sa_init(). 2363910Sdougm */ 2373910Sdougm 2383910Sdougm sa_handle_impl_t 2393910Sdougm get_handle_for_root(xmlNodePtr root) 2403910Sdougm { 2413910Sdougm struct doc2handle *item; 2423910Sdougm 2433910Sdougm (void) mutex_lock(&sa_global_lock); 2443910Sdougm for (item = sa_global_handles; item != NULL; item = item->next) { 2454327Sdougm if (item->root == root) 2464327Sdougm break; 2473910Sdougm } 2483910Sdougm (void) mutex_unlock(&sa_global_lock); 2493910Sdougm if (item != NULL) 2504327Sdougm return (item->handle); 2513910Sdougm return (NULL); 2523910Sdougm } 2533910Sdougm 2543910Sdougm static int 2553910Sdougm add_handle_for_root(xmlNodePtr root, sa_handle_impl_t handle) 2563910Sdougm { 2573910Sdougm struct doc2handle *item; 2583910Sdougm int ret = SA_NO_MEMORY; 2593910Sdougm 2603910Sdougm item = (struct doc2handle *)calloc(sizeof (struct doc2handle), 1); 2613910Sdougm if (item != NULL) { 2624327Sdougm item->root = root; 2634327Sdougm item->handle = handle; 2644327Sdougm (void) mutex_lock(&sa_global_lock); 2654327Sdougm item->next = sa_global_handles; 2664327Sdougm sa_global_handles = item; 2674327Sdougm (void) mutex_unlock(&sa_global_lock); 2684327Sdougm ret = SA_OK; 2693910Sdougm } 2703910Sdougm return (ret); 2713910Sdougm } 2723910Sdougm 2733910Sdougm /* 2743910Sdougm * remove_handle_for_root(root) 2753910Sdougm * 2763910Sdougm * Walks the list of handles and removes the one for this "root" from 2773910Sdougm * the list. It is up to the caller to free the data. 2783910Sdougm */ 2793910Sdougm 2803910Sdougm static void 2813910Sdougm remove_handle_for_root(xmlNodePtr root) 2823910Sdougm { 2833910Sdougm struct doc2handle *item, *prev; 2843910Sdougm 2853910Sdougm (void) mutex_lock(&sa_global_lock); 2863910Sdougm for (prev = NULL, item = sa_global_handles; item != NULL; 2874327Sdougm item = item->next) { 2884327Sdougm if (item->root == root) { 2894327Sdougm /* first in the list */ 2904327Sdougm if (prev == NULL) 2914327Sdougm sa_global_handles = sa_global_handles->next; 2924327Sdougm else 2934327Sdougm prev->next = item->next; 2944327Sdougm /* Item is out of the list so free the list structure */ 2954327Sdougm free(item); 2964327Sdougm break; 2973910Sdougm } 2984327Sdougm prev = item; 2993910Sdougm } 3003910Sdougm (void) mutex_unlock(&sa_global_lock); 3013910Sdougm } 3023910Sdougm 3033910Sdougm /* 3043910Sdougm * sa_find_group_handle(sa_group_t group) 3053910Sdougm * 3063910Sdougm * Find the sa_handle_t for the configuration associated with this 3073910Sdougm * group. 3083910Sdougm */ 3093910Sdougm sa_handle_t 3103910Sdougm sa_find_group_handle(sa_group_t group) 3113910Sdougm { 3123910Sdougm xmlNodePtr node = (xmlNodePtr)group; 3133910Sdougm sa_handle_t handle; 3143910Sdougm 3153910Sdougm while (node != NULL) { 3164327Sdougm if (strcmp((char *)(node->name), "sharecfg") == 0) { 3174327Sdougm /* have the root so get the handle */ 3184327Sdougm handle = (sa_handle_t)get_handle_for_root(node); 3194327Sdougm return (handle); 3204327Sdougm } 3214327Sdougm node = node->parent; 3223910Sdougm } 3233910Sdougm return (NULL); 3243910Sdougm } 3253910Sdougm 3263910Sdougm /* 3273034Sdougm * set_legacy_timestamp(root, path, timevalue) 3283034Sdougm * 3293034Sdougm * add the current timestamp value to the configuration for use in 3303034Sdougm * determining when to update the legacy files. For SMF, this 3313034Sdougm * property is kept in default/operation/legacy_timestamp 3323034Sdougm */ 3333034Sdougm 3343034Sdougm static void 3353034Sdougm set_legacy_timestamp(xmlNodePtr root, char *path, uint64_t tval) 3363034Sdougm { 3373034Sdougm xmlNodePtr node; 3383034Sdougm xmlChar *lpath = NULL; 3393910Sdougm sa_handle_impl_t handle; 3403910Sdougm 3413910Sdougm /* Have to have a handle or else we weren't initialized. */ 3423910Sdougm handle = get_handle_for_root(root); 3433910Sdougm if (handle == NULL) 3444327Sdougm return; 3453034Sdougm 3463034Sdougm for (node = root->xmlChildrenNode; node != NULL; 3474327Sdougm node = node->next) { 3484327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"legacy") == 0) { 3494327Sdougm /* a possible legacy node for this path */ 3504327Sdougm lpath = xmlGetProp(node, (xmlChar *)"path"); 3514327Sdougm if (lpath != NULL && 3524327Sdougm xmlStrcmp(lpath, (xmlChar *)path) == 0) { 3534327Sdougm xmlFree(lpath); 3544327Sdougm break; 3554327Sdougm } 3564327Sdougm if (lpath != NULL) 3574327Sdougm xmlFree(lpath); 3583034Sdougm } 3593034Sdougm } 3603034Sdougm if (node == NULL) { 3614327Sdougm /* need to create the first legacy timestamp node */ 3624327Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"legacy", NULL); 3633034Sdougm } 3643034Sdougm if (node != NULL) { 3654327Sdougm char tstring[32]; 3664327Sdougm int ret; 3673034Sdougm 3684327Sdougm (void) snprintf(tstring, sizeof (tstring), "%lld", tval); 3696007Sthurlow (void) xmlSetProp(node, (xmlChar *)"timestamp", 3706007Sthurlow (xmlChar *)tstring); 3716007Sthurlow (void) xmlSetProp(node, (xmlChar *)"path", (xmlChar *)path); 3724327Sdougm /* now commit to SMF */ 3734327Sdougm ret = sa_get_instance(handle->scfhandle, "default"); 3743034Sdougm if (ret == SA_OK) { 3754327Sdougm ret = sa_start_transaction(handle->scfhandle, 3764327Sdougm "operation"); 3774327Sdougm if (ret == SA_OK) { 3784327Sdougm ret = sa_set_property(handle->scfhandle, 3794327Sdougm "legacy-timestamp", tstring); 3804327Sdougm if (ret == SA_OK) { 3814327Sdougm (void) sa_end_transaction( 3825951Sdougm handle->scfhandle, handle); 3834327Sdougm } else { 3844327Sdougm sa_abort_transaction(handle->scfhandle); 3854327Sdougm } 3864327Sdougm } 3873034Sdougm } 3883034Sdougm } 3893034Sdougm } 3903034Sdougm 3913034Sdougm /* 3923034Sdougm * is_shared(share) 3933034Sdougm * 3943034Sdougm * determine if the specified share is currently shared or not. 3953034Sdougm */ 3963034Sdougm static int 3973034Sdougm is_shared(sa_share_t share) 3983034Sdougm { 3993034Sdougm char *shared; 4003034Sdougm int result = 0; /* assume not */ 4013034Sdougm 4023034Sdougm shared = sa_get_share_attr(share, "shared"); 4033034Sdougm if (shared != NULL) { 4044327Sdougm if (strcmp(shared, "true") == 0) 4054327Sdougm result = 1; 4064327Sdougm sa_free_attr_string(shared); 4073034Sdougm } 4083034Sdougm return (result); 4093034Sdougm } 4103034Sdougm 4113034Sdougm /* 4125331Samw * excluded_protocol(share, proto) 4135331Samw * 4145331Samw * Returns B_TRUE if the specified protocol appears in the "exclude" 4155331Samw * property. This is used to prevent sharing special case shares 4165331Samw * (e.g. subdirs when SMB wants a subdir and NFS doesn't. B_FALSE is 4175331Samw * returned if the protocol isn't in the list. 4185331Samw */ 4195331Samw static boolean_t 4205331Samw excluded_protocol(sa_share_t share, char *proto) 4215331Samw { 4225331Samw char *protolist; 4235331Samw char *str; 4245331Samw char *token; 4255331Samw 4265331Samw protolist = sa_get_share_attr(share, "exclude"); 4275331Samw if (protolist != NULL) { 4285331Samw str = protolist; 4295331Samw while ((token = strtok(str, ",")) != NULL) { 4305331Samw if (strcmp(token, proto) == 0) { 4315331Samw sa_free_attr_string(protolist); 4325331Samw return (B_TRUE); 4335331Samw } 4345331Samw str = NULL; 4355331Samw } 4365331Samw sa_free_attr_string(protolist); 4375331Samw } 4385331Samw return (B_FALSE); 4395331Samw } 4405331Samw 4415331Samw /* 4423663Sdougm * checksubdirgroup(group, newpath, strictness) 4433348Sdougm * 4443663Sdougm * check all the specified newpath against all the paths in the 4453663Sdougm * group. This is a helper function for checksubdir to make it easier 4463663Sdougm * to also check ZFS subgroups. 4473663Sdougm * The strictness values mean: 4483348Sdougm * SA_CHECK_NORMAL == only check newpath against shares that are active 4493348Sdougm * SA_CHECK_STRICT == check newpath against both active shares and those 4503348Sdougm * stored in the repository 4513034Sdougm */ 4523034Sdougm static int 4533663Sdougm checksubdirgroup(sa_group_t group, char *newpath, int strictness) 4543034Sdougm { 4553034Sdougm sa_share_t share; 4563663Sdougm char *path; 4573663Sdougm int issub = SA_OK; 4585331Samw int subdir; 4595331Samw int parent; 4605331Samw 4615331Samw if (newpath == NULL) 4625331Samw return (SA_INVALID_PATH); 4633034Sdougm 4643663Sdougm for (share = sa_get_share(group, NULL); share != NULL; 4653663Sdougm share = sa_get_next_share(share)) { 4663034Sdougm /* 4673034Sdougm * The original behavior of share never checked 4683034Sdougm * against the permanent configuration 4693034Sdougm * (/etc/dfs/dfstab). PIT has a number of cases where 4703034Sdougm * it depends on this older behavior even though it 4713034Sdougm * could be considered incorrect. We may tighten this 4723034Sdougm * up in the future. 4733034Sdougm */ 4744327Sdougm if (strictness == SA_CHECK_NORMAL && !is_shared(share)) 4754327Sdougm continue; 4763034Sdougm 4774327Sdougm path = sa_get_share_attr(share, "path"); 4783348Sdougm /* 4793348Sdougm * If path is NULL, then a share is in the process of 4803348Sdougm * construction or someone has modified the property 4813663Sdougm * group inappropriately. It should be 4823663Sdougm * ignored. issubdir() comes from the original share 4833663Sdougm * implementation and does the difficult part of 4843663Sdougm * checking subdirectories. 4853348Sdougm */ 4864327Sdougm if (path == NULL) 4874327Sdougm continue; 4885331Samw 4895331Samw if (strcmp(path, newpath) == 0) { 4904327Sdougm issub = SA_INVALID_PATH; 4915331Samw } else { 4925331Samw subdir = issubdir(newpath, path); 4935331Samw parent = issubdir(path, newpath); 4945331Samw if (subdir || parent) { 4955331Samw sa_free_attr_string(path); 4965331Samw path = NULL; 4975331Samw return (subdir ? 4985331Samw SA_PATH_IS_SUBDIR : SA_PATH_IS_PARENTDIR); 4995331Samw } 5004327Sdougm } 5013034Sdougm sa_free_attr_string(path); 5023034Sdougm path = NULL; 5033663Sdougm } 5043663Sdougm return (issub); 5053663Sdougm } 5063663Sdougm 5073663Sdougm /* 5083663Sdougm * checksubdir(newpath, strictness) 5093663Sdougm * 5103663Sdougm * checksubdir determines if the specified path (newpath) is a 5113663Sdougm * subdirectory of another share. It calls checksubdirgroup() to do 5123663Sdougm * the complicated work. The strictness parameter determines how 5133663Sdougm * strict a check to make against the path. The strictness values 5143663Sdougm * mean: SA_CHECK_NORMAL == only check newpath against shares that are 5153663Sdougm * active SA_CHECK_STRICT == check newpath against both active shares 5163663Sdougm * and those * stored in the repository 5173663Sdougm */ 5183663Sdougm static int 5193910Sdougm checksubdir(sa_handle_t handle, char *newpath, int strictness) 5203663Sdougm { 5213663Sdougm sa_group_t group; 5225331Samw int issub = SA_OK; 5233663Sdougm char *path = NULL; 5243663Sdougm 5255331Samw for (group = sa_get_group(handle, NULL); 5265331Samw group != NULL && issub == SA_OK; 5275331Samw group = sa_get_next_group(group)) { 5284327Sdougm if (sa_group_is_zfs(group)) { 5294327Sdougm sa_group_t subgroup; 5304327Sdougm for (subgroup = sa_get_sub_group(group); 5315331Samw subgroup != NULL && issub == SA_OK; 5324327Sdougm subgroup = sa_get_next_group(subgroup)) 5334327Sdougm issub = checksubdirgroup(subgroup, newpath, 5344327Sdougm strictness); 5354327Sdougm } else { 5364327Sdougm issub = checksubdirgroup(group, newpath, strictness); 5374327Sdougm } 5383034Sdougm } 5393034Sdougm if (path != NULL) 5404327Sdougm sa_free_attr_string(path); 5413034Sdougm return (issub); 5423034Sdougm } 5433034Sdougm 5443034Sdougm /* 5453348Sdougm * validpath(path, strictness) 5463034Sdougm * determine if the provided path is valid for a share. It shouldn't 5473034Sdougm * be a sub-dir of an already shared path or the parent directory of a 5483034Sdougm * share path. 5493034Sdougm */ 5503034Sdougm static int 5513910Sdougm validpath(sa_handle_t handle, char *path, int strictness) 5523034Sdougm { 5533034Sdougm int error = SA_OK; 5543034Sdougm struct stat st; 5553034Sdougm sa_share_t share; 5563034Sdougm char *fstype; 5573034Sdougm 5584327Sdougm if (*path != '/') 5594327Sdougm return (SA_BAD_PATH); 5604327Sdougm 5613034Sdougm if (stat(path, &st) < 0) { 5624327Sdougm error = SA_NO_SUCH_PATH; 5633034Sdougm } else { 5644327Sdougm share = sa_find_share(handle, path); 5654327Sdougm if (share != NULL) 5664327Sdougm error = SA_DUPLICATE_NAME; 5674327Sdougm 5684327Sdougm if (error == SA_OK) { 5694327Sdougm /* 5704327Sdougm * check for special case with file system 5714327Sdougm * that might have restrictions. For now, ZFS 5724327Sdougm * is the only case since it has its own idea 5734327Sdougm * of how to configure shares. We do this 5744327Sdougm * before subdir checking since things like 5754327Sdougm * ZFS will do that for us. This should also 5764327Sdougm * be done via plugin interface. 5774327Sdougm */ 5784327Sdougm fstype = sa_fstype(path); 5794327Sdougm if (fstype != NULL && strcmp(fstype, "zfs") == 0) { 5804327Sdougm if (sa_zfs_is_shared(handle, path)) 5814327Sdougm error = SA_INVALID_NAME; 5824327Sdougm } 5834327Sdougm if (fstype != NULL) 5844327Sdougm sa_free_fstype(fstype); 5853034Sdougm } 5864327Sdougm if (error == SA_OK) 5874327Sdougm error = checksubdir(handle, path, strictness); 5883034Sdougm } 5893034Sdougm return (error); 5903034Sdougm } 5913034Sdougm 5923034Sdougm /* 5933034Sdougm * check to see if group/share is persistent. 5945331Samw * 5955331Samw * "group" can be either an sa_group_t or an sa_share_t. (void *) 5965331Samw * works since both thse types are also void *. 5973034Sdougm */ 5985331Samw int 5995331Samw sa_is_persistent(void *group) 6003034Sdougm { 6013034Sdougm char *type; 6023034Sdougm int persist = 1; 6033034Sdougm 6045331Samw type = sa_get_group_attr((sa_group_t)group, "type"); 6053034Sdougm if (type != NULL && strcmp(type, "transient") == 0) 6064327Sdougm persist = 0; 6073034Sdougm if (type != NULL) 6084327Sdougm sa_free_attr_string(type); 6093034Sdougm return (persist); 6103034Sdougm } 6113034Sdougm 6123034Sdougm /* 6133034Sdougm * sa_valid_group_name(name) 6143034Sdougm * 6153034Sdougm * check that the "name" contains only valid characters and otherwise 6163034Sdougm * fits the required naming conventions. Valid names must start with 6173034Sdougm * an alphabetic and the remainder may consist of only alphanumeric 6183034Sdougm * plus the '-' and '_' characters. This name limitation comes from 6193034Sdougm * inherent limitations in SMF. 6203034Sdougm */ 6213034Sdougm 6223034Sdougm int 6233034Sdougm sa_valid_group_name(char *name) 6243034Sdougm { 6253034Sdougm int ret = 1; 6263034Sdougm ssize_t len; 6273034Sdougm 6283034Sdougm if (name != NULL && isalpha(*name)) { 6294327Sdougm char c; 6304327Sdougm len = strlen(name); 6314327Sdougm if (len < (scf_max_name_len - sizeof ("group:"))) { 6324327Sdougm for (c = *name++; c != '\0' && ret != 0; c = *name++) { 6334327Sdougm if (!isalnum(c) && c != '-' && c != '_') 6344327Sdougm ret = 0; 6354327Sdougm } 6364327Sdougm } else { 6373034Sdougm ret = 0; 6383034Sdougm } 6394327Sdougm } else { 6403034Sdougm ret = 0; 6413034Sdougm } 6423034Sdougm return (ret); 6433034Sdougm } 6443034Sdougm 6453034Sdougm 6463034Sdougm /* 6473034Sdougm * is_zfs_group(group) 6483034Sdougm * Determine if the specified group is a ZFS sharenfs group 6493034Sdougm */ 6503034Sdougm static int 6513034Sdougm is_zfs_group(sa_group_t group) 6523034Sdougm { 6533034Sdougm int ret = 0; 6543034Sdougm xmlNodePtr parent; 6553034Sdougm xmlChar *zfs; 6563034Sdougm 6574327Sdougm if (strcmp((char *)((xmlNodePtr)group)->name, "share") == 0) 6584327Sdougm parent = (xmlNodePtr)sa_get_parent_group(group); 6594327Sdougm else 6604327Sdougm parent = (xmlNodePtr)group; 6613034Sdougm zfs = xmlGetProp(parent, (xmlChar *)"zfs"); 6623034Sdougm if (zfs != NULL) { 6634327Sdougm xmlFree(zfs); 6644327Sdougm ret = 1; 6653034Sdougm } 6663034Sdougm return (ret); 6673034Sdougm } 6683034Sdougm 6693034Sdougm /* 6705331Samw * sa_get_object_type(object) 6715331Samw * 6725331Samw * This function returns a numeric value representing the object 6735331Samw * type. This allows using simpler checks when doing type specific 6745331Samw * operations. 6755331Samw */ 6765331Samw 6775331Samw static int 6785331Samw sa_get_object_type(void *object) 6795331Samw { 6805331Samw xmlNodePtr node = (xmlNodePtr)object; 6815331Samw int type; 6825331Samw 6835331Samw if (xmlStrcmp(node->name, (xmlChar *)"group") == 0) 6845331Samw type = SA_TYPE_GROUP; 6855331Samw else if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) 6865331Samw type = SA_TYPE_SHARE; 6875331Samw else if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0) 6885331Samw type = SA_TYPE_RESOURCE; 6895331Samw else if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) 6905331Samw type = SA_TYPE_OPTIONSET; 6915331Samw else if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) 6925331Samw type = SA_TYPE_ALTSPACE; 6935331Samw else 6945331Samw assert(0); 6955331Samw return (type); 6965331Samw } 6975331Samw 6985331Samw /* 6993034Sdougm * sa_optionset_name(optionset, oname, len, id) 7003034Sdougm * return the SMF name for the optionset. If id is not NULL, it 7013034Sdougm * will have the GUID value for a share and should be used 7023034Sdougm * instead of the keyword "optionset" which is used for 7033034Sdougm * groups. If the optionset doesn't have a protocol type 7043034Sdougm * associated with it, "default" is used. This shouldn't happen 7053034Sdougm * at this point but may be desirable in the future if there are 7063034Sdougm * protocol independent properties added. The name is returned in 7073034Sdougm * oname. 7083034Sdougm */ 7093034Sdougm 7103034Sdougm static int 7113034Sdougm sa_optionset_name(sa_optionset_t optionset, char *oname, size_t len, char *id) 7123034Sdougm { 7133034Sdougm char *proto; 7145331Samw void *parent; 7155331Samw int ptype; 7163034Sdougm 7173034Sdougm if (id == NULL) 7184327Sdougm id = "optionset"; 7193034Sdougm 7205331Samw parent = sa_get_optionset_parent(optionset); 7215331Samw if (parent != NULL) { 7225331Samw ptype = sa_get_object_type(parent); 7235331Samw proto = sa_get_optionset_attr(optionset, "type"); 7245331Samw if (ptype != SA_TYPE_RESOURCE) { 7255331Samw len = snprintf(oname, len, "%s_%s", id, 7265331Samw proto ? proto : "default"); 7275331Samw } else { 7285331Samw char *index; 7295331Samw index = get_node_attr((void *)parent, "id"); 7305331Samw if (index != NULL) 7315331Samw len = snprintf(oname, len, "%s_%s_%s", id, 7325331Samw proto ? proto : "default", index); 7335331Samw else 7345331Samw len = 0; 7355331Samw } 7365331Samw 7375331Samw if (proto != NULL) 7385331Samw sa_free_attr_string(proto); 7395331Samw } else { 7405331Samw len = 0; 7415331Samw } 7423034Sdougm return (len); 7433034Sdougm } 7443034Sdougm 7453034Sdougm /* 7463034Sdougm * sa_security_name(optionset, oname, len, id) 7473034Sdougm * 7483034Sdougm * return the SMF name for the security. If id is not NULL, it will 7493034Sdougm * have the GUID value for a share and should be used instead of the 7503034Sdougm * keyword "optionset" which is used for groups. If the optionset 7513034Sdougm * doesn't have a protocol type associated with it, "default" is 7523034Sdougm * used. This shouldn't happen at this point but may be desirable in 7533034Sdougm * the future if there are protocol independent properties added. The 7543034Sdougm * name is returned in oname. The security type is also encoded into 7553034Sdougm * the name. In the future, this wil *be handled a bit differently. 7563034Sdougm */ 7573034Sdougm 7583034Sdougm static int 7593034Sdougm sa_security_name(sa_security_t security, char *oname, size_t len, char *id) 7603034Sdougm { 7613034Sdougm char *proto; 7623034Sdougm char *sectype; 7633034Sdougm 7643034Sdougm if (id == NULL) 7654327Sdougm id = "optionset"; 7663034Sdougm 7673034Sdougm proto = sa_get_security_attr(security, "type"); 7683034Sdougm sectype = sa_get_security_attr(security, "sectype"); 7694327Sdougm len = snprintf(oname, len, "%s_%s_%s", id, proto ? proto : "default", 7704327Sdougm sectype ? sectype : "default"); 7713034Sdougm if (proto != NULL) 7724327Sdougm sa_free_attr_string(proto); 7733034Sdougm if (sectype != NULL) 7744327Sdougm sa_free_attr_string(sectype); 7753034Sdougm return (len); 7763034Sdougm } 7773034Sdougm 7783034Sdougm /* 7794327Sdougm * verifydefgroupopts(handle) 7804327Sdougm * 7814327Sdougm * Make sure a "default" group exists and has default protocols enabled. 7824327Sdougm */ 7834327Sdougm static void 7844327Sdougm verifydefgroupopts(sa_handle_t handle) 7854327Sdougm { 7864327Sdougm sa_group_t defgrp; 7874327Sdougm sa_optionset_t opt; 7885331Samw 7894327Sdougm defgrp = sa_get_group(handle, "default"); 7904327Sdougm if (defgrp != NULL) { 7914327Sdougm opt = sa_get_optionset(defgrp, NULL); 7924327Sdougm /* 7934327Sdougm * NFS is the default for default group 7944327Sdougm */ 7954327Sdougm if (opt == NULL) 7964327Sdougm opt = sa_create_optionset(defgrp, "nfs"); 7974327Sdougm } 7984327Sdougm } 7994327Sdougm 8004327Sdougm /* 8013348Sdougm * sa_init(init_service) 8023034Sdougm * Initialize the API 8033034Sdougm * find all the shared objects 8043034Sdougm * init the tables with all objects 8053034Sdougm * read in the current configuration 8063034Sdougm */ 8073034Sdougm 8084327Sdougm #define GETPROP(prop) scf_simple_prop_next_astring(prop) 8094327Sdougm #define CHECKTSTAMP(st, tval) stat(SA_LEGACY_DFSTAB, &st) >= 0 && \ 8104327Sdougm tval != TSTAMP(st.st_ctim) 8114327Sdougm 8123910Sdougm sa_handle_t 8133034Sdougm sa_init(int init_service) 8143034Sdougm { 8153034Sdougm struct stat st; 8163034Sdougm int legacy = 0; 8173034Sdougm uint64_t tval = 0; 8183663Sdougm int lockfd; 8193663Sdougm sigset_t old; 8203663Sdougm int updatelegacy = B_FALSE; 8213663Sdougm scf_simple_prop_t *prop; 8223910Sdougm sa_handle_impl_t handle; 8233910Sdougm int err; 8243034Sdougm 8253910Sdougm handle = calloc(sizeof (struct sa_handle_impl), 1); 8263910Sdougm 8273910Sdougm if (handle != NULL) { 8286304Sdougm /* 8296304Sdougm * Get protocol specific structures, but only if this 8306304Sdougm * is the only handle. 8316304Sdougm */ 8326304Sdougm (void) mutex_lock(&sa_global_lock); 8336304Sdougm if (sa_global_handles == NULL) 8346304Sdougm (void) proto_plugin_init(); 8356304Sdougm (void) mutex_unlock(&sa_global_lock); 8364327Sdougm if (init_service & SA_INIT_SHARE_API) { 8373663Sdougm /* 8384327Sdougm * initialize access into libzfs. We use this 8394327Sdougm * when collecting info about ZFS datasets and 8404327Sdougm * shares. 8413663Sdougm */ 8424327Sdougm if (sa_zfs_init(handle) == B_FALSE) { 8434327Sdougm free(handle); 8448474SJose.Borrego@Sun.COM (void) mutex_lock(&sa_global_lock); 8454327Sdougm (void) proto_plugin_fini(); 8468474SJose.Borrego@Sun.COM (void) mutex_unlock(&sa_global_lock); 8474327Sdougm return (NULL); 8484327Sdougm } 8493663Sdougm /* 8504327Sdougm * since we want to use SMF, initialize an svc handle 8514327Sdougm * and find out what is there. 8523663Sdougm */ 8534327Sdougm handle->scfhandle = sa_scf_init(handle); 8544327Sdougm if (handle->scfhandle != NULL) { 8554327Sdougm /* 8564327Sdougm * Need to lock the extraction of the 8574327Sdougm * configuration if the dfstab file has 8584327Sdougm * changed. Lock everything now and release if 8594327Sdougm * not needed. Use a file that isn't being 8604327Sdougm * manipulated by other parts of the system in 8614327Sdougm * order to not interfere with locking. Using 8624327Sdougm * dfstab doesn't work. 8634327Sdougm */ 8644327Sdougm sablocksigs(&old); 8654327Sdougm lockfd = open(DFS_LOCK_FILE, O_RDWR); 8664327Sdougm if (lockfd >= 0) { 8674327Sdougm extern int errno; 8684327Sdougm errno = 0; 8694327Sdougm (void) lockf(lockfd, F_LOCK, 0); 8704327Sdougm /* 8714327Sdougm * Check whether we are going to need 8724327Sdougm * to merge any dfstab changes. This 8734327Sdougm * is done by comparing the value of 8744327Sdougm * legacy-timestamp with the current 8754327Sdougm * st_ctim of the file. If they are 8764327Sdougm * different, an update is needed and 8774327Sdougm * the file must remain locked until 8784327Sdougm * the merge is done in order to 8794327Sdougm * prevent multiple startups from 8804327Sdougm * changing the SMF repository at the 8814327Sdougm * same time. The first to get the 8824327Sdougm * lock will make any changes before 8834327Sdougm * the others can read the repository. 8844327Sdougm */ 8854327Sdougm prop = scf_simple_prop_get 8864327Sdougm (handle->scfhandle->handle, 8874327Sdougm (const char *)SA_SVC_FMRI_BASE 8884327Sdougm ":default", "operation", 8894327Sdougm "legacy-timestamp"); 8904327Sdougm if (prop != NULL) { 8914327Sdougm char *i64; 8924327Sdougm i64 = GETPROP(prop); 8934327Sdougm if (i64 != NULL) 8944327Sdougm tval = strtoull(i64, 8954327Sdougm NULL, 0); 8964327Sdougm if (CHECKTSTAMP(st, tval)) 8974327Sdougm updatelegacy = B_TRUE; 8984327Sdougm scf_simple_prop_free(prop); 8994327Sdougm } else { 9004327Sdougm /* 9014327Sdougm * We haven't set the 9024327Sdougm * timestamp before so do it. 9034327Sdougm */ 9044327Sdougm updatelegacy = B_TRUE; 9054327Sdougm } 9064327Sdougm } 9074327Sdougm if (updatelegacy == B_FALSE) { 9084327Sdougm /* Don't need the lock anymore */ 9094327Sdougm (void) lockf(lockfd, F_ULOCK, 0); 9104327Sdougm (void) close(lockfd); 9114327Sdougm } 9123973Sdougm 9134327Sdougm /* 9144327Sdougm * It is essential that the document tree and 9154327Sdougm * the internal list of roots to handles be 9164327Sdougm * setup before anything that might try to 9174327Sdougm * create a new object is called. The document 9184327Sdougm * tree is the combination of handle->doc and 9194327Sdougm * handle->tree. This allows searches, 9204327Sdougm * etc. when all you have is an object in the 9214327Sdougm * tree. 9224327Sdougm */ 9234327Sdougm handle->doc = xmlNewDoc((xmlChar *)"1.0"); 9244327Sdougm handle->tree = xmlNewNode(NULL, 9254327Sdougm (xmlChar *)"sharecfg"); 9264327Sdougm if (handle->doc != NULL && 9274327Sdougm handle->tree != NULL) { 9286007Sthurlow (void) xmlDocSetRootElement(handle->doc, 9294327Sdougm handle->tree); 9304327Sdougm err = add_handle_for_root(handle->tree, 9314327Sdougm handle); 9324327Sdougm if (err == SA_OK) 9334327Sdougm err = sa_get_config( 9344327Sdougm handle->scfhandle, 9353973Sdougm handle->tree, handle); 9364327Sdougm } else { 9374327Sdougm if (handle->doc != NULL) 9384327Sdougm xmlFreeDoc(handle->doc); 9394327Sdougm if (handle->tree != NULL) 9404327Sdougm xmlFreeNode(handle->tree); 9414327Sdougm err = SA_NO_MEMORY; 9424327Sdougm } 9433973Sdougm 9444327Sdougm saunblocksigs(&old); 9453910Sdougm 9464327Sdougm if (err != SA_OK) { 9474327Sdougm /* 9484327Sdougm * If we couldn't add the tree handle 9494327Sdougm * to the list, then things are going 9504327Sdougm * to fail badly. Might as well undo 9514327Sdougm * everything now and fail the 9524327Sdougm * sa_init(). 9534327Sdougm */ 9544327Sdougm sa_fini(handle); 9554327Sdougm return (NULL); 9564327Sdougm } 9573910Sdougm 9584327Sdougm if (tval == 0) { 9594327Sdougm /* 9604327Sdougm * first time so make sure 9614327Sdougm * default is setup 9624327Sdougm */ 9634327Sdougm verifydefgroupopts(handle); 9644327Sdougm } 9653973Sdougm 9664524Sdougm if (updatelegacy == B_TRUE) { 9674524Sdougm sablocksigs(&old); 9684524Sdougm getlegacyconfig((sa_handle_t)handle, 9694524Sdougm SA_LEGACY_DFSTAB, &handle->tree); 9704524Sdougm if (stat(SA_LEGACY_DFSTAB, &st) >= 0) 9714524Sdougm set_legacy_timestamp( 9724524Sdougm handle->tree, 9734524Sdougm SA_LEGACY_DFSTAB, 9744524Sdougm TSTAMP(st.st_ctim)); 9754524Sdougm saunblocksigs(&old); 9764524Sdougm /* 9774524Sdougm * Safe to unlock now to allow 9784524Sdougm * others to run 9794524Sdougm */ 9804524Sdougm (void) lockf(lockfd, F_ULOCK, 0); 9814524Sdougm (void) close(lockfd); 9824524Sdougm } 9835951Sdougm /* Get sharetab timestamp */ 9845951Sdougm sa_update_sharetab_ts((sa_handle_t)handle); 9855951Sdougm 9865951Sdougm /* Get lastupdate (transaction) timestamp */ 9875951Sdougm prop = scf_simple_prop_get( 9885951Sdougm handle->scfhandle->handle, 9895951Sdougm (const char *)SA_SVC_FMRI_BASE ":default", 9905951Sdougm "state", "lastupdate"); 9915951Sdougm if (prop != NULL) { 9925951Sdougm char *str; 9935951Sdougm str = 9945951Sdougm scf_simple_prop_next_astring(prop); 9955951Sdougm if (str != NULL) 9965951Sdougm handle->tstrans = 9975951Sdougm strtoull(str, NULL, 0); 9985951Sdougm else 9995951Sdougm handle->tstrans = 0; 10005951Sdougm scf_simple_prop_free(prop); 10015951Sdougm } 10024524Sdougm legacy |= sa_get_zfs_shares(handle, "zfs"); 10034524Sdougm legacy |= gettransients(handle, &handle->tree); 10044327Sdougm } 10054327Sdougm } 10063034Sdougm } 10073910Sdougm return ((sa_handle_t)handle); 10083034Sdougm } 10093034Sdougm 10103034Sdougm /* 10113910Sdougm * sa_fini(handle) 10123034Sdougm * Uninitialize the API structures including the configuration 10133218Sdougm * data structures and ZFS related data. 10143034Sdougm */ 10153034Sdougm 10163034Sdougm void 10173910Sdougm sa_fini(sa_handle_t handle) 10183034Sdougm { 10193910Sdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle; 10203910Sdougm 10213910Sdougm if (impl_handle != NULL) { 10223910Sdougm /* 10233910Sdougm * Free the config trees and any other data structures 10243910Sdougm * used in the handle. 10253910Sdougm */ 10263910Sdougm if (impl_handle->doc != NULL) 10273910Sdougm xmlFreeDoc(impl_handle->doc); 10283910Sdougm 10293910Sdougm /* Remove and free the entry in the global list. */ 10303910Sdougm remove_handle_for_root(impl_handle->tree); 10313910Sdougm 10323910Sdougm /* 10333910Sdougm * If this was the last handle to release, unload the 10346304Sdougm * plugins that were loaded. Use a mutex in case 10356304Sdougm * another thread is reinitializing. 10363910Sdougm */ 10376304Sdougm (void) mutex_lock(&sa_global_lock); 10383910Sdougm if (sa_global_handles == NULL) 10394327Sdougm (void) proto_plugin_fini(); 10406304Sdougm (void) mutex_unlock(&sa_global_lock); 10413910Sdougm 10427010Sgwr sa_scf_fini(impl_handle->scfhandle); 10437010Sgwr sa_zfs_fini(impl_handle); 10447010Sgwr 10457010Sgwr /* Make sure we free the handle */ 10467010Sgwr free(impl_handle); 10477010Sgwr 10483034Sdougm } 10493034Sdougm } 10503034Sdougm 10513034Sdougm /* 10523034Sdougm * sa_get_protocols(char **protocol) 10533034Sdougm * Get array of protocols that are supported 10543034Sdougm * Returns pointer to an allocated and NULL terminated 10553034Sdougm * array of strings. Caller must free. 10563034Sdougm * This really should be determined dynamically. 10573034Sdougm * If there aren't any defined, return -1. 10583034Sdougm * Use free() to return memory. 10593034Sdougm */ 10603034Sdougm 10613034Sdougm int 10623034Sdougm sa_get_protocols(char ***protocols) 10633034Sdougm { 10643034Sdougm int numproto = -1; 10653034Sdougm 10663034Sdougm if (protocols != NULL) { 10674327Sdougm struct sa_proto_plugin *plug; 10684327Sdougm for (numproto = 0, plug = sap_proto_list; plug != NULL; 10694327Sdougm plug = plug->plugin_next) { 10704327Sdougm numproto++; 10714327Sdougm } 10723034Sdougm 10734327Sdougm *protocols = calloc(numproto + 1, sizeof (char *)); 10744327Sdougm if (*protocols != NULL) { 10754327Sdougm int ret = 0; 10764327Sdougm for (plug = sap_proto_list; plug != NULL; 10774327Sdougm plug = plug->plugin_next) { 10784327Sdougm /* faking for now */ 10794327Sdougm (*protocols)[ret++] = 10804327Sdougm plug->plugin_ops->sa_protocol; 10814327Sdougm } 10824327Sdougm } else { 10834327Sdougm numproto = -1; 10843034Sdougm } 10853034Sdougm } 10863034Sdougm return (numproto); 10873034Sdougm } 10883034Sdougm 10893034Sdougm /* 10903034Sdougm * find_group_by_name(node, group) 10913034Sdougm * 10923034Sdougm * search the XML document subtree specified by node to find the group 10933034Sdougm * specified by group. Searching subtree allows subgroups to be 10943034Sdougm * searched for. 10953034Sdougm */ 10963034Sdougm 10973034Sdougm static xmlNodePtr 10983034Sdougm find_group_by_name(xmlNodePtr node, xmlChar *group) 10993034Sdougm { 11003034Sdougm xmlChar *name = NULL; 11013034Sdougm 11023034Sdougm for (node = node->xmlChildrenNode; node != NULL; 11033034Sdougm node = node->next) { 11044327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"group") == 0) { 11054327Sdougm /* if no groupname, return the first found */ 11064327Sdougm if (group == NULL) 11074327Sdougm break; 11084327Sdougm name = xmlGetProp(node, (xmlChar *)"name"); 11094327Sdougm if (name != NULL && xmlStrcmp(name, group) == 0) 11104327Sdougm break; 11114327Sdougm if (name != NULL) { 11124327Sdougm xmlFree(name); 11134327Sdougm name = NULL; 11144327Sdougm } 11153034Sdougm } 11163034Sdougm } 11173034Sdougm if (name != NULL) 11184327Sdougm xmlFree(name); 11193034Sdougm return (node); 11203034Sdougm } 11213034Sdougm 11223034Sdougm /* 11233034Sdougm * sa_get_group(groupname) 11243034Sdougm * Return the "group" specified. If groupname is NULL, 11253034Sdougm * return the first group of the list of groups. 11263034Sdougm */ 11273034Sdougm sa_group_t 11283910Sdougm sa_get_group(sa_handle_t handle, char *groupname) 11293034Sdougm { 11303034Sdougm xmlNodePtr node = NULL; 11313034Sdougm char *subgroup = NULL; 11323034Sdougm char *group = NULL; 11333910Sdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle; 11343034Sdougm 11353910Sdougm if (impl_handle != NULL && impl_handle->tree != NULL) { 11364327Sdougm if (groupname != NULL) { 11374327Sdougm group = strdup(groupname); 11384345Sdougm if (group != NULL) { 11394345Sdougm subgroup = strchr(group, '/'); 11404345Sdougm if (subgroup != NULL) 11414345Sdougm *subgroup++ = '\0'; 11424345Sdougm } 11434327Sdougm } 11444345Sdougm /* 11454345Sdougm * We want to find the, possibly, named group. If 11464345Sdougm * group is not NULL, then lookup the name. If it is 11474345Sdougm * NULL, we only do the find if groupname is also 11484345Sdougm * NULL. This allows lookup of the "first" group in 11494345Sdougm * the internal list. 11504345Sdougm */ 11514345Sdougm if (group != NULL || groupname == NULL) 11524345Sdougm node = find_group_by_name(impl_handle->tree, 11534345Sdougm (xmlChar *)group); 11544345Sdougm 11554327Sdougm /* if a subgroup, find it before returning */ 11564327Sdougm if (subgroup != NULL && node != NULL) 11574327Sdougm node = find_group_by_name(node, (xmlChar *)subgroup); 11583034Sdougm } 11593034Sdougm if (node != NULL && (char *)group != NULL) 11604327Sdougm (void) sa_get_instance(impl_handle->scfhandle, (char *)group); 11613034Sdougm if (group != NULL) 11624327Sdougm free(group); 11633034Sdougm return ((sa_group_t)(node)); 11643034Sdougm } 11653034Sdougm 11663034Sdougm /* 11673034Sdougm * sa_get_next_group(group) 11683034Sdougm * Return the "next" group after the specified group from 11693034Sdougm * the internal group list. NULL if there are no more. 11703034Sdougm */ 11713034Sdougm sa_group_t 11723034Sdougm sa_get_next_group(sa_group_t group) 11733034Sdougm { 11743034Sdougm xmlNodePtr ngroup = NULL; 11753034Sdougm if (group != NULL) { 11764327Sdougm for (ngroup = ((xmlNodePtr)group)->next; ngroup != NULL; 11773034Sdougm ngroup = ngroup->next) { 11784327Sdougm if (xmlStrcmp(ngroup->name, (xmlChar *)"group") == 0) 11794327Sdougm break; 11804327Sdougm } 11813034Sdougm } 11823034Sdougm return ((sa_group_t)ngroup); 11833034Sdougm } 11843034Sdougm 11853034Sdougm /* 11863034Sdougm * sa_get_share(group, sharepath) 11873034Sdougm * Return the share object for the share specified. The share 11883034Sdougm * must be in the specified group. Return NULL if not found. 11893034Sdougm */ 11903034Sdougm sa_share_t 11913034Sdougm sa_get_share(sa_group_t group, char *sharepath) 11923034Sdougm { 11933034Sdougm xmlNodePtr node = NULL; 11943034Sdougm xmlChar *path; 11953034Sdougm 11963034Sdougm /* 11973034Sdougm * For future scalability, this should end up building a cache 11983034Sdougm * since it will get called regularly by the mountd and info 11993034Sdougm * services. 12003034Sdougm */ 12013034Sdougm if (group != NULL) { 12024327Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 12033034Sdougm node = node->next) { 12044327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) { 12054327Sdougm if (sharepath == NULL) { 12064327Sdougm break; 12074327Sdougm } else { 12084327Sdougm /* is it the correct share? */ 12094327Sdougm path = xmlGetProp(node, 12104327Sdougm (xmlChar *)"path"); 12114327Sdougm if (path != NULL && 12124327Sdougm xmlStrcmp(path, 12134327Sdougm (xmlChar *)sharepath) == 0) { 12144327Sdougm xmlFree(path); 12154327Sdougm break; 12164327Sdougm } 12174327Sdougm xmlFree(path); 12184327Sdougm } 12193034Sdougm } 12203034Sdougm } 12213034Sdougm } 12223034Sdougm return ((sa_share_t)node); 12233034Sdougm } 12243034Sdougm 12253034Sdougm /* 12263034Sdougm * sa_get_next_share(share) 12273034Sdougm * Return the next share following the specified share 12283034Sdougm * from the internal list of shares. Returns NULL if there 12293034Sdougm * are no more shares. The list is relative to the same 12303034Sdougm * group. 12313034Sdougm */ 12323034Sdougm sa_share_t 12333034Sdougm sa_get_next_share(sa_share_t share) 12343034Sdougm { 12353034Sdougm xmlNodePtr node = NULL; 12363034Sdougm 12373034Sdougm if (share != NULL) { 12384327Sdougm for (node = ((xmlNodePtr)share)->next; node != NULL; 12393034Sdougm node = node->next) { 12404327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) { 12414327Sdougm break; 12424327Sdougm } 12433034Sdougm } 12443034Sdougm } 12453034Sdougm return ((sa_share_t)node); 12463034Sdougm } 12473034Sdougm 12483034Sdougm /* 12493034Sdougm * _sa_get_child_node(node, type) 12503034Sdougm * 12513034Sdougm * find the child node of the specified node that has "type". This is 12523034Sdougm * used to implement several internal functions. 12533034Sdougm */ 12543034Sdougm 12553034Sdougm static xmlNodePtr 12563034Sdougm _sa_get_child_node(xmlNodePtr node, xmlChar *type) 12573034Sdougm { 12583034Sdougm xmlNodePtr child; 12593034Sdougm for (child = node->xmlChildrenNode; child != NULL; 12603034Sdougm child = child->next) 12614327Sdougm if (xmlStrcmp(child->name, type) == 0) 12624327Sdougm return (child); 12633034Sdougm return ((xmlNodePtr)NULL); 12643034Sdougm } 12653034Sdougm 12663034Sdougm /* 12673034Sdougm * find_share(group, path) 12683034Sdougm * 12693034Sdougm * Search all the shares in the specified group for one that has the 12703034Sdougm * specified path. 12713034Sdougm */ 12723034Sdougm 12733034Sdougm static sa_share_t 12743034Sdougm find_share(sa_group_t group, char *sharepath) 12753034Sdougm { 12763034Sdougm sa_share_t share; 12773034Sdougm char *path; 12783034Sdougm 12793034Sdougm for (share = sa_get_share(group, NULL); share != NULL; 12803034Sdougm share = sa_get_next_share(share)) { 12814327Sdougm path = sa_get_share_attr(share, "path"); 12824327Sdougm if (path != NULL && strcmp(path, sharepath) == 0) { 12834327Sdougm sa_free_attr_string(path); 12844327Sdougm break; 12854327Sdougm } 12864327Sdougm if (path != NULL) 12874327Sdougm sa_free_attr_string(path); 12883034Sdougm } 12893034Sdougm return (share); 12903034Sdougm } 12913034Sdougm 12923034Sdougm /* 12933034Sdougm * sa_get_sub_group(group) 12943034Sdougm * 12953034Sdougm * Get the first sub-group of group. The sa_get_next_group() function 12963034Sdougm * can be used to get the rest. This is currently only used for ZFS 12973034Sdougm * sub-groups but could be used to implement a more general mechanism. 12983034Sdougm */ 12993034Sdougm 13003034Sdougm sa_group_t 13013034Sdougm sa_get_sub_group(sa_group_t group) 13023034Sdougm { 13033034Sdougm return ((sa_group_t)_sa_get_child_node((xmlNodePtr)group, 13044327Sdougm (xmlChar *)"group")); 13053034Sdougm } 13063034Sdougm 13073034Sdougm /* 13083034Sdougm * sa_find_share(sharepath) 13093034Sdougm * Finds a share regardless of group. In the future, this 13103034Sdougm * function should utilize a cache and hash table of some kind. 13113034Sdougm * The current assumption is that a path will only be shared 13123034Sdougm * once. In the future, this may change as implementation of 13133034Sdougm * resource names comes into being. 13143034Sdougm */ 13153034Sdougm sa_share_t 13163910Sdougm sa_find_share(sa_handle_t handle, char *sharepath) 13173034Sdougm { 13183034Sdougm sa_group_t group; 13193034Sdougm sa_group_t zgroup; 13203034Sdougm sa_share_t share = NULL; 13213034Sdougm int done = 0; 13223034Sdougm 13233910Sdougm for (group = sa_get_group(handle, NULL); group != NULL && !done; 13244327Sdougm group = sa_get_next_group(group)) { 13254327Sdougm if (is_zfs_group(group)) { 13264327Sdougm for (zgroup = 13274327Sdougm (sa_group_t)_sa_get_child_node((xmlNodePtr)group, 13284327Sdougm (xmlChar *)"group"); 13294327Sdougm zgroup != NULL; 13304327Sdougm zgroup = sa_get_next_group(zgroup)) { 13314327Sdougm share = find_share(zgroup, sharepath); 13324327Sdougm if (share != NULL) 13334327Sdougm break; 13344327Sdougm } 13354327Sdougm } else { 13364327Sdougm share = find_share(group, sharepath); 13374327Sdougm } 13384327Sdougm if (share != NULL) 13393034Sdougm break; 13403034Sdougm } 13413034Sdougm return (share); 13423034Sdougm } 13433034Sdougm 13443034Sdougm /* 13453348Sdougm * sa_check_path(group, path, strictness) 13463034Sdougm * 13475331Samw * Check that path is a valid path relative to the group. Currently, 13483034Sdougm * we are ignoring the group and checking only the NFS rules. Later, 13493034Sdougm * we may want to use the group to then check against the protocols 13503348Sdougm * enabled on the group. The strictness values mean: 13513348Sdougm * SA_CHECK_NORMAL == only check newpath against shares that are active 13523348Sdougm * SA_CHECK_STRICT == check newpath against both active shares and those 13533348Sdougm * stored in the repository 13543034Sdougm */ 13553034Sdougm 13563034Sdougm int 13573348Sdougm sa_check_path(sa_group_t group, char *path, int strictness) 13583034Sdougm { 13593910Sdougm sa_handle_t handle; 13603910Sdougm 13613910Sdougm handle = sa_find_group_handle(group); 13623910Sdougm return (validpath(handle, path, strictness)); 13633034Sdougm } 13643034Sdougm 13653034Sdougm /* 13665331Samw * mark_excluded_protos(group, share, flags) 13673034Sdougm * 13685331Samw * Walk through all the protocols enabled for the group and check to 13695331Samw * see if the share has any of them should be in the exclude list 13705331Samw * based on the featureset of the protocol. If there are any, add the 13715331Samw * "exclude" property to the share. 13725331Samw */ 13735331Samw static void 13745331Samw mark_excluded_protos(sa_group_t group, xmlNodePtr share, uint64_t flags) 13755331Samw { 13765331Samw sa_optionset_t optionset; 13775331Samw char exclude_list[SA_STRSIZE]; 13785331Samw char *sep = ""; 13795331Samw 13805331Samw exclude_list[0] = '\0'; 13815331Samw for (optionset = sa_get_optionset(group, NULL); 13825331Samw optionset != NULL; 13835331Samw optionset = sa_get_next_optionset(optionset)) { 13845331Samw char *value; 13855331Samw uint64_t features; 13865331Samw value = sa_get_optionset_attr(optionset, "type"); 13875331Samw if (value == NULL) 13885331Samw continue; 13895331Samw features = sa_proto_get_featureset(value); 13905331Samw sa_free_attr_string(value); 13915331Samw if (!(features & flags)) { 13925331Samw (void) strlcat(exclude_list, sep, 13935331Samw sizeof (exclude_list)); 13945331Samw (void) strlcat(exclude_list, value, 13955331Samw sizeof (exclude_list)); 13965331Samw sep = ","; 13975331Samw } 13985331Samw } 13995331Samw if (exclude_list[0] != '\0') 14006007Sthurlow (void) xmlSetProp(share, (xmlChar *)"exclude", 14015331Samw (xmlChar *)exclude_list); 14025331Samw } 14035331Samw 14045331Samw /* 14055331Samw * get_all_features(group) 14065331Samw * 14075331Samw * Walk through all the protocols on the group and collect all 14085331Samw * possible enabled features. This is the OR of all the featuresets. 14095331Samw */ 14105331Samw static uint64_t 14115331Samw get_all_features(sa_group_t group) 14125331Samw { 14135331Samw sa_optionset_t optionset; 14145331Samw uint64_t features = 0; 14155331Samw 14165331Samw for (optionset = sa_get_optionset(group, NULL); 14175331Samw optionset != NULL; 14185331Samw optionset = sa_get_next_optionset(optionset)) { 14195331Samw char *value; 14205331Samw value = sa_get_optionset_attr(optionset, "type"); 14215331Samw if (value == NULL) 14225331Samw continue; 14235331Samw features |= sa_proto_get_featureset(value); 14245331Samw sa_free_attr_string(value); 14255331Samw } 14265331Samw return (features); 14275331Samw } 14285331Samw 14295331Samw 14305331Samw /* 14315331Samw * _sa_add_share(group, sharepath, persist, *error, flags) 14325331Samw * 14335331Samw * Common code for all types of add_share. sa_add_share() is the 14343034Sdougm * public API, we also need to be able to do this when parsing legacy 14353034Sdougm * files and construction of the internal configuration while 14365331Samw * extracting config info from SMF. "flags" indicates if some 14375331Samw * protocols need relaxed rules while other don't. These values are 14385331Samw * the featureset values defined in libshare.h. 14393034Sdougm */ 14403034Sdougm 14413034Sdougm sa_share_t 14425331Samw _sa_add_share(sa_group_t group, char *sharepath, int persist, int *error, 14435331Samw uint64_t flags) 14443034Sdougm { 14453034Sdougm xmlNodePtr node = NULL; 14463034Sdougm int err; 14473034Sdougm 14483034Sdougm err = SA_OK; /* assume success */ 14493034Sdougm 14504327Sdougm node = xmlNewChild((xmlNodePtr)group, NULL, (xmlChar *)"share", NULL); 14515331Samw if (node == NULL) { 14525331Samw if (error != NULL) 14535331Samw *error = SA_NO_MEMORY; 14545331Samw return (node); 14555331Samw } 14565331Samw 14576007Sthurlow (void) xmlSetProp(node, (xmlChar *)"path", (xmlChar *)sharepath); 14586007Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", 14595331Samw persist ? (xmlChar *)"persist" : (xmlChar *)"transient"); 14605331Samw if (flags != 0) 14615331Samw mark_excluded_protos(group, node, flags); 14625331Samw if (persist != SA_SHARE_TRANSIENT) { 14635331Samw /* 14645331Samw * persistent shares come in two flavors: SMF and 14655331Samw * ZFS. Sort this one out based on target group and 14665331Samw * path type. Both NFS and SMB are supported. First, 14675331Samw * check to see if the protocol is enabled on the 14685331Samw * subgroup and then setup the share appropriately. 14695331Samw */ 14705331Samw if (sa_group_is_zfs(group) && 14715331Samw sa_path_is_zfs(sharepath)) { 14725331Samw if (sa_get_optionset(group, "nfs") != NULL) 14734327Sdougm err = sa_zfs_set_sharenfs(group, sharepath, 1); 14745331Samw else if (sa_get_optionset(group, "smb") != NULL) 14755331Samw err = sa_zfs_set_sharesmb(group, sharepath, 1); 14765331Samw } else { 14775331Samw sa_handle_impl_t impl_handle; 14785331Samw impl_handle = 14795331Samw (sa_handle_impl_t)sa_find_group_handle(group); 14805331Samw if (impl_handle != NULL) { 14815331Samw err = sa_commit_share(impl_handle->scfhandle, 14825331Samw group, (sa_share_t)node); 14834327Sdougm } else { 14845331Samw err = SA_SYSTEM_ERR; 14854327Sdougm } 14863034Sdougm } 14873034Sdougm } 14885331Samw if (err == SA_NO_PERMISSION && persist & SA_SHARE_PARSER) 14895331Samw /* called by the dfstab parser so could be a show */ 14905331Samw err = SA_OK; 14915331Samw 14925331Samw if (err != SA_OK) { 14935331Samw /* 14945331Samw * we couldn't commit to the repository so undo 14955331Samw * our internal state to reflect reality. 14965331Samw */ 14975331Samw xmlUnlinkNode(node); 14985331Samw xmlFreeNode(node); 14995331Samw node = NULL; 15005331Samw } 15015331Samw 15023034Sdougm if (error != NULL) 15034327Sdougm *error = err; 15045331Samw 15053034Sdougm return (node); 15063034Sdougm } 15073034Sdougm 15083034Sdougm /* 15093034Sdougm * sa_add_share(group, sharepath, persist, *error) 15103034Sdougm * 15113034Sdougm * Add a new share object to the specified group. The share will 15123034Sdougm * have the specified sharepath and will only be constructed if 15133034Sdougm * it is a valid path to be shared. NULL is returned on error 15143034Sdougm * and a detailed error value will be returned via the error 15153034Sdougm * pointer. 15163034Sdougm */ 15173034Sdougm sa_share_t 15183034Sdougm sa_add_share(sa_group_t group, char *sharepath, int persist, int *error) 15193034Sdougm { 15203034Sdougm xmlNodePtr node = NULL; 15213348Sdougm int strictness = SA_CHECK_NORMAL; 15223910Sdougm sa_handle_t handle; 15235331Samw uint64_t special = 0; 15245331Samw uint64_t features; 15253348Sdougm 15263348Sdougm /* 15273348Sdougm * If the share is to be permanent, use strict checking so a 15283348Sdougm * bad config doesn't get created. Transient shares only need 15293348Sdougm * to check against the currently active 15303348Sdougm * shares. SA_SHARE_PARSER is a modifier used internally to 15313348Sdougm * indicate that we are being called by the dfstab parser and 15323348Sdougm * that we need strict checking in all cases. Normally persist 15333348Sdougm * is in integer value but SA_SHARE_PARSER may be or'd into 15343348Sdougm * it as an override. 15353348Sdougm */ 15363348Sdougm if (persist & SA_SHARE_PARSER || persist == SA_SHARE_PERMANENT) 15374327Sdougm strictness = SA_CHECK_STRICT; 15383034Sdougm 15393910Sdougm handle = sa_find_group_handle(group); 15403910Sdougm 15415331Samw /* 15425331Samw * need to determine if the share is valid. The rules are: 15435331Samw * - The path must not already exist 15445331Samw * - The path must not be a subdir or parent dir of an 15455331Samw * existing path unless at least one protocol allows it. 15465331Samw * The sub/parent check is done in sa_check_path(). 15475331Samw */ 15485331Samw 15495331Samw if (sa_find_share(handle, sharepath) == NULL) { 15505331Samw *error = sa_check_path(group, sharepath, strictness); 15515331Samw features = get_all_features(group); 15525331Samw switch (*error) { 15535331Samw case SA_PATH_IS_SUBDIR: 15545331Samw if (features & SA_FEATURE_ALLOWSUBDIRS) 15555331Samw special |= SA_FEATURE_ALLOWSUBDIRS; 15565331Samw break; 15575331Samw case SA_PATH_IS_PARENTDIR: 15585331Samw if (features & SA_FEATURE_ALLOWPARDIRS) 15595331Samw special |= SA_FEATURE_ALLOWPARDIRS; 15605331Samw break; 15615331Samw } 15625331Samw if (*error == SA_OK || special != SA_FEATURE_NONE) 15635331Samw node = _sa_add_share(group, sharepath, persist, 15645331Samw error, special); 15655331Samw } else { 15665331Samw *error = SA_DUPLICATE_NAME; 15673034Sdougm } 15683034Sdougm 15693034Sdougm return ((sa_share_t)node); 15703034Sdougm } 15713034Sdougm 15723034Sdougm /* 15733034Sdougm * sa_enable_share(share, protocol) 15743034Sdougm * Enable the specified share to the specified protocol. 15753034Sdougm * If protocol is NULL, then all protocols. 15763034Sdougm */ 15773034Sdougm int 15783034Sdougm sa_enable_share(sa_share_t share, char *protocol) 15793034Sdougm { 15803034Sdougm char *sharepath; 15813034Sdougm struct stat st; 15825331Samw int err = SA_OK; 15835331Samw int ret; 15843034Sdougm 15853034Sdougm sharepath = sa_get_share_attr(share, "path"); 15865331Samw if (sharepath == NULL) 15875331Samw return (SA_NO_MEMORY); 15883034Sdougm if (stat(sharepath, &st) < 0) { 15894327Sdougm err = SA_NO_SUCH_PATH; 15903034Sdougm } else { 15914327Sdougm /* tell the server about the share */ 15924327Sdougm if (protocol != NULL) { 15935331Samw if (excluded_protocol(share, protocol)) 15945331Samw goto done; 15955331Samw 15964327Sdougm /* lookup protocol specific handler */ 15974327Sdougm err = sa_proto_share(protocol, share); 15984327Sdougm if (err == SA_OK) 15995331Samw (void) sa_set_share_attr(share, 16005331Samw "shared", "true"); 16014327Sdougm } else { 16025331Samw /* Tell all protocols about the share */ 16035331Samw sa_group_t group; 16045331Samw sa_optionset_t optionset; 16055331Samw 16065331Samw group = sa_get_parent_group(share); 16075331Samw 16085331Samw for (optionset = sa_get_optionset(group, NULL); 16095331Samw optionset != NULL; 16105331Samw optionset = sa_get_next_optionset(optionset)) { 16115331Samw char *proto; 16125331Samw proto = sa_get_optionset_attr(optionset, 16135331Samw "type"); 16145331Samw if (proto != NULL) { 16155331Samw if (!excluded_protocol(share, proto)) { 16165331Samw ret = sa_proto_share(proto, 16175331Samw share); 16185331Samw if (ret != SA_OK) 16195331Samw err = ret; 16205331Samw } 16215331Samw sa_free_attr_string(proto); 16225331Samw } 16235331Samw } 16244327Sdougm (void) sa_set_share_attr(share, "shared", "true"); 16254327Sdougm } 16263034Sdougm } 16275331Samw done: 16283034Sdougm if (sharepath != NULL) 16294327Sdougm sa_free_attr_string(sharepath); 16303034Sdougm return (err); 16313034Sdougm } 16323034Sdougm 16333034Sdougm /* 16343034Sdougm * sa_disable_share(share, protocol) 16355331Samw * Disable the specified share to the specified protocol. If 16365331Samw * protocol is NULL, then all protocols that are enabled for the 16375331Samw * share should be disabled. 16383034Sdougm */ 16393034Sdougm int 16403034Sdougm sa_disable_share(sa_share_t share, char *protocol) 16413034Sdougm { 16423034Sdougm char *path; 16435331Samw int err = SA_OK; 16443034Sdougm int ret = SA_OK; 16453034Sdougm 16463034Sdougm path = sa_get_share_attr(share, "path"); 16473034Sdougm 16483034Sdougm if (protocol != NULL) { 16494543Smarks ret = sa_proto_unshare(share, protocol, path); 16503034Sdougm } else { 16514327Sdougm /* need to do all protocols */ 16525331Samw sa_group_t group; 16535331Samw sa_optionset_t optionset; 16545331Samw 16555331Samw group = sa_get_parent_group(share); 16565331Samw 16575331Samw /* Tell all protocols about the share */ 16585331Samw for (optionset = sa_get_optionset(group, NULL); 16595331Samw optionset != NULL; 16605331Samw optionset = sa_get_next_optionset(optionset)) { 16615331Samw char *proto; 16625331Samw 16635331Samw proto = sa_get_optionset_attr(optionset, "type"); 16645331Samw if (proto != NULL) { 16655331Samw err = sa_proto_unshare(share, proto, path); 16665331Samw if (err != SA_OK) 16675331Samw ret = err; 16685331Samw sa_free_attr_string(proto); 16695331Samw } 16705331Samw } 16713034Sdougm } 16723034Sdougm if (ret == SA_OK) 16733034Sdougm (void) sa_set_share_attr(share, "shared", NULL); 16743034Sdougm if (path != NULL) 16754327Sdougm sa_free_attr_string(path); 16763034Sdougm return (ret); 16773034Sdougm } 16783034Sdougm 16793034Sdougm /* 16803034Sdougm * sa_remove_share(share) 16813034Sdougm * 16823034Sdougm * remove the specified share from its containing group. 16833034Sdougm * Remove from the SMF or ZFS configuration space. 16843034Sdougm */ 16853034Sdougm 16863034Sdougm int 16873034Sdougm sa_remove_share(sa_share_t share) 16883034Sdougm { 16893034Sdougm sa_group_t group; 16903034Sdougm int ret = SA_OK; 16913034Sdougm char *type; 16923034Sdougm int transient = 0; 16933034Sdougm char *groupname; 16943034Sdougm char *zfs; 16953034Sdougm 16963034Sdougm type = sa_get_share_attr(share, "type"); 16973034Sdougm group = sa_get_parent_group(share); 16983034Sdougm zfs = sa_get_group_attr(group, "zfs"); 16993034Sdougm groupname = sa_get_group_attr(group, "name"); 17003034Sdougm if (type != NULL && strcmp(type, "persist") != 0) 17014327Sdougm transient = 1; 17023034Sdougm if (type != NULL) 17034327Sdougm sa_free_attr_string(type); 17043034Sdougm 17053034Sdougm /* remove the node from its group then free the memory */ 17063034Sdougm 17073034Sdougm /* 17083034Sdougm * need to test if "busy" 17093034Sdougm */ 17103034Sdougm /* only do SMF action if permanent */ 17113034Sdougm if (!transient || zfs != NULL) { 17124327Sdougm /* remove from legacy dfstab as well as possible SMF */ 17135331Samw ret = sa_delete_legacy(share, NULL); 17144327Sdougm if (ret == SA_OK) { 17154327Sdougm if (!sa_group_is_zfs(group)) { 17164327Sdougm sa_handle_impl_t impl_handle; 17174327Sdougm impl_handle = (sa_handle_impl_t) 17184327Sdougm sa_find_group_handle(group); 17194327Sdougm if (impl_handle != NULL) { 17204327Sdougm ret = sa_delete_share( 17214327Sdougm impl_handle->scfhandle, group, 17224327Sdougm share); 17234327Sdougm } else { 17244327Sdougm ret = SA_SYSTEM_ERR; 17254327Sdougm } 17264327Sdougm } else { 17274327Sdougm char *sharepath = sa_get_share_attr(share, 17284327Sdougm "path"); 17294327Sdougm if (sharepath != NULL) { 17304327Sdougm ret = sa_zfs_set_sharenfs(group, 17314327Sdougm sharepath, 0); 17324327Sdougm sa_free_attr_string(sharepath); 17334327Sdougm } 17344327Sdougm } 17353034Sdougm } 17363034Sdougm } 17373034Sdougm if (groupname != NULL) 17384327Sdougm sa_free_attr_string(groupname); 17393034Sdougm if (zfs != NULL) 17404327Sdougm sa_free_attr_string(zfs); 17413034Sdougm 17423034Sdougm xmlUnlinkNode((xmlNodePtr)share); 17433034Sdougm xmlFreeNode((xmlNodePtr)share); 17443034Sdougm return (ret); 17453034Sdougm } 17463034Sdougm 17473034Sdougm /* 17483034Sdougm * sa_move_share(group, share) 17493034Sdougm * 17503034Sdougm * move the specified share to the specified group. Update SMF 17513034Sdougm * appropriately. 17523034Sdougm */ 17533034Sdougm 17543034Sdougm int 17553034Sdougm sa_move_share(sa_group_t group, sa_share_t share) 17563034Sdougm { 17573034Sdougm sa_group_t oldgroup; 17583034Sdougm int ret = SA_OK; 17593034Sdougm 17603034Sdougm /* remove the node from its group then free the memory */ 17613034Sdougm 17623034Sdougm oldgroup = sa_get_parent_group(share); 17633034Sdougm if (oldgroup != group) { 17644327Sdougm sa_handle_impl_t impl_handle; 17654327Sdougm xmlUnlinkNode((xmlNodePtr)share); 17663034Sdougm /* 17674327Sdougm * now that the share isn't in its old group, add to 17684327Sdougm * the new one 17693034Sdougm */ 17706007Sthurlow (void) xmlAddChild((xmlNodePtr)group, (xmlNodePtr)share); 17714327Sdougm /* need to deal with SMF */ 17724327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 17734327Sdougm if (impl_handle != NULL) { 17744327Sdougm /* 17754327Sdougm * need to remove from old group first and then add to 17764327Sdougm * new group. Ideally, we would do the other order but 17774327Sdougm * need to avoid having the share in two groups at the 17784327Sdougm * same time. 17794327Sdougm */ 17804327Sdougm ret = sa_delete_share(impl_handle->scfhandle, oldgroup, 17814327Sdougm share); 17824327Sdougm if (ret == SA_OK) 17834327Sdougm ret = sa_commit_share(impl_handle->scfhandle, 17844327Sdougm group, share); 17854327Sdougm } else { 17864327Sdougm ret = SA_SYSTEM_ERR; 17874327Sdougm } 17883034Sdougm } 17893034Sdougm return (ret); 17903034Sdougm } 17913034Sdougm 17923034Sdougm /* 17933034Sdougm * sa_get_parent_group(share) 17943034Sdougm * 17955331Samw * Return the containing group for the share. If a group was actually 17963034Sdougm * passed in, we don't want a parent so return NULL. 17973034Sdougm */ 17983034Sdougm 17993034Sdougm sa_group_t 18003034Sdougm sa_get_parent_group(sa_share_t share) 18013034Sdougm { 18023034Sdougm xmlNodePtr node = NULL; 18033034Sdougm if (share != NULL) { 18044327Sdougm node = ((xmlNodePtr)share)->parent; 18053034Sdougm /* 18063034Sdougm * make sure parent is a group and not sharecfg since 18073034Sdougm * we may be cheating and passing in a group. 18083034Sdougm * Eventually, groups of groups might come into being. 18093034Sdougm */ 18104327Sdougm if (node == NULL || 18114327Sdougm xmlStrcmp(node->name, (xmlChar *)"sharecfg") == 0) 18124327Sdougm node = NULL; 18133034Sdougm } 18143034Sdougm return ((sa_group_t)node); 18153034Sdougm } 18163034Sdougm 18173034Sdougm /* 18183910Sdougm * _sa_create_group(impl_handle, groupname) 18193034Sdougm * 18203034Sdougm * Create a group in the document. The caller will need to deal with 18213034Sdougm * configuration store and activation. 18223034Sdougm */ 18233034Sdougm 18243034Sdougm sa_group_t 18253910Sdougm _sa_create_group(sa_handle_impl_t impl_handle, char *groupname) 18263034Sdougm { 18273034Sdougm xmlNodePtr node = NULL; 18283034Sdougm 18293034Sdougm if (sa_valid_group_name(groupname)) { 18304327Sdougm node = xmlNewChild(impl_handle->tree, NULL, (xmlChar *)"group", 18314327Sdougm NULL); 18324327Sdougm if (node != NULL) { 18336007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 18344327Sdougm (xmlChar *)groupname); 18356007Sthurlow (void) xmlSetProp(node, (xmlChar *)"state", 18364327Sdougm (xmlChar *)"enabled"); 18374327Sdougm } 18383034Sdougm } 18393034Sdougm return ((sa_group_t)node); 18403034Sdougm } 18413034Sdougm 18423034Sdougm /* 18433034Sdougm * _sa_create_zfs_group(group, groupname) 18443034Sdougm * 18453034Sdougm * Create a ZFS subgroup under the specified group. This may 18463034Sdougm * eventually form the basis of general sub-groups, but is currently 18473034Sdougm * restricted to ZFS. 18483034Sdougm */ 18493034Sdougm sa_group_t 18503034Sdougm _sa_create_zfs_group(sa_group_t group, char *groupname) 18513034Sdougm { 18523034Sdougm xmlNodePtr node = NULL; 18533034Sdougm 18544327Sdougm node = xmlNewChild((xmlNodePtr)group, NULL, (xmlChar *)"group", NULL); 18553034Sdougm if (node != NULL) { 18566007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 18576007Sthurlow (xmlChar *)groupname); 18586007Sthurlow (void) xmlSetProp(node, (xmlChar *)"state", 18596007Sthurlow (xmlChar *)"enabled"); 18603034Sdougm } 18613034Sdougm 18623034Sdougm return ((sa_group_t)node); 18633034Sdougm } 18643034Sdougm 18653034Sdougm /* 18663034Sdougm * sa_create_group(groupname, *error) 18673034Sdougm * 18683034Sdougm * Create a new group with groupname. Need to validate that it is a 18693034Sdougm * legal name for SMF and the construct the SMF service instance of 18703034Sdougm * svc:/network/shares/group to implement the group. All necessary 18713034Sdougm * operational properties must be added to the group at this point 18723034Sdougm * (via the SMF transaction model). 18733034Sdougm */ 18743034Sdougm sa_group_t 18753910Sdougm sa_create_group(sa_handle_t handle, char *groupname, int *error) 18763034Sdougm { 18773034Sdougm xmlNodePtr node = NULL; 18783034Sdougm sa_group_t group; 18793034Sdougm int ret; 18804327Sdougm char rbacstr[SA_STRSIZE]; 18813910Sdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle; 18823034Sdougm 18833034Sdougm ret = SA_OK; 18843034Sdougm 18853910Sdougm if (impl_handle == NULL || impl_handle->scfhandle == NULL) { 18864327Sdougm ret = SA_SYSTEM_ERR; 18874327Sdougm goto err; 18883034Sdougm } 18893034Sdougm 18903910Sdougm group = sa_get_group(handle, groupname); 18913034Sdougm if (group != NULL) { 18924327Sdougm ret = SA_DUPLICATE_NAME; 18933034Sdougm } else { 18944327Sdougm if (sa_valid_group_name(groupname)) { 18954327Sdougm node = xmlNewChild(impl_handle->tree, NULL, 18964327Sdougm (xmlChar *)"group", NULL); 18974327Sdougm if (node != NULL) { 18986007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 18994327Sdougm (xmlChar *)groupname); 19004327Sdougm /* default to the group being enabled */ 19016007Sthurlow (void) xmlSetProp(node, (xmlChar *)"state", 19024327Sdougm (xmlChar *)"enabled"); 19034327Sdougm ret = sa_create_instance(impl_handle->scfhandle, 19044327Sdougm groupname); 19054327Sdougm if (ret == SA_OK) { 19064327Sdougm ret = sa_start_transaction( 19074327Sdougm impl_handle->scfhandle, 19084327Sdougm "operation"); 19094327Sdougm } 19104327Sdougm if (ret == SA_OK) { 19114327Sdougm ret = sa_set_property( 19124327Sdougm impl_handle->scfhandle, 19134327Sdougm "state", "enabled"); 19144327Sdougm if (ret == SA_OK) { 19154327Sdougm ret = sa_end_transaction( 19165951Sdougm impl_handle->scfhandle, 19175951Sdougm impl_handle); 19184327Sdougm } else { 19194327Sdougm sa_abort_transaction( 19204327Sdougm impl_handle->scfhandle); 19214327Sdougm } 19224327Sdougm } 19234327Sdougm if (ret == SA_OK) { 19244327Sdougm /* initialize the RBAC strings */ 19254327Sdougm ret = sa_start_transaction( 19264327Sdougm impl_handle->scfhandle, 19274327Sdougm "general"); 19284327Sdougm if (ret == SA_OK) { 19294327Sdougm (void) snprintf(rbacstr, 19304327Sdougm sizeof (rbacstr), "%s.%s", 19314327Sdougm SA_RBAC_MANAGE, groupname); 19324327Sdougm ret = sa_set_property( 19334327Sdougm impl_handle->scfhandle, 19343034Sdougm "action_authorization", 19353034Sdougm rbacstr); 19364327Sdougm } 19374327Sdougm if (ret == SA_OK) { 19384327Sdougm (void) snprintf(rbacstr, 19394327Sdougm sizeof (rbacstr), "%s.%s", 19404327Sdougm SA_RBAC_VALUE, groupname); 19414327Sdougm ret = sa_set_property( 19424327Sdougm impl_handle->scfhandle, 19433034Sdougm "value_authorization", 19443034Sdougm rbacstr); 19454327Sdougm } 19464327Sdougm if (ret == SA_OK) { 19474327Sdougm ret = sa_end_transaction( 19485951Sdougm impl_handle->scfhandle, 19495951Sdougm impl_handle); 19504327Sdougm } else { 19514327Sdougm sa_abort_transaction( 19524327Sdougm impl_handle->scfhandle); 19534327Sdougm } 19544327Sdougm } 19554327Sdougm if (ret != SA_OK) { 19564327Sdougm /* 19574327Sdougm * Couldn't commit the group 19584327Sdougm * so we need to undo 19594327Sdougm * internally. 19604327Sdougm */ 19614327Sdougm xmlUnlinkNode(node); 19624327Sdougm xmlFreeNode(node); 19634327Sdougm node = NULL; 19644327Sdougm } 19653034Sdougm } else { 19664327Sdougm ret = SA_NO_MEMORY; 19673034Sdougm } 19683034Sdougm } else { 19694327Sdougm ret = SA_INVALID_NAME; 19703034Sdougm } 19713034Sdougm } 19723034Sdougm err: 19733034Sdougm if (error != NULL) 19744327Sdougm *error = ret; 19753034Sdougm return ((sa_group_t)node); 19763034Sdougm } 19773034Sdougm 19783034Sdougm /* 19793034Sdougm * sa_remove_group(group) 19803034Sdougm * 19813034Sdougm * Remove the specified group. This deletes from the SMF repository. 19823034Sdougm * All property groups and properties are removed. 19833034Sdougm */ 19843034Sdougm 19853034Sdougm int 19863034Sdougm sa_remove_group(sa_group_t group) 19873034Sdougm { 19883034Sdougm char *name; 19893034Sdougm int ret = SA_OK; 19903910Sdougm sa_handle_impl_t impl_handle; 19913034Sdougm 19923910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 19933910Sdougm if (impl_handle != NULL) { 19944327Sdougm name = sa_get_group_attr(group, "name"); 19954327Sdougm if (name != NULL) { 19964327Sdougm ret = sa_delete_instance(impl_handle->scfhandle, name); 19974327Sdougm sa_free_attr_string(name); 19984327Sdougm } 19994327Sdougm xmlUnlinkNode((xmlNodePtr)group); /* make sure unlinked */ 20004327Sdougm xmlFreeNode((xmlNodePtr)group); /* now it is gone */ 20013910Sdougm } else { 20024327Sdougm ret = SA_SYSTEM_ERR; 20033034Sdougm } 20043034Sdougm return (ret); 20053034Sdougm } 20063034Sdougm 20073034Sdougm /* 20083034Sdougm * sa_update_config() 20093034Sdougm * 20103034Sdougm * Used to update legacy files that need to be updated in bulk 20113034Sdougm * Currently, this is a placeholder and will go away in a future 20123034Sdougm * release. 20133034Sdougm */ 20143034Sdougm 20153034Sdougm int 20163910Sdougm sa_update_config(sa_handle_t handle) 20173034Sdougm { 20183034Sdougm /* 20193034Sdougm * do legacy files first so we can tell when they change. 20203034Sdougm * This will go away when we start updating individual records 20213034Sdougm * rather than the whole file. 20223034Sdougm */ 20233910Sdougm update_legacy_config(handle); 20243034Sdougm return (SA_OK); 20253034Sdougm } 20263034Sdougm 20273034Sdougm /* 20283034Sdougm * get_node_attr(node, tag) 20293034Sdougm * 20305331Samw * Get the specified tag(attribute) if it exists on the node. This is 20313034Sdougm * used internally by a number of attribute oriented functions. 20323034Sdougm */ 20333034Sdougm 20343034Sdougm static char * 20353034Sdougm get_node_attr(void *nodehdl, char *tag) 20363034Sdougm { 20373034Sdougm xmlNodePtr node = (xmlNodePtr)nodehdl; 20383034Sdougm xmlChar *name = NULL; 20393034Sdougm 20404327Sdougm if (node != NULL) 20413034Sdougm name = xmlGetProp(node, (xmlChar *)tag); 20423034Sdougm return ((char *)name); 20433034Sdougm } 20443034Sdougm 20453034Sdougm /* 20463034Sdougm * get_node_attr(node, tag) 20473034Sdougm * 20485331Samw * Set the specified tag(attribute) to the specified value This is 20493034Sdougm * used internally by a number of attribute oriented functions. It 20503034Sdougm * doesn't update the repository, only the internal document state. 20513034Sdougm */ 20523034Sdougm 20533034Sdougm void 20543034Sdougm set_node_attr(void *nodehdl, char *tag, char *value) 20553034Sdougm { 20563034Sdougm xmlNodePtr node = (xmlNodePtr)nodehdl; 20573034Sdougm if (node != NULL && tag != NULL) { 20584327Sdougm if (value != NULL) 20596007Sthurlow (void) xmlSetProp(node, (xmlChar *)tag, 20606007Sthurlow (xmlChar *)value); 20614327Sdougm else 20626007Sthurlow (void) xmlUnsetProp(node, (xmlChar *)tag); 20633034Sdougm } 20643034Sdougm } 20653034Sdougm 20663034Sdougm /* 20673034Sdougm * sa_get_group_attr(group, tag) 20683034Sdougm * 20693034Sdougm * Get the specied attribute, if defined, for the group. 20703034Sdougm */ 20713034Sdougm 20723034Sdougm char * 20733034Sdougm sa_get_group_attr(sa_group_t group, char *tag) 20743034Sdougm { 20753034Sdougm return (get_node_attr((void *)group, tag)); 20763034Sdougm } 20773034Sdougm 20783034Sdougm /* 20793034Sdougm * sa_set_group_attr(group, tag, value) 20803034Sdougm * 20813034Sdougm * set the specified tag/attribute on the group using value as its 20823034Sdougm * value. 20833034Sdougm * 20843034Sdougm * This will result in setting the property in the SMF repository as 20853034Sdougm * well as in the internal document. 20863034Sdougm */ 20873034Sdougm 20883034Sdougm int 20893034Sdougm sa_set_group_attr(sa_group_t group, char *tag, char *value) 20903034Sdougm { 20913034Sdougm int ret; 20923034Sdougm char *groupname; 20933910Sdougm sa_handle_impl_t impl_handle; 20943034Sdougm 20955331Samw /* 20965331Samw * ZFS group/subgroup doesn't need the handle so shortcut. 20975331Samw */ 20985331Samw if (sa_group_is_zfs(group)) { 20995331Samw set_node_attr((void *)group, tag, value); 21005331Samw return (SA_OK); 21015331Samw } 21025331Samw 21033910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 21043910Sdougm if (impl_handle != NULL) { 21054327Sdougm groupname = sa_get_group_attr(group, "name"); 21064327Sdougm ret = sa_get_instance(impl_handle->scfhandle, groupname); 21073910Sdougm if (ret == SA_OK) { 21084327Sdougm set_node_attr((void *)group, tag, value); 21094327Sdougm ret = sa_start_transaction(impl_handle->scfhandle, 21104327Sdougm "operation"); 21114327Sdougm if (ret == SA_OK) { 21124327Sdougm ret = sa_set_property(impl_handle->scfhandle, 21134327Sdougm tag, value); 21144327Sdougm if (ret == SA_OK) 21155885Sdougm ret = sa_end_transaction( 21165951Sdougm impl_handle->scfhandle, 21175951Sdougm impl_handle); 21184327Sdougm else 21194327Sdougm sa_abort_transaction( 21204327Sdougm impl_handle->scfhandle); 21214327Sdougm } 21225885Sdougm if (ret == SA_SYSTEM_ERR) 21235885Sdougm ret = SA_NO_PERMISSION; 21243034Sdougm } 21254327Sdougm if (groupname != NULL) 21264327Sdougm sa_free_attr_string(groupname); 21273910Sdougm } else { 21284327Sdougm ret = SA_SYSTEM_ERR; 21293034Sdougm } 21303034Sdougm return (ret); 21313034Sdougm } 21323034Sdougm 21333034Sdougm /* 21343034Sdougm * sa_get_share_attr(share, tag) 21353034Sdougm * 21363034Sdougm * Return the value of the tag/attribute set on the specified 21373034Sdougm * share. Returns NULL if the tag doesn't exist. 21383034Sdougm */ 21393034Sdougm 21403034Sdougm char * 21413034Sdougm sa_get_share_attr(sa_share_t share, char *tag) 21423034Sdougm { 21433034Sdougm return (get_node_attr((void *)share, tag)); 21443034Sdougm } 21453034Sdougm 21463034Sdougm /* 21473034Sdougm * _sa_set_share_description(share, description) 21483034Sdougm * 21495331Samw * Add a description tag with text contents to the specified share. A 21505331Samw * separate XML tag is used rather than a property. This can also be 21515331Samw * used with resources. 21523034Sdougm */ 21533034Sdougm 21543034Sdougm xmlNodePtr 21555331Samw _sa_set_share_description(void *share, char *content) 21563034Sdougm { 21573034Sdougm xmlNodePtr node; 21584327Sdougm node = xmlNewChild((xmlNodePtr)share, NULL, (xmlChar *)"description", 21594327Sdougm NULL); 21603034Sdougm xmlNodeSetContent(node, (xmlChar *)content); 21613034Sdougm return (node); 21623034Sdougm } 21633034Sdougm 21643034Sdougm /* 21653034Sdougm * sa_set_share_attr(share, tag, value) 21663034Sdougm * 21673034Sdougm * Set the share attribute specified by tag to the specified value. In 21683034Sdougm * the case of "resource", enforce a no duplicates in a group rule. If 21693034Sdougm * the share is not transient, commit the changes to the repository 21703034Sdougm * else just update the share internally. 21713034Sdougm */ 21723034Sdougm 21733034Sdougm int 21743034Sdougm sa_set_share_attr(sa_share_t share, char *tag, char *value) 21753034Sdougm { 21763034Sdougm sa_group_t group; 21773034Sdougm sa_share_t resource; 21783034Sdougm int ret = SA_OK; 21793034Sdougm 21803034Sdougm group = sa_get_parent_group(share); 21813034Sdougm 21823034Sdougm /* 21833034Sdougm * There are some attributes that may have specific 21843034Sdougm * restrictions on them. Initially, only "resource" has 21853034Sdougm * special meaning that needs to be checked. Only one instance 21863034Sdougm * of a resource name may exist within a group. 21873034Sdougm */ 21883034Sdougm 21893034Sdougm if (strcmp(tag, "resource") == 0) { 21904327Sdougm resource = sa_get_resource(group, value); 21914327Sdougm if (resource != share && resource != NULL) 21924327Sdougm ret = SA_DUPLICATE_NAME; 21933034Sdougm } 21943034Sdougm if (ret == SA_OK) { 21954327Sdougm set_node_attr((void *)share, tag, value); 21964327Sdougm if (group != NULL) { 21974327Sdougm char *type; 21984327Sdougm /* we can probably optimize this some */ 21994327Sdougm type = sa_get_share_attr(share, "type"); 22004327Sdougm if (type == NULL || strcmp(type, "transient") != 0) { 22014327Sdougm sa_handle_impl_t impl_handle; 22024327Sdougm impl_handle = 22034327Sdougm (sa_handle_impl_t)sa_find_group_handle( 22044327Sdougm group); 22054327Sdougm if (impl_handle != NULL) { 22064327Sdougm ret = sa_commit_share( 22074327Sdougm impl_handle->scfhandle, group, 22084327Sdougm share); 22094327Sdougm } else { 22104327Sdougm ret = SA_SYSTEM_ERR; 22114327Sdougm } 22124327Sdougm } 22134327Sdougm if (type != NULL) 22144327Sdougm sa_free_attr_string(type); 22153910Sdougm } 22163034Sdougm } 22173034Sdougm return (ret); 22183034Sdougm } 22193034Sdougm 22203034Sdougm /* 22213034Sdougm * sa_get_property_attr(prop, tag) 22223034Sdougm * 22233034Sdougm * Get the value of the specified property attribute. Standard 22243034Sdougm * attributes are "type" and "value". 22253034Sdougm */ 22263034Sdougm 22273034Sdougm char * 22283034Sdougm sa_get_property_attr(sa_property_t prop, char *tag) 22293034Sdougm { 22303034Sdougm return (get_node_attr((void *)prop, tag)); 22313034Sdougm } 22323034Sdougm 22333034Sdougm /* 22343034Sdougm * sa_get_optionset_attr(prop, tag) 22353034Sdougm * 22363034Sdougm * Get the value of the specified property attribute. Standard 22373034Sdougm * attribute is "type". 22383034Sdougm */ 22393034Sdougm 22403034Sdougm char * 22413034Sdougm sa_get_optionset_attr(sa_property_t optionset, char *tag) 22423034Sdougm { 22433034Sdougm return (get_node_attr((void *)optionset, tag)); 22443034Sdougm 22453034Sdougm } 22463034Sdougm 22473034Sdougm /* 22483034Sdougm * sa_set_optionset_attr(optionset, tag, value) 22493034Sdougm * 22503034Sdougm * Set the specified attribute(tag) to the specified value on the 22513034Sdougm * optionset. 22523034Sdougm */ 22533034Sdougm 22543034Sdougm void 22553034Sdougm sa_set_optionset_attr(sa_group_t optionset, char *tag, char *value) 22563034Sdougm { 22573034Sdougm set_node_attr((void *)optionset, tag, value); 22583034Sdougm } 22593034Sdougm 22603034Sdougm /* 22613034Sdougm * sa_free_attr_string(string) 22623034Sdougm * 22633034Sdougm * Free the string that was returned in one of the sa_get_*_attr() 22643034Sdougm * functions. 22653034Sdougm */ 22663034Sdougm 22673034Sdougm void 22683034Sdougm sa_free_attr_string(char *string) 22693034Sdougm { 22703034Sdougm xmlFree((xmlChar *)string); 22713034Sdougm } 22723034Sdougm 22733034Sdougm /* 22743034Sdougm * sa_get_optionset(group, proto) 22753034Sdougm * 22763034Sdougm * Return the optionset, if it exists, that is associated with the 22773034Sdougm * specified protocol. 22783034Sdougm */ 22793034Sdougm 22803034Sdougm sa_optionset_t 22813034Sdougm sa_get_optionset(void *group, char *proto) 22823034Sdougm { 22833034Sdougm xmlNodePtr node; 22843034Sdougm xmlChar *value = NULL; 22853034Sdougm 22863034Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 22874327Sdougm node = node->next) { 22883034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) { 22894327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 22904327Sdougm if (proto != NULL) { 22914327Sdougm if (value != NULL && 22924327Sdougm xmlStrcmp(value, (xmlChar *)proto) == 0) { 22934327Sdougm break; 22944327Sdougm } 22954327Sdougm if (value != NULL) { 22964327Sdougm xmlFree(value); 22974327Sdougm value = NULL; 22984327Sdougm } 22994327Sdougm } else { 23004327Sdougm break; 23013034Sdougm } 23023034Sdougm } 23033034Sdougm } 23043034Sdougm if (value != NULL) 23054327Sdougm xmlFree(value); 23063034Sdougm return ((sa_optionset_t)node); 23073034Sdougm } 23083034Sdougm 23093034Sdougm /* 23103034Sdougm * sa_get_next_optionset(optionset) 23113034Sdougm * 23123034Sdougm * Return the next optionset in the group. NULL if this was the last. 23133034Sdougm */ 23143034Sdougm 23153034Sdougm sa_optionset_t 23163034Sdougm sa_get_next_optionset(sa_optionset_t optionset) 23173034Sdougm { 23183034Sdougm xmlNodePtr node; 23193034Sdougm 23203034Sdougm for (node = ((xmlNodePtr)optionset)->next; node != NULL; 23214327Sdougm node = node->next) { 23223034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) { 23233034Sdougm break; 23243034Sdougm } 23253034Sdougm } 23263034Sdougm return ((sa_optionset_t)node); 23273034Sdougm } 23283034Sdougm 23293034Sdougm /* 23303034Sdougm * sa_get_security(group, sectype, proto) 23313034Sdougm * 23323034Sdougm * Return the security optionset. The internal name is a hold over 23333034Sdougm * from the implementation and will be changed before the API is 23343034Sdougm * finalized. This is really a named optionset that can be negotiated 23353034Sdougm * as a group of properties (like NFS security options). 23363034Sdougm */ 23373034Sdougm 23383034Sdougm sa_security_t 23393034Sdougm sa_get_security(sa_group_t group, char *sectype, char *proto) 23403034Sdougm { 23413034Sdougm xmlNodePtr node; 23423034Sdougm xmlChar *value = NULL; 23433034Sdougm 23443034Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 23454327Sdougm node = node->next) { 23464327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) { 23474327Sdougm if (proto != NULL) { 23484327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 23494327Sdougm if (value == NULL || 23504327Sdougm (value != NULL && 23514327Sdougm xmlStrcmp(value, (xmlChar *)proto) != 0)) { 23524327Sdougm /* it doesn't match so continue */ 23534327Sdougm xmlFree(value); 23544327Sdougm value = NULL; 23554327Sdougm continue; 23564327Sdougm } 23574327Sdougm } 23584327Sdougm if (value != NULL) { 23594327Sdougm xmlFree(value); 23604327Sdougm value = NULL; 23614327Sdougm } 23624327Sdougm /* potential match */ 23634327Sdougm if (sectype != NULL) { 23644327Sdougm value = xmlGetProp(node, (xmlChar *)"sectype"); 23654327Sdougm if (value != NULL && 23664327Sdougm xmlStrcmp(value, (xmlChar *)sectype) == 0) { 23674327Sdougm break; 23684327Sdougm } 23694327Sdougm } else { 23704327Sdougm break; 23714327Sdougm } 23723034Sdougm } 23733034Sdougm if (value != NULL) { 23744327Sdougm xmlFree(value); 23754327Sdougm value = NULL; 23763034Sdougm } 23773034Sdougm } 23783034Sdougm if (value != NULL) 23794327Sdougm xmlFree(value); 23803034Sdougm return ((sa_security_t)node); 23813034Sdougm } 23823034Sdougm 23833034Sdougm /* 23843034Sdougm * sa_get_next_security(security) 23853034Sdougm * 23863034Sdougm * Get the next security optionset if one exists. 23873034Sdougm */ 23883034Sdougm 23893034Sdougm sa_security_t 23903034Sdougm sa_get_next_security(sa_security_t security) 23913034Sdougm { 23923034Sdougm xmlNodePtr node; 23933034Sdougm 23943034Sdougm for (node = ((xmlNodePtr)security)->next; node != NULL; 23954327Sdougm node = node->next) { 23963034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) { 23973034Sdougm break; 23983034Sdougm } 23993034Sdougm } 24003034Sdougm return ((sa_security_t)node); 24013034Sdougm } 24023034Sdougm 24033034Sdougm /* 24043034Sdougm * sa_get_property(optionset, prop) 24053034Sdougm * 24063034Sdougm * Get the property object with the name specified in prop from the 24073034Sdougm * optionset. 24083034Sdougm */ 24093034Sdougm 24103034Sdougm sa_property_t 24113034Sdougm sa_get_property(sa_optionset_t optionset, char *prop) 24123034Sdougm { 24133034Sdougm xmlNodePtr node = (xmlNodePtr)optionset; 24143034Sdougm xmlChar *value = NULL; 24153034Sdougm 24163034Sdougm if (optionset == NULL) 24174327Sdougm return (NULL); 24183034Sdougm 24193034Sdougm for (node = node->children; node != NULL; 24204327Sdougm node = node->next) { 24214327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 24224327Sdougm if (prop == NULL) 24234327Sdougm break; 24244327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 24254327Sdougm if (value != NULL && 24264327Sdougm xmlStrcmp(value, (xmlChar *)prop) == 0) { 24274327Sdougm break; 24284327Sdougm } 24294327Sdougm if (value != NULL) { 24304327Sdougm xmlFree(value); 24314327Sdougm value = NULL; 24324327Sdougm } 24333034Sdougm } 24343034Sdougm } 24353034Sdougm if (value != NULL) 24363034Sdougm xmlFree(value); 24373034Sdougm if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"option") != 0) { 24384327Sdougm /* 24394327Sdougm * avoid a non option node -- it is possible to be a 24404327Sdougm * text node 24414327Sdougm */ 24424327Sdougm node = NULL; 24433034Sdougm } 24443034Sdougm return ((sa_property_t)node); 24453034Sdougm } 24463034Sdougm 24473034Sdougm /* 24483034Sdougm * sa_get_next_property(property) 24493034Sdougm * 24503034Sdougm * Get the next property following the specified property. NULL if 24513034Sdougm * this was the last. 24523034Sdougm */ 24533034Sdougm 24543034Sdougm sa_property_t 24553034Sdougm sa_get_next_property(sa_property_t property) 24563034Sdougm { 24573034Sdougm xmlNodePtr node; 24583034Sdougm 24593034Sdougm for (node = ((xmlNodePtr)property)->next; node != NULL; 24604327Sdougm node = node->next) { 24613034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 24623034Sdougm break; 24633034Sdougm } 24643034Sdougm } 24653034Sdougm return ((sa_property_t)node); 24663034Sdougm } 24673034Sdougm 24683034Sdougm /* 24693034Sdougm * sa_set_share_description(share, content) 24703034Sdougm * 24713034Sdougm * Set the description of share to content. 24723034Sdougm */ 24733034Sdougm 24743034Sdougm int 24753034Sdougm sa_set_share_description(sa_share_t share, char *content) 24763034Sdougm { 24773034Sdougm xmlNodePtr node; 24783034Sdougm sa_group_t group; 24793034Sdougm int ret = SA_OK; 24803034Sdougm 24813034Sdougm for (node = ((xmlNodePtr)share)->children; node != NULL; 24824327Sdougm node = node->next) { 24833034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 24843034Sdougm break; 24853034Sdougm } 24863034Sdougm } 24873034Sdougm /* no existing description but want to add */ 24883034Sdougm if (node == NULL && content != NULL) { 24893034Sdougm /* add a description */ 24904327Sdougm node = _sa_set_share_description(share, content); 24913034Sdougm } else if (node != NULL && content != NULL) { 24923034Sdougm /* update a description */ 24933034Sdougm xmlNodeSetContent(node, (xmlChar *)content); 24943034Sdougm } else if (node != NULL && content == NULL) { 24953034Sdougm /* remove an existing description */ 24963034Sdougm xmlUnlinkNode(node); 24973034Sdougm xmlFreeNode(node); 24983034Sdougm } 24995331Samw group = sa_get_parent_group(share); 25005331Samw if (group != NULL && sa_is_persistent(share)) { 25014327Sdougm sa_handle_impl_t impl_handle; 25024327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 25034327Sdougm if (impl_handle != NULL) { 25044327Sdougm ret = sa_commit_share(impl_handle->scfhandle, group, 25054327Sdougm share); 25064327Sdougm } else { 25074327Sdougm ret = SA_SYSTEM_ERR; 25084327Sdougm } 25093910Sdougm } 25103034Sdougm return (ret); 25113034Sdougm } 25123034Sdougm 25133034Sdougm /* 25143034Sdougm * fixproblemchars(string) 25153034Sdougm * 25163034Sdougm * don't want any newline or tab characters in the text since these 25173034Sdougm * could break display of data and legacy file formats. 25183034Sdougm */ 25193034Sdougm static void 25203034Sdougm fixproblemchars(char *str) 25213034Sdougm { 25223034Sdougm int c; 25233034Sdougm for (c = *str; c != '\0'; c = *++str) { 25244327Sdougm if (c == '\t' || c == '\n') 25254327Sdougm *str = ' '; 25264327Sdougm else if (c == '"') 25274327Sdougm *str = '\''; 25283034Sdougm } 25293034Sdougm } 25303034Sdougm 25313034Sdougm /* 25323034Sdougm * sa_get_share_description(share) 25333034Sdougm * 25343034Sdougm * Return the description text for the specified share if it 25353034Sdougm * exists. NULL if no description exists. 25363034Sdougm */ 25373034Sdougm 25383034Sdougm char * 25393034Sdougm sa_get_share_description(sa_share_t share) 25403034Sdougm { 25413034Sdougm xmlChar *description = NULL; 25423034Sdougm xmlNodePtr node; 25433034Sdougm 25443034Sdougm for (node = ((xmlNodePtr)share)->children; node != NULL; 25454327Sdougm node = node->next) { 25464327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 25474327Sdougm break; 25484327Sdougm } 25493034Sdougm } 25503034Sdougm if (node != NULL) { 25515331Samw description = xmlNodeGetContent(node); 25524327Sdougm fixproblemchars((char *)description); 25533034Sdougm } 25543034Sdougm return ((char *)description); 25553034Sdougm } 25563034Sdougm 25573034Sdougm /* 25583034Sdougm * sa_free(share_description(description) 25593034Sdougm * 25603034Sdougm * Free the description string. 25613034Sdougm */ 25623034Sdougm 25633034Sdougm void 25643034Sdougm sa_free_share_description(char *description) 25653034Sdougm { 25663034Sdougm xmlFree((xmlChar *)description); 25673034Sdougm } 25683034Sdougm 25693034Sdougm /* 25703034Sdougm * sa_create_optionset(group, proto) 25713034Sdougm * 25723034Sdougm * Create an optionset for the specified protocol in the specied 25733034Sdougm * group. This is manifested as a property group within SMF. 25743034Sdougm */ 25753034Sdougm 25763034Sdougm sa_optionset_t 25773034Sdougm sa_create_optionset(sa_group_t group, char *proto) 25783034Sdougm { 25793034Sdougm sa_optionset_t optionset; 25803034Sdougm sa_group_t parent = group; 25815331Samw sa_share_t share = NULL; 25825331Samw int err = SA_OK; 25835331Samw char *id = NULL; 25843034Sdougm 25853034Sdougm optionset = sa_get_optionset(group, proto); 25863034Sdougm if (optionset != NULL) { 25873034Sdougm /* can't have a duplicate protocol */ 25884327Sdougm optionset = NULL; 25893034Sdougm } else { 25905331Samw /* 25915331Samw * Account for resource names being slightly 25925331Samw * different. 25935331Samw */ 25945331Samw if (sa_is_share(group)) { 25955331Samw /* 25965331Samw * Transient shares do not have an "id" so not an 25975331Samw * error to not find one. 25985331Samw */ 25995331Samw id = sa_get_share_attr((sa_share_t)group, "id"); 26005331Samw } else if (sa_is_resource(group)) { 26015331Samw share = sa_get_resource_parent( 26025331Samw (sa_resource_t)group); 26035331Samw id = sa_get_resource_attr(share, "id"); 26045331Samw 26055331Samw /* id can be NULL if the group is transient (ZFS) */ 26065331Samw if (id == NULL && sa_is_persistent(group)) 26075331Samw err = SA_NO_MEMORY; 26085331Samw } 26095331Samw if (err == SA_NO_MEMORY) { 26105331Samw /* 26115331Samw * Couldn't get the id for the share or 26125331Samw * resource. While this could be a 26135331Samw * configuration issue, it is most likely an 26145331Samw * out of memory. In any case, fail the create. 26155331Samw */ 26165331Samw return (NULL); 26175331Samw } 26185331Samw 26194327Sdougm optionset = (sa_optionset_t)xmlNewChild((xmlNodePtr)group, 26204327Sdougm NULL, (xmlChar *)"optionset", NULL); 26213034Sdougm /* 26223034Sdougm * only put to repository if on a group and we were 26233034Sdougm * able to create an optionset. 26243034Sdougm */ 26254327Sdougm if (optionset != NULL) { 26264327Sdougm char oname[SA_STRSIZE]; 26274327Sdougm char *groupname; 26285331Samw 26295331Samw /* 26305331Samw * Need to get parent group in all cases, but also get 26315331Samw * the share if this is a resource. 26325331Samw */ 26335331Samw if (sa_is_share(group)) { 26344327Sdougm parent = sa_get_parent_group((sa_share_t)group); 26355331Samw } else if (sa_is_resource(group)) { 26365331Samw share = sa_get_resource_parent( 26375331Samw (sa_resource_t)group); 26385331Samw parent = sa_get_parent_group(share); 26395331Samw } 26404327Sdougm 26414327Sdougm sa_set_optionset_attr(optionset, "type", proto); 26423034Sdougm 26434327Sdougm (void) sa_optionset_name(optionset, oname, 26444327Sdougm sizeof (oname), id); 26454327Sdougm groupname = sa_get_group_attr(parent, "name"); 26465331Samw if (groupname != NULL && sa_is_persistent(group)) { 26474327Sdougm sa_handle_impl_t impl_handle; 26485331Samw impl_handle = 26495331Samw (sa_handle_impl_t)sa_find_group_handle( 26505331Samw group); 26514327Sdougm assert(impl_handle != NULL); 26524327Sdougm if (impl_handle != NULL) { 26534327Sdougm (void) sa_get_instance( 26545331Samw impl_handle->scfhandle, groupname); 26554327Sdougm (void) sa_create_pgroup( 26564327Sdougm impl_handle->scfhandle, oname); 26574327Sdougm } 26584327Sdougm } 26594327Sdougm if (groupname != NULL) 26604327Sdougm sa_free_attr_string(groupname); 26613034Sdougm } 26623034Sdougm } 26635331Samw 26645331Samw if (id != NULL) 26655331Samw sa_free_attr_string(id); 26663034Sdougm return (optionset); 26673034Sdougm } 26683034Sdougm 26693034Sdougm /* 26703034Sdougm * sa_get_property_parent(property) 26713034Sdougm * 26723034Sdougm * Given a property, return the object it is a property of. This will 26733034Sdougm * be an optionset of some type. 26743034Sdougm */ 26753034Sdougm 26763034Sdougm static sa_optionset_t 26773034Sdougm sa_get_property_parent(sa_property_t property) 26783034Sdougm { 26793034Sdougm xmlNodePtr node = NULL; 26803034Sdougm 26814327Sdougm if (property != NULL) 26824327Sdougm node = ((xmlNodePtr)property)->parent; 26833034Sdougm return ((sa_optionset_t)node); 26843034Sdougm } 26853034Sdougm 26863034Sdougm /* 26873034Sdougm * sa_get_optionset_parent(optionset) 26883034Sdougm * 26893034Sdougm * Return the parent of the specified optionset. This could be a group 26903034Sdougm * or a share. 26913034Sdougm */ 26923034Sdougm 26933034Sdougm static sa_group_t 26943034Sdougm sa_get_optionset_parent(sa_optionset_t optionset) 26953034Sdougm { 26963034Sdougm xmlNodePtr node = NULL; 26973034Sdougm 26984327Sdougm if (optionset != NULL) 26994327Sdougm node = ((xmlNodePtr)optionset)->parent; 27003034Sdougm return ((sa_group_t)node); 27013034Sdougm } 27023034Sdougm 27033034Sdougm /* 27043034Sdougm * zfs_needs_update(share) 27053034Sdougm * 27063034Sdougm * In order to avoid making multiple updates to a ZFS share when 27073034Sdougm * setting properties, the share attribute "changed" will be set to 27085331Samw * true when a property is added or modified. When done adding 27093034Sdougm * properties, we can then detect that an update is needed. We then 27103034Sdougm * clear the state here to detect additional changes. 27113034Sdougm */ 27123034Sdougm 27133034Sdougm static int 27143034Sdougm zfs_needs_update(sa_share_t share) 27153034Sdougm { 27163034Sdougm char *attr; 27173034Sdougm int result = 0; 27183034Sdougm 27193034Sdougm attr = sa_get_share_attr(share, "changed"); 27203034Sdougm if (attr != NULL) { 27214327Sdougm sa_free_attr_string(attr); 27223034Sdougm result = 1; 27233034Sdougm } 27243034Sdougm set_node_attr((void *)share, "changed", NULL); 27253034Sdougm return (result); 27263034Sdougm } 27273034Sdougm 27283034Sdougm /* 27293034Sdougm * zfs_set_update(share) 27303034Sdougm * 27313034Sdougm * Set the changed attribute of the share to true. 27323034Sdougm */ 27333034Sdougm 27343034Sdougm static void 27353034Sdougm zfs_set_update(sa_share_t share) 27363034Sdougm { 27373034Sdougm set_node_attr((void *)share, "changed", "true"); 27383034Sdougm } 27393034Sdougm 27403034Sdougm /* 27413034Sdougm * sa_commit_properties(optionset, clear) 27423034Sdougm * 27433034Sdougm * Check if SMF or ZFS config and either update or abort the pending 27443034Sdougm * changes. 27453034Sdougm */ 27463034Sdougm 27473034Sdougm int 27483034Sdougm sa_commit_properties(sa_optionset_t optionset, int clear) 27493034Sdougm { 27503034Sdougm sa_group_t group; 27513034Sdougm sa_group_t parent; 27523034Sdougm int zfs = 0; 27533034Sdougm int needsupdate = 0; 27543034Sdougm int ret = SA_OK; 27553910Sdougm sa_handle_impl_t impl_handle; 27563034Sdougm 27573034Sdougm group = sa_get_optionset_parent(optionset); 27583034Sdougm if (group != NULL && (sa_is_share(group) || is_zfs_group(group))) { 27594327Sdougm /* only update ZFS if on a share */ 27604327Sdougm parent = sa_get_parent_group(group); 27614327Sdougm zfs++; 27624327Sdougm if (parent != NULL && is_zfs_group(parent)) 27634327Sdougm needsupdate = zfs_needs_update(group); 27644327Sdougm else 27654327Sdougm zfs = 0; 27663034Sdougm } 27673034Sdougm if (zfs) { 27684327Sdougm if (!clear && needsupdate) 27694327Sdougm ret = sa_zfs_update((sa_share_t)group); 27703034Sdougm } else { 27714327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 27724327Sdougm if (impl_handle != NULL) { 27734327Sdougm if (clear) { 27744327Sdougm (void) sa_abort_transaction( 27754327Sdougm impl_handle->scfhandle); 27764327Sdougm } else { 27774327Sdougm ret = sa_end_transaction( 27785951Sdougm impl_handle->scfhandle, impl_handle); 27794327Sdougm } 27804327Sdougm } else { 27814327Sdougm ret = SA_SYSTEM_ERR; 27824327Sdougm } 27833034Sdougm } 27843034Sdougm return (ret); 27853034Sdougm } 27863034Sdougm 27873034Sdougm /* 27883034Sdougm * sa_destroy_optionset(optionset) 27893034Sdougm * 27905331Samw * Remove the optionset from its group. Update the repository to 27913034Sdougm * reflect this change. 27923034Sdougm */ 27933034Sdougm 27943034Sdougm int 27953034Sdougm sa_destroy_optionset(sa_optionset_t optionset) 27963034Sdougm { 27974327Sdougm char name[SA_STRSIZE]; 27983034Sdougm int len; 27993034Sdougm int ret; 28003034Sdougm char *id = NULL; 28013034Sdougm sa_group_t group; 28023034Sdougm int ispersist = 1; 28033034Sdougm 28043034Sdougm /* now delete the prop group */ 28053034Sdougm group = sa_get_optionset_parent(optionset); 28065331Samw if (group != NULL) { 28075331Samw if (sa_is_resource(group)) { 28085331Samw sa_resource_t resource = group; 28095331Samw sa_share_t share = sa_get_resource_parent(resource); 28105331Samw group = sa_get_parent_group(share); 28115331Samw id = sa_get_share_attr(share, "id"); 28125331Samw } else if (sa_is_share(group)) { 28135331Samw id = sa_get_share_attr((sa_share_t)group, "id"); 28145331Samw } 28155331Samw ispersist = sa_is_persistent(group); 28163034Sdougm } 28173034Sdougm if (ispersist) { 28184327Sdougm sa_handle_impl_t impl_handle; 28194327Sdougm len = sa_optionset_name(optionset, name, sizeof (name), id); 28204327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 28214327Sdougm if (impl_handle != NULL) { 28224327Sdougm if (len > 0) { 28234327Sdougm ret = sa_delete_pgroup(impl_handle->scfhandle, 28244327Sdougm name); 28254327Sdougm } 28264327Sdougm } else { 28274327Sdougm ret = SA_SYSTEM_ERR; 28283910Sdougm } 28293034Sdougm } 28303034Sdougm xmlUnlinkNode((xmlNodePtr)optionset); 28313034Sdougm xmlFreeNode((xmlNodePtr)optionset); 28323034Sdougm if (id != NULL) 28334327Sdougm sa_free_attr_string(id); 28343034Sdougm return (ret); 28353034Sdougm } 28363034Sdougm 28373034Sdougm /* private to the implementation */ 28383034Sdougm int 28393034Sdougm _sa_remove_optionset(sa_optionset_t optionset) 28403034Sdougm { 28413034Sdougm int ret = SA_OK; 28423034Sdougm 28433034Sdougm xmlUnlinkNode((xmlNodePtr)optionset); 28443034Sdougm xmlFreeNode((xmlNodePtr)optionset); 28453034Sdougm return (ret); 28463034Sdougm } 28473034Sdougm 28483034Sdougm /* 28493034Sdougm * sa_create_security(group, sectype, proto) 28503034Sdougm * 28513034Sdougm * Create a security optionset (one that has a type name and a 28523034Sdougm * proto). Security is left over from a pure NFS implementation. The 28533034Sdougm * naming will change in the future when the API is released. 28543034Sdougm */ 28553034Sdougm sa_security_t 28563034Sdougm sa_create_security(sa_group_t group, char *sectype, char *proto) 28573034Sdougm { 28583034Sdougm sa_security_t security; 28593034Sdougm char *id = NULL; 28603034Sdougm sa_group_t parent; 28613034Sdougm char *groupname = NULL; 28623034Sdougm 28633034Sdougm if (group != NULL && sa_is_share(group)) { 28644327Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 28654327Sdougm parent = sa_get_parent_group(group); 28664327Sdougm if (parent != NULL) 28674327Sdougm groupname = sa_get_group_attr(parent, "name"); 28683034Sdougm } else if (group != NULL) { 28694327Sdougm groupname = sa_get_group_attr(group, "name"); 28703034Sdougm } 28713034Sdougm 28723034Sdougm security = sa_get_security(group, sectype, proto); 28733034Sdougm if (security != NULL) { 28743034Sdougm /* can't have a duplicate security option */ 28753034Sdougm security = NULL; 28763034Sdougm } else { 28773034Sdougm security = (sa_security_t)xmlNewChild((xmlNodePtr)group, 28784327Sdougm NULL, (xmlChar *)"security", NULL); 28793034Sdougm if (security != NULL) { 28804327Sdougm char oname[SA_STRSIZE]; 28813034Sdougm sa_set_security_attr(security, "type", proto); 28823034Sdougm 28833034Sdougm sa_set_security_attr(security, "sectype", sectype); 28843034Sdougm (void) sa_security_name(security, oname, 28854327Sdougm sizeof (oname), id); 28865331Samw if (groupname != NULL && sa_is_persistent(group)) { 28874327Sdougm sa_handle_impl_t impl_handle; 28884327Sdougm impl_handle = 28894327Sdougm (sa_handle_impl_t)sa_find_group_handle( 28904327Sdougm group); 28914327Sdougm if (impl_handle != NULL) { 28924327Sdougm (void) sa_get_instance( 28934327Sdougm impl_handle->scfhandle, groupname); 28944327Sdougm (void) sa_create_pgroup( 28954327Sdougm impl_handle->scfhandle, oname); 28964327Sdougm } 28973034Sdougm } 28983034Sdougm } 28993034Sdougm } 29003034Sdougm if (groupname != NULL) 29014327Sdougm sa_free_attr_string(groupname); 29023034Sdougm return (security); 29033034Sdougm } 29043034Sdougm 29053034Sdougm /* 29063034Sdougm * sa_destroy_security(security) 29073034Sdougm * 29083034Sdougm * Remove the specified optionset from the document and the 29093034Sdougm * configuration. 29103034Sdougm */ 29113034Sdougm 29123034Sdougm int 29133034Sdougm sa_destroy_security(sa_security_t security) 29143034Sdougm { 29154327Sdougm char name[SA_STRSIZE]; 29163034Sdougm int len; 29173034Sdougm int ret = SA_OK; 29183034Sdougm char *id = NULL; 29193034Sdougm sa_group_t group; 29203034Sdougm int iszfs = 0; 29213034Sdougm int ispersist = 1; 29223034Sdougm 29233034Sdougm group = sa_get_optionset_parent(security); 29243034Sdougm 29253034Sdougm if (group != NULL) 29264327Sdougm iszfs = sa_group_is_zfs(group); 29273034Sdougm 29283034Sdougm if (group != NULL && !iszfs) { 29294327Sdougm if (sa_is_share(group)) 29305331Samw ispersist = sa_is_persistent(group); 29314327Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 29323034Sdougm } 29333034Sdougm if (ispersist) { 29344327Sdougm len = sa_security_name(security, name, sizeof (name), id); 29354327Sdougm if (!iszfs && len > 0) { 29364327Sdougm sa_handle_impl_t impl_handle; 29374327Sdougm impl_handle = 29384327Sdougm (sa_handle_impl_t)sa_find_group_handle(group); 29394327Sdougm if (impl_handle != NULL) { 29404327Sdougm ret = sa_delete_pgroup(impl_handle->scfhandle, 29414327Sdougm name); 29424327Sdougm } else { 29434327Sdougm ret = SA_SYSTEM_ERR; 29444327Sdougm } 29453910Sdougm } 29463034Sdougm } 29473034Sdougm xmlUnlinkNode((xmlNodePtr)security); 29483034Sdougm xmlFreeNode((xmlNodePtr)security); 29494327Sdougm if (iszfs) 29504327Sdougm ret = sa_zfs_update(group); 29513034Sdougm if (id != NULL) 29524327Sdougm sa_free_attr_string(id); 29533034Sdougm return (ret); 29543034Sdougm } 29553034Sdougm 29563034Sdougm /* 29573034Sdougm * sa_get_security_attr(optionset, tag) 29583034Sdougm * 29593034Sdougm * Return the specified attribute value from the optionset. 29603034Sdougm */ 29613034Sdougm 29623034Sdougm char * 29633034Sdougm sa_get_security_attr(sa_property_t optionset, char *tag) 29643034Sdougm { 29653034Sdougm return (get_node_attr((void *)optionset, tag)); 29663034Sdougm 29673034Sdougm } 29683034Sdougm 29693034Sdougm /* 29703034Sdougm * sa_set_security_attr(optionset, tag, value) 29713034Sdougm * 29723034Sdougm * Set the optioset attribute specied by tag to the specified value. 29733034Sdougm */ 29743034Sdougm 29753034Sdougm void 29763034Sdougm sa_set_security_attr(sa_group_t optionset, char *tag, char *value) 29773034Sdougm { 29783034Sdougm set_node_attr((void *)optionset, tag, value); 29793034Sdougm } 29803034Sdougm 29813034Sdougm /* 29823034Sdougm * is_nodetype(node, type) 29833034Sdougm * 29843034Sdougm * Check to see if node is of the type specified. 29853034Sdougm */ 29863034Sdougm 29873034Sdougm static int 29883034Sdougm is_nodetype(void *node, char *type) 29893034Sdougm { 29903034Sdougm return (strcmp((char *)((xmlNodePtr)node)->name, type) == 0); 29913034Sdougm } 29923034Sdougm 29934327Sdougm /* 29944327Sdougm * add_or_update() 29954327Sdougm * 29964327Sdougm * Add or update a property. Pulled out of sa_set_prop_by_prop for 29974327Sdougm * readability. 29984327Sdougm */ 29994327Sdougm static int 30004327Sdougm add_or_update(scfutilhandle_t *scf_handle, int type, scf_value_t *value, 30014327Sdougm scf_transaction_entry_t *entry, char *name, char *valstr) 30024327Sdougm { 30034327Sdougm int ret = SA_SYSTEM_ERR; 30044327Sdougm 30054327Sdougm if (value != NULL) { 30064327Sdougm if (type == SA_PROP_OP_ADD) 30074327Sdougm ret = scf_transaction_property_new(scf_handle->trans, 30084327Sdougm entry, name, SCF_TYPE_ASTRING); 30094327Sdougm else 30104327Sdougm ret = scf_transaction_property_change(scf_handle->trans, 30114327Sdougm entry, name, SCF_TYPE_ASTRING); 30124327Sdougm if (ret == 0) { 30134327Sdougm ret = scf_value_set_astring(value, valstr); 30144327Sdougm if (ret == 0) 30154327Sdougm ret = scf_entry_add_value(entry, value); 30164327Sdougm if (ret == 0) 30174327Sdougm return (ret); 30184327Sdougm scf_value_destroy(value); 30194327Sdougm } else { 30204327Sdougm scf_entry_destroy(entry); 30214327Sdougm } 30224327Sdougm } 30234327Sdougm return (SA_SYSTEM_ERR); 30244327Sdougm } 30254327Sdougm 30263034Sdougm /* 30273034Sdougm * sa_set_prop_by_prop(optionset, group, prop, type) 30283034Sdougm * 30293034Sdougm * Add/remove/update the specified property prop into the optionset or 30303034Sdougm * share. If a share, sort out which property group based on GUID. In 30313034Sdougm * all cases, the appropriate transaction is set (or ZFS share is 30323034Sdougm * marked as needing an update) 30333034Sdougm */ 30343034Sdougm 30353034Sdougm static int 30363034Sdougm sa_set_prop_by_prop(sa_optionset_t optionset, sa_group_t group, 30373034Sdougm sa_property_t prop, int type) 30383034Sdougm { 30393034Sdougm char *name; 30403034Sdougm char *valstr; 30413034Sdougm int ret = SA_OK; 30423034Sdougm scf_transaction_entry_t *entry; 30433034Sdougm scf_value_t *value; 30443034Sdougm int opttype; /* 1 == optionset, 0 == security */ 30453034Sdougm char *id = NULL; 30463034Sdougm int iszfs = 0; 30473034Sdougm sa_group_t parent = NULL; 30485331Samw sa_share_t share = NULL; 30493910Sdougm sa_handle_impl_t impl_handle; 30503910Sdougm scfutilhandle_t *scf_handle; 30513034Sdougm 30525331Samw if (!sa_is_persistent(group)) { 30533034Sdougm /* 30543034Sdougm * if the group/share is not persistent we don't need 30553034Sdougm * to do anything here 30563034Sdougm */ 30574327Sdougm return (SA_OK); 30583034Sdougm } 30593910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 30604327Sdougm if (impl_handle == NULL || impl_handle->scfhandle == NULL) 30614327Sdougm return (SA_SYSTEM_ERR); 30623910Sdougm scf_handle = impl_handle->scfhandle; 30633034Sdougm name = sa_get_property_attr(prop, "type"); 30643034Sdougm valstr = sa_get_property_attr(prop, "value"); 30653034Sdougm entry = scf_entry_create(scf_handle->handle); 30663034Sdougm opttype = is_nodetype((void *)optionset, "optionset"); 30673034Sdougm 30685331Samw /* 30695331Samw * Check for share vs. resource since they need slightly 30705331Samw * different treatment given the hierarchy. 30715331Samw */ 30723034Sdougm if (valstr != NULL && entry != NULL) { 30734327Sdougm if (sa_is_share(group)) { 30744327Sdougm parent = sa_get_parent_group(group); 30755331Samw share = (sa_share_t)group; 30764327Sdougm if (parent != NULL) 30774327Sdougm iszfs = is_zfs_group(parent); 30785331Samw } else if (sa_is_resource(group)) { 30795331Samw share = sa_get_parent_group(group); 30805331Samw if (share != NULL) 30815331Samw parent = sa_get_parent_group(share); 30824327Sdougm } else { 30834327Sdougm iszfs = is_zfs_group(group); 30843034Sdougm } 30854327Sdougm if (!iszfs) { 30864327Sdougm if (scf_handle->trans == NULL) { 30874327Sdougm char oname[SA_STRSIZE]; 30884327Sdougm char *groupname = NULL; 30895331Samw if (share != NULL) { 30905331Samw if (parent != NULL) 30914327Sdougm groupname = 30924327Sdougm sa_get_group_attr(parent, 30934327Sdougm "name"); 30945331Samw id = sa_get_share_attr( 30955331Samw (sa_share_t)share, "id"); 30964327Sdougm } else { 30974327Sdougm groupname = sa_get_group_attr(group, 30984327Sdougm "name"); 30994327Sdougm } 31004327Sdougm if (groupname != NULL) { 31014327Sdougm ret = sa_get_instance(scf_handle, 31024327Sdougm groupname); 31034327Sdougm sa_free_attr_string(groupname); 31044327Sdougm } 31054327Sdougm if (opttype) 31064327Sdougm (void) sa_optionset_name(optionset, 31074327Sdougm oname, sizeof (oname), id); 31084327Sdougm else 31094327Sdougm (void) sa_security_name(optionset, 31104327Sdougm oname, sizeof (oname), id); 31114327Sdougm ret = sa_start_transaction(scf_handle, oname); 31123910Sdougm } 31134327Sdougm if (ret == SA_OK) { 31144327Sdougm switch (type) { 31154327Sdougm case SA_PROP_OP_REMOVE: 31164327Sdougm ret = scf_transaction_property_delete( 31174327Sdougm scf_handle->trans, entry, name); 31184327Sdougm break; 31194327Sdougm case SA_PROP_OP_ADD: 31204327Sdougm case SA_PROP_OP_UPDATE: 31214327Sdougm value = scf_value_create( 31224327Sdougm scf_handle->handle); 31234327Sdougm ret = add_or_update(scf_handle, type, 31244327Sdougm value, entry, name, valstr); 31254327Sdougm break; 31263034Sdougm } 31273034Sdougm } 31284327Sdougm } else { 31294327Sdougm /* 31304327Sdougm * ZFS update. The calling function would have updated 31314327Sdougm * the internal XML structure. Just need to flag it as 31324327Sdougm * changed for ZFS. 31334327Sdougm */ 31344327Sdougm zfs_set_update((sa_share_t)group); 31354327Sdougm } 31363034Sdougm } 31373034Sdougm 31383034Sdougm if (name != NULL) 31394327Sdougm sa_free_attr_string(name); 31403034Sdougm if (valstr != NULL) 31414327Sdougm sa_free_attr_string(valstr); 31423034Sdougm else if (entry != NULL) 31434327Sdougm scf_entry_destroy(entry); 31443034Sdougm 31453034Sdougm if (ret == -1) 31464327Sdougm ret = SA_SYSTEM_ERR; 31473034Sdougm 31483034Sdougm return (ret); 31493034Sdougm } 31503034Sdougm 31513034Sdougm /* 31526007Sthurlow * sa_create_section(name, value) 31536007Sthurlow * 31546007Sthurlow * Create a new section with the specified name and extra data. 31556007Sthurlow */ 31566007Sthurlow 31576007Sthurlow sa_property_t 31586007Sthurlow sa_create_section(char *name, char *extra) 31596007Sthurlow { 31606007Sthurlow xmlNodePtr node; 31616007Sthurlow 31626007Sthurlow node = xmlNewNode(NULL, (xmlChar *)"section"); 31636007Sthurlow if (node != NULL) { 31646007Sthurlow if (name != NULL) 31656007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 31666007Sthurlow (xmlChar *)name); 31676007Sthurlow if (extra != NULL) 31686007Sthurlow (void) xmlSetProp(node, (xmlChar *)"extra", 31696007Sthurlow (xmlChar *)extra); 31706007Sthurlow } 31716007Sthurlow return ((sa_property_t)node); 31726007Sthurlow } 31736007Sthurlow 31746007Sthurlow void 31756007Sthurlow sa_set_section_attr(sa_property_t sect, char *name, char *value) 31766007Sthurlow { 31776007Sthurlow (void) xmlSetProp(sect, (xmlChar *)name, (xmlChar *)value); 31786007Sthurlow } 31796007Sthurlow 31806007Sthurlow /* 31816007Sthurlow * sa_create_property(section, name, value) 31823034Sdougm * 31833034Sdougm * Create a new property with the specified name and value. 31843034Sdougm */ 31853034Sdougm 31863034Sdougm sa_property_t 31873034Sdougm sa_create_property(char *name, char *value) 31883034Sdougm { 31893034Sdougm xmlNodePtr node; 31903034Sdougm 31913034Sdougm node = xmlNewNode(NULL, (xmlChar *)"option"); 31923034Sdougm if (node != NULL) { 31936007Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", (xmlChar *)name); 31946007Sthurlow (void) xmlSetProp(node, (xmlChar *)"value", (xmlChar *)value); 31953034Sdougm } 31963034Sdougm return ((sa_property_t)node); 31973034Sdougm } 31983034Sdougm 31993034Sdougm /* 32003034Sdougm * sa_add_property(object, property) 32013034Sdougm * 32023034Sdougm * Add the specified property to the object. Issue the appropriate 32033034Sdougm * transaction or mark a ZFS object as needing an update. 32043034Sdougm */ 32053034Sdougm 32063034Sdougm int 32073034Sdougm sa_add_property(void *object, sa_property_t property) 32083034Sdougm { 32093034Sdougm int ret = SA_OK; 32103034Sdougm sa_group_t parent; 32113034Sdougm sa_group_t group; 32123034Sdougm char *proto; 32136214Sdougm 32143034Sdougm if (property != NULL) { 32156271Sdougm sa_handle_t handle; 32166214Sdougm handle = sa_find_group_handle((sa_group_t)object); 32176271Sdougm /* It is legitimate to not find a handle */ 32186214Sdougm proto = sa_get_optionset_attr(object, "type"); 32196214Sdougm if ((ret = sa_valid_property(handle, object, proto, 32206214Sdougm property)) == SA_OK) { 32214327Sdougm property = (sa_property_t)xmlAddChild( 32224327Sdougm (xmlNodePtr)object, (xmlNodePtr)property); 32234327Sdougm } else { 32244327Sdougm if (proto != NULL) 32254327Sdougm sa_free_attr_string(proto); 32264327Sdougm return (ret); 32274327Sdougm } 32286214Sdougm if (proto != NULL) 32296214Sdougm sa_free_attr_string(proto); 32303034Sdougm } 32313034Sdougm 32323034Sdougm 32333034Sdougm parent = sa_get_parent_group(object); 32345331Samw if (!sa_is_persistent(parent)) 32354327Sdougm return (ret); 32365331Samw 32375331Samw if (sa_is_resource(parent)) { 32385331Samw /* 32395331Samw * Resources are children of share. Need to go up two 32405331Samw * levels to find the group but the parent needs to be 32415331Samw * the share at this point in order to get the "id". 32425331Samw */ 32435331Samw parent = sa_get_parent_group(parent); 32445331Samw group = sa_get_parent_group(parent); 32455331Samw } else if (sa_is_share(parent)) { 32465331Samw group = sa_get_parent_group(parent); 32475331Samw } else { 32485331Samw group = parent; 32493034Sdougm } 32503034Sdougm 32514327Sdougm if (property == NULL) { 32524327Sdougm ret = SA_NO_MEMORY; 32534327Sdougm } else { 32544327Sdougm char oname[SA_STRSIZE]; 32553034Sdougm 32564327Sdougm if (!is_zfs_group(group)) { 32574327Sdougm char *id = NULL; 32584327Sdougm sa_handle_impl_t impl_handle; 32594327Sdougm scfutilhandle_t *scf_handle; 32603910Sdougm 32614327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle( 32624327Sdougm group); 32634327Sdougm if (impl_handle == NULL || 32644327Sdougm impl_handle->scfhandle == NULL) 32654327Sdougm ret = SA_SYSTEM_ERR; 32664327Sdougm if (ret == SA_OK) { 32674327Sdougm scf_handle = impl_handle->scfhandle; 32684327Sdougm if (sa_is_share((sa_group_t)parent)) { 32694327Sdougm id = sa_get_share_attr( 32704327Sdougm (sa_share_t)parent, "id"); 32714327Sdougm } 32724327Sdougm if (scf_handle->trans == NULL) { 32734327Sdougm if (is_nodetype(object, "optionset")) { 32744327Sdougm (void) sa_optionset_name( 32754327Sdougm (sa_optionset_t)object, 32764327Sdougm oname, sizeof (oname), id); 32774327Sdougm } else { 32784327Sdougm (void) sa_security_name( 32794327Sdougm (sa_optionset_t)object, 32804327Sdougm oname, sizeof (oname), id); 32814327Sdougm } 32824327Sdougm ret = sa_start_transaction(scf_handle, 32834327Sdougm oname); 32844327Sdougm } 32854327Sdougm if (ret == SA_OK) { 32864327Sdougm char *name; 32874327Sdougm char *value; 32884327Sdougm name = sa_get_property_attr(property, 32894327Sdougm "type"); 32904327Sdougm value = sa_get_property_attr(property, 32914327Sdougm "value"); 32924327Sdougm if (name != NULL && value != NULL) { 32934327Sdougm if (scf_handle->scf_state == 32944327Sdougm SCH_STATE_INIT) { 32954327Sdougm ret = sa_set_property( 32964327Sdougm scf_handle, name, 32974327Sdougm value); 32984327Sdougm } 32994327Sdougm } else { 33004327Sdougm ret = SA_CONFIG_ERR; 33014327Sdougm } 33024327Sdougm if (name != NULL) 33034327Sdougm sa_free_attr_string( 33044327Sdougm name); 33054327Sdougm if (value != NULL) 33064327Sdougm sa_free_attr_string(value); 33074327Sdougm } 33084327Sdougm if (id != NULL) 33094327Sdougm sa_free_attr_string(id); 33104327Sdougm } 33114327Sdougm } else { 33124327Sdougm /* 33134327Sdougm * ZFS is a special case. We do want 33144327Sdougm * to allow editing property/security 33154327Sdougm * lists since we can have a better 33164327Sdougm * syntax and we also want to keep 33174327Sdougm * things consistent when possible. 33184327Sdougm * 33194327Sdougm * Right now, we defer until the 33204327Sdougm * sa_commit_properties so we can get 33214327Sdougm * them all at once. We do need to 33224327Sdougm * mark the share as "changed" 33234327Sdougm */ 33244327Sdougm zfs_set_update((sa_share_t)parent); 33253034Sdougm } 33263034Sdougm } 33273034Sdougm return (ret); 33283034Sdougm } 33293034Sdougm 33303034Sdougm /* 33313034Sdougm * sa_remove_property(property) 33323034Sdougm * 33333034Sdougm * Remove the specied property from its containing object. Update the 33343034Sdougm * repository as appropriate. 33353034Sdougm */ 33363034Sdougm 33373034Sdougm int 33383034Sdougm sa_remove_property(sa_property_t property) 33393034Sdougm { 33403034Sdougm int ret = SA_OK; 33413034Sdougm 33423034Sdougm if (property != NULL) { 33433034Sdougm sa_optionset_t optionset; 33443034Sdougm sa_group_t group; 33453034Sdougm optionset = sa_get_property_parent(property); 33463034Sdougm if (optionset != NULL) { 33474327Sdougm group = sa_get_optionset_parent(optionset); 33484327Sdougm if (group != NULL) { 33494327Sdougm ret = sa_set_prop_by_prop(optionset, group, 33504327Sdougm property, SA_PROP_OP_REMOVE); 33514327Sdougm } 33523034Sdougm } 33533034Sdougm xmlUnlinkNode((xmlNodePtr)property); 33543034Sdougm xmlFreeNode((xmlNodePtr)property); 33553034Sdougm } else { 33564327Sdougm ret = SA_NO_SUCH_PROP; 33573034Sdougm } 33583034Sdougm return (ret); 33593034Sdougm } 33603034Sdougm 33613034Sdougm /* 33623034Sdougm * sa_update_property(property, value) 33633034Sdougm * 33643034Sdougm * Update the specified property to the new value. If value is NULL, 33653034Sdougm * we currently treat this as a remove. 33663034Sdougm */ 33673034Sdougm 33683034Sdougm int 33693034Sdougm sa_update_property(sa_property_t property, char *value) 33703034Sdougm { 33713034Sdougm int ret = SA_OK; 33723034Sdougm if (value == NULL) { 33733034Sdougm return (sa_remove_property(property)); 33743034Sdougm } else { 33753034Sdougm sa_optionset_t optionset; 33763034Sdougm sa_group_t group; 33773034Sdougm set_node_attr((void *)property, "value", value); 33783034Sdougm optionset = sa_get_property_parent(property); 33793034Sdougm if (optionset != NULL) { 33804327Sdougm group = sa_get_optionset_parent(optionset); 33814327Sdougm if (group != NULL) { 33824327Sdougm ret = sa_set_prop_by_prop(optionset, group, 33834327Sdougm property, SA_PROP_OP_UPDATE); 33844327Sdougm } 33853034Sdougm } else { 33864327Sdougm ret = SA_NO_SUCH_PROP; 33873034Sdougm } 33883034Sdougm } 33893034Sdougm return (ret); 33903034Sdougm } 33913034Sdougm 33923034Sdougm /* 33936007Sthurlow * sa_get_protocol_section(propset, prop) 33946007Sthurlow * 33956007Sthurlow * Get the specified protocol specific section. These are global to 33966007Sthurlow * the protocol and not specific to a group or share. 33976007Sthurlow */ 33986007Sthurlow 33996007Sthurlow sa_protocol_properties_t 34006007Sthurlow sa_get_protocol_section(sa_protocol_properties_t propset, char *section) 34016007Sthurlow { 34026007Sthurlow xmlNodePtr node = (xmlNodePtr)propset; 34036007Sthurlow xmlChar *value = NULL; 34046007Sthurlow char *proto; 34056007Sthurlow 34066007Sthurlow proto = sa_get_optionset_attr(propset, "type"); 34078271SGordon.Ross@Sun.COM if ((sa_proto_get_featureset(proto) & SA_FEATURE_HAS_SECTIONS) == 0) { 34088271SGordon.Ross@Sun.COM if (proto != NULL) 34098271SGordon.Ross@Sun.COM sa_free_attr_string(proto); 34106007Sthurlow return (propset); 34118271SGordon.Ross@Sun.COM } 34126007Sthurlow 34136007Sthurlow for (node = node->children; node != NULL; 34146007Sthurlow node = node->next) { 34156007Sthurlow if (xmlStrcmp(node->name, (xmlChar *)"section") == 0) { 34166007Sthurlow if (section == NULL) 34176007Sthurlow break; 34186007Sthurlow value = xmlGetProp(node, (xmlChar *)"name"); 34196007Sthurlow if (value != NULL && 34206007Sthurlow xmlStrcasecmp(value, (xmlChar *)section) == 0) { 34216007Sthurlow break; 34226007Sthurlow } 34236007Sthurlow if (value != NULL) { 34246007Sthurlow xmlFree(value); 34256007Sthurlow value = NULL; 34266007Sthurlow } 34276007Sthurlow } 34286007Sthurlow } 34296007Sthurlow if (value != NULL) 34306007Sthurlow xmlFree(value); 34318271SGordon.Ross@Sun.COM if (proto != NULL) 34328271SGordon.Ross@Sun.COM sa_free_attr_string(proto); 34336007Sthurlow if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"section") != 0) { 34346007Sthurlow /* 34356007Sthurlow * avoid a non option node -- it is possible to be a 34366007Sthurlow * text node 34376007Sthurlow */ 34386007Sthurlow node = NULL; 34396007Sthurlow } 34406007Sthurlow return ((sa_protocol_properties_t)node); 34416007Sthurlow } 34426007Sthurlow 34436007Sthurlow /* 34446007Sthurlow * sa_get_next_protocol_section(prop, find) 34456007Sthurlow * 34466007Sthurlow * Get the next protocol specific section in the list. 34476007Sthurlow */ 34486007Sthurlow 34496007Sthurlow sa_property_t 34506007Sthurlow sa_get_next_protocol_section(sa_property_t prop, char *find) 34516007Sthurlow { 34526007Sthurlow xmlNodePtr node; 34536007Sthurlow xmlChar *value = NULL; 34546007Sthurlow char *proto; 34556007Sthurlow 34566007Sthurlow proto = sa_get_optionset_attr(prop, "type"); 34578271SGordon.Ross@Sun.COM if ((sa_proto_get_featureset(proto) & SA_FEATURE_HAS_SECTIONS) == 0) { 34588271SGordon.Ross@Sun.COM if (proto != NULL) 34598271SGordon.Ross@Sun.COM sa_free_attr_string(proto); 34606007Sthurlow return ((sa_property_t)NULL); 34618271SGordon.Ross@Sun.COM } 34626007Sthurlow 34636007Sthurlow for (node = ((xmlNodePtr)prop)->next; node != NULL; 34646007Sthurlow node = node->next) { 34656007Sthurlow if (xmlStrcmp(node->name, (xmlChar *)"section") == 0) { 34666007Sthurlow if (find == NULL) 34676007Sthurlow break; 34686007Sthurlow value = xmlGetProp(node, (xmlChar *)"name"); 34696007Sthurlow if (value != NULL && 34706007Sthurlow xmlStrcasecmp(value, (xmlChar *)find) == 0) { 34716007Sthurlow break; 34726007Sthurlow } 34736007Sthurlow if (value != NULL) { 34746007Sthurlow xmlFree(value); 34756007Sthurlow value = NULL; 34766007Sthurlow } 34776007Sthurlow 34786007Sthurlow } 34796007Sthurlow } 34806007Sthurlow if (value != NULL) 34816007Sthurlow xmlFree(value); 34828271SGordon.Ross@Sun.COM if (proto != NULL) 34838271SGordon.Ross@Sun.COM sa_free_attr_string(proto); 34846007Sthurlow return ((sa_property_t)node); 34856007Sthurlow } 34866007Sthurlow 34876007Sthurlow /* 34883034Sdougm * sa_get_protocol_property(propset, prop) 34893034Sdougm * 34903034Sdougm * Get the specified protocol specific property. These are global to 34913034Sdougm * the protocol and not specific to a group or share. 34923034Sdougm */ 34933034Sdougm 34943034Sdougm sa_property_t 34953034Sdougm sa_get_protocol_property(sa_protocol_properties_t propset, char *prop) 34963034Sdougm { 34973034Sdougm xmlNodePtr node = (xmlNodePtr)propset; 34983034Sdougm xmlChar *value = NULL; 34993034Sdougm 35006007Sthurlow if (propset == NULL) 35016007Sthurlow return (NULL); 35026007Sthurlow 35033034Sdougm for (node = node->children; node != NULL; 35044327Sdougm node = node->next) { 35054327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 35064327Sdougm if (prop == NULL) 35074327Sdougm break; 35084327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 35094327Sdougm if (value != NULL && 35104327Sdougm xmlStrcasecmp(value, (xmlChar *)prop) == 0) { 35114327Sdougm break; 35124327Sdougm } 35134327Sdougm if (value != NULL) { 35144327Sdougm xmlFree(value); 35154327Sdougm value = NULL; 35164327Sdougm } 35173034Sdougm } 35183034Sdougm } 35193034Sdougm if (value != NULL) 35203034Sdougm xmlFree(value); 35213034Sdougm if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"option") != 0) { 35224327Sdougm /* 35234327Sdougm * avoid a non option node -- it is possible to be a 35244327Sdougm * text node 35254327Sdougm */ 35264327Sdougm node = NULL; 35273034Sdougm } 35283034Sdougm return ((sa_property_t)node); 35293034Sdougm } 35303034Sdougm 35313034Sdougm /* 35323034Sdougm * sa_get_next_protocol_property(prop) 35333034Sdougm * 35343034Sdougm * Get the next protocol specific property in the list. 35353034Sdougm */ 35363034Sdougm 35373034Sdougm sa_property_t 35386007Sthurlow sa_get_next_protocol_property(sa_property_t prop, char *find) 35393034Sdougm { 35403034Sdougm xmlNodePtr node; 35416007Sthurlow xmlChar *value = NULL; 35423034Sdougm 35433034Sdougm for (node = ((xmlNodePtr)prop)->next; node != NULL; 35444327Sdougm node = node->next) { 35453034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 35466007Sthurlow if (find == NULL) 35476007Sthurlow break; 35486007Sthurlow value = xmlGetProp(node, (xmlChar *)"type"); 35496007Sthurlow if (value != NULL && 35506007Sthurlow xmlStrcasecmp(value, (xmlChar *)find) == 0) { 35516007Sthurlow break; 35526007Sthurlow } 35536007Sthurlow if (value != NULL) { 35546007Sthurlow xmlFree(value); 35556007Sthurlow value = NULL; 35566007Sthurlow } 35576007Sthurlow 35583034Sdougm } 35593034Sdougm } 35606007Sthurlow if (value != NULL) 35616007Sthurlow xmlFree(value); 35623034Sdougm return ((sa_property_t)node); 35633034Sdougm } 35643034Sdougm 35653034Sdougm /* 35663034Sdougm * sa_set_protocol_property(prop, value) 35673034Sdougm * 35683034Sdougm * Set the specified property to have the new value. The protocol 35693034Sdougm * specific plugin will then be called to update the property. 35703034Sdougm */ 35713034Sdougm 35723034Sdougm int 35736007Sthurlow sa_set_protocol_property(sa_property_t prop, char *section, char *value) 35743034Sdougm { 35753034Sdougm sa_protocol_properties_t propset; 35763034Sdougm char *proto; 35773034Sdougm int ret = SA_INVALID_PROTOCOL; 35783034Sdougm 35793034Sdougm propset = ((xmlNodePtr)prop)->parent; 35803034Sdougm if (propset != NULL) { 35814327Sdougm proto = sa_get_optionset_attr(propset, "type"); 35824327Sdougm if (proto != NULL) { 35836007Sthurlow if (section != NULL) 35846007Sthurlow set_node_attr((xmlNodePtr)prop, "section", 35856007Sthurlow section); 35864327Sdougm set_node_attr((xmlNodePtr)prop, "value", value); 35874327Sdougm ret = sa_proto_set_property(proto, prop); 35884327Sdougm sa_free_attr_string(proto); 35894327Sdougm } 35903034Sdougm } 35913034Sdougm return (ret); 35923034Sdougm } 35933034Sdougm 35943034Sdougm /* 35953034Sdougm * sa_add_protocol_property(propset, prop) 35963034Sdougm * 35975331Samw * Add a new property to the protocol specific property set. 35983034Sdougm */ 35993034Sdougm 36003034Sdougm int 36013034Sdougm sa_add_protocol_property(sa_protocol_properties_t propset, sa_property_t prop) 36023034Sdougm { 36033034Sdougm xmlNodePtr node; 36043034Sdougm 36053034Sdougm /* should check for legitimacy */ 36063034Sdougm node = xmlAddChild((xmlNodePtr)propset, (xmlNodePtr)prop); 36073034Sdougm if (node != NULL) 36084327Sdougm return (SA_OK); 36093034Sdougm return (SA_NO_MEMORY); 36103034Sdougm } 36113034Sdougm 36123034Sdougm /* 36133034Sdougm * sa_create_protocol_properties(proto) 36143034Sdougm * 36155331Samw * Create a protocol specific property set. 36163034Sdougm */ 36173034Sdougm 36183034Sdougm sa_protocol_properties_t 36193034Sdougm sa_create_protocol_properties(char *proto) 36203034Sdougm { 36213034Sdougm xmlNodePtr node; 36224327Sdougm 36233034Sdougm node = xmlNewNode(NULL, (xmlChar *)"propertyset"); 36244327Sdougm if (node != NULL) 36256007Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto); 36263034Sdougm return (node); 36273034Sdougm } 36285331Samw 36295331Samw /* 36305331Samw * sa_get_share_resource(share, resource) 36315331Samw * 36325331Samw * Get the named resource from the share, if it exists. If resource is 36335331Samw * NULL, get the first resource. 36345331Samw */ 36355331Samw 36365331Samw sa_resource_t 36375331Samw sa_get_share_resource(sa_share_t share, char *resource) 36385331Samw { 36395331Samw xmlNodePtr node = NULL; 36405331Samw xmlChar *name; 36415331Samw 36425331Samw if (share != NULL) { 36435331Samw for (node = ((xmlNodePtr)share)->children; node != NULL; 36445331Samw node = node->next) { 36455331Samw if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0) { 36465331Samw if (resource == NULL) { 36475331Samw /* 36485331Samw * We are looking for the first 36495331Samw * resource node and not a names 36505331Samw * resource. 36515331Samw */ 36525331Samw break; 36535331Samw } else { 36545331Samw /* is it the correct share? */ 36555331Samw name = xmlGetProp(node, 36565331Samw (xmlChar *)"name"); 36575331Samw if (name != NULL && 36585331Samw xmlStrcasecmp(name, 36595331Samw (xmlChar *)resource) == 0) { 36605331Samw xmlFree(name); 36615331Samw break; 36625331Samw } 36635331Samw xmlFree(name); 36645331Samw } 36655331Samw } 36665331Samw } 36675331Samw } 36685331Samw return ((sa_resource_t)node); 36695331Samw } 36705331Samw 36715331Samw /* 36725331Samw * sa_get_next_resource(resource) 36735331Samw * Return the next share following the specified share 36745331Samw * from the internal list of shares. Returns NULL if there 36755331Samw * are no more shares. The list is relative to the same 36765331Samw * group. 36775331Samw */ 36785331Samw sa_share_t 36795331Samw sa_get_next_resource(sa_resource_t resource) 36805331Samw { 36815331Samw xmlNodePtr node = NULL; 36825331Samw 36835331Samw if (resource != NULL) { 36845331Samw for (node = ((xmlNodePtr)resource)->next; node != NULL; 36855331Samw node = node->next) { 36865331Samw if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0) 36875331Samw break; 36885331Samw } 36895331Samw } 36905331Samw return ((sa_share_t)node); 36915331Samw } 36925331Samw 36935331Samw /* 36945331Samw * _sa_get_next_resource_index(share) 36955331Samw * 36965331Samw * get the next resource index number (one greater then current largest) 36975331Samw */ 36985331Samw 36995331Samw static int 37005331Samw _sa_get_next_resource_index(sa_share_t share) 37015331Samw { 37025331Samw sa_resource_t resource; 37035331Samw int index = 0; 37045331Samw char *id; 37055331Samw 37065331Samw for (resource = sa_get_share_resource(share, NULL); 37075331Samw resource != NULL; 37085331Samw resource = sa_get_next_resource(resource)) { 37095331Samw id = get_node_attr((void *)resource, "id"); 37105331Samw if (id != NULL) { 37115331Samw int val; 37125331Samw val = atoi(id); 37135331Samw if (val > index) 37145331Samw index = val; 37155331Samw sa_free_attr_string(id); 37165331Samw } 37175331Samw } 37185331Samw return (index + 1); 37195331Samw } 37205331Samw 37215331Samw 37225331Samw /* 37235331Samw * sa_add_resource(share, resource, persist, &err) 37245331Samw * 37255331Samw * Adds a new resource name associated with share. The resource name 37265331Samw * must be unique in the system and will be case insensitive (eventually). 37275331Samw */ 37285331Samw 37295331Samw sa_resource_t 37305331Samw sa_add_resource(sa_share_t share, char *resource, int persist, int *error) 37315331Samw { 37325331Samw xmlNodePtr node; 37335331Samw int err = SA_OK; 37345331Samw sa_resource_t res; 37355331Samw sa_group_t group; 37365331Samw sa_handle_t handle; 37375331Samw char istring[8]; /* just big enough for an integer value */ 37385331Samw int index; 37395331Samw 37405331Samw group = sa_get_parent_group(share); 37415331Samw handle = sa_find_group_handle(group); 37425331Samw res = sa_find_resource(handle, resource); 37435331Samw if (res != NULL) { 37445331Samw err = SA_DUPLICATE_NAME; 37455331Samw res = NULL; 37465331Samw } else { 37475331Samw node = xmlNewChild((xmlNodePtr)share, NULL, 37485331Samw (xmlChar *)"resource", NULL); 37495331Samw if (node != NULL) { 37506007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 37515331Samw (xmlChar *)resource); 37526007Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", persist ? 37535331Samw (xmlChar *)"persist" : (xmlChar *)"transient"); 37545331Samw if (persist != SA_SHARE_TRANSIENT) { 37555331Samw index = _sa_get_next_resource_index(share); 37565331Samw (void) snprintf(istring, sizeof (istring), "%d", 37575331Samw index); 37586007Sthurlow (void) xmlSetProp(node, (xmlChar *)"id", 37595331Samw (xmlChar *)istring); 37607483SDoug.McCallum@Sun.COM 37617483SDoug.McCallum@Sun.COM if (!sa_is_persistent((sa_group_t)share)) 37627483SDoug.McCallum@Sun.COM goto done; 37637483SDoug.McCallum@Sun.COM 37647483SDoug.McCallum@Sun.COM if (!sa_group_is_zfs(group)) { 37655331Samw /* ZFS doesn't use resource names */ 37665331Samw sa_handle_impl_t ihandle; 37677483SDoug.McCallum@Sun.COM 37685331Samw ihandle = (sa_handle_impl_t) 37695331Samw sa_find_group_handle( 37705331Samw group); 37715331Samw if (ihandle != NULL) 37725331Samw err = sa_commit_share( 37735331Samw ihandle->scfhandle, group, 37745331Samw share); 37755331Samw else 37765331Samw err = SA_SYSTEM_ERR; 37777483SDoug.McCallum@Sun.COM } else { 37787483SDoug.McCallum@Sun.COM err = sa_zfs_update((sa_share_t)group); 37795331Samw } 37805331Samw } 37815331Samw } 37825331Samw } 37837483SDoug.McCallum@Sun.COM done: 37845331Samw if (error != NULL) 37855331Samw *error = err; 37865331Samw return ((sa_resource_t)node); 37875331Samw } 37885331Samw 37895331Samw /* 37905331Samw * sa_remove_resource(resource) 37915331Samw * 37925331Samw * Remove the resource name from the share (and the system) 37935331Samw */ 37945331Samw 37955331Samw int 37965331Samw sa_remove_resource(sa_resource_t resource) 37975331Samw { 37985331Samw sa_share_t share; 37995331Samw sa_group_t group; 38005331Samw char *type; 38015331Samw int ret = SA_OK; 38027483SDoug.McCallum@Sun.COM boolean_t transient = B_FALSE; 38035521Sas200622 sa_optionset_t opt; 38045331Samw 38055331Samw share = sa_get_resource_parent(resource); 38065331Samw type = sa_get_share_attr(share, "type"); 38075331Samw group = sa_get_parent_group(share); 38085331Samw 38095331Samw 38105331Samw if (type != NULL) { 38115331Samw if (strcmp(type, "persist") != 0) 38127483SDoug.McCallum@Sun.COM transient = B_TRUE; 38135331Samw sa_free_attr_string(type); 38145331Samw } 38155331Samw 38165521Sas200622 /* Disable the resource for all protocols. */ 38175521Sas200622 (void) sa_disable_resource(resource, NULL); 38185521Sas200622 38195521Sas200622 /* Remove any optionsets from the resource. */ 38205521Sas200622 for (opt = sa_get_optionset(resource, NULL); 38215521Sas200622 opt != NULL; 38225521Sas200622 opt = sa_get_next_optionset(opt)) 38235521Sas200622 (void) sa_destroy_optionset(opt); 38245521Sas200622 38255331Samw /* Remove from the share */ 38265331Samw xmlUnlinkNode((xmlNode *)resource); 38275331Samw xmlFreeNode((xmlNode *)resource); 38285331Samw 38295331Samw /* only do SMF action if permanent and not ZFS */ 38307483SDoug.McCallum@Sun.COM if (transient) 38317483SDoug.McCallum@Sun.COM return (ret); 38327483SDoug.McCallum@Sun.COM 38337483SDoug.McCallum@Sun.COM if (!sa_group_is_zfs(group)) { 38345331Samw sa_handle_impl_t ihandle; 38355331Samw ihandle = (sa_handle_impl_t)sa_find_group_handle(group); 38365331Samw if (ihandle != NULL) 38375331Samw ret = sa_commit_share(ihandle->scfhandle, group, share); 38385331Samw else 38395331Samw ret = SA_SYSTEM_ERR; 38407483SDoug.McCallum@Sun.COM } else { 38417483SDoug.McCallum@Sun.COM ret = sa_zfs_update((sa_share_t)group); 38425331Samw } 3843*8845Samw@Sun.COM 38445331Samw return (ret); 38455331Samw } 38465331Samw 38475331Samw /* 3848*8845Samw@Sun.COM * proto_rename_resource(handle, group, resource, newname) 38495331Samw * 38505331Samw * Helper function for sa_rename_resource that notifies the protocol 38515331Samw * of a resource name change prior to a config repository update. 38525331Samw */ 38535331Samw static int 38545331Samw proto_rename_resource(sa_handle_t handle, sa_group_t group, 38555331Samw sa_resource_t resource, char *newname) 38565331Samw { 38575331Samw sa_optionset_t optionset; 38585331Samw int ret = SA_OK; 38595331Samw int err; 38605331Samw 38615331Samw for (optionset = sa_get_optionset(group, NULL); 38625331Samw optionset != NULL; 38635331Samw optionset = sa_get_next_optionset(optionset)) { 38645331Samw char *type; 38655331Samw type = sa_get_optionset_attr(optionset, "type"); 38665331Samw if (type != NULL) { 38675331Samw err = sa_proto_rename_resource(handle, type, resource, 38685331Samw newname); 38695331Samw if (err != SA_OK) 38705331Samw ret = err; 38715331Samw sa_free_attr_string(type); 38725331Samw } 38735331Samw } 38745331Samw return (ret); 38755331Samw } 38765331Samw 38775331Samw /* 38785331Samw * sa_rename_resource(resource, newname) 38795331Samw * 38805331Samw * Rename the resource to the new name, if it is unique. 38815331Samw */ 38825331Samw 38835331Samw int 38845331Samw sa_rename_resource(sa_resource_t resource, char *newname) 38855331Samw { 38865331Samw sa_share_t share; 38875331Samw sa_group_t group = NULL; 38885331Samw sa_resource_t target; 38895331Samw int ret = SA_CONFIG_ERR; 38905331Samw sa_handle_t handle = NULL; 38915331Samw 38925331Samw share = sa_get_resource_parent(resource); 38935331Samw if (share == NULL) 38945331Samw return (ret); 38955331Samw 38965331Samw group = sa_get_parent_group(share); 38975331Samw if (group == NULL) 38985331Samw return (ret); 38995331Samw 39005331Samw handle = (sa_handle_impl_t)sa_find_group_handle(group); 39015331Samw if (handle == NULL) 39025331Samw return (ret); 39035331Samw 39045331Samw target = sa_find_resource(handle, newname); 39055331Samw if (target != NULL) { 39065331Samw ret = SA_DUPLICATE_NAME; 39075331Samw } else { 39085331Samw /* 39095331Samw * Everything appears to be valid at this 39105331Samw * point. Change the name of the active share and then 39115331Samw * update the share in the appropriate repository. 39125331Samw */ 39135331Samw ret = proto_rename_resource(handle, group, resource, newname); 39145331Samw set_node_attr(resource, "name", newname); 39157483SDoug.McCallum@Sun.COM 39167483SDoug.McCallum@Sun.COM if (!sa_is_persistent((sa_group_t)share)) 39177483SDoug.McCallum@Sun.COM return (ret); 39187483SDoug.McCallum@Sun.COM 39197483SDoug.McCallum@Sun.COM if (!sa_group_is_zfs(group)) { 39205331Samw sa_handle_impl_t ihandle = (sa_handle_impl_t)handle; 39215331Samw ret = sa_commit_share(ihandle->scfhandle, group, 39225331Samw share); 39237483SDoug.McCallum@Sun.COM } else { 39247483SDoug.McCallum@Sun.COM ret = sa_zfs_update((sa_share_t)group); 39255331Samw } 39265331Samw } 39275331Samw return (ret); 39285331Samw } 39295331Samw 39305331Samw /* 39315331Samw * sa_get_resource_attr(resource, tag) 39325331Samw * 39335331Samw * Get the named attribute of the resource. "name" and "id" are 39345331Samw * currently defined. NULL if tag not defined. 39355331Samw */ 39365331Samw 39375331Samw char * 39385331Samw sa_get_resource_attr(sa_resource_t resource, char *tag) 39395331Samw { 39405331Samw return (get_node_attr((void *)resource, tag)); 39415331Samw } 39425331Samw 39435331Samw /* 39445331Samw * sa_set_resource_attr(resource, tag, value) 39455331Samw * 39465331Samw * Get the named attribute of the resource. "name" and "id" are 39475331Samw * currently defined. NULL if tag not defined. Currently we don't do 39485331Samw * much, but additional checking may be needed in the future. 39495331Samw */ 39505331Samw 39515331Samw int 39525331Samw sa_set_resource_attr(sa_resource_t resource, char *tag, char *value) 39535331Samw { 39545331Samw set_node_attr((void *)resource, tag, value); 39555331Samw return (SA_OK); 39565331Samw } 39575331Samw 39585331Samw /* 39595331Samw * sa_get_resource_parent(resource_t) 39605331Samw * 39615331Samw * Returns the share associated with the resource. 39625331Samw */ 39635331Samw 39645331Samw sa_share_t 39655331Samw sa_get_resource_parent(sa_resource_t resource) 39665331Samw { 39675331Samw sa_share_t share = NULL; 39685331Samw 39695331Samw if (resource != NULL) 39705331Samw share = (sa_share_t)((xmlNodePtr)resource)->parent; 39715331Samw return (share); 39725331Samw } 39735331Samw 39745331Samw /* 39755331Samw * find_resource(group, name) 39765331Samw * 39775331Samw * Find the resource within the group. 39785331Samw */ 39795331Samw 39805331Samw static sa_resource_t 39815331Samw find_resource(sa_group_t group, char *resname) 39825331Samw { 39835331Samw sa_share_t share; 39845331Samw sa_resource_t resource = NULL; 39855331Samw char *name; 39865331Samw 39875331Samw /* Iterate over all the shares and resources in the group. */ 39885331Samw for (share = sa_get_share(group, NULL); 39895331Samw share != NULL && resource == NULL; 39905331Samw share = sa_get_next_share(share)) { 39915331Samw for (resource = sa_get_share_resource(share, NULL); 39925331Samw resource != NULL; 39935331Samw resource = sa_get_next_resource(resource)) { 39945331Samw name = sa_get_resource_attr(resource, "name"); 39955331Samw if (name != NULL && xmlStrcasecmp((xmlChar*)name, 39965331Samw (xmlChar*)resname) == 0) { 39975331Samw sa_free_attr_string(name); 39985331Samw break; 39995331Samw } 40005331Samw if (name != NULL) { 40015331Samw sa_free_attr_string(name); 40025331Samw } 40035331Samw } 40045331Samw } 40055331Samw return (resource); 40065331Samw } 40075331Samw 40085331Samw /* 40095331Samw * sa_find_resource(name) 40105331Samw * 40115331Samw * Find the named resource in the system. 40125331Samw */ 40135331Samw 40145331Samw sa_resource_t 40155331Samw sa_find_resource(sa_handle_t handle, char *name) 40165331Samw { 40175331Samw sa_group_t group; 40185331Samw sa_group_t zgroup; 40195331Samw sa_resource_t resource = NULL; 40205331Samw 40215331Samw /* 40225331Samw * Iterate over all groups and zfs subgroups and check for 40235331Samw * resource name in them. 40245331Samw */ 40255331Samw for (group = sa_get_group(handle, NULL); group != NULL; 40265331Samw group = sa_get_next_group(group)) { 40275331Samw 40285331Samw if (is_zfs_group(group)) { 40295331Samw for (zgroup = 40305331Samw (sa_group_t)_sa_get_child_node((xmlNodePtr)group, 40315331Samw (xmlChar *)"group"); 40325331Samw zgroup != NULL && resource == NULL; 40335331Samw zgroup = sa_get_next_group(zgroup)) { 40345331Samw resource = find_resource(zgroup, name); 40355331Samw } 40365331Samw } else { 40375331Samw resource = find_resource(group, name); 40385331Samw } 40395331Samw if (resource != NULL) 40405331Samw break; 40415331Samw } 40425331Samw return (resource); 40435331Samw } 40445331Samw 40455331Samw /* 40465331Samw * sa_get_resource(group, resource) 40475331Samw * 40485331Samw * Search all the shares in the specified group for a share with a 40495331Samw * resource name matching the one specified. 40505331Samw * 40515331Samw * In the future, it may be advantageous to allow group to be NULL and 40525331Samw * search all groups but that isn't needed at present. 40535331Samw */ 40545331Samw 40555331Samw sa_resource_t 40565331Samw sa_get_resource(sa_group_t group, char *resource) 40575331Samw { 40585331Samw sa_share_t share = NULL; 40595331Samw sa_resource_t res = NULL; 40605331Samw 40615331Samw if (resource != NULL) { 40625331Samw for (share = sa_get_share(group, NULL); 40635331Samw share != NULL && res == NULL; 40645331Samw share = sa_get_next_share(share)) { 40655331Samw res = sa_get_share_resource(share, resource); 40665331Samw } 40675331Samw } 40685331Samw return (res); 40695331Samw } 40705331Samw 40715331Samw /* 40726270Sdougm * get_protocol_list(optionset, object) 40736270Sdougm * 40746270Sdougm * Get the protocol optionset list for the object and add them as 40756270Sdougm * properties to optionset. 40766270Sdougm */ 40776270Sdougm static int 40786270Sdougm get_protocol_list(sa_optionset_t optionset, void *object) 40796270Sdougm { 40806270Sdougm sa_property_t prop; 40816270Sdougm sa_optionset_t opts; 40826270Sdougm int ret = SA_OK; 40836270Sdougm 40846270Sdougm for (opts = sa_get_optionset(object, NULL); 40856270Sdougm opts != NULL; 40866270Sdougm opts = sa_get_next_optionset(opts)) { 40876270Sdougm char *type; 40886270Sdougm type = sa_get_optionset_attr(opts, "type"); 40896270Sdougm /* 40906270Sdougm * It is possible to have a non-protocol optionset. We 40916270Sdougm * skip any of those found. 40926270Sdougm */ 40936270Sdougm if (type == NULL) 40946270Sdougm continue; 40956270Sdougm prop = sa_create_property(type, "true"); 40966270Sdougm sa_free_attr_string(type); 40976270Sdougm if (prop != NULL) 40986270Sdougm prop = (sa_property_t)xmlAddChild((xmlNodePtr)optionset, 40996270Sdougm (xmlNodePtr)prop); 41006270Sdougm /* If prop is NULL, don't bother continuing */ 41016270Sdougm if (prop == NULL) { 41026270Sdougm ret = SA_NO_MEMORY; 41036270Sdougm break; 41046270Sdougm } 41056270Sdougm } 41066270Sdougm return (ret); 41076270Sdougm } 41086270Sdougm 41096270Sdougm /* 41106270Sdougm * sa_free_protoset(optionset) 41116270Sdougm * 41126270Sdougm * Free the protocol property optionset. 41136270Sdougm */ 41146270Sdougm static void 41156270Sdougm sa_free_protoset(sa_optionset_t optionset) 41166270Sdougm { 41176270Sdougm if (optionset != NULL) { 41186270Sdougm xmlUnlinkNode((xmlNodePtr) optionset); 41196270Sdougm xmlFreeNode((xmlNodePtr) optionset); 41206270Sdougm } 41216270Sdougm } 41226270Sdougm 41236270Sdougm /* 41246270Sdougm * sa_optionset_t sa_get_active_protocols(object) 41256270Sdougm * 41266270Sdougm * Return a list of the protocols that are active for the object. 41276270Sdougm * This is currently an internal helper function, but could be 41286270Sdougm * made visible if there is enough demand for it. 41296270Sdougm * 41306270Sdougm * The function finds the parent group and extracts the protocol 41316270Sdougm * optionsets creating a new optionset with the protocols as properties. 41326270Sdougm * 41336270Sdougm * The caller must free the returned optionset. 41346270Sdougm */ 41356270Sdougm 41366270Sdougm static sa_optionset_t 41376270Sdougm sa_get_active_protocols(void *object) 41386270Sdougm { 41396270Sdougm sa_optionset_t options; 41406270Sdougm sa_share_t share = NULL; 41416270Sdougm sa_group_t group = NULL; 41426270Sdougm sa_resource_t resource = NULL; 41436270Sdougm int ret = SA_OK; 41446270Sdougm 41456270Sdougm if (object == NULL) 41466270Sdougm return (NULL); 41476270Sdougm options = (sa_optionset_t)xmlNewNode(NULL, (xmlChar *)"optionset"); 41486270Sdougm if (options == NULL) 41496270Sdougm return (NULL); 41506270Sdougm 41516270Sdougm /* 41526270Sdougm * Find the objects up the tree that might have protocols 41536270Sdougm * enabled on them. 41546270Sdougm */ 41556270Sdougm if (sa_is_resource(object)) { 41566270Sdougm resource = (sa_resource_t)object; 41576270Sdougm share = sa_get_resource_parent(resource); 41586270Sdougm group = sa_get_parent_group(share); 41596270Sdougm } else if (sa_is_share(object)) { 41606270Sdougm share = (sa_share_t)object; 41616270Sdougm group = sa_get_parent_group(share); 41626270Sdougm } else { 41636270Sdougm group = (sa_group_t)group; 41646270Sdougm } 41656270Sdougm if (resource != NULL) 41666270Sdougm ret = get_protocol_list(options, resource); 41676270Sdougm if (ret == SA_OK && share != NULL) 41686270Sdougm ret = get_protocol_list(options, share); 41696270Sdougm if (ret == SA_OK && group != NULL) 41706270Sdougm ret = get_protocol_list(options, group); 41716270Sdougm 41726270Sdougm /* 41736270Sdougm * If there was an error, we won't have a complete list so 41746270Sdougm * abandon everything. The caller will have to deal with the 41756270Sdougm * issue. 41766270Sdougm */ 41776270Sdougm if (ret != SA_OK) { 41786270Sdougm sa_free_protoset(options); 41796270Sdougm options = NULL; 41806270Sdougm } 41816270Sdougm return (options); 41826270Sdougm } 41836270Sdougm 41846270Sdougm /* 41855331Samw * sa_enable_resource, protocol) 41865331Samw * Disable the specified share to the specified protocol. 41875331Samw * If protocol is NULL, then all protocols. 41885331Samw */ 41895331Samw int 41905331Samw sa_enable_resource(sa_resource_t resource, char *protocol) 41915331Samw { 41925331Samw int ret = SA_OK; 41935331Samw 41945331Samw if (protocol != NULL) { 41955331Samw ret = sa_proto_share_resource(protocol, resource); 41965331Samw } else { 41976270Sdougm sa_optionset_t protoset; 41986270Sdougm sa_property_t prop; 41996270Sdougm char *proto; 42006270Sdougm int err; 42016270Sdougm 42025331Samw /* need to do all protocols */ 42036270Sdougm protoset = sa_get_active_protocols(resource); 42046270Sdougm if (protoset == NULL) 42056270Sdougm return (SA_NO_MEMORY); 42066270Sdougm for (prop = sa_get_property(protoset, NULL); 42076270Sdougm prop != NULL; 42086270Sdougm prop = sa_get_next_property(prop)) { 42096270Sdougm proto = sa_get_property_attr(prop, "type"); 42106270Sdougm if (proto == NULL) { 42116270Sdougm ret = SA_NO_MEMORY; 42126270Sdougm continue; 42135331Samw } 42146270Sdougm err = sa_proto_share_resource(proto, resource); 42156270Sdougm if (err != SA_OK) 42166270Sdougm ret = err; 42176270Sdougm sa_free_attr_string(proto); 42185331Samw } 42196270Sdougm sa_free_protoset(protoset); 42205331Samw } 42215331Samw if (ret == SA_OK) 42225331Samw (void) sa_set_resource_attr(resource, "shared", NULL); 42235331Samw 42245331Samw return (ret); 42255331Samw } 42265331Samw 42275331Samw /* 42285331Samw * sa_disable_resource(resource, protocol) 42295331Samw * 42305331Samw * Disable the specified share for the specified protocol. If 42315331Samw * protocol is NULL, then all protocols. If the underlying 42325331Samw * protocol doesn't implement disable at the resource level, we 42335331Samw * disable at the share level. 42345331Samw */ 42355331Samw int 42365331Samw sa_disable_resource(sa_resource_t resource, char *protocol) 42375331Samw { 42385331Samw int ret = SA_OK; 42395331Samw 42405331Samw if (protocol != NULL) { 42415331Samw ret = sa_proto_unshare_resource(protocol, resource); 42425331Samw if (ret == SA_NOT_IMPLEMENTED) { 42435331Samw sa_share_t parent; 42445331Samw /* 42455331Samw * The protocol doesn't implement unshare 42465331Samw * resource. That implies that resource names are 42475331Samw * simple aliases for this protocol so we need to 42485331Samw * unshare the share. 42495331Samw */ 42505331Samw parent = sa_get_resource_parent(resource); 42515331Samw if (parent != NULL) 42525331Samw ret = sa_disable_share(parent, protocol); 42535331Samw else 42545331Samw ret = SA_CONFIG_ERR; 42555331Samw } 42565331Samw } else { 42576270Sdougm sa_optionset_t protoset; 42586270Sdougm sa_property_t prop; 42596270Sdougm char *proto; 42606270Sdougm int err; 42616270Sdougm 42625331Samw /* need to do all protocols */ 42636270Sdougm protoset = sa_get_active_protocols(resource); 42646270Sdougm if (protoset == NULL) 42656270Sdougm return (SA_NO_MEMORY); 42666270Sdougm for (prop = sa_get_property(protoset, NULL); 42676270Sdougm prop != NULL; 42686270Sdougm prop = sa_get_next_property(prop)) { 42696270Sdougm proto = sa_get_property_attr(prop, "type"); 42706270Sdougm if (proto == NULL) { 42716270Sdougm ret = SA_NO_MEMORY; 42726270Sdougm continue; 42735331Samw } 42746270Sdougm err = sa_proto_unshare_resource(proto, resource); 42756270Sdougm if (err == SA_NOT_SUPPORTED) { 42766270Sdougm sa_share_t parent; 42776270Sdougm parent = sa_get_resource_parent(resource); 42786270Sdougm if (parent != NULL) 42796270Sdougm err = sa_disable_share(parent, proto); 42806270Sdougm else 42816270Sdougm err = SA_CONFIG_ERR; 42826270Sdougm } 42836270Sdougm if (err != SA_OK) 42846270Sdougm ret = err; 42856270Sdougm sa_free_attr_string(proto); 42865331Samw } 42876270Sdougm sa_free_protoset(protoset); 42885331Samw } 42895331Samw if (ret == SA_OK) 42905331Samw (void) sa_set_resource_attr(resource, "shared", NULL); 42915331Samw 42925331Samw return (ret); 42935331Samw } 42945331Samw 42955331Samw /* 42965331Samw * sa_set_resource_description(resource, content) 42975331Samw * 42985331Samw * Set the description of share to content. 42995331Samw */ 43005331Samw 43015331Samw int 43025331Samw sa_set_resource_description(sa_resource_t resource, char *content) 43035331Samw { 43045331Samw xmlNodePtr node; 43055331Samw sa_group_t group; 43065331Samw sa_share_t share; 43075331Samw int ret = SA_OK; 43085331Samw 43095331Samw for (node = ((xmlNodePtr)resource)->children; 43105331Samw node != NULL; 43115331Samw node = node->next) { 43125331Samw if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 43135331Samw break; 43145331Samw } 43155331Samw } 43165331Samw 43175331Samw /* no existing description but want to add */ 43185331Samw if (node == NULL && content != NULL) { 43195331Samw /* add a description */ 43205331Samw node = _sa_set_share_description(resource, content); 43215331Samw } else if (node != NULL && content != NULL) { 43225331Samw /* update a description */ 43235331Samw xmlNodeSetContent(node, (xmlChar *)content); 43245331Samw } else if (node != NULL && content == NULL) { 43255331Samw /* remove an existing description */ 43265331Samw xmlUnlinkNode(node); 43275331Samw xmlFreeNode(node); 43285331Samw } 43295331Samw share = sa_get_resource_parent(resource); 43305331Samw group = sa_get_parent_group(share); 43315331Samw if (group != NULL && sa_is_persistent(share)) { 43325331Samw sa_handle_impl_t impl_handle; 43335331Samw impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 43345331Samw if (impl_handle != NULL) 43355331Samw ret = sa_commit_share(impl_handle->scfhandle, 43365331Samw group, share); 43375331Samw else 43385331Samw ret = SA_SYSTEM_ERR; 43395331Samw } 43405331Samw return (ret); 43415331Samw } 43425331Samw 43435331Samw /* 43445331Samw * sa_get_resource_description(share) 43455331Samw * 43465331Samw * Return the description text for the specified share if it 43475331Samw * exists. NULL if no description exists. 43485331Samw */ 43495331Samw 43505331Samw char * 43515331Samw sa_get_resource_description(sa_resource_t resource) 43525331Samw { 43535331Samw xmlChar *description = NULL; 43545331Samw xmlNodePtr node; 43555331Samw 43565331Samw for (node = ((xmlNodePtr)resource)->children; node != NULL; 43575331Samw node = node->next) { 43585331Samw if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) 43595331Samw break; 43605331Samw } 43615331Samw if (node != NULL) { 43625331Samw description = xmlNodeGetContent(node); 43635331Samw fixproblemchars((char *)description); 43645331Samw } 43655331Samw return ((char *)description); 43665331Samw } 4367