13034Sdougm /* 23034Sdougm * CDDL HEADER START 33034Sdougm * 43034Sdougm * The contents of this file are subject to the terms of the 53034Sdougm * Common Development and Distribution License (the "License"). 63034Sdougm * You may not use this file except in compliance with the License. 73034Sdougm * 83034Sdougm * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 93034Sdougm * or http://www.opensolaris.org/os/licensing. 103034Sdougm * See the License for the specific language governing permissions 113034Sdougm * and limitations under the License. 123034Sdougm * 133034Sdougm * When distributing Covered Code, include this CDDL HEADER in each 143034Sdougm * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 153034Sdougm * If applicable, add the following below this CDDL HEADER, with the 163034Sdougm * fields enclosed by brackets "[]" replaced with your own identifying 173034Sdougm * information: Portions Copyright [yyyy] [name of copyright owner] 183034Sdougm * 193034Sdougm * CDDL HEADER END 203034Sdougm */ 213034Sdougm 223034Sdougm /* 235772Sas200622 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 243034Sdougm * Use is subject to license terms. 253034Sdougm */ 263034Sdougm 273034Sdougm /* 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); 8444327Sdougm (void) proto_plugin_fini(); 8454327Sdougm return (NULL); 8464327Sdougm } 8473663Sdougm /* 8484327Sdougm * since we want to use SMF, initialize an svc handle 8494327Sdougm * and find out what is there. 8503663Sdougm */ 8514327Sdougm handle->scfhandle = sa_scf_init(handle); 8524327Sdougm if (handle->scfhandle != NULL) { 8534327Sdougm /* 8544327Sdougm * Need to lock the extraction of the 8554327Sdougm * configuration if the dfstab file has 8564327Sdougm * changed. Lock everything now and release if 8574327Sdougm * not needed. Use a file that isn't being 8584327Sdougm * manipulated by other parts of the system in 8594327Sdougm * order to not interfere with locking. Using 8604327Sdougm * dfstab doesn't work. 8614327Sdougm */ 8624327Sdougm sablocksigs(&old); 8634327Sdougm lockfd = open(DFS_LOCK_FILE, O_RDWR); 8644327Sdougm if (lockfd >= 0) { 8654327Sdougm extern int errno; 8664327Sdougm errno = 0; 8674327Sdougm (void) lockf(lockfd, F_LOCK, 0); 8684327Sdougm /* 8694327Sdougm * Check whether we are going to need 8704327Sdougm * to merge any dfstab changes. This 8714327Sdougm * is done by comparing the value of 8724327Sdougm * legacy-timestamp with the current 8734327Sdougm * st_ctim of the file. If they are 8744327Sdougm * different, an update is needed and 8754327Sdougm * the file must remain locked until 8764327Sdougm * the merge is done in order to 8774327Sdougm * prevent multiple startups from 8784327Sdougm * changing the SMF repository at the 8794327Sdougm * same time. The first to get the 8804327Sdougm * lock will make any changes before 8814327Sdougm * the others can read the repository. 8824327Sdougm */ 8834327Sdougm prop = scf_simple_prop_get 8844327Sdougm (handle->scfhandle->handle, 8854327Sdougm (const char *)SA_SVC_FMRI_BASE 8864327Sdougm ":default", "operation", 8874327Sdougm "legacy-timestamp"); 8884327Sdougm if (prop != NULL) { 8894327Sdougm char *i64; 8904327Sdougm i64 = GETPROP(prop); 8914327Sdougm if (i64 != NULL) 8924327Sdougm tval = strtoull(i64, 8934327Sdougm NULL, 0); 8944327Sdougm if (CHECKTSTAMP(st, tval)) 8954327Sdougm updatelegacy = B_TRUE; 8964327Sdougm scf_simple_prop_free(prop); 8974327Sdougm } else { 8984327Sdougm /* 8994327Sdougm * We haven't set the 9004327Sdougm * timestamp before so do it. 9014327Sdougm */ 9024327Sdougm updatelegacy = B_TRUE; 9034327Sdougm } 9044327Sdougm } 9054327Sdougm if (updatelegacy == B_FALSE) { 9064327Sdougm /* Don't need the lock anymore */ 9074327Sdougm (void) lockf(lockfd, F_ULOCK, 0); 9084327Sdougm (void) close(lockfd); 9094327Sdougm } 9103973Sdougm 9114327Sdougm /* 9124327Sdougm * It is essential that the document tree and 9134327Sdougm * the internal list of roots to handles be 9144327Sdougm * setup before anything that might try to 9154327Sdougm * create a new object is called. The document 9164327Sdougm * tree is the combination of handle->doc and 9174327Sdougm * handle->tree. This allows searches, 9184327Sdougm * etc. when all you have is an object in the 9194327Sdougm * tree. 9204327Sdougm */ 9214327Sdougm handle->doc = xmlNewDoc((xmlChar *)"1.0"); 9224327Sdougm handle->tree = xmlNewNode(NULL, 9234327Sdougm (xmlChar *)"sharecfg"); 9244327Sdougm if (handle->doc != NULL && 9254327Sdougm handle->tree != NULL) { 9266007Sthurlow (void) xmlDocSetRootElement(handle->doc, 9274327Sdougm handle->tree); 9284327Sdougm err = add_handle_for_root(handle->tree, 9294327Sdougm handle); 9304327Sdougm if (err == SA_OK) 9314327Sdougm err = sa_get_config( 9324327Sdougm handle->scfhandle, 9333973Sdougm handle->tree, handle); 9344327Sdougm } else { 9354327Sdougm if (handle->doc != NULL) 9364327Sdougm xmlFreeDoc(handle->doc); 9374327Sdougm if (handle->tree != NULL) 9384327Sdougm xmlFreeNode(handle->tree); 9394327Sdougm err = SA_NO_MEMORY; 9404327Sdougm } 9413973Sdougm 9424327Sdougm saunblocksigs(&old); 9433910Sdougm 9444327Sdougm if (err != SA_OK) { 9454327Sdougm /* 9464327Sdougm * If we couldn't add the tree handle 9474327Sdougm * to the list, then things are going 9484327Sdougm * to fail badly. Might as well undo 9494327Sdougm * everything now and fail the 9504327Sdougm * sa_init(). 9514327Sdougm */ 9524327Sdougm sa_fini(handle); 9534327Sdougm return (NULL); 9544327Sdougm } 9553910Sdougm 9564327Sdougm if (tval == 0) { 9574327Sdougm /* 9584327Sdougm * first time so make sure 9594327Sdougm * default is setup 9604327Sdougm */ 9614327Sdougm verifydefgroupopts(handle); 9624327Sdougm } 9633973Sdougm 9644524Sdougm if (updatelegacy == B_TRUE) { 9654524Sdougm sablocksigs(&old); 9664524Sdougm getlegacyconfig((sa_handle_t)handle, 9674524Sdougm SA_LEGACY_DFSTAB, &handle->tree); 9684524Sdougm if (stat(SA_LEGACY_DFSTAB, &st) >= 0) 9694524Sdougm set_legacy_timestamp( 9704524Sdougm handle->tree, 9714524Sdougm SA_LEGACY_DFSTAB, 9724524Sdougm TSTAMP(st.st_ctim)); 9734524Sdougm saunblocksigs(&old); 9744524Sdougm /* 9754524Sdougm * Safe to unlock now to allow 9764524Sdougm * others to run 9774524Sdougm */ 9784524Sdougm (void) lockf(lockfd, F_ULOCK, 0); 9794524Sdougm (void) close(lockfd); 9804524Sdougm } 9815951Sdougm /* Get sharetab timestamp */ 9825951Sdougm sa_update_sharetab_ts((sa_handle_t)handle); 9835951Sdougm 9845951Sdougm /* Get lastupdate (transaction) timestamp */ 9855951Sdougm prop = scf_simple_prop_get( 9865951Sdougm handle->scfhandle->handle, 9875951Sdougm (const char *)SA_SVC_FMRI_BASE ":default", 9885951Sdougm "state", "lastupdate"); 9895951Sdougm if (prop != NULL) { 9905951Sdougm char *str; 9915951Sdougm str = 9925951Sdougm scf_simple_prop_next_astring(prop); 9935951Sdougm if (str != NULL) 9945951Sdougm handle->tstrans = 9955951Sdougm strtoull(str, NULL, 0); 9965951Sdougm else 9975951Sdougm handle->tstrans = 0; 9985951Sdougm scf_simple_prop_free(prop); 9995951Sdougm } 10004524Sdougm legacy |= sa_get_zfs_shares(handle, "zfs"); 10014524Sdougm legacy |= gettransients(handle, &handle->tree); 10024327Sdougm } 10034327Sdougm } 10043034Sdougm } 10053910Sdougm return ((sa_handle_t)handle); 10063034Sdougm } 10073034Sdougm 10083034Sdougm /* 10093910Sdougm * sa_fini(handle) 10103034Sdougm * Uninitialize the API structures including the configuration 10113218Sdougm * data structures and ZFS related data. 10123034Sdougm */ 10133034Sdougm 10143034Sdougm void 10153910Sdougm sa_fini(sa_handle_t handle) 10163034Sdougm { 10173910Sdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle; 10183910Sdougm 10193910Sdougm if (impl_handle != NULL) { 10203910Sdougm /* 10213910Sdougm * Free the config trees and any other data structures 10223910Sdougm * used in the handle. 10233910Sdougm */ 10243910Sdougm if (impl_handle->doc != NULL) 10253910Sdougm xmlFreeDoc(impl_handle->doc); 10263910Sdougm 10273910Sdougm /* Remove and free the entry in the global list. */ 10283910Sdougm remove_handle_for_root(impl_handle->tree); 10293910Sdougm 10303910Sdougm /* 10313910Sdougm * If this was the last handle to release, unload the 10326304Sdougm * plugins that were loaded. Use a mutex in case 10336304Sdougm * another thread is reinitializing. 10343910Sdougm */ 10356304Sdougm (void) mutex_lock(&sa_global_lock); 10363910Sdougm if (sa_global_handles == NULL) 10374327Sdougm (void) proto_plugin_fini(); 10386304Sdougm (void) mutex_unlock(&sa_global_lock); 10393910Sdougm 10407010Sgwr sa_scf_fini(impl_handle->scfhandle); 10417010Sgwr sa_zfs_fini(impl_handle); 10427010Sgwr 10437010Sgwr /* Make sure we free the handle */ 10447010Sgwr free(impl_handle); 10457010Sgwr 10463034Sdougm } 10473034Sdougm } 10483034Sdougm 10493034Sdougm /* 10503034Sdougm * sa_get_protocols(char **protocol) 10513034Sdougm * Get array of protocols that are supported 10523034Sdougm * Returns pointer to an allocated and NULL terminated 10533034Sdougm * array of strings. Caller must free. 10543034Sdougm * This really should be determined dynamically. 10553034Sdougm * If there aren't any defined, return -1. 10563034Sdougm * Use free() to return memory. 10573034Sdougm */ 10583034Sdougm 10593034Sdougm int 10603034Sdougm sa_get_protocols(char ***protocols) 10613034Sdougm { 10623034Sdougm int numproto = -1; 10633034Sdougm 10643034Sdougm if (protocols != NULL) { 10654327Sdougm struct sa_proto_plugin *plug; 10664327Sdougm for (numproto = 0, plug = sap_proto_list; plug != NULL; 10674327Sdougm plug = plug->plugin_next) { 10684327Sdougm numproto++; 10694327Sdougm } 10703034Sdougm 10714327Sdougm *protocols = calloc(numproto + 1, sizeof (char *)); 10724327Sdougm if (*protocols != NULL) { 10734327Sdougm int ret = 0; 10744327Sdougm for (plug = sap_proto_list; plug != NULL; 10754327Sdougm plug = plug->plugin_next) { 10764327Sdougm /* faking for now */ 10774327Sdougm (*protocols)[ret++] = 10784327Sdougm plug->plugin_ops->sa_protocol; 10794327Sdougm } 10804327Sdougm } else { 10814327Sdougm numproto = -1; 10823034Sdougm } 10833034Sdougm } 10843034Sdougm return (numproto); 10853034Sdougm } 10863034Sdougm 10873034Sdougm /* 10883034Sdougm * find_group_by_name(node, group) 10893034Sdougm * 10903034Sdougm * search the XML document subtree specified by node to find the group 10913034Sdougm * specified by group. Searching subtree allows subgroups to be 10923034Sdougm * searched for. 10933034Sdougm */ 10943034Sdougm 10953034Sdougm static xmlNodePtr 10963034Sdougm find_group_by_name(xmlNodePtr node, xmlChar *group) 10973034Sdougm { 10983034Sdougm xmlChar *name = NULL; 10993034Sdougm 11003034Sdougm for (node = node->xmlChildrenNode; node != NULL; 11013034Sdougm node = node->next) { 11024327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"group") == 0) { 11034327Sdougm /* if no groupname, return the first found */ 11044327Sdougm if (group == NULL) 11054327Sdougm break; 11064327Sdougm name = xmlGetProp(node, (xmlChar *)"name"); 11074327Sdougm if (name != NULL && xmlStrcmp(name, group) == 0) 11084327Sdougm break; 11094327Sdougm if (name != NULL) { 11104327Sdougm xmlFree(name); 11114327Sdougm name = NULL; 11124327Sdougm } 11133034Sdougm } 11143034Sdougm } 11153034Sdougm if (name != NULL) 11164327Sdougm xmlFree(name); 11173034Sdougm return (node); 11183034Sdougm } 11193034Sdougm 11203034Sdougm /* 11213034Sdougm * sa_get_group(groupname) 11223034Sdougm * Return the "group" specified. If groupname is NULL, 11233034Sdougm * return the first group of the list of groups. 11243034Sdougm */ 11253034Sdougm sa_group_t 11263910Sdougm sa_get_group(sa_handle_t handle, char *groupname) 11273034Sdougm { 11283034Sdougm xmlNodePtr node = NULL; 11293034Sdougm char *subgroup = NULL; 11303034Sdougm char *group = NULL; 11313910Sdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle; 11323034Sdougm 11333910Sdougm if (impl_handle != NULL && impl_handle->tree != NULL) { 11344327Sdougm if (groupname != NULL) { 11354327Sdougm group = strdup(groupname); 11364345Sdougm if (group != NULL) { 11374345Sdougm subgroup = strchr(group, '/'); 11384345Sdougm if (subgroup != NULL) 11394345Sdougm *subgroup++ = '\0'; 11404345Sdougm } 11414327Sdougm } 11424345Sdougm /* 11434345Sdougm * We want to find the, possibly, named group. If 11444345Sdougm * group is not NULL, then lookup the name. If it is 11454345Sdougm * NULL, we only do the find if groupname is also 11464345Sdougm * NULL. This allows lookup of the "first" group in 11474345Sdougm * the internal list. 11484345Sdougm */ 11494345Sdougm if (group != NULL || groupname == NULL) 11504345Sdougm node = find_group_by_name(impl_handle->tree, 11514345Sdougm (xmlChar *)group); 11524345Sdougm 11534327Sdougm /* if a subgroup, find it before returning */ 11544327Sdougm if (subgroup != NULL && node != NULL) 11554327Sdougm node = find_group_by_name(node, (xmlChar *)subgroup); 11563034Sdougm } 11573034Sdougm if (node != NULL && (char *)group != NULL) 11584327Sdougm (void) sa_get_instance(impl_handle->scfhandle, (char *)group); 11593034Sdougm if (group != NULL) 11604327Sdougm free(group); 11613034Sdougm return ((sa_group_t)(node)); 11623034Sdougm } 11633034Sdougm 11643034Sdougm /* 11653034Sdougm * sa_get_next_group(group) 11663034Sdougm * Return the "next" group after the specified group from 11673034Sdougm * the internal group list. NULL if there are no more. 11683034Sdougm */ 11693034Sdougm sa_group_t 11703034Sdougm sa_get_next_group(sa_group_t group) 11713034Sdougm { 11723034Sdougm xmlNodePtr ngroup = NULL; 11733034Sdougm if (group != NULL) { 11744327Sdougm for (ngroup = ((xmlNodePtr)group)->next; ngroup != NULL; 11753034Sdougm ngroup = ngroup->next) { 11764327Sdougm if (xmlStrcmp(ngroup->name, (xmlChar *)"group") == 0) 11774327Sdougm break; 11784327Sdougm } 11793034Sdougm } 11803034Sdougm return ((sa_group_t)ngroup); 11813034Sdougm } 11823034Sdougm 11833034Sdougm /* 11843034Sdougm * sa_get_share(group, sharepath) 11853034Sdougm * Return the share object for the share specified. The share 11863034Sdougm * must be in the specified group. Return NULL if not found. 11873034Sdougm */ 11883034Sdougm sa_share_t 11893034Sdougm sa_get_share(sa_group_t group, char *sharepath) 11903034Sdougm { 11913034Sdougm xmlNodePtr node = NULL; 11923034Sdougm xmlChar *path; 11933034Sdougm 11943034Sdougm /* 11953034Sdougm * For future scalability, this should end up building a cache 11963034Sdougm * since it will get called regularly by the mountd and info 11973034Sdougm * services. 11983034Sdougm */ 11993034Sdougm if (group != NULL) { 12004327Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 12013034Sdougm node = node->next) { 12024327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) { 12034327Sdougm if (sharepath == NULL) { 12044327Sdougm break; 12054327Sdougm } else { 12064327Sdougm /* is it the correct share? */ 12074327Sdougm path = xmlGetProp(node, 12084327Sdougm (xmlChar *)"path"); 12094327Sdougm if (path != NULL && 12104327Sdougm xmlStrcmp(path, 12114327Sdougm (xmlChar *)sharepath) == 0) { 12124327Sdougm xmlFree(path); 12134327Sdougm break; 12144327Sdougm } 12154327Sdougm xmlFree(path); 12164327Sdougm } 12173034Sdougm } 12183034Sdougm } 12193034Sdougm } 12203034Sdougm return ((sa_share_t)node); 12213034Sdougm } 12223034Sdougm 12233034Sdougm /* 12243034Sdougm * sa_get_next_share(share) 12253034Sdougm * Return the next share following the specified share 12263034Sdougm * from the internal list of shares. Returns NULL if there 12273034Sdougm * are no more shares. The list is relative to the same 12283034Sdougm * group. 12293034Sdougm */ 12303034Sdougm sa_share_t 12313034Sdougm sa_get_next_share(sa_share_t share) 12323034Sdougm { 12333034Sdougm xmlNodePtr node = NULL; 12343034Sdougm 12353034Sdougm if (share != NULL) { 12364327Sdougm for (node = ((xmlNodePtr)share)->next; node != NULL; 12373034Sdougm node = node->next) { 12384327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) { 12394327Sdougm break; 12404327Sdougm } 12413034Sdougm } 12423034Sdougm } 12433034Sdougm return ((sa_share_t)node); 12443034Sdougm } 12453034Sdougm 12463034Sdougm /* 12473034Sdougm * _sa_get_child_node(node, type) 12483034Sdougm * 12493034Sdougm * find the child node of the specified node that has "type". This is 12503034Sdougm * used to implement several internal functions. 12513034Sdougm */ 12523034Sdougm 12533034Sdougm static xmlNodePtr 12543034Sdougm _sa_get_child_node(xmlNodePtr node, xmlChar *type) 12553034Sdougm { 12563034Sdougm xmlNodePtr child; 12573034Sdougm for (child = node->xmlChildrenNode; child != NULL; 12583034Sdougm child = child->next) 12594327Sdougm if (xmlStrcmp(child->name, type) == 0) 12604327Sdougm return (child); 12613034Sdougm return ((xmlNodePtr)NULL); 12623034Sdougm } 12633034Sdougm 12643034Sdougm /* 12653034Sdougm * find_share(group, path) 12663034Sdougm * 12673034Sdougm * Search all the shares in the specified group for one that has the 12683034Sdougm * specified path. 12693034Sdougm */ 12703034Sdougm 12713034Sdougm static sa_share_t 12723034Sdougm find_share(sa_group_t group, char *sharepath) 12733034Sdougm { 12743034Sdougm sa_share_t share; 12753034Sdougm char *path; 12763034Sdougm 12773034Sdougm for (share = sa_get_share(group, NULL); share != NULL; 12783034Sdougm share = sa_get_next_share(share)) { 12794327Sdougm path = sa_get_share_attr(share, "path"); 12804327Sdougm if (path != NULL && strcmp(path, sharepath) == 0) { 12814327Sdougm sa_free_attr_string(path); 12824327Sdougm break; 12834327Sdougm } 12844327Sdougm if (path != NULL) 12854327Sdougm sa_free_attr_string(path); 12863034Sdougm } 12873034Sdougm return (share); 12883034Sdougm } 12893034Sdougm 12903034Sdougm /* 12913034Sdougm * sa_get_sub_group(group) 12923034Sdougm * 12933034Sdougm * Get the first sub-group of group. The sa_get_next_group() function 12943034Sdougm * can be used to get the rest. This is currently only used for ZFS 12953034Sdougm * sub-groups but could be used to implement a more general mechanism. 12963034Sdougm */ 12973034Sdougm 12983034Sdougm sa_group_t 12993034Sdougm sa_get_sub_group(sa_group_t group) 13003034Sdougm { 13013034Sdougm return ((sa_group_t)_sa_get_child_node((xmlNodePtr)group, 13024327Sdougm (xmlChar *)"group")); 13033034Sdougm } 13043034Sdougm 13053034Sdougm /* 13063034Sdougm * sa_find_share(sharepath) 13073034Sdougm * Finds a share regardless of group. In the future, this 13083034Sdougm * function should utilize a cache and hash table of some kind. 13093034Sdougm * The current assumption is that a path will only be shared 13103034Sdougm * once. In the future, this may change as implementation of 13113034Sdougm * resource names comes into being. 13123034Sdougm */ 13133034Sdougm sa_share_t 13143910Sdougm sa_find_share(sa_handle_t handle, char *sharepath) 13153034Sdougm { 13163034Sdougm sa_group_t group; 13173034Sdougm sa_group_t zgroup; 13183034Sdougm sa_share_t share = NULL; 13193034Sdougm int done = 0; 13203034Sdougm 13213910Sdougm for (group = sa_get_group(handle, NULL); group != NULL && !done; 13224327Sdougm group = sa_get_next_group(group)) { 13234327Sdougm if (is_zfs_group(group)) { 13244327Sdougm for (zgroup = 13254327Sdougm (sa_group_t)_sa_get_child_node((xmlNodePtr)group, 13264327Sdougm (xmlChar *)"group"); 13274327Sdougm zgroup != NULL; 13284327Sdougm zgroup = sa_get_next_group(zgroup)) { 13294327Sdougm share = find_share(zgroup, sharepath); 13304327Sdougm if (share != NULL) 13314327Sdougm break; 13324327Sdougm } 13334327Sdougm } else { 13344327Sdougm share = find_share(group, sharepath); 13354327Sdougm } 13364327Sdougm if (share != NULL) 13373034Sdougm break; 13383034Sdougm } 13393034Sdougm return (share); 13403034Sdougm } 13413034Sdougm 13423034Sdougm /* 13433348Sdougm * sa_check_path(group, path, strictness) 13443034Sdougm * 13455331Samw * Check that path is a valid path relative to the group. Currently, 13463034Sdougm * we are ignoring the group and checking only the NFS rules. Later, 13473034Sdougm * we may want to use the group to then check against the protocols 13483348Sdougm * enabled on the group. The strictness values mean: 13493348Sdougm * SA_CHECK_NORMAL == only check newpath against shares that are active 13503348Sdougm * SA_CHECK_STRICT == check newpath against both active shares and those 13513348Sdougm * stored in the repository 13523034Sdougm */ 13533034Sdougm 13543034Sdougm int 13553348Sdougm sa_check_path(sa_group_t group, char *path, int strictness) 13563034Sdougm { 13573910Sdougm sa_handle_t handle; 13583910Sdougm 13593910Sdougm handle = sa_find_group_handle(group); 13603910Sdougm return (validpath(handle, path, strictness)); 13613034Sdougm } 13623034Sdougm 13633034Sdougm /* 13645331Samw * mark_excluded_protos(group, share, flags) 13653034Sdougm * 13665331Samw * Walk through all the protocols enabled for the group and check to 13675331Samw * see if the share has any of them should be in the exclude list 13685331Samw * based on the featureset of the protocol. If there are any, add the 13695331Samw * "exclude" property to the share. 13705331Samw */ 13715331Samw static void 13725331Samw mark_excluded_protos(sa_group_t group, xmlNodePtr share, uint64_t flags) 13735331Samw { 13745331Samw sa_optionset_t optionset; 13755331Samw char exclude_list[SA_STRSIZE]; 13765331Samw char *sep = ""; 13775331Samw 13785331Samw exclude_list[0] = '\0'; 13795331Samw for (optionset = sa_get_optionset(group, NULL); 13805331Samw optionset != NULL; 13815331Samw optionset = sa_get_next_optionset(optionset)) { 13825331Samw char *value; 13835331Samw uint64_t features; 13845331Samw value = sa_get_optionset_attr(optionset, "type"); 13855331Samw if (value == NULL) 13865331Samw continue; 13875331Samw features = sa_proto_get_featureset(value); 13885331Samw sa_free_attr_string(value); 13895331Samw if (!(features & flags)) { 13905331Samw (void) strlcat(exclude_list, sep, 13915331Samw sizeof (exclude_list)); 13925331Samw (void) strlcat(exclude_list, value, 13935331Samw sizeof (exclude_list)); 13945331Samw sep = ","; 13955331Samw } 13965331Samw } 13975331Samw if (exclude_list[0] != '\0') 13986007Sthurlow (void) xmlSetProp(share, (xmlChar *)"exclude", 13995331Samw (xmlChar *)exclude_list); 14005331Samw } 14015331Samw 14025331Samw /* 14035331Samw * get_all_features(group) 14045331Samw * 14055331Samw * Walk through all the protocols on the group and collect all 14065331Samw * possible enabled features. This is the OR of all the featuresets. 14075331Samw */ 14085331Samw static uint64_t 14095331Samw get_all_features(sa_group_t group) 14105331Samw { 14115331Samw sa_optionset_t optionset; 14125331Samw uint64_t features = 0; 14135331Samw 14145331Samw for (optionset = sa_get_optionset(group, NULL); 14155331Samw optionset != NULL; 14165331Samw optionset = sa_get_next_optionset(optionset)) { 14175331Samw char *value; 14185331Samw value = sa_get_optionset_attr(optionset, "type"); 14195331Samw if (value == NULL) 14205331Samw continue; 14215331Samw features |= sa_proto_get_featureset(value); 14225331Samw sa_free_attr_string(value); 14235331Samw } 14245331Samw return (features); 14255331Samw } 14265331Samw 14275331Samw 14285331Samw /* 14295331Samw * _sa_add_share(group, sharepath, persist, *error, flags) 14305331Samw * 14315331Samw * Common code for all types of add_share. sa_add_share() is the 14323034Sdougm * public API, we also need to be able to do this when parsing legacy 14333034Sdougm * files and construction of the internal configuration while 14345331Samw * extracting config info from SMF. "flags" indicates if some 14355331Samw * protocols need relaxed rules while other don't. These values are 14365331Samw * the featureset values defined in libshare.h. 14373034Sdougm */ 14383034Sdougm 14393034Sdougm sa_share_t 14405331Samw _sa_add_share(sa_group_t group, char *sharepath, int persist, int *error, 14415331Samw uint64_t flags) 14423034Sdougm { 14433034Sdougm xmlNodePtr node = NULL; 14443034Sdougm int err; 14453034Sdougm 14463034Sdougm err = SA_OK; /* assume success */ 14473034Sdougm 14484327Sdougm node = xmlNewChild((xmlNodePtr)group, NULL, (xmlChar *)"share", NULL); 14495331Samw if (node == NULL) { 14505331Samw if (error != NULL) 14515331Samw *error = SA_NO_MEMORY; 14525331Samw return (node); 14535331Samw } 14545331Samw 14556007Sthurlow (void) xmlSetProp(node, (xmlChar *)"path", (xmlChar *)sharepath); 14566007Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", 14575331Samw persist ? (xmlChar *)"persist" : (xmlChar *)"transient"); 14585331Samw if (flags != 0) 14595331Samw mark_excluded_protos(group, node, flags); 14605331Samw if (persist != SA_SHARE_TRANSIENT) { 14615331Samw /* 14625331Samw * persistent shares come in two flavors: SMF and 14635331Samw * ZFS. Sort this one out based on target group and 14645331Samw * path type. Both NFS and SMB are supported. First, 14655331Samw * check to see if the protocol is enabled on the 14665331Samw * subgroup and then setup the share appropriately. 14675331Samw */ 14685331Samw if (sa_group_is_zfs(group) && 14695331Samw sa_path_is_zfs(sharepath)) { 14705331Samw if (sa_get_optionset(group, "nfs") != NULL) 14714327Sdougm err = sa_zfs_set_sharenfs(group, sharepath, 1); 14725331Samw else if (sa_get_optionset(group, "smb") != NULL) 14735331Samw err = sa_zfs_set_sharesmb(group, sharepath, 1); 14745331Samw } else { 14755331Samw sa_handle_impl_t impl_handle; 14765331Samw impl_handle = 14775331Samw (sa_handle_impl_t)sa_find_group_handle(group); 14785331Samw if (impl_handle != NULL) { 14795331Samw err = sa_commit_share(impl_handle->scfhandle, 14805331Samw group, (sa_share_t)node); 14814327Sdougm } else { 14825331Samw err = SA_SYSTEM_ERR; 14834327Sdougm } 14843034Sdougm } 14853034Sdougm } 14865331Samw if (err == SA_NO_PERMISSION && persist & SA_SHARE_PARSER) 14875331Samw /* called by the dfstab parser so could be a show */ 14885331Samw err = SA_OK; 14895331Samw 14905331Samw if (err != SA_OK) { 14915331Samw /* 14925331Samw * we couldn't commit to the repository so undo 14935331Samw * our internal state to reflect reality. 14945331Samw */ 14955331Samw xmlUnlinkNode(node); 14965331Samw xmlFreeNode(node); 14975331Samw node = NULL; 14985331Samw } 14995331Samw 15003034Sdougm if (error != NULL) 15014327Sdougm *error = err; 15025331Samw 15033034Sdougm return (node); 15043034Sdougm } 15053034Sdougm 15063034Sdougm /* 15073034Sdougm * sa_add_share(group, sharepath, persist, *error) 15083034Sdougm * 15093034Sdougm * Add a new share object to the specified group. The share will 15103034Sdougm * have the specified sharepath and will only be constructed if 15113034Sdougm * it is a valid path to be shared. NULL is returned on error 15123034Sdougm * and a detailed error value will be returned via the error 15133034Sdougm * pointer. 15143034Sdougm */ 15153034Sdougm sa_share_t 15163034Sdougm sa_add_share(sa_group_t group, char *sharepath, int persist, int *error) 15173034Sdougm { 15183034Sdougm xmlNodePtr node = NULL; 15193348Sdougm int strictness = SA_CHECK_NORMAL; 15203910Sdougm sa_handle_t handle; 15215331Samw uint64_t special = 0; 15225331Samw uint64_t features; 15233348Sdougm 15243348Sdougm /* 15253348Sdougm * If the share is to be permanent, use strict checking so a 15263348Sdougm * bad config doesn't get created. Transient shares only need 15273348Sdougm * to check against the currently active 15283348Sdougm * shares. SA_SHARE_PARSER is a modifier used internally to 15293348Sdougm * indicate that we are being called by the dfstab parser and 15303348Sdougm * that we need strict checking in all cases. Normally persist 15313348Sdougm * is in integer value but SA_SHARE_PARSER may be or'd into 15323348Sdougm * it as an override. 15333348Sdougm */ 15343348Sdougm if (persist & SA_SHARE_PARSER || persist == SA_SHARE_PERMANENT) 15354327Sdougm strictness = SA_CHECK_STRICT; 15363034Sdougm 15373910Sdougm handle = sa_find_group_handle(group); 15383910Sdougm 15395331Samw /* 15405331Samw * need to determine if the share is valid. The rules are: 15415331Samw * - The path must not already exist 15425331Samw * - The path must not be a subdir or parent dir of an 15435331Samw * existing path unless at least one protocol allows it. 15445331Samw * The sub/parent check is done in sa_check_path(). 15455331Samw */ 15465331Samw 15475331Samw if (sa_find_share(handle, sharepath) == NULL) { 15485331Samw *error = sa_check_path(group, sharepath, strictness); 15495331Samw features = get_all_features(group); 15505331Samw switch (*error) { 15515331Samw case SA_PATH_IS_SUBDIR: 15525331Samw if (features & SA_FEATURE_ALLOWSUBDIRS) 15535331Samw special |= SA_FEATURE_ALLOWSUBDIRS; 15545331Samw break; 15555331Samw case SA_PATH_IS_PARENTDIR: 15565331Samw if (features & SA_FEATURE_ALLOWPARDIRS) 15575331Samw special |= SA_FEATURE_ALLOWPARDIRS; 15585331Samw break; 15595331Samw } 15605331Samw if (*error == SA_OK || special != SA_FEATURE_NONE) 15615331Samw node = _sa_add_share(group, sharepath, persist, 15625331Samw error, special); 15635331Samw } else { 15645331Samw *error = SA_DUPLICATE_NAME; 15653034Sdougm } 15663034Sdougm 15673034Sdougm return ((sa_share_t)node); 15683034Sdougm } 15693034Sdougm 15703034Sdougm /* 15713034Sdougm * sa_enable_share(share, protocol) 15723034Sdougm * Enable the specified share to the specified protocol. 15733034Sdougm * If protocol is NULL, then all protocols. 15743034Sdougm */ 15753034Sdougm int 15763034Sdougm sa_enable_share(sa_share_t share, char *protocol) 15773034Sdougm { 15783034Sdougm char *sharepath; 15793034Sdougm struct stat st; 15805331Samw int err = SA_OK; 15815331Samw int ret; 15823034Sdougm 15833034Sdougm sharepath = sa_get_share_attr(share, "path"); 15845331Samw if (sharepath == NULL) 15855331Samw return (SA_NO_MEMORY); 15863034Sdougm if (stat(sharepath, &st) < 0) { 15874327Sdougm err = SA_NO_SUCH_PATH; 15883034Sdougm } else { 15894327Sdougm /* tell the server about the share */ 15904327Sdougm if (protocol != NULL) { 15915331Samw if (excluded_protocol(share, protocol)) 15925331Samw goto done; 15935331Samw 15944327Sdougm /* lookup protocol specific handler */ 15954327Sdougm err = sa_proto_share(protocol, share); 15964327Sdougm if (err == SA_OK) 15975331Samw (void) sa_set_share_attr(share, 15985331Samw "shared", "true"); 15994327Sdougm } else { 16005331Samw /* Tell all protocols about the share */ 16015331Samw sa_group_t group; 16025331Samw sa_optionset_t optionset; 16035331Samw 16045331Samw group = sa_get_parent_group(share); 16055331Samw 16065331Samw for (optionset = sa_get_optionset(group, NULL); 16075331Samw optionset != NULL; 16085331Samw optionset = sa_get_next_optionset(optionset)) { 16095331Samw char *proto; 16105331Samw proto = sa_get_optionset_attr(optionset, 16115331Samw "type"); 16125331Samw if (proto != NULL) { 16135331Samw if (!excluded_protocol(share, proto)) { 16145331Samw ret = sa_proto_share(proto, 16155331Samw share); 16165331Samw if (ret != SA_OK) 16175331Samw err = ret; 16185331Samw } 16195331Samw sa_free_attr_string(proto); 16205331Samw } 16215331Samw } 16224327Sdougm (void) sa_set_share_attr(share, "shared", "true"); 16234327Sdougm } 16243034Sdougm } 16255331Samw done: 16263034Sdougm if (sharepath != NULL) 16274327Sdougm sa_free_attr_string(sharepath); 16283034Sdougm return (err); 16293034Sdougm } 16303034Sdougm 16313034Sdougm /* 16323034Sdougm * sa_disable_share(share, protocol) 16335331Samw * Disable the specified share to the specified protocol. If 16345331Samw * protocol is NULL, then all protocols that are enabled for the 16355331Samw * share should be disabled. 16363034Sdougm */ 16373034Sdougm int 16383034Sdougm sa_disable_share(sa_share_t share, char *protocol) 16393034Sdougm { 16403034Sdougm char *path; 16415331Samw int err = SA_OK; 16423034Sdougm int ret = SA_OK; 16433034Sdougm 16443034Sdougm path = sa_get_share_attr(share, "path"); 16453034Sdougm 16463034Sdougm if (protocol != NULL) { 16474543Smarks ret = sa_proto_unshare(share, protocol, path); 16483034Sdougm } else { 16494327Sdougm /* need to do all protocols */ 16505331Samw sa_group_t group; 16515331Samw sa_optionset_t optionset; 16525331Samw 16535331Samw group = sa_get_parent_group(share); 16545331Samw 16555331Samw /* Tell all protocols about the share */ 16565331Samw for (optionset = sa_get_optionset(group, NULL); 16575331Samw optionset != NULL; 16585331Samw optionset = sa_get_next_optionset(optionset)) { 16595331Samw char *proto; 16605331Samw 16615331Samw proto = sa_get_optionset_attr(optionset, "type"); 16625331Samw if (proto != NULL) { 16635331Samw err = sa_proto_unshare(share, proto, path); 16645331Samw if (err != SA_OK) 16655331Samw ret = err; 16665331Samw sa_free_attr_string(proto); 16675331Samw } 16685331Samw } 16693034Sdougm } 16703034Sdougm if (ret == SA_OK) 16713034Sdougm (void) sa_set_share_attr(share, "shared", NULL); 16723034Sdougm if (path != NULL) 16734327Sdougm sa_free_attr_string(path); 16743034Sdougm return (ret); 16753034Sdougm } 16763034Sdougm 16773034Sdougm /* 16783034Sdougm * sa_remove_share(share) 16793034Sdougm * 16803034Sdougm * remove the specified share from its containing group. 16813034Sdougm * Remove from the SMF or ZFS configuration space. 16823034Sdougm */ 16833034Sdougm 16843034Sdougm int 16853034Sdougm sa_remove_share(sa_share_t share) 16863034Sdougm { 16873034Sdougm sa_group_t group; 16883034Sdougm int ret = SA_OK; 16893034Sdougm char *type; 16903034Sdougm int transient = 0; 16913034Sdougm char *groupname; 16923034Sdougm char *zfs; 16933034Sdougm 16943034Sdougm type = sa_get_share_attr(share, "type"); 16953034Sdougm group = sa_get_parent_group(share); 16963034Sdougm zfs = sa_get_group_attr(group, "zfs"); 16973034Sdougm groupname = sa_get_group_attr(group, "name"); 16983034Sdougm if (type != NULL && strcmp(type, "persist") != 0) 16994327Sdougm transient = 1; 17003034Sdougm if (type != NULL) 17014327Sdougm sa_free_attr_string(type); 17023034Sdougm 17033034Sdougm /* remove the node from its group then free the memory */ 17043034Sdougm 17053034Sdougm /* 17063034Sdougm * need to test if "busy" 17073034Sdougm */ 17083034Sdougm /* only do SMF action if permanent */ 17093034Sdougm if (!transient || zfs != NULL) { 17104327Sdougm /* remove from legacy dfstab as well as possible SMF */ 17115331Samw ret = sa_delete_legacy(share, NULL); 17124327Sdougm if (ret == SA_OK) { 17134327Sdougm if (!sa_group_is_zfs(group)) { 17144327Sdougm sa_handle_impl_t impl_handle; 17154327Sdougm impl_handle = (sa_handle_impl_t) 17164327Sdougm sa_find_group_handle(group); 17174327Sdougm if (impl_handle != NULL) { 17184327Sdougm ret = sa_delete_share( 17194327Sdougm impl_handle->scfhandle, group, 17204327Sdougm share); 17214327Sdougm } else { 17224327Sdougm ret = SA_SYSTEM_ERR; 17234327Sdougm } 17244327Sdougm } else { 17254327Sdougm char *sharepath = sa_get_share_attr(share, 17264327Sdougm "path"); 17274327Sdougm if (sharepath != NULL) { 17284327Sdougm ret = sa_zfs_set_sharenfs(group, 17294327Sdougm sharepath, 0); 17304327Sdougm sa_free_attr_string(sharepath); 17314327Sdougm } 17324327Sdougm } 17333034Sdougm } 17343034Sdougm } 17353034Sdougm if (groupname != NULL) 17364327Sdougm sa_free_attr_string(groupname); 17373034Sdougm if (zfs != NULL) 17384327Sdougm sa_free_attr_string(zfs); 17393034Sdougm 17403034Sdougm xmlUnlinkNode((xmlNodePtr)share); 17413034Sdougm xmlFreeNode((xmlNodePtr)share); 17423034Sdougm return (ret); 17433034Sdougm } 17443034Sdougm 17453034Sdougm /* 17463034Sdougm * sa_move_share(group, share) 17473034Sdougm * 17483034Sdougm * move the specified share to the specified group. Update SMF 17493034Sdougm * appropriately. 17503034Sdougm */ 17513034Sdougm 17523034Sdougm int 17533034Sdougm sa_move_share(sa_group_t group, sa_share_t share) 17543034Sdougm { 17553034Sdougm sa_group_t oldgroup; 17563034Sdougm int ret = SA_OK; 17573034Sdougm 17583034Sdougm /* remove the node from its group then free the memory */ 17593034Sdougm 17603034Sdougm oldgroup = sa_get_parent_group(share); 17613034Sdougm if (oldgroup != group) { 17624327Sdougm sa_handle_impl_t impl_handle; 17634327Sdougm xmlUnlinkNode((xmlNodePtr)share); 17643034Sdougm /* 17654327Sdougm * now that the share isn't in its old group, add to 17664327Sdougm * the new one 17673034Sdougm */ 17686007Sthurlow (void) xmlAddChild((xmlNodePtr)group, (xmlNodePtr)share); 17694327Sdougm /* need to deal with SMF */ 17704327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 17714327Sdougm if (impl_handle != NULL) { 17724327Sdougm /* 17734327Sdougm * need to remove from old group first and then add to 17744327Sdougm * new group. Ideally, we would do the other order but 17754327Sdougm * need to avoid having the share in two groups at the 17764327Sdougm * same time. 17774327Sdougm */ 17784327Sdougm ret = sa_delete_share(impl_handle->scfhandle, oldgroup, 17794327Sdougm share); 17804327Sdougm if (ret == SA_OK) 17814327Sdougm ret = sa_commit_share(impl_handle->scfhandle, 17824327Sdougm group, share); 17834327Sdougm } else { 17844327Sdougm ret = SA_SYSTEM_ERR; 17854327Sdougm } 17863034Sdougm } 17873034Sdougm return (ret); 17883034Sdougm } 17893034Sdougm 17903034Sdougm /* 17913034Sdougm * sa_get_parent_group(share) 17923034Sdougm * 17935331Samw * Return the containing group for the share. If a group was actually 17943034Sdougm * passed in, we don't want a parent so return NULL. 17953034Sdougm */ 17963034Sdougm 17973034Sdougm sa_group_t 17983034Sdougm sa_get_parent_group(sa_share_t share) 17993034Sdougm { 18003034Sdougm xmlNodePtr node = NULL; 18013034Sdougm if (share != NULL) { 18024327Sdougm node = ((xmlNodePtr)share)->parent; 18033034Sdougm /* 18043034Sdougm * make sure parent is a group and not sharecfg since 18053034Sdougm * we may be cheating and passing in a group. 18063034Sdougm * Eventually, groups of groups might come into being. 18073034Sdougm */ 18084327Sdougm if (node == NULL || 18094327Sdougm xmlStrcmp(node->name, (xmlChar *)"sharecfg") == 0) 18104327Sdougm node = NULL; 18113034Sdougm } 18123034Sdougm return ((sa_group_t)node); 18133034Sdougm } 18143034Sdougm 18153034Sdougm /* 18163910Sdougm * _sa_create_group(impl_handle, groupname) 18173034Sdougm * 18183034Sdougm * Create a group in the document. The caller will need to deal with 18193034Sdougm * configuration store and activation. 18203034Sdougm */ 18213034Sdougm 18223034Sdougm sa_group_t 18233910Sdougm _sa_create_group(sa_handle_impl_t impl_handle, char *groupname) 18243034Sdougm { 18253034Sdougm xmlNodePtr node = NULL; 18263034Sdougm 18273034Sdougm if (sa_valid_group_name(groupname)) { 18284327Sdougm node = xmlNewChild(impl_handle->tree, NULL, (xmlChar *)"group", 18294327Sdougm NULL); 18304327Sdougm if (node != NULL) { 18316007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 18324327Sdougm (xmlChar *)groupname); 18336007Sthurlow (void) xmlSetProp(node, (xmlChar *)"state", 18344327Sdougm (xmlChar *)"enabled"); 18354327Sdougm } 18363034Sdougm } 18373034Sdougm return ((sa_group_t)node); 18383034Sdougm } 18393034Sdougm 18403034Sdougm /* 18413034Sdougm * _sa_create_zfs_group(group, groupname) 18423034Sdougm * 18433034Sdougm * Create a ZFS subgroup under the specified group. This may 18443034Sdougm * eventually form the basis of general sub-groups, but is currently 18453034Sdougm * restricted to ZFS. 18463034Sdougm */ 18473034Sdougm sa_group_t 18483034Sdougm _sa_create_zfs_group(sa_group_t group, char *groupname) 18493034Sdougm { 18503034Sdougm xmlNodePtr node = NULL; 18513034Sdougm 18524327Sdougm node = xmlNewChild((xmlNodePtr)group, NULL, (xmlChar *)"group", NULL); 18533034Sdougm if (node != NULL) { 18546007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 18556007Sthurlow (xmlChar *)groupname); 18566007Sthurlow (void) xmlSetProp(node, (xmlChar *)"state", 18576007Sthurlow (xmlChar *)"enabled"); 18583034Sdougm } 18593034Sdougm 18603034Sdougm return ((sa_group_t)node); 18613034Sdougm } 18623034Sdougm 18633034Sdougm /* 18643034Sdougm * sa_create_group(groupname, *error) 18653034Sdougm * 18663034Sdougm * Create a new group with groupname. Need to validate that it is a 18673034Sdougm * legal name for SMF and the construct the SMF service instance of 18683034Sdougm * svc:/network/shares/group to implement the group. All necessary 18693034Sdougm * operational properties must be added to the group at this point 18703034Sdougm * (via the SMF transaction model). 18713034Sdougm */ 18723034Sdougm sa_group_t 18733910Sdougm sa_create_group(sa_handle_t handle, char *groupname, int *error) 18743034Sdougm { 18753034Sdougm xmlNodePtr node = NULL; 18763034Sdougm sa_group_t group; 18773034Sdougm int ret; 18784327Sdougm char rbacstr[SA_STRSIZE]; 18793910Sdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle; 18803034Sdougm 18813034Sdougm ret = SA_OK; 18823034Sdougm 18833910Sdougm if (impl_handle == NULL || impl_handle->scfhandle == NULL) { 18844327Sdougm ret = SA_SYSTEM_ERR; 18854327Sdougm goto err; 18863034Sdougm } 18873034Sdougm 18883910Sdougm group = sa_get_group(handle, groupname); 18893034Sdougm if (group != NULL) { 18904327Sdougm ret = SA_DUPLICATE_NAME; 18913034Sdougm } else { 18924327Sdougm if (sa_valid_group_name(groupname)) { 18934327Sdougm node = xmlNewChild(impl_handle->tree, NULL, 18944327Sdougm (xmlChar *)"group", NULL); 18954327Sdougm if (node != NULL) { 18966007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 18974327Sdougm (xmlChar *)groupname); 18984327Sdougm /* default to the group being enabled */ 18996007Sthurlow (void) xmlSetProp(node, (xmlChar *)"state", 19004327Sdougm (xmlChar *)"enabled"); 19014327Sdougm ret = sa_create_instance(impl_handle->scfhandle, 19024327Sdougm groupname); 19034327Sdougm if (ret == SA_OK) { 19044327Sdougm ret = sa_start_transaction( 19054327Sdougm impl_handle->scfhandle, 19064327Sdougm "operation"); 19074327Sdougm } 19084327Sdougm if (ret == SA_OK) { 19094327Sdougm ret = sa_set_property( 19104327Sdougm impl_handle->scfhandle, 19114327Sdougm "state", "enabled"); 19124327Sdougm if (ret == SA_OK) { 19134327Sdougm ret = sa_end_transaction( 19145951Sdougm impl_handle->scfhandle, 19155951Sdougm impl_handle); 19164327Sdougm } else { 19174327Sdougm sa_abort_transaction( 19184327Sdougm impl_handle->scfhandle); 19194327Sdougm } 19204327Sdougm } 19214327Sdougm if (ret == SA_OK) { 19224327Sdougm /* initialize the RBAC strings */ 19234327Sdougm ret = sa_start_transaction( 19244327Sdougm impl_handle->scfhandle, 19254327Sdougm "general"); 19264327Sdougm if (ret == SA_OK) { 19274327Sdougm (void) snprintf(rbacstr, 19284327Sdougm sizeof (rbacstr), "%s.%s", 19294327Sdougm SA_RBAC_MANAGE, groupname); 19304327Sdougm ret = sa_set_property( 19314327Sdougm impl_handle->scfhandle, 19323034Sdougm "action_authorization", 19333034Sdougm rbacstr); 19344327Sdougm } 19354327Sdougm if (ret == SA_OK) { 19364327Sdougm (void) snprintf(rbacstr, 19374327Sdougm sizeof (rbacstr), "%s.%s", 19384327Sdougm SA_RBAC_VALUE, groupname); 19394327Sdougm ret = sa_set_property( 19404327Sdougm impl_handle->scfhandle, 19413034Sdougm "value_authorization", 19423034Sdougm rbacstr); 19434327Sdougm } 19444327Sdougm if (ret == SA_OK) { 19454327Sdougm ret = sa_end_transaction( 19465951Sdougm impl_handle->scfhandle, 19475951Sdougm impl_handle); 19484327Sdougm } else { 19494327Sdougm sa_abort_transaction( 19504327Sdougm impl_handle->scfhandle); 19514327Sdougm } 19524327Sdougm } 19534327Sdougm if (ret != SA_OK) { 19544327Sdougm /* 19554327Sdougm * Couldn't commit the group 19564327Sdougm * so we need to undo 19574327Sdougm * internally. 19584327Sdougm */ 19594327Sdougm xmlUnlinkNode(node); 19604327Sdougm xmlFreeNode(node); 19614327Sdougm node = NULL; 19624327Sdougm } 19633034Sdougm } else { 19644327Sdougm ret = SA_NO_MEMORY; 19653034Sdougm } 19663034Sdougm } else { 19674327Sdougm ret = SA_INVALID_NAME; 19683034Sdougm } 19693034Sdougm } 19703034Sdougm err: 19713034Sdougm if (error != NULL) 19724327Sdougm *error = ret; 19733034Sdougm return ((sa_group_t)node); 19743034Sdougm } 19753034Sdougm 19763034Sdougm /* 19773034Sdougm * sa_remove_group(group) 19783034Sdougm * 19793034Sdougm * Remove the specified group. This deletes from the SMF repository. 19803034Sdougm * All property groups and properties are removed. 19813034Sdougm */ 19823034Sdougm 19833034Sdougm int 19843034Sdougm sa_remove_group(sa_group_t group) 19853034Sdougm { 19863034Sdougm char *name; 19873034Sdougm int ret = SA_OK; 19883910Sdougm sa_handle_impl_t impl_handle; 19893034Sdougm 19903910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 19913910Sdougm if (impl_handle != NULL) { 19924327Sdougm name = sa_get_group_attr(group, "name"); 19934327Sdougm if (name != NULL) { 19944327Sdougm ret = sa_delete_instance(impl_handle->scfhandle, name); 19954327Sdougm sa_free_attr_string(name); 19964327Sdougm } 19974327Sdougm xmlUnlinkNode((xmlNodePtr)group); /* make sure unlinked */ 19984327Sdougm xmlFreeNode((xmlNodePtr)group); /* now it is gone */ 19993910Sdougm } else { 20004327Sdougm ret = SA_SYSTEM_ERR; 20013034Sdougm } 20023034Sdougm return (ret); 20033034Sdougm } 20043034Sdougm 20053034Sdougm /* 20063034Sdougm * sa_update_config() 20073034Sdougm * 20083034Sdougm * Used to update legacy files that need to be updated in bulk 20093034Sdougm * Currently, this is a placeholder and will go away in a future 20103034Sdougm * release. 20113034Sdougm */ 20123034Sdougm 20133034Sdougm int 20143910Sdougm sa_update_config(sa_handle_t handle) 20153034Sdougm { 20163034Sdougm /* 20173034Sdougm * do legacy files first so we can tell when they change. 20183034Sdougm * This will go away when we start updating individual records 20193034Sdougm * rather than the whole file. 20203034Sdougm */ 20213910Sdougm update_legacy_config(handle); 20223034Sdougm return (SA_OK); 20233034Sdougm } 20243034Sdougm 20253034Sdougm /* 20263034Sdougm * get_node_attr(node, tag) 20273034Sdougm * 20285331Samw * Get the specified tag(attribute) if it exists on the node. This is 20293034Sdougm * used internally by a number of attribute oriented functions. 20303034Sdougm */ 20313034Sdougm 20323034Sdougm static char * 20333034Sdougm get_node_attr(void *nodehdl, char *tag) 20343034Sdougm { 20353034Sdougm xmlNodePtr node = (xmlNodePtr)nodehdl; 20363034Sdougm xmlChar *name = NULL; 20373034Sdougm 20384327Sdougm if (node != NULL) 20393034Sdougm name = xmlGetProp(node, (xmlChar *)tag); 20403034Sdougm return ((char *)name); 20413034Sdougm } 20423034Sdougm 20433034Sdougm /* 20443034Sdougm * get_node_attr(node, tag) 20453034Sdougm * 20465331Samw * Set the specified tag(attribute) to the specified value This is 20473034Sdougm * used internally by a number of attribute oriented functions. It 20483034Sdougm * doesn't update the repository, only the internal document state. 20493034Sdougm */ 20503034Sdougm 20513034Sdougm void 20523034Sdougm set_node_attr(void *nodehdl, char *tag, char *value) 20533034Sdougm { 20543034Sdougm xmlNodePtr node = (xmlNodePtr)nodehdl; 20553034Sdougm if (node != NULL && tag != NULL) { 20564327Sdougm if (value != NULL) 20576007Sthurlow (void) xmlSetProp(node, (xmlChar *)tag, 20586007Sthurlow (xmlChar *)value); 20594327Sdougm else 20606007Sthurlow (void) xmlUnsetProp(node, (xmlChar *)tag); 20613034Sdougm } 20623034Sdougm } 20633034Sdougm 20643034Sdougm /* 20653034Sdougm * sa_get_group_attr(group, tag) 20663034Sdougm * 20673034Sdougm * Get the specied attribute, if defined, for the group. 20683034Sdougm */ 20693034Sdougm 20703034Sdougm char * 20713034Sdougm sa_get_group_attr(sa_group_t group, char *tag) 20723034Sdougm { 20733034Sdougm return (get_node_attr((void *)group, tag)); 20743034Sdougm } 20753034Sdougm 20763034Sdougm /* 20773034Sdougm * sa_set_group_attr(group, tag, value) 20783034Sdougm * 20793034Sdougm * set the specified tag/attribute on the group using value as its 20803034Sdougm * value. 20813034Sdougm * 20823034Sdougm * This will result in setting the property in the SMF repository as 20833034Sdougm * well as in the internal document. 20843034Sdougm */ 20853034Sdougm 20863034Sdougm int 20873034Sdougm sa_set_group_attr(sa_group_t group, char *tag, char *value) 20883034Sdougm { 20893034Sdougm int ret; 20903034Sdougm char *groupname; 20913910Sdougm sa_handle_impl_t impl_handle; 20923034Sdougm 20935331Samw /* 20945331Samw * ZFS group/subgroup doesn't need the handle so shortcut. 20955331Samw */ 20965331Samw if (sa_group_is_zfs(group)) { 20975331Samw set_node_attr((void *)group, tag, value); 20985331Samw return (SA_OK); 20995331Samw } 21005331Samw 21013910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 21023910Sdougm if (impl_handle != NULL) { 21034327Sdougm groupname = sa_get_group_attr(group, "name"); 21044327Sdougm ret = sa_get_instance(impl_handle->scfhandle, groupname); 21053910Sdougm if (ret == SA_OK) { 21064327Sdougm set_node_attr((void *)group, tag, value); 21074327Sdougm ret = sa_start_transaction(impl_handle->scfhandle, 21084327Sdougm "operation"); 21094327Sdougm if (ret == SA_OK) { 21104327Sdougm ret = sa_set_property(impl_handle->scfhandle, 21114327Sdougm tag, value); 21124327Sdougm if (ret == SA_OK) 21135885Sdougm ret = sa_end_transaction( 21145951Sdougm impl_handle->scfhandle, 21155951Sdougm impl_handle); 21164327Sdougm else 21174327Sdougm sa_abort_transaction( 21184327Sdougm impl_handle->scfhandle); 21194327Sdougm } 21205885Sdougm if (ret == SA_SYSTEM_ERR) 21215885Sdougm ret = SA_NO_PERMISSION; 21223034Sdougm } 21234327Sdougm if (groupname != NULL) 21244327Sdougm sa_free_attr_string(groupname); 21253910Sdougm } else { 21264327Sdougm ret = SA_SYSTEM_ERR; 21273034Sdougm } 21283034Sdougm return (ret); 21293034Sdougm } 21303034Sdougm 21313034Sdougm /* 21323034Sdougm * sa_get_share_attr(share, tag) 21333034Sdougm * 21343034Sdougm * Return the value of the tag/attribute set on the specified 21353034Sdougm * share. Returns NULL if the tag doesn't exist. 21363034Sdougm */ 21373034Sdougm 21383034Sdougm char * 21393034Sdougm sa_get_share_attr(sa_share_t share, char *tag) 21403034Sdougm { 21413034Sdougm return (get_node_attr((void *)share, tag)); 21423034Sdougm } 21433034Sdougm 21443034Sdougm /* 21453034Sdougm * _sa_set_share_description(share, description) 21463034Sdougm * 21475331Samw * Add a description tag with text contents to the specified share. A 21485331Samw * separate XML tag is used rather than a property. This can also be 21495331Samw * used with resources. 21503034Sdougm */ 21513034Sdougm 21523034Sdougm xmlNodePtr 21535331Samw _sa_set_share_description(void *share, char *content) 21543034Sdougm { 21553034Sdougm xmlNodePtr node; 21564327Sdougm node = xmlNewChild((xmlNodePtr)share, NULL, (xmlChar *)"description", 21574327Sdougm NULL); 21583034Sdougm xmlNodeSetContent(node, (xmlChar *)content); 21593034Sdougm return (node); 21603034Sdougm } 21613034Sdougm 21623034Sdougm /* 21633034Sdougm * sa_set_share_attr(share, tag, value) 21643034Sdougm * 21653034Sdougm * Set the share attribute specified by tag to the specified value. In 21663034Sdougm * the case of "resource", enforce a no duplicates in a group rule. If 21673034Sdougm * the share is not transient, commit the changes to the repository 21683034Sdougm * else just update the share internally. 21693034Sdougm */ 21703034Sdougm 21713034Sdougm int 21723034Sdougm sa_set_share_attr(sa_share_t share, char *tag, char *value) 21733034Sdougm { 21743034Sdougm sa_group_t group; 21753034Sdougm sa_share_t resource; 21763034Sdougm int ret = SA_OK; 21773034Sdougm 21783034Sdougm group = sa_get_parent_group(share); 21793034Sdougm 21803034Sdougm /* 21813034Sdougm * There are some attributes that may have specific 21823034Sdougm * restrictions on them. Initially, only "resource" has 21833034Sdougm * special meaning that needs to be checked. Only one instance 21843034Sdougm * of a resource name may exist within a group. 21853034Sdougm */ 21863034Sdougm 21873034Sdougm if (strcmp(tag, "resource") == 0) { 21884327Sdougm resource = sa_get_resource(group, value); 21894327Sdougm if (resource != share && resource != NULL) 21904327Sdougm ret = SA_DUPLICATE_NAME; 21913034Sdougm } 21923034Sdougm if (ret == SA_OK) { 21934327Sdougm set_node_attr((void *)share, tag, value); 21944327Sdougm if (group != NULL) { 21954327Sdougm char *type; 21964327Sdougm /* we can probably optimize this some */ 21974327Sdougm type = sa_get_share_attr(share, "type"); 21984327Sdougm if (type == NULL || strcmp(type, "transient") != 0) { 21994327Sdougm sa_handle_impl_t impl_handle; 22004327Sdougm impl_handle = 22014327Sdougm (sa_handle_impl_t)sa_find_group_handle( 22024327Sdougm group); 22034327Sdougm if (impl_handle != NULL) { 22044327Sdougm ret = sa_commit_share( 22054327Sdougm impl_handle->scfhandle, group, 22064327Sdougm share); 22074327Sdougm } else { 22084327Sdougm ret = SA_SYSTEM_ERR; 22094327Sdougm } 22104327Sdougm } 22114327Sdougm if (type != NULL) 22124327Sdougm sa_free_attr_string(type); 22133910Sdougm } 22143034Sdougm } 22153034Sdougm return (ret); 22163034Sdougm } 22173034Sdougm 22183034Sdougm /* 22193034Sdougm * sa_get_property_attr(prop, tag) 22203034Sdougm * 22213034Sdougm * Get the value of the specified property attribute. Standard 22223034Sdougm * attributes are "type" and "value". 22233034Sdougm */ 22243034Sdougm 22253034Sdougm char * 22263034Sdougm sa_get_property_attr(sa_property_t prop, char *tag) 22273034Sdougm { 22283034Sdougm return (get_node_attr((void *)prop, tag)); 22293034Sdougm } 22303034Sdougm 22313034Sdougm /* 22323034Sdougm * sa_get_optionset_attr(prop, tag) 22333034Sdougm * 22343034Sdougm * Get the value of the specified property attribute. Standard 22353034Sdougm * attribute is "type". 22363034Sdougm */ 22373034Sdougm 22383034Sdougm char * 22393034Sdougm sa_get_optionset_attr(sa_property_t optionset, char *tag) 22403034Sdougm { 22413034Sdougm return (get_node_attr((void *)optionset, tag)); 22423034Sdougm 22433034Sdougm } 22443034Sdougm 22453034Sdougm /* 22463034Sdougm * sa_set_optionset_attr(optionset, tag, value) 22473034Sdougm * 22483034Sdougm * Set the specified attribute(tag) to the specified value on the 22493034Sdougm * optionset. 22503034Sdougm */ 22513034Sdougm 22523034Sdougm void 22533034Sdougm sa_set_optionset_attr(sa_group_t optionset, char *tag, char *value) 22543034Sdougm { 22553034Sdougm set_node_attr((void *)optionset, tag, value); 22563034Sdougm } 22573034Sdougm 22583034Sdougm /* 22593034Sdougm * sa_free_attr_string(string) 22603034Sdougm * 22613034Sdougm * Free the string that was returned in one of the sa_get_*_attr() 22623034Sdougm * functions. 22633034Sdougm */ 22643034Sdougm 22653034Sdougm void 22663034Sdougm sa_free_attr_string(char *string) 22673034Sdougm { 22683034Sdougm xmlFree((xmlChar *)string); 22693034Sdougm } 22703034Sdougm 22713034Sdougm /* 22723034Sdougm * sa_get_optionset(group, proto) 22733034Sdougm * 22743034Sdougm * Return the optionset, if it exists, that is associated with the 22753034Sdougm * specified protocol. 22763034Sdougm */ 22773034Sdougm 22783034Sdougm sa_optionset_t 22793034Sdougm sa_get_optionset(void *group, char *proto) 22803034Sdougm { 22813034Sdougm xmlNodePtr node; 22823034Sdougm xmlChar *value = NULL; 22833034Sdougm 22843034Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 22854327Sdougm node = node->next) { 22863034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) { 22874327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 22884327Sdougm if (proto != NULL) { 22894327Sdougm if (value != NULL && 22904327Sdougm xmlStrcmp(value, (xmlChar *)proto) == 0) { 22914327Sdougm break; 22924327Sdougm } 22934327Sdougm if (value != NULL) { 22944327Sdougm xmlFree(value); 22954327Sdougm value = NULL; 22964327Sdougm } 22974327Sdougm } else { 22984327Sdougm break; 22993034Sdougm } 23003034Sdougm } 23013034Sdougm } 23023034Sdougm if (value != NULL) 23034327Sdougm xmlFree(value); 23043034Sdougm return ((sa_optionset_t)node); 23053034Sdougm } 23063034Sdougm 23073034Sdougm /* 23083034Sdougm * sa_get_next_optionset(optionset) 23093034Sdougm * 23103034Sdougm * Return the next optionset in the group. NULL if this was the last. 23113034Sdougm */ 23123034Sdougm 23133034Sdougm sa_optionset_t 23143034Sdougm sa_get_next_optionset(sa_optionset_t optionset) 23153034Sdougm { 23163034Sdougm xmlNodePtr node; 23173034Sdougm 23183034Sdougm for (node = ((xmlNodePtr)optionset)->next; node != NULL; 23194327Sdougm node = node->next) { 23203034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) { 23213034Sdougm break; 23223034Sdougm } 23233034Sdougm } 23243034Sdougm return ((sa_optionset_t)node); 23253034Sdougm } 23263034Sdougm 23273034Sdougm /* 23283034Sdougm * sa_get_security(group, sectype, proto) 23293034Sdougm * 23303034Sdougm * Return the security optionset. The internal name is a hold over 23313034Sdougm * from the implementation and will be changed before the API is 23323034Sdougm * finalized. This is really a named optionset that can be negotiated 23333034Sdougm * as a group of properties (like NFS security options). 23343034Sdougm */ 23353034Sdougm 23363034Sdougm sa_security_t 23373034Sdougm sa_get_security(sa_group_t group, char *sectype, char *proto) 23383034Sdougm { 23393034Sdougm xmlNodePtr node; 23403034Sdougm xmlChar *value = NULL; 23413034Sdougm 23423034Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 23434327Sdougm node = node->next) { 23444327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) { 23454327Sdougm if (proto != NULL) { 23464327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 23474327Sdougm if (value == NULL || 23484327Sdougm (value != NULL && 23494327Sdougm xmlStrcmp(value, (xmlChar *)proto) != 0)) { 23504327Sdougm /* it doesn't match so continue */ 23514327Sdougm xmlFree(value); 23524327Sdougm value = NULL; 23534327Sdougm continue; 23544327Sdougm } 23554327Sdougm } 23564327Sdougm if (value != NULL) { 23574327Sdougm xmlFree(value); 23584327Sdougm value = NULL; 23594327Sdougm } 23604327Sdougm /* potential match */ 23614327Sdougm if (sectype != NULL) { 23624327Sdougm value = xmlGetProp(node, (xmlChar *)"sectype"); 23634327Sdougm if (value != NULL && 23644327Sdougm xmlStrcmp(value, (xmlChar *)sectype) == 0) { 23654327Sdougm break; 23664327Sdougm } 23674327Sdougm } else { 23684327Sdougm break; 23694327Sdougm } 23703034Sdougm } 23713034Sdougm if (value != NULL) { 23724327Sdougm xmlFree(value); 23734327Sdougm value = NULL; 23743034Sdougm } 23753034Sdougm } 23763034Sdougm if (value != NULL) 23774327Sdougm xmlFree(value); 23783034Sdougm return ((sa_security_t)node); 23793034Sdougm } 23803034Sdougm 23813034Sdougm /* 23823034Sdougm * sa_get_next_security(security) 23833034Sdougm * 23843034Sdougm * Get the next security optionset if one exists. 23853034Sdougm */ 23863034Sdougm 23873034Sdougm sa_security_t 23883034Sdougm sa_get_next_security(sa_security_t security) 23893034Sdougm { 23903034Sdougm xmlNodePtr node; 23913034Sdougm 23923034Sdougm for (node = ((xmlNodePtr)security)->next; node != NULL; 23934327Sdougm node = node->next) { 23943034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) { 23953034Sdougm break; 23963034Sdougm } 23973034Sdougm } 23983034Sdougm return ((sa_security_t)node); 23993034Sdougm } 24003034Sdougm 24013034Sdougm /* 24023034Sdougm * sa_get_property(optionset, prop) 24033034Sdougm * 24043034Sdougm * Get the property object with the name specified in prop from the 24053034Sdougm * optionset. 24063034Sdougm */ 24073034Sdougm 24083034Sdougm sa_property_t 24093034Sdougm sa_get_property(sa_optionset_t optionset, char *prop) 24103034Sdougm { 24113034Sdougm xmlNodePtr node = (xmlNodePtr)optionset; 24123034Sdougm xmlChar *value = NULL; 24133034Sdougm 24143034Sdougm if (optionset == NULL) 24154327Sdougm return (NULL); 24163034Sdougm 24173034Sdougm for (node = node->children; node != NULL; 24184327Sdougm node = node->next) { 24194327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 24204327Sdougm if (prop == NULL) 24214327Sdougm break; 24224327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 24234327Sdougm if (value != NULL && 24244327Sdougm xmlStrcmp(value, (xmlChar *)prop) == 0) { 24254327Sdougm break; 24264327Sdougm } 24274327Sdougm if (value != NULL) { 24284327Sdougm xmlFree(value); 24294327Sdougm value = NULL; 24304327Sdougm } 24313034Sdougm } 24323034Sdougm } 24333034Sdougm if (value != NULL) 24343034Sdougm xmlFree(value); 24353034Sdougm if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"option") != 0) { 24364327Sdougm /* 24374327Sdougm * avoid a non option node -- it is possible to be a 24384327Sdougm * text node 24394327Sdougm */ 24404327Sdougm node = NULL; 24413034Sdougm } 24423034Sdougm return ((sa_property_t)node); 24433034Sdougm } 24443034Sdougm 24453034Sdougm /* 24463034Sdougm * sa_get_next_property(property) 24473034Sdougm * 24483034Sdougm * Get the next property following the specified property. NULL if 24493034Sdougm * this was the last. 24503034Sdougm */ 24513034Sdougm 24523034Sdougm sa_property_t 24533034Sdougm sa_get_next_property(sa_property_t property) 24543034Sdougm { 24553034Sdougm xmlNodePtr node; 24563034Sdougm 24573034Sdougm for (node = ((xmlNodePtr)property)->next; node != NULL; 24584327Sdougm node = node->next) { 24593034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 24603034Sdougm break; 24613034Sdougm } 24623034Sdougm } 24633034Sdougm return ((sa_property_t)node); 24643034Sdougm } 24653034Sdougm 24663034Sdougm /* 24673034Sdougm * sa_set_share_description(share, content) 24683034Sdougm * 24693034Sdougm * Set the description of share to content. 24703034Sdougm */ 24713034Sdougm 24723034Sdougm int 24733034Sdougm sa_set_share_description(sa_share_t share, char *content) 24743034Sdougm { 24753034Sdougm xmlNodePtr node; 24763034Sdougm sa_group_t group; 24773034Sdougm int ret = SA_OK; 24783034Sdougm 24793034Sdougm for (node = ((xmlNodePtr)share)->children; node != NULL; 24804327Sdougm node = node->next) { 24813034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 24823034Sdougm break; 24833034Sdougm } 24843034Sdougm } 24853034Sdougm /* no existing description but want to add */ 24863034Sdougm if (node == NULL && content != NULL) { 24873034Sdougm /* add a description */ 24884327Sdougm node = _sa_set_share_description(share, content); 24893034Sdougm } else if (node != NULL && content != NULL) { 24903034Sdougm /* update a description */ 24913034Sdougm xmlNodeSetContent(node, (xmlChar *)content); 24923034Sdougm } else if (node != NULL && content == NULL) { 24933034Sdougm /* remove an existing description */ 24943034Sdougm xmlUnlinkNode(node); 24953034Sdougm xmlFreeNode(node); 24963034Sdougm } 24975331Samw group = sa_get_parent_group(share); 24985331Samw if (group != NULL && sa_is_persistent(share)) { 24994327Sdougm sa_handle_impl_t impl_handle; 25004327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 25014327Sdougm if (impl_handle != NULL) { 25024327Sdougm ret = sa_commit_share(impl_handle->scfhandle, group, 25034327Sdougm share); 25044327Sdougm } else { 25054327Sdougm ret = SA_SYSTEM_ERR; 25064327Sdougm } 25073910Sdougm } 25083034Sdougm return (ret); 25093034Sdougm } 25103034Sdougm 25113034Sdougm /* 25123034Sdougm * fixproblemchars(string) 25133034Sdougm * 25143034Sdougm * don't want any newline or tab characters in the text since these 25153034Sdougm * could break display of data and legacy file formats. 25163034Sdougm */ 25173034Sdougm static void 25183034Sdougm fixproblemchars(char *str) 25193034Sdougm { 25203034Sdougm int c; 25213034Sdougm for (c = *str; c != '\0'; c = *++str) { 25224327Sdougm if (c == '\t' || c == '\n') 25234327Sdougm *str = ' '; 25244327Sdougm else if (c == '"') 25254327Sdougm *str = '\''; 25263034Sdougm } 25273034Sdougm } 25283034Sdougm 25293034Sdougm /* 25303034Sdougm * sa_get_share_description(share) 25313034Sdougm * 25323034Sdougm * Return the description text for the specified share if it 25333034Sdougm * exists. NULL if no description exists. 25343034Sdougm */ 25353034Sdougm 25363034Sdougm char * 25373034Sdougm sa_get_share_description(sa_share_t share) 25383034Sdougm { 25393034Sdougm xmlChar *description = NULL; 25403034Sdougm xmlNodePtr node; 25413034Sdougm 25423034Sdougm for (node = ((xmlNodePtr)share)->children; node != NULL; 25434327Sdougm node = node->next) { 25444327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 25454327Sdougm break; 25464327Sdougm } 25473034Sdougm } 25483034Sdougm if (node != NULL) { 25495331Samw description = xmlNodeGetContent(node); 25504327Sdougm fixproblemchars((char *)description); 25513034Sdougm } 25523034Sdougm return ((char *)description); 25533034Sdougm } 25543034Sdougm 25553034Sdougm /* 25563034Sdougm * sa_free(share_description(description) 25573034Sdougm * 25583034Sdougm * Free the description string. 25593034Sdougm */ 25603034Sdougm 25613034Sdougm void 25623034Sdougm sa_free_share_description(char *description) 25633034Sdougm { 25643034Sdougm xmlFree((xmlChar *)description); 25653034Sdougm } 25663034Sdougm 25673034Sdougm /* 25683034Sdougm * sa_create_optionset(group, proto) 25693034Sdougm * 25703034Sdougm * Create an optionset for the specified protocol in the specied 25713034Sdougm * group. This is manifested as a property group within SMF. 25723034Sdougm */ 25733034Sdougm 25743034Sdougm sa_optionset_t 25753034Sdougm sa_create_optionset(sa_group_t group, char *proto) 25763034Sdougm { 25773034Sdougm sa_optionset_t optionset; 25783034Sdougm sa_group_t parent = group; 25795331Samw sa_share_t share = NULL; 25805331Samw int err = SA_OK; 25815331Samw char *id = NULL; 25823034Sdougm 25833034Sdougm optionset = sa_get_optionset(group, proto); 25843034Sdougm if (optionset != NULL) { 25853034Sdougm /* can't have a duplicate protocol */ 25864327Sdougm optionset = NULL; 25873034Sdougm } else { 25885331Samw /* 25895331Samw * Account for resource names being slightly 25905331Samw * different. 25915331Samw */ 25925331Samw if (sa_is_share(group)) { 25935331Samw /* 25945331Samw * Transient shares do not have an "id" so not an 25955331Samw * error to not find one. 25965331Samw */ 25975331Samw id = sa_get_share_attr((sa_share_t)group, "id"); 25985331Samw } else if (sa_is_resource(group)) { 25995331Samw share = sa_get_resource_parent( 26005331Samw (sa_resource_t)group); 26015331Samw id = sa_get_resource_attr(share, "id"); 26025331Samw 26035331Samw /* id can be NULL if the group is transient (ZFS) */ 26045331Samw if (id == NULL && sa_is_persistent(group)) 26055331Samw err = SA_NO_MEMORY; 26065331Samw } 26075331Samw if (err == SA_NO_MEMORY) { 26085331Samw /* 26095331Samw * Couldn't get the id for the share or 26105331Samw * resource. While this could be a 26115331Samw * configuration issue, it is most likely an 26125331Samw * out of memory. In any case, fail the create. 26135331Samw */ 26145331Samw return (NULL); 26155331Samw } 26165331Samw 26174327Sdougm optionset = (sa_optionset_t)xmlNewChild((xmlNodePtr)group, 26184327Sdougm NULL, (xmlChar *)"optionset", NULL); 26193034Sdougm /* 26203034Sdougm * only put to repository if on a group and we were 26213034Sdougm * able to create an optionset. 26223034Sdougm */ 26234327Sdougm if (optionset != NULL) { 26244327Sdougm char oname[SA_STRSIZE]; 26254327Sdougm char *groupname; 26265331Samw 26275331Samw /* 26285331Samw * Need to get parent group in all cases, but also get 26295331Samw * the share if this is a resource. 26305331Samw */ 26315331Samw if (sa_is_share(group)) { 26324327Sdougm parent = sa_get_parent_group((sa_share_t)group); 26335331Samw } else if (sa_is_resource(group)) { 26345331Samw share = sa_get_resource_parent( 26355331Samw (sa_resource_t)group); 26365331Samw parent = sa_get_parent_group(share); 26375331Samw } 26384327Sdougm 26394327Sdougm sa_set_optionset_attr(optionset, "type", proto); 26403034Sdougm 26414327Sdougm (void) sa_optionset_name(optionset, oname, 26424327Sdougm sizeof (oname), id); 26434327Sdougm groupname = sa_get_group_attr(parent, "name"); 26445331Samw if (groupname != NULL && sa_is_persistent(group)) { 26454327Sdougm sa_handle_impl_t impl_handle; 26465331Samw impl_handle = 26475331Samw (sa_handle_impl_t)sa_find_group_handle( 26485331Samw group); 26494327Sdougm assert(impl_handle != NULL); 26504327Sdougm if (impl_handle != NULL) { 26514327Sdougm (void) sa_get_instance( 26525331Samw impl_handle->scfhandle, groupname); 26534327Sdougm (void) sa_create_pgroup( 26544327Sdougm impl_handle->scfhandle, oname); 26554327Sdougm } 26564327Sdougm } 26574327Sdougm if (groupname != NULL) 26584327Sdougm sa_free_attr_string(groupname); 26593034Sdougm } 26603034Sdougm } 26615331Samw 26625331Samw if (id != NULL) 26635331Samw sa_free_attr_string(id); 26643034Sdougm return (optionset); 26653034Sdougm } 26663034Sdougm 26673034Sdougm /* 26683034Sdougm * sa_get_property_parent(property) 26693034Sdougm * 26703034Sdougm * Given a property, return the object it is a property of. This will 26713034Sdougm * be an optionset of some type. 26723034Sdougm */ 26733034Sdougm 26743034Sdougm static sa_optionset_t 26753034Sdougm sa_get_property_parent(sa_property_t property) 26763034Sdougm { 26773034Sdougm xmlNodePtr node = NULL; 26783034Sdougm 26794327Sdougm if (property != NULL) 26804327Sdougm node = ((xmlNodePtr)property)->parent; 26813034Sdougm return ((sa_optionset_t)node); 26823034Sdougm } 26833034Sdougm 26843034Sdougm /* 26853034Sdougm * sa_get_optionset_parent(optionset) 26863034Sdougm * 26873034Sdougm * Return the parent of the specified optionset. This could be a group 26883034Sdougm * or a share. 26893034Sdougm */ 26903034Sdougm 26913034Sdougm static sa_group_t 26923034Sdougm sa_get_optionset_parent(sa_optionset_t optionset) 26933034Sdougm { 26943034Sdougm xmlNodePtr node = NULL; 26953034Sdougm 26964327Sdougm if (optionset != NULL) 26974327Sdougm node = ((xmlNodePtr)optionset)->parent; 26983034Sdougm return ((sa_group_t)node); 26993034Sdougm } 27003034Sdougm 27013034Sdougm /* 27023034Sdougm * zfs_needs_update(share) 27033034Sdougm * 27043034Sdougm * In order to avoid making multiple updates to a ZFS share when 27053034Sdougm * setting properties, the share attribute "changed" will be set to 27065331Samw * true when a property is added or modified. When done adding 27073034Sdougm * properties, we can then detect that an update is needed. We then 27083034Sdougm * clear the state here to detect additional changes. 27093034Sdougm */ 27103034Sdougm 27113034Sdougm static int 27123034Sdougm zfs_needs_update(sa_share_t share) 27133034Sdougm { 27143034Sdougm char *attr; 27153034Sdougm int result = 0; 27163034Sdougm 27173034Sdougm attr = sa_get_share_attr(share, "changed"); 27183034Sdougm if (attr != NULL) { 27194327Sdougm sa_free_attr_string(attr); 27203034Sdougm result = 1; 27213034Sdougm } 27223034Sdougm set_node_attr((void *)share, "changed", NULL); 27233034Sdougm return (result); 27243034Sdougm } 27253034Sdougm 27263034Sdougm /* 27273034Sdougm * zfs_set_update(share) 27283034Sdougm * 27293034Sdougm * Set the changed attribute of the share to true. 27303034Sdougm */ 27313034Sdougm 27323034Sdougm static void 27333034Sdougm zfs_set_update(sa_share_t share) 27343034Sdougm { 27353034Sdougm set_node_attr((void *)share, "changed", "true"); 27363034Sdougm } 27373034Sdougm 27383034Sdougm /* 27393034Sdougm * sa_commit_properties(optionset, clear) 27403034Sdougm * 27413034Sdougm * Check if SMF or ZFS config and either update or abort the pending 27423034Sdougm * changes. 27433034Sdougm */ 27443034Sdougm 27453034Sdougm int 27463034Sdougm sa_commit_properties(sa_optionset_t optionset, int clear) 27473034Sdougm { 27483034Sdougm sa_group_t group; 27493034Sdougm sa_group_t parent; 27503034Sdougm int zfs = 0; 27513034Sdougm int needsupdate = 0; 27523034Sdougm int ret = SA_OK; 27533910Sdougm sa_handle_impl_t impl_handle; 27543034Sdougm 27553034Sdougm group = sa_get_optionset_parent(optionset); 27563034Sdougm if (group != NULL && (sa_is_share(group) || is_zfs_group(group))) { 27574327Sdougm /* only update ZFS if on a share */ 27584327Sdougm parent = sa_get_parent_group(group); 27594327Sdougm zfs++; 27604327Sdougm if (parent != NULL && is_zfs_group(parent)) 27614327Sdougm needsupdate = zfs_needs_update(group); 27624327Sdougm else 27634327Sdougm zfs = 0; 27643034Sdougm } 27653034Sdougm if (zfs) { 27664327Sdougm if (!clear && needsupdate) 27674327Sdougm ret = sa_zfs_update((sa_share_t)group); 27683034Sdougm } else { 27694327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 27704327Sdougm if (impl_handle != NULL) { 27714327Sdougm if (clear) { 27724327Sdougm (void) sa_abort_transaction( 27734327Sdougm impl_handle->scfhandle); 27744327Sdougm } else { 27754327Sdougm ret = sa_end_transaction( 27765951Sdougm impl_handle->scfhandle, impl_handle); 27774327Sdougm } 27784327Sdougm } else { 27794327Sdougm ret = SA_SYSTEM_ERR; 27804327Sdougm } 27813034Sdougm } 27823034Sdougm return (ret); 27833034Sdougm } 27843034Sdougm 27853034Sdougm /* 27863034Sdougm * sa_destroy_optionset(optionset) 27873034Sdougm * 27885331Samw * Remove the optionset from its group. Update the repository to 27893034Sdougm * reflect this change. 27903034Sdougm */ 27913034Sdougm 27923034Sdougm int 27933034Sdougm sa_destroy_optionset(sa_optionset_t optionset) 27943034Sdougm { 27954327Sdougm char name[SA_STRSIZE]; 27963034Sdougm int len; 27973034Sdougm int ret; 27983034Sdougm char *id = NULL; 27993034Sdougm sa_group_t group; 28003034Sdougm int ispersist = 1; 28013034Sdougm 28023034Sdougm /* now delete the prop group */ 28033034Sdougm group = sa_get_optionset_parent(optionset); 28045331Samw if (group != NULL) { 28055331Samw if (sa_is_resource(group)) { 28065331Samw sa_resource_t resource = group; 28075331Samw sa_share_t share = sa_get_resource_parent(resource); 28085331Samw group = sa_get_parent_group(share); 28095331Samw id = sa_get_share_attr(share, "id"); 28105331Samw } else if (sa_is_share(group)) { 28115331Samw id = sa_get_share_attr((sa_share_t)group, "id"); 28125331Samw } 28135331Samw ispersist = sa_is_persistent(group); 28143034Sdougm } 28153034Sdougm if (ispersist) { 28164327Sdougm sa_handle_impl_t impl_handle; 28174327Sdougm len = sa_optionset_name(optionset, name, sizeof (name), id); 28184327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 28194327Sdougm if (impl_handle != NULL) { 28204327Sdougm if (len > 0) { 28214327Sdougm ret = sa_delete_pgroup(impl_handle->scfhandle, 28224327Sdougm name); 28234327Sdougm } 28244327Sdougm } else { 28254327Sdougm ret = SA_SYSTEM_ERR; 28263910Sdougm } 28273034Sdougm } 28283034Sdougm xmlUnlinkNode((xmlNodePtr)optionset); 28293034Sdougm xmlFreeNode((xmlNodePtr)optionset); 28303034Sdougm if (id != NULL) 28314327Sdougm sa_free_attr_string(id); 28323034Sdougm return (ret); 28333034Sdougm } 28343034Sdougm 28353034Sdougm /* private to the implementation */ 28363034Sdougm int 28373034Sdougm _sa_remove_optionset(sa_optionset_t optionset) 28383034Sdougm { 28393034Sdougm int ret = SA_OK; 28403034Sdougm 28413034Sdougm xmlUnlinkNode((xmlNodePtr)optionset); 28423034Sdougm xmlFreeNode((xmlNodePtr)optionset); 28433034Sdougm return (ret); 28443034Sdougm } 28453034Sdougm 28463034Sdougm /* 28473034Sdougm * sa_create_security(group, sectype, proto) 28483034Sdougm * 28493034Sdougm * Create a security optionset (one that has a type name and a 28503034Sdougm * proto). Security is left over from a pure NFS implementation. The 28513034Sdougm * naming will change in the future when the API is released. 28523034Sdougm */ 28533034Sdougm sa_security_t 28543034Sdougm sa_create_security(sa_group_t group, char *sectype, char *proto) 28553034Sdougm { 28563034Sdougm sa_security_t security; 28573034Sdougm char *id = NULL; 28583034Sdougm sa_group_t parent; 28593034Sdougm char *groupname = NULL; 28603034Sdougm 28613034Sdougm if (group != NULL && sa_is_share(group)) { 28624327Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 28634327Sdougm parent = sa_get_parent_group(group); 28644327Sdougm if (parent != NULL) 28654327Sdougm groupname = sa_get_group_attr(parent, "name"); 28663034Sdougm } else if (group != NULL) { 28674327Sdougm groupname = sa_get_group_attr(group, "name"); 28683034Sdougm } 28693034Sdougm 28703034Sdougm security = sa_get_security(group, sectype, proto); 28713034Sdougm if (security != NULL) { 28723034Sdougm /* can't have a duplicate security option */ 28733034Sdougm security = NULL; 28743034Sdougm } else { 28753034Sdougm security = (sa_security_t)xmlNewChild((xmlNodePtr)group, 28764327Sdougm NULL, (xmlChar *)"security", NULL); 28773034Sdougm if (security != NULL) { 28784327Sdougm char oname[SA_STRSIZE]; 28793034Sdougm sa_set_security_attr(security, "type", proto); 28803034Sdougm 28813034Sdougm sa_set_security_attr(security, "sectype", sectype); 28823034Sdougm (void) sa_security_name(security, oname, 28834327Sdougm sizeof (oname), id); 28845331Samw if (groupname != NULL && sa_is_persistent(group)) { 28854327Sdougm sa_handle_impl_t impl_handle; 28864327Sdougm impl_handle = 28874327Sdougm (sa_handle_impl_t)sa_find_group_handle( 28884327Sdougm group); 28894327Sdougm if (impl_handle != NULL) { 28904327Sdougm (void) sa_get_instance( 28914327Sdougm impl_handle->scfhandle, groupname); 28924327Sdougm (void) sa_create_pgroup( 28934327Sdougm impl_handle->scfhandle, oname); 28944327Sdougm } 28953034Sdougm } 28963034Sdougm } 28973034Sdougm } 28983034Sdougm if (groupname != NULL) 28994327Sdougm sa_free_attr_string(groupname); 29003034Sdougm return (security); 29013034Sdougm } 29023034Sdougm 29033034Sdougm /* 29043034Sdougm * sa_destroy_security(security) 29053034Sdougm * 29063034Sdougm * Remove the specified optionset from the document and the 29073034Sdougm * configuration. 29083034Sdougm */ 29093034Sdougm 29103034Sdougm int 29113034Sdougm sa_destroy_security(sa_security_t security) 29123034Sdougm { 29134327Sdougm char name[SA_STRSIZE]; 29143034Sdougm int len; 29153034Sdougm int ret = SA_OK; 29163034Sdougm char *id = NULL; 29173034Sdougm sa_group_t group; 29183034Sdougm int iszfs = 0; 29193034Sdougm int ispersist = 1; 29203034Sdougm 29213034Sdougm group = sa_get_optionset_parent(security); 29223034Sdougm 29233034Sdougm if (group != NULL) 29244327Sdougm iszfs = sa_group_is_zfs(group); 29253034Sdougm 29263034Sdougm if (group != NULL && !iszfs) { 29274327Sdougm if (sa_is_share(group)) 29285331Samw ispersist = sa_is_persistent(group); 29294327Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 29303034Sdougm } 29313034Sdougm if (ispersist) { 29324327Sdougm len = sa_security_name(security, name, sizeof (name), id); 29334327Sdougm if (!iszfs && len > 0) { 29344327Sdougm sa_handle_impl_t impl_handle; 29354327Sdougm impl_handle = 29364327Sdougm (sa_handle_impl_t)sa_find_group_handle(group); 29374327Sdougm if (impl_handle != NULL) { 29384327Sdougm ret = sa_delete_pgroup(impl_handle->scfhandle, 29394327Sdougm name); 29404327Sdougm } else { 29414327Sdougm ret = SA_SYSTEM_ERR; 29424327Sdougm } 29433910Sdougm } 29443034Sdougm } 29453034Sdougm xmlUnlinkNode((xmlNodePtr)security); 29463034Sdougm xmlFreeNode((xmlNodePtr)security); 29474327Sdougm if (iszfs) 29484327Sdougm ret = sa_zfs_update(group); 29493034Sdougm if (id != NULL) 29504327Sdougm sa_free_attr_string(id); 29513034Sdougm return (ret); 29523034Sdougm } 29533034Sdougm 29543034Sdougm /* 29553034Sdougm * sa_get_security_attr(optionset, tag) 29563034Sdougm * 29573034Sdougm * Return the specified attribute value from the optionset. 29583034Sdougm */ 29593034Sdougm 29603034Sdougm char * 29613034Sdougm sa_get_security_attr(sa_property_t optionset, char *tag) 29623034Sdougm { 29633034Sdougm return (get_node_attr((void *)optionset, tag)); 29643034Sdougm 29653034Sdougm } 29663034Sdougm 29673034Sdougm /* 29683034Sdougm * sa_set_security_attr(optionset, tag, value) 29693034Sdougm * 29703034Sdougm * Set the optioset attribute specied by tag to the specified value. 29713034Sdougm */ 29723034Sdougm 29733034Sdougm void 29743034Sdougm sa_set_security_attr(sa_group_t optionset, char *tag, char *value) 29753034Sdougm { 29763034Sdougm set_node_attr((void *)optionset, tag, value); 29773034Sdougm } 29783034Sdougm 29793034Sdougm /* 29803034Sdougm * is_nodetype(node, type) 29813034Sdougm * 29823034Sdougm * Check to see if node is of the type specified. 29833034Sdougm */ 29843034Sdougm 29853034Sdougm static int 29863034Sdougm is_nodetype(void *node, char *type) 29873034Sdougm { 29883034Sdougm return (strcmp((char *)((xmlNodePtr)node)->name, type) == 0); 29893034Sdougm } 29903034Sdougm 29914327Sdougm /* 29924327Sdougm * add_or_update() 29934327Sdougm * 29944327Sdougm * Add or update a property. Pulled out of sa_set_prop_by_prop for 29954327Sdougm * readability. 29964327Sdougm */ 29974327Sdougm static int 29984327Sdougm add_or_update(scfutilhandle_t *scf_handle, int type, scf_value_t *value, 29994327Sdougm scf_transaction_entry_t *entry, char *name, char *valstr) 30004327Sdougm { 30014327Sdougm int ret = SA_SYSTEM_ERR; 30024327Sdougm 30034327Sdougm if (value != NULL) { 30044327Sdougm if (type == SA_PROP_OP_ADD) 30054327Sdougm ret = scf_transaction_property_new(scf_handle->trans, 30064327Sdougm entry, name, SCF_TYPE_ASTRING); 30074327Sdougm else 30084327Sdougm ret = scf_transaction_property_change(scf_handle->trans, 30094327Sdougm entry, name, SCF_TYPE_ASTRING); 30104327Sdougm if (ret == 0) { 30114327Sdougm ret = scf_value_set_astring(value, valstr); 30124327Sdougm if (ret == 0) 30134327Sdougm ret = scf_entry_add_value(entry, value); 30144327Sdougm if (ret == 0) 30154327Sdougm return (ret); 30164327Sdougm scf_value_destroy(value); 30174327Sdougm } else { 30184327Sdougm scf_entry_destroy(entry); 30194327Sdougm } 30204327Sdougm } 30214327Sdougm return (SA_SYSTEM_ERR); 30224327Sdougm } 30234327Sdougm 30243034Sdougm /* 30253034Sdougm * sa_set_prop_by_prop(optionset, group, prop, type) 30263034Sdougm * 30273034Sdougm * Add/remove/update the specified property prop into the optionset or 30283034Sdougm * share. If a share, sort out which property group based on GUID. In 30293034Sdougm * all cases, the appropriate transaction is set (or ZFS share is 30303034Sdougm * marked as needing an update) 30313034Sdougm */ 30323034Sdougm 30333034Sdougm static int 30343034Sdougm sa_set_prop_by_prop(sa_optionset_t optionset, sa_group_t group, 30353034Sdougm sa_property_t prop, int type) 30363034Sdougm { 30373034Sdougm char *name; 30383034Sdougm char *valstr; 30393034Sdougm int ret = SA_OK; 30403034Sdougm scf_transaction_entry_t *entry; 30413034Sdougm scf_value_t *value; 30423034Sdougm int opttype; /* 1 == optionset, 0 == security */ 30433034Sdougm char *id = NULL; 30443034Sdougm int iszfs = 0; 30453034Sdougm sa_group_t parent = NULL; 30465331Samw sa_share_t share = NULL; 30473910Sdougm sa_handle_impl_t impl_handle; 30483910Sdougm scfutilhandle_t *scf_handle; 30493034Sdougm 30505331Samw if (!sa_is_persistent(group)) { 30513034Sdougm /* 30523034Sdougm * if the group/share is not persistent we don't need 30533034Sdougm * to do anything here 30543034Sdougm */ 30554327Sdougm return (SA_OK); 30563034Sdougm } 30573910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 30584327Sdougm if (impl_handle == NULL || impl_handle->scfhandle == NULL) 30594327Sdougm return (SA_SYSTEM_ERR); 30603910Sdougm scf_handle = impl_handle->scfhandle; 30613034Sdougm name = sa_get_property_attr(prop, "type"); 30623034Sdougm valstr = sa_get_property_attr(prop, "value"); 30633034Sdougm entry = scf_entry_create(scf_handle->handle); 30643034Sdougm opttype = is_nodetype((void *)optionset, "optionset"); 30653034Sdougm 30665331Samw /* 30675331Samw * Check for share vs. resource since they need slightly 30685331Samw * different treatment given the hierarchy. 30695331Samw */ 30703034Sdougm if (valstr != NULL && entry != NULL) { 30714327Sdougm if (sa_is_share(group)) { 30724327Sdougm parent = sa_get_parent_group(group); 30735331Samw share = (sa_share_t)group; 30744327Sdougm if (parent != NULL) 30754327Sdougm iszfs = is_zfs_group(parent); 30765331Samw } else if (sa_is_resource(group)) { 30775331Samw share = sa_get_parent_group(group); 30785331Samw if (share != NULL) 30795331Samw parent = sa_get_parent_group(share); 30804327Sdougm } else { 30814327Sdougm iszfs = is_zfs_group(group); 30823034Sdougm } 30834327Sdougm if (!iszfs) { 30844327Sdougm if (scf_handle->trans == NULL) { 30854327Sdougm char oname[SA_STRSIZE]; 30864327Sdougm char *groupname = NULL; 30875331Samw if (share != NULL) { 30885331Samw if (parent != NULL) 30894327Sdougm groupname = 30904327Sdougm sa_get_group_attr(parent, 30914327Sdougm "name"); 30925331Samw id = sa_get_share_attr( 30935331Samw (sa_share_t)share, "id"); 30944327Sdougm } else { 30954327Sdougm groupname = sa_get_group_attr(group, 30964327Sdougm "name"); 30974327Sdougm } 30984327Sdougm if (groupname != NULL) { 30994327Sdougm ret = sa_get_instance(scf_handle, 31004327Sdougm groupname); 31014327Sdougm sa_free_attr_string(groupname); 31024327Sdougm } 31034327Sdougm if (opttype) 31044327Sdougm (void) sa_optionset_name(optionset, 31054327Sdougm oname, sizeof (oname), id); 31064327Sdougm else 31074327Sdougm (void) sa_security_name(optionset, 31084327Sdougm oname, sizeof (oname), id); 31094327Sdougm ret = sa_start_transaction(scf_handle, oname); 31103910Sdougm } 31114327Sdougm if (ret == SA_OK) { 31124327Sdougm switch (type) { 31134327Sdougm case SA_PROP_OP_REMOVE: 31144327Sdougm ret = scf_transaction_property_delete( 31154327Sdougm scf_handle->trans, entry, name); 31164327Sdougm break; 31174327Sdougm case SA_PROP_OP_ADD: 31184327Sdougm case SA_PROP_OP_UPDATE: 31194327Sdougm value = scf_value_create( 31204327Sdougm scf_handle->handle); 31214327Sdougm ret = add_or_update(scf_handle, type, 31224327Sdougm value, entry, name, valstr); 31234327Sdougm break; 31243034Sdougm } 31253034Sdougm } 31264327Sdougm } else { 31274327Sdougm /* 31284327Sdougm * ZFS update. The calling function would have updated 31294327Sdougm * the internal XML structure. Just need to flag it as 31304327Sdougm * changed for ZFS. 31314327Sdougm */ 31324327Sdougm zfs_set_update((sa_share_t)group); 31334327Sdougm } 31343034Sdougm } 31353034Sdougm 31363034Sdougm if (name != NULL) 31374327Sdougm sa_free_attr_string(name); 31383034Sdougm if (valstr != NULL) 31394327Sdougm sa_free_attr_string(valstr); 31403034Sdougm else if (entry != NULL) 31414327Sdougm scf_entry_destroy(entry); 31423034Sdougm 31433034Sdougm if (ret == -1) 31444327Sdougm ret = SA_SYSTEM_ERR; 31453034Sdougm 31463034Sdougm return (ret); 31473034Sdougm } 31483034Sdougm 31493034Sdougm /* 31506007Sthurlow * sa_create_section(name, value) 31516007Sthurlow * 31526007Sthurlow * Create a new section with the specified name and extra data. 31536007Sthurlow */ 31546007Sthurlow 31556007Sthurlow sa_property_t 31566007Sthurlow sa_create_section(char *name, char *extra) 31576007Sthurlow { 31586007Sthurlow xmlNodePtr node; 31596007Sthurlow 31606007Sthurlow node = xmlNewNode(NULL, (xmlChar *)"section"); 31616007Sthurlow if (node != NULL) { 31626007Sthurlow if (name != NULL) 31636007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 31646007Sthurlow (xmlChar *)name); 31656007Sthurlow if (extra != NULL) 31666007Sthurlow (void) xmlSetProp(node, (xmlChar *)"extra", 31676007Sthurlow (xmlChar *)extra); 31686007Sthurlow } 31696007Sthurlow return ((sa_property_t)node); 31706007Sthurlow } 31716007Sthurlow 31726007Sthurlow void 31736007Sthurlow sa_set_section_attr(sa_property_t sect, char *name, char *value) 31746007Sthurlow { 31756007Sthurlow (void) xmlSetProp(sect, (xmlChar *)name, (xmlChar *)value); 31766007Sthurlow } 31776007Sthurlow 31786007Sthurlow /* 31796007Sthurlow * sa_create_property(section, name, value) 31803034Sdougm * 31813034Sdougm * Create a new property with the specified name and value. 31823034Sdougm */ 31833034Sdougm 31843034Sdougm sa_property_t 31853034Sdougm sa_create_property(char *name, char *value) 31863034Sdougm { 31873034Sdougm xmlNodePtr node; 31883034Sdougm 31893034Sdougm node = xmlNewNode(NULL, (xmlChar *)"option"); 31903034Sdougm if (node != NULL) { 31916007Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", (xmlChar *)name); 31926007Sthurlow (void) xmlSetProp(node, (xmlChar *)"value", (xmlChar *)value); 31933034Sdougm } 31943034Sdougm return ((sa_property_t)node); 31953034Sdougm } 31963034Sdougm 31973034Sdougm /* 31983034Sdougm * sa_add_property(object, property) 31993034Sdougm * 32003034Sdougm * Add the specified property to the object. Issue the appropriate 32013034Sdougm * transaction or mark a ZFS object as needing an update. 32023034Sdougm */ 32033034Sdougm 32043034Sdougm int 32053034Sdougm sa_add_property(void *object, sa_property_t property) 32063034Sdougm { 32073034Sdougm int ret = SA_OK; 32083034Sdougm sa_group_t parent; 32093034Sdougm sa_group_t group; 32103034Sdougm char *proto; 32116214Sdougm 32123034Sdougm if (property != NULL) { 32136271Sdougm sa_handle_t handle; 32146214Sdougm handle = sa_find_group_handle((sa_group_t)object); 32156271Sdougm /* It is legitimate to not find a handle */ 32166214Sdougm proto = sa_get_optionset_attr(object, "type"); 32176214Sdougm if ((ret = sa_valid_property(handle, object, proto, 32186214Sdougm property)) == SA_OK) { 32194327Sdougm property = (sa_property_t)xmlAddChild( 32204327Sdougm (xmlNodePtr)object, (xmlNodePtr)property); 32214327Sdougm } else { 32224327Sdougm if (proto != NULL) 32234327Sdougm sa_free_attr_string(proto); 32244327Sdougm return (ret); 32254327Sdougm } 32266214Sdougm if (proto != NULL) 32276214Sdougm sa_free_attr_string(proto); 32283034Sdougm } 32293034Sdougm 32303034Sdougm 32313034Sdougm parent = sa_get_parent_group(object); 32325331Samw if (!sa_is_persistent(parent)) 32334327Sdougm return (ret); 32345331Samw 32355331Samw if (sa_is_resource(parent)) { 32365331Samw /* 32375331Samw * Resources are children of share. Need to go up two 32385331Samw * levels to find the group but the parent needs to be 32395331Samw * the share at this point in order to get the "id". 32405331Samw */ 32415331Samw parent = sa_get_parent_group(parent); 32425331Samw group = sa_get_parent_group(parent); 32435331Samw } else if (sa_is_share(parent)) { 32445331Samw group = sa_get_parent_group(parent); 32455331Samw } else { 32465331Samw group = parent; 32473034Sdougm } 32483034Sdougm 32494327Sdougm if (property == NULL) { 32504327Sdougm ret = SA_NO_MEMORY; 32514327Sdougm } else { 32524327Sdougm char oname[SA_STRSIZE]; 32533034Sdougm 32544327Sdougm if (!is_zfs_group(group)) { 32554327Sdougm char *id = NULL; 32564327Sdougm sa_handle_impl_t impl_handle; 32574327Sdougm scfutilhandle_t *scf_handle; 32583910Sdougm 32594327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle( 32604327Sdougm group); 32614327Sdougm if (impl_handle == NULL || 32624327Sdougm impl_handle->scfhandle == NULL) 32634327Sdougm ret = SA_SYSTEM_ERR; 32644327Sdougm if (ret == SA_OK) { 32654327Sdougm scf_handle = impl_handle->scfhandle; 32664327Sdougm if (sa_is_share((sa_group_t)parent)) { 32674327Sdougm id = sa_get_share_attr( 32684327Sdougm (sa_share_t)parent, "id"); 32694327Sdougm } 32704327Sdougm if (scf_handle->trans == NULL) { 32714327Sdougm if (is_nodetype(object, "optionset")) { 32724327Sdougm (void) sa_optionset_name( 32734327Sdougm (sa_optionset_t)object, 32744327Sdougm oname, sizeof (oname), id); 32754327Sdougm } else { 32764327Sdougm (void) sa_security_name( 32774327Sdougm (sa_optionset_t)object, 32784327Sdougm oname, sizeof (oname), id); 32794327Sdougm } 32804327Sdougm ret = sa_start_transaction(scf_handle, 32814327Sdougm oname); 32824327Sdougm } 32834327Sdougm if (ret == SA_OK) { 32844327Sdougm char *name; 32854327Sdougm char *value; 32864327Sdougm name = sa_get_property_attr(property, 32874327Sdougm "type"); 32884327Sdougm value = sa_get_property_attr(property, 32894327Sdougm "value"); 32904327Sdougm if (name != NULL && value != NULL) { 32914327Sdougm if (scf_handle->scf_state == 32924327Sdougm SCH_STATE_INIT) { 32934327Sdougm ret = sa_set_property( 32944327Sdougm scf_handle, name, 32954327Sdougm value); 32964327Sdougm } 32974327Sdougm } else { 32984327Sdougm ret = SA_CONFIG_ERR; 32994327Sdougm } 33004327Sdougm if (name != NULL) 33014327Sdougm sa_free_attr_string( 33024327Sdougm name); 33034327Sdougm if (value != NULL) 33044327Sdougm sa_free_attr_string(value); 33054327Sdougm } 33064327Sdougm if (id != NULL) 33074327Sdougm sa_free_attr_string(id); 33084327Sdougm } 33094327Sdougm } else { 33104327Sdougm /* 33114327Sdougm * ZFS is a special case. We do want 33124327Sdougm * to allow editing property/security 33134327Sdougm * lists since we can have a better 33144327Sdougm * syntax and we also want to keep 33154327Sdougm * things consistent when possible. 33164327Sdougm * 33174327Sdougm * Right now, we defer until the 33184327Sdougm * sa_commit_properties so we can get 33194327Sdougm * them all at once. We do need to 33204327Sdougm * mark the share as "changed" 33214327Sdougm */ 33224327Sdougm zfs_set_update((sa_share_t)parent); 33233034Sdougm } 33243034Sdougm } 33253034Sdougm return (ret); 33263034Sdougm } 33273034Sdougm 33283034Sdougm /* 33293034Sdougm * sa_remove_property(property) 33303034Sdougm * 33313034Sdougm * Remove the specied property from its containing object. Update the 33323034Sdougm * repository as appropriate. 33333034Sdougm */ 33343034Sdougm 33353034Sdougm int 33363034Sdougm sa_remove_property(sa_property_t property) 33373034Sdougm { 33383034Sdougm int ret = SA_OK; 33393034Sdougm 33403034Sdougm if (property != NULL) { 33413034Sdougm sa_optionset_t optionset; 33423034Sdougm sa_group_t group; 33433034Sdougm optionset = sa_get_property_parent(property); 33443034Sdougm if (optionset != NULL) { 33454327Sdougm group = sa_get_optionset_parent(optionset); 33464327Sdougm if (group != NULL) { 33474327Sdougm ret = sa_set_prop_by_prop(optionset, group, 33484327Sdougm property, SA_PROP_OP_REMOVE); 33494327Sdougm } 33503034Sdougm } 33513034Sdougm xmlUnlinkNode((xmlNodePtr)property); 33523034Sdougm xmlFreeNode((xmlNodePtr)property); 33533034Sdougm } else { 33544327Sdougm ret = SA_NO_SUCH_PROP; 33553034Sdougm } 33563034Sdougm return (ret); 33573034Sdougm } 33583034Sdougm 33593034Sdougm /* 33603034Sdougm * sa_update_property(property, value) 33613034Sdougm * 33623034Sdougm * Update the specified property to the new value. If value is NULL, 33633034Sdougm * we currently treat this as a remove. 33643034Sdougm */ 33653034Sdougm 33663034Sdougm int 33673034Sdougm sa_update_property(sa_property_t property, char *value) 33683034Sdougm { 33693034Sdougm int ret = SA_OK; 33703034Sdougm if (value == NULL) { 33713034Sdougm return (sa_remove_property(property)); 33723034Sdougm } else { 33733034Sdougm sa_optionset_t optionset; 33743034Sdougm sa_group_t group; 33753034Sdougm set_node_attr((void *)property, "value", value); 33763034Sdougm optionset = sa_get_property_parent(property); 33773034Sdougm if (optionset != NULL) { 33784327Sdougm group = sa_get_optionset_parent(optionset); 33794327Sdougm if (group != NULL) { 33804327Sdougm ret = sa_set_prop_by_prop(optionset, group, 33814327Sdougm property, SA_PROP_OP_UPDATE); 33824327Sdougm } 33833034Sdougm } else { 33844327Sdougm ret = SA_NO_SUCH_PROP; 33853034Sdougm } 33863034Sdougm } 33873034Sdougm return (ret); 33883034Sdougm } 33893034Sdougm 33903034Sdougm /* 33916007Sthurlow * sa_get_protocol_section(propset, prop) 33926007Sthurlow * 33936007Sthurlow * Get the specified protocol specific section. These are global to 33946007Sthurlow * the protocol and not specific to a group or share. 33956007Sthurlow */ 33966007Sthurlow 33976007Sthurlow sa_protocol_properties_t 33986007Sthurlow sa_get_protocol_section(sa_protocol_properties_t propset, char *section) 33996007Sthurlow { 34006007Sthurlow xmlNodePtr node = (xmlNodePtr)propset; 34016007Sthurlow xmlChar *value = NULL; 34026007Sthurlow char *proto; 34036007Sthurlow 34046007Sthurlow proto = sa_get_optionset_attr(propset, "type"); 3405*8271SGordon.Ross@Sun.COM if ((sa_proto_get_featureset(proto) & SA_FEATURE_HAS_SECTIONS) == 0) { 3406*8271SGordon.Ross@Sun.COM if (proto != NULL) 3407*8271SGordon.Ross@Sun.COM sa_free_attr_string(proto); 34086007Sthurlow return (propset); 3409*8271SGordon.Ross@Sun.COM } 34106007Sthurlow 34116007Sthurlow for (node = node->children; node != NULL; 34126007Sthurlow node = node->next) { 34136007Sthurlow if (xmlStrcmp(node->name, (xmlChar *)"section") == 0) { 34146007Sthurlow if (section == NULL) 34156007Sthurlow break; 34166007Sthurlow value = xmlGetProp(node, (xmlChar *)"name"); 34176007Sthurlow if (value != NULL && 34186007Sthurlow xmlStrcasecmp(value, (xmlChar *)section) == 0) { 34196007Sthurlow break; 34206007Sthurlow } 34216007Sthurlow if (value != NULL) { 34226007Sthurlow xmlFree(value); 34236007Sthurlow value = NULL; 34246007Sthurlow } 34256007Sthurlow } 34266007Sthurlow } 34276007Sthurlow if (value != NULL) 34286007Sthurlow xmlFree(value); 3429*8271SGordon.Ross@Sun.COM if (proto != NULL) 3430*8271SGordon.Ross@Sun.COM sa_free_attr_string(proto); 34316007Sthurlow if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"section") != 0) { 34326007Sthurlow /* 34336007Sthurlow * avoid a non option node -- it is possible to be a 34346007Sthurlow * text node 34356007Sthurlow */ 34366007Sthurlow node = NULL; 34376007Sthurlow } 34386007Sthurlow return ((sa_protocol_properties_t)node); 34396007Sthurlow } 34406007Sthurlow 34416007Sthurlow /* 34426007Sthurlow * sa_get_next_protocol_section(prop, find) 34436007Sthurlow * 34446007Sthurlow * Get the next protocol specific section in the list. 34456007Sthurlow */ 34466007Sthurlow 34476007Sthurlow sa_property_t 34486007Sthurlow sa_get_next_protocol_section(sa_property_t prop, char *find) 34496007Sthurlow { 34506007Sthurlow xmlNodePtr node; 34516007Sthurlow xmlChar *value = NULL; 34526007Sthurlow char *proto; 34536007Sthurlow 34546007Sthurlow proto = sa_get_optionset_attr(prop, "type"); 3455*8271SGordon.Ross@Sun.COM if ((sa_proto_get_featureset(proto) & SA_FEATURE_HAS_SECTIONS) == 0) { 3456*8271SGordon.Ross@Sun.COM if (proto != NULL) 3457*8271SGordon.Ross@Sun.COM sa_free_attr_string(proto); 34586007Sthurlow return ((sa_property_t)NULL); 3459*8271SGordon.Ross@Sun.COM } 34606007Sthurlow 34616007Sthurlow for (node = ((xmlNodePtr)prop)->next; node != NULL; 34626007Sthurlow node = node->next) { 34636007Sthurlow if (xmlStrcmp(node->name, (xmlChar *)"section") == 0) { 34646007Sthurlow if (find == NULL) 34656007Sthurlow break; 34666007Sthurlow value = xmlGetProp(node, (xmlChar *)"name"); 34676007Sthurlow if (value != NULL && 34686007Sthurlow xmlStrcasecmp(value, (xmlChar *)find) == 0) { 34696007Sthurlow break; 34706007Sthurlow } 34716007Sthurlow if (value != NULL) { 34726007Sthurlow xmlFree(value); 34736007Sthurlow value = NULL; 34746007Sthurlow } 34756007Sthurlow 34766007Sthurlow } 34776007Sthurlow } 34786007Sthurlow if (value != NULL) 34796007Sthurlow xmlFree(value); 3480*8271SGordon.Ross@Sun.COM if (proto != NULL) 3481*8271SGordon.Ross@Sun.COM sa_free_attr_string(proto); 34826007Sthurlow return ((sa_property_t)node); 34836007Sthurlow } 34846007Sthurlow 34856007Sthurlow /* 34863034Sdougm * sa_get_protocol_property(propset, prop) 34873034Sdougm * 34883034Sdougm * Get the specified protocol specific property. These are global to 34893034Sdougm * the protocol and not specific to a group or share. 34903034Sdougm */ 34913034Sdougm 34923034Sdougm sa_property_t 34933034Sdougm sa_get_protocol_property(sa_protocol_properties_t propset, char *prop) 34943034Sdougm { 34953034Sdougm xmlNodePtr node = (xmlNodePtr)propset; 34963034Sdougm xmlChar *value = NULL; 34973034Sdougm 34986007Sthurlow if (propset == NULL) 34996007Sthurlow return (NULL); 35006007Sthurlow 35013034Sdougm for (node = node->children; node != NULL; 35024327Sdougm node = node->next) { 35034327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 35044327Sdougm if (prop == NULL) 35054327Sdougm break; 35064327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 35074327Sdougm if (value != NULL && 35084327Sdougm xmlStrcasecmp(value, (xmlChar *)prop) == 0) { 35094327Sdougm break; 35104327Sdougm } 35114327Sdougm if (value != NULL) { 35124327Sdougm xmlFree(value); 35134327Sdougm value = NULL; 35144327Sdougm } 35153034Sdougm } 35163034Sdougm } 35173034Sdougm if (value != NULL) 35183034Sdougm xmlFree(value); 35193034Sdougm if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"option") != 0) { 35204327Sdougm /* 35214327Sdougm * avoid a non option node -- it is possible to be a 35224327Sdougm * text node 35234327Sdougm */ 35244327Sdougm node = NULL; 35253034Sdougm } 35263034Sdougm return ((sa_property_t)node); 35273034Sdougm } 35283034Sdougm 35293034Sdougm /* 35303034Sdougm * sa_get_next_protocol_property(prop) 35313034Sdougm * 35323034Sdougm * Get the next protocol specific property in the list. 35333034Sdougm */ 35343034Sdougm 35353034Sdougm sa_property_t 35366007Sthurlow sa_get_next_protocol_property(sa_property_t prop, char *find) 35373034Sdougm { 35383034Sdougm xmlNodePtr node; 35396007Sthurlow xmlChar *value = NULL; 35403034Sdougm 35413034Sdougm for (node = ((xmlNodePtr)prop)->next; node != NULL; 35424327Sdougm node = node->next) { 35433034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 35446007Sthurlow if (find == NULL) 35456007Sthurlow break; 35466007Sthurlow value = xmlGetProp(node, (xmlChar *)"type"); 35476007Sthurlow if (value != NULL && 35486007Sthurlow xmlStrcasecmp(value, (xmlChar *)find) == 0) { 35496007Sthurlow break; 35506007Sthurlow } 35516007Sthurlow if (value != NULL) { 35526007Sthurlow xmlFree(value); 35536007Sthurlow value = NULL; 35546007Sthurlow } 35556007Sthurlow 35563034Sdougm } 35573034Sdougm } 35586007Sthurlow if (value != NULL) 35596007Sthurlow xmlFree(value); 35603034Sdougm return ((sa_property_t)node); 35613034Sdougm } 35623034Sdougm 35633034Sdougm /* 35643034Sdougm * sa_set_protocol_property(prop, value) 35653034Sdougm * 35663034Sdougm * Set the specified property to have the new value. The protocol 35673034Sdougm * specific plugin will then be called to update the property. 35683034Sdougm */ 35693034Sdougm 35703034Sdougm int 35716007Sthurlow sa_set_protocol_property(sa_property_t prop, char *section, char *value) 35723034Sdougm { 35733034Sdougm sa_protocol_properties_t propset; 35743034Sdougm char *proto; 35753034Sdougm int ret = SA_INVALID_PROTOCOL; 35763034Sdougm 35773034Sdougm propset = ((xmlNodePtr)prop)->parent; 35783034Sdougm if (propset != NULL) { 35794327Sdougm proto = sa_get_optionset_attr(propset, "type"); 35804327Sdougm if (proto != NULL) { 35816007Sthurlow if (section != NULL) 35826007Sthurlow set_node_attr((xmlNodePtr)prop, "section", 35836007Sthurlow section); 35844327Sdougm set_node_attr((xmlNodePtr)prop, "value", value); 35854327Sdougm ret = sa_proto_set_property(proto, prop); 35864327Sdougm sa_free_attr_string(proto); 35874327Sdougm } 35883034Sdougm } 35893034Sdougm return (ret); 35903034Sdougm } 35913034Sdougm 35923034Sdougm /* 35933034Sdougm * sa_add_protocol_property(propset, prop) 35943034Sdougm * 35955331Samw * Add a new property to the protocol specific property set. 35963034Sdougm */ 35973034Sdougm 35983034Sdougm int 35993034Sdougm sa_add_protocol_property(sa_protocol_properties_t propset, sa_property_t prop) 36003034Sdougm { 36013034Sdougm xmlNodePtr node; 36023034Sdougm 36033034Sdougm /* should check for legitimacy */ 36043034Sdougm node = xmlAddChild((xmlNodePtr)propset, (xmlNodePtr)prop); 36053034Sdougm if (node != NULL) 36064327Sdougm return (SA_OK); 36073034Sdougm return (SA_NO_MEMORY); 36083034Sdougm } 36093034Sdougm 36103034Sdougm /* 36113034Sdougm * sa_create_protocol_properties(proto) 36123034Sdougm * 36135331Samw * Create a protocol specific property set. 36143034Sdougm */ 36153034Sdougm 36163034Sdougm sa_protocol_properties_t 36173034Sdougm sa_create_protocol_properties(char *proto) 36183034Sdougm { 36193034Sdougm xmlNodePtr node; 36204327Sdougm 36213034Sdougm node = xmlNewNode(NULL, (xmlChar *)"propertyset"); 36224327Sdougm if (node != NULL) 36236007Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto); 36243034Sdougm return (node); 36253034Sdougm } 36265331Samw 36275331Samw /* 36285331Samw * sa_get_share_resource(share, resource) 36295331Samw * 36305331Samw * Get the named resource from the share, if it exists. If resource is 36315331Samw * NULL, get the first resource. 36325331Samw */ 36335331Samw 36345331Samw sa_resource_t 36355331Samw sa_get_share_resource(sa_share_t share, char *resource) 36365331Samw { 36375331Samw xmlNodePtr node = NULL; 36385331Samw xmlChar *name; 36395331Samw 36405331Samw if (share != NULL) { 36415331Samw for (node = ((xmlNodePtr)share)->children; node != NULL; 36425331Samw node = node->next) { 36435331Samw if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0) { 36445331Samw if (resource == NULL) { 36455331Samw /* 36465331Samw * We are looking for the first 36475331Samw * resource node and not a names 36485331Samw * resource. 36495331Samw */ 36505331Samw break; 36515331Samw } else { 36525331Samw /* is it the correct share? */ 36535331Samw name = xmlGetProp(node, 36545331Samw (xmlChar *)"name"); 36555331Samw if (name != NULL && 36565331Samw xmlStrcasecmp(name, 36575331Samw (xmlChar *)resource) == 0) { 36585331Samw xmlFree(name); 36595331Samw break; 36605331Samw } 36615331Samw xmlFree(name); 36625331Samw } 36635331Samw } 36645331Samw } 36655331Samw } 36665331Samw return ((sa_resource_t)node); 36675331Samw } 36685331Samw 36695331Samw /* 36705331Samw * sa_get_next_resource(resource) 36715331Samw * Return the next share following the specified share 36725331Samw * from the internal list of shares. Returns NULL if there 36735331Samw * are no more shares. The list is relative to the same 36745331Samw * group. 36755331Samw */ 36765331Samw sa_share_t 36775331Samw sa_get_next_resource(sa_resource_t resource) 36785331Samw { 36795331Samw xmlNodePtr node = NULL; 36805331Samw 36815331Samw if (resource != NULL) { 36825331Samw for (node = ((xmlNodePtr)resource)->next; node != NULL; 36835331Samw node = node->next) { 36845331Samw if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0) 36855331Samw break; 36865331Samw } 36875331Samw } 36885331Samw return ((sa_share_t)node); 36895331Samw } 36905331Samw 36915331Samw /* 36925331Samw * _sa_get_next_resource_index(share) 36935331Samw * 36945331Samw * get the next resource index number (one greater then current largest) 36955331Samw */ 36965331Samw 36975331Samw static int 36985331Samw _sa_get_next_resource_index(sa_share_t share) 36995331Samw { 37005331Samw sa_resource_t resource; 37015331Samw int index = 0; 37025331Samw char *id; 37035331Samw 37045331Samw for (resource = sa_get_share_resource(share, NULL); 37055331Samw resource != NULL; 37065331Samw resource = sa_get_next_resource(resource)) { 37075331Samw id = get_node_attr((void *)resource, "id"); 37085331Samw if (id != NULL) { 37095331Samw int val; 37105331Samw val = atoi(id); 37115331Samw if (val > index) 37125331Samw index = val; 37135331Samw sa_free_attr_string(id); 37145331Samw } 37155331Samw } 37165331Samw return (index + 1); 37175331Samw } 37185331Samw 37195331Samw 37205331Samw /* 37215331Samw * sa_add_resource(share, resource, persist, &err) 37225331Samw * 37235331Samw * Adds a new resource name associated with share. The resource name 37245331Samw * must be unique in the system and will be case insensitive (eventually). 37255331Samw */ 37265331Samw 37275331Samw sa_resource_t 37285331Samw sa_add_resource(sa_share_t share, char *resource, int persist, int *error) 37295331Samw { 37305331Samw xmlNodePtr node; 37315331Samw int err = SA_OK; 37325331Samw sa_resource_t res; 37335331Samw sa_group_t group; 37345331Samw sa_handle_t handle; 37355331Samw char istring[8]; /* just big enough for an integer value */ 37365331Samw int index; 37375331Samw 37385331Samw group = sa_get_parent_group(share); 37395331Samw handle = sa_find_group_handle(group); 37405331Samw res = sa_find_resource(handle, resource); 37415331Samw if (res != NULL) { 37425331Samw err = SA_DUPLICATE_NAME; 37435331Samw res = NULL; 37445331Samw } else { 37455331Samw node = xmlNewChild((xmlNodePtr)share, NULL, 37465331Samw (xmlChar *)"resource", NULL); 37475331Samw if (node != NULL) { 37486007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 37495331Samw (xmlChar *)resource); 37506007Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", persist ? 37515331Samw (xmlChar *)"persist" : (xmlChar *)"transient"); 37525331Samw if (persist != SA_SHARE_TRANSIENT) { 37535331Samw index = _sa_get_next_resource_index(share); 37545331Samw (void) snprintf(istring, sizeof (istring), "%d", 37555331Samw index); 37566007Sthurlow (void) xmlSetProp(node, (xmlChar *)"id", 37575331Samw (xmlChar *)istring); 37587483SDoug.McCallum@Sun.COM 37597483SDoug.McCallum@Sun.COM if (!sa_is_persistent((sa_group_t)share)) 37607483SDoug.McCallum@Sun.COM goto done; 37617483SDoug.McCallum@Sun.COM 37627483SDoug.McCallum@Sun.COM if (!sa_group_is_zfs(group)) { 37635331Samw /* ZFS doesn't use resource names */ 37645331Samw sa_handle_impl_t ihandle; 37657483SDoug.McCallum@Sun.COM 37665331Samw ihandle = (sa_handle_impl_t) 37675331Samw sa_find_group_handle( 37685331Samw group); 37695331Samw if (ihandle != NULL) 37705331Samw err = sa_commit_share( 37715331Samw ihandle->scfhandle, group, 37725331Samw share); 37735331Samw else 37745331Samw err = SA_SYSTEM_ERR; 37757483SDoug.McCallum@Sun.COM } else { 37767483SDoug.McCallum@Sun.COM err = sa_zfs_update((sa_share_t)group); 37775331Samw } 37785331Samw } 37795331Samw } 37805331Samw } 37817483SDoug.McCallum@Sun.COM done: 37825331Samw if (error != NULL) 37835331Samw *error = err; 37845331Samw return ((sa_resource_t)node); 37855331Samw } 37865331Samw 37875331Samw /* 37885331Samw * sa_remove_resource(resource) 37895331Samw * 37905331Samw * Remove the resource name from the share (and the system) 37915331Samw */ 37925331Samw 37935331Samw int 37945331Samw sa_remove_resource(sa_resource_t resource) 37955331Samw { 37965331Samw sa_share_t share; 37975331Samw sa_group_t group; 37985331Samw char *type; 37995331Samw int ret = SA_OK; 38007483SDoug.McCallum@Sun.COM boolean_t transient = B_FALSE; 38015521Sas200622 sa_optionset_t opt; 38025331Samw 38035331Samw share = sa_get_resource_parent(resource); 38045331Samw type = sa_get_share_attr(share, "type"); 38055331Samw group = sa_get_parent_group(share); 38065331Samw 38075331Samw 38085331Samw if (type != NULL) { 38095331Samw if (strcmp(type, "persist") != 0) 38107483SDoug.McCallum@Sun.COM transient = B_TRUE; 38115331Samw sa_free_attr_string(type); 38125331Samw } 38135331Samw 38145521Sas200622 /* Disable the resource for all protocols. */ 38155521Sas200622 (void) sa_disable_resource(resource, NULL); 38165521Sas200622 38175521Sas200622 /* Remove any optionsets from the resource. */ 38185521Sas200622 for (opt = sa_get_optionset(resource, NULL); 38195521Sas200622 opt != NULL; 38205521Sas200622 opt = sa_get_next_optionset(opt)) 38215521Sas200622 (void) sa_destroy_optionset(opt); 38225521Sas200622 38235331Samw /* Remove from the share */ 38245331Samw xmlUnlinkNode((xmlNode *)resource); 38255331Samw xmlFreeNode((xmlNode *)resource); 38265331Samw 38275331Samw /* only do SMF action if permanent and not ZFS */ 38287483SDoug.McCallum@Sun.COM if (transient) 38297483SDoug.McCallum@Sun.COM return (ret); 38307483SDoug.McCallum@Sun.COM 38317483SDoug.McCallum@Sun.COM if (!sa_group_is_zfs(group)) { 38325331Samw sa_handle_impl_t ihandle; 38335331Samw ihandle = (sa_handle_impl_t)sa_find_group_handle(group); 38345331Samw if (ihandle != NULL) 38355331Samw ret = sa_commit_share(ihandle->scfhandle, group, share); 38365331Samw else 38375331Samw ret = SA_SYSTEM_ERR; 38387483SDoug.McCallum@Sun.COM } else { 38397483SDoug.McCallum@Sun.COM ret = sa_zfs_update((sa_share_t)group); 38405331Samw } 38415331Samw return (ret); 38425331Samw } 38435331Samw 38445331Samw /* 38455331Samw * proto_resource_rename(handle, group, resource, newname) 38465331Samw * 38475331Samw * Helper function for sa_rename_resource that notifies the protocol 38485331Samw * of a resource name change prior to a config repository update. 38495331Samw */ 38505331Samw static int 38515331Samw proto_rename_resource(sa_handle_t handle, sa_group_t group, 38525331Samw sa_resource_t resource, char *newname) 38535331Samw { 38545331Samw sa_optionset_t optionset; 38555331Samw int ret = SA_OK; 38565331Samw int err; 38575331Samw 38585331Samw for (optionset = sa_get_optionset(group, NULL); 38595331Samw optionset != NULL; 38605331Samw optionset = sa_get_next_optionset(optionset)) { 38615331Samw char *type; 38625331Samw type = sa_get_optionset_attr(optionset, "type"); 38635331Samw if (type != NULL) { 38645331Samw err = sa_proto_rename_resource(handle, type, resource, 38655331Samw newname); 38665331Samw if (err != SA_OK) 38675331Samw ret = err; 38685331Samw sa_free_attr_string(type); 38695331Samw } 38705331Samw } 38715331Samw return (ret); 38725331Samw } 38735331Samw 38745331Samw /* 38755331Samw * sa_rename_resource(resource, newname) 38765331Samw * 38775331Samw * Rename the resource to the new name, if it is unique. 38785331Samw */ 38795331Samw 38805331Samw int 38815331Samw sa_rename_resource(sa_resource_t resource, char *newname) 38825331Samw { 38835331Samw sa_share_t share; 38845331Samw sa_group_t group = NULL; 38855331Samw sa_resource_t target; 38865331Samw int ret = SA_CONFIG_ERR; 38875331Samw sa_handle_t handle = NULL; 38885331Samw 38895331Samw share = sa_get_resource_parent(resource); 38905331Samw if (share == NULL) 38915331Samw return (ret); 38925331Samw 38935331Samw group = sa_get_parent_group(share); 38945331Samw if (group == NULL) 38955331Samw return (ret); 38965331Samw 38975331Samw handle = (sa_handle_impl_t)sa_find_group_handle(group); 38985331Samw if (handle == NULL) 38995331Samw return (ret); 39005331Samw 39015331Samw target = sa_find_resource(handle, newname); 39025331Samw if (target != NULL) { 39035331Samw ret = SA_DUPLICATE_NAME; 39045331Samw } else { 39055331Samw /* 39065331Samw * Everything appears to be valid at this 39075331Samw * point. Change the name of the active share and then 39085331Samw * update the share in the appropriate repository. 39095331Samw */ 39105331Samw ret = proto_rename_resource(handle, group, resource, newname); 39115331Samw set_node_attr(resource, "name", newname); 39127483SDoug.McCallum@Sun.COM 39137483SDoug.McCallum@Sun.COM if (!sa_is_persistent((sa_group_t)share)) 39147483SDoug.McCallum@Sun.COM return (ret); 39157483SDoug.McCallum@Sun.COM 39167483SDoug.McCallum@Sun.COM if (!sa_group_is_zfs(group)) { 39175331Samw sa_handle_impl_t ihandle = (sa_handle_impl_t)handle; 39185331Samw ret = sa_commit_share(ihandle->scfhandle, group, 39195331Samw share); 39207483SDoug.McCallum@Sun.COM } else { 39217483SDoug.McCallum@Sun.COM ret = sa_zfs_update((sa_share_t)group); 39225331Samw } 39235331Samw } 39245331Samw return (ret); 39255331Samw } 39265331Samw 39275331Samw /* 39285331Samw * sa_get_resource_attr(resource, tag) 39295331Samw * 39305331Samw * Get the named attribute of the resource. "name" and "id" are 39315331Samw * currently defined. NULL if tag not defined. 39325331Samw */ 39335331Samw 39345331Samw char * 39355331Samw sa_get_resource_attr(sa_resource_t resource, char *tag) 39365331Samw { 39375331Samw return (get_node_attr((void *)resource, tag)); 39385331Samw } 39395331Samw 39405331Samw /* 39415331Samw * sa_set_resource_attr(resource, tag, value) 39425331Samw * 39435331Samw * Get the named attribute of the resource. "name" and "id" are 39445331Samw * currently defined. NULL if tag not defined. Currently we don't do 39455331Samw * much, but additional checking may be needed in the future. 39465331Samw */ 39475331Samw 39485331Samw int 39495331Samw sa_set_resource_attr(sa_resource_t resource, char *tag, char *value) 39505331Samw { 39515331Samw set_node_attr((void *)resource, tag, value); 39525331Samw return (SA_OK); 39535331Samw } 39545331Samw 39555331Samw /* 39565331Samw * sa_get_resource_parent(resource_t) 39575331Samw * 39585331Samw * Returns the share associated with the resource. 39595331Samw */ 39605331Samw 39615331Samw sa_share_t 39625331Samw sa_get_resource_parent(sa_resource_t resource) 39635331Samw { 39645331Samw sa_share_t share = NULL; 39655331Samw 39665331Samw if (resource != NULL) 39675331Samw share = (sa_share_t)((xmlNodePtr)resource)->parent; 39685331Samw return (share); 39695331Samw } 39705331Samw 39715331Samw /* 39725331Samw * find_resource(group, name) 39735331Samw * 39745331Samw * Find the resource within the group. 39755331Samw */ 39765331Samw 39775331Samw static sa_resource_t 39785331Samw find_resource(sa_group_t group, char *resname) 39795331Samw { 39805331Samw sa_share_t share; 39815331Samw sa_resource_t resource = NULL; 39825331Samw char *name; 39835331Samw 39845331Samw /* Iterate over all the shares and resources in the group. */ 39855331Samw for (share = sa_get_share(group, NULL); 39865331Samw share != NULL && resource == NULL; 39875331Samw share = sa_get_next_share(share)) { 39885331Samw for (resource = sa_get_share_resource(share, NULL); 39895331Samw resource != NULL; 39905331Samw resource = sa_get_next_resource(resource)) { 39915331Samw name = sa_get_resource_attr(resource, "name"); 39925331Samw if (name != NULL && xmlStrcasecmp((xmlChar*)name, 39935331Samw (xmlChar*)resname) == 0) { 39945331Samw sa_free_attr_string(name); 39955331Samw break; 39965331Samw } 39975331Samw if (name != NULL) { 39985331Samw sa_free_attr_string(name); 39995331Samw } 40005331Samw } 40015331Samw } 40025331Samw return (resource); 40035331Samw } 40045331Samw 40055331Samw /* 40065331Samw * sa_find_resource(name) 40075331Samw * 40085331Samw * Find the named resource in the system. 40095331Samw */ 40105331Samw 40115331Samw sa_resource_t 40125331Samw sa_find_resource(sa_handle_t handle, char *name) 40135331Samw { 40145331Samw sa_group_t group; 40155331Samw sa_group_t zgroup; 40165331Samw sa_resource_t resource = NULL; 40175331Samw 40185331Samw /* 40195331Samw * Iterate over all groups and zfs subgroups and check for 40205331Samw * resource name in them. 40215331Samw */ 40225331Samw for (group = sa_get_group(handle, NULL); group != NULL; 40235331Samw group = sa_get_next_group(group)) { 40245331Samw 40255331Samw if (is_zfs_group(group)) { 40265331Samw for (zgroup = 40275331Samw (sa_group_t)_sa_get_child_node((xmlNodePtr)group, 40285331Samw (xmlChar *)"group"); 40295331Samw zgroup != NULL && resource == NULL; 40305331Samw zgroup = sa_get_next_group(zgroup)) { 40315331Samw resource = find_resource(zgroup, name); 40325331Samw } 40335331Samw } else { 40345331Samw resource = find_resource(group, name); 40355331Samw } 40365331Samw if (resource != NULL) 40375331Samw break; 40385331Samw } 40395331Samw return (resource); 40405331Samw } 40415331Samw 40425331Samw /* 40435331Samw * sa_get_resource(group, resource) 40445331Samw * 40455331Samw * Search all the shares in the specified group for a share with a 40465331Samw * resource name matching the one specified. 40475331Samw * 40485331Samw * In the future, it may be advantageous to allow group to be NULL and 40495331Samw * search all groups but that isn't needed at present. 40505331Samw */ 40515331Samw 40525331Samw sa_resource_t 40535331Samw sa_get_resource(sa_group_t group, char *resource) 40545331Samw { 40555331Samw sa_share_t share = NULL; 40565331Samw sa_resource_t res = NULL; 40575331Samw 40585331Samw if (resource != NULL) { 40595331Samw for (share = sa_get_share(group, NULL); 40605331Samw share != NULL && res == NULL; 40615331Samw share = sa_get_next_share(share)) { 40625331Samw res = sa_get_share_resource(share, resource); 40635331Samw } 40645331Samw } 40655331Samw return (res); 40665331Samw } 40675331Samw 40685331Samw /* 40696270Sdougm * get_protocol_list(optionset, object) 40706270Sdougm * 40716270Sdougm * Get the protocol optionset list for the object and add them as 40726270Sdougm * properties to optionset. 40736270Sdougm */ 40746270Sdougm static int 40756270Sdougm get_protocol_list(sa_optionset_t optionset, void *object) 40766270Sdougm { 40776270Sdougm sa_property_t prop; 40786270Sdougm sa_optionset_t opts; 40796270Sdougm int ret = SA_OK; 40806270Sdougm 40816270Sdougm for (opts = sa_get_optionset(object, NULL); 40826270Sdougm opts != NULL; 40836270Sdougm opts = sa_get_next_optionset(opts)) { 40846270Sdougm char *type; 40856270Sdougm type = sa_get_optionset_attr(opts, "type"); 40866270Sdougm /* 40876270Sdougm * It is possible to have a non-protocol optionset. We 40886270Sdougm * skip any of those found. 40896270Sdougm */ 40906270Sdougm if (type == NULL) 40916270Sdougm continue; 40926270Sdougm prop = sa_create_property(type, "true"); 40936270Sdougm sa_free_attr_string(type); 40946270Sdougm if (prop != NULL) 40956270Sdougm prop = (sa_property_t)xmlAddChild((xmlNodePtr)optionset, 40966270Sdougm (xmlNodePtr)prop); 40976270Sdougm /* If prop is NULL, don't bother continuing */ 40986270Sdougm if (prop == NULL) { 40996270Sdougm ret = SA_NO_MEMORY; 41006270Sdougm break; 41016270Sdougm } 41026270Sdougm } 41036270Sdougm return (ret); 41046270Sdougm } 41056270Sdougm 41066270Sdougm /* 41076270Sdougm * sa_free_protoset(optionset) 41086270Sdougm * 41096270Sdougm * Free the protocol property optionset. 41106270Sdougm */ 41116270Sdougm static void 41126270Sdougm sa_free_protoset(sa_optionset_t optionset) 41136270Sdougm { 41146270Sdougm if (optionset != NULL) { 41156270Sdougm xmlUnlinkNode((xmlNodePtr) optionset); 41166270Sdougm xmlFreeNode((xmlNodePtr) optionset); 41176270Sdougm } 41186270Sdougm } 41196270Sdougm 41206270Sdougm /* 41216270Sdougm * sa_optionset_t sa_get_active_protocols(object) 41226270Sdougm * 41236270Sdougm * Return a list of the protocols that are active for the object. 41246270Sdougm * This is currently an internal helper function, but could be 41256270Sdougm * made visible if there is enough demand for it. 41266270Sdougm * 41276270Sdougm * The function finds the parent group and extracts the protocol 41286270Sdougm * optionsets creating a new optionset with the protocols as properties. 41296270Sdougm * 41306270Sdougm * The caller must free the returned optionset. 41316270Sdougm */ 41326270Sdougm 41336270Sdougm static sa_optionset_t 41346270Sdougm sa_get_active_protocols(void *object) 41356270Sdougm { 41366270Sdougm sa_optionset_t options; 41376270Sdougm sa_share_t share = NULL; 41386270Sdougm sa_group_t group = NULL; 41396270Sdougm sa_resource_t resource = NULL; 41406270Sdougm int ret = SA_OK; 41416270Sdougm 41426270Sdougm if (object == NULL) 41436270Sdougm return (NULL); 41446270Sdougm options = (sa_optionset_t)xmlNewNode(NULL, (xmlChar *)"optionset"); 41456270Sdougm if (options == NULL) 41466270Sdougm return (NULL); 41476270Sdougm 41486270Sdougm /* 41496270Sdougm * Find the objects up the tree that might have protocols 41506270Sdougm * enabled on them. 41516270Sdougm */ 41526270Sdougm if (sa_is_resource(object)) { 41536270Sdougm resource = (sa_resource_t)object; 41546270Sdougm share = sa_get_resource_parent(resource); 41556270Sdougm group = sa_get_parent_group(share); 41566270Sdougm } else if (sa_is_share(object)) { 41576270Sdougm share = (sa_share_t)object; 41586270Sdougm group = sa_get_parent_group(share); 41596270Sdougm } else { 41606270Sdougm group = (sa_group_t)group; 41616270Sdougm } 41626270Sdougm if (resource != NULL) 41636270Sdougm ret = get_protocol_list(options, resource); 41646270Sdougm if (ret == SA_OK && share != NULL) 41656270Sdougm ret = get_protocol_list(options, share); 41666270Sdougm if (ret == SA_OK && group != NULL) 41676270Sdougm ret = get_protocol_list(options, group); 41686270Sdougm 41696270Sdougm /* 41706270Sdougm * If there was an error, we won't have a complete list so 41716270Sdougm * abandon everything. The caller will have to deal with the 41726270Sdougm * issue. 41736270Sdougm */ 41746270Sdougm if (ret != SA_OK) { 41756270Sdougm sa_free_protoset(options); 41766270Sdougm options = NULL; 41776270Sdougm } 41786270Sdougm return (options); 41796270Sdougm } 41806270Sdougm 41816270Sdougm /* 41825331Samw * sa_enable_resource, protocol) 41835331Samw * Disable the specified share to the specified protocol. 41845331Samw * If protocol is NULL, then all protocols. 41855331Samw */ 41865331Samw int 41875331Samw sa_enable_resource(sa_resource_t resource, char *protocol) 41885331Samw { 41895331Samw int ret = SA_OK; 41905331Samw 41915331Samw if (protocol != NULL) { 41925331Samw ret = sa_proto_share_resource(protocol, resource); 41935331Samw } else { 41946270Sdougm sa_optionset_t protoset; 41956270Sdougm sa_property_t prop; 41966270Sdougm char *proto; 41976270Sdougm int err; 41986270Sdougm 41995331Samw /* need to do all protocols */ 42006270Sdougm protoset = sa_get_active_protocols(resource); 42016270Sdougm if (protoset == NULL) 42026270Sdougm return (SA_NO_MEMORY); 42036270Sdougm for (prop = sa_get_property(protoset, NULL); 42046270Sdougm prop != NULL; 42056270Sdougm prop = sa_get_next_property(prop)) { 42066270Sdougm proto = sa_get_property_attr(prop, "type"); 42076270Sdougm if (proto == NULL) { 42086270Sdougm ret = SA_NO_MEMORY; 42096270Sdougm continue; 42105331Samw } 42116270Sdougm err = sa_proto_share_resource(proto, resource); 42126270Sdougm if (err != SA_OK) 42136270Sdougm ret = err; 42146270Sdougm sa_free_attr_string(proto); 42155331Samw } 42166270Sdougm sa_free_protoset(protoset); 42175331Samw } 42185331Samw if (ret == SA_OK) 42195331Samw (void) sa_set_resource_attr(resource, "shared", NULL); 42205331Samw 42215331Samw return (ret); 42225331Samw } 42235331Samw 42245331Samw /* 42255331Samw * sa_disable_resource(resource, protocol) 42265331Samw * 42275331Samw * Disable the specified share for the specified protocol. If 42285331Samw * protocol is NULL, then all protocols. If the underlying 42295331Samw * protocol doesn't implement disable at the resource level, we 42305331Samw * disable at the share level. 42315331Samw */ 42325331Samw int 42335331Samw sa_disable_resource(sa_resource_t resource, char *protocol) 42345331Samw { 42355331Samw int ret = SA_OK; 42365331Samw 42375331Samw if (protocol != NULL) { 42385331Samw ret = sa_proto_unshare_resource(protocol, resource); 42395331Samw if (ret == SA_NOT_IMPLEMENTED) { 42405331Samw sa_share_t parent; 42415331Samw /* 42425331Samw * The protocol doesn't implement unshare 42435331Samw * resource. That implies that resource names are 42445331Samw * simple aliases for this protocol so we need to 42455331Samw * unshare the share. 42465331Samw */ 42475331Samw parent = sa_get_resource_parent(resource); 42485331Samw if (parent != NULL) 42495331Samw ret = sa_disable_share(parent, protocol); 42505331Samw else 42515331Samw ret = SA_CONFIG_ERR; 42525331Samw } 42535331Samw } else { 42546270Sdougm sa_optionset_t protoset; 42556270Sdougm sa_property_t prop; 42566270Sdougm char *proto; 42576270Sdougm int err; 42586270Sdougm 42595331Samw /* need to do all protocols */ 42606270Sdougm protoset = sa_get_active_protocols(resource); 42616270Sdougm if (protoset == NULL) 42626270Sdougm return (SA_NO_MEMORY); 42636270Sdougm for (prop = sa_get_property(protoset, NULL); 42646270Sdougm prop != NULL; 42656270Sdougm prop = sa_get_next_property(prop)) { 42666270Sdougm proto = sa_get_property_attr(prop, "type"); 42676270Sdougm if (proto == NULL) { 42686270Sdougm ret = SA_NO_MEMORY; 42696270Sdougm continue; 42705331Samw } 42716270Sdougm err = sa_proto_unshare_resource(proto, resource); 42726270Sdougm if (err == SA_NOT_SUPPORTED) { 42736270Sdougm sa_share_t parent; 42746270Sdougm parent = sa_get_resource_parent(resource); 42756270Sdougm if (parent != NULL) 42766270Sdougm err = sa_disable_share(parent, proto); 42776270Sdougm else 42786270Sdougm err = SA_CONFIG_ERR; 42796270Sdougm } 42806270Sdougm if (err != SA_OK) 42816270Sdougm ret = err; 42826270Sdougm sa_free_attr_string(proto); 42835331Samw } 42846270Sdougm sa_free_protoset(protoset); 42855331Samw } 42865331Samw if (ret == SA_OK) 42875331Samw (void) sa_set_resource_attr(resource, "shared", NULL); 42885331Samw 42895331Samw return (ret); 42905331Samw } 42915331Samw 42925331Samw /* 42935331Samw * sa_set_resource_description(resource, content) 42945331Samw * 42955331Samw * Set the description of share to content. 42965331Samw */ 42975331Samw 42985331Samw int 42995331Samw sa_set_resource_description(sa_resource_t resource, char *content) 43005331Samw { 43015331Samw xmlNodePtr node; 43025331Samw sa_group_t group; 43035331Samw sa_share_t share; 43045331Samw int ret = SA_OK; 43055331Samw 43065331Samw for (node = ((xmlNodePtr)resource)->children; 43075331Samw node != NULL; 43085331Samw node = node->next) { 43095331Samw if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 43105331Samw break; 43115331Samw } 43125331Samw } 43135331Samw 43145331Samw /* no existing description but want to add */ 43155331Samw if (node == NULL && content != NULL) { 43165331Samw /* add a description */ 43175331Samw node = _sa_set_share_description(resource, content); 43185331Samw } else if (node != NULL && content != NULL) { 43195331Samw /* update a description */ 43205331Samw xmlNodeSetContent(node, (xmlChar *)content); 43215331Samw } else if (node != NULL && content == NULL) { 43225331Samw /* remove an existing description */ 43235331Samw xmlUnlinkNode(node); 43245331Samw xmlFreeNode(node); 43255331Samw } 43265331Samw share = sa_get_resource_parent(resource); 43275331Samw group = sa_get_parent_group(share); 43285331Samw if (group != NULL && sa_is_persistent(share)) { 43295331Samw sa_handle_impl_t impl_handle; 43305331Samw impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 43315331Samw if (impl_handle != NULL) 43325331Samw ret = sa_commit_share(impl_handle->scfhandle, 43335331Samw group, share); 43345331Samw else 43355331Samw ret = SA_SYSTEM_ERR; 43365331Samw } 43375331Samw return (ret); 43385331Samw } 43395331Samw 43405331Samw /* 43415331Samw * sa_get_resource_description(share) 43425331Samw * 43435331Samw * Return the description text for the specified share if it 43445331Samw * exists. NULL if no description exists. 43455331Samw */ 43465331Samw 43475331Samw char * 43485331Samw sa_get_resource_description(sa_resource_t resource) 43495331Samw { 43505331Samw xmlChar *description = NULL; 43515331Samw xmlNodePtr node; 43525331Samw 43535331Samw for (node = ((xmlNodePtr)resource)->children; node != NULL; 43545331Samw node = node->next) { 43555331Samw if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) 43565331Samw break; 43575331Samw } 43585331Samw if (node != NULL) { 43595331Samw description = xmlNodeGetContent(node); 43605331Samw fixproblemchars((char *)description); 43615331Samw } 43625331Samw return ((char *)description); 43635331Samw } 4364