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 /* 2312508Samw@Sun.COM * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. 243034Sdougm */ 253034Sdougm 263034Sdougm /* 273034Sdougm * Share control API 283034Sdougm */ 293034Sdougm #include <stdio.h> 303034Sdougm #include <string.h> 313034Sdougm #include <ctype.h> 323034Sdougm #include <sys/types.h> 333034Sdougm #include <sys/stat.h> 343663Sdougm #include <fcntl.h> 353034Sdougm #include <unistd.h> 363034Sdougm #include <libxml/parser.h> 373034Sdougm #include <libxml/tree.h> 383034Sdougm #include "libshare.h" 393034Sdougm #include "libshare_impl.h" 403034Sdougm #include <libscf.h> 413034Sdougm #include "scfutil.h" 423034Sdougm #include <ctype.h> 433034Sdougm #include <libintl.h> 443910Sdougm #include <thread.h> 453910Sdougm #include <synch.h> 463034Sdougm 473663Sdougm #define DFS_LOCK_FILE "/etc/dfs/fstypes" 484327Sdougm #define SA_STRSIZE 256 /* max string size for names */ 493663Sdougm 503034Sdougm /* 515331Samw * internal object type values returned by sa_get_object_type() 525331Samw */ 535331Samw #define SA_TYPE_UNKNOWN 0 545331Samw #define SA_TYPE_GROUP 1 555331Samw #define SA_TYPE_SHARE 2 565331Samw #define SA_TYPE_RESOURCE 3 575331Samw #define SA_TYPE_OPTIONSET 4 585331Samw #define SA_TYPE_ALTSPACE 5 595331Samw 605331Samw /* 613034Sdougm * internal data structures 623034Sdougm */ 633034Sdougm 643034Sdougm extern struct sa_proto_plugin *sap_proto_list; 653034Sdougm 663034Sdougm /* current SMF/SVC repository handle */ 673910Sdougm extern void getlegacyconfig(sa_handle_t, char *, xmlNodePtr *); 683910Sdougm extern int gettransients(sa_handle_impl_t, xmlNodePtr *); 693034Sdougm extern char *sa_fstype(char *); 703034Sdougm extern int sa_is_share(void *); 715331Samw extern int sa_is_resource(void *); 723034Sdougm extern ssize_t scf_max_name_len; /* defined in scfutil during initialization */ 733034Sdougm extern int sa_group_is_zfs(sa_group_t); 743034Sdougm extern int sa_path_is_zfs(char *); 753034Sdougm extern int sa_zfs_set_sharenfs(sa_group_t, char *, int); 765331Samw extern int sa_zfs_set_sharesmb(sa_group_t, char *, int); 773910Sdougm extern void update_legacy_config(sa_handle_t); 783034Sdougm extern int issubdir(char *, char *); 794327Sdougm extern int sa_zfs_init(sa_handle_impl_t); 803910Sdougm extern void sa_zfs_fini(sa_handle_impl_t); 813663Sdougm extern void sablocksigs(sigset_t *); 823663Sdougm extern void saunblocksigs(sigset_t *); 835331Samw static sa_group_t sa_get_optionset_parent(sa_optionset_t); 845331Samw static char *get_node_attr(void *, char *); 855951Sdougm extern void sa_update_sharetab_ts(sa_handle_t); 863034Sdougm 873910Sdougm /* 883910Sdougm * Data structures for finding/managing the document root to access 893910Sdougm * handle mapping. The list isn't expected to grow very large so a 903910Sdougm * simple list is acceptable. The purpose is to provide a way to start 913910Sdougm * with a group or share and find the library handle needed for 923910Sdougm * various operations. 933910Sdougm */ 943910Sdougm mutex_t sa_global_lock; 953910Sdougm struct doc2handle { 963910Sdougm struct doc2handle *next; 973910Sdougm xmlNodePtr root; 983910Sdougm sa_handle_impl_t handle; 993910Sdougm }; 1003910Sdougm 10112508Samw@Sun.COM mutex_t sa_dfstab_lock; 10212508Samw@Sun.COM 1034327Sdougm /* definitions used in a couple of property functions */ 1044327Sdougm #define SA_PROP_OP_REMOVE 1 1054327Sdougm #define SA_PROP_OP_ADD 2 1064327Sdougm #define SA_PROP_OP_UPDATE 3 1074327Sdougm 1083910Sdougm static struct doc2handle *sa_global_handles = NULL; 1093034Sdougm 1103034Sdougm /* helper functions */ 1113034Sdougm 1123910Sdougm /* 1133910Sdougm * sa_errorstr(err) 1143910Sdougm * 1153910Sdougm * convert an error value to an error string 1163910Sdougm */ 1173910Sdougm 1183034Sdougm char * 1193034Sdougm sa_errorstr(int err) 1203034Sdougm { 1213034Sdougm static char errstr[32]; 1223034Sdougm char *ret = NULL; 1233034Sdougm 1243034Sdougm switch (err) { 1253034Sdougm case SA_OK: 1264327Sdougm ret = dgettext(TEXT_DOMAIN, "ok"); 1274327Sdougm break; 1283034Sdougm case SA_NO_SUCH_PATH: 1294327Sdougm ret = dgettext(TEXT_DOMAIN, "path doesn't exist"); 1304327Sdougm break; 1313034Sdougm case SA_NO_MEMORY: 1324327Sdougm ret = dgettext(TEXT_DOMAIN, "no memory"); 1334327Sdougm break; 1343034Sdougm case SA_DUPLICATE_NAME: 1354327Sdougm ret = dgettext(TEXT_DOMAIN, "name in use"); 1364327Sdougm break; 1373034Sdougm case SA_BAD_PATH: 1384327Sdougm ret = dgettext(TEXT_DOMAIN, "bad path"); 1394327Sdougm break; 1403034Sdougm case SA_NO_SUCH_GROUP: 1414327Sdougm ret = dgettext(TEXT_DOMAIN, "no such group"); 1424327Sdougm break; 1433034Sdougm case SA_CONFIG_ERR: 1444327Sdougm ret = dgettext(TEXT_DOMAIN, "configuration error"); 1454327Sdougm break; 1463034Sdougm case SA_SYSTEM_ERR: 1474327Sdougm ret = dgettext(TEXT_DOMAIN, "system error"); 1484327Sdougm break; 1493034Sdougm case SA_SYNTAX_ERR: 1504327Sdougm ret = dgettext(TEXT_DOMAIN, "syntax error"); 1514327Sdougm break; 1523034Sdougm case SA_NO_PERMISSION: 1534327Sdougm ret = dgettext(TEXT_DOMAIN, "no permission"); 1544327Sdougm break; 1553034Sdougm case SA_BUSY: 1564327Sdougm ret = dgettext(TEXT_DOMAIN, "busy"); 1574327Sdougm break; 1583034Sdougm case SA_NO_SUCH_PROP: 1594327Sdougm ret = dgettext(TEXT_DOMAIN, "no such property"); 1604327Sdougm break; 1613034Sdougm case SA_INVALID_NAME: 1624327Sdougm ret = dgettext(TEXT_DOMAIN, "invalid name"); 1634327Sdougm break; 1643034Sdougm case SA_INVALID_PROTOCOL: 1654327Sdougm ret = dgettext(TEXT_DOMAIN, "invalid protocol"); 1664327Sdougm break; 1673034Sdougm case SA_NOT_ALLOWED: 1684327Sdougm ret = dgettext(TEXT_DOMAIN, "operation not allowed"); 1694327Sdougm break; 1703034Sdougm case SA_BAD_VALUE: 1714327Sdougm ret = dgettext(TEXT_DOMAIN, "bad property value"); 1724327Sdougm break; 1733034Sdougm case SA_INVALID_SECURITY: 1744327Sdougm ret = dgettext(TEXT_DOMAIN, "invalid security type"); 1754327Sdougm break; 1763034Sdougm case SA_NO_SUCH_SECURITY: 1774327Sdougm ret = dgettext(TEXT_DOMAIN, "security type not found"); 1784327Sdougm break; 1793034Sdougm case SA_VALUE_CONFLICT: 1804327Sdougm ret = dgettext(TEXT_DOMAIN, "property value conflict"); 1814327Sdougm break; 1823034Sdougm case SA_NOT_IMPLEMENTED: 1834327Sdougm ret = dgettext(TEXT_DOMAIN, "not implemented"); 1844327Sdougm break; 1853034Sdougm case SA_INVALID_PATH: 1864327Sdougm ret = dgettext(TEXT_DOMAIN, "invalid path"); 1874327Sdougm break; 1883034Sdougm case SA_NOT_SUPPORTED: 1894327Sdougm ret = dgettext(TEXT_DOMAIN, "operation not supported"); 1904327Sdougm break; 1913034Sdougm case SA_PROP_SHARE_ONLY: 1924327Sdougm ret = dgettext(TEXT_DOMAIN, "property not valid for group"); 1934327Sdougm break; 1943034Sdougm case SA_NOT_SHARED: 1954327Sdougm ret = dgettext(TEXT_DOMAIN, "not shared"); 1964327Sdougm break; 1975331Samw case SA_NO_SUCH_RESOURCE: 1985331Samw ret = dgettext(TEXT_DOMAIN, "no such resource"); 1995331Samw break; 2005331Samw case SA_RESOURCE_REQUIRED: 2015331Samw ret = dgettext(TEXT_DOMAIN, "resource name required"); 2025331Samw break; 2035331Samw case SA_MULTIPLE_ERROR: 2045331Samw ret = dgettext(TEXT_DOMAIN, "errors from multiple protocols"); 2055331Samw break; 2065331Samw case SA_PATH_IS_SUBDIR: 2075331Samw ret = dgettext(TEXT_DOMAIN, "path is a subpath of share"); 2085331Samw break; 2095331Samw case SA_PATH_IS_PARENTDIR: 2105331Samw ret = dgettext(TEXT_DOMAIN, "path is parent of a share"); 2115331Samw break; 2126007Sthurlow case SA_NO_SECTION: 2136007Sthurlow ret = dgettext(TEXT_DOMAIN, "protocol requires a section"); 2146007Sthurlow break; 2156007Sthurlow case SA_NO_PROPERTIES: 2166007Sthurlow ret = dgettext(TEXT_DOMAIN, "properties not found"); 2176007Sthurlow break; 2186007Sthurlow case SA_NO_SUCH_SECTION: 2196007Sthurlow ret = dgettext(TEXT_DOMAIN, "section not found"); 2206007Sthurlow break; 2216007Sthurlow case SA_PASSWORD_ENC: 2226007Sthurlow ret = dgettext(TEXT_DOMAIN, "passwords must be encrypted"); 2236007Sthurlow break; 224*12679SPavel.Filipensky@Sun.COM case SA_SHARE_EXISTS: 225*12679SPavel.Filipensky@Sun.COM ret = dgettext(TEXT_DOMAIN, "path or file is already shared"); 226*12679SPavel.Filipensky@Sun.COM break; 2273034Sdougm default: 2284327Sdougm (void) snprintf(errstr, sizeof (errstr), 2294327Sdougm dgettext(TEXT_DOMAIN, "unknown %d"), err); 2304327Sdougm ret = errstr; 2313034Sdougm } 2323034Sdougm return (ret); 2333034Sdougm } 2343034Sdougm 2353034Sdougm /* 2363910Sdougm * Document root to active handle mapping functions. These are only 2373910Sdougm * used internally. A mutex is used to prevent access while the list 2383910Sdougm * is changing. In general, the list will be relatively short - one 2393910Sdougm * item per thread that has called sa_init(). 2403910Sdougm */ 2413910Sdougm 2423910Sdougm sa_handle_impl_t 2433910Sdougm get_handle_for_root(xmlNodePtr root) 2443910Sdougm { 2453910Sdougm struct doc2handle *item; 2463910Sdougm 2473910Sdougm (void) mutex_lock(&sa_global_lock); 2483910Sdougm for (item = sa_global_handles; item != NULL; item = item->next) { 2494327Sdougm if (item->root == root) 2504327Sdougm break; 2513910Sdougm } 2523910Sdougm (void) mutex_unlock(&sa_global_lock); 2533910Sdougm if (item != NULL) 2544327Sdougm return (item->handle); 2553910Sdougm return (NULL); 2563910Sdougm } 2573910Sdougm 2583910Sdougm static int 2593910Sdougm add_handle_for_root(xmlNodePtr root, sa_handle_impl_t handle) 2603910Sdougm { 2613910Sdougm struct doc2handle *item; 2623910Sdougm int ret = SA_NO_MEMORY; 2633910Sdougm 2643910Sdougm item = (struct doc2handle *)calloc(sizeof (struct doc2handle), 1); 2653910Sdougm if (item != NULL) { 2664327Sdougm item->root = root; 2674327Sdougm item->handle = handle; 2684327Sdougm (void) mutex_lock(&sa_global_lock); 2694327Sdougm item->next = sa_global_handles; 2704327Sdougm sa_global_handles = item; 2714327Sdougm (void) mutex_unlock(&sa_global_lock); 2724327Sdougm ret = SA_OK; 2733910Sdougm } 2743910Sdougm return (ret); 2753910Sdougm } 2763910Sdougm 2773910Sdougm /* 2783910Sdougm * remove_handle_for_root(root) 2793910Sdougm * 2803910Sdougm * Walks the list of handles and removes the one for this "root" from 2813910Sdougm * the list. It is up to the caller to free the data. 2823910Sdougm */ 2833910Sdougm 2843910Sdougm static void 2853910Sdougm remove_handle_for_root(xmlNodePtr root) 2863910Sdougm { 2873910Sdougm struct doc2handle *item, *prev; 2883910Sdougm 2893910Sdougm (void) mutex_lock(&sa_global_lock); 2903910Sdougm for (prev = NULL, item = sa_global_handles; item != NULL; 2914327Sdougm item = item->next) { 2924327Sdougm if (item->root == root) { 2934327Sdougm /* first in the list */ 2944327Sdougm if (prev == NULL) 2954327Sdougm sa_global_handles = sa_global_handles->next; 2964327Sdougm else 2974327Sdougm prev->next = item->next; 2984327Sdougm /* Item is out of the list so free the list structure */ 2994327Sdougm free(item); 3004327Sdougm break; 3013910Sdougm } 3024327Sdougm prev = item; 3033910Sdougm } 3043910Sdougm (void) mutex_unlock(&sa_global_lock); 3053910Sdougm } 3063910Sdougm 3073910Sdougm /* 3083910Sdougm * sa_find_group_handle(sa_group_t group) 3093910Sdougm * 3103910Sdougm * Find the sa_handle_t for the configuration associated with this 3113910Sdougm * group. 3123910Sdougm */ 3133910Sdougm sa_handle_t 3143910Sdougm sa_find_group_handle(sa_group_t group) 3153910Sdougm { 3163910Sdougm xmlNodePtr node = (xmlNodePtr)group; 3173910Sdougm sa_handle_t handle; 3183910Sdougm 3193910Sdougm while (node != NULL) { 3204327Sdougm if (strcmp((char *)(node->name), "sharecfg") == 0) { 3214327Sdougm /* have the root so get the handle */ 3224327Sdougm handle = (sa_handle_t)get_handle_for_root(node); 3234327Sdougm return (handle); 3244327Sdougm } 3254327Sdougm node = node->parent; 3263910Sdougm } 3273910Sdougm return (NULL); 3283910Sdougm } 3293910Sdougm 3303910Sdougm /* 3313034Sdougm * set_legacy_timestamp(root, path, timevalue) 3323034Sdougm * 3333034Sdougm * add the current timestamp value to the configuration for use in 3343034Sdougm * determining when to update the legacy files. For SMF, this 3353034Sdougm * property is kept in default/operation/legacy_timestamp 3363034Sdougm */ 3373034Sdougm 3383034Sdougm static void 3393034Sdougm set_legacy_timestamp(xmlNodePtr root, char *path, uint64_t tval) 3403034Sdougm { 3413034Sdougm xmlNodePtr node; 3423034Sdougm xmlChar *lpath = NULL; 3433910Sdougm sa_handle_impl_t handle; 3443910Sdougm 3453910Sdougm /* Have to have a handle or else we weren't initialized. */ 3463910Sdougm handle = get_handle_for_root(root); 3473910Sdougm if (handle == NULL) 3484327Sdougm return; 3493034Sdougm 3503034Sdougm for (node = root->xmlChildrenNode; node != NULL; 3514327Sdougm node = node->next) { 3524327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"legacy") == 0) { 3534327Sdougm /* a possible legacy node for this path */ 3544327Sdougm lpath = xmlGetProp(node, (xmlChar *)"path"); 3554327Sdougm if (lpath != NULL && 3564327Sdougm xmlStrcmp(lpath, (xmlChar *)path) == 0) { 3574327Sdougm xmlFree(lpath); 3584327Sdougm break; 3594327Sdougm } 3604327Sdougm if (lpath != NULL) 3614327Sdougm xmlFree(lpath); 3623034Sdougm } 3633034Sdougm } 3643034Sdougm if (node == NULL) { 3654327Sdougm /* need to create the first legacy timestamp node */ 3664327Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"legacy", NULL); 3673034Sdougm } 3683034Sdougm if (node != NULL) { 3694327Sdougm char tstring[32]; 3704327Sdougm int ret; 3713034Sdougm 3724327Sdougm (void) snprintf(tstring, sizeof (tstring), "%lld", tval); 3736007Sthurlow (void) xmlSetProp(node, (xmlChar *)"timestamp", 3746007Sthurlow (xmlChar *)tstring); 3756007Sthurlow (void) xmlSetProp(node, (xmlChar *)"path", (xmlChar *)path); 3764327Sdougm /* now commit to SMF */ 3774327Sdougm ret = sa_get_instance(handle->scfhandle, "default"); 3783034Sdougm if (ret == SA_OK) { 3794327Sdougm ret = sa_start_transaction(handle->scfhandle, 3804327Sdougm "operation"); 3814327Sdougm if (ret == SA_OK) { 3824327Sdougm ret = sa_set_property(handle->scfhandle, 3834327Sdougm "legacy-timestamp", tstring); 3844327Sdougm if (ret == SA_OK) { 3854327Sdougm (void) sa_end_transaction( 3865951Sdougm handle->scfhandle, handle); 3874327Sdougm } else { 3884327Sdougm sa_abort_transaction(handle->scfhandle); 3894327Sdougm } 3904327Sdougm } 3913034Sdougm } 3923034Sdougm } 3933034Sdougm } 3943034Sdougm 3953034Sdougm /* 3963034Sdougm * is_shared(share) 3973034Sdougm * 3983034Sdougm * determine if the specified share is currently shared or not. 3993034Sdougm */ 4003034Sdougm static int 4013034Sdougm is_shared(sa_share_t share) 4023034Sdougm { 4033034Sdougm char *shared; 4043034Sdougm int result = 0; /* assume not */ 4053034Sdougm 4063034Sdougm shared = sa_get_share_attr(share, "shared"); 4073034Sdougm if (shared != NULL) { 4084327Sdougm if (strcmp(shared, "true") == 0) 4094327Sdougm result = 1; 4104327Sdougm sa_free_attr_string(shared); 4113034Sdougm } 4123034Sdougm return (result); 4133034Sdougm } 4143034Sdougm 4153034Sdougm /* 4165331Samw * excluded_protocol(share, proto) 4175331Samw * 4185331Samw * Returns B_TRUE if the specified protocol appears in the "exclude" 4195331Samw * property. This is used to prevent sharing special case shares 4205331Samw * (e.g. subdirs when SMB wants a subdir and NFS doesn't. B_FALSE is 4215331Samw * returned if the protocol isn't in the list. 4225331Samw */ 4235331Samw static boolean_t 4245331Samw excluded_protocol(sa_share_t share, char *proto) 4255331Samw { 4265331Samw char *protolist; 4275331Samw char *str; 4285331Samw char *token; 4295331Samw 4305331Samw protolist = sa_get_share_attr(share, "exclude"); 4315331Samw if (protolist != NULL) { 4325331Samw str = protolist; 4335331Samw while ((token = strtok(str, ",")) != NULL) { 4345331Samw if (strcmp(token, proto) == 0) { 4355331Samw sa_free_attr_string(protolist); 4365331Samw return (B_TRUE); 4375331Samw } 4385331Samw str = NULL; 4395331Samw } 4405331Samw sa_free_attr_string(protolist); 4415331Samw } 4425331Samw return (B_FALSE); 4435331Samw } 4445331Samw 4455331Samw /* 4463663Sdougm * checksubdirgroup(group, newpath, strictness) 4473348Sdougm * 4483663Sdougm * check all the specified newpath against all the paths in the 4493663Sdougm * group. This is a helper function for checksubdir to make it easier 4503663Sdougm * to also check ZFS subgroups. 4513663Sdougm * The strictness values mean: 4523348Sdougm * SA_CHECK_NORMAL == only check newpath against shares that are active 4533348Sdougm * SA_CHECK_STRICT == check newpath against both active shares and those 4543348Sdougm * stored in the repository 4553034Sdougm */ 4563034Sdougm static int 4573663Sdougm checksubdirgroup(sa_group_t group, char *newpath, int strictness) 4583034Sdougm { 4593034Sdougm sa_share_t share; 4603663Sdougm char *path; 4613663Sdougm int issub = SA_OK; 4625331Samw int subdir; 4635331Samw int parent; 4645331Samw 4655331Samw if (newpath == NULL) 4665331Samw return (SA_INVALID_PATH); 4673034Sdougm 4683663Sdougm for (share = sa_get_share(group, NULL); share != NULL; 4693663Sdougm share = sa_get_next_share(share)) { 4703034Sdougm /* 4713034Sdougm * The original behavior of share never checked 4723034Sdougm * against the permanent configuration 4733034Sdougm * (/etc/dfs/dfstab). PIT has a number of cases where 4743034Sdougm * it depends on this older behavior even though it 4753034Sdougm * could be considered incorrect. We may tighten this 4763034Sdougm * up in the future. 4773034Sdougm */ 4784327Sdougm if (strictness == SA_CHECK_NORMAL && !is_shared(share)) 4794327Sdougm continue; 4803034Sdougm 4814327Sdougm path = sa_get_share_attr(share, "path"); 4823348Sdougm /* 4833348Sdougm * If path is NULL, then a share is in the process of 4843348Sdougm * construction or someone has modified the property 4853663Sdougm * group inappropriately. It should be 4863663Sdougm * ignored. issubdir() comes from the original share 4873663Sdougm * implementation and does the difficult part of 4883663Sdougm * checking subdirectories. 4893348Sdougm */ 4904327Sdougm if (path == NULL) 4914327Sdougm continue; 4925331Samw 4935331Samw if (strcmp(path, newpath) == 0) { 4944327Sdougm issub = SA_INVALID_PATH; 4955331Samw } else { 4965331Samw subdir = issubdir(newpath, path); 4975331Samw parent = issubdir(path, newpath); 4985331Samw if (subdir || parent) { 4995331Samw sa_free_attr_string(path); 5005331Samw path = NULL; 5015331Samw return (subdir ? 5025331Samw SA_PATH_IS_SUBDIR : SA_PATH_IS_PARENTDIR); 5035331Samw } 5044327Sdougm } 5053034Sdougm sa_free_attr_string(path); 5063034Sdougm path = NULL; 5073663Sdougm } 5083663Sdougm return (issub); 5093663Sdougm } 5103663Sdougm 5113663Sdougm /* 5123663Sdougm * checksubdir(newpath, strictness) 5133663Sdougm * 5143663Sdougm * checksubdir determines if the specified path (newpath) is a 5153663Sdougm * subdirectory of another share. It calls checksubdirgroup() to do 5163663Sdougm * the complicated work. The strictness parameter determines how 5173663Sdougm * strict a check to make against the path. The strictness values 5183663Sdougm * mean: SA_CHECK_NORMAL == only check newpath against shares that are 5193663Sdougm * active SA_CHECK_STRICT == check newpath against both active shares 5203663Sdougm * and those * stored in the repository 5213663Sdougm */ 5223663Sdougm static int 5233910Sdougm checksubdir(sa_handle_t handle, char *newpath, int strictness) 5243663Sdougm { 5253663Sdougm sa_group_t group; 5265331Samw int issub = SA_OK; 5273663Sdougm char *path = NULL; 5283663Sdougm 5295331Samw for (group = sa_get_group(handle, NULL); 5305331Samw group != NULL && issub == SA_OK; 5315331Samw group = sa_get_next_group(group)) { 5324327Sdougm if (sa_group_is_zfs(group)) { 5334327Sdougm sa_group_t subgroup; 5344327Sdougm for (subgroup = sa_get_sub_group(group); 5355331Samw subgroup != NULL && issub == SA_OK; 5364327Sdougm subgroup = sa_get_next_group(subgroup)) 5374327Sdougm issub = checksubdirgroup(subgroup, newpath, 5384327Sdougm strictness); 5394327Sdougm } else { 5404327Sdougm issub = checksubdirgroup(group, newpath, strictness); 5414327Sdougm } 5423034Sdougm } 5433034Sdougm if (path != NULL) 5444327Sdougm sa_free_attr_string(path); 5453034Sdougm return (issub); 5463034Sdougm } 5473034Sdougm 5483034Sdougm /* 5493348Sdougm * validpath(path, strictness) 5503034Sdougm * determine if the provided path is valid for a share. It shouldn't 5513034Sdougm * be a sub-dir of an already shared path or the parent directory of a 5523034Sdougm * share path. 5533034Sdougm */ 5543034Sdougm static int 5553910Sdougm validpath(sa_handle_t handle, char *path, int strictness) 5563034Sdougm { 5573034Sdougm int error = SA_OK; 5583034Sdougm struct stat st; 5593034Sdougm sa_share_t share; 5603034Sdougm char *fstype; 5613034Sdougm 5624327Sdougm if (*path != '/') 5634327Sdougm return (SA_BAD_PATH); 5644327Sdougm 5653034Sdougm if (stat(path, &st) < 0) { 5664327Sdougm error = SA_NO_SUCH_PATH; 5673034Sdougm } else { 5684327Sdougm share = sa_find_share(handle, path); 5694327Sdougm if (share != NULL) 5704327Sdougm error = SA_DUPLICATE_NAME; 5714327Sdougm 5724327Sdougm if (error == SA_OK) { 5734327Sdougm /* 5744327Sdougm * check for special case with file system 5754327Sdougm * that might have restrictions. For now, ZFS 5764327Sdougm * is the only case since it has its own idea 5774327Sdougm * of how to configure shares. We do this 5784327Sdougm * before subdir checking since things like 5794327Sdougm * ZFS will do that for us. This should also 5804327Sdougm * be done via plugin interface. 5814327Sdougm */ 5824327Sdougm fstype = sa_fstype(path); 5834327Sdougm if (fstype != NULL && strcmp(fstype, "zfs") == 0) { 5844327Sdougm if (sa_zfs_is_shared(handle, path)) 5854327Sdougm error = SA_INVALID_NAME; 5864327Sdougm } 5874327Sdougm if (fstype != NULL) 5884327Sdougm sa_free_fstype(fstype); 5893034Sdougm } 5904327Sdougm if (error == SA_OK) 5914327Sdougm error = checksubdir(handle, path, strictness); 5923034Sdougm } 5933034Sdougm return (error); 5943034Sdougm } 5953034Sdougm 5963034Sdougm /* 5973034Sdougm * check to see if group/share is persistent. 5985331Samw * 5995331Samw * "group" can be either an sa_group_t or an sa_share_t. (void *) 6005331Samw * works since both thse types are also void *. 60112508Samw@Sun.COM * If the share is a ZFS share, mark it as persistent. 6023034Sdougm */ 6035331Samw int 6045331Samw sa_is_persistent(void *group) 6053034Sdougm { 6063034Sdougm char *type; 6073034Sdougm int persist = 1; 60812508Samw@Sun.COM sa_group_t grp; 6093034Sdougm 6105331Samw type = sa_get_group_attr((sa_group_t)group, "type"); 61112508Samw@Sun.COM if (type != NULL) { 61212508Samw@Sun.COM if (strcmp(type, "transient") == 0) 61312508Samw@Sun.COM persist = 0; 6144327Sdougm sa_free_attr_string(type); 61512508Samw@Sun.COM } 61612508Samw@Sun.COM 61712508Samw@Sun.COM grp = (sa_is_share(group)) ? sa_get_parent_group(group) : group; 61812508Samw@Sun.COM if (sa_group_is_zfs(grp)) 61912508Samw@Sun.COM persist = 1; 62012508Samw@Sun.COM 6213034Sdougm return (persist); 6223034Sdougm } 6233034Sdougm 6243034Sdougm /* 6253034Sdougm * sa_valid_group_name(name) 6263034Sdougm * 6273034Sdougm * check that the "name" contains only valid characters and otherwise 6283034Sdougm * fits the required naming conventions. Valid names must start with 6293034Sdougm * an alphabetic and the remainder may consist of only alphanumeric 6303034Sdougm * plus the '-' and '_' characters. This name limitation comes from 6313034Sdougm * inherent limitations in SMF. 6323034Sdougm */ 6333034Sdougm 6343034Sdougm int 6353034Sdougm sa_valid_group_name(char *name) 6363034Sdougm { 6373034Sdougm int ret = 1; 6383034Sdougm ssize_t len; 6393034Sdougm 6403034Sdougm if (name != NULL && isalpha(*name)) { 6414327Sdougm char c; 6424327Sdougm len = strlen(name); 6434327Sdougm if (len < (scf_max_name_len - sizeof ("group:"))) { 6444327Sdougm for (c = *name++; c != '\0' && ret != 0; c = *name++) { 6454327Sdougm if (!isalnum(c) && c != '-' && c != '_') 6464327Sdougm ret = 0; 6474327Sdougm } 6484327Sdougm } else { 6493034Sdougm ret = 0; 6503034Sdougm } 6514327Sdougm } else { 6523034Sdougm ret = 0; 6533034Sdougm } 6543034Sdougm return (ret); 6553034Sdougm } 6563034Sdougm 6573034Sdougm 6583034Sdougm /* 6593034Sdougm * is_zfs_group(group) 6603034Sdougm * Determine if the specified group is a ZFS sharenfs group 6613034Sdougm */ 6623034Sdougm static int 6633034Sdougm is_zfs_group(sa_group_t group) 6643034Sdougm { 6653034Sdougm int ret = 0; 6663034Sdougm xmlNodePtr parent; 6673034Sdougm xmlChar *zfs; 6683034Sdougm 6694327Sdougm if (strcmp((char *)((xmlNodePtr)group)->name, "share") == 0) 6704327Sdougm parent = (xmlNodePtr)sa_get_parent_group(group); 6714327Sdougm else 6724327Sdougm parent = (xmlNodePtr)group; 6733034Sdougm zfs = xmlGetProp(parent, (xmlChar *)"zfs"); 6743034Sdougm if (zfs != NULL) { 6754327Sdougm xmlFree(zfs); 6764327Sdougm ret = 1; 6773034Sdougm } 6783034Sdougm return (ret); 6793034Sdougm } 6803034Sdougm 6813034Sdougm /* 6825331Samw * sa_get_object_type(object) 6835331Samw * 6845331Samw * This function returns a numeric value representing the object 6855331Samw * type. This allows using simpler checks when doing type specific 6865331Samw * operations. 6875331Samw */ 6885331Samw 6895331Samw static int 6905331Samw sa_get_object_type(void *object) 6915331Samw { 6925331Samw xmlNodePtr node = (xmlNodePtr)object; 6935331Samw int type; 6945331Samw 6955331Samw if (xmlStrcmp(node->name, (xmlChar *)"group") == 0) 6965331Samw type = SA_TYPE_GROUP; 6975331Samw else if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) 6985331Samw type = SA_TYPE_SHARE; 6995331Samw else if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0) 7005331Samw type = SA_TYPE_RESOURCE; 7015331Samw else if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) 7025331Samw type = SA_TYPE_OPTIONSET; 7035331Samw else if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) 7045331Samw type = SA_TYPE_ALTSPACE; 7055331Samw else 7065331Samw assert(0); 7075331Samw return (type); 7085331Samw } 7095331Samw 7105331Samw /* 7113034Sdougm * sa_optionset_name(optionset, oname, len, id) 7123034Sdougm * return the SMF name for the optionset. If id is not NULL, it 7133034Sdougm * will have the GUID value for a share and should be used 7143034Sdougm * instead of the keyword "optionset" which is used for 7153034Sdougm * groups. If the optionset doesn't have a protocol type 7163034Sdougm * associated with it, "default" is used. This shouldn't happen 7173034Sdougm * at this point but may be desirable in the future if there are 7183034Sdougm * protocol independent properties added. The name is returned in 7193034Sdougm * oname. 7203034Sdougm */ 7213034Sdougm 7223034Sdougm static int 7233034Sdougm sa_optionset_name(sa_optionset_t optionset, char *oname, size_t len, char *id) 7243034Sdougm { 7253034Sdougm char *proto; 7265331Samw void *parent; 7275331Samw int ptype; 7283034Sdougm 7293034Sdougm if (id == NULL) 7304327Sdougm id = "optionset"; 7313034Sdougm 7325331Samw parent = sa_get_optionset_parent(optionset); 7335331Samw if (parent != NULL) { 7345331Samw ptype = sa_get_object_type(parent); 7355331Samw proto = sa_get_optionset_attr(optionset, "type"); 7365331Samw if (ptype != SA_TYPE_RESOURCE) { 7375331Samw len = snprintf(oname, len, "%s_%s", id, 7385331Samw proto ? proto : "default"); 7395331Samw } else { 7405331Samw char *index; 7415331Samw index = get_node_attr((void *)parent, "id"); 74211337SWilliam.Krier@Sun.COM if (index != NULL) { 7435331Samw len = snprintf(oname, len, "%s_%s_%s", id, 7445331Samw proto ? proto : "default", index); 74511337SWilliam.Krier@Sun.COM sa_free_attr_string(index); 74611337SWilliam.Krier@Sun.COM } else { 7475331Samw len = 0; 74811337SWilliam.Krier@Sun.COM } 7495331Samw } 7505331Samw 7515331Samw if (proto != NULL) 7525331Samw sa_free_attr_string(proto); 7535331Samw } else { 7545331Samw len = 0; 7555331Samw } 7563034Sdougm return (len); 7573034Sdougm } 7583034Sdougm 7593034Sdougm /* 7603034Sdougm * sa_security_name(optionset, oname, len, id) 7613034Sdougm * 7623034Sdougm * return the SMF name for the security. If id is not NULL, it will 7633034Sdougm * have the GUID value for a share and should be used instead of the 7643034Sdougm * keyword "optionset" which is used for groups. If the optionset 7653034Sdougm * doesn't have a protocol type associated with it, "default" is 7663034Sdougm * used. This shouldn't happen at this point but may be desirable in 7673034Sdougm * the future if there are protocol independent properties added. The 7683034Sdougm * name is returned in oname. The security type is also encoded into 7693034Sdougm * the name. In the future, this wil *be handled a bit differently. 7703034Sdougm */ 7713034Sdougm 7723034Sdougm static int 7733034Sdougm sa_security_name(sa_security_t security, char *oname, size_t len, char *id) 7743034Sdougm { 7753034Sdougm char *proto; 7763034Sdougm char *sectype; 7773034Sdougm 7783034Sdougm if (id == NULL) 7794327Sdougm id = "optionset"; 7803034Sdougm 7813034Sdougm proto = sa_get_security_attr(security, "type"); 7823034Sdougm sectype = sa_get_security_attr(security, "sectype"); 7834327Sdougm len = snprintf(oname, len, "%s_%s_%s", id, proto ? proto : "default", 7844327Sdougm sectype ? sectype : "default"); 7853034Sdougm if (proto != NULL) 7864327Sdougm sa_free_attr_string(proto); 7873034Sdougm if (sectype != NULL) 7884327Sdougm sa_free_attr_string(sectype); 7893034Sdougm return (len); 7903034Sdougm } 7913034Sdougm 7923034Sdougm /* 7934327Sdougm * verifydefgroupopts(handle) 7944327Sdougm * 7954327Sdougm * Make sure a "default" group exists and has default protocols enabled. 7964327Sdougm */ 7974327Sdougm static void 7984327Sdougm verifydefgroupopts(sa_handle_t handle) 7994327Sdougm { 8004327Sdougm sa_group_t defgrp; 8014327Sdougm sa_optionset_t opt; 8025331Samw 8034327Sdougm defgrp = sa_get_group(handle, "default"); 8044327Sdougm if (defgrp != NULL) { 8054327Sdougm opt = sa_get_optionset(defgrp, NULL); 8064327Sdougm /* 8074327Sdougm * NFS is the default for default group 8084327Sdougm */ 8094327Sdougm if (opt == NULL) 8104327Sdougm opt = sa_create_optionset(defgrp, "nfs"); 8114327Sdougm } 8124327Sdougm } 8134327Sdougm 8144327Sdougm /* 8153348Sdougm * sa_init(init_service) 8163034Sdougm * Initialize the API 8173034Sdougm * find all the shared objects 8183034Sdougm * init the tables with all objects 8193034Sdougm * read in the current configuration 8203034Sdougm */ 8213034Sdougm 8224327Sdougm #define GETPROP(prop) scf_simple_prop_next_astring(prop) 8234327Sdougm #define CHECKTSTAMP(st, tval) stat(SA_LEGACY_DFSTAB, &st) >= 0 && \ 8244327Sdougm tval != TSTAMP(st.st_ctim) 8254327Sdougm 8263910Sdougm sa_handle_t 8273034Sdougm sa_init(int init_service) 8283034Sdougm { 8293034Sdougm struct stat st; 8303034Sdougm int legacy = 0; 8313034Sdougm uint64_t tval = 0; 8323663Sdougm int lockfd; 8333663Sdougm sigset_t old; 8343663Sdougm int updatelegacy = B_FALSE; 8353663Sdougm scf_simple_prop_t *prop; 8363910Sdougm sa_handle_impl_t handle; 8373910Sdougm int err; 8383034Sdougm 8393910Sdougm handle = calloc(sizeof (struct sa_handle_impl), 1); 8403910Sdougm 8413910Sdougm if (handle != NULL) { 8426304Sdougm /* 8436304Sdougm * Get protocol specific structures, but only if this 8446304Sdougm * is the only handle. 8456304Sdougm */ 8466304Sdougm (void) mutex_lock(&sa_global_lock); 8476304Sdougm if (sa_global_handles == NULL) 8486304Sdougm (void) proto_plugin_init(); 8496304Sdougm (void) mutex_unlock(&sa_global_lock); 8504327Sdougm if (init_service & SA_INIT_SHARE_API) { 8513663Sdougm /* 8524327Sdougm * initialize access into libzfs. We use this 8534327Sdougm * when collecting info about ZFS datasets and 8544327Sdougm * shares. 8553663Sdougm */ 8564327Sdougm if (sa_zfs_init(handle) == B_FALSE) { 8574327Sdougm free(handle); 8588474SJose.Borrego@Sun.COM (void) mutex_lock(&sa_global_lock); 8594327Sdougm (void) proto_plugin_fini(); 8608474SJose.Borrego@Sun.COM (void) mutex_unlock(&sa_global_lock); 8614327Sdougm return (NULL); 8624327Sdougm } 8633663Sdougm /* 8644327Sdougm * since we want to use SMF, initialize an svc handle 8654327Sdougm * and find out what is there. 8663663Sdougm */ 8674327Sdougm handle->scfhandle = sa_scf_init(handle); 8684327Sdougm if (handle->scfhandle != NULL) { 8694327Sdougm /* 8704327Sdougm * Need to lock the extraction of the 8714327Sdougm * configuration if the dfstab file has 8724327Sdougm * changed. Lock everything now and release if 8734327Sdougm * not needed. Use a file that isn't being 8744327Sdougm * manipulated by other parts of the system in 8754327Sdougm * order to not interfere with locking. Using 8764327Sdougm * dfstab doesn't work. 8774327Sdougm */ 8784327Sdougm sablocksigs(&old); 8794327Sdougm lockfd = open(DFS_LOCK_FILE, O_RDWR); 8804327Sdougm if (lockfd >= 0) { 8814327Sdougm extern int errno; 8824327Sdougm errno = 0; 8834327Sdougm (void) lockf(lockfd, F_LOCK, 0); 88412508Samw@Sun.COM (void) mutex_lock(&sa_dfstab_lock); 8854327Sdougm /* 8864327Sdougm * Check whether we are going to need 8874327Sdougm * to merge any dfstab changes. This 8884327Sdougm * is done by comparing the value of 8894327Sdougm * legacy-timestamp with the current 8904327Sdougm * st_ctim of the file. If they are 8914327Sdougm * different, an update is needed and 8924327Sdougm * the file must remain locked until 8934327Sdougm * the merge is done in order to 8944327Sdougm * prevent multiple startups from 8954327Sdougm * changing the SMF repository at the 8964327Sdougm * same time. The first to get the 8974327Sdougm * lock will make any changes before 8984327Sdougm * the others can read the repository. 8994327Sdougm */ 9004327Sdougm prop = scf_simple_prop_get 9014327Sdougm (handle->scfhandle->handle, 9024327Sdougm (const char *)SA_SVC_FMRI_BASE 9034327Sdougm ":default", "operation", 9044327Sdougm "legacy-timestamp"); 9054327Sdougm if (prop != NULL) { 9064327Sdougm char *i64; 9074327Sdougm i64 = GETPROP(prop); 9084327Sdougm if (i64 != NULL) 9094327Sdougm tval = strtoull(i64, 9104327Sdougm NULL, 0); 9114327Sdougm if (CHECKTSTAMP(st, tval)) 9124327Sdougm updatelegacy = B_TRUE; 9134327Sdougm scf_simple_prop_free(prop); 9144327Sdougm } else { 9154327Sdougm /* 9164327Sdougm * We haven't set the 9174327Sdougm * timestamp before so do it. 9184327Sdougm */ 9194327Sdougm updatelegacy = B_TRUE; 9204327Sdougm } 92112508Samw@Sun.COM if (updatelegacy == B_FALSE) { 92212508Samw@Sun.COM (void) mutex_unlock( 92312508Samw@Sun.COM &sa_dfstab_lock); 92412508Samw@Sun.COM (void) lockf(lockfd, F_ULOCK, 92512508Samw@Sun.COM 0); 92612508Samw@Sun.COM (void) close(lockfd); 92712508Samw@Sun.COM } 92812508Samw@Sun.COM 9294327Sdougm } 9304327Sdougm /* 9314327Sdougm * It is essential that the document tree and 9324327Sdougm * the internal list of roots to handles be 9334327Sdougm * setup before anything that might try to 9344327Sdougm * create a new object is called. The document 9354327Sdougm * tree is the combination of handle->doc and 9364327Sdougm * handle->tree. This allows searches, 9374327Sdougm * etc. when all you have is an object in the 9384327Sdougm * tree. 9394327Sdougm */ 9404327Sdougm handle->doc = xmlNewDoc((xmlChar *)"1.0"); 9414327Sdougm handle->tree = xmlNewNode(NULL, 9424327Sdougm (xmlChar *)"sharecfg"); 9434327Sdougm if (handle->doc != NULL && 9444327Sdougm handle->tree != NULL) { 9456007Sthurlow (void) xmlDocSetRootElement(handle->doc, 9464327Sdougm handle->tree); 9474327Sdougm err = add_handle_for_root(handle->tree, 9484327Sdougm handle); 9494327Sdougm if (err == SA_OK) 9504327Sdougm err = sa_get_config( 9514327Sdougm handle->scfhandle, 9523973Sdougm handle->tree, handle); 9534327Sdougm } else { 9544327Sdougm if (handle->doc != NULL) 9554327Sdougm xmlFreeDoc(handle->doc); 9564327Sdougm if (handle->tree != NULL) 9574327Sdougm xmlFreeNode(handle->tree); 9584327Sdougm err = SA_NO_MEMORY; 9594327Sdougm } 9603973Sdougm 9614327Sdougm saunblocksigs(&old); 9623910Sdougm 9634327Sdougm if (err != SA_OK) { 9644327Sdougm /* 9654327Sdougm * If we couldn't add the tree handle 9664327Sdougm * to the list, then things are going 9674327Sdougm * to fail badly. Might as well undo 9684327Sdougm * everything now and fail the 9694327Sdougm * sa_init(). 9704327Sdougm */ 9714327Sdougm sa_fini(handle); 97212508Samw@Sun.COM if (updatelegacy == B_TRUE) { 97312508Samw@Sun.COM (void) mutex_unlock( 97412508Samw@Sun.COM &sa_dfstab_lock); 97512508Samw@Sun.COM (void) lockf(lockfd, 97612508Samw@Sun.COM F_ULOCK, 0); 97712508Samw@Sun.COM (void) close(lockfd); 97812508Samw@Sun.COM } 9794327Sdougm return (NULL); 9804327Sdougm } 9813910Sdougm 9824327Sdougm if (tval == 0) { 9834327Sdougm /* 9844327Sdougm * first time so make sure 9854327Sdougm * default is setup 9864327Sdougm */ 9874327Sdougm verifydefgroupopts(handle); 9884327Sdougm } 9893973Sdougm 9904524Sdougm if (updatelegacy == B_TRUE) { 9914524Sdougm sablocksigs(&old); 9924524Sdougm getlegacyconfig((sa_handle_t)handle, 9934524Sdougm SA_LEGACY_DFSTAB, &handle->tree); 9944524Sdougm if (stat(SA_LEGACY_DFSTAB, &st) >= 0) 9954524Sdougm set_legacy_timestamp( 9964524Sdougm handle->tree, 9974524Sdougm SA_LEGACY_DFSTAB, 9984524Sdougm TSTAMP(st.st_ctim)); 9994524Sdougm saunblocksigs(&old); 10004524Sdougm /* 10014524Sdougm * Safe to unlock now to allow 10024524Sdougm * others to run 10034524Sdougm */ 100412508Samw@Sun.COM (void) mutex_unlock(&sa_dfstab_lock); 10054524Sdougm (void) lockf(lockfd, F_ULOCK, 0); 10064524Sdougm (void) close(lockfd); 10074524Sdougm } 10085951Sdougm /* Get sharetab timestamp */ 10095951Sdougm sa_update_sharetab_ts((sa_handle_t)handle); 10105951Sdougm 10115951Sdougm /* Get lastupdate (transaction) timestamp */ 10125951Sdougm prop = scf_simple_prop_get( 10135951Sdougm handle->scfhandle->handle, 10145951Sdougm (const char *)SA_SVC_FMRI_BASE ":default", 10155951Sdougm "state", "lastupdate"); 10165951Sdougm if (prop != NULL) { 10175951Sdougm char *str; 10185951Sdougm str = 10195951Sdougm scf_simple_prop_next_astring(prop); 10205951Sdougm if (str != NULL) 10215951Sdougm handle->tstrans = 10225951Sdougm strtoull(str, NULL, 0); 10235951Sdougm else 10245951Sdougm handle->tstrans = 0; 10255951Sdougm scf_simple_prop_free(prop); 10265951Sdougm } 10274524Sdougm legacy |= sa_get_zfs_shares(handle, "zfs"); 10284524Sdougm legacy |= gettransients(handle, &handle->tree); 10294327Sdougm } 10304327Sdougm } 10313034Sdougm } 10323910Sdougm return ((sa_handle_t)handle); 10333034Sdougm } 10343034Sdougm 10353034Sdougm /* 10363910Sdougm * sa_fini(handle) 10373034Sdougm * Uninitialize the API structures including the configuration 10383218Sdougm * data structures and ZFS related data. 10393034Sdougm */ 10403034Sdougm 10413034Sdougm void 10423910Sdougm sa_fini(sa_handle_t handle) 10433034Sdougm { 10443910Sdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle; 10453910Sdougm 10463910Sdougm if (impl_handle != NULL) { 10473910Sdougm /* 10483910Sdougm * Free the config trees and any other data structures 10493910Sdougm * used in the handle. 10503910Sdougm */ 10513910Sdougm if (impl_handle->doc != NULL) 10523910Sdougm xmlFreeDoc(impl_handle->doc); 10533910Sdougm 10543910Sdougm /* Remove and free the entry in the global list. */ 10553910Sdougm remove_handle_for_root(impl_handle->tree); 10563910Sdougm 10573910Sdougm /* 10583910Sdougm * If this was the last handle to release, unload the 10596304Sdougm * plugins that were loaded. Use a mutex in case 10606304Sdougm * another thread is reinitializing. 10613910Sdougm */ 10626304Sdougm (void) mutex_lock(&sa_global_lock); 10633910Sdougm if (sa_global_handles == NULL) 10644327Sdougm (void) proto_plugin_fini(); 10656304Sdougm (void) mutex_unlock(&sa_global_lock); 10663910Sdougm 10677010Sgwr sa_scf_fini(impl_handle->scfhandle); 10687010Sgwr sa_zfs_fini(impl_handle); 10697010Sgwr 10707010Sgwr /* Make sure we free the handle */ 10717010Sgwr free(impl_handle); 10727010Sgwr 10733034Sdougm } 10743034Sdougm } 10753034Sdougm 10763034Sdougm /* 10773034Sdougm * sa_get_protocols(char **protocol) 10783034Sdougm * Get array of protocols that are supported 10793034Sdougm * Returns pointer to an allocated and NULL terminated 10803034Sdougm * array of strings. Caller must free. 10813034Sdougm * This really should be determined dynamically. 10823034Sdougm * If there aren't any defined, return -1. 10833034Sdougm * Use free() to return memory. 10843034Sdougm */ 10853034Sdougm 10863034Sdougm int 10873034Sdougm sa_get_protocols(char ***protocols) 10883034Sdougm { 10893034Sdougm int numproto = -1; 10903034Sdougm 10913034Sdougm if (protocols != NULL) { 10924327Sdougm struct sa_proto_plugin *plug; 10934327Sdougm for (numproto = 0, plug = sap_proto_list; plug != NULL; 10944327Sdougm plug = plug->plugin_next) { 10954327Sdougm numproto++; 10964327Sdougm } 10973034Sdougm 10984327Sdougm *protocols = calloc(numproto + 1, sizeof (char *)); 10994327Sdougm if (*protocols != NULL) { 11004327Sdougm int ret = 0; 11014327Sdougm for (plug = sap_proto_list; plug != NULL; 11024327Sdougm plug = plug->plugin_next) { 11034327Sdougm /* faking for now */ 11044327Sdougm (*protocols)[ret++] = 11054327Sdougm plug->plugin_ops->sa_protocol; 11064327Sdougm } 11074327Sdougm } else { 11084327Sdougm numproto = -1; 11093034Sdougm } 11103034Sdougm } 11113034Sdougm return (numproto); 11123034Sdougm } 11133034Sdougm 11143034Sdougm /* 11153034Sdougm * find_group_by_name(node, group) 11163034Sdougm * 11173034Sdougm * search the XML document subtree specified by node to find the group 11183034Sdougm * specified by group. Searching subtree allows subgroups to be 11193034Sdougm * searched for. 11203034Sdougm */ 11213034Sdougm 11223034Sdougm static xmlNodePtr 11233034Sdougm find_group_by_name(xmlNodePtr node, xmlChar *group) 11243034Sdougm { 11253034Sdougm xmlChar *name = NULL; 11263034Sdougm 11273034Sdougm for (node = node->xmlChildrenNode; node != NULL; 11283034Sdougm node = node->next) { 11294327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"group") == 0) { 11304327Sdougm /* if no groupname, return the first found */ 11314327Sdougm if (group == NULL) 11324327Sdougm break; 11334327Sdougm name = xmlGetProp(node, (xmlChar *)"name"); 11344327Sdougm if (name != NULL && xmlStrcmp(name, group) == 0) 11354327Sdougm break; 11364327Sdougm if (name != NULL) { 11374327Sdougm xmlFree(name); 11384327Sdougm name = NULL; 11394327Sdougm } 11403034Sdougm } 11413034Sdougm } 11423034Sdougm if (name != NULL) 11434327Sdougm xmlFree(name); 11443034Sdougm return (node); 11453034Sdougm } 11463034Sdougm 11473034Sdougm /* 11483034Sdougm * sa_get_group(groupname) 11493034Sdougm * Return the "group" specified. If groupname is NULL, 11503034Sdougm * return the first group of the list of groups. 11513034Sdougm */ 11523034Sdougm sa_group_t 11533910Sdougm sa_get_group(sa_handle_t handle, char *groupname) 11543034Sdougm { 11553034Sdougm xmlNodePtr node = NULL; 11563034Sdougm char *subgroup = NULL; 11573034Sdougm char *group = NULL; 11583910Sdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle; 11593034Sdougm 11603910Sdougm if (impl_handle != NULL && impl_handle->tree != NULL) { 11614327Sdougm if (groupname != NULL) { 11624327Sdougm group = strdup(groupname); 11634345Sdougm if (group != NULL) { 11644345Sdougm subgroup = strchr(group, '/'); 11654345Sdougm if (subgroup != NULL) 11664345Sdougm *subgroup++ = '\0'; 11674345Sdougm } 11684327Sdougm } 11694345Sdougm /* 11704345Sdougm * We want to find the, possibly, named group. If 11714345Sdougm * group is not NULL, then lookup the name. If it is 11724345Sdougm * NULL, we only do the find if groupname is also 11734345Sdougm * NULL. This allows lookup of the "first" group in 11744345Sdougm * the internal list. 11754345Sdougm */ 11764345Sdougm if (group != NULL || groupname == NULL) 11774345Sdougm node = find_group_by_name(impl_handle->tree, 11784345Sdougm (xmlChar *)group); 11794345Sdougm 11804327Sdougm /* if a subgroup, find it before returning */ 11814327Sdougm if (subgroup != NULL && node != NULL) 11824327Sdougm node = find_group_by_name(node, (xmlChar *)subgroup); 11833034Sdougm } 11843034Sdougm if (node != NULL && (char *)group != NULL) 11854327Sdougm (void) sa_get_instance(impl_handle->scfhandle, (char *)group); 11863034Sdougm if (group != NULL) 11874327Sdougm free(group); 11883034Sdougm return ((sa_group_t)(node)); 11893034Sdougm } 11903034Sdougm 11913034Sdougm /* 11923034Sdougm * sa_get_next_group(group) 11933034Sdougm * Return the "next" group after the specified group from 11943034Sdougm * the internal group list. NULL if there are no more. 11953034Sdougm */ 11963034Sdougm sa_group_t 11973034Sdougm sa_get_next_group(sa_group_t group) 11983034Sdougm { 11993034Sdougm xmlNodePtr ngroup = NULL; 12003034Sdougm if (group != NULL) { 12014327Sdougm for (ngroup = ((xmlNodePtr)group)->next; ngroup != NULL; 12023034Sdougm ngroup = ngroup->next) { 12034327Sdougm if (xmlStrcmp(ngroup->name, (xmlChar *)"group") == 0) 12044327Sdougm break; 12054327Sdougm } 12063034Sdougm } 12073034Sdougm return ((sa_group_t)ngroup); 12083034Sdougm } 12093034Sdougm 12103034Sdougm /* 12113034Sdougm * sa_get_share(group, sharepath) 12123034Sdougm * Return the share object for the share specified. The share 12133034Sdougm * must be in the specified group. Return NULL if not found. 12143034Sdougm */ 12153034Sdougm sa_share_t 12163034Sdougm sa_get_share(sa_group_t group, char *sharepath) 12173034Sdougm { 12183034Sdougm xmlNodePtr node = NULL; 12193034Sdougm xmlChar *path; 12203034Sdougm 12213034Sdougm /* 12223034Sdougm * For future scalability, this should end up building a cache 12233034Sdougm * since it will get called regularly by the mountd and info 12243034Sdougm * services. 12253034Sdougm */ 12263034Sdougm if (group != NULL) { 12274327Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 12283034Sdougm node = node->next) { 12294327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) { 12304327Sdougm if (sharepath == NULL) { 12314327Sdougm break; 12324327Sdougm } else { 12334327Sdougm /* is it the correct share? */ 12344327Sdougm path = xmlGetProp(node, 12354327Sdougm (xmlChar *)"path"); 12364327Sdougm if (path != NULL && 12374327Sdougm xmlStrcmp(path, 12384327Sdougm (xmlChar *)sharepath) == 0) { 12394327Sdougm xmlFree(path); 12404327Sdougm break; 12414327Sdougm } 12424327Sdougm xmlFree(path); 12434327Sdougm } 12443034Sdougm } 12453034Sdougm } 12463034Sdougm } 12473034Sdougm return ((sa_share_t)node); 12483034Sdougm } 12493034Sdougm 12503034Sdougm /* 12513034Sdougm * sa_get_next_share(share) 12523034Sdougm * Return the next share following the specified share 12533034Sdougm * from the internal list of shares. Returns NULL if there 12543034Sdougm * are no more shares. The list is relative to the same 12553034Sdougm * group. 12563034Sdougm */ 12573034Sdougm sa_share_t 12583034Sdougm sa_get_next_share(sa_share_t share) 12593034Sdougm { 12603034Sdougm xmlNodePtr node = NULL; 12613034Sdougm 12623034Sdougm if (share != NULL) { 12634327Sdougm for (node = ((xmlNodePtr)share)->next; node != NULL; 12643034Sdougm node = node->next) { 12654327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) { 12664327Sdougm break; 12674327Sdougm } 12683034Sdougm } 12693034Sdougm } 12703034Sdougm return ((sa_share_t)node); 12713034Sdougm } 12723034Sdougm 12733034Sdougm /* 12743034Sdougm * _sa_get_child_node(node, type) 12753034Sdougm * 12763034Sdougm * find the child node of the specified node that has "type". This is 12773034Sdougm * used to implement several internal functions. 12783034Sdougm */ 12793034Sdougm 12803034Sdougm static xmlNodePtr 12813034Sdougm _sa_get_child_node(xmlNodePtr node, xmlChar *type) 12823034Sdougm { 12833034Sdougm xmlNodePtr child; 12843034Sdougm for (child = node->xmlChildrenNode; child != NULL; 12853034Sdougm child = child->next) 12864327Sdougm if (xmlStrcmp(child->name, type) == 0) 12874327Sdougm return (child); 12883034Sdougm return ((xmlNodePtr)NULL); 12893034Sdougm } 12903034Sdougm 12913034Sdougm /* 12923034Sdougm * find_share(group, path) 12933034Sdougm * 12943034Sdougm * Search all the shares in the specified group for one that has the 12953034Sdougm * specified path. 12963034Sdougm */ 12973034Sdougm 12983034Sdougm static sa_share_t 12993034Sdougm find_share(sa_group_t group, char *sharepath) 13003034Sdougm { 13013034Sdougm sa_share_t share; 13023034Sdougm char *path; 13033034Sdougm 13043034Sdougm for (share = sa_get_share(group, NULL); share != NULL; 13053034Sdougm share = sa_get_next_share(share)) { 13064327Sdougm path = sa_get_share_attr(share, "path"); 13074327Sdougm if (path != NULL && strcmp(path, sharepath) == 0) { 13084327Sdougm sa_free_attr_string(path); 13094327Sdougm break; 13104327Sdougm } 13114327Sdougm if (path != NULL) 13124327Sdougm sa_free_attr_string(path); 13133034Sdougm } 13143034Sdougm return (share); 13153034Sdougm } 13163034Sdougm 13173034Sdougm /* 13183034Sdougm * sa_get_sub_group(group) 13193034Sdougm * 13203034Sdougm * Get the first sub-group of group. The sa_get_next_group() function 13213034Sdougm * can be used to get the rest. This is currently only used for ZFS 13223034Sdougm * sub-groups but could be used to implement a more general mechanism. 13233034Sdougm */ 13243034Sdougm 13253034Sdougm sa_group_t 13263034Sdougm sa_get_sub_group(sa_group_t group) 13273034Sdougm { 13283034Sdougm return ((sa_group_t)_sa_get_child_node((xmlNodePtr)group, 13294327Sdougm (xmlChar *)"group")); 13303034Sdougm } 13313034Sdougm 13323034Sdougm /* 13333034Sdougm * sa_find_share(sharepath) 13343034Sdougm * Finds a share regardless of group. In the future, this 13353034Sdougm * function should utilize a cache and hash table of some kind. 13363034Sdougm * The current assumption is that a path will only be shared 13373034Sdougm * once. In the future, this may change as implementation of 13383034Sdougm * resource names comes into being. 13393034Sdougm */ 13403034Sdougm sa_share_t 13413910Sdougm sa_find_share(sa_handle_t handle, char *sharepath) 13423034Sdougm { 13433034Sdougm sa_group_t group; 13443034Sdougm sa_group_t zgroup; 13453034Sdougm sa_share_t share = NULL; 13463034Sdougm int done = 0; 13473034Sdougm 13483910Sdougm for (group = sa_get_group(handle, NULL); group != NULL && !done; 13494327Sdougm group = sa_get_next_group(group)) { 13504327Sdougm if (is_zfs_group(group)) { 13514327Sdougm for (zgroup = 13524327Sdougm (sa_group_t)_sa_get_child_node((xmlNodePtr)group, 13534327Sdougm (xmlChar *)"group"); 13544327Sdougm zgroup != NULL; 13554327Sdougm zgroup = sa_get_next_group(zgroup)) { 13564327Sdougm share = find_share(zgroup, sharepath); 13574327Sdougm if (share != NULL) 13584327Sdougm break; 13594327Sdougm } 13604327Sdougm } else { 13614327Sdougm share = find_share(group, sharepath); 13624327Sdougm } 13634327Sdougm if (share != NULL) 13643034Sdougm break; 13653034Sdougm } 13663034Sdougm return (share); 13673034Sdougm } 13683034Sdougm 13693034Sdougm /* 13703348Sdougm * sa_check_path(group, path, strictness) 13713034Sdougm * 13725331Samw * Check that path is a valid path relative to the group. Currently, 13733034Sdougm * we are ignoring the group and checking only the NFS rules. Later, 13743034Sdougm * we may want to use the group to then check against the protocols 13753348Sdougm * enabled on the group. The strictness values mean: 13763348Sdougm * SA_CHECK_NORMAL == only check newpath against shares that are active 13773348Sdougm * SA_CHECK_STRICT == check newpath against both active shares and those 13783348Sdougm * stored in the repository 13793034Sdougm */ 13803034Sdougm 13813034Sdougm int 13823348Sdougm sa_check_path(sa_group_t group, char *path, int strictness) 13833034Sdougm { 13843910Sdougm sa_handle_t handle; 13853910Sdougm 13863910Sdougm handle = sa_find_group_handle(group); 138711963SAfshin.Ardakani@Sun.COM if (handle == NULL) 138811963SAfshin.Ardakani@Sun.COM return (SA_BAD_PATH); 138911963SAfshin.Ardakani@Sun.COM 13903910Sdougm return (validpath(handle, path, strictness)); 13913034Sdougm } 13923034Sdougm 13933034Sdougm /* 13945331Samw * mark_excluded_protos(group, share, flags) 13953034Sdougm * 13965331Samw * Walk through all the protocols enabled for the group and check to 13975331Samw * see if the share has any of them should be in the exclude list 13985331Samw * based on the featureset of the protocol. If there are any, add the 13995331Samw * "exclude" property to the share. 14005331Samw */ 14015331Samw static void 14025331Samw mark_excluded_protos(sa_group_t group, xmlNodePtr share, uint64_t flags) 14035331Samw { 14045331Samw sa_optionset_t optionset; 14055331Samw char exclude_list[SA_STRSIZE]; 14065331Samw char *sep = ""; 14075331Samw 14085331Samw exclude_list[0] = '\0'; 14095331Samw for (optionset = sa_get_optionset(group, NULL); 14105331Samw optionset != NULL; 14115331Samw optionset = sa_get_next_optionset(optionset)) { 14125331Samw char *value; 14135331Samw uint64_t features; 14145331Samw value = sa_get_optionset_attr(optionset, "type"); 14155331Samw if (value == NULL) 14165331Samw continue; 14175331Samw features = sa_proto_get_featureset(value); 14185331Samw if (!(features & flags)) { 14195331Samw (void) strlcat(exclude_list, sep, 14205331Samw sizeof (exclude_list)); 14215331Samw (void) strlcat(exclude_list, value, 14225331Samw sizeof (exclude_list)); 14235331Samw sep = ","; 14245331Samw } 142511337SWilliam.Krier@Sun.COM sa_free_attr_string(value); 14265331Samw } 14275331Samw if (exclude_list[0] != '\0') 14286007Sthurlow (void) xmlSetProp(share, (xmlChar *)"exclude", 14295331Samw (xmlChar *)exclude_list); 14305331Samw } 14315331Samw 14325331Samw /* 14335331Samw * get_all_features(group) 14345331Samw * 14355331Samw * Walk through all the protocols on the group and collect all 14365331Samw * possible enabled features. This is the OR of all the featuresets. 14375331Samw */ 14385331Samw static uint64_t 14395331Samw get_all_features(sa_group_t group) 14405331Samw { 14415331Samw sa_optionset_t optionset; 14425331Samw uint64_t features = 0; 14435331Samw 14445331Samw for (optionset = sa_get_optionset(group, NULL); 14455331Samw optionset != NULL; 14465331Samw optionset = sa_get_next_optionset(optionset)) { 14475331Samw char *value; 14485331Samw value = sa_get_optionset_attr(optionset, "type"); 14495331Samw if (value == NULL) 14505331Samw continue; 14515331Samw features |= sa_proto_get_featureset(value); 14525331Samw sa_free_attr_string(value); 14535331Samw } 14545331Samw return (features); 14555331Samw } 14565331Samw 14575331Samw 14585331Samw /* 14595331Samw * _sa_add_share(group, sharepath, persist, *error, flags) 14605331Samw * 14615331Samw * Common code for all types of add_share. sa_add_share() is the 14623034Sdougm * public API, we also need to be able to do this when parsing legacy 14633034Sdougm * files and construction of the internal configuration while 14645331Samw * extracting config info from SMF. "flags" indicates if some 14655331Samw * protocols need relaxed rules while other don't. These values are 14665331Samw * the featureset values defined in libshare.h. 14673034Sdougm */ 14683034Sdougm 14693034Sdougm sa_share_t 14705331Samw _sa_add_share(sa_group_t group, char *sharepath, int persist, int *error, 14715331Samw uint64_t flags) 14723034Sdougm { 14733034Sdougm xmlNodePtr node = NULL; 14743034Sdougm int err; 14753034Sdougm 14763034Sdougm err = SA_OK; /* assume success */ 14773034Sdougm 14784327Sdougm node = xmlNewChild((xmlNodePtr)group, NULL, (xmlChar *)"share", NULL); 14795331Samw if (node == NULL) { 14805331Samw if (error != NULL) 14815331Samw *error = SA_NO_MEMORY; 14825331Samw return (node); 14835331Samw } 14845331Samw 14856007Sthurlow (void) xmlSetProp(node, (xmlChar *)"path", (xmlChar *)sharepath); 14866007Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", 14875331Samw persist ? (xmlChar *)"persist" : (xmlChar *)"transient"); 14885331Samw if (flags != 0) 14895331Samw mark_excluded_protos(group, node, flags); 14905331Samw if (persist != SA_SHARE_TRANSIENT) { 14915331Samw /* 14925331Samw * persistent shares come in two flavors: SMF and 14935331Samw * ZFS. Sort this one out based on target group and 14945331Samw * path type. Both NFS and SMB are supported. First, 14955331Samw * check to see if the protocol is enabled on the 14965331Samw * subgroup and then setup the share appropriately. 14975331Samw */ 14985331Samw if (sa_group_is_zfs(group) && 14995331Samw sa_path_is_zfs(sharepath)) { 15005331Samw if (sa_get_optionset(group, "nfs") != NULL) 15014327Sdougm err = sa_zfs_set_sharenfs(group, sharepath, 1); 15025331Samw else if (sa_get_optionset(group, "smb") != NULL) 15035331Samw err = sa_zfs_set_sharesmb(group, sharepath, 1); 15045331Samw } else { 15055331Samw sa_handle_impl_t impl_handle; 15065331Samw impl_handle = 15075331Samw (sa_handle_impl_t)sa_find_group_handle(group); 15085331Samw if (impl_handle != NULL) { 15095331Samw err = sa_commit_share(impl_handle->scfhandle, 15105331Samw group, (sa_share_t)node); 15114327Sdougm } else { 15125331Samw err = SA_SYSTEM_ERR; 15134327Sdougm } 15143034Sdougm } 15153034Sdougm } 15165331Samw if (err == SA_NO_PERMISSION && persist & SA_SHARE_PARSER) 15175331Samw /* called by the dfstab parser so could be a show */ 15185331Samw err = SA_OK; 15195331Samw 15205331Samw if (err != SA_OK) { 15215331Samw /* 15225331Samw * we couldn't commit to the repository so undo 15235331Samw * our internal state to reflect reality. 15245331Samw */ 15255331Samw xmlUnlinkNode(node); 15265331Samw xmlFreeNode(node); 15275331Samw node = NULL; 15285331Samw } 15295331Samw 15303034Sdougm if (error != NULL) 15314327Sdougm *error = err; 15325331Samw 15333034Sdougm return (node); 15343034Sdougm } 15353034Sdougm 15363034Sdougm /* 15373034Sdougm * sa_add_share(group, sharepath, persist, *error) 15383034Sdougm * 15393034Sdougm * Add a new share object to the specified group. The share will 15403034Sdougm * have the specified sharepath and will only be constructed if 15413034Sdougm * it is a valid path to be shared. NULL is returned on error 15423034Sdougm * and a detailed error value will be returned via the error 15433034Sdougm * pointer. 15443034Sdougm */ 15453034Sdougm sa_share_t 15463034Sdougm sa_add_share(sa_group_t group, char *sharepath, int persist, int *error) 15473034Sdougm { 15483034Sdougm xmlNodePtr node = NULL; 15493348Sdougm int strictness = SA_CHECK_NORMAL; 15503910Sdougm sa_handle_t handle; 15515331Samw uint64_t special = 0; 15525331Samw uint64_t features; 15533348Sdougm 15543348Sdougm /* 15553348Sdougm * If the share is to be permanent, use strict checking so a 15563348Sdougm * bad config doesn't get created. Transient shares only need 15573348Sdougm * to check against the currently active 15583348Sdougm * shares. SA_SHARE_PARSER is a modifier used internally to 15593348Sdougm * indicate that we are being called by the dfstab parser and 15603348Sdougm * that we need strict checking in all cases. Normally persist 15613348Sdougm * is in integer value but SA_SHARE_PARSER may be or'd into 15623348Sdougm * it as an override. 15633348Sdougm */ 15643348Sdougm if (persist & SA_SHARE_PARSER || persist == SA_SHARE_PERMANENT) 15654327Sdougm strictness = SA_CHECK_STRICT; 15663034Sdougm 15673910Sdougm handle = sa_find_group_handle(group); 15683910Sdougm 15695331Samw /* 15705331Samw * need to determine if the share is valid. The rules are: 15715331Samw * - The path must not already exist 15725331Samw * - The path must not be a subdir or parent dir of an 15735331Samw * existing path unless at least one protocol allows it. 15745331Samw * The sub/parent check is done in sa_check_path(). 15755331Samw */ 15765331Samw 15775331Samw if (sa_find_share(handle, sharepath) == NULL) { 15785331Samw *error = sa_check_path(group, sharepath, strictness); 15795331Samw features = get_all_features(group); 15805331Samw switch (*error) { 15815331Samw case SA_PATH_IS_SUBDIR: 15825331Samw if (features & SA_FEATURE_ALLOWSUBDIRS) 15835331Samw special |= SA_FEATURE_ALLOWSUBDIRS; 15845331Samw break; 15855331Samw case SA_PATH_IS_PARENTDIR: 15865331Samw if (features & SA_FEATURE_ALLOWPARDIRS) 15875331Samw special |= SA_FEATURE_ALLOWPARDIRS; 15885331Samw break; 15895331Samw } 15905331Samw if (*error == SA_OK || special != SA_FEATURE_NONE) 15915331Samw node = _sa_add_share(group, sharepath, persist, 15925331Samw error, special); 15935331Samw } else { 15945331Samw *error = SA_DUPLICATE_NAME; 15953034Sdougm } 15963034Sdougm 15973034Sdougm return ((sa_share_t)node); 15983034Sdougm } 15993034Sdougm 16003034Sdougm /* 16013034Sdougm * sa_enable_share(share, protocol) 16023034Sdougm * Enable the specified share to the specified protocol. 16033034Sdougm * If protocol is NULL, then all protocols. 16043034Sdougm */ 16053034Sdougm int 16063034Sdougm sa_enable_share(sa_share_t share, char *protocol) 16073034Sdougm { 16083034Sdougm char *sharepath; 16093034Sdougm struct stat st; 16105331Samw int err = SA_OK; 16115331Samw int ret; 16123034Sdougm 16133034Sdougm sharepath = sa_get_share_attr(share, "path"); 16145331Samw if (sharepath == NULL) 16155331Samw return (SA_NO_MEMORY); 16163034Sdougm if (stat(sharepath, &st) < 0) { 16174327Sdougm err = SA_NO_SUCH_PATH; 16183034Sdougm } else { 16194327Sdougm /* tell the server about the share */ 16204327Sdougm if (protocol != NULL) { 16215331Samw if (excluded_protocol(share, protocol)) 16225331Samw goto done; 16235331Samw 16244327Sdougm /* lookup protocol specific handler */ 16254327Sdougm err = sa_proto_share(protocol, share); 16264327Sdougm if (err == SA_OK) 16275331Samw (void) sa_set_share_attr(share, 16285331Samw "shared", "true"); 16294327Sdougm } else { 16305331Samw /* Tell all protocols about the share */ 16315331Samw sa_group_t group; 16325331Samw sa_optionset_t optionset; 16335331Samw 16345331Samw group = sa_get_parent_group(share); 16355331Samw 16365331Samw for (optionset = sa_get_optionset(group, NULL); 16375331Samw optionset != NULL; 16385331Samw optionset = sa_get_next_optionset(optionset)) { 16395331Samw char *proto; 16405331Samw proto = sa_get_optionset_attr(optionset, 16415331Samw "type"); 16425331Samw if (proto != NULL) { 16435331Samw if (!excluded_protocol(share, proto)) { 16445331Samw ret = sa_proto_share(proto, 16455331Samw share); 16465331Samw if (ret != SA_OK) 16475331Samw err = ret; 16485331Samw } 16495331Samw sa_free_attr_string(proto); 16505331Samw } 16515331Samw } 16524327Sdougm (void) sa_set_share_attr(share, "shared", "true"); 16534327Sdougm } 16543034Sdougm } 16555331Samw done: 16563034Sdougm if (sharepath != NULL) 16574327Sdougm sa_free_attr_string(sharepath); 16583034Sdougm return (err); 16593034Sdougm } 16603034Sdougm 16613034Sdougm /* 16623034Sdougm * sa_disable_share(share, protocol) 16635331Samw * Disable the specified share to the specified protocol. If 16645331Samw * protocol is NULL, then all protocols that are enabled for the 16655331Samw * share should be disabled. 16663034Sdougm */ 16673034Sdougm int 16683034Sdougm sa_disable_share(sa_share_t share, char *protocol) 16693034Sdougm { 16703034Sdougm char *path; 16715331Samw int err = SA_OK; 16723034Sdougm int ret = SA_OK; 16733034Sdougm 16743034Sdougm path = sa_get_share_attr(share, "path"); 16753034Sdougm 16763034Sdougm if (protocol != NULL) { 16774543Smarks ret = sa_proto_unshare(share, protocol, path); 16783034Sdougm } else { 16794327Sdougm /* need to do all protocols */ 16805331Samw sa_group_t group; 16815331Samw sa_optionset_t optionset; 16825331Samw 16835331Samw group = sa_get_parent_group(share); 16845331Samw 16855331Samw /* Tell all protocols about the share */ 16865331Samw for (optionset = sa_get_optionset(group, NULL); 16875331Samw optionset != NULL; 16885331Samw optionset = sa_get_next_optionset(optionset)) { 16895331Samw char *proto; 16905331Samw 16915331Samw proto = sa_get_optionset_attr(optionset, "type"); 16925331Samw if (proto != NULL) { 16935331Samw err = sa_proto_unshare(share, proto, path); 16945331Samw if (err != SA_OK) 16955331Samw ret = err; 16965331Samw sa_free_attr_string(proto); 16975331Samw } 16985331Samw } 16993034Sdougm } 17003034Sdougm if (ret == SA_OK) 17013034Sdougm (void) sa_set_share_attr(share, "shared", NULL); 17023034Sdougm if (path != NULL) 17034327Sdougm sa_free_attr_string(path); 17043034Sdougm return (ret); 17053034Sdougm } 17063034Sdougm 17073034Sdougm /* 17083034Sdougm * sa_remove_share(share) 17093034Sdougm * 17103034Sdougm * remove the specified share from its containing group. 17113034Sdougm * Remove from the SMF or ZFS configuration space. 17123034Sdougm */ 17133034Sdougm 17143034Sdougm int 17153034Sdougm sa_remove_share(sa_share_t share) 17163034Sdougm { 17173034Sdougm sa_group_t group; 17183034Sdougm int ret = SA_OK; 17193034Sdougm char *type; 17203034Sdougm int transient = 0; 17213034Sdougm char *groupname; 17223034Sdougm char *zfs; 17233034Sdougm 17243034Sdougm type = sa_get_share_attr(share, "type"); 17253034Sdougm group = sa_get_parent_group(share); 17263034Sdougm zfs = sa_get_group_attr(group, "zfs"); 17273034Sdougm groupname = sa_get_group_attr(group, "name"); 17283034Sdougm if (type != NULL && strcmp(type, "persist") != 0) 17294327Sdougm transient = 1; 17303034Sdougm if (type != NULL) 17314327Sdougm sa_free_attr_string(type); 17323034Sdougm 17333034Sdougm /* remove the node from its group then free the memory */ 17343034Sdougm 17353034Sdougm /* 17363034Sdougm * need to test if "busy" 17373034Sdougm */ 17383034Sdougm /* only do SMF action if permanent */ 17393034Sdougm if (!transient || zfs != NULL) { 17404327Sdougm /* remove from legacy dfstab as well as possible SMF */ 17415331Samw ret = sa_delete_legacy(share, NULL); 17424327Sdougm if (ret == SA_OK) { 17434327Sdougm if (!sa_group_is_zfs(group)) { 17444327Sdougm sa_handle_impl_t impl_handle; 17454327Sdougm impl_handle = (sa_handle_impl_t) 17464327Sdougm sa_find_group_handle(group); 17474327Sdougm if (impl_handle != NULL) { 17484327Sdougm ret = sa_delete_share( 17494327Sdougm impl_handle->scfhandle, group, 17504327Sdougm share); 17514327Sdougm } else { 17524327Sdougm ret = SA_SYSTEM_ERR; 17534327Sdougm } 17544327Sdougm } else { 17554327Sdougm char *sharepath = sa_get_share_attr(share, 17564327Sdougm "path"); 17574327Sdougm if (sharepath != NULL) { 17584327Sdougm ret = sa_zfs_set_sharenfs(group, 17594327Sdougm sharepath, 0); 17604327Sdougm sa_free_attr_string(sharepath); 17614327Sdougm } 17624327Sdougm } 17633034Sdougm } 17643034Sdougm } 17653034Sdougm if (groupname != NULL) 17664327Sdougm sa_free_attr_string(groupname); 17673034Sdougm if (zfs != NULL) 17684327Sdougm sa_free_attr_string(zfs); 17693034Sdougm 17703034Sdougm xmlUnlinkNode((xmlNodePtr)share); 17713034Sdougm xmlFreeNode((xmlNodePtr)share); 17723034Sdougm return (ret); 17733034Sdougm } 17743034Sdougm 17753034Sdougm /* 17763034Sdougm * sa_move_share(group, share) 17773034Sdougm * 17783034Sdougm * move the specified share to the specified group. Update SMF 17793034Sdougm * appropriately. 17803034Sdougm */ 17813034Sdougm 17823034Sdougm int 17833034Sdougm sa_move_share(sa_group_t group, sa_share_t share) 17843034Sdougm { 17853034Sdougm sa_group_t oldgroup; 17863034Sdougm int ret = SA_OK; 17873034Sdougm 17883034Sdougm /* remove the node from its group then free the memory */ 17893034Sdougm 17903034Sdougm oldgroup = sa_get_parent_group(share); 17913034Sdougm if (oldgroup != group) { 17924327Sdougm sa_handle_impl_t impl_handle; 17934327Sdougm xmlUnlinkNode((xmlNodePtr)share); 17943034Sdougm /* 17954327Sdougm * now that the share isn't in its old group, add to 17964327Sdougm * the new one 17973034Sdougm */ 17986007Sthurlow (void) xmlAddChild((xmlNodePtr)group, (xmlNodePtr)share); 17994327Sdougm /* need to deal with SMF */ 18004327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 18014327Sdougm if (impl_handle != NULL) { 18024327Sdougm /* 18034327Sdougm * need to remove from old group first and then add to 18044327Sdougm * new group. Ideally, we would do the other order but 18054327Sdougm * need to avoid having the share in two groups at the 18064327Sdougm * same time. 18074327Sdougm */ 18084327Sdougm ret = sa_delete_share(impl_handle->scfhandle, oldgroup, 18094327Sdougm share); 18104327Sdougm if (ret == SA_OK) 18114327Sdougm ret = sa_commit_share(impl_handle->scfhandle, 18124327Sdougm group, share); 18134327Sdougm } else { 18144327Sdougm ret = SA_SYSTEM_ERR; 18154327Sdougm } 18163034Sdougm } 18173034Sdougm return (ret); 18183034Sdougm } 18193034Sdougm 18203034Sdougm /* 18213034Sdougm * sa_get_parent_group(share) 18223034Sdougm * 18235331Samw * Return the containing group for the share. If a group was actually 18243034Sdougm * passed in, we don't want a parent so return NULL. 18253034Sdougm */ 18263034Sdougm 18273034Sdougm sa_group_t 18283034Sdougm sa_get_parent_group(sa_share_t share) 18293034Sdougm { 18303034Sdougm xmlNodePtr node = NULL; 18313034Sdougm if (share != NULL) { 18324327Sdougm node = ((xmlNodePtr)share)->parent; 18333034Sdougm /* 18343034Sdougm * make sure parent is a group and not sharecfg since 18353034Sdougm * we may be cheating and passing in a group. 18363034Sdougm * Eventually, groups of groups might come into being. 18373034Sdougm */ 18384327Sdougm if (node == NULL || 18394327Sdougm xmlStrcmp(node->name, (xmlChar *)"sharecfg") == 0) 18404327Sdougm node = NULL; 18413034Sdougm } 18423034Sdougm return ((sa_group_t)node); 18433034Sdougm } 18443034Sdougm 18453034Sdougm /* 18463910Sdougm * _sa_create_group(impl_handle, groupname) 18473034Sdougm * 18483034Sdougm * Create a group in the document. The caller will need to deal with 18493034Sdougm * configuration store and activation. 18503034Sdougm */ 18513034Sdougm 18523034Sdougm sa_group_t 18533910Sdougm _sa_create_group(sa_handle_impl_t impl_handle, char *groupname) 18543034Sdougm { 18553034Sdougm xmlNodePtr node = NULL; 18563034Sdougm 18573034Sdougm if (sa_valid_group_name(groupname)) { 18584327Sdougm node = xmlNewChild(impl_handle->tree, NULL, (xmlChar *)"group", 18594327Sdougm NULL); 18604327Sdougm if (node != NULL) { 18616007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 18624327Sdougm (xmlChar *)groupname); 18636007Sthurlow (void) xmlSetProp(node, (xmlChar *)"state", 18644327Sdougm (xmlChar *)"enabled"); 18654327Sdougm } 18663034Sdougm } 18673034Sdougm return ((sa_group_t)node); 18683034Sdougm } 18693034Sdougm 18703034Sdougm /* 18713034Sdougm * _sa_create_zfs_group(group, groupname) 18723034Sdougm * 18733034Sdougm * Create a ZFS subgroup under the specified group. This may 18743034Sdougm * eventually form the basis of general sub-groups, but is currently 18753034Sdougm * restricted to ZFS. 18763034Sdougm */ 18773034Sdougm sa_group_t 18783034Sdougm _sa_create_zfs_group(sa_group_t group, char *groupname) 18793034Sdougm { 18803034Sdougm xmlNodePtr node = NULL; 18813034Sdougm 18824327Sdougm node = xmlNewChild((xmlNodePtr)group, NULL, (xmlChar *)"group", NULL); 18833034Sdougm if (node != NULL) { 18846007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 18856007Sthurlow (xmlChar *)groupname); 18866007Sthurlow (void) xmlSetProp(node, (xmlChar *)"state", 18876007Sthurlow (xmlChar *)"enabled"); 18883034Sdougm } 18893034Sdougm 18903034Sdougm return ((sa_group_t)node); 18913034Sdougm } 18923034Sdougm 18933034Sdougm /* 18943034Sdougm * sa_create_group(groupname, *error) 18953034Sdougm * 18963034Sdougm * Create a new group with groupname. Need to validate that it is a 18973034Sdougm * legal name for SMF and the construct the SMF service instance of 18983034Sdougm * svc:/network/shares/group to implement the group. All necessary 18993034Sdougm * operational properties must be added to the group at this point 19003034Sdougm * (via the SMF transaction model). 19013034Sdougm */ 19023034Sdougm sa_group_t 19033910Sdougm sa_create_group(sa_handle_t handle, char *groupname, int *error) 19043034Sdougm { 19053034Sdougm xmlNodePtr node = NULL; 19063034Sdougm sa_group_t group; 19073034Sdougm int ret; 19084327Sdougm char rbacstr[SA_STRSIZE]; 19093910Sdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle; 19103034Sdougm 19113034Sdougm ret = SA_OK; 19123034Sdougm 19133910Sdougm if (impl_handle == NULL || impl_handle->scfhandle == NULL) { 19144327Sdougm ret = SA_SYSTEM_ERR; 19154327Sdougm goto err; 19163034Sdougm } 19173034Sdougm 19183910Sdougm group = sa_get_group(handle, groupname); 19193034Sdougm if (group != NULL) { 19204327Sdougm ret = SA_DUPLICATE_NAME; 19213034Sdougm } else { 19224327Sdougm if (sa_valid_group_name(groupname)) { 19234327Sdougm node = xmlNewChild(impl_handle->tree, NULL, 19244327Sdougm (xmlChar *)"group", NULL); 19254327Sdougm if (node != NULL) { 19266007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 19274327Sdougm (xmlChar *)groupname); 19284327Sdougm /* default to the group being enabled */ 19296007Sthurlow (void) xmlSetProp(node, (xmlChar *)"state", 19304327Sdougm (xmlChar *)"enabled"); 19314327Sdougm ret = sa_create_instance(impl_handle->scfhandle, 19324327Sdougm groupname); 19334327Sdougm if (ret == SA_OK) { 19344327Sdougm ret = sa_start_transaction( 19354327Sdougm impl_handle->scfhandle, 19364327Sdougm "operation"); 19374327Sdougm } 19384327Sdougm if (ret == SA_OK) { 19394327Sdougm ret = sa_set_property( 19404327Sdougm impl_handle->scfhandle, 19414327Sdougm "state", "enabled"); 19424327Sdougm if (ret == SA_OK) { 19434327Sdougm ret = sa_end_transaction( 19445951Sdougm impl_handle->scfhandle, 19455951Sdougm impl_handle); 19464327Sdougm } else { 19474327Sdougm sa_abort_transaction( 19484327Sdougm impl_handle->scfhandle); 19494327Sdougm } 19504327Sdougm } 19514327Sdougm if (ret == SA_OK) { 19524327Sdougm /* initialize the RBAC strings */ 19534327Sdougm ret = sa_start_transaction( 19544327Sdougm impl_handle->scfhandle, 19554327Sdougm "general"); 19564327Sdougm if (ret == SA_OK) { 19574327Sdougm (void) snprintf(rbacstr, 19584327Sdougm sizeof (rbacstr), "%s.%s", 19594327Sdougm SA_RBAC_MANAGE, groupname); 19604327Sdougm ret = sa_set_property( 19614327Sdougm impl_handle->scfhandle, 19623034Sdougm "action_authorization", 19633034Sdougm rbacstr); 19644327Sdougm } 19654327Sdougm if (ret == SA_OK) { 19664327Sdougm (void) snprintf(rbacstr, 19674327Sdougm sizeof (rbacstr), "%s.%s", 19684327Sdougm SA_RBAC_VALUE, groupname); 19694327Sdougm ret = sa_set_property( 19704327Sdougm impl_handle->scfhandle, 19713034Sdougm "value_authorization", 19723034Sdougm rbacstr); 19734327Sdougm } 19744327Sdougm if (ret == SA_OK) { 19754327Sdougm ret = sa_end_transaction( 19765951Sdougm impl_handle->scfhandle, 19775951Sdougm impl_handle); 19784327Sdougm } else { 19794327Sdougm sa_abort_transaction( 19804327Sdougm impl_handle->scfhandle); 19814327Sdougm } 19824327Sdougm } 19834327Sdougm if (ret != SA_OK) { 19844327Sdougm /* 19854327Sdougm * Couldn't commit the group 19864327Sdougm * so we need to undo 19874327Sdougm * internally. 19884327Sdougm */ 19894327Sdougm xmlUnlinkNode(node); 19904327Sdougm xmlFreeNode(node); 19914327Sdougm node = NULL; 19924327Sdougm } 19933034Sdougm } else { 19944327Sdougm ret = SA_NO_MEMORY; 19953034Sdougm } 19963034Sdougm } else { 19974327Sdougm ret = SA_INVALID_NAME; 19983034Sdougm } 19993034Sdougm } 20003034Sdougm err: 20013034Sdougm if (error != NULL) 20024327Sdougm *error = ret; 20033034Sdougm return ((sa_group_t)node); 20043034Sdougm } 20053034Sdougm 20063034Sdougm /* 20073034Sdougm * sa_remove_group(group) 20083034Sdougm * 20093034Sdougm * Remove the specified group. This deletes from the SMF repository. 20103034Sdougm * All property groups and properties are removed. 20113034Sdougm */ 20123034Sdougm 20133034Sdougm int 20143034Sdougm sa_remove_group(sa_group_t group) 20153034Sdougm { 20163034Sdougm char *name; 20173034Sdougm int ret = SA_OK; 20183910Sdougm sa_handle_impl_t impl_handle; 20193034Sdougm 20203910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 20213910Sdougm if (impl_handle != NULL) { 20224327Sdougm name = sa_get_group_attr(group, "name"); 20234327Sdougm if (name != NULL) { 20244327Sdougm ret = sa_delete_instance(impl_handle->scfhandle, name); 20254327Sdougm sa_free_attr_string(name); 20264327Sdougm } 20274327Sdougm xmlUnlinkNode((xmlNodePtr)group); /* make sure unlinked */ 20284327Sdougm xmlFreeNode((xmlNodePtr)group); /* now it is gone */ 20293910Sdougm } else { 20304327Sdougm ret = SA_SYSTEM_ERR; 20313034Sdougm } 20323034Sdougm return (ret); 20333034Sdougm } 20343034Sdougm 20353034Sdougm /* 20363034Sdougm * sa_update_config() 20373034Sdougm * 20383034Sdougm * Used to update legacy files that need to be updated in bulk 20393034Sdougm * Currently, this is a placeholder and will go away in a future 20403034Sdougm * release. 20413034Sdougm */ 20423034Sdougm 20433034Sdougm int 20443910Sdougm sa_update_config(sa_handle_t handle) 20453034Sdougm { 20463034Sdougm /* 20473034Sdougm * do legacy files first so we can tell when they change. 20483034Sdougm * This will go away when we start updating individual records 20493034Sdougm * rather than the whole file. 20503034Sdougm */ 20513910Sdougm update_legacy_config(handle); 20523034Sdougm return (SA_OK); 20533034Sdougm } 20543034Sdougm 20553034Sdougm /* 20563034Sdougm * get_node_attr(node, tag) 20573034Sdougm * 20585331Samw * Get the specified tag(attribute) if it exists on the node. This is 20593034Sdougm * used internally by a number of attribute oriented functions. 20603034Sdougm */ 20613034Sdougm 20623034Sdougm static char * 20633034Sdougm get_node_attr(void *nodehdl, char *tag) 20643034Sdougm { 20653034Sdougm xmlNodePtr node = (xmlNodePtr)nodehdl; 20663034Sdougm xmlChar *name = NULL; 20673034Sdougm 20684327Sdougm if (node != NULL) 20693034Sdougm name = xmlGetProp(node, (xmlChar *)tag); 20703034Sdougm return ((char *)name); 20713034Sdougm } 20723034Sdougm 20733034Sdougm /* 207411337SWilliam.Krier@Sun.COM * set_node_attr(node, tag) 20753034Sdougm * 20765331Samw * Set the specified tag(attribute) to the specified value This is 20773034Sdougm * used internally by a number of attribute oriented functions. It 20783034Sdougm * doesn't update the repository, only the internal document state. 20793034Sdougm */ 20803034Sdougm 20813034Sdougm void 20823034Sdougm set_node_attr(void *nodehdl, char *tag, char *value) 20833034Sdougm { 20843034Sdougm xmlNodePtr node = (xmlNodePtr)nodehdl; 20853034Sdougm if (node != NULL && tag != NULL) { 20864327Sdougm if (value != NULL) 20876007Sthurlow (void) xmlSetProp(node, (xmlChar *)tag, 20886007Sthurlow (xmlChar *)value); 20894327Sdougm else 20906007Sthurlow (void) xmlUnsetProp(node, (xmlChar *)tag); 20913034Sdougm } 20923034Sdougm } 20933034Sdougm 20943034Sdougm /* 20953034Sdougm * sa_get_group_attr(group, tag) 20963034Sdougm * 20973034Sdougm * Get the specied attribute, if defined, for the group. 20983034Sdougm */ 20993034Sdougm 21003034Sdougm char * 21013034Sdougm sa_get_group_attr(sa_group_t group, char *tag) 21023034Sdougm { 21033034Sdougm return (get_node_attr((void *)group, tag)); 21043034Sdougm } 21053034Sdougm 21063034Sdougm /* 21073034Sdougm * sa_set_group_attr(group, tag, value) 21083034Sdougm * 21093034Sdougm * set the specified tag/attribute on the group using value as its 21103034Sdougm * value. 21113034Sdougm * 21123034Sdougm * This will result in setting the property in the SMF repository as 21133034Sdougm * well as in the internal document. 21143034Sdougm */ 21153034Sdougm 21163034Sdougm int 21173034Sdougm sa_set_group_attr(sa_group_t group, char *tag, char *value) 21183034Sdougm { 21193034Sdougm int ret; 21203034Sdougm char *groupname; 21213910Sdougm sa_handle_impl_t impl_handle; 21223034Sdougm 21235331Samw /* 21245331Samw * ZFS group/subgroup doesn't need the handle so shortcut. 21255331Samw */ 21265331Samw if (sa_group_is_zfs(group)) { 21275331Samw set_node_attr((void *)group, tag, value); 21285331Samw return (SA_OK); 21295331Samw } 21305331Samw 21313910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 21323910Sdougm if (impl_handle != NULL) { 21334327Sdougm groupname = sa_get_group_attr(group, "name"); 21344327Sdougm ret = sa_get_instance(impl_handle->scfhandle, groupname); 21353910Sdougm if (ret == SA_OK) { 21364327Sdougm set_node_attr((void *)group, tag, value); 21374327Sdougm ret = sa_start_transaction(impl_handle->scfhandle, 21384327Sdougm "operation"); 21394327Sdougm if (ret == SA_OK) { 21404327Sdougm ret = sa_set_property(impl_handle->scfhandle, 21414327Sdougm tag, value); 21424327Sdougm if (ret == SA_OK) 21435885Sdougm ret = sa_end_transaction( 21445951Sdougm impl_handle->scfhandle, 21455951Sdougm impl_handle); 21464327Sdougm else 21474327Sdougm sa_abort_transaction( 21484327Sdougm impl_handle->scfhandle); 21494327Sdougm } 21505885Sdougm if (ret == SA_SYSTEM_ERR) 21515885Sdougm ret = SA_NO_PERMISSION; 21523034Sdougm } 21534327Sdougm if (groupname != NULL) 21544327Sdougm sa_free_attr_string(groupname); 21553910Sdougm } else { 21564327Sdougm ret = SA_SYSTEM_ERR; 21573034Sdougm } 21583034Sdougm return (ret); 21593034Sdougm } 21603034Sdougm 21613034Sdougm /* 21623034Sdougm * sa_get_share_attr(share, tag) 21633034Sdougm * 21643034Sdougm * Return the value of the tag/attribute set on the specified 21653034Sdougm * share. Returns NULL if the tag doesn't exist. 21663034Sdougm */ 21673034Sdougm 21683034Sdougm char * 21693034Sdougm sa_get_share_attr(sa_share_t share, char *tag) 21703034Sdougm { 21713034Sdougm return (get_node_attr((void *)share, tag)); 21723034Sdougm } 21733034Sdougm 21743034Sdougm /* 21753034Sdougm * _sa_set_share_description(share, description) 21763034Sdougm * 21775331Samw * Add a description tag with text contents to the specified share. A 21785331Samw * separate XML tag is used rather than a property. This can also be 21795331Samw * used with resources. 21803034Sdougm */ 21813034Sdougm 21823034Sdougm xmlNodePtr 21835331Samw _sa_set_share_description(void *share, char *content) 21843034Sdougm { 21853034Sdougm xmlNodePtr node; 21864327Sdougm node = xmlNewChild((xmlNodePtr)share, NULL, (xmlChar *)"description", 21874327Sdougm NULL); 21883034Sdougm xmlNodeSetContent(node, (xmlChar *)content); 21893034Sdougm return (node); 21903034Sdougm } 21913034Sdougm 21923034Sdougm /* 21933034Sdougm * sa_set_share_attr(share, tag, value) 21943034Sdougm * 21953034Sdougm * Set the share attribute specified by tag to the specified value. In 21963034Sdougm * the case of "resource", enforce a no duplicates in a group rule. If 21973034Sdougm * the share is not transient, commit the changes to the repository 21983034Sdougm * else just update the share internally. 21993034Sdougm */ 22003034Sdougm 22013034Sdougm int 22023034Sdougm sa_set_share_attr(sa_share_t share, char *tag, char *value) 22033034Sdougm { 22043034Sdougm sa_group_t group; 22053034Sdougm sa_share_t resource; 22063034Sdougm int ret = SA_OK; 22073034Sdougm 22083034Sdougm group = sa_get_parent_group(share); 22093034Sdougm 22103034Sdougm /* 22113034Sdougm * There are some attributes that may have specific 22123034Sdougm * restrictions on them. Initially, only "resource" has 22133034Sdougm * special meaning that needs to be checked. Only one instance 22143034Sdougm * of a resource name may exist within a group. 22153034Sdougm */ 22163034Sdougm 22173034Sdougm if (strcmp(tag, "resource") == 0) { 22184327Sdougm resource = sa_get_resource(group, value); 22194327Sdougm if (resource != share && resource != NULL) 22204327Sdougm ret = SA_DUPLICATE_NAME; 22213034Sdougm } 22223034Sdougm if (ret == SA_OK) { 22234327Sdougm set_node_attr((void *)share, tag, value); 22244327Sdougm if (group != NULL) { 22254327Sdougm char *type; 22264327Sdougm /* we can probably optimize this some */ 22274327Sdougm type = sa_get_share_attr(share, "type"); 22284327Sdougm if (type == NULL || strcmp(type, "transient") != 0) { 22294327Sdougm sa_handle_impl_t impl_handle; 22304327Sdougm impl_handle = 22314327Sdougm (sa_handle_impl_t)sa_find_group_handle( 22324327Sdougm group); 22334327Sdougm if (impl_handle != NULL) { 22344327Sdougm ret = sa_commit_share( 22354327Sdougm impl_handle->scfhandle, group, 22364327Sdougm share); 22374327Sdougm } else { 22384327Sdougm ret = SA_SYSTEM_ERR; 22394327Sdougm } 22404327Sdougm } 22414327Sdougm if (type != NULL) 22424327Sdougm sa_free_attr_string(type); 22433910Sdougm } 22443034Sdougm } 22453034Sdougm return (ret); 22463034Sdougm } 22473034Sdougm 22483034Sdougm /* 22493034Sdougm * sa_get_property_attr(prop, tag) 22503034Sdougm * 22513034Sdougm * Get the value of the specified property attribute. Standard 22523034Sdougm * attributes are "type" and "value". 22533034Sdougm */ 22543034Sdougm 22553034Sdougm char * 22563034Sdougm sa_get_property_attr(sa_property_t prop, char *tag) 22573034Sdougm { 22583034Sdougm return (get_node_attr((void *)prop, tag)); 22593034Sdougm } 22603034Sdougm 22613034Sdougm /* 22623034Sdougm * sa_get_optionset_attr(prop, tag) 22633034Sdougm * 22643034Sdougm * Get the value of the specified property attribute. Standard 22653034Sdougm * attribute is "type". 22663034Sdougm */ 22673034Sdougm 22683034Sdougm char * 22693034Sdougm sa_get_optionset_attr(sa_property_t optionset, char *tag) 22703034Sdougm { 22713034Sdougm return (get_node_attr((void *)optionset, tag)); 22723034Sdougm 22733034Sdougm } 22743034Sdougm 22753034Sdougm /* 22763034Sdougm * sa_set_optionset_attr(optionset, tag, value) 22773034Sdougm * 22783034Sdougm * Set the specified attribute(tag) to the specified value on the 22793034Sdougm * optionset. 22803034Sdougm */ 22813034Sdougm 22823034Sdougm void 22833034Sdougm sa_set_optionset_attr(sa_group_t optionset, char *tag, char *value) 22843034Sdougm { 22853034Sdougm set_node_attr((void *)optionset, tag, value); 22863034Sdougm } 22873034Sdougm 22883034Sdougm /* 22893034Sdougm * sa_free_attr_string(string) 22903034Sdougm * 22913034Sdougm * Free the string that was returned in one of the sa_get_*_attr() 22923034Sdougm * functions. 22933034Sdougm */ 22943034Sdougm 22953034Sdougm void 22963034Sdougm sa_free_attr_string(char *string) 22973034Sdougm { 22983034Sdougm xmlFree((xmlChar *)string); 22993034Sdougm } 23003034Sdougm 23013034Sdougm /* 23023034Sdougm * sa_get_optionset(group, proto) 23033034Sdougm * 23043034Sdougm * Return the optionset, if it exists, that is associated with the 23053034Sdougm * specified protocol. 23063034Sdougm */ 23073034Sdougm 23083034Sdougm sa_optionset_t 23093034Sdougm sa_get_optionset(void *group, char *proto) 23103034Sdougm { 23113034Sdougm xmlNodePtr node; 23123034Sdougm xmlChar *value = NULL; 23133034Sdougm 23143034Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 23154327Sdougm node = node->next) { 23163034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) { 23174327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 23184327Sdougm if (proto != NULL) { 23194327Sdougm if (value != NULL && 23204327Sdougm xmlStrcmp(value, (xmlChar *)proto) == 0) { 23214327Sdougm break; 23224327Sdougm } 23234327Sdougm if (value != NULL) { 23244327Sdougm xmlFree(value); 23254327Sdougm value = NULL; 23264327Sdougm } 23274327Sdougm } else { 23284327Sdougm break; 23293034Sdougm } 23303034Sdougm } 23313034Sdougm } 23323034Sdougm if (value != NULL) 23334327Sdougm xmlFree(value); 23343034Sdougm return ((sa_optionset_t)node); 23353034Sdougm } 23363034Sdougm 23373034Sdougm /* 23383034Sdougm * sa_get_next_optionset(optionset) 23393034Sdougm * 23403034Sdougm * Return the next optionset in the group. NULL if this was the last. 23413034Sdougm */ 23423034Sdougm 23433034Sdougm sa_optionset_t 23443034Sdougm sa_get_next_optionset(sa_optionset_t optionset) 23453034Sdougm { 23463034Sdougm xmlNodePtr node; 23473034Sdougm 23483034Sdougm for (node = ((xmlNodePtr)optionset)->next; node != NULL; 23494327Sdougm node = node->next) { 23503034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) { 23513034Sdougm break; 23523034Sdougm } 23533034Sdougm } 23543034Sdougm return ((sa_optionset_t)node); 23553034Sdougm } 23563034Sdougm 23573034Sdougm /* 23583034Sdougm * sa_get_security(group, sectype, proto) 23593034Sdougm * 23603034Sdougm * Return the security optionset. The internal name is a hold over 23613034Sdougm * from the implementation and will be changed before the API is 23623034Sdougm * finalized. This is really a named optionset that can be negotiated 23633034Sdougm * as a group of properties (like NFS security options). 23643034Sdougm */ 23653034Sdougm 23663034Sdougm sa_security_t 23673034Sdougm sa_get_security(sa_group_t group, char *sectype, char *proto) 23683034Sdougm { 23693034Sdougm xmlNodePtr node; 23703034Sdougm xmlChar *value = NULL; 23713034Sdougm 23723034Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 23734327Sdougm node = node->next) { 23744327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) { 23754327Sdougm if (proto != NULL) { 23764327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 23774327Sdougm if (value == NULL || 23784327Sdougm (value != NULL && 23794327Sdougm xmlStrcmp(value, (xmlChar *)proto) != 0)) { 23804327Sdougm /* it doesn't match so continue */ 23814327Sdougm xmlFree(value); 23824327Sdougm value = NULL; 23834327Sdougm continue; 23844327Sdougm } 23854327Sdougm } 23864327Sdougm if (value != NULL) { 23874327Sdougm xmlFree(value); 23884327Sdougm value = NULL; 23894327Sdougm } 23904327Sdougm /* potential match */ 23914327Sdougm if (sectype != NULL) { 23924327Sdougm value = xmlGetProp(node, (xmlChar *)"sectype"); 23934327Sdougm if (value != NULL && 23944327Sdougm xmlStrcmp(value, (xmlChar *)sectype) == 0) { 23954327Sdougm break; 23964327Sdougm } 23974327Sdougm } else { 23984327Sdougm break; 23994327Sdougm } 24003034Sdougm } 24013034Sdougm if (value != NULL) { 24024327Sdougm xmlFree(value); 24034327Sdougm value = NULL; 24043034Sdougm } 24053034Sdougm } 24063034Sdougm if (value != NULL) 24074327Sdougm xmlFree(value); 24083034Sdougm return ((sa_security_t)node); 24093034Sdougm } 24103034Sdougm 24113034Sdougm /* 24123034Sdougm * sa_get_next_security(security) 24133034Sdougm * 24143034Sdougm * Get the next security optionset if one exists. 24153034Sdougm */ 24163034Sdougm 24173034Sdougm sa_security_t 24183034Sdougm sa_get_next_security(sa_security_t security) 24193034Sdougm { 24203034Sdougm xmlNodePtr node; 24213034Sdougm 24223034Sdougm for (node = ((xmlNodePtr)security)->next; node != NULL; 24234327Sdougm node = node->next) { 24243034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) { 24253034Sdougm break; 24263034Sdougm } 24273034Sdougm } 24283034Sdougm return ((sa_security_t)node); 24293034Sdougm } 24303034Sdougm 24313034Sdougm /* 24323034Sdougm * sa_get_property(optionset, prop) 24333034Sdougm * 24343034Sdougm * Get the property object with the name specified in prop from the 24353034Sdougm * optionset. 24363034Sdougm */ 24373034Sdougm 24383034Sdougm sa_property_t 24393034Sdougm sa_get_property(sa_optionset_t optionset, char *prop) 24403034Sdougm { 24413034Sdougm xmlNodePtr node = (xmlNodePtr)optionset; 24423034Sdougm xmlChar *value = NULL; 24433034Sdougm 24443034Sdougm if (optionset == NULL) 24454327Sdougm return (NULL); 24463034Sdougm 24473034Sdougm for (node = node->children; node != NULL; 24484327Sdougm node = node->next) { 24494327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 24504327Sdougm if (prop == NULL) 24514327Sdougm break; 24524327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 24534327Sdougm if (value != NULL && 24544327Sdougm xmlStrcmp(value, (xmlChar *)prop) == 0) { 24554327Sdougm break; 24564327Sdougm } 24574327Sdougm if (value != NULL) { 24584327Sdougm xmlFree(value); 24594327Sdougm value = NULL; 24604327Sdougm } 24613034Sdougm } 24623034Sdougm } 24633034Sdougm if (value != NULL) 24643034Sdougm xmlFree(value); 24653034Sdougm if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"option") != 0) { 24664327Sdougm /* 24674327Sdougm * avoid a non option node -- it is possible to be a 24684327Sdougm * text node 24694327Sdougm */ 24704327Sdougm node = NULL; 24713034Sdougm } 24723034Sdougm return ((sa_property_t)node); 24733034Sdougm } 24743034Sdougm 24753034Sdougm /* 24763034Sdougm * sa_get_next_property(property) 24773034Sdougm * 24783034Sdougm * Get the next property following the specified property. NULL if 24793034Sdougm * this was the last. 24803034Sdougm */ 24813034Sdougm 24823034Sdougm sa_property_t 24833034Sdougm sa_get_next_property(sa_property_t property) 24843034Sdougm { 24853034Sdougm xmlNodePtr node; 24863034Sdougm 24873034Sdougm for (node = ((xmlNodePtr)property)->next; node != NULL; 24884327Sdougm node = node->next) { 24893034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 24903034Sdougm break; 24913034Sdougm } 24923034Sdougm } 24933034Sdougm return ((sa_property_t)node); 24943034Sdougm } 24953034Sdougm 24963034Sdougm /* 24973034Sdougm * sa_set_share_description(share, content) 24983034Sdougm * 24993034Sdougm * Set the description of share to content. 25003034Sdougm */ 25013034Sdougm 25023034Sdougm int 25033034Sdougm sa_set_share_description(sa_share_t share, char *content) 25043034Sdougm { 25053034Sdougm xmlNodePtr node; 25063034Sdougm sa_group_t group; 25073034Sdougm int ret = SA_OK; 25083034Sdougm 25093034Sdougm for (node = ((xmlNodePtr)share)->children; node != NULL; 25104327Sdougm node = node->next) { 25113034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 25123034Sdougm break; 25133034Sdougm } 25143034Sdougm } 25153034Sdougm /* no existing description but want to add */ 25163034Sdougm if (node == NULL && content != NULL) { 25173034Sdougm /* add a description */ 25184327Sdougm node = _sa_set_share_description(share, content); 25193034Sdougm } else if (node != NULL && content != NULL) { 25203034Sdougm /* update a description */ 25213034Sdougm xmlNodeSetContent(node, (xmlChar *)content); 25223034Sdougm } else if (node != NULL && content == NULL) { 25233034Sdougm /* remove an existing description */ 25243034Sdougm xmlUnlinkNode(node); 25253034Sdougm xmlFreeNode(node); 25263034Sdougm } 25275331Samw group = sa_get_parent_group(share); 252812508Samw@Sun.COM if (group != NULL && 252912508Samw@Sun.COM sa_is_persistent(share) && (!sa_group_is_zfs(group))) { 25304327Sdougm sa_handle_impl_t impl_handle; 25314327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 25324327Sdougm if (impl_handle != NULL) { 25334327Sdougm ret = sa_commit_share(impl_handle->scfhandle, group, 25344327Sdougm share); 25354327Sdougm } else { 25364327Sdougm ret = SA_SYSTEM_ERR; 25374327Sdougm } 25383910Sdougm } 25393034Sdougm return (ret); 25403034Sdougm } 25413034Sdougm 25423034Sdougm /* 25433034Sdougm * fixproblemchars(string) 25443034Sdougm * 25453034Sdougm * don't want any newline or tab characters in the text since these 25463034Sdougm * could break display of data and legacy file formats. 25473034Sdougm */ 25483034Sdougm static void 25493034Sdougm fixproblemchars(char *str) 25503034Sdougm { 25513034Sdougm int c; 25523034Sdougm for (c = *str; c != '\0'; c = *++str) { 25534327Sdougm if (c == '\t' || c == '\n') 25544327Sdougm *str = ' '; 25554327Sdougm else if (c == '"') 25564327Sdougm *str = '\''; 25573034Sdougm } 25583034Sdougm } 25593034Sdougm 25603034Sdougm /* 25613034Sdougm * sa_get_share_description(share) 25623034Sdougm * 25633034Sdougm * Return the description text for the specified share if it 25643034Sdougm * exists. NULL if no description exists. 25653034Sdougm */ 25663034Sdougm 25673034Sdougm char * 25683034Sdougm sa_get_share_description(sa_share_t share) 25693034Sdougm { 25703034Sdougm xmlChar *description = NULL; 25713034Sdougm xmlNodePtr node; 25723034Sdougm 25733034Sdougm for (node = ((xmlNodePtr)share)->children; node != NULL; 25744327Sdougm node = node->next) { 25754327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 25764327Sdougm break; 25774327Sdougm } 25783034Sdougm } 25793034Sdougm if (node != NULL) { 25805331Samw description = xmlNodeGetContent(node); 25814327Sdougm fixproblemchars((char *)description); 25823034Sdougm } 25833034Sdougm return ((char *)description); 25843034Sdougm } 25853034Sdougm 25863034Sdougm /* 25873034Sdougm * sa_free(share_description(description) 25883034Sdougm * 25893034Sdougm * Free the description string. 25903034Sdougm */ 25913034Sdougm 25923034Sdougm void 25933034Sdougm sa_free_share_description(char *description) 25943034Sdougm { 25953034Sdougm xmlFree((xmlChar *)description); 25963034Sdougm } 25973034Sdougm 25983034Sdougm /* 25993034Sdougm * sa_create_optionset(group, proto) 26003034Sdougm * 26013034Sdougm * Create an optionset for the specified protocol in the specied 26023034Sdougm * group. This is manifested as a property group within SMF. 26033034Sdougm */ 26043034Sdougm 26053034Sdougm sa_optionset_t 26063034Sdougm sa_create_optionset(sa_group_t group, char *proto) 26073034Sdougm { 26083034Sdougm sa_optionset_t optionset; 26093034Sdougm sa_group_t parent = group; 26105331Samw sa_share_t share = NULL; 26115331Samw int err = SA_OK; 26125331Samw char *id = NULL; 26133034Sdougm 26143034Sdougm optionset = sa_get_optionset(group, proto); 26153034Sdougm if (optionset != NULL) { 26163034Sdougm /* can't have a duplicate protocol */ 26174327Sdougm optionset = NULL; 26183034Sdougm } else { 26195331Samw /* 26205331Samw * Account for resource names being slightly 26215331Samw * different. 26225331Samw */ 26235331Samw if (sa_is_share(group)) { 26245331Samw /* 26255331Samw * Transient shares do not have an "id" so not an 26265331Samw * error to not find one. 26275331Samw */ 26285331Samw id = sa_get_share_attr((sa_share_t)group, "id"); 26295331Samw } else if (sa_is_resource(group)) { 26305331Samw share = sa_get_resource_parent( 26315331Samw (sa_resource_t)group); 26325331Samw id = sa_get_resource_attr(share, "id"); 26335331Samw 26345331Samw /* id can be NULL if the group is transient (ZFS) */ 26355331Samw if (id == NULL && sa_is_persistent(group)) 26365331Samw err = SA_NO_MEMORY; 26375331Samw } 26385331Samw if (err == SA_NO_MEMORY) { 26395331Samw /* 26405331Samw * Couldn't get the id for the share or 26415331Samw * resource. While this could be a 26425331Samw * configuration issue, it is most likely an 26435331Samw * out of memory. In any case, fail the create. 26445331Samw */ 26455331Samw return (NULL); 26465331Samw } 26475331Samw 26484327Sdougm optionset = (sa_optionset_t)xmlNewChild((xmlNodePtr)group, 26494327Sdougm NULL, (xmlChar *)"optionset", NULL); 26503034Sdougm /* 26513034Sdougm * only put to repository if on a group and we were 26523034Sdougm * able to create an optionset. 26533034Sdougm */ 26544327Sdougm if (optionset != NULL) { 26554327Sdougm char oname[SA_STRSIZE]; 26564327Sdougm char *groupname; 26575331Samw 26585331Samw /* 26595331Samw * Need to get parent group in all cases, but also get 26605331Samw * the share if this is a resource. 26615331Samw */ 26625331Samw if (sa_is_share(group)) { 26634327Sdougm parent = sa_get_parent_group((sa_share_t)group); 26645331Samw } else if (sa_is_resource(group)) { 26655331Samw share = sa_get_resource_parent( 26665331Samw (sa_resource_t)group); 26675331Samw parent = sa_get_parent_group(share); 26685331Samw } 26694327Sdougm 26704327Sdougm sa_set_optionset_attr(optionset, "type", proto); 26713034Sdougm 26724327Sdougm (void) sa_optionset_name(optionset, oname, 26734327Sdougm sizeof (oname), id); 26744327Sdougm groupname = sa_get_group_attr(parent, "name"); 26755331Samw if (groupname != NULL && sa_is_persistent(group)) { 26764327Sdougm sa_handle_impl_t impl_handle; 26775331Samw impl_handle = 26785331Samw (sa_handle_impl_t)sa_find_group_handle( 26795331Samw group); 26804327Sdougm assert(impl_handle != NULL); 26814327Sdougm if (impl_handle != NULL) { 26824327Sdougm (void) sa_get_instance( 26835331Samw impl_handle->scfhandle, groupname); 26844327Sdougm (void) sa_create_pgroup( 26854327Sdougm impl_handle->scfhandle, oname); 26864327Sdougm } 26874327Sdougm } 26884327Sdougm if (groupname != NULL) 26894327Sdougm sa_free_attr_string(groupname); 26903034Sdougm } 26913034Sdougm } 26925331Samw 26935331Samw if (id != NULL) 26945331Samw sa_free_attr_string(id); 26953034Sdougm return (optionset); 26963034Sdougm } 26973034Sdougm 26983034Sdougm /* 26993034Sdougm * sa_get_property_parent(property) 27003034Sdougm * 27013034Sdougm * Given a property, return the object it is a property of. This will 27023034Sdougm * be an optionset of some type. 27033034Sdougm */ 27043034Sdougm 27053034Sdougm static sa_optionset_t 27063034Sdougm sa_get_property_parent(sa_property_t property) 27073034Sdougm { 27083034Sdougm xmlNodePtr node = NULL; 27093034Sdougm 27104327Sdougm if (property != NULL) 27114327Sdougm node = ((xmlNodePtr)property)->parent; 27123034Sdougm return ((sa_optionset_t)node); 27133034Sdougm } 27143034Sdougm 27153034Sdougm /* 27163034Sdougm * sa_get_optionset_parent(optionset) 27173034Sdougm * 27183034Sdougm * Return the parent of the specified optionset. This could be a group 27193034Sdougm * or a share. 27203034Sdougm */ 27213034Sdougm 27223034Sdougm static sa_group_t 27233034Sdougm sa_get_optionset_parent(sa_optionset_t optionset) 27243034Sdougm { 27253034Sdougm xmlNodePtr node = NULL; 27263034Sdougm 27274327Sdougm if (optionset != NULL) 27284327Sdougm node = ((xmlNodePtr)optionset)->parent; 27293034Sdougm return ((sa_group_t)node); 27303034Sdougm } 27313034Sdougm 27323034Sdougm /* 27333034Sdougm * zfs_needs_update(share) 27343034Sdougm * 27353034Sdougm * In order to avoid making multiple updates to a ZFS share when 27363034Sdougm * setting properties, the share attribute "changed" will be set to 27375331Samw * true when a property is added or modified. When done adding 27383034Sdougm * properties, we can then detect that an update is needed. We then 27393034Sdougm * clear the state here to detect additional changes. 27403034Sdougm */ 27413034Sdougm 27423034Sdougm static int 27433034Sdougm zfs_needs_update(sa_share_t share) 27443034Sdougm { 27453034Sdougm char *attr; 27463034Sdougm int result = 0; 27473034Sdougm 27483034Sdougm attr = sa_get_share_attr(share, "changed"); 27493034Sdougm if (attr != NULL) { 27504327Sdougm sa_free_attr_string(attr); 27513034Sdougm result = 1; 27523034Sdougm } 27533034Sdougm set_node_attr((void *)share, "changed", NULL); 27543034Sdougm return (result); 27553034Sdougm } 27563034Sdougm 27573034Sdougm /* 27583034Sdougm * zfs_set_update(share) 27593034Sdougm * 27603034Sdougm * Set the changed attribute of the share to true. 27613034Sdougm */ 27623034Sdougm 27633034Sdougm static void 27643034Sdougm zfs_set_update(sa_share_t share) 27653034Sdougm { 27663034Sdougm set_node_attr((void *)share, "changed", "true"); 27673034Sdougm } 27683034Sdougm 27693034Sdougm /* 27703034Sdougm * sa_commit_properties(optionset, clear) 27713034Sdougm * 27723034Sdougm * Check if SMF or ZFS config and either update or abort the pending 27733034Sdougm * changes. 27743034Sdougm */ 27753034Sdougm 27763034Sdougm int 27773034Sdougm sa_commit_properties(sa_optionset_t optionset, int clear) 27783034Sdougm { 27793034Sdougm sa_group_t group; 27803034Sdougm sa_group_t parent; 27813034Sdougm int zfs = 0; 27823034Sdougm int needsupdate = 0; 27833034Sdougm int ret = SA_OK; 27843910Sdougm sa_handle_impl_t impl_handle; 27853034Sdougm 27863034Sdougm group = sa_get_optionset_parent(optionset); 27873034Sdougm if (group != NULL && (sa_is_share(group) || is_zfs_group(group))) { 27884327Sdougm /* only update ZFS if on a share */ 27894327Sdougm parent = sa_get_parent_group(group); 27904327Sdougm zfs++; 27914327Sdougm if (parent != NULL && is_zfs_group(parent)) 27924327Sdougm needsupdate = zfs_needs_update(group); 27934327Sdougm else 27944327Sdougm zfs = 0; 27953034Sdougm } 27963034Sdougm if (zfs) { 27974327Sdougm if (!clear && needsupdate) 27984327Sdougm ret = sa_zfs_update((sa_share_t)group); 27993034Sdougm } else { 28004327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 28014327Sdougm if (impl_handle != NULL) { 28024327Sdougm if (clear) { 28034327Sdougm (void) sa_abort_transaction( 28044327Sdougm impl_handle->scfhandle); 28054327Sdougm } else { 28064327Sdougm ret = sa_end_transaction( 28075951Sdougm impl_handle->scfhandle, impl_handle); 28084327Sdougm } 28094327Sdougm } else { 28104327Sdougm ret = SA_SYSTEM_ERR; 28114327Sdougm } 28123034Sdougm } 28133034Sdougm return (ret); 28143034Sdougm } 28153034Sdougm 28163034Sdougm /* 28173034Sdougm * sa_destroy_optionset(optionset) 28183034Sdougm * 28195331Samw * Remove the optionset from its group. Update the repository to 28203034Sdougm * reflect this change. 28213034Sdougm */ 28223034Sdougm 28233034Sdougm int 28243034Sdougm sa_destroy_optionset(sa_optionset_t optionset) 28253034Sdougm { 28264327Sdougm char name[SA_STRSIZE]; 28273034Sdougm int len; 28283034Sdougm int ret; 28293034Sdougm char *id = NULL; 28303034Sdougm sa_group_t group; 28313034Sdougm int ispersist = 1; 28323034Sdougm 28333034Sdougm /* now delete the prop group */ 28343034Sdougm group = sa_get_optionset_parent(optionset); 28355331Samw if (group != NULL) { 28365331Samw if (sa_is_resource(group)) { 28375331Samw sa_resource_t resource = group; 28385331Samw sa_share_t share = sa_get_resource_parent(resource); 28395331Samw group = sa_get_parent_group(share); 28405331Samw id = sa_get_share_attr(share, "id"); 28415331Samw } else if (sa_is_share(group)) { 28425331Samw id = sa_get_share_attr((sa_share_t)group, "id"); 28435331Samw } 28445331Samw ispersist = sa_is_persistent(group); 28453034Sdougm } 28463034Sdougm if (ispersist) { 28474327Sdougm sa_handle_impl_t impl_handle; 28484327Sdougm len = sa_optionset_name(optionset, name, sizeof (name), id); 28494327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 28504327Sdougm if (impl_handle != NULL) { 28514327Sdougm if (len > 0) { 28524327Sdougm ret = sa_delete_pgroup(impl_handle->scfhandle, 28534327Sdougm name); 28544327Sdougm } 28554327Sdougm } else { 28564327Sdougm ret = SA_SYSTEM_ERR; 28573910Sdougm } 28583034Sdougm } 28593034Sdougm xmlUnlinkNode((xmlNodePtr)optionset); 28603034Sdougm xmlFreeNode((xmlNodePtr)optionset); 28613034Sdougm if (id != NULL) 28624327Sdougm sa_free_attr_string(id); 28633034Sdougm return (ret); 28643034Sdougm } 28653034Sdougm 28663034Sdougm /* private to the implementation */ 28673034Sdougm int 28683034Sdougm _sa_remove_optionset(sa_optionset_t optionset) 28693034Sdougm { 28703034Sdougm int ret = SA_OK; 28713034Sdougm 28723034Sdougm xmlUnlinkNode((xmlNodePtr)optionset); 28733034Sdougm xmlFreeNode((xmlNodePtr)optionset); 28743034Sdougm return (ret); 28753034Sdougm } 28763034Sdougm 28773034Sdougm /* 28783034Sdougm * sa_create_security(group, sectype, proto) 28793034Sdougm * 28803034Sdougm * Create a security optionset (one that has a type name and a 28813034Sdougm * proto). Security is left over from a pure NFS implementation. The 28823034Sdougm * naming will change in the future when the API is released. 28833034Sdougm */ 28843034Sdougm sa_security_t 28853034Sdougm sa_create_security(sa_group_t group, char *sectype, char *proto) 28863034Sdougm { 28873034Sdougm sa_security_t security; 28883034Sdougm char *id = NULL; 28893034Sdougm sa_group_t parent; 28903034Sdougm char *groupname = NULL; 28913034Sdougm 28923034Sdougm if (group != NULL && sa_is_share(group)) { 28934327Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 28944327Sdougm parent = sa_get_parent_group(group); 28954327Sdougm if (parent != NULL) 28964327Sdougm groupname = sa_get_group_attr(parent, "name"); 28973034Sdougm } else if (group != NULL) { 28984327Sdougm groupname = sa_get_group_attr(group, "name"); 28993034Sdougm } 29003034Sdougm 29013034Sdougm security = sa_get_security(group, sectype, proto); 29023034Sdougm if (security != NULL) { 29033034Sdougm /* can't have a duplicate security option */ 29043034Sdougm security = NULL; 29053034Sdougm } else { 29063034Sdougm security = (sa_security_t)xmlNewChild((xmlNodePtr)group, 29074327Sdougm NULL, (xmlChar *)"security", NULL); 29083034Sdougm if (security != NULL) { 29094327Sdougm char oname[SA_STRSIZE]; 29103034Sdougm sa_set_security_attr(security, "type", proto); 29113034Sdougm 29123034Sdougm sa_set_security_attr(security, "sectype", sectype); 29133034Sdougm (void) sa_security_name(security, oname, 29144327Sdougm sizeof (oname), id); 29155331Samw if (groupname != NULL && sa_is_persistent(group)) { 29164327Sdougm sa_handle_impl_t impl_handle; 29174327Sdougm impl_handle = 29184327Sdougm (sa_handle_impl_t)sa_find_group_handle( 29194327Sdougm group); 29204327Sdougm if (impl_handle != NULL) { 29214327Sdougm (void) sa_get_instance( 29224327Sdougm impl_handle->scfhandle, groupname); 29234327Sdougm (void) sa_create_pgroup( 29244327Sdougm impl_handle->scfhandle, oname); 29254327Sdougm } 29263034Sdougm } 29273034Sdougm } 29283034Sdougm } 292911337SWilliam.Krier@Sun.COM if (id != NULL) 293011337SWilliam.Krier@Sun.COM sa_free_attr_string(id); 29313034Sdougm if (groupname != NULL) 29324327Sdougm sa_free_attr_string(groupname); 29333034Sdougm return (security); 29343034Sdougm } 29353034Sdougm 29363034Sdougm /* 29373034Sdougm * sa_destroy_security(security) 29383034Sdougm * 29393034Sdougm * Remove the specified optionset from the document and the 29403034Sdougm * configuration. 29413034Sdougm */ 29423034Sdougm 29433034Sdougm int 29443034Sdougm sa_destroy_security(sa_security_t security) 29453034Sdougm { 29464327Sdougm char name[SA_STRSIZE]; 29473034Sdougm int len; 29483034Sdougm int ret = SA_OK; 29493034Sdougm char *id = NULL; 29503034Sdougm sa_group_t group; 29513034Sdougm int iszfs = 0; 29523034Sdougm int ispersist = 1; 29533034Sdougm 29543034Sdougm group = sa_get_optionset_parent(security); 29553034Sdougm 29563034Sdougm if (group != NULL) 29574327Sdougm iszfs = sa_group_is_zfs(group); 29583034Sdougm 29593034Sdougm if (group != NULL && !iszfs) { 29604327Sdougm if (sa_is_share(group)) 29615331Samw ispersist = sa_is_persistent(group); 29624327Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 29633034Sdougm } 29643034Sdougm if (ispersist) { 29654327Sdougm len = sa_security_name(security, name, sizeof (name), id); 29664327Sdougm if (!iszfs && len > 0) { 29674327Sdougm sa_handle_impl_t impl_handle; 29684327Sdougm impl_handle = 29694327Sdougm (sa_handle_impl_t)sa_find_group_handle(group); 29704327Sdougm if (impl_handle != NULL) { 29714327Sdougm ret = sa_delete_pgroup(impl_handle->scfhandle, 29724327Sdougm name); 29734327Sdougm } else { 29744327Sdougm ret = SA_SYSTEM_ERR; 29754327Sdougm } 29763910Sdougm } 29773034Sdougm } 29783034Sdougm xmlUnlinkNode((xmlNodePtr)security); 29793034Sdougm xmlFreeNode((xmlNodePtr)security); 29804327Sdougm if (iszfs) 29814327Sdougm ret = sa_zfs_update(group); 29823034Sdougm if (id != NULL) 29834327Sdougm sa_free_attr_string(id); 29843034Sdougm return (ret); 29853034Sdougm } 29863034Sdougm 29873034Sdougm /* 29883034Sdougm * sa_get_security_attr(optionset, tag) 29893034Sdougm * 29903034Sdougm * Return the specified attribute value from the optionset. 29913034Sdougm */ 29923034Sdougm 29933034Sdougm char * 29943034Sdougm sa_get_security_attr(sa_property_t optionset, char *tag) 29953034Sdougm { 29963034Sdougm return (get_node_attr((void *)optionset, tag)); 29973034Sdougm 29983034Sdougm } 29993034Sdougm 30003034Sdougm /* 30013034Sdougm * sa_set_security_attr(optionset, tag, value) 30023034Sdougm * 30033034Sdougm * Set the optioset attribute specied by tag to the specified value. 30043034Sdougm */ 30053034Sdougm 30063034Sdougm void 30073034Sdougm sa_set_security_attr(sa_group_t optionset, char *tag, char *value) 30083034Sdougm { 30093034Sdougm set_node_attr((void *)optionset, tag, value); 30103034Sdougm } 30113034Sdougm 30123034Sdougm /* 30133034Sdougm * is_nodetype(node, type) 30143034Sdougm * 30153034Sdougm * Check to see if node is of the type specified. 30163034Sdougm */ 30173034Sdougm 30183034Sdougm static int 30193034Sdougm is_nodetype(void *node, char *type) 30203034Sdougm { 30213034Sdougm return (strcmp((char *)((xmlNodePtr)node)->name, type) == 0); 30223034Sdougm } 30233034Sdougm 30244327Sdougm /* 30254327Sdougm * add_or_update() 30264327Sdougm * 30274327Sdougm * Add or update a property. Pulled out of sa_set_prop_by_prop for 30284327Sdougm * readability. 30294327Sdougm */ 30304327Sdougm static int 30314327Sdougm add_or_update(scfutilhandle_t *scf_handle, int type, scf_value_t *value, 30324327Sdougm scf_transaction_entry_t *entry, char *name, char *valstr) 30334327Sdougm { 30344327Sdougm int ret = SA_SYSTEM_ERR; 30354327Sdougm 30364327Sdougm if (value != NULL) { 30374327Sdougm if (type == SA_PROP_OP_ADD) 30384327Sdougm ret = scf_transaction_property_new(scf_handle->trans, 30394327Sdougm entry, name, SCF_TYPE_ASTRING); 30404327Sdougm else 30414327Sdougm ret = scf_transaction_property_change(scf_handle->trans, 30424327Sdougm entry, name, SCF_TYPE_ASTRING); 30434327Sdougm if (ret == 0) { 30444327Sdougm ret = scf_value_set_astring(value, valstr); 30454327Sdougm if (ret == 0) 30464327Sdougm ret = scf_entry_add_value(entry, value); 30474327Sdougm if (ret == 0) 30484327Sdougm return (ret); 30494327Sdougm scf_value_destroy(value); 30504327Sdougm } else { 30514327Sdougm scf_entry_destroy(entry); 30524327Sdougm } 30534327Sdougm } 30544327Sdougm return (SA_SYSTEM_ERR); 30554327Sdougm } 30564327Sdougm 30573034Sdougm /* 30583034Sdougm * sa_set_prop_by_prop(optionset, group, prop, type) 30593034Sdougm * 30603034Sdougm * Add/remove/update the specified property prop into the optionset or 30613034Sdougm * share. If a share, sort out which property group based on GUID. In 30623034Sdougm * all cases, the appropriate transaction is set (or ZFS share is 30633034Sdougm * marked as needing an update) 30643034Sdougm */ 30653034Sdougm 30663034Sdougm static int 30673034Sdougm sa_set_prop_by_prop(sa_optionset_t optionset, sa_group_t group, 30683034Sdougm sa_property_t prop, int type) 30693034Sdougm { 30703034Sdougm char *name; 30713034Sdougm char *valstr; 30723034Sdougm int ret = SA_OK; 30733034Sdougm scf_transaction_entry_t *entry; 30743034Sdougm scf_value_t *value; 30753034Sdougm int opttype; /* 1 == optionset, 0 == security */ 30763034Sdougm char *id = NULL; 30773034Sdougm int iszfs = 0; 30783034Sdougm sa_group_t parent = NULL; 30795331Samw sa_share_t share = NULL; 30803910Sdougm sa_handle_impl_t impl_handle; 30813910Sdougm scfutilhandle_t *scf_handle; 30823034Sdougm 30835331Samw if (!sa_is_persistent(group)) { 30843034Sdougm /* 30853034Sdougm * if the group/share is not persistent we don't need 30863034Sdougm * to do anything here 30873034Sdougm */ 30884327Sdougm return (SA_OK); 30893034Sdougm } 30903910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 30914327Sdougm if (impl_handle == NULL || impl_handle->scfhandle == NULL) 30924327Sdougm return (SA_SYSTEM_ERR); 30933910Sdougm scf_handle = impl_handle->scfhandle; 30943034Sdougm name = sa_get_property_attr(prop, "type"); 30953034Sdougm valstr = sa_get_property_attr(prop, "value"); 30963034Sdougm entry = scf_entry_create(scf_handle->handle); 30973034Sdougm opttype = is_nodetype((void *)optionset, "optionset"); 30983034Sdougm 30995331Samw /* 31005331Samw * Check for share vs. resource since they need slightly 31015331Samw * different treatment given the hierarchy. 31025331Samw */ 31033034Sdougm if (valstr != NULL && entry != NULL) { 31044327Sdougm if (sa_is_share(group)) { 31054327Sdougm parent = sa_get_parent_group(group); 31065331Samw share = (sa_share_t)group; 31074327Sdougm if (parent != NULL) 31084327Sdougm iszfs = is_zfs_group(parent); 31095331Samw } else if (sa_is_resource(group)) { 31105331Samw share = sa_get_parent_group(group); 31115331Samw if (share != NULL) 31125331Samw parent = sa_get_parent_group(share); 31134327Sdougm } else { 31144327Sdougm iszfs = is_zfs_group(group); 31153034Sdougm } 31164327Sdougm if (!iszfs) { 31174327Sdougm if (scf_handle->trans == NULL) { 31184327Sdougm char oname[SA_STRSIZE]; 31194327Sdougm char *groupname = NULL; 31205331Samw if (share != NULL) { 31215331Samw if (parent != NULL) 31224327Sdougm groupname = 31234327Sdougm sa_get_group_attr(parent, 31244327Sdougm "name"); 31255331Samw id = sa_get_share_attr( 31265331Samw (sa_share_t)share, "id"); 31274327Sdougm } else { 31284327Sdougm groupname = sa_get_group_attr(group, 31294327Sdougm "name"); 31304327Sdougm } 31314327Sdougm if (groupname != NULL) { 31324327Sdougm ret = sa_get_instance(scf_handle, 31334327Sdougm groupname); 31344327Sdougm sa_free_attr_string(groupname); 31354327Sdougm } 31364327Sdougm if (opttype) 31374327Sdougm (void) sa_optionset_name(optionset, 31384327Sdougm oname, sizeof (oname), id); 31394327Sdougm else 31404327Sdougm (void) sa_security_name(optionset, 31414327Sdougm oname, sizeof (oname), id); 31424327Sdougm ret = sa_start_transaction(scf_handle, oname); 314311337SWilliam.Krier@Sun.COM if (id != NULL) 314411337SWilliam.Krier@Sun.COM sa_free_attr_string(id); 31453910Sdougm } 31464327Sdougm if (ret == SA_OK) { 31474327Sdougm switch (type) { 31484327Sdougm case SA_PROP_OP_REMOVE: 31494327Sdougm ret = scf_transaction_property_delete( 31504327Sdougm scf_handle->trans, entry, name); 31514327Sdougm break; 31524327Sdougm case SA_PROP_OP_ADD: 31534327Sdougm case SA_PROP_OP_UPDATE: 31544327Sdougm value = scf_value_create( 31554327Sdougm scf_handle->handle); 31564327Sdougm ret = add_or_update(scf_handle, type, 31574327Sdougm value, entry, name, valstr); 31584327Sdougm break; 31593034Sdougm } 31603034Sdougm } 31614327Sdougm } else { 31624327Sdougm /* 31634327Sdougm * ZFS update. The calling function would have updated 31644327Sdougm * the internal XML structure. Just need to flag it as 31654327Sdougm * changed for ZFS. 31664327Sdougm */ 31674327Sdougm zfs_set_update((sa_share_t)group); 31684327Sdougm } 31693034Sdougm } 31703034Sdougm 31713034Sdougm if (name != NULL) 31724327Sdougm sa_free_attr_string(name); 31733034Sdougm if (valstr != NULL) 31744327Sdougm sa_free_attr_string(valstr); 31753034Sdougm else if (entry != NULL) 31764327Sdougm scf_entry_destroy(entry); 31773034Sdougm 31783034Sdougm if (ret == -1) 31794327Sdougm ret = SA_SYSTEM_ERR; 31803034Sdougm 31813034Sdougm return (ret); 31823034Sdougm } 31833034Sdougm 31843034Sdougm /* 31856007Sthurlow * sa_create_section(name, value) 31866007Sthurlow * 31876007Sthurlow * Create a new section with the specified name and extra data. 31886007Sthurlow */ 31896007Sthurlow 31906007Sthurlow sa_property_t 31916007Sthurlow sa_create_section(char *name, char *extra) 31926007Sthurlow { 31936007Sthurlow xmlNodePtr node; 31946007Sthurlow 31956007Sthurlow node = xmlNewNode(NULL, (xmlChar *)"section"); 31966007Sthurlow if (node != NULL) { 31976007Sthurlow if (name != NULL) 31986007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 31996007Sthurlow (xmlChar *)name); 32006007Sthurlow if (extra != NULL) 32016007Sthurlow (void) xmlSetProp(node, (xmlChar *)"extra", 32026007Sthurlow (xmlChar *)extra); 32036007Sthurlow } 32046007Sthurlow return ((sa_property_t)node); 32056007Sthurlow } 32066007Sthurlow 32076007Sthurlow void 32086007Sthurlow sa_set_section_attr(sa_property_t sect, char *name, char *value) 32096007Sthurlow { 32106007Sthurlow (void) xmlSetProp(sect, (xmlChar *)name, (xmlChar *)value); 32116007Sthurlow } 32126007Sthurlow 32136007Sthurlow /* 32146007Sthurlow * sa_create_property(section, name, value) 32153034Sdougm * 32163034Sdougm * Create a new property with the specified name and value. 32173034Sdougm */ 32183034Sdougm 32193034Sdougm sa_property_t 32203034Sdougm sa_create_property(char *name, char *value) 32213034Sdougm { 32223034Sdougm xmlNodePtr node; 32233034Sdougm 32243034Sdougm node = xmlNewNode(NULL, (xmlChar *)"option"); 32253034Sdougm if (node != NULL) { 32266007Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", (xmlChar *)name); 32276007Sthurlow (void) xmlSetProp(node, (xmlChar *)"value", (xmlChar *)value); 32283034Sdougm } 32293034Sdougm return ((sa_property_t)node); 32303034Sdougm } 32313034Sdougm 32323034Sdougm /* 32333034Sdougm * sa_add_property(object, property) 32343034Sdougm * 32353034Sdougm * Add the specified property to the object. Issue the appropriate 32363034Sdougm * transaction or mark a ZFS object as needing an update. 32373034Sdougm */ 32383034Sdougm 32393034Sdougm int 32403034Sdougm sa_add_property(void *object, sa_property_t property) 32413034Sdougm { 32423034Sdougm int ret = SA_OK; 32433034Sdougm sa_group_t parent; 32443034Sdougm sa_group_t group; 32453034Sdougm char *proto; 32466214Sdougm 32473034Sdougm if (property != NULL) { 32486271Sdougm sa_handle_t handle; 32496214Sdougm handle = sa_find_group_handle((sa_group_t)object); 32506271Sdougm /* It is legitimate to not find a handle */ 32516214Sdougm proto = sa_get_optionset_attr(object, "type"); 32526214Sdougm if ((ret = sa_valid_property(handle, object, proto, 32536214Sdougm property)) == SA_OK) { 32544327Sdougm property = (sa_property_t)xmlAddChild( 32554327Sdougm (xmlNodePtr)object, (xmlNodePtr)property); 32564327Sdougm } else { 32574327Sdougm if (proto != NULL) 32584327Sdougm sa_free_attr_string(proto); 32594327Sdougm return (ret); 32604327Sdougm } 32616214Sdougm if (proto != NULL) 32626214Sdougm sa_free_attr_string(proto); 32633034Sdougm } 32643034Sdougm 32653034Sdougm 32663034Sdougm parent = sa_get_parent_group(object); 32675331Samw if (!sa_is_persistent(parent)) 32684327Sdougm return (ret); 32695331Samw 32705331Samw if (sa_is_resource(parent)) { 32715331Samw /* 32725331Samw * Resources are children of share. Need to go up two 32735331Samw * levels to find the group but the parent needs to be 32745331Samw * the share at this point in order to get the "id". 32755331Samw */ 32765331Samw parent = sa_get_parent_group(parent); 32775331Samw group = sa_get_parent_group(parent); 32785331Samw } else if (sa_is_share(parent)) { 32795331Samw group = sa_get_parent_group(parent); 32805331Samw } else { 32815331Samw group = parent; 32823034Sdougm } 32833034Sdougm 32844327Sdougm if (property == NULL) { 32854327Sdougm ret = SA_NO_MEMORY; 32864327Sdougm } else { 32874327Sdougm char oname[SA_STRSIZE]; 32883034Sdougm 32894327Sdougm if (!is_zfs_group(group)) { 32904327Sdougm char *id = NULL; 32914327Sdougm sa_handle_impl_t impl_handle; 32924327Sdougm scfutilhandle_t *scf_handle; 32933910Sdougm 32944327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle( 32954327Sdougm group); 32964327Sdougm if (impl_handle == NULL || 32974327Sdougm impl_handle->scfhandle == NULL) 32984327Sdougm ret = SA_SYSTEM_ERR; 32994327Sdougm if (ret == SA_OK) { 33004327Sdougm scf_handle = impl_handle->scfhandle; 33014327Sdougm if (sa_is_share((sa_group_t)parent)) { 33024327Sdougm id = sa_get_share_attr( 33034327Sdougm (sa_share_t)parent, "id"); 33044327Sdougm } 33054327Sdougm if (scf_handle->trans == NULL) { 33064327Sdougm if (is_nodetype(object, "optionset")) { 33074327Sdougm (void) sa_optionset_name( 33084327Sdougm (sa_optionset_t)object, 33094327Sdougm oname, sizeof (oname), id); 33104327Sdougm } else { 33114327Sdougm (void) sa_security_name( 33124327Sdougm (sa_optionset_t)object, 33134327Sdougm oname, sizeof (oname), id); 33144327Sdougm } 33154327Sdougm ret = sa_start_transaction(scf_handle, 33164327Sdougm oname); 33174327Sdougm } 33184327Sdougm if (ret == SA_OK) { 33194327Sdougm char *name; 33204327Sdougm char *value; 33214327Sdougm name = sa_get_property_attr(property, 33224327Sdougm "type"); 33234327Sdougm value = sa_get_property_attr(property, 33244327Sdougm "value"); 33254327Sdougm if (name != NULL && value != NULL) { 33264327Sdougm if (scf_handle->scf_state == 33274327Sdougm SCH_STATE_INIT) { 33284327Sdougm ret = sa_set_property( 33294327Sdougm scf_handle, name, 33304327Sdougm value); 33314327Sdougm } 33324327Sdougm } else { 33334327Sdougm ret = SA_CONFIG_ERR; 33344327Sdougm } 33354327Sdougm if (name != NULL) 33364327Sdougm sa_free_attr_string( 33374327Sdougm name); 33384327Sdougm if (value != NULL) 33394327Sdougm sa_free_attr_string(value); 33404327Sdougm } 33414327Sdougm if (id != NULL) 33424327Sdougm sa_free_attr_string(id); 33434327Sdougm } 33444327Sdougm } else { 33454327Sdougm /* 33464327Sdougm * ZFS is a special case. We do want 33474327Sdougm * to allow editing property/security 33484327Sdougm * lists since we can have a better 33494327Sdougm * syntax and we also want to keep 33504327Sdougm * things consistent when possible. 33514327Sdougm * 33524327Sdougm * Right now, we defer until the 33534327Sdougm * sa_commit_properties so we can get 33544327Sdougm * them all at once. We do need to 33554327Sdougm * mark the share as "changed" 33564327Sdougm */ 33574327Sdougm zfs_set_update((sa_share_t)parent); 33583034Sdougm } 33593034Sdougm } 33603034Sdougm return (ret); 33613034Sdougm } 33623034Sdougm 33633034Sdougm /* 33643034Sdougm * sa_remove_property(property) 33653034Sdougm * 33663034Sdougm * Remove the specied property from its containing object. Update the 33673034Sdougm * repository as appropriate. 33683034Sdougm */ 33693034Sdougm 33703034Sdougm int 33713034Sdougm sa_remove_property(sa_property_t property) 33723034Sdougm { 33733034Sdougm int ret = SA_OK; 33743034Sdougm 33753034Sdougm if (property != NULL) { 33763034Sdougm sa_optionset_t optionset; 33773034Sdougm sa_group_t group; 33783034Sdougm optionset = sa_get_property_parent(property); 33793034Sdougm if (optionset != NULL) { 33804327Sdougm group = sa_get_optionset_parent(optionset); 33814327Sdougm if (group != NULL) { 33824327Sdougm ret = sa_set_prop_by_prop(optionset, group, 33834327Sdougm property, SA_PROP_OP_REMOVE); 33844327Sdougm } 33853034Sdougm } 33863034Sdougm xmlUnlinkNode((xmlNodePtr)property); 33873034Sdougm xmlFreeNode((xmlNodePtr)property); 33883034Sdougm } else { 33894327Sdougm ret = SA_NO_SUCH_PROP; 33903034Sdougm } 33913034Sdougm return (ret); 33923034Sdougm } 33933034Sdougm 33943034Sdougm /* 33953034Sdougm * sa_update_property(property, value) 33963034Sdougm * 33973034Sdougm * Update the specified property to the new value. If value is NULL, 33983034Sdougm * we currently treat this as a remove. 33993034Sdougm */ 34003034Sdougm 34013034Sdougm int 34023034Sdougm sa_update_property(sa_property_t property, char *value) 34033034Sdougm { 34043034Sdougm int ret = SA_OK; 34053034Sdougm if (value == NULL) { 34063034Sdougm return (sa_remove_property(property)); 34073034Sdougm } else { 34083034Sdougm sa_optionset_t optionset; 34093034Sdougm sa_group_t group; 34103034Sdougm set_node_attr((void *)property, "value", value); 34113034Sdougm optionset = sa_get_property_parent(property); 34123034Sdougm if (optionset != NULL) { 34134327Sdougm group = sa_get_optionset_parent(optionset); 34144327Sdougm if (group != NULL) { 34154327Sdougm ret = sa_set_prop_by_prop(optionset, group, 34164327Sdougm property, SA_PROP_OP_UPDATE); 34174327Sdougm } 34183034Sdougm } else { 34194327Sdougm ret = SA_NO_SUCH_PROP; 34203034Sdougm } 34213034Sdougm } 34223034Sdougm return (ret); 34233034Sdougm } 34243034Sdougm 34253034Sdougm /* 34266007Sthurlow * sa_get_protocol_section(propset, prop) 34276007Sthurlow * 34286007Sthurlow * Get the specified protocol specific section. These are global to 34296007Sthurlow * the protocol and not specific to a group or share. 34306007Sthurlow */ 34316007Sthurlow 34326007Sthurlow sa_protocol_properties_t 34336007Sthurlow sa_get_protocol_section(sa_protocol_properties_t propset, char *section) 34346007Sthurlow { 34356007Sthurlow xmlNodePtr node = (xmlNodePtr)propset; 34366007Sthurlow xmlChar *value = NULL; 34376007Sthurlow char *proto; 34386007Sthurlow 34396007Sthurlow proto = sa_get_optionset_attr(propset, "type"); 34408271SGordon.Ross@Sun.COM if ((sa_proto_get_featureset(proto) & SA_FEATURE_HAS_SECTIONS) == 0) { 34418271SGordon.Ross@Sun.COM if (proto != NULL) 34428271SGordon.Ross@Sun.COM sa_free_attr_string(proto); 34436007Sthurlow return (propset); 34448271SGordon.Ross@Sun.COM } 34456007Sthurlow 34466007Sthurlow for (node = node->children; node != NULL; 34476007Sthurlow node = node->next) { 34486007Sthurlow if (xmlStrcmp(node->name, (xmlChar *)"section") == 0) { 34496007Sthurlow if (section == NULL) 34506007Sthurlow break; 34516007Sthurlow value = xmlGetProp(node, (xmlChar *)"name"); 34526007Sthurlow if (value != NULL && 34536007Sthurlow xmlStrcasecmp(value, (xmlChar *)section) == 0) { 34546007Sthurlow break; 34556007Sthurlow } 34566007Sthurlow if (value != NULL) { 34576007Sthurlow xmlFree(value); 34586007Sthurlow value = NULL; 34596007Sthurlow } 34606007Sthurlow } 34616007Sthurlow } 34626007Sthurlow if (value != NULL) 34636007Sthurlow xmlFree(value); 34648271SGordon.Ross@Sun.COM if (proto != NULL) 34658271SGordon.Ross@Sun.COM sa_free_attr_string(proto); 34666007Sthurlow if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"section") != 0) { 34676007Sthurlow /* 34686007Sthurlow * avoid a non option node -- it is possible to be a 34696007Sthurlow * text node 34706007Sthurlow */ 34716007Sthurlow node = NULL; 34726007Sthurlow } 34736007Sthurlow return ((sa_protocol_properties_t)node); 34746007Sthurlow } 34756007Sthurlow 34766007Sthurlow /* 34776007Sthurlow * sa_get_next_protocol_section(prop, find) 34786007Sthurlow * 34796007Sthurlow * Get the next protocol specific section in the list. 34806007Sthurlow */ 34816007Sthurlow 34826007Sthurlow sa_property_t 34836007Sthurlow sa_get_next_protocol_section(sa_property_t prop, char *find) 34846007Sthurlow { 34856007Sthurlow xmlNodePtr node; 34866007Sthurlow xmlChar *value = NULL; 34876007Sthurlow char *proto; 34886007Sthurlow 34896007Sthurlow proto = sa_get_optionset_attr(prop, "type"); 34908271SGordon.Ross@Sun.COM if ((sa_proto_get_featureset(proto) & SA_FEATURE_HAS_SECTIONS) == 0) { 34918271SGordon.Ross@Sun.COM if (proto != NULL) 34928271SGordon.Ross@Sun.COM sa_free_attr_string(proto); 34936007Sthurlow return ((sa_property_t)NULL); 34948271SGordon.Ross@Sun.COM } 34956007Sthurlow 34966007Sthurlow for (node = ((xmlNodePtr)prop)->next; node != NULL; 34976007Sthurlow node = node->next) { 34986007Sthurlow if (xmlStrcmp(node->name, (xmlChar *)"section") == 0) { 34996007Sthurlow if (find == NULL) 35006007Sthurlow break; 35016007Sthurlow value = xmlGetProp(node, (xmlChar *)"name"); 35026007Sthurlow if (value != NULL && 35036007Sthurlow xmlStrcasecmp(value, (xmlChar *)find) == 0) { 35046007Sthurlow break; 35056007Sthurlow } 35066007Sthurlow if (value != NULL) { 35076007Sthurlow xmlFree(value); 35086007Sthurlow value = NULL; 35096007Sthurlow } 35106007Sthurlow 35116007Sthurlow } 35126007Sthurlow } 35136007Sthurlow if (value != NULL) 35146007Sthurlow xmlFree(value); 35158271SGordon.Ross@Sun.COM if (proto != NULL) 35168271SGordon.Ross@Sun.COM sa_free_attr_string(proto); 35176007Sthurlow return ((sa_property_t)node); 35186007Sthurlow } 35196007Sthurlow 35206007Sthurlow /* 35213034Sdougm * sa_get_protocol_property(propset, prop) 35223034Sdougm * 35233034Sdougm * Get the specified protocol specific property. These are global to 35243034Sdougm * the protocol and not specific to a group or share. 35253034Sdougm */ 35263034Sdougm 35273034Sdougm sa_property_t 35283034Sdougm sa_get_protocol_property(sa_protocol_properties_t propset, char *prop) 35293034Sdougm { 35303034Sdougm xmlNodePtr node = (xmlNodePtr)propset; 35313034Sdougm xmlChar *value = NULL; 35323034Sdougm 35336007Sthurlow if (propset == NULL) 35346007Sthurlow return (NULL); 35356007Sthurlow 35363034Sdougm for (node = node->children; node != NULL; 35374327Sdougm node = node->next) { 35384327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 35394327Sdougm if (prop == NULL) 35404327Sdougm break; 35414327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 35424327Sdougm if (value != NULL && 35434327Sdougm xmlStrcasecmp(value, (xmlChar *)prop) == 0) { 35444327Sdougm break; 35454327Sdougm } 35464327Sdougm if (value != NULL) { 35474327Sdougm xmlFree(value); 35484327Sdougm value = NULL; 35494327Sdougm } 35503034Sdougm } 35513034Sdougm } 35523034Sdougm if (value != NULL) 35533034Sdougm xmlFree(value); 35543034Sdougm if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"option") != 0) { 35554327Sdougm /* 35564327Sdougm * avoid a non option node -- it is possible to be a 35574327Sdougm * text node 35584327Sdougm */ 35594327Sdougm node = NULL; 35603034Sdougm } 35613034Sdougm return ((sa_property_t)node); 35623034Sdougm } 35633034Sdougm 35643034Sdougm /* 35653034Sdougm * sa_get_next_protocol_property(prop) 35663034Sdougm * 35673034Sdougm * Get the next protocol specific property in the list. 35683034Sdougm */ 35693034Sdougm 35703034Sdougm sa_property_t 35716007Sthurlow sa_get_next_protocol_property(sa_property_t prop, char *find) 35723034Sdougm { 35733034Sdougm xmlNodePtr node; 35746007Sthurlow xmlChar *value = NULL; 35753034Sdougm 35763034Sdougm for (node = ((xmlNodePtr)prop)->next; node != NULL; 35774327Sdougm node = node->next) { 35783034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 35796007Sthurlow if (find == NULL) 35806007Sthurlow break; 35816007Sthurlow value = xmlGetProp(node, (xmlChar *)"type"); 35826007Sthurlow if (value != NULL && 35836007Sthurlow xmlStrcasecmp(value, (xmlChar *)find) == 0) { 35846007Sthurlow break; 35856007Sthurlow } 35866007Sthurlow if (value != NULL) { 35876007Sthurlow xmlFree(value); 35886007Sthurlow value = NULL; 35896007Sthurlow } 35906007Sthurlow 35913034Sdougm } 35923034Sdougm } 35936007Sthurlow if (value != NULL) 35946007Sthurlow xmlFree(value); 35953034Sdougm return ((sa_property_t)node); 35963034Sdougm } 35973034Sdougm 35983034Sdougm /* 35993034Sdougm * sa_set_protocol_property(prop, value) 36003034Sdougm * 36013034Sdougm * Set the specified property to have the new value. The protocol 36023034Sdougm * specific plugin will then be called to update the property. 36033034Sdougm */ 36043034Sdougm 36053034Sdougm int 36066007Sthurlow sa_set_protocol_property(sa_property_t prop, char *section, char *value) 36073034Sdougm { 36083034Sdougm sa_protocol_properties_t propset; 36093034Sdougm char *proto; 36103034Sdougm int ret = SA_INVALID_PROTOCOL; 36113034Sdougm 36123034Sdougm propset = ((xmlNodePtr)prop)->parent; 36133034Sdougm if (propset != NULL) { 36144327Sdougm proto = sa_get_optionset_attr(propset, "type"); 36154327Sdougm if (proto != NULL) { 36166007Sthurlow if (section != NULL) 36176007Sthurlow set_node_attr((xmlNodePtr)prop, "section", 36186007Sthurlow section); 36194327Sdougm set_node_attr((xmlNodePtr)prop, "value", value); 36204327Sdougm ret = sa_proto_set_property(proto, prop); 36214327Sdougm sa_free_attr_string(proto); 36224327Sdougm } 36233034Sdougm } 36243034Sdougm return (ret); 36253034Sdougm } 36263034Sdougm 36273034Sdougm /* 36283034Sdougm * sa_add_protocol_property(propset, prop) 36293034Sdougm * 36305331Samw * Add a new property to the protocol specific property set. 36313034Sdougm */ 36323034Sdougm 36333034Sdougm int 36343034Sdougm sa_add_protocol_property(sa_protocol_properties_t propset, sa_property_t prop) 36353034Sdougm { 36363034Sdougm xmlNodePtr node; 36373034Sdougm 36383034Sdougm /* should check for legitimacy */ 36393034Sdougm node = xmlAddChild((xmlNodePtr)propset, (xmlNodePtr)prop); 36403034Sdougm if (node != NULL) 36414327Sdougm return (SA_OK); 36423034Sdougm return (SA_NO_MEMORY); 36433034Sdougm } 36443034Sdougm 36453034Sdougm /* 36463034Sdougm * sa_create_protocol_properties(proto) 36473034Sdougm * 36485331Samw * Create a protocol specific property set. 36493034Sdougm */ 36503034Sdougm 36513034Sdougm sa_protocol_properties_t 36523034Sdougm sa_create_protocol_properties(char *proto) 36533034Sdougm { 36543034Sdougm xmlNodePtr node; 36554327Sdougm 36563034Sdougm node = xmlNewNode(NULL, (xmlChar *)"propertyset"); 36574327Sdougm if (node != NULL) 36586007Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto); 36593034Sdougm return (node); 36603034Sdougm } 36615331Samw 36625331Samw /* 36635331Samw * sa_get_share_resource(share, resource) 36645331Samw * 36655331Samw * Get the named resource from the share, if it exists. If resource is 36665331Samw * NULL, get the first resource. 36675331Samw */ 36685331Samw 36695331Samw sa_resource_t 36705331Samw sa_get_share_resource(sa_share_t share, char *resource) 36715331Samw { 36725331Samw xmlNodePtr node = NULL; 36735331Samw xmlChar *name; 36745331Samw 36755331Samw if (share != NULL) { 36765331Samw for (node = ((xmlNodePtr)share)->children; node != NULL; 36775331Samw node = node->next) { 36785331Samw if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0) { 36795331Samw if (resource == NULL) { 36805331Samw /* 36815331Samw * We are looking for the first 36825331Samw * resource node and not a names 36835331Samw * resource. 36845331Samw */ 36855331Samw break; 36865331Samw } else { 36875331Samw /* is it the correct share? */ 36885331Samw name = xmlGetProp(node, 36895331Samw (xmlChar *)"name"); 36905331Samw if (name != NULL && 36915331Samw xmlStrcasecmp(name, 36925331Samw (xmlChar *)resource) == 0) { 36935331Samw xmlFree(name); 36945331Samw break; 36955331Samw } 36965331Samw xmlFree(name); 36975331Samw } 36985331Samw } 36995331Samw } 37005331Samw } 37015331Samw return ((sa_resource_t)node); 37025331Samw } 37035331Samw 37045331Samw /* 37055331Samw * sa_get_next_resource(resource) 37065331Samw * Return the next share following the specified share 37075331Samw * from the internal list of shares. Returns NULL if there 37085331Samw * are no more shares. The list is relative to the same 37095331Samw * group. 37105331Samw */ 37115331Samw sa_share_t 37125331Samw sa_get_next_resource(sa_resource_t resource) 37135331Samw { 37145331Samw xmlNodePtr node = NULL; 37155331Samw 37165331Samw if (resource != NULL) { 37175331Samw for (node = ((xmlNodePtr)resource)->next; node != NULL; 37185331Samw node = node->next) { 37195331Samw if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0) 37205331Samw break; 37215331Samw } 37225331Samw } 37235331Samw return ((sa_share_t)node); 37245331Samw } 37255331Samw 37265331Samw /* 37275331Samw * _sa_get_next_resource_index(share) 37285331Samw * 37295331Samw * get the next resource index number (one greater then current largest) 37305331Samw */ 37315331Samw 37325331Samw static int 37335331Samw _sa_get_next_resource_index(sa_share_t share) 37345331Samw { 37355331Samw sa_resource_t resource; 37365331Samw int index = 0; 37375331Samw char *id; 37385331Samw 37395331Samw for (resource = sa_get_share_resource(share, NULL); 37405331Samw resource != NULL; 37415331Samw resource = sa_get_next_resource(resource)) { 37425331Samw id = get_node_attr((void *)resource, "id"); 37435331Samw if (id != NULL) { 37445331Samw int val; 37455331Samw val = atoi(id); 37465331Samw if (val > index) 37475331Samw index = val; 37485331Samw sa_free_attr_string(id); 37495331Samw } 37505331Samw } 37515331Samw return (index + 1); 37525331Samw } 37535331Samw 37545331Samw 37555331Samw /* 37565331Samw * sa_add_resource(share, resource, persist, &err) 37575331Samw * 37585331Samw * Adds a new resource name associated with share. The resource name 37595331Samw * must be unique in the system and will be case insensitive (eventually). 37605331Samw */ 37615331Samw 37625331Samw sa_resource_t 37635331Samw sa_add_resource(sa_share_t share, char *resource, int persist, int *error) 37645331Samw { 37655331Samw xmlNodePtr node; 37665331Samw int err = SA_OK; 37675331Samw sa_resource_t res; 37685331Samw sa_group_t group; 37695331Samw sa_handle_t handle; 37705331Samw char istring[8]; /* just big enough for an integer value */ 37715331Samw int index; 37725331Samw 37735331Samw group = sa_get_parent_group(share); 37745331Samw handle = sa_find_group_handle(group); 37755331Samw res = sa_find_resource(handle, resource); 37765331Samw if (res != NULL) { 37775331Samw err = SA_DUPLICATE_NAME; 37785331Samw res = NULL; 37795331Samw } else { 37805331Samw node = xmlNewChild((xmlNodePtr)share, NULL, 37815331Samw (xmlChar *)"resource", NULL); 37825331Samw if (node != NULL) { 37836007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 37845331Samw (xmlChar *)resource); 37856007Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", persist ? 37865331Samw (xmlChar *)"persist" : (xmlChar *)"transient"); 37875331Samw if (persist != SA_SHARE_TRANSIENT) { 37885331Samw index = _sa_get_next_resource_index(share); 37895331Samw (void) snprintf(istring, sizeof (istring), "%d", 37905331Samw index); 37916007Sthurlow (void) xmlSetProp(node, (xmlChar *)"id", 37925331Samw (xmlChar *)istring); 37937483SDoug.McCallum@Sun.COM 37947483SDoug.McCallum@Sun.COM if (!sa_is_persistent((sa_group_t)share)) 37957483SDoug.McCallum@Sun.COM goto done; 37967483SDoug.McCallum@Sun.COM 37977483SDoug.McCallum@Sun.COM if (!sa_group_is_zfs(group)) { 37985331Samw /* ZFS doesn't use resource names */ 37995331Samw sa_handle_impl_t ihandle; 38007483SDoug.McCallum@Sun.COM 38015331Samw ihandle = (sa_handle_impl_t) 38025331Samw sa_find_group_handle( 38035331Samw group); 38045331Samw if (ihandle != NULL) 38055331Samw err = sa_commit_share( 38065331Samw ihandle->scfhandle, group, 38075331Samw share); 38085331Samw else 38095331Samw err = SA_SYSTEM_ERR; 38107483SDoug.McCallum@Sun.COM } else { 38117483SDoug.McCallum@Sun.COM err = sa_zfs_update((sa_share_t)group); 38125331Samw } 38135331Samw } 38145331Samw } 38155331Samw } 38167483SDoug.McCallum@Sun.COM done: 38175331Samw if (error != NULL) 38185331Samw *error = err; 38195331Samw return ((sa_resource_t)node); 38205331Samw } 38215331Samw 38225331Samw /* 38235331Samw * sa_remove_resource(resource) 38245331Samw * 38255331Samw * Remove the resource name from the share (and the system) 38265331Samw */ 38275331Samw 38285331Samw int 38295331Samw sa_remove_resource(sa_resource_t resource) 38305331Samw { 38315331Samw sa_share_t share; 38325331Samw sa_group_t group; 38335331Samw char *type; 38345331Samw int ret = SA_OK; 38357483SDoug.McCallum@Sun.COM boolean_t transient = B_FALSE; 38365521Sas200622 sa_optionset_t opt; 38375331Samw 38385331Samw share = sa_get_resource_parent(resource); 38395331Samw type = sa_get_share_attr(share, "type"); 38405331Samw group = sa_get_parent_group(share); 38415331Samw 38425331Samw 38435331Samw if (type != NULL) { 38445331Samw if (strcmp(type, "persist") != 0) 38457483SDoug.McCallum@Sun.COM transient = B_TRUE; 38465331Samw sa_free_attr_string(type); 38475331Samw } 38485331Samw 38495521Sas200622 /* Disable the resource for all protocols. */ 38505521Sas200622 (void) sa_disable_resource(resource, NULL); 38515521Sas200622 38525521Sas200622 /* Remove any optionsets from the resource. */ 38535521Sas200622 for (opt = sa_get_optionset(resource, NULL); 38545521Sas200622 opt != NULL; 38555521Sas200622 opt = sa_get_next_optionset(opt)) 38565521Sas200622 (void) sa_destroy_optionset(opt); 38575521Sas200622 38585331Samw /* Remove from the share */ 38595331Samw xmlUnlinkNode((xmlNode *)resource); 38605331Samw xmlFreeNode((xmlNode *)resource); 38615331Samw 38625331Samw /* only do SMF action if permanent and not ZFS */ 38637483SDoug.McCallum@Sun.COM if (transient) 38647483SDoug.McCallum@Sun.COM return (ret); 38657483SDoug.McCallum@Sun.COM 38667483SDoug.McCallum@Sun.COM if (!sa_group_is_zfs(group)) { 38675331Samw sa_handle_impl_t ihandle; 38685331Samw ihandle = (sa_handle_impl_t)sa_find_group_handle(group); 38695331Samw if (ihandle != NULL) 38705331Samw ret = sa_commit_share(ihandle->scfhandle, group, share); 38715331Samw else 38725331Samw ret = SA_SYSTEM_ERR; 38737483SDoug.McCallum@Sun.COM } else { 38747483SDoug.McCallum@Sun.COM ret = sa_zfs_update((sa_share_t)group); 38755331Samw } 38768845Samw@Sun.COM 38775331Samw return (ret); 38785331Samw } 38795331Samw 38805331Samw /* 38818845Samw@Sun.COM * proto_rename_resource(handle, group, resource, newname) 38825331Samw * 38835331Samw * Helper function for sa_rename_resource that notifies the protocol 38845331Samw * of a resource name change prior to a config repository update. 38855331Samw */ 38865331Samw static int 38875331Samw proto_rename_resource(sa_handle_t handle, sa_group_t group, 38885331Samw sa_resource_t resource, char *newname) 38895331Samw { 38905331Samw sa_optionset_t optionset; 38915331Samw int ret = SA_OK; 38925331Samw int err; 38935331Samw 38945331Samw for (optionset = sa_get_optionset(group, NULL); 38955331Samw optionset != NULL; 38965331Samw optionset = sa_get_next_optionset(optionset)) { 38975331Samw char *type; 38985331Samw type = sa_get_optionset_attr(optionset, "type"); 38995331Samw if (type != NULL) { 39005331Samw err = sa_proto_rename_resource(handle, type, resource, 39015331Samw newname); 39025331Samw if (err != SA_OK) 39035331Samw ret = err; 39045331Samw sa_free_attr_string(type); 39055331Samw } 39065331Samw } 39075331Samw return (ret); 39085331Samw } 39095331Samw 39105331Samw /* 39115331Samw * sa_rename_resource(resource, newname) 39125331Samw * 39135331Samw * Rename the resource to the new name, if it is unique. 39145331Samw */ 39155331Samw 39165331Samw int 39175331Samw sa_rename_resource(sa_resource_t resource, char *newname) 39185331Samw { 39195331Samw sa_share_t share; 39205331Samw sa_group_t group = NULL; 39215331Samw sa_resource_t target; 39225331Samw int ret = SA_CONFIG_ERR; 39235331Samw sa_handle_t handle = NULL; 39245331Samw 39255331Samw share = sa_get_resource_parent(resource); 39265331Samw if (share == NULL) 39275331Samw return (ret); 39285331Samw 39295331Samw group = sa_get_parent_group(share); 39305331Samw if (group == NULL) 39315331Samw return (ret); 39325331Samw 39335331Samw handle = (sa_handle_impl_t)sa_find_group_handle(group); 39345331Samw if (handle == NULL) 39355331Samw return (ret); 39365331Samw 39375331Samw target = sa_find_resource(handle, newname); 39385331Samw if (target != NULL) { 39395331Samw ret = SA_DUPLICATE_NAME; 39405331Samw } else { 39415331Samw /* 39425331Samw * Everything appears to be valid at this 39435331Samw * point. Change the name of the active share and then 39445331Samw * update the share in the appropriate repository. 39455331Samw */ 39465331Samw ret = proto_rename_resource(handle, group, resource, newname); 39475331Samw set_node_attr(resource, "name", newname); 39487483SDoug.McCallum@Sun.COM 39497483SDoug.McCallum@Sun.COM if (!sa_is_persistent((sa_group_t)share)) 39507483SDoug.McCallum@Sun.COM return (ret); 39517483SDoug.McCallum@Sun.COM 39527483SDoug.McCallum@Sun.COM if (!sa_group_is_zfs(group)) { 39535331Samw sa_handle_impl_t ihandle = (sa_handle_impl_t)handle; 39545331Samw ret = sa_commit_share(ihandle->scfhandle, group, 39555331Samw share); 39567483SDoug.McCallum@Sun.COM } else { 39577483SDoug.McCallum@Sun.COM ret = sa_zfs_update((sa_share_t)group); 39585331Samw } 39595331Samw } 39605331Samw return (ret); 39615331Samw } 39625331Samw 39635331Samw /* 39645331Samw * sa_get_resource_attr(resource, tag) 39655331Samw * 39665331Samw * Get the named attribute of the resource. "name" and "id" are 39675331Samw * currently defined. NULL if tag not defined. 39685331Samw */ 39695331Samw 39705331Samw char * 39715331Samw sa_get_resource_attr(sa_resource_t resource, char *tag) 39725331Samw { 39735331Samw return (get_node_attr((void *)resource, tag)); 39745331Samw } 39755331Samw 39765331Samw /* 39775331Samw * sa_set_resource_attr(resource, tag, value) 39785331Samw * 39795331Samw * Get the named attribute of the resource. "name" and "id" are 39805331Samw * currently defined. NULL if tag not defined. Currently we don't do 39815331Samw * much, but additional checking may be needed in the future. 39825331Samw */ 39835331Samw 39845331Samw int 39855331Samw sa_set_resource_attr(sa_resource_t resource, char *tag, char *value) 39865331Samw { 39875331Samw set_node_attr((void *)resource, tag, value); 39885331Samw return (SA_OK); 39895331Samw } 39905331Samw 39915331Samw /* 39925331Samw * sa_get_resource_parent(resource_t) 39935331Samw * 39945331Samw * Returns the share associated with the resource. 39955331Samw */ 39965331Samw 39975331Samw sa_share_t 39985331Samw sa_get_resource_parent(sa_resource_t resource) 39995331Samw { 40005331Samw sa_share_t share = NULL; 40015331Samw 40025331Samw if (resource != NULL) 40035331Samw share = (sa_share_t)((xmlNodePtr)resource)->parent; 40045331Samw return (share); 40055331Samw } 40065331Samw 40075331Samw /* 40085331Samw * find_resource(group, name) 40095331Samw * 40105331Samw * Find the resource within the group. 40115331Samw */ 40125331Samw 40135331Samw static sa_resource_t 40145331Samw find_resource(sa_group_t group, char *resname) 40155331Samw { 40165331Samw sa_share_t share; 40175331Samw sa_resource_t resource = NULL; 40185331Samw char *name; 40195331Samw 40205331Samw /* Iterate over all the shares and resources in the group. */ 40215331Samw for (share = sa_get_share(group, NULL); 40225331Samw share != NULL && resource == NULL; 40235331Samw share = sa_get_next_share(share)) { 40245331Samw for (resource = sa_get_share_resource(share, NULL); 40255331Samw resource != NULL; 40265331Samw resource = sa_get_next_resource(resource)) { 40275331Samw name = sa_get_resource_attr(resource, "name"); 40285331Samw if (name != NULL && xmlStrcasecmp((xmlChar*)name, 40295331Samw (xmlChar*)resname) == 0) { 40305331Samw sa_free_attr_string(name); 40315331Samw break; 40325331Samw } 40335331Samw if (name != NULL) { 40345331Samw sa_free_attr_string(name); 40355331Samw } 40365331Samw } 40375331Samw } 40385331Samw return (resource); 40395331Samw } 40405331Samw 40415331Samw /* 40425331Samw * sa_find_resource(name) 40435331Samw * 40445331Samw * Find the named resource in the system. 40455331Samw */ 40465331Samw 40475331Samw sa_resource_t 40485331Samw sa_find_resource(sa_handle_t handle, char *name) 40495331Samw { 40505331Samw sa_group_t group; 40515331Samw sa_group_t zgroup; 40525331Samw sa_resource_t resource = NULL; 40535331Samw 40545331Samw /* 40555331Samw * Iterate over all groups and zfs subgroups and check for 40565331Samw * resource name in them. 40575331Samw */ 40585331Samw for (group = sa_get_group(handle, NULL); group != NULL; 40595331Samw group = sa_get_next_group(group)) { 40605331Samw 40615331Samw if (is_zfs_group(group)) { 40625331Samw for (zgroup = 40635331Samw (sa_group_t)_sa_get_child_node((xmlNodePtr)group, 40645331Samw (xmlChar *)"group"); 40655331Samw zgroup != NULL && resource == NULL; 40665331Samw zgroup = sa_get_next_group(zgroup)) { 40675331Samw resource = find_resource(zgroup, name); 40685331Samw } 40695331Samw } else { 40705331Samw resource = find_resource(group, name); 40715331Samw } 40725331Samw if (resource != NULL) 40735331Samw break; 40745331Samw } 40755331Samw return (resource); 40765331Samw } 40775331Samw 40785331Samw /* 40795331Samw * sa_get_resource(group, resource) 40805331Samw * 40815331Samw * Search all the shares in the specified group for a share with a 40825331Samw * resource name matching the one specified. 40835331Samw * 40845331Samw * In the future, it may be advantageous to allow group to be NULL and 40855331Samw * search all groups but that isn't needed at present. 40865331Samw */ 40875331Samw 40885331Samw sa_resource_t 40895331Samw sa_get_resource(sa_group_t group, char *resource) 40905331Samw { 40915331Samw sa_share_t share = NULL; 40925331Samw sa_resource_t res = NULL; 40935331Samw 40945331Samw if (resource != NULL) { 40955331Samw for (share = sa_get_share(group, NULL); 40965331Samw share != NULL && res == NULL; 40975331Samw share = sa_get_next_share(share)) { 40985331Samw res = sa_get_share_resource(share, resource); 40995331Samw } 41005331Samw } 41015331Samw return (res); 41025331Samw } 41035331Samw 41045331Samw /* 41056270Sdougm * get_protocol_list(optionset, object) 41066270Sdougm * 41076270Sdougm * Get the protocol optionset list for the object and add them as 41086270Sdougm * properties to optionset. 41096270Sdougm */ 41106270Sdougm static int 41116270Sdougm get_protocol_list(sa_optionset_t optionset, void *object) 41126270Sdougm { 41136270Sdougm sa_property_t prop; 41146270Sdougm sa_optionset_t opts; 41156270Sdougm int ret = SA_OK; 41166270Sdougm 41176270Sdougm for (opts = sa_get_optionset(object, NULL); 41186270Sdougm opts != NULL; 41196270Sdougm opts = sa_get_next_optionset(opts)) { 41206270Sdougm char *type; 41216270Sdougm type = sa_get_optionset_attr(opts, "type"); 41226270Sdougm /* 41236270Sdougm * It is possible to have a non-protocol optionset. We 41246270Sdougm * skip any of those found. 41256270Sdougm */ 41266270Sdougm if (type == NULL) 41276270Sdougm continue; 41286270Sdougm prop = sa_create_property(type, "true"); 41296270Sdougm sa_free_attr_string(type); 41306270Sdougm if (prop != NULL) 41316270Sdougm prop = (sa_property_t)xmlAddChild((xmlNodePtr)optionset, 41326270Sdougm (xmlNodePtr)prop); 41336270Sdougm /* If prop is NULL, don't bother continuing */ 41346270Sdougm if (prop == NULL) { 41356270Sdougm ret = SA_NO_MEMORY; 41366270Sdougm break; 41376270Sdougm } 41386270Sdougm } 41396270Sdougm return (ret); 41406270Sdougm } 41416270Sdougm 41426270Sdougm /* 41436270Sdougm * sa_free_protoset(optionset) 41446270Sdougm * 41456270Sdougm * Free the protocol property optionset. 41466270Sdougm */ 41476270Sdougm static void 41486270Sdougm sa_free_protoset(sa_optionset_t optionset) 41496270Sdougm { 41506270Sdougm if (optionset != NULL) { 41516270Sdougm xmlUnlinkNode((xmlNodePtr) optionset); 41526270Sdougm xmlFreeNode((xmlNodePtr) optionset); 41536270Sdougm } 41546270Sdougm } 41556270Sdougm 41566270Sdougm /* 41576270Sdougm * sa_optionset_t sa_get_active_protocols(object) 41586270Sdougm * 41596270Sdougm * Return a list of the protocols that are active for the object. 41606270Sdougm * This is currently an internal helper function, but could be 41616270Sdougm * made visible if there is enough demand for it. 41626270Sdougm * 41636270Sdougm * The function finds the parent group and extracts the protocol 41646270Sdougm * optionsets creating a new optionset with the protocols as properties. 41656270Sdougm * 41666270Sdougm * The caller must free the returned optionset. 41676270Sdougm */ 41686270Sdougm 41696270Sdougm static sa_optionset_t 41706270Sdougm sa_get_active_protocols(void *object) 41716270Sdougm { 41726270Sdougm sa_optionset_t options; 41736270Sdougm sa_share_t share = NULL; 41746270Sdougm sa_group_t group = NULL; 41756270Sdougm sa_resource_t resource = NULL; 41766270Sdougm int ret = SA_OK; 41776270Sdougm 41786270Sdougm if (object == NULL) 41796270Sdougm return (NULL); 41806270Sdougm options = (sa_optionset_t)xmlNewNode(NULL, (xmlChar *)"optionset"); 41816270Sdougm if (options == NULL) 41826270Sdougm return (NULL); 41836270Sdougm 41846270Sdougm /* 41856270Sdougm * Find the objects up the tree that might have protocols 41866270Sdougm * enabled on them. 41876270Sdougm */ 41886270Sdougm if (sa_is_resource(object)) { 41896270Sdougm resource = (sa_resource_t)object; 41906270Sdougm share = sa_get_resource_parent(resource); 41916270Sdougm group = sa_get_parent_group(share); 41926270Sdougm } else if (sa_is_share(object)) { 41936270Sdougm share = (sa_share_t)object; 41946270Sdougm group = sa_get_parent_group(share); 41956270Sdougm } else { 41966270Sdougm group = (sa_group_t)group; 41976270Sdougm } 41986270Sdougm if (resource != NULL) 41996270Sdougm ret = get_protocol_list(options, resource); 42006270Sdougm if (ret == SA_OK && share != NULL) 42016270Sdougm ret = get_protocol_list(options, share); 42026270Sdougm if (ret == SA_OK && group != NULL) 42036270Sdougm ret = get_protocol_list(options, group); 42046270Sdougm 42056270Sdougm /* 42066270Sdougm * If there was an error, we won't have a complete list so 42076270Sdougm * abandon everything. The caller will have to deal with the 42086270Sdougm * issue. 42096270Sdougm */ 42106270Sdougm if (ret != SA_OK) { 42116270Sdougm sa_free_protoset(options); 42126270Sdougm options = NULL; 42136270Sdougm } 42146270Sdougm return (options); 42156270Sdougm } 42166270Sdougm 42176270Sdougm /* 42185331Samw * sa_enable_resource, protocol) 42195331Samw * Disable the specified share to the specified protocol. 42205331Samw * If protocol is NULL, then all protocols. 42215331Samw */ 42225331Samw int 42235331Samw sa_enable_resource(sa_resource_t resource, char *protocol) 42245331Samw { 42255331Samw int ret = SA_OK; 42265331Samw 42275331Samw if (protocol != NULL) { 42285331Samw ret = sa_proto_share_resource(protocol, resource); 42295331Samw } else { 42306270Sdougm sa_optionset_t protoset; 42316270Sdougm sa_property_t prop; 42326270Sdougm char *proto; 42336270Sdougm int err; 42346270Sdougm 42355331Samw /* need to do all protocols */ 42366270Sdougm protoset = sa_get_active_protocols(resource); 42376270Sdougm if (protoset == NULL) 42386270Sdougm return (SA_NO_MEMORY); 42396270Sdougm for (prop = sa_get_property(protoset, NULL); 42406270Sdougm prop != NULL; 42416270Sdougm prop = sa_get_next_property(prop)) { 42426270Sdougm proto = sa_get_property_attr(prop, "type"); 42436270Sdougm if (proto == NULL) { 42446270Sdougm ret = SA_NO_MEMORY; 42456270Sdougm continue; 42465331Samw } 42476270Sdougm err = sa_proto_share_resource(proto, resource); 42486270Sdougm if (err != SA_OK) 42496270Sdougm ret = err; 42506270Sdougm sa_free_attr_string(proto); 42515331Samw } 42526270Sdougm sa_free_protoset(protoset); 42535331Samw } 42545331Samw if (ret == SA_OK) 42555331Samw (void) sa_set_resource_attr(resource, "shared", NULL); 42565331Samw 42575331Samw return (ret); 42585331Samw } 42595331Samw 42605331Samw /* 42615331Samw * sa_disable_resource(resource, protocol) 42625331Samw * 42635331Samw * Disable the specified share for the specified protocol. If 42645331Samw * protocol is NULL, then all protocols. If the underlying 42655331Samw * protocol doesn't implement disable at the resource level, we 42665331Samw * disable at the share level. 42675331Samw */ 42685331Samw int 42695331Samw sa_disable_resource(sa_resource_t resource, char *protocol) 42705331Samw { 42715331Samw int ret = SA_OK; 42725331Samw 42735331Samw if (protocol != NULL) { 42745331Samw ret = sa_proto_unshare_resource(protocol, resource); 42755331Samw if (ret == SA_NOT_IMPLEMENTED) { 42765331Samw sa_share_t parent; 42775331Samw /* 42785331Samw * The protocol doesn't implement unshare 42795331Samw * resource. That implies that resource names are 42805331Samw * simple aliases for this protocol so we need to 42815331Samw * unshare the share. 42825331Samw */ 42835331Samw parent = sa_get_resource_parent(resource); 42845331Samw if (parent != NULL) 42855331Samw ret = sa_disable_share(parent, protocol); 42865331Samw else 42875331Samw ret = SA_CONFIG_ERR; 42885331Samw } 42895331Samw } else { 42906270Sdougm sa_optionset_t protoset; 42916270Sdougm sa_property_t prop; 42926270Sdougm char *proto; 42936270Sdougm int err; 42946270Sdougm 42955331Samw /* need to do all protocols */ 42966270Sdougm protoset = sa_get_active_protocols(resource); 42976270Sdougm if (protoset == NULL) 42986270Sdougm return (SA_NO_MEMORY); 42996270Sdougm for (prop = sa_get_property(protoset, NULL); 43006270Sdougm prop != NULL; 43016270Sdougm prop = sa_get_next_property(prop)) { 43026270Sdougm proto = sa_get_property_attr(prop, "type"); 43036270Sdougm if (proto == NULL) { 43046270Sdougm ret = SA_NO_MEMORY; 43056270Sdougm continue; 43065331Samw } 43076270Sdougm err = sa_proto_unshare_resource(proto, resource); 43086270Sdougm if (err == SA_NOT_SUPPORTED) { 43096270Sdougm sa_share_t parent; 43106270Sdougm parent = sa_get_resource_parent(resource); 43116270Sdougm if (parent != NULL) 43126270Sdougm err = sa_disable_share(parent, proto); 43136270Sdougm else 43146270Sdougm err = SA_CONFIG_ERR; 43156270Sdougm } 43166270Sdougm if (err != SA_OK) 43176270Sdougm ret = err; 43186270Sdougm sa_free_attr_string(proto); 43195331Samw } 43206270Sdougm sa_free_protoset(protoset); 43215331Samw } 43225331Samw if (ret == SA_OK) 43235331Samw (void) sa_set_resource_attr(resource, "shared", NULL); 43245331Samw 43255331Samw return (ret); 43265331Samw } 43275331Samw 43285331Samw /* 43295331Samw * sa_set_resource_description(resource, content) 43305331Samw * 43315331Samw * Set the description of share to content. 43325331Samw */ 43335331Samw 43345331Samw int 43355331Samw sa_set_resource_description(sa_resource_t resource, char *content) 43365331Samw { 43375331Samw xmlNodePtr node; 43385331Samw sa_group_t group; 43395331Samw sa_share_t share; 43405331Samw int ret = SA_OK; 43415331Samw 43425331Samw for (node = ((xmlNodePtr)resource)->children; 43435331Samw node != NULL; 43445331Samw node = node->next) { 43455331Samw if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 43465331Samw break; 43475331Samw } 43485331Samw } 43495331Samw 43505331Samw /* no existing description but want to add */ 43515331Samw if (node == NULL && content != NULL) { 43525331Samw /* add a description */ 43535331Samw node = _sa_set_share_description(resource, content); 43545331Samw } else if (node != NULL && content != NULL) { 43555331Samw /* update a description */ 43565331Samw xmlNodeSetContent(node, (xmlChar *)content); 43575331Samw } else if (node != NULL && content == NULL) { 43585331Samw /* remove an existing description */ 43595331Samw xmlUnlinkNode(node); 43605331Samw xmlFreeNode(node); 43615331Samw } 436212508Samw@Sun.COM 43635331Samw share = sa_get_resource_parent(resource); 43645331Samw group = sa_get_parent_group(share); 436512508Samw@Sun.COM if (group != NULL && 436612508Samw@Sun.COM sa_is_persistent(share) && (!sa_group_is_zfs(group))) { 43675331Samw sa_handle_impl_t impl_handle; 43685331Samw impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 43695331Samw if (impl_handle != NULL) 43705331Samw ret = sa_commit_share(impl_handle->scfhandle, 43715331Samw group, share); 43725331Samw else 43735331Samw ret = SA_SYSTEM_ERR; 43745331Samw } 43755331Samw return (ret); 43765331Samw } 43775331Samw 43785331Samw /* 43795331Samw * sa_get_resource_description(share) 43805331Samw * 43815331Samw * Return the description text for the specified share if it 43825331Samw * exists. NULL if no description exists. 43835331Samw */ 43845331Samw 43855331Samw char * 43865331Samw sa_get_resource_description(sa_resource_t resource) 43875331Samw { 43885331Samw xmlChar *description = NULL; 43895331Samw xmlNodePtr node; 43905331Samw 43915331Samw for (node = ((xmlNodePtr)resource)->children; node != NULL; 43925331Samw node = node->next) { 43935331Samw if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) 43945331Samw break; 43955331Samw } 43965331Samw if (node != NULL) { 43975331Samw description = xmlNodeGetContent(node); 43985331Samw fixproblemchars((char *)description); 43995331Samw } 44005331Samw return ((char *)description); 44015331Samw } 4402