13034Sdougm /* 23034Sdougm * CDDL HEADER START 33034Sdougm * 43034Sdougm * The contents of this file are subject to the terms of the 53034Sdougm * Common Development and Distribution License (the "License"). 63034Sdougm * You may not use this file except in compliance with the License. 73034Sdougm * 83034Sdougm * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 93034Sdougm * or http://www.opensolaris.org/os/licensing. 103034Sdougm * See the License for the specific language governing permissions 113034Sdougm * and limitations under the License. 123034Sdougm * 133034Sdougm * When distributing Covered Code, include this CDDL HEADER in each 143034Sdougm * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 153034Sdougm * If applicable, add the following below this CDDL HEADER, with the 163034Sdougm * fields enclosed by brackets "[]" replaced with your own identifying 173034Sdougm * information: Portions Copyright [yyyy] [name of copyright owner] 183034Sdougm * 193034Sdougm * CDDL HEADER END 203034Sdougm */ 213034Sdougm 223034Sdougm /* 238474SJose.Borrego@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 243034Sdougm * Use is subject to license terms. 253034Sdougm */ 263034Sdougm 273034Sdougm /* 283034Sdougm * Share control API 293034Sdougm */ 303034Sdougm #include <stdio.h> 313034Sdougm #include <string.h> 323034Sdougm #include <ctype.h> 333034Sdougm #include <sys/types.h> 343034Sdougm #include <sys/stat.h> 353663Sdougm #include <fcntl.h> 363034Sdougm #include <unistd.h> 373034Sdougm #include <libxml/parser.h> 383034Sdougm #include <libxml/tree.h> 393034Sdougm #include "libshare.h" 403034Sdougm #include "libshare_impl.h" 413034Sdougm #include <libscf.h> 423034Sdougm #include "scfutil.h" 433034Sdougm #include <ctype.h> 443034Sdougm #include <libintl.h> 453910Sdougm #include <thread.h> 463910Sdougm #include <synch.h> 473034Sdougm 483663Sdougm #define DFS_LOCK_FILE "/etc/dfs/fstypes" 494327Sdougm #define SA_STRSIZE 256 /* max string size for names */ 503663Sdougm 513034Sdougm /* 525331Samw * internal object type values returned by sa_get_object_type() 535331Samw */ 545331Samw #define SA_TYPE_UNKNOWN 0 555331Samw #define SA_TYPE_GROUP 1 565331Samw #define SA_TYPE_SHARE 2 575331Samw #define SA_TYPE_RESOURCE 3 585331Samw #define SA_TYPE_OPTIONSET 4 595331Samw #define SA_TYPE_ALTSPACE 5 605331Samw 615331Samw /* 623034Sdougm * internal data structures 633034Sdougm */ 643034Sdougm 653034Sdougm extern struct sa_proto_plugin *sap_proto_list; 663034Sdougm 673034Sdougm /* current SMF/SVC repository handle */ 683910Sdougm extern void getlegacyconfig(sa_handle_t, char *, xmlNodePtr *); 693910Sdougm extern int gettransients(sa_handle_impl_t, xmlNodePtr *); 703034Sdougm extern char *sa_fstype(char *); 713034Sdougm extern int sa_is_share(void *); 725331Samw extern int sa_is_resource(void *); 733034Sdougm extern ssize_t scf_max_name_len; /* defined in scfutil during initialization */ 743034Sdougm extern int sa_group_is_zfs(sa_group_t); 753034Sdougm extern int sa_path_is_zfs(char *); 763034Sdougm extern int sa_zfs_set_sharenfs(sa_group_t, char *, int); 775331Samw extern int sa_zfs_set_sharesmb(sa_group_t, char *, int); 783910Sdougm extern void update_legacy_config(sa_handle_t); 793034Sdougm extern int issubdir(char *, char *); 804327Sdougm extern int sa_zfs_init(sa_handle_impl_t); 813910Sdougm extern void sa_zfs_fini(sa_handle_impl_t); 823663Sdougm extern void sablocksigs(sigset_t *); 833663Sdougm extern void saunblocksigs(sigset_t *); 845331Samw static sa_group_t sa_get_optionset_parent(sa_optionset_t); 855331Samw static char *get_node_attr(void *, char *); 865951Sdougm extern void sa_update_sharetab_ts(sa_handle_t); 873034Sdougm 883910Sdougm /* 893910Sdougm * Data structures for finding/managing the document root to access 903910Sdougm * handle mapping. The list isn't expected to grow very large so a 913910Sdougm * simple list is acceptable. The purpose is to provide a way to start 923910Sdougm * with a group or share and find the library handle needed for 933910Sdougm * various operations. 943910Sdougm */ 953910Sdougm mutex_t sa_global_lock; 963910Sdougm struct doc2handle { 973910Sdougm struct doc2handle *next; 983910Sdougm xmlNodePtr root; 993910Sdougm sa_handle_impl_t handle; 1003910Sdougm }; 1013910Sdougm 1024327Sdougm /* definitions used in a couple of property functions */ 1034327Sdougm #define SA_PROP_OP_REMOVE 1 1044327Sdougm #define SA_PROP_OP_ADD 2 1054327Sdougm #define SA_PROP_OP_UPDATE 3 1064327Sdougm 1073910Sdougm static struct doc2handle *sa_global_handles = NULL; 1083034Sdougm 1093034Sdougm /* helper functions */ 1103034Sdougm 1113910Sdougm /* 1123910Sdougm * sa_errorstr(err) 1133910Sdougm * 1143910Sdougm * convert an error value to an error string 1153910Sdougm */ 1163910Sdougm 1173034Sdougm char * 1183034Sdougm sa_errorstr(int err) 1193034Sdougm { 1203034Sdougm static char errstr[32]; 1213034Sdougm char *ret = NULL; 1223034Sdougm 1233034Sdougm switch (err) { 1243034Sdougm case SA_OK: 1254327Sdougm ret = dgettext(TEXT_DOMAIN, "ok"); 1264327Sdougm break; 1273034Sdougm case SA_NO_SUCH_PATH: 1284327Sdougm ret = dgettext(TEXT_DOMAIN, "path doesn't exist"); 1294327Sdougm break; 1303034Sdougm case SA_NO_MEMORY: 1314327Sdougm ret = dgettext(TEXT_DOMAIN, "no memory"); 1324327Sdougm break; 1333034Sdougm case SA_DUPLICATE_NAME: 1344327Sdougm ret = dgettext(TEXT_DOMAIN, "name in use"); 1354327Sdougm break; 1363034Sdougm case SA_BAD_PATH: 1374327Sdougm ret = dgettext(TEXT_DOMAIN, "bad path"); 1384327Sdougm break; 1393034Sdougm case SA_NO_SUCH_GROUP: 1404327Sdougm ret = dgettext(TEXT_DOMAIN, "no such group"); 1414327Sdougm break; 1423034Sdougm case SA_CONFIG_ERR: 1434327Sdougm ret = dgettext(TEXT_DOMAIN, "configuration error"); 1444327Sdougm break; 1453034Sdougm case SA_SYSTEM_ERR: 1464327Sdougm ret = dgettext(TEXT_DOMAIN, "system error"); 1474327Sdougm break; 1483034Sdougm case SA_SYNTAX_ERR: 1494327Sdougm ret = dgettext(TEXT_DOMAIN, "syntax error"); 1504327Sdougm break; 1513034Sdougm case SA_NO_PERMISSION: 1524327Sdougm ret = dgettext(TEXT_DOMAIN, "no permission"); 1534327Sdougm break; 1543034Sdougm case SA_BUSY: 1554327Sdougm ret = dgettext(TEXT_DOMAIN, "busy"); 1564327Sdougm break; 1573034Sdougm case SA_NO_SUCH_PROP: 1584327Sdougm ret = dgettext(TEXT_DOMAIN, "no such property"); 1594327Sdougm break; 1603034Sdougm case SA_INVALID_NAME: 1614327Sdougm ret = dgettext(TEXT_DOMAIN, "invalid name"); 1624327Sdougm break; 1633034Sdougm case SA_INVALID_PROTOCOL: 1644327Sdougm ret = dgettext(TEXT_DOMAIN, "invalid protocol"); 1654327Sdougm break; 1663034Sdougm case SA_NOT_ALLOWED: 1674327Sdougm ret = dgettext(TEXT_DOMAIN, "operation not allowed"); 1684327Sdougm break; 1693034Sdougm case SA_BAD_VALUE: 1704327Sdougm ret = dgettext(TEXT_DOMAIN, "bad property value"); 1714327Sdougm break; 1723034Sdougm case SA_INVALID_SECURITY: 1734327Sdougm ret = dgettext(TEXT_DOMAIN, "invalid security type"); 1744327Sdougm break; 1753034Sdougm case SA_NO_SUCH_SECURITY: 1764327Sdougm ret = dgettext(TEXT_DOMAIN, "security type not found"); 1774327Sdougm break; 1783034Sdougm case SA_VALUE_CONFLICT: 1794327Sdougm ret = dgettext(TEXT_DOMAIN, "property value conflict"); 1804327Sdougm break; 1813034Sdougm case SA_NOT_IMPLEMENTED: 1824327Sdougm ret = dgettext(TEXT_DOMAIN, "not implemented"); 1834327Sdougm break; 1843034Sdougm case SA_INVALID_PATH: 1854327Sdougm ret = dgettext(TEXT_DOMAIN, "invalid path"); 1864327Sdougm break; 1873034Sdougm case SA_NOT_SUPPORTED: 1884327Sdougm ret = dgettext(TEXT_DOMAIN, "operation not supported"); 1894327Sdougm break; 1903034Sdougm case SA_PROP_SHARE_ONLY: 1914327Sdougm ret = dgettext(TEXT_DOMAIN, "property not valid for group"); 1924327Sdougm break; 1933034Sdougm case SA_NOT_SHARED: 1944327Sdougm ret = dgettext(TEXT_DOMAIN, "not shared"); 1954327Sdougm break; 1965331Samw case SA_NO_SUCH_RESOURCE: 1975331Samw ret = dgettext(TEXT_DOMAIN, "no such resource"); 1985331Samw break; 1995331Samw case SA_RESOURCE_REQUIRED: 2005331Samw ret = dgettext(TEXT_DOMAIN, "resource name required"); 2015331Samw break; 2025331Samw case SA_MULTIPLE_ERROR: 2035331Samw ret = dgettext(TEXT_DOMAIN, "errors from multiple protocols"); 2045331Samw break; 2055331Samw case SA_PATH_IS_SUBDIR: 2065331Samw ret = dgettext(TEXT_DOMAIN, "path is a subpath of share"); 2075331Samw break; 2085331Samw case SA_PATH_IS_PARENTDIR: 2095331Samw ret = dgettext(TEXT_DOMAIN, "path is parent of a share"); 2105331Samw break; 2116007Sthurlow case SA_NO_SECTION: 2126007Sthurlow ret = dgettext(TEXT_DOMAIN, "protocol requires a section"); 2136007Sthurlow break; 2146007Sthurlow case SA_NO_PROPERTIES: 2156007Sthurlow ret = dgettext(TEXT_DOMAIN, "properties not found"); 2166007Sthurlow break; 2176007Sthurlow case SA_NO_SUCH_SECTION: 2186007Sthurlow ret = dgettext(TEXT_DOMAIN, "section not found"); 2196007Sthurlow break; 2206007Sthurlow case SA_PASSWORD_ENC: 2216007Sthurlow ret = dgettext(TEXT_DOMAIN, "passwords must be encrypted"); 2226007Sthurlow break; 2233034Sdougm default: 2244327Sdougm (void) snprintf(errstr, sizeof (errstr), 2254327Sdougm dgettext(TEXT_DOMAIN, "unknown %d"), err); 2264327Sdougm ret = errstr; 2273034Sdougm } 2283034Sdougm return (ret); 2293034Sdougm } 2303034Sdougm 2313034Sdougm /* 2323910Sdougm * Document root to active handle mapping functions. These are only 2333910Sdougm * used internally. A mutex is used to prevent access while the list 2343910Sdougm * is changing. In general, the list will be relatively short - one 2353910Sdougm * item per thread that has called sa_init(). 2363910Sdougm */ 2373910Sdougm 2383910Sdougm sa_handle_impl_t 2393910Sdougm get_handle_for_root(xmlNodePtr root) 2403910Sdougm { 2413910Sdougm struct doc2handle *item; 2423910Sdougm 2433910Sdougm (void) mutex_lock(&sa_global_lock); 2443910Sdougm for (item = sa_global_handles; item != NULL; item = item->next) { 2454327Sdougm if (item->root == root) 2464327Sdougm break; 2473910Sdougm } 2483910Sdougm (void) mutex_unlock(&sa_global_lock); 2493910Sdougm if (item != NULL) 2504327Sdougm return (item->handle); 2513910Sdougm return (NULL); 2523910Sdougm } 2533910Sdougm 2543910Sdougm static int 2553910Sdougm add_handle_for_root(xmlNodePtr root, sa_handle_impl_t handle) 2563910Sdougm { 2573910Sdougm struct doc2handle *item; 2583910Sdougm int ret = SA_NO_MEMORY; 2593910Sdougm 2603910Sdougm item = (struct doc2handle *)calloc(sizeof (struct doc2handle), 1); 2613910Sdougm if (item != NULL) { 2624327Sdougm item->root = root; 2634327Sdougm item->handle = handle; 2644327Sdougm (void) mutex_lock(&sa_global_lock); 2654327Sdougm item->next = sa_global_handles; 2664327Sdougm sa_global_handles = item; 2674327Sdougm (void) mutex_unlock(&sa_global_lock); 2684327Sdougm ret = SA_OK; 2693910Sdougm } 2703910Sdougm return (ret); 2713910Sdougm } 2723910Sdougm 2733910Sdougm /* 2743910Sdougm * remove_handle_for_root(root) 2753910Sdougm * 2763910Sdougm * Walks the list of handles and removes the one for this "root" from 2773910Sdougm * the list. It is up to the caller to free the data. 2783910Sdougm */ 2793910Sdougm 2803910Sdougm static void 2813910Sdougm remove_handle_for_root(xmlNodePtr root) 2823910Sdougm { 2833910Sdougm struct doc2handle *item, *prev; 2843910Sdougm 2853910Sdougm (void) mutex_lock(&sa_global_lock); 2863910Sdougm for (prev = NULL, item = sa_global_handles; item != NULL; 2874327Sdougm item = item->next) { 2884327Sdougm if (item->root == root) { 2894327Sdougm /* first in the list */ 2904327Sdougm if (prev == NULL) 2914327Sdougm sa_global_handles = sa_global_handles->next; 2924327Sdougm else 2934327Sdougm prev->next = item->next; 2944327Sdougm /* Item is out of the list so free the list structure */ 2954327Sdougm free(item); 2964327Sdougm break; 2973910Sdougm } 2984327Sdougm prev = item; 2993910Sdougm } 3003910Sdougm (void) mutex_unlock(&sa_global_lock); 3013910Sdougm } 3023910Sdougm 3033910Sdougm /* 3043910Sdougm * sa_find_group_handle(sa_group_t group) 3053910Sdougm * 3063910Sdougm * Find the sa_handle_t for the configuration associated with this 3073910Sdougm * group. 3083910Sdougm */ 3093910Sdougm sa_handle_t 3103910Sdougm sa_find_group_handle(sa_group_t group) 3113910Sdougm { 3123910Sdougm xmlNodePtr node = (xmlNodePtr)group; 3133910Sdougm sa_handle_t handle; 3143910Sdougm 3153910Sdougm while (node != NULL) { 3164327Sdougm if (strcmp((char *)(node->name), "sharecfg") == 0) { 3174327Sdougm /* have the root so get the handle */ 3184327Sdougm handle = (sa_handle_t)get_handle_for_root(node); 3194327Sdougm return (handle); 3204327Sdougm } 3214327Sdougm node = node->parent; 3223910Sdougm } 3233910Sdougm return (NULL); 3243910Sdougm } 3253910Sdougm 3263910Sdougm /* 3273034Sdougm * set_legacy_timestamp(root, path, timevalue) 3283034Sdougm * 3293034Sdougm * add the current timestamp value to the configuration for use in 3303034Sdougm * determining when to update the legacy files. For SMF, this 3313034Sdougm * property is kept in default/operation/legacy_timestamp 3323034Sdougm */ 3333034Sdougm 3343034Sdougm static void 3353034Sdougm set_legacy_timestamp(xmlNodePtr root, char *path, uint64_t tval) 3363034Sdougm { 3373034Sdougm xmlNodePtr node; 3383034Sdougm xmlChar *lpath = NULL; 3393910Sdougm sa_handle_impl_t handle; 3403910Sdougm 3413910Sdougm /* Have to have a handle or else we weren't initialized. */ 3423910Sdougm handle = get_handle_for_root(root); 3433910Sdougm if (handle == NULL) 3444327Sdougm return; 3453034Sdougm 3463034Sdougm for (node = root->xmlChildrenNode; node != NULL; 3474327Sdougm node = node->next) { 3484327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"legacy") == 0) { 3494327Sdougm /* a possible legacy node for this path */ 3504327Sdougm lpath = xmlGetProp(node, (xmlChar *)"path"); 3514327Sdougm if (lpath != NULL && 3524327Sdougm xmlStrcmp(lpath, (xmlChar *)path) == 0) { 3534327Sdougm xmlFree(lpath); 3544327Sdougm break; 3554327Sdougm } 3564327Sdougm if (lpath != NULL) 3574327Sdougm xmlFree(lpath); 3583034Sdougm } 3593034Sdougm } 3603034Sdougm if (node == NULL) { 3614327Sdougm /* need to create the first legacy timestamp node */ 3624327Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"legacy", NULL); 3633034Sdougm } 3643034Sdougm if (node != NULL) { 3654327Sdougm char tstring[32]; 3664327Sdougm int ret; 3673034Sdougm 3684327Sdougm (void) snprintf(tstring, sizeof (tstring), "%lld", tval); 3696007Sthurlow (void) xmlSetProp(node, (xmlChar *)"timestamp", 3706007Sthurlow (xmlChar *)tstring); 3716007Sthurlow (void) xmlSetProp(node, (xmlChar *)"path", (xmlChar *)path); 3724327Sdougm /* now commit to SMF */ 3734327Sdougm ret = sa_get_instance(handle->scfhandle, "default"); 3743034Sdougm if (ret == SA_OK) { 3754327Sdougm ret = sa_start_transaction(handle->scfhandle, 3764327Sdougm "operation"); 3774327Sdougm if (ret == SA_OK) { 3784327Sdougm ret = sa_set_property(handle->scfhandle, 3794327Sdougm "legacy-timestamp", tstring); 3804327Sdougm if (ret == SA_OK) { 3814327Sdougm (void) sa_end_transaction( 3825951Sdougm handle->scfhandle, handle); 3834327Sdougm } else { 3844327Sdougm sa_abort_transaction(handle->scfhandle); 3854327Sdougm } 3864327Sdougm } 3873034Sdougm } 3883034Sdougm } 3893034Sdougm } 3903034Sdougm 3913034Sdougm /* 3923034Sdougm * is_shared(share) 3933034Sdougm * 3943034Sdougm * determine if the specified share is currently shared or not. 3953034Sdougm */ 3963034Sdougm static int 3973034Sdougm is_shared(sa_share_t share) 3983034Sdougm { 3993034Sdougm char *shared; 4003034Sdougm int result = 0; /* assume not */ 4013034Sdougm 4023034Sdougm shared = sa_get_share_attr(share, "shared"); 4033034Sdougm if (shared != NULL) { 4044327Sdougm if (strcmp(shared, "true") == 0) 4054327Sdougm result = 1; 4064327Sdougm sa_free_attr_string(shared); 4073034Sdougm } 4083034Sdougm return (result); 4093034Sdougm } 4103034Sdougm 4113034Sdougm /* 4125331Samw * excluded_protocol(share, proto) 4135331Samw * 4145331Samw * Returns B_TRUE if the specified protocol appears in the "exclude" 4155331Samw * property. This is used to prevent sharing special case shares 4165331Samw * (e.g. subdirs when SMB wants a subdir and NFS doesn't. B_FALSE is 4175331Samw * returned if the protocol isn't in the list. 4185331Samw */ 4195331Samw static boolean_t 4205331Samw excluded_protocol(sa_share_t share, char *proto) 4215331Samw { 4225331Samw char *protolist; 4235331Samw char *str; 4245331Samw char *token; 4255331Samw 4265331Samw protolist = sa_get_share_attr(share, "exclude"); 4275331Samw if (protolist != NULL) { 4285331Samw str = protolist; 4295331Samw while ((token = strtok(str, ",")) != NULL) { 4305331Samw if (strcmp(token, proto) == 0) { 4315331Samw sa_free_attr_string(protolist); 4325331Samw return (B_TRUE); 4335331Samw } 4345331Samw str = NULL; 4355331Samw } 4365331Samw sa_free_attr_string(protolist); 4375331Samw } 4385331Samw return (B_FALSE); 4395331Samw } 4405331Samw 4415331Samw /* 4423663Sdougm * checksubdirgroup(group, newpath, strictness) 4433348Sdougm * 4443663Sdougm * check all the specified newpath against all the paths in the 4453663Sdougm * group. This is a helper function for checksubdir to make it easier 4463663Sdougm * to also check ZFS subgroups. 4473663Sdougm * The strictness values mean: 4483348Sdougm * SA_CHECK_NORMAL == only check newpath against shares that are active 4493348Sdougm * SA_CHECK_STRICT == check newpath against both active shares and those 4503348Sdougm * stored in the repository 4513034Sdougm */ 4523034Sdougm static int 4533663Sdougm checksubdirgroup(sa_group_t group, char *newpath, int strictness) 4543034Sdougm { 4553034Sdougm sa_share_t share; 4563663Sdougm char *path; 4573663Sdougm int issub = SA_OK; 4585331Samw int subdir; 4595331Samw int parent; 4605331Samw 4615331Samw if (newpath == NULL) 4625331Samw return (SA_INVALID_PATH); 4633034Sdougm 4643663Sdougm for (share = sa_get_share(group, NULL); share != NULL; 4653663Sdougm share = sa_get_next_share(share)) { 4663034Sdougm /* 4673034Sdougm * The original behavior of share never checked 4683034Sdougm * against the permanent configuration 4693034Sdougm * (/etc/dfs/dfstab). PIT has a number of cases where 4703034Sdougm * it depends on this older behavior even though it 4713034Sdougm * could be considered incorrect. We may tighten this 4723034Sdougm * up in the future. 4733034Sdougm */ 4744327Sdougm if (strictness == SA_CHECK_NORMAL && !is_shared(share)) 4754327Sdougm continue; 4763034Sdougm 4774327Sdougm path = sa_get_share_attr(share, "path"); 4783348Sdougm /* 4793348Sdougm * If path is NULL, then a share is in the process of 4803348Sdougm * construction or someone has modified the property 4813663Sdougm * group inappropriately. It should be 4823663Sdougm * ignored. issubdir() comes from the original share 4833663Sdougm * implementation and does the difficult part of 4843663Sdougm * checking subdirectories. 4853348Sdougm */ 4864327Sdougm if (path == NULL) 4874327Sdougm continue; 4885331Samw 4895331Samw if (strcmp(path, newpath) == 0) { 4904327Sdougm issub = SA_INVALID_PATH; 4915331Samw } else { 4925331Samw subdir = issubdir(newpath, path); 4935331Samw parent = issubdir(path, newpath); 4945331Samw if (subdir || parent) { 4955331Samw sa_free_attr_string(path); 4965331Samw path = NULL; 4975331Samw return (subdir ? 4985331Samw SA_PATH_IS_SUBDIR : SA_PATH_IS_PARENTDIR); 4995331Samw } 5004327Sdougm } 5013034Sdougm sa_free_attr_string(path); 5023034Sdougm path = NULL; 5033663Sdougm } 5043663Sdougm return (issub); 5053663Sdougm } 5063663Sdougm 5073663Sdougm /* 5083663Sdougm * checksubdir(newpath, strictness) 5093663Sdougm * 5103663Sdougm * checksubdir determines if the specified path (newpath) is a 5113663Sdougm * subdirectory of another share. It calls checksubdirgroup() to do 5123663Sdougm * the complicated work. The strictness parameter determines how 5133663Sdougm * strict a check to make against the path. The strictness values 5143663Sdougm * mean: SA_CHECK_NORMAL == only check newpath against shares that are 5153663Sdougm * active SA_CHECK_STRICT == check newpath against both active shares 5163663Sdougm * and those * stored in the repository 5173663Sdougm */ 5183663Sdougm static int 5193910Sdougm checksubdir(sa_handle_t handle, char *newpath, int strictness) 5203663Sdougm { 5213663Sdougm sa_group_t group; 5225331Samw int issub = SA_OK; 5233663Sdougm char *path = NULL; 5243663Sdougm 5255331Samw for (group = sa_get_group(handle, NULL); 5265331Samw group != NULL && issub == SA_OK; 5275331Samw group = sa_get_next_group(group)) { 5284327Sdougm if (sa_group_is_zfs(group)) { 5294327Sdougm sa_group_t subgroup; 5304327Sdougm for (subgroup = sa_get_sub_group(group); 5315331Samw subgroup != NULL && issub == SA_OK; 5324327Sdougm subgroup = sa_get_next_group(subgroup)) 5334327Sdougm issub = checksubdirgroup(subgroup, newpath, 5344327Sdougm strictness); 5354327Sdougm } else { 5364327Sdougm issub = checksubdirgroup(group, newpath, strictness); 5374327Sdougm } 5383034Sdougm } 5393034Sdougm if (path != NULL) 5404327Sdougm sa_free_attr_string(path); 5413034Sdougm return (issub); 5423034Sdougm } 5433034Sdougm 5443034Sdougm /* 5453348Sdougm * validpath(path, strictness) 5463034Sdougm * determine if the provided path is valid for a share. It shouldn't 5473034Sdougm * be a sub-dir of an already shared path or the parent directory of a 5483034Sdougm * share path. 5493034Sdougm */ 5503034Sdougm static int 5513910Sdougm validpath(sa_handle_t handle, char *path, int strictness) 5523034Sdougm { 5533034Sdougm int error = SA_OK; 5543034Sdougm struct stat st; 5553034Sdougm sa_share_t share; 5563034Sdougm char *fstype; 5573034Sdougm 5584327Sdougm if (*path != '/') 5594327Sdougm return (SA_BAD_PATH); 5604327Sdougm 5613034Sdougm if (stat(path, &st) < 0) { 5624327Sdougm error = SA_NO_SUCH_PATH; 5633034Sdougm } else { 5644327Sdougm share = sa_find_share(handle, path); 5654327Sdougm if (share != NULL) 5664327Sdougm error = SA_DUPLICATE_NAME; 5674327Sdougm 5684327Sdougm if (error == SA_OK) { 5694327Sdougm /* 5704327Sdougm * check for special case with file system 5714327Sdougm * that might have restrictions. For now, ZFS 5724327Sdougm * is the only case since it has its own idea 5734327Sdougm * of how to configure shares. We do this 5744327Sdougm * before subdir checking since things like 5754327Sdougm * ZFS will do that for us. This should also 5764327Sdougm * be done via plugin interface. 5774327Sdougm */ 5784327Sdougm fstype = sa_fstype(path); 5794327Sdougm if (fstype != NULL && strcmp(fstype, "zfs") == 0) { 5804327Sdougm if (sa_zfs_is_shared(handle, path)) 5814327Sdougm error = SA_INVALID_NAME; 5824327Sdougm } 5834327Sdougm if (fstype != NULL) 5844327Sdougm sa_free_fstype(fstype); 5853034Sdougm } 5864327Sdougm if (error == SA_OK) 5874327Sdougm error = checksubdir(handle, path, strictness); 5883034Sdougm } 5893034Sdougm return (error); 5903034Sdougm } 5913034Sdougm 5923034Sdougm /* 5933034Sdougm * check to see if group/share is persistent. 5945331Samw * 5955331Samw * "group" can be either an sa_group_t or an sa_share_t. (void *) 5965331Samw * works since both thse types are also void *. 5973034Sdougm */ 5985331Samw int 5995331Samw sa_is_persistent(void *group) 6003034Sdougm { 6013034Sdougm char *type; 6023034Sdougm int persist = 1; 6033034Sdougm 6045331Samw type = sa_get_group_attr((sa_group_t)group, "type"); 6053034Sdougm if (type != NULL && strcmp(type, "transient") == 0) 6064327Sdougm persist = 0; 6073034Sdougm if (type != NULL) 6084327Sdougm sa_free_attr_string(type); 6093034Sdougm return (persist); 6103034Sdougm } 6113034Sdougm 6123034Sdougm /* 6133034Sdougm * sa_valid_group_name(name) 6143034Sdougm * 6153034Sdougm * check that the "name" contains only valid characters and otherwise 6163034Sdougm * fits the required naming conventions. Valid names must start with 6173034Sdougm * an alphabetic and the remainder may consist of only alphanumeric 6183034Sdougm * plus the '-' and '_' characters. This name limitation comes from 6193034Sdougm * inherent limitations in SMF. 6203034Sdougm */ 6213034Sdougm 6223034Sdougm int 6233034Sdougm sa_valid_group_name(char *name) 6243034Sdougm { 6253034Sdougm int ret = 1; 6263034Sdougm ssize_t len; 6273034Sdougm 6283034Sdougm if (name != NULL && isalpha(*name)) { 6294327Sdougm char c; 6304327Sdougm len = strlen(name); 6314327Sdougm if (len < (scf_max_name_len - sizeof ("group:"))) { 6324327Sdougm for (c = *name++; c != '\0' && ret != 0; c = *name++) { 6334327Sdougm if (!isalnum(c) && c != '-' && c != '_') 6344327Sdougm ret = 0; 6354327Sdougm } 6364327Sdougm } else { 6373034Sdougm ret = 0; 6383034Sdougm } 6394327Sdougm } else { 6403034Sdougm ret = 0; 6413034Sdougm } 6423034Sdougm return (ret); 6433034Sdougm } 6443034Sdougm 6453034Sdougm 6463034Sdougm /* 6473034Sdougm * is_zfs_group(group) 6483034Sdougm * Determine if the specified group is a ZFS sharenfs group 6493034Sdougm */ 6503034Sdougm static int 6513034Sdougm is_zfs_group(sa_group_t group) 6523034Sdougm { 6533034Sdougm int ret = 0; 6543034Sdougm xmlNodePtr parent; 6553034Sdougm xmlChar *zfs; 6563034Sdougm 6574327Sdougm if (strcmp((char *)((xmlNodePtr)group)->name, "share") == 0) 6584327Sdougm parent = (xmlNodePtr)sa_get_parent_group(group); 6594327Sdougm else 6604327Sdougm parent = (xmlNodePtr)group; 6613034Sdougm zfs = xmlGetProp(parent, (xmlChar *)"zfs"); 6623034Sdougm if (zfs != NULL) { 6634327Sdougm xmlFree(zfs); 6644327Sdougm ret = 1; 6653034Sdougm } 6663034Sdougm return (ret); 6673034Sdougm } 6683034Sdougm 6693034Sdougm /* 6705331Samw * sa_get_object_type(object) 6715331Samw * 6725331Samw * This function returns a numeric value representing the object 6735331Samw * type. This allows using simpler checks when doing type specific 6745331Samw * operations. 6755331Samw */ 6765331Samw 6775331Samw static int 6785331Samw sa_get_object_type(void *object) 6795331Samw { 6805331Samw xmlNodePtr node = (xmlNodePtr)object; 6815331Samw int type; 6825331Samw 6835331Samw if (xmlStrcmp(node->name, (xmlChar *)"group") == 0) 6845331Samw type = SA_TYPE_GROUP; 6855331Samw else if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) 6865331Samw type = SA_TYPE_SHARE; 6875331Samw else if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0) 6885331Samw type = SA_TYPE_RESOURCE; 6895331Samw else if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) 6905331Samw type = SA_TYPE_OPTIONSET; 6915331Samw else if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) 6925331Samw type = SA_TYPE_ALTSPACE; 6935331Samw else 6945331Samw assert(0); 6955331Samw return (type); 6965331Samw } 6975331Samw 6985331Samw /* 6993034Sdougm * sa_optionset_name(optionset, oname, len, id) 7003034Sdougm * return the SMF name for the optionset. If id is not NULL, it 7013034Sdougm * will have the GUID value for a share and should be used 7023034Sdougm * instead of the keyword "optionset" which is used for 7033034Sdougm * groups. If the optionset doesn't have a protocol type 7043034Sdougm * associated with it, "default" is used. This shouldn't happen 7053034Sdougm * at this point but may be desirable in the future if there are 7063034Sdougm * protocol independent properties added. The name is returned in 7073034Sdougm * oname. 7083034Sdougm */ 7093034Sdougm 7103034Sdougm static int 7113034Sdougm sa_optionset_name(sa_optionset_t optionset, char *oname, size_t len, char *id) 7123034Sdougm { 7133034Sdougm char *proto; 7145331Samw void *parent; 7155331Samw int ptype; 7163034Sdougm 7173034Sdougm if (id == NULL) 7184327Sdougm id = "optionset"; 7193034Sdougm 7205331Samw parent = sa_get_optionset_parent(optionset); 7215331Samw if (parent != NULL) { 7225331Samw ptype = sa_get_object_type(parent); 7235331Samw proto = sa_get_optionset_attr(optionset, "type"); 7245331Samw if (ptype != SA_TYPE_RESOURCE) { 7255331Samw len = snprintf(oname, len, "%s_%s", id, 7265331Samw proto ? proto : "default"); 7275331Samw } else { 7285331Samw char *index; 7295331Samw index = get_node_attr((void *)parent, "id"); 730*11337SWilliam.Krier@Sun.COM if (index != NULL) { 7315331Samw len = snprintf(oname, len, "%s_%s_%s", id, 7325331Samw proto ? proto : "default", index); 733*11337SWilliam.Krier@Sun.COM sa_free_attr_string(index); 734*11337SWilliam.Krier@Sun.COM } else { 7355331Samw len = 0; 736*11337SWilliam.Krier@Sun.COM } 7375331Samw } 7385331Samw 7395331Samw if (proto != NULL) 7405331Samw sa_free_attr_string(proto); 7415331Samw } else { 7425331Samw len = 0; 7435331Samw } 7443034Sdougm return (len); 7453034Sdougm } 7463034Sdougm 7473034Sdougm /* 7483034Sdougm * sa_security_name(optionset, oname, len, id) 7493034Sdougm * 7503034Sdougm * return the SMF name for the security. If id is not NULL, it will 7513034Sdougm * have the GUID value for a share and should be used instead of the 7523034Sdougm * keyword "optionset" which is used for groups. If the optionset 7533034Sdougm * doesn't have a protocol type associated with it, "default" is 7543034Sdougm * used. This shouldn't happen at this point but may be desirable in 7553034Sdougm * the future if there are protocol independent properties added. The 7563034Sdougm * name is returned in oname. The security type is also encoded into 7573034Sdougm * the name. In the future, this wil *be handled a bit differently. 7583034Sdougm */ 7593034Sdougm 7603034Sdougm static int 7613034Sdougm sa_security_name(sa_security_t security, char *oname, size_t len, char *id) 7623034Sdougm { 7633034Sdougm char *proto; 7643034Sdougm char *sectype; 7653034Sdougm 7663034Sdougm if (id == NULL) 7674327Sdougm id = "optionset"; 7683034Sdougm 7693034Sdougm proto = sa_get_security_attr(security, "type"); 7703034Sdougm sectype = sa_get_security_attr(security, "sectype"); 7714327Sdougm len = snprintf(oname, len, "%s_%s_%s", id, proto ? proto : "default", 7724327Sdougm sectype ? sectype : "default"); 7733034Sdougm if (proto != NULL) 7744327Sdougm sa_free_attr_string(proto); 7753034Sdougm if (sectype != NULL) 7764327Sdougm sa_free_attr_string(sectype); 7773034Sdougm return (len); 7783034Sdougm } 7793034Sdougm 7803034Sdougm /* 7814327Sdougm * verifydefgroupopts(handle) 7824327Sdougm * 7834327Sdougm * Make sure a "default" group exists and has default protocols enabled. 7844327Sdougm */ 7854327Sdougm static void 7864327Sdougm verifydefgroupopts(sa_handle_t handle) 7874327Sdougm { 7884327Sdougm sa_group_t defgrp; 7894327Sdougm sa_optionset_t opt; 7905331Samw 7914327Sdougm defgrp = sa_get_group(handle, "default"); 7924327Sdougm if (defgrp != NULL) { 7934327Sdougm opt = sa_get_optionset(defgrp, NULL); 7944327Sdougm /* 7954327Sdougm * NFS is the default for default group 7964327Sdougm */ 7974327Sdougm if (opt == NULL) 7984327Sdougm opt = sa_create_optionset(defgrp, "nfs"); 7994327Sdougm } 8004327Sdougm } 8014327Sdougm 8024327Sdougm /* 8033348Sdougm * sa_init(init_service) 8043034Sdougm * Initialize the API 8053034Sdougm * find all the shared objects 8063034Sdougm * init the tables with all objects 8073034Sdougm * read in the current configuration 8083034Sdougm */ 8093034Sdougm 8104327Sdougm #define GETPROP(prop) scf_simple_prop_next_astring(prop) 8114327Sdougm #define CHECKTSTAMP(st, tval) stat(SA_LEGACY_DFSTAB, &st) >= 0 && \ 8124327Sdougm tval != TSTAMP(st.st_ctim) 8134327Sdougm 8143910Sdougm sa_handle_t 8153034Sdougm sa_init(int init_service) 8163034Sdougm { 8173034Sdougm struct stat st; 8183034Sdougm int legacy = 0; 8193034Sdougm uint64_t tval = 0; 8203663Sdougm int lockfd; 8213663Sdougm sigset_t old; 8223663Sdougm int updatelegacy = B_FALSE; 8233663Sdougm scf_simple_prop_t *prop; 8243910Sdougm sa_handle_impl_t handle; 8253910Sdougm int err; 8263034Sdougm 8273910Sdougm handle = calloc(sizeof (struct sa_handle_impl), 1); 8283910Sdougm 8293910Sdougm if (handle != NULL) { 8306304Sdougm /* 8316304Sdougm * Get protocol specific structures, but only if this 8326304Sdougm * is the only handle. 8336304Sdougm */ 8346304Sdougm (void) mutex_lock(&sa_global_lock); 8356304Sdougm if (sa_global_handles == NULL) 8366304Sdougm (void) proto_plugin_init(); 8376304Sdougm (void) mutex_unlock(&sa_global_lock); 8384327Sdougm if (init_service & SA_INIT_SHARE_API) { 8393663Sdougm /* 8404327Sdougm * initialize access into libzfs. We use this 8414327Sdougm * when collecting info about ZFS datasets and 8424327Sdougm * shares. 8433663Sdougm */ 8444327Sdougm if (sa_zfs_init(handle) == B_FALSE) { 8454327Sdougm free(handle); 8468474SJose.Borrego@Sun.COM (void) mutex_lock(&sa_global_lock); 8474327Sdougm (void) proto_plugin_fini(); 8488474SJose.Borrego@Sun.COM (void) mutex_unlock(&sa_global_lock); 8494327Sdougm return (NULL); 8504327Sdougm } 8513663Sdougm /* 8524327Sdougm * since we want to use SMF, initialize an svc handle 8534327Sdougm * and find out what is there. 8543663Sdougm */ 8554327Sdougm handle->scfhandle = sa_scf_init(handle); 8564327Sdougm if (handle->scfhandle != NULL) { 8574327Sdougm /* 8584327Sdougm * Need to lock the extraction of the 8594327Sdougm * configuration if the dfstab file has 8604327Sdougm * changed. Lock everything now and release if 8614327Sdougm * not needed. Use a file that isn't being 8624327Sdougm * manipulated by other parts of the system in 8634327Sdougm * order to not interfere with locking. Using 8644327Sdougm * dfstab doesn't work. 8654327Sdougm */ 8664327Sdougm sablocksigs(&old); 8674327Sdougm lockfd = open(DFS_LOCK_FILE, O_RDWR); 8684327Sdougm if (lockfd >= 0) { 8694327Sdougm extern int errno; 8704327Sdougm errno = 0; 8714327Sdougm (void) lockf(lockfd, F_LOCK, 0); 8724327Sdougm /* 8734327Sdougm * Check whether we are going to need 8744327Sdougm * to merge any dfstab changes. This 8754327Sdougm * is done by comparing the value of 8764327Sdougm * legacy-timestamp with the current 8774327Sdougm * st_ctim of the file. If they are 8784327Sdougm * different, an update is needed and 8794327Sdougm * the file must remain locked until 8804327Sdougm * the merge is done in order to 8814327Sdougm * prevent multiple startups from 8824327Sdougm * changing the SMF repository at the 8834327Sdougm * same time. The first to get the 8844327Sdougm * lock will make any changes before 8854327Sdougm * the others can read the repository. 8864327Sdougm */ 8874327Sdougm prop = scf_simple_prop_get 8884327Sdougm (handle->scfhandle->handle, 8894327Sdougm (const char *)SA_SVC_FMRI_BASE 8904327Sdougm ":default", "operation", 8914327Sdougm "legacy-timestamp"); 8924327Sdougm if (prop != NULL) { 8934327Sdougm char *i64; 8944327Sdougm i64 = GETPROP(prop); 8954327Sdougm if (i64 != NULL) 8964327Sdougm tval = strtoull(i64, 8974327Sdougm NULL, 0); 8984327Sdougm if (CHECKTSTAMP(st, tval)) 8994327Sdougm updatelegacy = B_TRUE; 9004327Sdougm scf_simple_prop_free(prop); 9014327Sdougm } else { 9024327Sdougm /* 9034327Sdougm * We haven't set the 9044327Sdougm * timestamp before so do it. 9054327Sdougm */ 9064327Sdougm updatelegacy = B_TRUE; 9074327Sdougm } 9084327Sdougm } 9094327Sdougm if (updatelegacy == B_FALSE) { 9104327Sdougm /* Don't need the lock anymore */ 9114327Sdougm (void) lockf(lockfd, F_ULOCK, 0); 9124327Sdougm (void) close(lockfd); 9134327Sdougm } 9143973Sdougm 9154327Sdougm /* 9164327Sdougm * It is essential that the document tree and 9174327Sdougm * the internal list of roots to handles be 9184327Sdougm * setup before anything that might try to 9194327Sdougm * create a new object is called. The document 9204327Sdougm * tree is the combination of handle->doc and 9214327Sdougm * handle->tree. This allows searches, 9224327Sdougm * etc. when all you have is an object in the 9234327Sdougm * tree. 9244327Sdougm */ 9254327Sdougm handle->doc = xmlNewDoc((xmlChar *)"1.0"); 9264327Sdougm handle->tree = xmlNewNode(NULL, 9274327Sdougm (xmlChar *)"sharecfg"); 9284327Sdougm if (handle->doc != NULL && 9294327Sdougm handle->tree != NULL) { 9306007Sthurlow (void) xmlDocSetRootElement(handle->doc, 9314327Sdougm handle->tree); 9324327Sdougm err = add_handle_for_root(handle->tree, 9334327Sdougm handle); 9344327Sdougm if (err == SA_OK) 9354327Sdougm err = sa_get_config( 9364327Sdougm handle->scfhandle, 9373973Sdougm handle->tree, handle); 9384327Sdougm } else { 9394327Sdougm if (handle->doc != NULL) 9404327Sdougm xmlFreeDoc(handle->doc); 9414327Sdougm if (handle->tree != NULL) 9424327Sdougm xmlFreeNode(handle->tree); 9434327Sdougm err = SA_NO_MEMORY; 9444327Sdougm } 9453973Sdougm 9464327Sdougm saunblocksigs(&old); 9473910Sdougm 9484327Sdougm if (err != SA_OK) { 9494327Sdougm /* 9504327Sdougm * If we couldn't add the tree handle 9514327Sdougm * to the list, then things are going 9524327Sdougm * to fail badly. Might as well undo 9534327Sdougm * everything now and fail the 9544327Sdougm * sa_init(). 9554327Sdougm */ 9564327Sdougm sa_fini(handle); 9574327Sdougm return (NULL); 9584327Sdougm } 9593910Sdougm 9604327Sdougm if (tval == 0) { 9614327Sdougm /* 9624327Sdougm * first time so make sure 9634327Sdougm * default is setup 9644327Sdougm */ 9654327Sdougm verifydefgroupopts(handle); 9664327Sdougm } 9673973Sdougm 9684524Sdougm if (updatelegacy == B_TRUE) { 9694524Sdougm sablocksigs(&old); 9704524Sdougm getlegacyconfig((sa_handle_t)handle, 9714524Sdougm SA_LEGACY_DFSTAB, &handle->tree); 9724524Sdougm if (stat(SA_LEGACY_DFSTAB, &st) >= 0) 9734524Sdougm set_legacy_timestamp( 9744524Sdougm handle->tree, 9754524Sdougm SA_LEGACY_DFSTAB, 9764524Sdougm TSTAMP(st.st_ctim)); 9774524Sdougm saunblocksigs(&old); 9784524Sdougm /* 9794524Sdougm * Safe to unlock now to allow 9804524Sdougm * others to run 9814524Sdougm */ 9824524Sdougm (void) lockf(lockfd, F_ULOCK, 0); 9834524Sdougm (void) close(lockfd); 9844524Sdougm } 9855951Sdougm /* Get sharetab timestamp */ 9865951Sdougm sa_update_sharetab_ts((sa_handle_t)handle); 9875951Sdougm 9885951Sdougm /* Get lastupdate (transaction) timestamp */ 9895951Sdougm prop = scf_simple_prop_get( 9905951Sdougm handle->scfhandle->handle, 9915951Sdougm (const char *)SA_SVC_FMRI_BASE ":default", 9925951Sdougm "state", "lastupdate"); 9935951Sdougm if (prop != NULL) { 9945951Sdougm char *str; 9955951Sdougm str = 9965951Sdougm scf_simple_prop_next_astring(prop); 9975951Sdougm if (str != NULL) 9985951Sdougm handle->tstrans = 9995951Sdougm strtoull(str, NULL, 0); 10005951Sdougm else 10015951Sdougm handle->tstrans = 0; 10025951Sdougm scf_simple_prop_free(prop); 10035951Sdougm } 10044524Sdougm legacy |= sa_get_zfs_shares(handle, "zfs"); 10054524Sdougm legacy |= gettransients(handle, &handle->tree); 10064327Sdougm } 10074327Sdougm } 10083034Sdougm } 10093910Sdougm return ((sa_handle_t)handle); 10103034Sdougm } 10113034Sdougm 10123034Sdougm /* 10133910Sdougm * sa_fini(handle) 10143034Sdougm * Uninitialize the API structures including the configuration 10153218Sdougm * data structures and ZFS related data. 10163034Sdougm */ 10173034Sdougm 10183034Sdougm void 10193910Sdougm sa_fini(sa_handle_t handle) 10203034Sdougm { 10213910Sdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle; 10223910Sdougm 10233910Sdougm if (impl_handle != NULL) { 10243910Sdougm /* 10253910Sdougm * Free the config trees and any other data structures 10263910Sdougm * used in the handle. 10273910Sdougm */ 10283910Sdougm if (impl_handle->doc != NULL) 10293910Sdougm xmlFreeDoc(impl_handle->doc); 10303910Sdougm 10313910Sdougm /* Remove and free the entry in the global list. */ 10323910Sdougm remove_handle_for_root(impl_handle->tree); 10333910Sdougm 10343910Sdougm /* 10353910Sdougm * If this was the last handle to release, unload the 10366304Sdougm * plugins that were loaded. Use a mutex in case 10376304Sdougm * another thread is reinitializing. 10383910Sdougm */ 10396304Sdougm (void) mutex_lock(&sa_global_lock); 10403910Sdougm if (sa_global_handles == NULL) 10414327Sdougm (void) proto_plugin_fini(); 10426304Sdougm (void) mutex_unlock(&sa_global_lock); 10433910Sdougm 10447010Sgwr sa_scf_fini(impl_handle->scfhandle); 10457010Sgwr sa_zfs_fini(impl_handle); 10467010Sgwr 10477010Sgwr /* Make sure we free the handle */ 10487010Sgwr free(impl_handle); 10497010Sgwr 10503034Sdougm } 10513034Sdougm } 10523034Sdougm 10533034Sdougm /* 10543034Sdougm * sa_get_protocols(char **protocol) 10553034Sdougm * Get array of protocols that are supported 10563034Sdougm * Returns pointer to an allocated and NULL terminated 10573034Sdougm * array of strings. Caller must free. 10583034Sdougm * This really should be determined dynamically. 10593034Sdougm * If there aren't any defined, return -1. 10603034Sdougm * Use free() to return memory. 10613034Sdougm */ 10623034Sdougm 10633034Sdougm int 10643034Sdougm sa_get_protocols(char ***protocols) 10653034Sdougm { 10663034Sdougm int numproto = -1; 10673034Sdougm 10683034Sdougm if (protocols != NULL) { 10694327Sdougm struct sa_proto_plugin *plug; 10704327Sdougm for (numproto = 0, plug = sap_proto_list; plug != NULL; 10714327Sdougm plug = plug->plugin_next) { 10724327Sdougm numproto++; 10734327Sdougm } 10743034Sdougm 10754327Sdougm *protocols = calloc(numproto + 1, sizeof (char *)); 10764327Sdougm if (*protocols != NULL) { 10774327Sdougm int ret = 0; 10784327Sdougm for (plug = sap_proto_list; plug != NULL; 10794327Sdougm plug = plug->plugin_next) { 10804327Sdougm /* faking for now */ 10814327Sdougm (*protocols)[ret++] = 10824327Sdougm plug->plugin_ops->sa_protocol; 10834327Sdougm } 10844327Sdougm } else { 10854327Sdougm numproto = -1; 10863034Sdougm } 10873034Sdougm } 10883034Sdougm return (numproto); 10893034Sdougm } 10903034Sdougm 10913034Sdougm /* 10923034Sdougm * find_group_by_name(node, group) 10933034Sdougm * 10943034Sdougm * search the XML document subtree specified by node to find the group 10953034Sdougm * specified by group. Searching subtree allows subgroups to be 10963034Sdougm * searched for. 10973034Sdougm */ 10983034Sdougm 10993034Sdougm static xmlNodePtr 11003034Sdougm find_group_by_name(xmlNodePtr node, xmlChar *group) 11013034Sdougm { 11023034Sdougm xmlChar *name = NULL; 11033034Sdougm 11043034Sdougm for (node = node->xmlChildrenNode; node != NULL; 11053034Sdougm node = node->next) { 11064327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"group") == 0) { 11074327Sdougm /* if no groupname, return the first found */ 11084327Sdougm if (group == NULL) 11094327Sdougm break; 11104327Sdougm name = xmlGetProp(node, (xmlChar *)"name"); 11114327Sdougm if (name != NULL && xmlStrcmp(name, group) == 0) 11124327Sdougm break; 11134327Sdougm if (name != NULL) { 11144327Sdougm xmlFree(name); 11154327Sdougm name = NULL; 11164327Sdougm } 11173034Sdougm } 11183034Sdougm } 11193034Sdougm if (name != NULL) 11204327Sdougm xmlFree(name); 11213034Sdougm return (node); 11223034Sdougm } 11233034Sdougm 11243034Sdougm /* 11253034Sdougm * sa_get_group(groupname) 11263034Sdougm * Return the "group" specified. If groupname is NULL, 11273034Sdougm * return the first group of the list of groups. 11283034Sdougm */ 11293034Sdougm sa_group_t 11303910Sdougm sa_get_group(sa_handle_t handle, char *groupname) 11313034Sdougm { 11323034Sdougm xmlNodePtr node = NULL; 11333034Sdougm char *subgroup = NULL; 11343034Sdougm char *group = NULL; 11353910Sdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle; 11363034Sdougm 11373910Sdougm if (impl_handle != NULL && impl_handle->tree != NULL) { 11384327Sdougm if (groupname != NULL) { 11394327Sdougm group = strdup(groupname); 11404345Sdougm if (group != NULL) { 11414345Sdougm subgroup = strchr(group, '/'); 11424345Sdougm if (subgroup != NULL) 11434345Sdougm *subgroup++ = '\0'; 11444345Sdougm } 11454327Sdougm } 11464345Sdougm /* 11474345Sdougm * We want to find the, possibly, named group. If 11484345Sdougm * group is not NULL, then lookup the name. If it is 11494345Sdougm * NULL, we only do the find if groupname is also 11504345Sdougm * NULL. This allows lookup of the "first" group in 11514345Sdougm * the internal list. 11524345Sdougm */ 11534345Sdougm if (group != NULL || groupname == NULL) 11544345Sdougm node = find_group_by_name(impl_handle->tree, 11554345Sdougm (xmlChar *)group); 11564345Sdougm 11574327Sdougm /* if a subgroup, find it before returning */ 11584327Sdougm if (subgroup != NULL && node != NULL) 11594327Sdougm node = find_group_by_name(node, (xmlChar *)subgroup); 11603034Sdougm } 11613034Sdougm if (node != NULL && (char *)group != NULL) 11624327Sdougm (void) sa_get_instance(impl_handle->scfhandle, (char *)group); 11633034Sdougm if (group != NULL) 11644327Sdougm free(group); 11653034Sdougm return ((sa_group_t)(node)); 11663034Sdougm } 11673034Sdougm 11683034Sdougm /* 11693034Sdougm * sa_get_next_group(group) 11703034Sdougm * Return the "next" group after the specified group from 11713034Sdougm * the internal group list. NULL if there are no more. 11723034Sdougm */ 11733034Sdougm sa_group_t 11743034Sdougm sa_get_next_group(sa_group_t group) 11753034Sdougm { 11763034Sdougm xmlNodePtr ngroup = NULL; 11773034Sdougm if (group != NULL) { 11784327Sdougm for (ngroup = ((xmlNodePtr)group)->next; ngroup != NULL; 11793034Sdougm ngroup = ngroup->next) { 11804327Sdougm if (xmlStrcmp(ngroup->name, (xmlChar *)"group") == 0) 11814327Sdougm break; 11824327Sdougm } 11833034Sdougm } 11843034Sdougm return ((sa_group_t)ngroup); 11853034Sdougm } 11863034Sdougm 11873034Sdougm /* 11883034Sdougm * sa_get_share(group, sharepath) 11893034Sdougm * Return the share object for the share specified. The share 11903034Sdougm * must be in the specified group. Return NULL if not found. 11913034Sdougm */ 11923034Sdougm sa_share_t 11933034Sdougm sa_get_share(sa_group_t group, char *sharepath) 11943034Sdougm { 11953034Sdougm xmlNodePtr node = NULL; 11963034Sdougm xmlChar *path; 11973034Sdougm 11983034Sdougm /* 11993034Sdougm * For future scalability, this should end up building a cache 12003034Sdougm * since it will get called regularly by the mountd and info 12013034Sdougm * services. 12023034Sdougm */ 12033034Sdougm if (group != NULL) { 12044327Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 12053034Sdougm node = node->next) { 12064327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) { 12074327Sdougm if (sharepath == NULL) { 12084327Sdougm break; 12094327Sdougm } else { 12104327Sdougm /* is it the correct share? */ 12114327Sdougm path = xmlGetProp(node, 12124327Sdougm (xmlChar *)"path"); 12134327Sdougm if (path != NULL && 12144327Sdougm xmlStrcmp(path, 12154327Sdougm (xmlChar *)sharepath) == 0) { 12164327Sdougm xmlFree(path); 12174327Sdougm break; 12184327Sdougm } 12194327Sdougm xmlFree(path); 12204327Sdougm } 12213034Sdougm } 12223034Sdougm } 12233034Sdougm } 12243034Sdougm return ((sa_share_t)node); 12253034Sdougm } 12263034Sdougm 12273034Sdougm /* 12283034Sdougm * sa_get_next_share(share) 12293034Sdougm * Return the next share following the specified share 12303034Sdougm * from the internal list of shares. Returns NULL if there 12313034Sdougm * are no more shares. The list is relative to the same 12323034Sdougm * group. 12333034Sdougm */ 12343034Sdougm sa_share_t 12353034Sdougm sa_get_next_share(sa_share_t share) 12363034Sdougm { 12373034Sdougm xmlNodePtr node = NULL; 12383034Sdougm 12393034Sdougm if (share != NULL) { 12404327Sdougm for (node = ((xmlNodePtr)share)->next; node != NULL; 12413034Sdougm node = node->next) { 12424327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) { 12434327Sdougm break; 12444327Sdougm } 12453034Sdougm } 12463034Sdougm } 12473034Sdougm return ((sa_share_t)node); 12483034Sdougm } 12493034Sdougm 12503034Sdougm /* 12513034Sdougm * _sa_get_child_node(node, type) 12523034Sdougm * 12533034Sdougm * find the child node of the specified node that has "type". This is 12543034Sdougm * used to implement several internal functions. 12553034Sdougm */ 12563034Sdougm 12573034Sdougm static xmlNodePtr 12583034Sdougm _sa_get_child_node(xmlNodePtr node, xmlChar *type) 12593034Sdougm { 12603034Sdougm xmlNodePtr child; 12613034Sdougm for (child = node->xmlChildrenNode; child != NULL; 12623034Sdougm child = child->next) 12634327Sdougm if (xmlStrcmp(child->name, type) == 0) 12644327Sdougm return (child); 12653034Sdougm return ((xmlNodePtr)NULL); 12663034Sdougm } 12673034Sdougm 12683034Sdougm /* 12693034Sdougm * find_share(group, path) 12703034Sdougm * 12713034Sdougm * Search all the shares in the specified group for one that has the 12723034Sdougm * specified path. 12733034Sdougm */ 12743034Sdougm 12753034Sdougm static sa_share_t 12763034Sdougm find_share(sa_group_t group, char *sharepath) 12773034Sdougm { 12783034Sdougm sa_share_t share; 12793034Sdougm char *path; 12803034Sdougm 12813034Sdougm for (share = sa_get_share(group, NULL); share != NULL; 12823034Sdougm share = sa_get_next_share(share)) { 12834327Sdougm path = sa_get_share_attr(share, "path"); 12844327Sdougm if (path != NULL && strcmp(path, sharepath) == 0) { 12854327Sdougm sa_free_attr_string(path); 12864327Sdougm break; 12874327Sdougm } 12884327Sdougm if (path != NULL) 12894327Sdougm sa_free_attr_string(path); 12903034Sdougm } 12913034Sdougm return (share); 12923034Sdougm } 12933034Sdougm 12943034Sdougm /* 12953034Sdougm * sa_get_sub_group(group) 12963034Sdougm * 12973034Sdougm * Get the first sub-group of group. The sa_get_next_group() function 12983034Sdougm * can be used to get the rest. This is currently only used for ZFS 12993034Sdougm * sub-groups but could be used to implement a more general mechanism. 13003034Sdougm */ 13013034Sdougm 13023034Sdougm sa_group_t 13033034Sdougm sa_get_sub_group(sa_group_t group) 13043034Sdougm { 13053034Sdougm return ((sa_group_t)_sa_get_child_node((xmlNodePtr)group, 13064327Sdougm (xmlChar *)"group")); 13073034Sdougm } 13083034Sdougm 13093034Sdougm /* 13103034Sdougm * sa_find_share(sharepath) 13113034Sdougm * Finds a share regardless of group. In the future, this 13123034Sdougm * function should utilize a cache and hash table of some kind. 13133034Sdougm * The current assumption is that a path will only be shared 13143034Sdougm * once. In the future, this may change as implementation of 13153034Sdougm * resource names comes into being. 13163034Sdougm */ 13173034Sdougm sa_share_t 13183910Sdougm sa_find_share(sa_handle_t handle, char *sharepath) 13193034Sdougm { 13203034Sdougm sa_group_t group; 13213034Sdougm sa_group_t zgroup; 13223034Sdougm sa_share_t share = NULL; 13233034Sdougm int done = 0; 13243034Sdougm 13253910Sdougm for (group = sa_get_group(handle, NULL); group != NULL && !done; 13264327Sdougm group = sa_get_next_group(group)) { 13274327Sdougm if (is_zfs_group(group)) { 13284327Sdougm for (zgroup = 13294327Sdougm (sa_group_t)_sa_get_child_node((xmlNodePtr)group, 13304327Sdougm (xmlChar *)"group"); 13314327Sdougm zgroup != NULL; 13324327Sdougm zgroup = sa_get_next_group(zgroup)) { 13334327Sdougm share = find_share(zgroup, sharepath); 13344327Sdougm if (share != NULL) 13354327Sdougm break; 13364327Sdougm } 13374327Sdougm } else { 13384327Sdougm share = find_share(group, sharepath); 13394327Sdougm } 13404327Sdougm if (share != NULL) 13413034Sdougm break; 13423034Sdougm } 13433034Sdougm return (share); 13443034Sdougm } 13453034Sdougm 13463034Sdougm /* 13473348Sdougm * sa_check_path(group, path, strictness) 13483034Sdougm * 13495331Samw * Check that path is a valid path relative to the group. Currently, 13503034Sdougm * we are ignoring the group and checking only the NFS rules. Later, 13513034Sdougm * we may want to use the group to then check against the protocols 13523348Sdougm * enabled on the group. The strictness values mean: 13533348Sdougm * SA_CHECK_NORMAL == only check newpath against shares that are active 13543348Sdougm * SA_CHECK_STRICT == check newpath against both active shares and those 13553348Sdougm * stored in the repository 13563034Sdougm */ 13573034Sdougm 13583034Sdougm int 13593348Sdougm sa_check_path(sa_group_t group, char *path, int strictness) 13603034Sdougm { 13613910Sdougm sa_handle_t handle; 13623910Sdougm 13633910Sdougm handle = sa_find_group_handle(group); 13643910Sdougm return (validpath(handle, path, strictness)); 13653034Sdougm } 13663034Sdougm 13673034Sdougm /* 13685331Samw * mark_excluded_protos(group, share, flags) 13693034Sdougm * 13705331Samw * Walk through all the protocols enabled for the group and check to 13715331Samw * see if the share has any of them should be in the exclude list 13725331Samw * based on the featureset of the protocol. If there are any, add the 13735331Samw * "exclude" property to the share. 13745331Samw */ 13755331Samw static void 13765331Samw mark_excluded_protos(sa_group_t group, xmlNodePtr share, uint64_t flags) 13775331Samw { 13785331Samw sa_optionset_t optionset; 13795331Samw char exclude_list[SA_STRSIZE]; 13805331Samw char *sep = ""; 13815331Samw 13825331Samw exclude_list[0] = '\0'; 13835331Samw for (optionset = sa_get_optionset(group, NULL); 13845331Samw optionset != NULL; 13855331Samw optionset = sa_get_next_optionset(optionset)) { 13865331Samw char *value; 13875331Samw uint64_t features; 13885331Samw value = sa_get_optionset_attr(optionset, "type"); 13895331Samw if (value == NULL) 13905331Samw continue; 13915331Samw features = sa_proto_get_featureset(value); 13925331Samw if (!(features & flags)) { 13935331Samw (void) strlcat(exclude_list, sep, 13945331Samw sizeof (exclude_list)); 13955331Samw (void) strlcat(exclude_list, value, 13965331Samw sizeof (exclude_list)); 13975331Samw sep = ","; 13985331Samw } 1399*11337SWilliam.Krier@Sun.COM sa_free_attr_string(value); 14005331Samw } 14015331Samw if (exclude_list[0] != '\0') 14026007Sthurlow (void) xmlSetProp(share, (xmlChar *)"exclude", 14035331Samw (xmlChar *)exclude_list); 14045331Samw } 14055331Samw 14065331Samw /* 14075331Samw * get_all_features(group) 14085331Samw * 14095331Samw * Walk through all the protocols on the group and collect all 14105331Samw * possible enabled features. This is the OR of all the featuresets. 14115331Samw */ 14125331Samw static uint64_t 14135331Samw get_all_features(sa_group_t group) 14145331Samw { 14155331Samw sa_optionset_t optionset; 14165331Samw uint64_t features = 0; 14175331Samw 14185331Samw for (optionset = sa_get_optionset(group, NULL); 14195331Samw optionset != NULL; 14205331Samw optionset = sa_get_next_optionset(optionset)) { 14215331Samw char *value; 14225331Samw value = sa_get_optionset_attr(optionset, "type"); 14235331Samw if (value == NULL) 14245331Samw continue; 14255331Samw features |= sa_proto_get_featureset(value); 14265331Samw sa_free_attr_string(value); 14275331Samw } 14285331Samw return (features); 14295331Samw } 14305331Samw 14315331Samw 14325331Samw /* 14335331Samw * _sa_add_share(group, sharepath, persist, *error, flags) 14345331Samw * 14355331Samw * Common code for all types of add_share. sa_add_share() is the 14363034Sdougm * public API, we also need to be able to do this when parsing legacy 14373034Sdougm * files and construction of the internal configuration while 14385331Samw * extracting config info from SMF. "flags" indicates if some 14395331Samw * protocols need relaxed rules while other don't. These values are 14405331Samw * the featureset values defined in libshare.h. 14413034Sdougm */ 14423034Sdougm 14433034Sdougm sa_share_t 14445331Samw _sa_add_share(sa_group_t group, char *sharepath, int persist, int *error, 14455331Samw uint64_t flags) 14463034Sdougm { 14473034Sdougm xmlNodePtr node = NULL; 14483034Sdougm int err; 14493034Sdougm 14503034Sdougm err = SA_OK; /* assume success */ 14513034Sdougm 14524327Sdougm node = xmlNewChild((xmlNodePtr)group, NULL, (xmlChar *)"share", NULL); 14535331Samw if (node == NULL) { 14545331Samw if (error != NULL) 14555331Samw *error = SA_NO_MEMORY; 14565331Samw return (node); 14575331Samw } 14585331Samw 14596007Sthurlow (void) xmlSetProp(node, (xmlChar *)"path", (xmlChar *)sharepath); 14606007Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", 14615331Samw persist ? (xmlChar *)"persist" : (xmlChar *)"transient"); 14625331Samw if (flags != 0) 14635331Samw mark_excluded_protos(group, node, flags); 14645331Samw if (persist != SA_SHARE_TRANSIENT) { 14655331Samw /* 14665331Samw * persistent shares come in two flavors: SMF and 14675331Samw * ZFS. Sort this one out based on target group and 14685331Samw * path type. Both NFS and SMB are supported. First, 14695331Samw * check to see if the protocol is enabled on the 14705331Samw * subgroup and then setup the share appropriately. 14715331Samw */ 14725331Samw if (sa_group_is_zfs(group) && 14735331Samw sa_path_is_zfs(sharepath)) { 14745331Samw if (sa_get_optionset(group, "nfs") != NULL) 14754327Sdougm err = sa_zfs_set_sharenfs(group, sharepath, 1); 14765331Samw else if (sa_get_optionset(group, "smb") != NULL) 14775331Samw err = sa_zfs_set_sharesmb(group, sharepath, 1); 14785331Samw } else { 14795331Samw sa_handle_impl_t impl_handle; 14805331Samw impl_handle = 14815331Samw (sa_handle_impl_t)sa_find_group_handle(group); 14825331Samw if (impl_handle != NULL) { 14835331Samw err = sa_commit_share(impl_handle->scfhandle, 14845331Samw group, (sa_share_t)node); 14854327Sdougm } else { 14865331Samw err = SA_SYSTEM_ERR; 14874327Sdougm } 14883034Sdougm } 14893034Sdougm } 14905331Samw if (err == SA_NO_PERMISSION && persist & SA_SHARE_PARSER) 14915331Samw /* called by the dfstab parser so could be a show */ 14925331Samw err = SA_OK; 14935331Samw 14945331Samw if (err != SA_OK) { 14955331Samw /* 14965331Samw * we couldn't commit to the repository so undo 14975331Samw * our internal state to reflect reality. 14985331Samw */ 14995331Samw xmlUnlinkNode(node); 15005331Samw xmlFreeNode(node); 15015331Samw node = NULL; 15025331Samw } 15035331Samw 15043034Sdougm if (error != NULL) 15054327Sdougm *error = err; 15065331Samw 15073034Sdougm return (node); 15083034Sdougm } 15093034Sdougm 15103034Sdougm /* 15113034Sdougm * sa_add_share(group, sharepath, persist, *error) 15123034Sdougm * 15133034Sdougm * Add a new share object to the specified group. The share will 15143034Sdougm * have the specified sharepath and will only be constructed if 15153034Sdougm * it is a valid path to be shared. NULL is returned on error 15163034Sdougm * and a detailed error value will be returned via the error 15173034Sdougm * pointer. 15183034Sdougm */ 15193034Sdougm sa_share_t 15203034Sdougm sa_add_share(sa_group_t group, char *sharepath, int persist, int *error) 15213034Sdougm { 15223034Sdougm xmlNodePtr node = NULL; 15233348Sdougm int strictness = SA_CHECK_NORMAL; 15243910Sdougm sa_handle_t handle; 15255331Samw uint64_t special = 0; 15265331Samw uint64_t features; 15273348Sdougm 15283348Sdougm /* 15293348Sdougm * If the share is to be permanent, use strict checking so a 15303348Sdougm * bad config doesn't get created. Transient shares only need 15313348Sdougm * to check against the currently active 15323348Sdougm * shares. SA_SHARE_PARSER is a modifier used internally to 15333348Sdougm * indicate that we are being called by the dfstab parser and 15343348Sdougm * that we need strict checking in all cases. Normally persist 15353348Sdougm * is in integer value but SA_SHARE_PARSER may be or'd into 15363348Sdougm * it as an override. 15373348Sdougm */ 15383348Sdougm if (persist & SA_SHARE_PARSER || persist == SA_SHARE_PERMANENT) 15394327Sdougm strictness = SA_CHECK_STRICT; 15403034Sdougm 15413910Sdougm handle = sa_find_group_handle(group); 15423910Sdougm 15435331Samw /* 15445331Samw * need to determine if the share is valid. The rules are: 15455331Samw * - The path must not already exist 15465331Samw * - The path must not be a subdir or parent dir of an 15475331Samw * existing path unless at least one protocol allows it. 15485331Samw * The sub/parent check is done in sa_check_path(). 15495331Samw */ 15505331Samw 15515331Samw if (sa_find_share(handle, sharepath) == NULL) { 15525331Samw *error = sa_check_path(group, sharepath, strictness); 15535331Samw features = get_all_features(group); 15545331Samw switch (*error) { 15555331Samw case SA_PATH_IS_SUBDIR: 15565331Samw if (features & SA_FEATURE_ALLOWSUBDIRS) 15575331Samw special |= SA_FEATURE_ALLOWSUBDIRS; 15585331Samw break; 15595331Samw case SA_PATH_IS_PARENTDIR: 15605331Samw if (features & SA_FEATURE_ALLOWPARDIRS) 15615331Samw special |= SA_FEATURE_ALLOWPARDIRS; 15625331Samw break; 15635331Samw } 15645331Samw if (*error == SA_OK || special != SA_FEATURE_NONE) 15655331Samw node = _sa_add_share(group, sharepath, persist, 15665331Samw error, special); 15675331Samw } else { 15685331Samw *error = SA_DUPLICATE_NAME; 15693034Sdougm } 15703034Sdougm 15713034Sdougm return ((sa_share_t)node); 15723034Sdougm } 15733034Sdougm 15743034Sdougm /* 15753034Sdougm * sa_enable_share(share, protocol) 15763034Sdougm * Enable the specified share to the specified protocol. 15773034Sdougm * If protocol is NULL, then all protocols. 15783034Sdougm */ 15793034Sdougm int 15803034Sdougm sa_enable_share(sa_share_t share, char *protocol) 15813034Sdougm { 15823034Sdougm char *sharepath; 15833034Sdougm struct stat st; 15845331Samw int err = SA_OK; 15855331Samw int ret; 15863034Sdougm 15873034Sdougm sharepath = sa_get_share_attr(share, "path"); 15885331Samw if (sharepath == NULL) 15895331Samw return (SA_NO_MEMORY); 15903034Sdougm if (stat(sharepath, &st) < 0) { 15914327Sdougm err = SA_NO_SUCH_PATH; 15923034Sdougm } else { 15934327Sdougm /* tell the server about the share */ 15944327Sdougm if (protocol != NULL) { 15955331Samw if (excluded_protocol(share, protocol)) 15965331Samw goto done; 15975331Samw 15984327Sdougm /* lookup protocol specific handler */ 15994327Sdougm err = sa_proto_share(protocol, share); 16004327Sdougm if (err == SA_OK) 16015331Samw (void) sa_set_share_attr(share, 16025331Samw "shared", "true"); 16034327Sdougm } else { 16045331Samw /* Tell all protocols about the share */ 16055331Samw sa_group_t group; 16065331Samw sa_optionset_t optionset; 16075331Samw 16085331Samw group = sa_get_parent_group(share); 16095331Samw 16105331Samw for (optionset = sa_get_optionset(group, NULL); 16115331Samw optionset != NULL; 16125331Samw optionset = sa_get_next_optionset(optionset)) { 16135331Samw char *proto; 16145331Samw proto = sa_get_optionset_attr(optionset, 16155331Samw "type"); 16165331Samw if (proto != NULL) { 16175331Samw if (!excluded_protocol(share, proto)) { 16185331Samw ret = sa_proto_share(proto, 16195331Samw share); 16205331Samw if (ret != SA_OK) 16215331Samw err = ret; 16225331Samw } 16235331Samw sa_free_attr_string(proto); 16245331Samw } 16255331Samw } 16264327Sdougm (void) sa_set_share_attr(share, "shared", "true"); 16274327Sdougm } 16283034Sdougm } 16295331Samw done: 16303034Sdougm if (sharepath != NULL) 16314327Sdougm sa_free_attr_string(sharepath); 16323034Sdougm return (err); 16333034Sdougm } 16343034Sdougm 16353034Sdougm /* 16363034Sdougm * sa_disable_share(share, protocol) 16375331Samw * Disable the specified share to the specified protocol. If 16385331Samw * protocol is NULL, then all protocols that are enabled for the 16395331Samw * share should be disabled. 16403034Sdougm */ 16413034Sdougm int 16423034Sdougm sa_disable_share(sa_share_t share, char *protocol) 16433034Sdougm { 16443034Sdougm char *path; 16455331Samw int err = SA_OK; 16463034Sdougm int ret = SA_OK; 16473034Sdougm 16483034Sdougm path = sa_get_share_attr(share, "path"); 16493034Sdougm 16503034Sdougm if (protocol != NULL) { 16514543Smarks ret = sa_proto_unshare(share, protocol, path); 16523034Sdougm } else { 16534327Sdougm /* need to do all protocols */ 16545331Samw sa_group_t group; 16555331Samw sa_optionset_t optionset; 16565331Samw 16575331Samw group = sa_get_parent_group(share); 16585331Samw 16595331Samw /* Tell all protocols about the share */ 16605331Samw for (optionset = sa_get_optionset(group, NULL); 16615331Samw optionset != NULL; 16625331Samw optionset = sa_get_next_optionset(optionset)) { 16635331Samw char *proto; 16645331Samw 16655331Samw proto = sa_get_optionset_attr(optionset, "type"); 16665331Samw if (proto != NULL) { 16675331Samw err = sa_proto_unshare(share, proto, path); 16685331Samw if (err != SA_OK) 16695331Samw ret = err; 16705331Samw sa_free_attr_string(proto); 16715331Samw } 16725331Samw } 16733034Sdougm } 16743034Sdougm if (ret == SA_OK) 16753034Sdougm (void) sa_set_share_attr(share, "shared", NULL); 16763034Sdougm if (path != NULL) 16774327Sdougm sa_free_attr_string(path); 16783034Sdougm return (ret); 16793034Sdougm } 16803034Sdougm 16813034Sdougm /* 16823034Sdougm * sa_remove_share(share) 16833034Sdougm * 16843034Sdougm * remove the specified share from its containing group. 16853034Sdougm * Remove from the SMF or ZFS configuration space. 16863034Sdougm */ 16873034Sdougm 16883034Sdougm int 16893034Sdougm sa_remove_share(sa_share_t share) 16903034Sdougm { 16913034Sdougm sa_group_t group; 16923034Sdougm int ret = SA_OK; 16933034Sdougm char *type; 16943034Sdougm int transient = 0; 16953034Sdougm char *groupname; 16963034Sdougm char *zfs; 16973034Sdougm 16983034Sdougm type = sa_get_share_attr(share, "type"); 16993034Sdougm group = sa_get_parent_group(share); 17003034Sdougm zfs = sa_get_group_attr(group, "zfs"); 17013034Sdougm groupname = sa_get_group_attr(group, "name"); 17023034Sdougm if (type != NULL && strcmp(type, "persist") != 0) 17034327Sdougm transient = 1; 17043034Sdougm if (type != NULL) 17054327Sdougm sa_free_attr_string(type); 17063034Sdougm 17073034Sdougm /* remove the node from its group then free the memory */ 17083034Sdougm 17093034Sdougm /* 17103034Sdougm * need to test if "busy" 17113034Sdougm */ 17123034Sdougm /* only do SMF action if permanent */ 17133034Sdougm if (!transient || zfs != NULL) { 17144327Sdougm /* remove from legacy dfstab as well as possible SMF */ 17155331Samw ret = sa_delete_legacy(share, NULL); 17164327Sdougm if (ret == SA_OK) { 17174327Sdougm if (!sa_group_is_zfs(group)) { 17184327Sdougm sa_handle_impl_t impl_handle; 17194327Sdougm impl_handle = (sa_handle_impl_t) 17204327Sdougm sa_find_group_handle(group); 17214327Sdougm if (impl_handle != NULL) { 17224327Sdougm ret = sa_delete_share( 17234327Sdougm impl_handle->scfhandle, group, 17244327Sdougm share); 17254327Sdougm } else { 17264327Sdougm ret = SA_SYSTEM_ERR; 17274327Sdougm } 17284327Sdougm } else { 17294327Sdougm char *sharepath = sa_get_share_attr(share, 17304327Sdougm "path"); 17314327Sdougm if (sharepath != NULL) { 17324327Sdougm ret = sa_zfs_set_sharenfs(group, 17334327Sdougm sharepath, 0); 17344327Sdougm sa_free_attr_string(sharepath); 17354327Sdougm } 17364327Sdougm } 17373034Sdougm } 17383034Sdougm } 17393034Sdougm if (groupname != NULL) 17404327Sdougm sa_free_attr_string(groupname); 17413034Sdougm if (zfs != NULL) 17424327Sdougm sa_free_attr_string(zfs); 17433034Sdougm 17443034Sdougm xmlUnlinkNode((xmlNodePtr)share); 17453034Sdougm xmlFreeNode((xmlNodePtr)share); 17463034Sdougm return (ret); 17473034Sdougm } 17483034Sdougm 17493034Sdougm /* 17503034Sdougm * sa_move_share(group, share) 17513034Sdougm * 17523034Sdougm * move the specified share to the specified group. Update SMF 17533034Sdougm * appropriately. 17543034Sdougm */ 17553034Sdougm 17563034Sdougm int 17573034Sdougm sa_move_share(sa_group_t group, sa_share_t share) 17583034Sdougm { 17593034Sdougm sa_group_t oldgroup; 17603034Sdougm int ret = SA_OK; 17613034Sdougm 17623034Sdougm /* remove the node from its group then free the memory */ 17633034Sdougm 17643034Sdougm oldgroup = sa_get_parent_group(share); 17653034Sdougm if (oldgroup != group) { 17664327Sdougm sa_handle_impl_t impl_handle; 17674327Sdougm xmlUnlinkNode((xmlNodePtr)share); 17683034Sdougm /* 17694327Sdougm * now that the share isn't in its old group, add to 17704327Sdougm * the new one 17713034Sdougm */ 17726007Sthurlow (void) xmlAddChild((xmlNodePtr)group, (xmlNodePtr)share); 17734327Sdougm /* need to deal with SMF */ 17744327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 17754327Sdougm if (impl_handle != NULL) { 17764327Sdougm /* 17774327Sdougm * need to remove from old group first and then add to 17784327Sdougm * new group. Ideally, we would do the other order but 17794327Sdougm * need to avoid having the share in two groups at the 17804327Sdougm * same time. 17814327Sdougm */ 17824327Sdougm ret = sa_delete_share(impl_handle->scfhandle, oldgroup, 17834327Sdougm share); 17844327Sdougm if (ret == SA_OK) 17854327Sdougm ret = sa_commit_share(impl_handle->scfhandle, 17864327Sdougm group, share); 17874327Sdougm } else { 17884327Sdougm ret = SA_SYSTEM_ERR; 17894327Sdougm } 17903034Sdougm } 17913034Sdougm return (ret); 17923034Sdougm } 17933034Sdougm 17943034Sdougm /* 17953034Sdougm * sa_get_parent_group(share) 17963034Sdougm * 17975331Samw * Return the containing group for the share. If a group was actually 17983034Sdougm * passed in, we don't want a parent so return NULL. 17993034Sdougm */ 18003034Sdougm 18013034Sdougm sa_group_t 18023034Sdougm sa_get_parent_group(sa_share_t share) 18033034Sdougm { 18043034Sdougm xmlNodePtr node = NULL; 18053034Sdougm if (share != NULL) { 18064327Sdougm node = ((xmlNodePtr)share)->parent; 18073034Sdougm /* 18083034Sdougm * make sure parent is a group and not sharecfg since 18093034Sdougm * we may be cheating and passing in a group. 18103034Sdougm * Eventually, groups of groups might come into being. 18113034Sdougm */ 18124327Sdougm if (node == NULL || 18134327Sdougm xmlStrcmp(node->name, (xmlChar *)"sharecfg") == 0) 18144327Sdougm node = NULL; 18153034Sdougm } 18163034Sdougm return ((sa_group_t)node); 18173034Sdougm } 18183034Sdougm 18193034Sdougm /* 18203910Sdougm * _sa_create_group(impl_handle, groupname) 18213034Sdougm * 18223034Sdougm * Create a group in the document. The caller will need to deal with 18233034Sdougm * configuration store and activation. 18243034Sdougm */ 18253034Sdougm 18263034Sdougm sa_group_t 18273910Sdougm _sa_create_group(sa_handle_impl_t impl_handle, char *groupname) 18283034Sdougm { 18293034Sdougm xmlNodePtr node = NULL; 18303034Sdougm 18313034Sdougm if (sa_valid_group_name(groupname)) { 18324327Sdougm node = xmlNewChild(impl_handle->tree, NULL, (xmlChar *)"group", 18334327Sdougm NULL); 18344327Sdougm if (node != NULL) { 18356007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 18364327Sdougm (xmlChar *)groupname); 18376007Sthurlow (void) xmlSetProp(node, (xmlChar *)"state", 18384327Sdougm (xmlChar *)"enabled"); 18394327Sdougm } 18403034Sdougm } 18413034Sdougm return ((sa_group_t)node); 18423034Sdougm } 18433034Sdougm 18443034Sdougm /* 18453034Sdougm * _sa_create_zfs_group(group, groupname) 18463034Sdougm * 18473034Sdougm * Create a ZFS subgroup under the specified group. This may 18483034Sdougm * eventually form the basis of general sub-groups, but is currently 18493034Sdougm * restricted to ZFS. 18503034Sdougm */ 18513034Sdougm sa_group_t 18523034Sdougm _sa_create_zfs_group(sa_group_t group, char *groupname) 18533034Sdougm { 18543034Sdougm xmlNodePtr node = NULL; 18553034Sdougm 18564327Sdougm node = xmlNewChild((xmlNodePtr)group, NULL, (xmlChar *)"group", NULL); 18573034Sdougm if (node != NULL) { 18586007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 18596007Sthurlow (xmlChar *)groupname); 18606007Sthurlow (void) xmlSetProp(node, (xmlChar *)"state", 18616007Sthurlow (xmlChar *)"enabled"); 18623034Sdougm } 18633034Sdougm 18643034Sdougm return ((sa_group_t)node); 18653034Sdougm } 18663034Sdougm 18673034Sdougm /* 18683034Sdougm * sa_create_group(groupname, *error) 18693034Sdougm * 18703034Sdougm * Create a new group with groupname. Need to validate that it is a 18713034Sdougm * legal name for SMF and the construct the SMF service instance of 18723034Sdougm * svc:/network/shares/group to implement the group. All necessary 18733034Sdougm * operational properties must be added to the group at this point 18743034Sdougm * (via the SMF transaction model). 18753034Sdougm */ 18763034Sdougm sa_group_t 18773910Sdougm sa_create_group(sa_handle_t handle, char *groupname, int *error) 18783034Sdougm { 18793034Sdougm xmlNodePtr node = NULL; 18803034Sdougm sa_group_t group; 18813034Sdougm int ret; 18824327Sdougm char rbacstr[SA_STRSIZE]; 18833910Sdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle; 18843034Sdougm 18853034Sdougm ret = SA_OK; 18863034Sdougm 18873910Sdougm if (impl_handle == NULL || impl_handle->scfhandle == NULL) { 18884327Sdougm ret = SA_SYSTEM_ERR; 18894327Sdougm goto err; 18903034Sdougm } 18913034Sdougm 18923910Sdougm group = sa_get_group(handle, groupname); 18933034Sdougm if (group != NULL) { 18944327Sdougm ret = SA_DUPLICATE_NAME; 18953034Sdougm } else { 18964327Sdougm if (sa_valid_group_name(groupname)) { 18974327Sdougm node = xmlNewChild(impl_handle->tree, NULL, 18984327Sdougm (xmlChar *)"group", NULL); 18994327Sdougm if (node != NULL) { 19006007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 19014327Sdougm (xmlChar *)groupname); 19024327Sdougm /* default to the group being enabled */ 19036007Sthurlow (void) xmlSetProp(node, (xmlChar *)"state", 19044327Sdougm (xmlChar *)"enabled"); 19054327Sdougm ret = sa_create_instance(impl_handle->scfhandle, 19064327Sdougm groupname); 19074327Sdougm if (ret == SA_OK) { 19084327Sdougm ret = sa_start_transaction( 19094327Sdougm impl_handle->scfhandle, 19104327Sdougm "operation"); 19114327Sdougm } 19124327Sdougm if (ret == SA_OK) { 19134327Sdougm ret = sa_set_property( 19144327Sdougm impl_handle->scfhandle, 19154327Sdougm "state", "enabled"); 19164327Sdougm if (ret == SA_OK) { 19174327Sdougm ret = sa_end_transaction( 19185951Sdougm impl_handle->scfhandle, 19195951Sdougm impl_handle); 19204327Sdougm } else { 19214327Sdougm sa_abort_transaction( 19224327Sdougm impl_handle->scfhandle); 19234327Sdougm } 19244327Sdougm } 19254327Sdougm if (ret == SA_OK) { 19264327Sdougm /* initialize the RBAC strings */ 19274327Sdougm ret = sa_start_transaction( 19284327Sdougm impl_handle->scfhandle, 19294327Sdougm "general"); 19304327Sdougm if (ret == SA_OK) { 19314327Sdougm (void) snprintf(rbacstr, 19324327Sdougm sizeof (rbacstr), "%s.%s", 19334327Sdougm SA_RBAC_MANAGE, groupname); 19344327Sdougm ret = sa_set_property( 19354327Sdougm impl_handle->scfhandle, 19363034Sdougm "action_authorization", 19373034Sdougm rbacstr); 19384327Sdougm } 19394327Sdougm if (ret == SA_OK) { 19404327Sdougm (void) snprintf(rbacstr, 19414327Sdougm sizeof (rbacstr), "%s.%s", 19424327Sdougm SA_RBAC_VALUE, groupname); 19434327Sdougm ret = sa_set_property( 19444327Sdougm impl_handle->scfhandle, 19453034Sdougm "value_authorization", 19463034Sdougm rbacstr); 19474327Sdougm } 19484327Sdougm if (ret == SA_OK) { 19494327Sdougm ret = sa_end_transaction( 19505951Sdougm impl_handle->scfhandle, 19515951Sdougm impl_handle); 19524327Sdougm } else { 19534327Sdougm sa_abort_transaction( 19544327Sdougm impl_handle->scfhandle); 19554327Sdougm } 19564327Sdougm } 19574327Sdougm if (ret != SA_OK) { 19584327Sdougm /* 19594327Sdougm * Couldn't commit the group 19604327Sdougm * so we need to undo 19614327Sdougm * internally. 19624327Sdougm */ 19634327Sdougm xmlUnlinkNode(node); 19644327Sdougm xmlFreeNode(node); 19654327Sdougm node = NULL; 19664327Sdougm } 19673034Sdougm } else { 19684327Sdougm ret = SA_NO_MEMORY; 19693034Sdougm } 19703034Sdougm } else { 19714327Sdougm ret = SA_INVALID_NAME; 19723034Sdougm } 19733034Sdougm } 19743034Sdougm err: 19753034Sdougm if (error != NULL) 19764327Sdougm *error = ret; 19773034Sdougm return ((sa_group_t)node); 19783034Sdougm } 19793034Sdougm 19803034Sdougm /* 19813034Sdougm * sa_remove_group(group) 19823034Sdougm * 19833034Sdougm * Remove the specified group. This deletes from the SMF repository. 19843034Sdougm * All property groups and properties are removed. 19853034Sdougm */ 19863034Sdougm 19873034Sdougm int 19883034Sdougm sa_remove_group(sa_group_t group) 19893034Sdougm { 19903034Sdougm char *name; 19913034Sdougm int ret = SA_OK; 19923910Sdougm sa_handle_impl_t impl_handle; 19933034Sdougm 19943910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 19953910Sdougm if (impl_handle != NULL) { 19964327Sdougm name = sa_get_group_attr(group, "name"); 19974327Sdougm if (name != NULL) { 19984327Sdougm ret = sa_delete_instance(impl_handle->scfhandle, name); 19994327Sdougm sa_free_attr_string(name); 20004327Sdougm } 20014327Sdougm xmlUnlinkNode((xmlNodePtr)group); /* make sure unlinked */ 20024327Sdougm xmlFreeNode((xmlNodePtr)group); /* now it is gone */ 20033910Sdougm } else { 20044327Sdougm ret = SA_SYSTEM_ERR; 20053034Sdougm } 20063034Sdougm return (ret); 20073034Sdougm } 20083034Sdougm 20093034Sdougm /* 20103034Sdougm * sa_update_config() 20113034Sdougm * 20123034Sdougm * Used to update legacy files that need to be updated in bulk 20133034Sdougm * Currently, this is a placeholder and will go away in a future 20143034Sdougm * release. 20153034Sdougm */ 20163034Sdougm 20173034Sdougm int 20183910Sdougm sa_update_config(sa_handle_t handle) 20193034Sdougm { 20203034Sdougm /* 20213034Sdougm * do legacy files first so we can tell when they change. 20223034Sdougm * This will go away when we start updating individual records 20233034Sdougm * rather than the whole file. 20243034Sdougm */ 20253910Sdougm update_legacy_config(handle); 20263034Sdougm return (SA_OK); 20273034Sdougm } 20283034Sdougm 20293034Sdougm /* 20303034Sdougm * get_node_attr(node, tag) 20313034Sdougm * 20325331Samw * Get the specified tag(attribute) if it exists on the node. This is 20333034Sdougm * used internally by a number of attribute oriented functions. 20343034Sdougm */ 20353034Sdougm 20363034Sdougm static char * 20373034Sdougm get_node_attr(void *nodehdl, char *tag) 20383034Sdougm { 20393034Sdougm xmlNodePtr node = (xmlNodePtr)nodehdl; 20403034Sdougm xmlChar *name = NULL; 20413034Sdougm 20424327Sdougm if (node != NULL) 20433034Sdougm name = xmlGetProp(node, (xmlChar *)tag); 20443034Sdougm return ((char *)name); 20453034Sdougm } 20463034Sdougm 20473034Sdougm /* 2048*11337SWilliam.Krier@Sun.COM * set_node_attr(node, tag) 20493034Sdougm * 20505331Samw * Set the specified tag(attribute) to the specified value This is 20513034Sdougm * used internally by a number of attribute oriented functions. It 20523034Sdougm * doesn't update the repository, only the internal document state. 20533034Sdougm */ 20543034Sdougm 20553034Sdougm void 20563034Sdougm set_node_attr(void *nodehdl, char *tag, char *value) 20573034Sdougm { 20583034Sdougm xmlNodePtr node = (xmlNodePtr)nodehdl; 20593034Sdougm if (node != NULL && tag != NULL) { 20604327Sdougm if (value != NULL) 20616007Sthurlow (void) xmlSetProp(node, (xmlChar *)tag, 20626007Sthurlow (xmlChar *)value); 20634327Sdougm else 20646007Sthurlow (void) xmlUnsetProp(node, (xmlChar *)tag); 20653034Sdougm } 20663034Sdougm } 20673034Sdougm 20683034Sdougm /* 20693034Sdougm * sa_get_group_attr(group, tag) 20703034Sdougm * 20713034Sdougm * Get the specied attribute, if defined, for the group. 20723034Sdougm */ 20733034Sdougm 20743034Sdougm char * 20753034Sdougm sa_get_group_attr(sa_group_t group, char *tag) 20763034Sdougm { 20773034Sdougm return (get_node_attr((void *)group, tag)); 20783034Sdougm } 20793034Sdougm 20803034Sdougm /* 20813034Sdougm * sa_set_group_attr(group, tag, value) 20823034Sdougm * 20833034Sdougm * set the specified tag/attribute on the group using value as its 20843034Sdougm * value. 20853034Sdougm * 20863034Sdougm * This will result in setting the property in the SMF repository as 20873034Sdougm * well as in the internal document. 20883034Sdougm */ 20893034Sdougm 20903034Sdougm int 20913034Sdougm sa_set_group_attr(sa_group_t group, char *tag, char *value) 20923034Sdougm { 20933034Sdougm int ret; 20943034Sdougm char *groupname; 20953910Sdougm sa_handle_impl_t impl_handle; 20963034Sdougm 20975331Samw /* 20985331Samw * ZFS group/subgroup doesn't need the handle so shortcut. 20995331Samw */ 21005331Samw if (sa_group_is_zfs(group)) { 21015331Samw set_node_attr((void *)group, tag, value); 21025331Samw return (SA_OK); 21035331Samw } 21045331Samw 21053910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 21063910Sdougm if (impl_handle != NULL) { 21074327Sdougm groupname = sa_get_group_attr(group, "name"); 21084327Sdougm ret = sa_get_instance(impl_handle->scfhandle, groupname); 21093910Sdougm if (ret == SA_OK) { 21104327Sdougm set_node_attr((void *)group, tag, value); 21114327Sdougm ret = sa_start_transaction(impl_handle->scfhandle, 21124327Sdougm "operation"); 21134327Sdougm if (ret == SA_OK) { 21144327Sdougm ret = sa_set_property(impl_handle->scfhandle, 21154327Sdougm tag, value); 21164327Sdougm if (ret == SA_OK) 21175885Sdougm ret = sa_end_transaction( 21185951Sdougm impl_handle->scfhandle, 21195951Sdougm impl_handle); 21204327Sdougm else 21214327Sdougm sa_abort_transaction( 21224327Sdougm impl_handle->scfhandle); 21234327Sdougm } 21245885Sdougm if (ret == SA_SYSTEM_ERR) 21255885Sdougm ret = SA_NO_PERMISSION; 21263034Sdougm } 21274327Sdougm if (groupname != NULL) 21284327Sdougm sa_free_attr_string(groupname); 21293910Sdougm } else { 21304327Sdougm ret = SA_SYSTEM_ERR; 21313034Sdougm } 21323034Sdougm return (ret); 21333034Sdougm } 21343034Sdougm 21353034Sdougm /* 21363034Sdougm * sa_get_share_attr(share, tag) 21373034Sdougm * 21383034Sdougm * Return the value of the tag/attribute set on the specified 21393034Sdougm * share. Returns NULL if the tag doesn't exist. 21403034Sdougm */ 21413034Sdougm 21423034Sdougm char * 21433034Sdougm sa_get_share_attr(sa_share_t share, char *tag) 21443034Sdougm { 21453034Sdougm return (get_node_attr((void *)share, tag)); 21463034Sdougm } 21473034Sdougm 21483034Sdougm /* 21493034Sdougm * _sa_set_share_description(share, description) 21503034Sdougm * 21515331Samw * Add a description tag with text contents to the specified share. A 21525331Samw * separate XML tag is used rather than a property. This can also be 21535331Samw * used with resources. 21543034Sdougm */ 21553034Sdougm 21563034Sdougm xmlNodePtr 21575331Samw _sa_set_share_description(void *share, char *content) 21583034Sdougm { 21593034Sdougm xmlNodePtr node; 21604327Sdougm node = xmlNewChild((xmlNodePtr)share, NULL, (xmlChar *)"description", 21614327Sdougm NULL); 21623034Sdougm xmlNodeSetContent(node, (xmlChar *)content); 21633034Sdougm return (node); 21643034Sdougm } 21653034Sdougm 21663034Sdougm /* 21673034Sdougm * sa_set_share_attr(share, tag, value) 21683034Sdougm * 21693034Sdougm * Set the share attribute specified by tag to the specified value. In 21703034Sdougm * the case of "resource", enforce a no duplicates in a group rule. If 21713034Sdougm * the share is not transient, commit the changes to the repository 21723034Sdougm * else just update the share internally. 21733034Sdougm */ 21743034Sdougm 21753034Sdougm int 21763034Sdougm sa_set_share_attr(sa_share_t share, char *tag, char *value) 21773034Sdougm { 21783034Sdougm sa_group_t group; 21793034Sdougm sa_share_t resource; 21803034Sdougm int ret = SA_OK; 21813034Sdougm 21823034Sdougm group = sa_get_parent_group(share); 21833034Sdougm 21843034Sdougm /* 21853034Sdougm * There are some attributes that may have specific 21863034Sdougm * restrictions on them. Initially, only "resource" has 21873034Sdougm * special meaning that needs to be checked. Only one instance 21883034Sdougm * of a resource name may exist within a group. 21893034Sdougm */ 21903034Sdougm 21913034Sdougm if (strcmp(tag, "resource") == 0) { 21924327Sdougm resource = sa_get_resource(group, value); 21934327Sdougm if (resource != share && resource != NULL) 21944327Sdougm ret = SA_DUPLICATE_NAME; 21953034Sdougm } 21963034Sdougm if (ret == SA_OK) { 21974327Sdougm set_node_attr((void *)share, tag, value); 21984327Sdougm if (group != NULL) { 21994327Sdougm char *type; 22004327Sdougm /* we can probably optimize this some */ 22014327Sdougm type = sa_get_share_attr(share, "type"); 22024327Sdougm if (type == NULL || strcmp(type, "transient") != 0) { 22034327Sdougm sa_handle_impl_t impl_handle; 22044327Sdougm impl_handle = 22054327Sdougm (sa_handle_impl_t)sa_find_group_handle( 22064327Sdougm group); 22074327Sdougm if (impl_handle != NULL) { 22084327Sdougm ret = sa_commit_share( 22094327Sdougm impl_handle->scfhandle, group, 22104327Sdougm share); 22114327Sdougm } else { 22124327Sdougm ret = SA_SYSTEM_ERR; 22134327Sdougm } 22144327Sdougm } 22154327Sdougm if (type != NULL) 22164327Sdougm sa_free_attr_string(type); 22173910Sdougm } 22183034Sdougm } 22193034Sdougm return (ret); 22203034Sdougm } 22213034Sdougm 22223034Sdougm /* 22233034Sdougm * sa_get_property_attr(prop, tag) 22243034Sdougm * 22253034Sdougm * Get the value of the specified property attribute. Standard 22263034Sdougm * attributes are "type" and "value". 22273034Sdougm */ 22283034Sdougm 22293034Sdougm char * 22303034Sdougm sa_get_property_attr(sa_property_t prop, char *tag) 22313034Sdougm { 22323034Sdougm return (get_node_attr((void *)prop, tag)); 22333034Sdougm } 22343034Sdougm 22353034Sdougm /* 22363034Sdougm * sa_get_optionset_attr(prop, tag) 22373034Sdougm * 22383034Sdougm * Get the value of the specified property attribute. Standard 22393034Sdougm * attribute is "type". 22403034Sdougm */ 22413034Sdougm 22423034Sdougm char * 22433034Sdougm sa_get_optionset_attr(sa_property_t optionset, char *tag) 22443034Sdougm { 22453034Sdougm return (get_node_attr((void *)optionset, tag)); 22463034Sdougm 22473034Sdougm } 22483034Sdougm 22493034Sdougm /* 22503034Sdougm * sa_set_optionset_attr(optionset, tag, value) 22513034Sdougm * 22523034Sdougm * Set the specified attribute(tag) to the specified value on the 22533034Sdougm * optionset. 22543034Sdougm */ 22553034Sdougm 22563034Sdougm void 22573034Sdougm sa_set_optionset_attr(sa_group_t optionset, char *tag, char *value) 22583034Sdougm { 22593034Sdougm set_node_attr((void *)optionset, tag, value); 22603034Sdougm } 22613034Sdougm 22623034Sdougm /* 22633034Sdougm * sa_free_attr_string(string) 22643034Sdougm * 22653034Sdougm * Free the string that was returned in one of the sa_get_*_attr() 22663034Sdougm * functions. 22673034Sdougm */ 22683034Sdougm 22693034Sdougm void 22703034Sdougm sa_free_attr_string(char *string) 22713034Sdougm { 22723034Sdougm xmlFree((xmlChar *)string); 22733034Sdougm } 22743034Sdougm 22753034Sdougm /* 22763034Sdougm * sa_get_optionset(group, proto) 22773034Sdougm * 22783034Sdougm * Return the optionset, if it exists, that is associated with the 22793034Sdougm * specified protocol. 22803034Sdougm */ 22813034Sdougm 22823034Sdougm sa_optionset_t 22833034Sdougm sa_get_optionset(void *group, char *proto) 22843034Sdougm { 22853034Sdougm xmlNodePtr node; 22863034Sdougm xmlChar *value = NULL; 22873034Sdougm 22883034Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 22894327Sdougm node = node->next) { 22903034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) { 22914327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 22924327Sdougm if (proto != NULL) { 22934327Sdougm if (value != NULL && 22944327Sdougm xmlStrcmp(value, (xmlChar *)proto) == 0) { 22954327Sdougm break; 22964327Sdougm } 22974327Sdougm if (value != NULL) { 22984327Sdougm xmlFree(value); 22994327Sdougm value = NULL; 23004327Sdougm } 23014327Sdougm } else { 23024327Sdougm break; 23033034Sdougm } 23043034Sdougm } 23053034Sdougm } 23063034Sdougm if (value != NULL) 23074327Sdougm xmlFree(value); 23083034Sdougm return ((sa_optionset_t)node); 23093034Sdougm } 23103034Sdougm 23113034Sdougm /* 23123034Sdougm * sa_get_next_optionset(optionset) 23133034Sdougm * 23143034Sdougm * Return the next optionset in the group. NULL if this was the last. 23153034Sdougm */ 23163034Sdougm 23173034Sdougm sa_optionset_t 23183034Sdougm sa_get_next_optionset(sa_optionset_t optionset) 23193034Sdougm { 23203034Sdougm xmlNodePtr node; 23213034Sdougm 23223034Sdougm for (node = ((xmlNodePtr)optionset)->next; node != NULL; 23234327Sdougm node = node->next) { 23243034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) { 23253034Sdougm break; 23263034Sdougm } 23273034Sdougm } 23283034Sdougm return ((sa_optionset_t)node); 23293034Sdougm } 23303034Sdougm 23313034Sdougm /* 23323034Sdougm * sa_get_security(group, sectype, proto) 23333034Sdougm * 23343034Sdougm * Return the security optionset. The internal name is a hold over 23353034Sdougm * from the implementation and will be changed before the API is 23363034Sdougm * finalized. This is really a named optionset that can be negotiated 23373034Sdougm * as a group of properties (like NFS security options). 23383034Sdougm */ 23393034Sdougm 23403034Sdougm sa_security_t 23413034Sdougm sa_get_security(sa_group_t group, char *sectype, char *proto) 23423034Sdougm { 23433034Sdougm xmlNodePtr node; 23443034Sdougm xmlChar *value = NULL; 23453034Sdougm 23463034Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 23474327Sdougm node = node->next) { 23484327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) { 23494327Sdougm if (proto != NULL) { 23504327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 23514327Sdougm if (value == NULL || 23524327Sdougm (value != NULL && 23534327Sdougm xmlStrcmp(value, (xmlChar *)proto) != 0)) { 23544327Sdougm /* it doesn't match so continue */ 23554327Sdougm xmlFree(value); 23564327Sdougm value = NULL; 23574327Sdougm continue; 23584327Sdougm } 23594327Sdougm } 23604327Sdougm if (value != NULL) { 23614327Sdougm xmlFree(value); 23624327Sdougm value = NULL; 23634327Sdougm } 23644327Sdougm /* potential match */ 23654327Sdougm if (sectype != NULL) { 23664327Sdougm value = xmlGetProp(node, (xmlChar *)"sectype"); 23674327Sdougm if (value != NULL && 23684327Sdougm xmlStrcmp(value, (xmlChar *)sectype) == 0) { 23694327Sdougm break; 23704327Sdougm } 23714327Sdougm } else { 23724327Sdougm break; 23734327Sdougm } 23743034Sdougm } 23753034Sdougm if (value != NULL) { 23764327Sdougm xmlFree(value); 23774327Sdougm value = NULL; 23783034Sdougm } 23793034Sdougm } 23803034Sdougm if (value != NULL) 23814327Sdougm xmlFree(value); 23823034Sdougm return ((sa_security_t)node); 23833034Sdougm } 23843034Sdougm 23853034Sdougm /* 23863034Sdougm * sa_get_next_security(security) 23873034Sdougm * 23883034Sdougm * Get the next security optionset if one exists. 23893034Sdougm */ 23903034Sdougm 23913034Sdougm sa_security_t 23923034Sdougm sa_get_next_security(sa_security_t security) 23933034Sdougm { 23943034Sdougm xmlNodePtr node; 23953034Sdougm 23963034Sdougm for (node = ((xmlNodePtr)security)->next; node != NULL; 23974327Sdougm node = node->next) { 23983034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) { 23993034Sdougm break; 24003034Sdougm } 24013034Sdougm } 24023034Sdougm return ((sa_security_t)node); 24033034Sdougm } 24043034Sdougm 24053034Sdougm /* 24063034Sdougm * sa_get_property(optionset, prop) 24073034Sdougm * 24083034Sdougm * Get the property object with the name specified in prop from the 24093034Sdougm * optionset. 24103034Sdougm */ 24113034Sdougm 24123034Sdougm sa_property_t 24133034Sdougm sa_get_property(sa_optionset_t optionset, char *prop) 24143034Sdougm { 24153034Sdougm xmlNodePtr node = (xmlNodePtr)optionset; 24163034Sdougm xmlChar *value = NULL; 24173034Sdougm 24183034Sdougm if (optionset == NULL) 24194327Sdougm return (NULL); 24203034Sdougm 24213034Sdougm for (node = node->children; node != NULL; 24224327Sdougm node = node->next) { 24234327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 24244327Sdougm if (prop == NULL) 24254327Sdougm break; 24264327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 24274327Sdougm if (value != NULL && 24284327Sdougm xmlStrcmp(value, (xmlChar *)prop) == 0) { 24294327Sdougm break; 24304327Sdougm } 24314327Sdougm if (value != NULL) { 24324327Sdougm xmlFree(value); 24334327Sdougm value = NULL; 24344327Sdougm } 24353034Sdougm } 24363034Sdougm } 24373034Sdougm if (value != NULL) 24383034Sdougm xmlFree(value); 24393034Sdougm if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"option") != 0) { 24404327Sdougm /* 24414327Sdougm * avoid a non option node -- it is possible to be a 24424327Sdougm * text node 24434327Sdougm */ 24444327Sdougm node = NULL; 24453034Sdougm } 24463034Sdougm return ((sa_property_t)node); 24473034Sdougm } 24483034Sdougm 24493034Sdougm /* 24503034Sdougm * sa_get_next_property(property) 24513034Sdougm * 24523034Sdougm * Get the next property following the specified property. NULL if 24533034Sdougm * this was the last. 24543034Sdougm */ 24553034Sdougm 24563034Sdougm sa_property_t 24573034Sdougm sa_get_next_property(sa_property_t property) 24583034Sdougm { 24593034Sdougm xmlNodePtr node; 24603034Sdougm 24613034Sdougm for (node = ((xmlNodePtr)property)->next; node != NULL; 24624327Sdougm node = node->next) { 24633034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 24643034Sdougm break; 24653034Sdougm } 24663034Sdougm } 24673034Sdougm return ((sa_property_t)node); 24683034Sdougm } 24693034Sdougm 24703034Sdougm /* 24713034Sdougm * sa_set_share_description(share, content) 24723034Sdougm * 24733034Sdougm * Set the description of share to content. 24743034Sdougm */ 24753034Sdougm 24763034Sdougm int 24773034Sdougm sa_set_share_description(sa_share_t share, char *content) 24783034Sdougm { 24793034Sdougm xmlNodePtr node; 24803034Sdougm sa_group_t group; 24813034Sdougm int ret = SA_OK; 24823034Sdougm 24833034Sdougm for (node = ((xmlNodePtr)share)->children; node != NULL; 24844327Sdougm node = node->next) { 24853034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 24863034Sdougm break; 24873034Sdougm } 24883034Sdougm } 24893034Sdougm /* no existing description but want to add */ 24903034Sdougm if (node == NULL && content != NULL) { 24913034Sdougm /* add a description */ 24924327Sdougm node = _sa_set_share_description(share, content); 24933034Sdougm } else if (node != NULL && content != NULL) { 24943034Sdougm /* update a description */ 24953034Sdougm xmlNodeSetContent(node, (xmlChar *)content); 24963034Sdougm } else if (node != NULL && content == NULL) { 24973034Sdougm /* remove an existing description */ 24983034Sdougm xmlUnlinkNode(node); 24993034Sdougm xmlFreeNode(node); 25003034Sdougm } 25015331Samw group = sa_get_parent_group(share); 25025331Samw if (group != NULL && sa_is_persistent(share)) { 25034327Sdougm sa_handle_impl_t impl_handle; 25044327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 25054327Sdougm if (impl_handle != NULL) { 25064327Sdougm ret = sa_commit_share(impl_handle->scfhandle, group, 25074327Sdougm share); 25084327Sdougm } else { 25094327Sdougm ret = SA_SYSTEM_ERR; 25104327Sdougm } 25113910Sdougm } 25123034Sdougm return (ret); 25133034Sdougm } 25143034Sdougm 25153034Sdougm /* 25163034Sdougm * fixproblemchars(string) 25173034Sdougm * 25183034Sdougm * don't want any newline or tab characters in the text since these 25193034Sdougm * could break display of data and legacy file formats. 25203034Sdougm */ 25213034Sdougm static void 25223034Sdougm fixproblemchars(char *str) 25233034Sdougm { 25243034Sdougm int c; 25253034Sdougm for (c = *str; c != '\0'; c = *++str) { 25264327Sdougm if (c == '\t' || c == '\n') 25274327Sdougm *str = ' '; 25284327Sdougm else if (c == '"') 25294327Sdougm *str = '\''; 25303034Sdougm } 25313034Sdougm } 25323034Sdougm 25333034Sdougm /* 25343034Sdougm * sa_get_share_description(share) 25353034Sdougm * 25363034Sdougm * Return the description text for the specified share if it 25373034Sdougm * exists. NULL if no description exists. 25383034Sdougm */ 25393034Sdougm 25403034Sdougm char * 25413034Sdougm sa_get_share_description(sa_share_t share) 25423034Sdougm { 25433034Sdougm xmlChar *description = NULL; 25443034Sdougm xmlNodePtr node; 25453034Sdougm 25463034Sdougm for (node = ((xmlNodePtr)share)->children; node != NULL; 25474327Sdougm node = node->next) { 25484327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 25494327Sdougm break; 25504327Sdougm } 25513034Sdougm } 25523034Sdougm if (node != NULL) { 25535331Samw description = xmlNodeGetContent(node); 25544327Sdougm fixproblemchars((char *)description); 25553034Sdougm } 25563034Sdougm return ((char *)description); 25573034Sdougm } 25583034Sdougm 25593034Sdougm /* 25603034Sdougm * sa_free(share_description(description) 25613034Sdougm * 25623034Sdougm * Free the description string. 25633034Sdougm */ 25643034Sdougm 25653034Sdougm void 25663034Sdougm sa_free_share_description(char *description) 25673034Sdougm { 25683034Sdougm xmlFree((xmlChar *)description); 25693034Sdougm } 25703034Sdougm 25713034Sdougm /* 25723034Sdougm * sa_create_optionset(group, proto) 25733034Sdougm * 25743034Sdougm * Create an optionset for the specified protocol in the specied 25753034Sdougm * group. This is manifested as a property group within SMF. 25763034Sdougm */ 25773034Sdougm 25783034Sdougm sa_optionset_t 25793034Sdougm sa_create_optionset(sa_group_t group, char *proto) 25803034Sdougm { 25813034Sdougm sa_optionset_t optionset; 25823034Sdougm sa_group_t parent = group; 25835331Samw sa_share_t share = NULL; 25845331Samw int err = SA_OK; 25855331Samw char *id = NULL; 25863034Sdougm 25873034Sdougm optionset = sa_get_optionset(group, proto); 25883034Sdougm if (optionset != NULL) { 25893034Sdougm /* can't have a duplicate protocol */ 25904327Sdougm optionset = NULL; 25913034Sdougm } else { 25925331Samw /* 25935331Samw * Account for resource names being slightly 25945331Samw * different. 25955331Samw */ 25965331Samw if (sa_is_share(group)) { 25975331Samw /* 25985331Samw * Transient shares do not have an "id" so not an 25995331Samw * error to not find one. 26005331Samw */ 26015331Samw id = sa_get_share_attr((sa_share_t)group, "id"); 26025331Samw } else if (sa_is_resource(group)) { 26035331Samw share = sa_get_resource_parent( 26045331Samw (sa_resource_t)group); 26055331Samw id = sa_get_resource_attr(share, "id"); 26065331Samw 26075331Samw /* id can be NULL if the group is transient (ZFS) */ 26085331Samw if (id == NULL && sa_is_persistent(group)) 26095331Samw err = SA_NO_MEMORY; 26105331Samw } 26115331Samw if (err == SA_NO_MEMORY) { 26125331Samw /* 26135331Samw * Couldn't get the id for the share or 26145331Samw * resource. While this could be a 26155331Samw * configuration issue, it is most likely an 26165331Samw * out of memory. In any case, fail the create. 26175331Samw */ 26185331Samw return (NULL); 26195331Samw } 26205331Samw 26214327Sdougm optionset = (sa_optionset_t)xmlNewChild((xmlNodePtr)group, 26224327Sdougm NULL, (xmlChar *)"optionset", NULL); 26233034Sdougm /* 26243034Sdougm * only put to repository if on a group and we were 26253034Sdougm * able to create an optionset. 26263034Sdougm */ 26274327Sdougm if (optionset != NULL) { 26284327Sdougm char oname[SA_STRSIZE]; 26294327Sdougm char *groupname; 26305331Samw 26315331Samw /* 26325331Samw * Need to get parent group in all cases, but also get 26335331Samw * the share if this is a resource. 26345331Samw */ 26355331Samw if (sa_is_share(group)) { 26364327Sdougm parent = sa_get_parent_group((sa_share_t)group); 26375331Samw } else if (sa_is_resource(group)) { 26385331Samw share = sa_get_resource_parent( 26395331Samw (sa_resource_t)group); 26405331Samw parent = sa_get_parent_group(share); 26415331Samw } 26424327Sdougm 26434327Sdougm sa_set_optionset_attr(optionset, "type", proto); 26443034Sdougm 26454327Sdougm (void) sa_optionset_name(optionset, oname, 26464327Sdougm sizeof (oname), id); 26474327Sdougm groupname = sa_get_group_attr(parent, "name"); 26485331Samw if (groupname != NULL && sa_is_persistent(group)) { 26494327Sdougm sa_handle_impl_t impl_handle; 26505331Samw impl_handle = 26515331Samw (sa_handle_impl_t)sa_find_group_handle( 26525331Samw group); 26534327Sdougm assert(impl_handle != NULL); 26544327Sdougm if (impl_handle != NULL) { 26554327Sdougm (void) sa_get_instance( 26565331Samw impl_handle->scfhandle, groupname); 26574327Sdougm (void) sa_create_pgroup( 26584327Sdougm impl_handle->scfhandle, oname); 26594327Sdougm } 26604327Sdougm } 26614327Sdougm if (groupname != NULL) 26624327Sdougm sa_free_attr_string(groupname); 26633034Sdougm } 26643034Sdougm } 26655331Samw 26665331Samw if (id != NULL) 26675331Samw sa_free_attr_string(id); 26683034Sdougm return (optionset); 26693034Sdougm } 26703034Sdougm 26713034Sdougm /* 26723034Sdougm * sa_get_property_parent(property) 26733034Sdougm * 26743034Sdougm * Given a property, return the object it is a property of. This will 26753034Sdougm * be an optionset of some type. 26763034Sdougm */ 26773034Sdougm 26783034Sdougm static sa_optionset_t 26793034Sdougm sa_get_property_parent(sa_property_t property) 26803034Sdougm { 26813034Sdougm xmlNodePtr node = NULL; 26823034Sdougm 26834327Sdougm if (property != NULL) 26844327Sdougm node = ((xmlNodePtr)property)->parent; 26853034Sdougm return ((sa_optionset_t)node); 26863034Sdougm } 26873034Sdougm 26883034Sdougm /* 26893034Sdougm * sa_get_optionset_parent(optionset) 26903034Sdougm * 26913034Sdougm * Return the parent of the specified optionset. This could be a group 26923034Sdougm * or a share. 26933034Sdougm */ 26943034Sdougm 26953034Sdougm static sa_group_t 26963034Sdougm sa_get_optionset_parent(sa_optionset_t optionset) 26973034Sdougm { 26983034Sdougm xmlNodePtr node = NULL; 26993034Sdougm 27004327Sdougm if (optionset != NULL) 27014327Sdougm node = ((xmlNodePtr)optionset)->parent; 27023034Sdougm return ((sa_group_t)node); 27033034Sdougm } 27043034Sdougm 27053034Sdougm /* 27063034Sdougm * zfs_needs_update(share) 27073034Sdougm * 27083034Sdougm * In order to avoid making multiple updates to a ZFS share when 27093034Sdougm * setting properties, the share attribute "changed" will be set to 27105331Samw * true when a property is added or modified. When done adding 27113034Sdougm * properties, we can then detect that an update is needed. We then 27123034Sdougm * clear the state here to detect additional changes. 27133034Sdougm */ 27143034Sdougm 27153034Sdougm static int 27163034Sdougm zfs_needs_update(sa_share_t share) 27173034Sdougm { 27183034Sdougm char *attr; 27193034Sdougm int result = 0; 27203034Sdougm 27213034Sdougm attr = sa_get_share_attr(share, "changed"); 27223034Sdougm if (attr != NULL) { 27234327Sdougm sa_free_attr_string(attr); 27243034Sdougm result = 1; 27253034Sdougm } 27263034Sdougm set_node_attr((void *)share, "changed", NULL); 27273034Sdougm return (result); 27283034Sdougm } 27293034Sdougm 27303034Sdougm /* 27313034Sdougm * zfs_set_update(share) 27323034Sdougm * 27333034Sdougm * Set the changed attribute of the share to true. 27343034Sdougm */ 27353034Sdougm 27363034Sdougm static void 27373034Sdougm zfs_set_update(sa_share_t share) 27383034Sdougm { 27393034Sdougm set_node_attr((void *)share, "changed", "true"); 27403034Sdougm } 27413034Sdougm 27423034Sdougm /* 27433034Sdougm * sa_commit_properties(optionset, clear) 27443034Sdougm * 27453034Sdougm * Check if SMF or ZFS config and either update or abort the pending 27463034Sdougm * changes. 27473034Sdougm */ 27483034Sdougm 27493034Sdougm int 27503034Sdougm sa_commit_properties(sa_optionset_t optionset, int clear) 27513034Sdougm { 27523034Sdougm sa_group_t group; 27533034Sdougm sa_group_t parent; 27543034Sdougm int zfs = 0; 27553034Sdougm int needsupdate = 0; 27563034Sdougm int ret = SA_OK; 27573910Sdougm sa_handle_impl_t impl_handle; 27583034Sdougm 27593034Sdougm group = sa_get_optionset_parent(optionset); 27603034Sdougm if (group != NULL && (sa_is_share(group) || is_zfs_group(group))) { 27614327Sdougm /* only update ZFS if on a share */ 27624327Sdougm parent = sa_get_parent_group(group); 27634327Sdougm zfs++; 27644327Sdougm if (parent != NULL && is_zfs_group(parent)) 27654327Sdougm needsupdate = zfs_needs_update(group); 27664327Sdougm else 27674327Sdougm zfs = 0; 27683034Sdougm } 27693034Sdougm if (zfs) { 27704327Sdougm if (!clear && needsupdate) 27714327Sdougm ret = sa_zfs_update((sa_share_t)group); 27723034Sdougm } else { 27734327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 27744327Sdougm if (impl_handle != NULL) { 27754327Sdougm if (clear) { 27764327Sdougm (void) sa_abort_transaction( 27774327Sdougm impl_handle->scfhandle); 27784327Sdougm } else { 27794327Sdougm ret = sa_end_transaction( 27805951Sdougm impl_handle->scfhandle, impl_handle); 27814327Sdougm } 27824327Sdougm } else { 27834327Sdougm ret = SA_SYSTEM_ERR; 27844327Sdougm } 27853034Sdougm } 27863034Sdougm return (ret); 27873034Sdougm } 27883034Sdougm 27893034Sdougm /* 27903034Sdougm * sa_destroy_optionset(optionset) 27913034Sdougm * 27925331Samw * Remove the optionset from its group. Update the repository to 27933034Sdougm * reflect this change. 27943034Sdougm */ 27953034Sdougm 27963034Sdougm int 27973034Sdougm sa_destroy_optionset(sa_optionset_t optionset) 27983034Sdougm { 27994327Sdougm char name[SA_STRSIZE]; 28003034Sdougm int len; 28013034Sdougm int ret; 28023034Sdougm char *id = NULL; 28033034Sdougm sa_group_t group; 28043034Sdougm int ispersist = 1; 28053034Sdougm 28063034Sdougm /* now delete the prop group */ 28073034Sdougm group = sa_get_optionset_parent(optionset); 28085331Samw if (group != NULL) { 28095331Samw if (sa_is_resource(group)) { 28105331Samw sa_resource_t resource = group; 28115331Samw sa_share_t share = sa_get_resource_parent(resource); 28125331Samw group = sa_get_parent_group(share); 28135331Samw id = sa_get_share_attr(share, "id"); 28145331Samw } else if (sa_is_share(group)) { 28155331Samw id = sa_get_share_attr((sa_share_t)group, "id"); 28165331Samw } 28175331Samw ispersist = sa_is_persistent(group); 28183034Sdougm } 28193034Sdougm if (ispersist) { 28204327Sdougm sa_handle_impl_t impl_handle; 28214327Sdougm len = sa_optionset_name(optionset, name, sizeof (name), id); 28224327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 28234327Sdougm if (impl_handle != NULL) { 28244327Sdougm if (len > 0) { 28254327Sdougm ret = sa_delete_pgroup(impl_handle->scfhandle, 28264327Sdougm name); 28274327Sdougm } 28284327Sdougm } else { 28294327Sdougm ret = SA_SYSTEM_ERR; 28303910Sdougm } 28313034Sdougm } 28323034Sdougm xmlUnlinkNode((xmlNodePtr)optionset); 28333034Sdougm xmlFreeNode((xmlNodePtr)optionset); 28343034Sdougm if (id != NULL) 28354327Sdougm sa_free_attr_string(id); 28363034Sdougm return (ret); 28373034Sdougm } 28383034Sdougm 28393034Sdougm /* private to the implementation */ 28403034Sdougm int 28413034Sdougm _sa_remove_optionset(sa_optionset_t optionset) 28423034Sdougm { 28433034Sdougm int ret = SA_OK; 28443034Sdougm 28453034Sdougm xmlUnlinkNode((xmlNodePtr)optionset); 28463034Sdougm xmlFreeNode((xmlNodePtr)optionset); 28473034Sdougm return (ret); 28483034Sdougm } 28493034Sdougm 28503034Sdougm /* 28513034Sdougm * sa_create_security(group, sectype, proto) 28523034Sdougm * 28533034Sdougm * Create a security optionset (one that has a type name and a 28543034Sdougm * proto). Security is left over from a pure NFS implementation. The 28553034Sdougm * naming will change in the future when the API is released. 28563034Sdougm */ 28573034Sdougm sa_security_t 28583034Sdougm sa_create_security(sa_group_t group, char *sectype, char *proto) 28593034Sdougm { 28603034Sdougm sa_security_t security; 28613034Sdougm char *id = NULL; 28623034Sdougm sa_group_t parent; 28633034Sdougm char *groupname = NULL; 28643034Sdougm 28653034Sdougm if (group != NULL && sa_is_share(group)) { 28664327Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 28674327Sdougm parent = sa_get_parent_group(group); 28684327Sdougm if (parent != NULL) 28694327Sdougm groupname = sa_get_group_attr(parent, "name"); 28703034Sdougm } else if (group != NULL) { 28714327Sdougm groupname = sa_get_group_attr(group, "name"); 28723034Sdougm } 28733034Sdougm 28743034Sdougm security = sa_get_security(group, sectype, proto); 28753034Sdougm if (security != NULL) { 28763034Sdougm /* can't have a duplicate security option */ 28773034Sdougm security = NULL; 28783034Sdougm } else { 28793034Sdougm security = (sa_security_t)xmlNewChild((xmlNodePtr)group, 28804327Sdougm NULL, (xmlChar *)"security", NULL); 28813034Sdougm if (security != NULL) { 28824327Sdougm char oname[SA_STRSIZE]; 28833034Sdougm sa_set_security_attr(security, "type", proto); 28843034Sdougm 28853034Sdougm sa_set_security_attr(security, "sectype", sectype); 28863034Sdougm (void) sa_security_name(security, oname, 28874327Sdougm sizeof (oname), id); 28885331Samw if (groupname != NULL && sa_is_persistent(group)) { 28894327Sdougm sa_handle_impl_t impl_handle; 28904327Sdougm impl_handle = 28914327Sdougm (sa_handle_impl_t)sa_find_group_handle( 28924327Sdougm group); 28934327Sdougm if (impl_handle != NULL) { 28944327Sdougm (void) sa_get_instance( 28954327Sdougm impl_handle->scfhandle, groupname); 28964327Sdougm (void) sa_create_pgroup( 28974327Sdougm impl_handle->scfhandle, oname); 28984327Sdougm } 28993034Sdougm } 29003034Sdougm } 29013034Sdougm } 2902*11337SWilliam.Krier@Sun.COM if (id != NULL) 2903*11337SWilliam.Krier@Sun.COM sa_free_attr_string(id); 29043034Sdougm if (groupname != NULL) 29054327Sdougm sa_free_attr_string(groupname); 29063034Sdougm return (security); 29073034Sdougm } 29083034Sdougm 29093034Sdougm /* 29103034Sdougm * sa_destroy_security(security) 29113034Sdougm * 29123034Sdougm * Remove the specified optionset from the document and the 29133034Sdougm * configuration. 29143034Sdougm */ 29153034Sdougm 29163034Sdougm int 29173034Sdougm sa_destroy_security(sa_security_t security) 29183034Sdougm { 29194327Sdougm char name[SA_STRSIZE]; 29203034Sdougm int len; 29213034Sdougm int ret = SA_OK; 29223034Sdougm char *id = NULL; 29233034Sdougm sa_group_t group; 29243034Sdougm int iszfs = 0; 29253034Sdougm int ispersist = 1; 29263034Sdougm 29273034Sdougm group = sa_get_optionset_parent(security); 29283034Sdougm 29293034Sdougm if (group != NULL) 29304327Sdougm iszfs = sa_group_is_zfs(group); 29313034Sdougm 29323034Sdougm if (group != NULL && !iszfs) { 29334327Sdougm if (sa_is_share(group)) 29345331Samw ispersist = sa_is_persistent(group); 29354327Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 29363034Sdougm } 29373034Sdougm if (ispersist) { 29384327Sdougm len = sa_security_name(security, name, sizeof (name), id); 29394327Sdougm if (!iszfs && len > 0) { 29404327Sdougm sa_handle_impl_t impl_handle; 29414327Sdougm impl_handle = 29424327Sdougm (sa_handle_impl_t)sa_find_group_handle(group); 29434327Sdougm if (impl_handle != NULL) { 29444327Sdougm ret = sa_delete_pgroup(impl_handle->scfhandle, 29454327Sdougm name); 29464327Sdougm } else { 29474327Sdougm ret = SA_SYSTEM_ERR; 29484327Sdougm } 29493910Sdougm } 29503034Sdougm } 29513034Sdougm xmlUnlinkNode((xmlNodePtr)security); 29523034Sdougm xmlFreeNode((xmlNodePtr)security); 29534327Sdougm if (iszfs) 29544327Sdougm ret = sa_zfs_update(group); 29553034Sdougm if (id != NULL) 29564327Sdougm sa_free_attr_string(id); 29573034Sdougm return (ret); 29583034Sdougm } 29593034Sdougm 29603034Sdougm /* 29613034Sdougm * sa_get_security_attr(optionset, tag) 29623034Sdougm * 29633034Sdougm * Return the specified attribute value from the optionset. 29643034Sdougm */ 29653034Sdougm 29663034Sdougm char * 29673034Sdougm sa_get_security_attr(sa_property_t optionset, char *tag) 29683034Sdougm { 29693034Sdougm return (get_node_attr((void *)optionset, tag)); 29703034Sdougm 29713034Sdougm } 29723034Sdougm 29733034Sdougm /* 29743034Sdougm * sa_set_security_attr(optionset, tag, value) 29753034Sdougm * 29763034Sdougm * Set the optioset attribute specied by tag to the specified value. 29773034Sdougm */ 29783034Sdougm 29793034Sdougm void 29803034Sdougm sa_set_security_attr(sa_group_t optionset, char *tag, char *value) 29813034Sdougm { 29823034Sdougm set_node_attr((void *)optionset, tag, value); 29833034Sdougm } 29843034Sdougm 29853034Sdougm /* 29863034Sdougm * is_nodetype(node, type) 29873034Sdougm * 29883034Sdougm * Check to see if node is of the type specified. 29893034Sdougm */ 29903034Sdougm 29913034Sdougm static int 29923034Sdougm is_nodetype(void *node, char *type) 29933034Sdougm { 29943034Sdougm return (strcmp((char *)((xmlNodePtr)node)->name, type) == 0); 29953034Sdougm } 29963034Sdougm 29974327Sdougm /* 29984327Sdougm * add_or_update() 29994327Sdougm * 30004327Sdougm * Add or update a property. Pulled out of sa_set_prop_by_prop for 30014327Sdougm * readability. 30024327Sdougm */ 30034327Sdougm static int 30044327Sdougm add_or_update(scfutilhandle_t *scf_handle, int type, scf_value_t *value, 30054327Sdougm scf_transaction_entry_t *entry, char *name, char *valstr) 30064327Sdougm { 30074327Sdougm int ret = SA_SYSTEM_ERR; 30084327Sdougm 30094327Sdougm if (value != NULL) { 30104327Sdougm if (type == SA_PROP_OP_ADD) 30114327Sdougm ret = scf_transaction_property_new(scf_handle->trans, 30124327Sdougm entry, name, SCF_TYPE_ASTRING); 30134327Sdougm else 30144327Sdougm ret = scf_transaction_property_change(scf_handle->trans, 30154327Sdougm entry, name, SCF_TYPE_ASTRING); 30164327Sdougm if (ret == 0) { 30174327Sdougm ret = scf_value_set_astring(value, valstr); 30184327Sdougm if (ret == 0) 30194327Sdougm ret = scf_entry_add_value(entry, value); 30204327Sdougm if (ret == 0) 30214327Sdougm return (ret); 30224327Sdougm scf_value_destroy(value); 30234327Sdougm } else { 30244327Sdougm scf_entry_destroy(entry); 30254327Sdougm } 30264327Sdougm } 30274327Sdougm return (SA_SYSTEM_ERR); 30284327Sdougm } 30294327Sdougm 30303034Sdougm /* 30313034Sdougm * sa_set_prop_by_prop(optionset, group, prop, type) 30323034Sdougm * 30333034Sdougm * Add/remove/update the specified property prop into the optionset or 30343034Sdougm * share. If a share, sort out which property group based on GUID. In 30353034Sdougm * all cases, the appropriate transaction is set (or ZFS share is 30363034Sdougm * marked as needing an update) 30373034Sdougm */ 30383034Sdougm 30393034Sdougm static int 30403034Sdougm sa_set_prop_by_prop(sa_optionset_t optionset, sa_group_t group, 30413034Sdougm sa_property_t prop, int type) 30423034Sdougm { 30433034Sdougm char *name; 30443034Sdougm char *valstr; 30453034Sdougm int ret = SA_OK; 30463034Sdougm scf_transaction_entry_t *entry; 30473034Sdougm scf_value_t *value; 30483034Sdougm int opttype; /* 1 == optionset, 0 == security */ 30493034Sdougm char *id = NULL; 30503034Sdougm int iszfs = 0; 30513034Sdougm sa_group_t parent = NULL; 30525331Samw sa_share_t share = NULL; 30533910Sdougm sa_handle_impl_t impl_handle; 30543910Sdougm scfutilhandle_t *scf_handle; 30553034Sdougm 30565331Samw if (!sa_is_persistent(group)) { 30573034Sdougm /* 30583034Sdougm * if the group/share is not persistent we don't need 30593034Sdougm * to do anything here 30603034Sdougm */ 30614327Sdougm return (SA_OK); 30623034Sdougm } 30633910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 30644327Sdougm if (impl_handle == NULL || impl_handle->scfhandle == NULL) 30654327Sdougm return (SA_SYSTEM_ERR); 30663910Sdougm scf_handle = impl_handle->scfhandle; 30673034Sdougm name = sa_get_property_attr(prop, "type"); 30683034Sdougm valstr = sa_get_property_attr(prop, "value"); 30693034Sdougm entry = scf_entry_create(scf_handle->handle); 30703034Sdougm opttype = is_nodetype((void *)optionset, "optionset"); 30713034Sdougm 30725331Samw /* 30735331Samw * Check for share vs. resource since they need slightly 30745331Samw * different treatment given the hierarchy. 30755331Samw */ 30763034Sdougm if (valstr != NULL && entry != NULL) { 30774327Sdougm if (sa_is_share(group)) { 30784327Sdougm parent = sa_get_parent_group(group); 30795331Samw share = (sa_share_t)group; 30804327Sdougm if (parent != NULL) 30814327Sdougm iszfs = is_zfs_group(parent); 30825331Samw } else if (sa_is_resource(group)) { 30835331Samw share = sa_get_parent_group(group); 30845331Samw if (share != NULL) 30855331Samw parent = sa_get_parent_group(share); 30864327Sdougm } else { 30874327Sdougm iszfs = is_zfs_group(group); 30883034Sdougm } 30894327Sdougm if (!iszfs) { 30904327Sdougm if (scf_handle->trans == NULL) { 30914327Sdougm char oname[SA_STRSIZE]; 30924327Sdougm char *groupname = NULL; 30935331Samw if (share != NULL) { 30945331Samw if (parent != NULL) 30954327Sdougm groupname = 30964327Sdougm sa_get_group_attr(parent, 30974327Sdougm "name"); 30985331Samw id = sa_get_share_attr( 30995331Samw (sa_share_t)share, "id"); 31004327Sdougm } else { 31014327Sdougm groupname = sa_get_group_attr(group, 31024327Sdougm "name"); 31034327Sdougm } 31044327Sdougm if (groupname != NULL) { 31054327Sdougm ret = sa_get_instance(scf_handle, 31064327Sdougm groupname); 31074327Sdougm sa_free_attr_string(groupname); 31084327Sdougm } 31094327Sdougm if (opttype) 31104327Sdougm (void) sa_optionset_name(optionset, 31114327Sdougm oname, sizeof (oname), id); 31124327Sdougm else 31134327Sdougm (void) sa_security_name(optionset, 31144327Sdougm oname, sizeof (oname), id); 31154327Sdougm ret = sa_start_transaction(scf_handle, oname); 3116*11337SWilliam.Krier@Sun.COM if (id != NULL) 3117*11337SWilliam.Krier@Sun.COM sa_free_attr_string(id); 31183910Sdougm } 31194327Sdougm if (ret == SA_OK) { 31204327Sdougm switch (type) { 31214327Sdougm case SA_PROP_OP_REMOVE: 31224327Sdougm ret = scf_transaction_property_delete( 31234327Sdougm scf_handle->trans, entry, name); 31244327Sdougm break; 31254327Sdougm case SA_PROP_OP_ADD: 31264327Sdougm case SA_PROP_OP_UPDATE: 31274327Sdougm value = scf_value_create( 31284327Sdougm scf_handle->handle); 31294327Sdougm ret = add_or_update(scf_handle, type, 31304327Sdougm value, entry, name, valstr); 31314327Sdougm break; 31323034Sdougm } 31333034Sdougm } 31344327Sdougm } else { 31354327Sdougm /* 31364327Sdougm * ZFS update. The calling function would have updated 31374327Sdougm * the internal XML structure. Just need to flag it as 31384327Sdougm * changed for ZFS. 31394327Sdougm */ 31404327Sdougm zfs_set_update((sa_share_t)group); 31414327Sdougm } 31423034Sdougm } 31433034Sdougm 31443034Sdougm if (name != NULL) 31454327Sdougm sa_free_attr_string(name); 31463034Sdougm if (valstr != NULL) 31474327Sdougm sa_free_attr_string(valstr); 31483034Sdougm else if (entry != NULL) 31494327Sdougm scf_entry_destroy(entry); 31503034Sdougm 31513034Sdougm if (ret == -1) 31524327Sdougm ret = SA_SYSTEM_ERR; 31533034Sdougm 31543034Sdougm return (ret); 31553034Sdougm } 31563034Sdougm 31573034Sdougm /* 31586007Sthurlow * sa_create_section(name, value) 31596007Sthurlow * 31606007Sthurlow * Create a new section with the specified name and extra data. 31616007Sthurlow */ 31626007Sthurlow 31636007Sthurlow sa_property_t 31646007Sthurlow sa_create_section(char *name, char *extra) 31656007Sthurlow { 31666007Sthurlow xmlNodePtr node; 31676007Sthurlow 31686007Sthurlow node = xmlNewNode(NULL, (xmlChar *)"section"); 31696007Sthurlow if (node != NULL) { 31706007Sthurlow if (name != NULL) 31716007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 31726007Sthurlow (xmlChar *)name); 31736007Sthurlow if (extra != NULL) 31746007Sthurlow (void) xmlSetProp(node, (xmlChar *)"extra", 31756007Sthurlow (xmlChar *)extra); 31766007Sthurlow } 31776007Sthurlow return ((sa_property_t)node); 31786007Sthurlow } 31796007Sthurlow 31806007Sthurlow void 31816007Sthurlow sa_set_section_attr(sa_property_t sect, char *name, char *value) 31826007Sthurlow { 31836007Sthurlow (void) xmlSetProp(sect, (xmlChar *)name, (xmlChar *)value); 31846007Sthurlow } 31856007Sthurlow 31866007Sthurlow /* 31876007Sthurlow * sa_create_property(section, name, value) 31883034Sdougm * 31893034Sdougm * Create a new property with the specified name and value. 31903034Sdougm */ 31913034Sdougm 31923034Sdougm sa_property_t 31933034Sdougm sa_create_property(char *name, char *value) 31943034Sdougm { 31953034Sdougm xmlNodePtr node; 31963034Sdougm 31973034Sdougm node = xmlNewNode(NULL, (xmlChar *)"option"); 31983034Sdougm if (node != NULL) { 31996007Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", (xmlChar *)name); 32006007Sthurlow (void) xmlSetProp(node, (xmlChar *)"value", (xmlChar *)value); 32013034Sdougm } 32023034Sdougm return ((sa_property_t)node); 32033034Sdougm } 32043034Sdougm 32053034Sdougm /* 32063034Sdougm * sa_add_property(object, property) 32073034Sdougm * 32083034Sdougm * Add the specified property to the object. Issue the appropriate 32093034Sdougm * transaction or mark a ZFS object as needing an update. 32103034Sdougm */ 32113034Sdougm 32123034Sdougm int 32133034Sdougm sa_add_property(void *object, sa_property_t property) 32143034Sdougm { 32153034Sdougm int ret = SA_OK; 32163034Sdougm sa_group_t parent; 32173034Sdougm sa_group_t group; 32183034Sdougm char *proto; 32196214Sdougm 32203034Sdougm if (property != NULL) { 32216271Sdougm sa_handle_t handle; 32226214Sdougm handle = sa_find_group_handle((sa_group_t)object); 32236271Sdougm /* It is legitimate to not find a handle */ 32246214Sdougm proto = sa_get_optionset_attr(object, "type"); 32256214Sdougm if ((ret = sa_valid_property(handle, object, proto, 32266214Sdougm property)) == SA_OK) { 32274327Sdougm property = (sa_property_t)xmlAddChild( 32284327Sdougm (xmlNodePtr)object, (xmlNodePtr)property); 32294327Sdougm } else { 32304327Sdougm if (proto != NULL) 32314327Sdougm sa_free_attr_string(proto); 32324327Sdougm return (ret); 32334327Sdougm } 32346214Sdougm if (proto != NULL) 32356214Sdougm sa_free_attr_string(proto); 32363034Sdougm } 32373034Sdougm 32383034Sdougm 32393034Sdougm parent = sa_get_parent_group(object); 32405331Samw if (!sa_is_persistent(parent)) 32414327Sdougm return (ret); 32425331Samw 32435331Samw if (sa_is_resource(parent)) { 32445331Samw /* 32455331Samw * Resources are children of share. Need to go up two 32465331Samw * levels to find the group but the parent needs to be 32475331Samw * the share at this point in order to get the "id". 32485331Samw */ 32495331Samw parent = sa_get_parent_group(parent); 32505331Samw group = sa_get_parent_group(parent); 32515331Samw } else if (sa_is_share(parent)) { 32525331Samw group = sa_get_parent_group(parent); 32535331Samw } else { 32545331Samw group = parent; 32553034Sdougm } 32563034Sdougm 32574327Sdougm if (property == NULL) { 32584327Sdougm ret = SA_NO_MEMORY; 32594327Sdougm } else { 32604327Sdougm char oname[SA_STRSIZE]; 32613034Sdougm 32624327Sdougm if (!is_zfs_group(group)) { 32634327Sdougm char *id = NULL; 32644327Sdougm sa_handle_impl_t impl_handle; 32654327Sdougm scfutilhandle_t *scf_handle; 32663910Sdougm 32674327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle( 32684327Sdougm group); 32694327Sdougm if (impl_handle == NULL || 32704327Sdougm impl_handle->scfhandle == NULL) 32714327Sdougm ret = SA_SYSTEM_ERR; 32724327Sdougm if (ret == SA_OK) { 32734327Sdougm scf_handle = impl_handle->scfhandle; 32744327Sdougm if (sa_is_share((sa_group_t)parent)) { 32754327Sdougm id = sa_get_share_attr( 32764327Sdougm (sa_share_t)parent, "id"); 32774327Sdougm } 32784327Sdougm if (scf_handle->trans == NULL) { 32794327Sdougm if (is_nodetype(object, "optionset")) { 32804327Sdougm (void) sa_optionset_name( 32814327Sdougm (sa_optionset_t)object, 32824327Sdougm oname, sizeof (oname), id); 32834327Sdougm } else { 32844327Sdougm (void) sa_security_name( 32854327Sdougm (sa_optionset_t)object, 32864327Sdougm oname, sizeof (oname), id); 32874327Sdougm } 32884327Sdougm ret = sa_start_transaction(scf_handle, 32894327Sdougm oname); 32904327Sdougm } 32914327Sdougm if (ret == SA_OK) { 32924327Sdougm char *name; 32934327Sdougm char *value; 32944327Sdougm name = sa_get_property_attr(property, 32954327Sdougm "type"); 32964327Sdougm value = sa_get_property_attr(property, 32974327Sdougm "value"); 32984327Sdougm if (name != NULL && value != NULL) { 32994327Sdougm if (scf_handle->scf_state == 33004327Sdougm SCH_STATE_INIT) { 33014327Sdougm ret = sa_set_property( 33024327Sdougm scf_handle, name, 33034327Sdougm value); 33044327Sdougm } 33054327Sdougm } else { 33064327Sdougm ret = SA_CONFIG_ERR; 33074327Sdougm } 33084327Sdougm if (name != NULL) 33094327Sdougm sa_free_attr_string( 33104327Sdougm name); 33114327Sdougm if (value != NULL) 33124327Sdougm sa_free_attr_string(value); 33134327Sdougm } 33144327Sdougm if (id != NULL) 33154327Sdougm sa_free_attr_string(id); 33164327Sdougm } 33174327Sdougm } else { 33184327Sdougm /* 33194327Sdougm * ZFS is a special case. We do want 33204327Sdougm * to allow editing property/security 33214327Sdougm * lists since we can have a better 33224327Sdougm * syntax and we also want to keep 33234327Sdougm * things consistent when possible. 33244327Sdougm * 33254327Sdougm * Right now, we defer until the 33264327Sdougm * sa_commit_properties so we can get 33274327Sdougm * them all at once. We do need to 33284327Sdougm * mark the share as "changed" 33294327Sdougm */ 33304327Sdougm zfs_set_update((sa_share_t)parent); 33313034Sdougm } 33323034Sdougm } 33333034Sdougm return (ret); 33343034Sdougm } 33353034Sdougm 33363034Sdougm /* 33373034Sdougm * sa_remove_property(property) 33383034Sdougm * 33393034Sdougm * Remove the specied property from its containing object. Update the 33403034Sdougm * repository as appropriate. 33413034Sdougm */ 33423034Sdougm 33433034Sdougm int 33443034Sdougm sa_remove_property(sa_property_t property) 33453034Sdougm { 33463034Sdougm int ret = SA_OK; 33473034Sdougm 33483034Sdougm if (property != NULL) { 33493034Sdougm sa_optionset_t optionset; 33503034Sdougm sa_group_t group; 33513034Sdougm optionset = sa_get_property_parent(property); 33523034Sdougm if (optionset != NULL) { 33534327Sdougm group = sa_get_optionset_parent(optionset); 33544327Sdougm if (group != NULL) { 33554327Sdougm ret = sa_set_prop_by_prop(optionset, group, 33564327Sdougm property, SA_PROP_OP_REMOVE); 33574327Sdougm } 33583034Sdougm } 33593034Sdougm xmlUnlinkNode((xmlNodePtr)property); 33603034Sdougm xmlFreeNode((xmlNodePtr)property); 33613034Sdougm } else { 33624327Sdougm ret = SA_NO_SUCH_PROP; 33633034Sdougm } 33643034Sdougm return (ret); 33653034Sdougm } 33663034Sdougm 33673034Sdougm /* 33683034Sdougm * sa_update_property(property, value) 33693034Sdougm * 33703034Sdougm * Update the specified property to the new value. If value is NULL, 33713034Sdougm * we currently treat this as a remove. 33723034Sdougm */ 33733034Sdougm 33743034Sdougm int 33753034Sdougm sa_update_property(sa_property_t property, char *value) 33763034Sdougm { 33773034Sdougm int ret = SA_OK; 33783034Sdougm if (value == NULL) { 33793034Sdougm return (sa_remove_property(property)); 33803034Sdougm } else { 33813034Sdougm sa_optionset_t optionset; 33823034Sdougm sa_group_t group; 33833034Sdougm set_node_attr((void *)property, "value", value); 33843034Sdougm optionset = sa_get_property_parent(property); 33853034Sdougm if (optionset != NULL) { 33864327Sdougm group = sa_get_optionset_parent(optionset); 33874327Sdougm if (group != NULL) { 33884327Sdougm ret = sa_set_prop_by_prop(optionset, group, 33894327Sdougm property, SA_PROP_OP_UPDATE); 33904327Sdougm } 33913034Sdougm } else { 33924327Sdougm ret = SA_NO_SUCH_PROP; 33933034Sdougm } 33943034Sdougm } 33953034Sdougm return (ret); 33963034Sdougm } 33973034Sdougm 33983034Sdougm /* 33996007Sthurlow * sa_get_protocol_section(propset, prop) 34006007Sthurlow * 34016007Sthurlow * Get the specified protocol specific section. These are global to 34026007Sthurlow * the protocol and not specific to a group or share. 34036007Sthurlow */ 34046007Sthurlow 34056007Sthurlow sa_protocol_properties_t 34066007Sthurlow sa_get_protocol_section(sa_protocol_properties_t propset, char *section) 34076007Sthurlow { 34086007Sthurlow xmlNodePtr node = (xmlNodePtr)propset; 34096007Sthurlow xmlChar *value = NULL; 34106007Sthurlow char *proto; 34116007Sthurlow 34126007Sthurlow proto = sa_get_optionset_attr(propset, "type"); 34138271SGordon.Ross@Sun.COM if ((sa_proto_get_featureset(proto) & SA_FEATURE_HAS_SECTIONS) == 0) { 34148271SGordon.Ross@Sun.COM if (proto != NULL) 34158271SGordon.Ross@Sun.COM sa_free_attr_string(proto); 34166007Sthurlow return (propset); 34178271SGordon.Ross@Sun.COM } 34186007Sthurlow 34196007Sthurlow for (node = node->children; node != NULL; 34206007Sthurlow node = node->next) { 34216007Sthurlow if (xmlStrcmp(node->name, (xmlChar *)"section") == 0) { 34226007Sthurlow if (section == NULL) 34236007Sthurlow break; 34246007Sthurlow value = xmlGetProp(node, (xmlChar *)"name"); 34256007Sthurlow if (value != NULL && 34266007Sthurlow xmlStrcasecmp(value, (xmlChar *)section) == 0) { 34276007Sthurlow break; 34286007Sthurlow } 34296007Sthurlow if (value != NULL) { 34306007Sthurlow xmlFree(value); 34316007Sthurlow value = NULL; 34326007Sthurlow } 34336007Sthurlow } 34346007Sthurlow } 34356007Sthurlow if (value != NULL) 34366007Sthurlow xmlFree(value); 34378271SGordon.Ross@Sun.COM if (proto != NULL) 34388271SGordon.Ross@Sun.COM sa_free_attr_string(proto); 34396007Sthurlow if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"section") != 0) { 34406007Sthurlow /* 34416007Sthurlow * avoid a non option node -- it is possible to be a 34426007Sthurlow * text node 34436007Sthurlow */ 34446007Sthurlow node = NULL; 34456007Sthurlow } 34466007Sthurlow return ((sa_protocol_properties_t)node); 34476007Sthurlow } 34486007Sthurlow 34496007Sthurlow /* 34506007Sthurlow * sa_get_next_protocol_section(prop, find) 34516007Sthurlow * 34526007Sthurlow * Get the next protocol specific section in the list. 34536007Sthurlow */ 34546007Sthurlow 34556007Sthurlow sa_property_t 34566007Sthurlow sa_get_next_protocol_section(sa_property_t prop, char *find) 34576007Sthurlow { 34586007Sthurlow xmlNodePtr node; 34596007Sthurlow xmlChar *value = NULL; 34606007Sthurlow char *proto; 34616007Sthurlow 34626007Sthurlow proto = sa_get_optionset_attr(prop, "type"); 34638271SGordon.Ross@Sun.COM if ((sa_proto_get_featureset(proto) & SA_FEATURE_HAS_SECTIONS) == 0) { 34648271SGordon.Ross@Sun.COM if (proto != NULL) 34658271SGordon.Ross@Sun.COM sa_free_attr_string(proto); 34666007Sthurlow return ((sa_property_t)NULL); 34678271SGordon.Ross@Sun.COM } 34686007Sthurlow 34696007Sthurlow for (node = ((xmlNodePtr)prop)->next; node != NULL; 34706007Sthurlow node = node->next) { 34716007Sthurlow if (xmlStrcmp(node->name, (xmlChar *)"section") == 0) { 34726007Sthurlow if (find == NULL) 34736007Sthurlow break; 34746007Sthurlow value = xmlGetProp(node, (xmlChar *)"name"); 34756007Sthurlow if (value != NULL && 34766007Sthurlow xmlStrcasecmp(value, (xmlChar *)find) == 0) { 34776007Sthurlow break; 34786007Sthurlow } 34796007Sthurlow if (value != NULL) { 34806007Sthurlow xmlFree(value); 34816007Sthurlow value = NULL; 34826007Sthurlow } 34836007Sthurlow 34846007Sthurlow } 34856007Sthurlow } 34866007Sthurlow if (value != NULL) 34876007Sthurlow xmlFree(value); 34888271SGordon.Ross@Sun.COM if (proto != NULL) 34898271SGordon.Ross@Sun.COM sa_free_attr_string(proto); 34906007Sthurlow return ((sa_property_t)node); 34916007Sthurlow } 34926007Sthurlow 34936007Sthurlow /* 34943034Sdougm * sa_get_protocol_property(propset, prop) 34953034Sdougm * 34963034Sdougm * Get the specified protocol specific property. These are global to 34973034Sdougm * the protocol and not specific to a group or share. 34983034Sdougm */ 34993034Sdougm 35003034Sdougm sa_property_t 35013034Sdougm sa_get_protocol_property(sa_protocol_properties_t propset, char *prop) 35023034Sdougm { 35033034Sdougm xmlNodePtr node = (xmlNodePtr)propset; 35043034Sdougm xmlChar *value = NULL; 35053034Sdougm 35066007Sthurlow if (propset == NULL) 35076007Sthurlow return (NULL); 35086007Sthurlow 35093034Sdougm for (node = node->children; node != NULL; 35104327Sdougm node = node->next) { 35114327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 35124327Sdougm if (prop == NULL) 35134327Sdougm break; 35144327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 35154327Sdougm if (value != NULL && 35164327Sdougm xmlStrcasecmp(value, (xmlChar *)prop) == 0) { 35174327Sdougm break; 35184327Sdougm } 35194327Sdougm if (value != NULL) { 35204327Sdougm xmlFree(value); 35214327Sdougm value = NULL; 35224327Sdougm } 35233034Sdougm } 35243034Sdougm } 35253034Sdougm if (value != NULL) 35263034Sdougm xmlFree(value); 35273034Sdougm if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"option") != 0) { 35284327Sdougm /* 35294327Sdougm * avoid a non option node -- it is possible to be a 35304327Sdougm * text node 35314327Sdougm */ 35324327Sdougm node = NULL; 35333034Sdougm } 35343034Sdougm return ((sa_property_t)node); 35353034Sdougm } 35363034Sdougm 35373034Sdougm /* 35383034Sdougm * sa_get_next_protocol_property(prop) 35393034Sdougm * 35403034Sdougm * Get the next protocol specific property in the list. 35413034Sdougm */ 35423034Sdougm 35433034Sdougm sa_property_t 35446007Sthurlow sa_get_next_protocol_property(sa_property_t prop, char *find) 35453034Sdougm { 35463034Sdougm xmlNodePtr node; 35476007Sthurlow xmlChar *value = NULL; 35483034Sdougm 35493034Sdougm for (node = ((xmlNodePtr)prop)->next; node != NULL; 35504327Sdougm node = node->next) { 35513034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 35526007Sthurlow if (find == NULL) 35536007Sthurlow break; 35546007Sthurlow value = xmlGetProp(node, (xmlChar *)"type"); 35556007Sthurlow if (value != NULL && 35566007Sthurlow xmlStrcasecmp(value, (xmlChar *)find) == 0) { 35576007Sthurlow break; 35586007Sthurlow } 35596007Sthurlow if (value != NULL) { 35606007Sthurlow xmlFree(value); 35616007Sthurlow value = NULL; 35626007Sthurlow } 35636007Sthurlow 35643034Sdougm } 35653034Sdougm } 35666007Sthurlow if (value != NULL) 35676007Sthurlow xmlFree(value); 35683034Sdougm return ((sa_property_t)node); 35693034Sdougm } 35703034Sdougm 35713034Sdougm /* 35723034Sdougm * sa_set_protocol_property(prop, value) 35733034Sdougm * 35743034Sdougm * Set the specified property to have the new value. The protocol 35753034Sdougm * specific plugin will then be called to update the property. 35763034Sdougm */ 35773034Sdougm 35783034Sdougm int 35796007Sthurlow sa_set_protocol_property(sa_property_t prop, char *section, char *value) 35803034Sdougm { 35813034Sdougm sa_protocol_properties_t propset; 35823034Sdougm char *proto; 35833034Sdougm int ret = SA_INVALID_PROTOCOL; 35843034Sdougm 35853034Sdougm propset = ((xmlNodePtr)prop)->parent; 35863034Sdougm if (propset != NULL) { 35874327Sdougm proto = sa_get_optionset_attr(propset, "type"); 35884327Sdougm if (proto != NULL) { 35896007Sthurlow if (section != NULL) 35906007Sthurlow set_node_attr((xmlNodePtr)prop, "section", 35916007Sthurlow section); 35924327Sdougm set_node_attr((xmlNodePtr)prop, "value", value); 35934327Sdougm ret = sa_proto_set_property(proto, prop); 35944327Sdougm sa_free_attr_string(proto); 35954327Sdougm } 35963034Sdougm } 35973034Sdougm return (ret); 35983034Sdougm } 35993034Sdougm 36003034Sdougm /* 36013034Sdougm * sa_add_protocol_property(propset, prop) 36023034Sdougm * 36035331Samw * Add a new property to the protocol specific property set. 36043034Sdougm */ 36053034Sdougm 36063034Sdougm int 36073034Sdougm sa_add_protocol_property(sa_protocol_properties_t propset, sa_property_t prop) 36083034Sdougm { 36093034Sdougm xmlNodePtr node; 36103034Sdougm 36113034Sdougm /* should check for legitimacy */ 36123034Sdougm node = xmlAddChild((xmlNodePtr)propset, (xmlNodePtr)prop); 36133034Sdougm if (node != NULL) 36144327Sdougm return (SA_OK); 36153034Sdougm return (SA_NO_MEMORY); 36163034Sdougm } 36173034Sdougm 36183034Sdougm /* 36193034Sdougm * sa_create_protocol_properties(proto) 36203034Sdougm * 36215331Samw * Create a protocol specific property set. 36223034Sdougm */ 36233034Sdougm 36243034Sdougm sa_protocol_properties_t 36253034Sdougm sa_create_protocol_properties(char *proto) 36263034Sdougm { 36273034Sdougm xmlNodePtr node; 36284327Sdougm 36293034Sdougm node = xmlNewNode(NULL, (xmlChar *)"propertyset"); 36304327Sdougm if (node != NULL) 36316007Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto); 36323034Sdougm return (node); 36333034Sdougm } 36345331Samw 36355331Samw /* 36365331Samw * sa_get_share_resource(share, resource) 36375331Samw * 36385331Samw * Get the named resource from the share, if it exists. If resource is 36395331Samw * NULL, get the first resource. 36405331Samw */ 36415331Samw 36425331Samw sa_resource_t 36435331Samw sa_get_share_resource(sa_share_t share, char *resource) 36445331Samw { 36455331Samw xmlNodePtr node = NULL; 36465331Samw xmlChar *name; 36475331Samw 36485331Samw if (share != NULL) { 36495331Samw for (node = ((xmlNodePtr)share)->children; node != NULL; 36505331Samw node = node->next) { 36515331Samw if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0) { 36525331Samw if (resource == NULL) { 36535331Samw /* 36545331Samw * We are looking for the first 36555331Samw * resource node and not a names 36565331Samw * resource. 36575331Samw */ 36585331Samw break; 36595331Samw } else { 36605331Samw /* is it the correct share? */ 36615331Samw name = xmlGetProp(node, 36625331Samw (xmlChar *)"name"); 36635331Samw if (name != NULL && 36645331Samw xmlStrcasecmp(name, 36655331Samw (xmlChar *)resource) == 0) { 36665331Samw xmlFree(name); 36675331Samw break; 36685331Samw } 36695331Samw xmlFree(name); 36705331Samw } 36715331Samw } 36725331Samw } 36735331Samw } 36745331Samw return ((sa_resource_t)node); 36755331Samw } 36765331Samw 36775331Samw /* 36785331Samw * sa_get_next_resource(resource) 36795331Samw * Return the next share following the specified share 36805331Samw * from the internal list of shares. Returns NULL if there 36815331Samw * are no more shares. The list is relative to the same 36825331Samw * group. 36835331Samw */ 36845331Samw sa_share_t 36855331Samw sa_get_next_resource(sa_resource_t resource) 36865331Samw { 36875331Samw xmlNodePtr node = NULL; 36885331Samw 36895331Samw if (resource != NULL) { 36905331Samw for (node = ((xmlNodePtr)resource)->next; node != NULL; 36915331Samw node = node->next) { 36925331Samw if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0) 36935331Samw break; 36945331Samw } 36955331Samw } 36965331Samw return ((sa_share_t)node); 36975331Samw } 36985331Samw 36995331Samw /* 37005331Samw * _sa_get_next_resource_index(share) 37015331Samw * 37025331Samw * get the next resource index number (one greater then current largest) 37035331Samw */ 37045331Samw 37055331Samw static int 37065331Samw _sa_get_next_resource_index(sa_share_t share) 37075331Samw { 37085331Samw sa_resource_t resource; 37095331Samw int index = 0; 37105331Samw char *id; 37115331Samw 37125331Samw for (resource = sa_get_share_resource(share, NULL); 37135331Samw resource != NULL; 37145331Samw resource = sa_get_next_resource(resource)) { 37155331Samw id = get_node_attr((void *)resource, "id"); 37165331Samw if (id != NULL) { 37175331Samw int val; 37185331Samw val = atoi(id); 37195331Samw if (val > index) 37205331Samw index = val; 37215331Samw sa_free_attr_string(id); 37225331Samw } 37235331Samw } 37245331Samw return (index + 1); 37255331Samw } 37265331Samw 37275331Samw 37285331Samw /* 37295331Samw * sa_add_resource(share, resource, persist, &err) 37305331Samw * 37315331Samw * Adds a new resource name associated with share. The resource name 37325331Samw * must be unique in the system and will be case insensitive (eventually). 37335331Samw */ 37345331Samw 37355331Samw sa_resource_t 37365331Samw sa_add_resource(sa_share_t share, char *resource, int persist, int *error) 37375331Samw { 37385331Samw xmlNodePtr node; 37395331Samw int err = SA_OK; 37405331Samw sa_resource_t res; 37415331Samw sa_group_t group; 37425331Samw sa_handle_t handle; 37435331Samw char istring[8]; /* just big enough for an integer value */ 37445331Samw int index; 37455331Samw 37465331Samw group = sa_get_parent_group(share); 37475331Samw handle = sa_find_group_handle(group); 37485331Samw res = sa_find_resource(handle, resource); 37495331Samw if (res != NULL) { 37505331Samw err = SA_DUPLICATE_NAME; 37515331Samw res = NULL; 37525331Samw } else { 37535331Samw node = xmlNewChild((xmlNodePtr)share, NULL, 37545331Samw (xmlChar *)"resource", NULL); 37555331Samw if (node != NULL) { 37566007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 37575331Samw (xmlChar *)resource); 37586007Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", persist ? 37595331Samw (xmlChar *)"persist" : (xmlChar *)"transient"); 37605331Samw if (persist != SA_SHARE_TRANSIENT) { 37615331Samw index = _sa_get_next_resource_index(share); 37625331Samw (void) snprintf(istring, sizeof (istring), "%d", 37635331Samw index); 37646007Sthurlow (void) xmlSetProp(node, (xmlChar *)"id", 37655331Samw (xmlChar *)istring); 37667483SDoug.McCallum@Sun.COM 37677483SDoug.McCallum@Sun.COM if (!sa_is_persistent((sa_group_t)share)) 37687483SDoug.McCallum@Sun.COM goto done; 37697483SDoug.McCallum@Sun.COM 37707483SDoug.McCallum@Sun.COM if (!sa_group_is_zfs(group)) { 37715331Samw /* ZFS doesn't use resource names */ 37725331Samw sa_handle_impl_t ihandle; 37737483SDoug.McCallum@Sun.COM 37745331Samw ihandle = (sa_handle_impl_t) 37755331Samw sa_find_group_handle( 37765331Samw group); 37775331Samw if (ihandle != NULL) 37785331Samw err = sa_commit_share( 37795331Samw ihandle->scfhandle, group, 37805331Samw share); 37815331Samw else 37825331Samw err = SA_SYSTEM_ERR; 37837483SDoug.McCallum@Sun.COM } else { 37847483SDoug.McCallum@Sun.COM err = sa_zfs_update((sa_share_t)group); 37855331Samw } 37865331Samw } 37875331Samw } 37885331Samw } 37897483SDoug.McCallum@Sun.COM done: 37905331Samw if (error != NULL) 37915331Samw *error = err; 37925331Samw return ((sa_resource_t)node); 37935331Samw } 37945331Samw 37955331Samw /* 37965331Samw * sa_remove_resource(resource) 37975331Samw * 37985331Samw * Remove the resource name from the share (and the system) 37995331Samw */ 38005331Samw 38015331Samw int 38025331Samw sa_remove_resource(sa_resource_t resource) 38035331Samw { 38045331Samw sa_share_t share; 38055331Samw sa_group_t group; 38065331Samw char *type; 38075331Samw int ret = SA_OK; 38087483SDoug.McCallum@Sun.COM boolean_t transient = B_FALSE; 38095521Sas200622 sa_optionset_t opt; 38105331Samw 38115331Samw share = sa_get_resource_parent(resource); 38125331Samw type = sa_get_share_attr(share, "type"); 38135331Samw group = sa_get_parent_group(share); 38145331Samw 38155331Samw 38165331Samw if (type != NULL) { 38175331Samw if (strcmp(type, "persist") != 0) 38187483SDoug.McCallum@Sun.COM transient = B_TRUE; 38195331Samw sa_free_attr_string(type); 38205331Samw } 38215331Samw 38225521Sas200622 /* Disable the resource for all protocols. */ 38235521Sas200622 (void) sa_disable_resource(resource, NULL); 38245521Sas200622 38255521Sas200622 /* Remove any optionsets from the resource. */ 38265521Sas200622 for (opt = sa_get_optionset(resource, NULL); 38275521Sas200622 opt != NULL; 38285521Sas200622 opt = sa_get_next_optionset(opt)) 38295521Sas200622 (void) sa_destroy_optionset(opt); 38305521Sas200622 38315331Samw /* Remove from the share */ 38325331Samw xmlUnlinkNode((xmlNode *)resource); 38335331Samw xmlFreeNode((xmlNode *)resource); 38345331Samw 38355331Samw /* only do SMF action if permanent and not ZFS */ 38367483SDoug.McCallum@Sun.COM if (transient) 38377483SDoug.McCallum@Sun.COM return (ret); 38387483SDoug.McCallum@Sun.COM 38397483SDoug.McCallum@Sun.COM if (!sa_group_is_zfs(group)) { 38405331Samw sa_handle_impl_t ihandle; 38415331Samw ihandle = (sa_handle_impl_t)sa_find_group_handle(group); 38425331Samw if (ihandle != NULL) 38435331Samw ret = sa_commit_share(ihandle->scfhandle, group, share); 38445331Samw else 38455331Samw ret = SA_SYSTEM_ERR; 38467483SDoug.McCallum@Sun.COM } else { 38477483SDoug.McCallum@Sun.COM ret = sa_zfs_update((sa_share_t)group); 38485331Samw } 38498845Samw@Sun.COM 38505331Samw return (ret); 38515331Samw } 38525331Samw 38535331Samw /* 38548845Samw@Sun.COM * proto_rename_resource(handle, group, resource, newname) 38555331Samw * 38565331Samw * Helper function for sa_rename_resource that notifies the protocol 38575331Samw * of a resource name change prior to a config repository update. 38585331Samw */ 38595331Samw static int 38605331Samw proto_rename_resource(sa_handle_t handle, sa_group_t group, 38615331Samw sa_resource_t resource, char *newname) 38625331Samw { 38635331Samw sa_optionset_t optionset; 38645331Samw int ret = SA_OK; 38655331Samw int err; 38665331Samw 38675331Samw for (optionset = sa_get_optionset(group, NULL); 38685331Samw optionset != NULL; 38695331Samw optionset = sa_get_next_optionset(optionset)) { 38705331Samw char *type; 38715331Samw type = sa_get_optionset_attr(optionset, "type"); 38725331Samw if (type != NULL) { 38735331Samw err = sa_proto_rename_resource(handle, type, resource, 38745331Samw newname); 38755331Samw if (err != SA_OK) 38765331Samw ret = err; 38775331Samw sa_free_attr_string(type); 38785331Samw } 38795331Samw } 38805331Samw return (ret); 38815331Samw } 38825331Samw 38835331Samw /* 38845331Samw * sa_rename_resource(resource, newname) 38855331Samw * 38865331Samw * Rename the resource to the new name, if it is unique. 38875331Samw */ 38885331Samw 38895331Samw int 38905331Samw sa_rename_resource(sa_resource_t resource, char *newname) 38915331Samw { 38925331Samw sa_share_t share; 38935331Samw sa_group_t group = NULL; 38945331Samw sa_resource_t target; 38955331Samw int ret = SA_CONFIG_ERR; 38965331Samw sa_handle_t handle = NULL; 38975331Samw 38985331Samw share = sa_get_resource_parent(resource); 38995331Samw if (share == NULL) 39005331Samw return (ret); 39015331Samw 39025331Samw group = sa_get_parent_group(share); 39035331Samw if (group == NULL) 39045331Samw return (ret); 39055331Samw 39065331Samw handle = (sa_handle_impl_t)sa_find_group_handle(group); 39075331Samw if (handle == NULL) 39085331Samw return (ret); 39095331Samw 39105331Samw target = sa_find_resource(handle, newname); 39115331Samw if (target != NULL) { 39125331Samw ret = SA_DUPLICATE_NAME; 39135331Samw } else { 39145331Samw /* 39155331Samw * Everything appears to be valid at this 39165331Samw * point. Change the name of the active share and then 39175331Samw * update the share in the appropriate repository. 39185331Samw */ 39195331Samw ret = proto_rename_resource(handle, group, resource, newname); 39205331Samw set_node_attr(resource, "name", newname); 39217483SDoug.McCallum@Sun.COM 39227483SDoug.McCallum@Sun.COM if (!sa_is_persistent((sa_group_t)share)) 39237483SDoug.McCallum@Sun.COM return (ret); 39247483SDoug.McCallum@Sun.COM 39257483SDoug.McCallum@Sun.COM if (!sa_group_is_zfs(group)) { 39265331Samw sa_handle_impl_t ihandle = (sa_handle_impl_t)handle; 39275331Samw ret = sa_commit_share(ihandle->scfhandle, group, 39285331Samw share); 39297483SDoug.McCallum@Sun.COM } else { 39307483SDoug.McCallum@Sun.COM ret = sa_zfs_update((sa_share_t)group); 39315331Samw } 39325331Samw } 39335331Samw return (ret); 39345331Samw } 39355331Samw 39365331Samw /* 39375331Samw * sa_get_resource_attr(resource, tag) 39385331Samw * 39395331Samw * Get the named attribute of the resource. "name" and "id" are 39405331Samw * currently defined. NULL if tag not defined. 39415331Samw */ 39425331Samw 39435331Samw char * 39445331Samw sa_get_resource_attr(sa_resource_t resource, char *tag) 39455331Samw { 39465331Samw return (get_node_attr((void *)resource, tag)); 39475331Samw } 39485331Samw 39495331Samw /* 39505331Samw * sa_set_resource_attr(resource, tag, value) 39515331Samw * 39525331Samw * Get the named attribute of the resource. "name" and "id" are 39535331Samw * currently defined. NULL if tag not defined. Currently we don't do 39545331Samw * much, but additional checking may be needed in the future. 39555331Samw */ 39565331Samw 39575331Samw int 39585331Samw sa_set_resource_attr(sa_resource_t resource, char *tag, char *value) 39595331Samw { 39605331Samw set_node_attr((void *)resource, tag, value); 39615331Samw return (SA_OK); 39625331Samw } 39635331Samw 39645331Samw /* 39655331Samw * sa_get_resource_parent(resource_t) 39665331Samw * 39675331Samw * Returns the share associated with the resource. 39685331Samw */ 39695331Samw 39705331Samw sa_share_t 39715331Samw sa_get_resource_parent(sa_resource_t resource) 39725331Samw { 39735331Samw sa_share_t share = NULL; 39745331Samw 39755331Samw if (resource != NULL) 39765331Samw share = (sa_share_t)((xmlNodePtr)resource)->parent; 39775331Samw return (share); 39785331Samw } 39795331Samw 39805331Samw /* 39815331Samw * find_resource(group, name) 39825331Samw * 39835331Samw * Find the resource within the group. 39845331Samw */ 39855331Samw 39865331Samw static sa_resource_t 39875331Samw find_resource(sa_group_t group, char *resname) 39885331Samw { 39895331Samw sa_share_t share; 39905331Samw sa_resource_t resource = NULL; 39915331Samw char *name; 39925331Samw 39935331Samw /* Iterate over all the shares and resources in the group. */ 39945331Samw for (share = sa_get_share(group, NULL); 39955331Samw share != NULL && resource == NULL; 39965331Samw share = sa_get_next_share(share)) { 39975331Samw for (resource = sa_get_share_resource(share, NULL); 39985331Samw resource != NULL; 39995331Samw resource = sa_get_next_resource(resource)) { 40005331Samw name = sa_get_resource_attr(resource, "name"); 40015331Samw if (name != NULL && xmlStrcasecmp((xmlChar*)name, 40025331Samw (xmlChar*)resname) == 0) { 40035331Samw sa_free_attr_string(name); 40045331Samw break; 40055331Samw } 40065331Samw if (name != NULL) { 40075331Samw sa_free_attr_string(name); 40085331Samw } 40095331Samw } 40105331Samw } 40115331Samw return (resource); 40125331Samw } 40135331Samw 40145331Samw /* 40155331Samw * sa_find_resource(name) 40165331Samw * 40175331Samw * Find the named resource in the system. 40185331Samw */ 40195331Samw 40205331Samw sa_resource_t 40215331Samw sa_find_resource(sa_handle_t handle, char *name) 40225331Samw { 40235331Samw sa_group_t group; 40245331Samw sa_group_t zgroup; 40255331Samw sa_resource_t resource = NULL; 40265331Samw 40275331Samw /* 40285331Samw * Iterate over all groups and zfs subgroups and check for 40295331Samw * resource name in them. 40305331Samw */ 40315331Samw for (group = sa_get_group(handle, NULL); group != NULL; 40325331Samw group = sa_get_next_group(group)) { 40335331Samw 40345331Samw if (is_zfs_group(group)) { 40355331Samw for (zgroup = 40365331Samw (sa_group_t)_sa_get_child_node((xmlNodePtr)group, 40375331Samw (xmlChar *)"group"); 40385331Samw zgroup != NULL && resource == NULL; 40395331Samw zgroup = sa_get_next_group(zgroup)) { 40405331Samw resource = find_resource(zgroup, name); 40415331Samw } 40425331Samw } else { 40435331Samw resource = find_resource(group, name); 40445331Samw } 40455331Samw if (resource != NULL) 40465331Samw break; 40475331Samw } 40485331Samw return (resource); 40495331Samw } 40505331Samw 40515331Samw /* 40525331Samw * sa_get_resource(group, resource) 40535331Samw * 40545331Samw * Search all the shares in the specified group for a share with a 40555331Samw * resource name matching the one specified. 40565331Samw * 40575331Samw * In the future, it may be advantageous to allow group to be NULL and 40585331Samw * search all groups but that isn't needed at present. 40595331Samw */ 40605331Samw 40615331Samw sa_resource_t 40625331Samw sa_get_resource(sa_group_t group, char *resource) 40635331Samw { 40645331Samw sa_share_t share = NULL; 40655331Samw sa_resource_t res = NULL; 40665331Samw 40675331Samw if (resource != NULL) { 40685331Samw for (share = sa_get_share(group, NULL); 40695331Samw share != NULL && res == NULL; 40705331Samw share = sa_get_next_share(share)) { 40715331Samw res = sa_get_share_resource(share, resource); 40725331Samw } 40735331Samw } 40745331Samw return (res); 40755331Samw } 40765331Samw 40775331Samw /* 40786270Sdougm * get_protocol_list(optionset, object) 40796270Sdougm * 40806270Sdougm * Get the protocol optionset list for the object and add them as 40816270Sdougm * properties to optionset. 40826270Sdougm */ 40836270Sdougm static int 40846270Sdougm get_protocol_list(sa_optionset_t optionset, void *object) 40856270Sdougm { 40866270Sdougm sa_property_t prop; 40876270Sdougm sa_optionset_t opts; 40886270Sdougm int ret = SA_OK; 40896270Sdougm 40906270Sdougm for (opts = sa_get_optionset(object, NULL); 40916270Sdougm opts != NULL; 40926270Sdougm opts = sa_get_next_optionset(opts)) { 40936270Sdougm char *type; 40946270Sdougm type = sa_get_optionset_attr(opts, "type"); 40956270Sdougm /* 40966270Sdougm * It is possible to have a non-protocol optionset. We 40976270Sdougm * skip any of those found. 40986270Sdougm */ 40996270Sdougm if (type == NULL) 41006270Sdougm continue; 41016270Sdougm prop = sa_create_property(type, "true"); 41026270Sdougm sa_free_attr_string(type); 41036270Sdougm if (prop != NULL) 41046270Sdougm prop = (sa_property_t)xmlAddChild((xmlNodePtr)optionset, 41056270Sdougm (xmlNodePtr)prop); 41066270Sdougm /* If prop is NULL, don't bother continuing */ 41076270Sdougm if (prop == NULL) { 41086270Sdougm ret = SA_NO_MEMORY; 41096270Sdougm break; 41106270Sdougm } 41116270Sdougm } 41126270Sdougm return (ret); 41136270Sdougm } 41146270Sdougm 41156270Sdougm /* 41166270Sdougm * sa_free_protoset(optionset) 41176270Sdougm * 41186270Sdougm * Free the protocol property optionset. 41196270Sdougm */ 41206270Sdougm static void 41216270Sdougm sa_free_protoset(sa_optionset_t optionset) 41226270Sdougm { 41236270Sdougm if (optionset != NULL) { 41246270Sdougm xmlUnlinkNode((xmlNodePtr) optionset); 41256270Sdougm xmlFreeNode((xmlNodePtr) optionset); 41266270Sdougm } 41276270Sdougm } 41286270Sdougm 41296270Sdougm /* 41306270Sdougm * sa_optionset_t sa_get_active_protocols(object) 41316270Sdougm * 41326270Sdougm * Return a list of the protocols that are active for the object. 41336270Sdougm * This is currently an internal helper function, but could be 41346270Sdougm * made visible if there is enough demand for it. 41356270Sdougm * 41366270Sdougm * The function finds the parent group and extracts the protocol 41376270Sdougm * optionsets creating a new optionset with the protocols as properties. 41386270Sdougm * 41396270Sdougm * The caller must free the returned optionset. 41406270Sdougm */ 41416270Sdougm 41426270Sdougm static sa_optionset_t 41436270Sdougm sa_get_active_protocols(void *object) 41446270Sdougm { 41456270Sdougm sa_optionset_t options; 41466270Sdougm sa_share_t share = NULL; 41476270Sdougm sa_group_t group = NULL; 41486270Sdougm sa_resource_t resource = NULL; 41496270Sdougm int ret = SA_OK; 41506270Sdougm 41516270Sdougm if (object == NULL) 41526270Sdougm return (NULL); 41536270Sdougm options = (sa_optionset_t)xmlNewNode(NULL, (xmlChar *)"optionset"); 41546270Sdougm if (options == NULL) 41556270Sdougm return (NULL); 41566270Sdougm 41576270Sdougm /* 41586270Sdougm * Find the objects up the tree that might have protocols 41596270Sdougm * enabled on them. 41606270Sdougm */ 41616270Sdougm if (sa_is_resource(object)) { 41626270Sdougm resource = (sa_resource_t)object; 41636270Sdougm share = sa_get_resource_parent(resource); 41646270Sdougm group = sa_get_parent_group(share); 41656270Sdougm } else if (sa_is_share(object)) { 41666270Sdougm share = (sa_share_t)object; 41676270Sdougm group = sa_get_parent_group(share); 41686270Sdougm } else { 41696270Sdougm group = (sa_group_t)group; 41706270Sdougm } 41716270Sdougm if (resource != NULL) 41726270Sdougm ret = get_protocol_list(options, resource); 41736270Sdougm if (ret == SA_OK && share != NULL) 41746270Sdougm ret = get_protocol_list(options, share); 41756270Sdougm if (ret == SA_OK && group != NULL) 41766270Sdougm ret = get_protocol_list(options, group); 41776270Sdougm 41786270Sdougm /* 41796270Sdougm * If there was an error, we won't have a complete list so 41806270Sdougm * abandon everything. The caller will have to deal with the 41816270Sdougm * issue. 41826270Sdougm */ 41836270Sdougm if (ret != SA_OK) { 41846270Sdougm sa_free_protoset(options); 41856270Sdougm options = NULL; 41866270Sdougm } 41876270Sdougm return (options); 41886270Sdougm } 41896270Sdougm 41906270Sdougm /* 41915331Samw * sa_enable_resource, protocol) 41925331Samw * Disable the specified share to the specified protocol. 41935331Samw * If protocol is NULL, then all protocols. 41945331Samw */ 41955331Samw int 41965331Samw sa_enable_resource(sa_resource_t resource, char *protocol) 41975331Samw { 41985331Samw int ret = SA_OK; 41995331Samw 42005331Samw if (protocol != NULL) { 42015331Samw ret = sa_proto_share_resource(protocol, resource); 42025331Samw } else { 42036270Sdougm sa_optionset_t protoset; 42046270Sdougm sa_property_t prop; 42056270Sdougm char *proto; 42066270Sdougm int err; 42076270Sdougm 42085331Samw /* need to do all protocols */ 42096270Sdougm protoset = sa_get_active_protocols(resource); 42106270Sdougm if (protoset == NULL) 42116270Sdougm return (SA_NO_MEMORY); 42126270Sdougm for (prop = sa_get_property(protoset, NULL); 42136270Sdougm prop != NULL; 42146270Sdougm prop = sa_get_next_property(prop)) { 42156270Sdougm proto = sa_get_property_attr(prop, "type"); 42166270Sdougm if (proto == NULL) { 42176270Sdougm ret = SA_NO_MEMORY; 42186270Sdougm continue; 42195331Samw } 42206270Sdougm err = sa_proto_share_resource(proto, resource); 42216270Sdougm if (err != SA_OK) 42226270Sdougm ret = err; 42236270Sdougm sa_free_attr_string(proto); 42245331Samw } 42256270Sdougm sa_free_protoset(protoset); 42265331Samw } 42275331Samw if (ret == SA_OK) 42285331Samw (void) sa_set_resource_attr(resource, "shared", NULL); 42295331Samw 42305331Samw return (ret); 42315331Samw } 42325331Samw 42335331Samw /* 42345331Samw * sa_disable_resource(resource, protocol) 42355331Samw * 42365331Samw * Disable the specified share for the specified protocol. If 42375331Samw * protocol is NULL, then all protocols. If the underlying 42385331Samw * protocol doesn't implement disable at the resource level, we 42395331Samw * disable at the share level. 42405331Samw */ 42415331Samw int 42425331Samw sa_disable_resource(sa_resource_t resource, char *protocol) 42435331Samw { 42445331Samw int ret = SA_OK; 42455331Samw 42465331Samw if (protocol != NULL) { 42475331Samw ret = sa_proto_unshare_resource(protocol, resource); 42485331Samw if (ret == SA_NOT_IMPLEMENTED) { 42495331Samw sa_share_t parent; 42505331Samw /* 42515331Samw * The protocol doesn't implement unshare 42525331Samw * resource. That implies that resource names are 42535331Samw * simple aliases for this protocol so we need to 42545331Samw * unshare the share. 42555331Samw */ 42565331Samw parent = sa_get_resource_parent(resource); 42575331Samw if (parent != NULL) 42585331Samw ret = sa_disable_share(parent, protocol); 42595331Samw else 42605331Samw ret = SA_CONFIG_ERR; 42615331Samw } 42625331Samw } else { 42636270Sdougm sa_optionset_t protoset; 42646270Sdougm sa_property_t prop; 42656270Sdougm char *proto; 42666270Sdougm int err; 42676270Sdougm 42685331Samw /* need to do all protocols */ 42696270Sdougm protoset = sa_get_active_protocols(resource); 42706270Sdougm if (protoset == NULL) 42716270Sdougm return (SA_NO_MEMORY); 42726270Sdougm for (prop = sa_get_property(protoset, NULL); 42736270Sdougm prop != NULL; 42746270Sdougm prop = sa_get_next_property(prop)) { 42756270Sdougm proto = sa_get_property_attr(prop, "type"); 42766270Sdougm if (proto == NULL) { 42776270Sdougm ret = SA_NO_MEMORY; 42786270Sdougm continue; 42795331Samw } 42806270Sdougm err = sa_proto_unshare_resource(proto, resource); 42816270Sdougm if (err == SA_NOT_SUPPORTED) { 42826270Sdougm sa_share_t parent; 42836270Sdougm parent = sa_get_resource_parent(resource); 42846270Sdougm if (parent != NULL) 42856270Sdougm err = sa_disable_share(parent, proto); 42866270Sdougm else 42876270Sdougm err = SA_CONFIG_ERR; 42886270Sdougm } 42896270Sdougm if (err != SA_OK) 42906270Sdougm ret = err; 42916270Sdougm sa_free_attr_string(proto); 42925331Samw } 42936270Sdougm sa_free_protoset(protoset); 42945331Samw } 42955331Samw if (ret == SA_OK) 42965331Samw (void) sa_set_resource_attr(resource, "shared", NULL); 42975331Samw 42985331Samw return (ret); 42995331Samw } 43005331Samw 43015331Samw /* 43025331Samw * sa_set_resource_description(resource, content) 43035331Samw * 43045331Samw * Set the description of share to content. 43055331Samw */ 43065331Samw 43075331Samw int 43085331Samw sa_set_resource_description(sa_resource_t resource, char *content) 43095331Samw { 43105331Samw xmlNodePtr node; 43115331Samw sa_group_t group; 43125331Samw sa_share_t share; 43135331Samw int ret = SA_OK; 43145331Samw 43155331Samw for (node = ((xmlNodePtr)resource)->children; 43165331Samw node != NULL; 43175331Samw node = node->next) { 43185331Samw if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 43195331Samw break; 43205331Samw } 43215331Samw } 43225331Samw 43235331Samw /* no existing description but want to add */ 43245331Samw if (node == NULL && content != NULL) { 43255331Samw /* add a description */ 43265331Samw node = _sa_set_share_description(resource, content); 43275331Samw } else if (node != NULL && content != NULL) { 43285331Samw /* update a description */ 43295331Samw xmlNodeSetContent(node, (xmlChar *)content); 43305331Samw } else if (node != NULL && content == NULL) { 43315331Samw /* remove an existing description */ 43325331Samw xmlUnlinkNode(node); 43335331Samw xmlFreeNode(node); 43345331Samw } 43355331Samw share = sa_get_resource_parent(resource); 43365331Samw group = sa_get_parent_group(share); 43375331Samw if (group != NULL && sa_is_persistent(share)) { 43385331Samw sa_handle_impl_t impl_handle; 43395331Samw impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 43405331Samw if (impl_handle != NULL) 43415331Samw ret = sa_commit_share(impl_handle->scfhandle, 43425331Samw group, share); 43435331Samw else 43445331Samw ret = SA_SYSTEM_ERR; 43455331Samw } 43465331Samw return (ret); 43475331Samw } 43485331Samw 43495331Samw /* 43505331Samw * sa_get_resource_description(share) 43515331Samw * 43525331Samw * Return the description text for the specified share if it 43535331Samw * exists. NULL if no description exists. 43545331Samw */ 43555331Samw 43565331Samw char * 43575331Samw sa_get_resource_description(sa_resource_t resource) 43585331Samw { 43595331Samw xmlChar *description = NULL; 43605331Samw xmlNodePtr node; 43615331Samw 43625331Samw for (node = ((xmlNodePtr)resource)->children; node != NULL; 43635331Samw node = node->next) { 43645331Samw if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) 43655331Samw break; 43665331Samw } 43675331Samw if (node != NULL) { 43685331Samw description = xmlNodeGetContent(node); 43695331Samw fixproblemchars((char *)description); 43705331Samw } 43715331Samw return ((char *)description); 43725331Samw } 4373