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 /* 23*11963SAfshin.Ardakani@Sun.COM * Copyright 2010 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"); 73011337SWilliam.Krier@Sun.COM if (index != NULL) { 7315331Samw len = snprintf(oname, len, "%s_%s_%s", id, 7325331Samw proto ? proto : "default", index); 73311337SWilliam.Krier@Sun.COM sa_free_attr_string(index); 73411337SWilliam.Krier@Sun.COM } else { 7355331Samw len = 0; 73611337SWilliam.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); 1364*11963SAfshin.Ardakani@Sun.COM if (handle == NULL) 1365*11963SAfshin.Ardakani@Sun.COM return (SA_BAD_PATH); 1366*11963SAfshin.Ardakani@Sun.COM 13673910Sdougm return (validpath(handle, path, strictness)); 13683034Sdougm } 13693034Sdougm 13703034Sdougm /* 13715331Samw * mark_excluded_protos(group, share, flags) 13723034Sdougm * 13735331Samw * Walk through all the protocols enabled for the group and check to 13745331Samw * see if the share has any of them should be in the exclude list 13755331Samw * based on the featureset of the protocol. If there are any, add the 13765331Samw * "exclude" property to the share. 13775331Samw */ 13785331Samw static void 13795331Samw mark_excluded_protos(sa_group_t group, xmlNodePtr share, uint64_t flags) 13805331Samw { 13815331Samw sa_optionset_t optionset; 13825331Samw char exclude_list[SA_STRSIZE]; 13835331Samw char *sep = ""; 13845331Samw 13855331Samw exclude_list[0] = '\0'; 13865331Samw for (optionset = sa_get_optionset(group, NULL); 13875331Samw optionset != NULL; 13885331Samw optionset = sa_get_next_optionset(optionset)) { 13895331Samw char *value; 13905331Samw uint64_t features; 13915331Samw value = sa_get_optionset_attr(optionset, "type"); 13925331Samw if (value == NULL) 13935331Samw continue; 13945331Samw features = sa_proto_get_featureset(value); 13955331Samw if (!(features & flags)) { 13965331Samw (void) strlcat(exclude_list, sep, 13975331Samw sizeof (exclude_list)); 13985331Samw (void) strlcat(exclude_list, value, 13995331Samw sizeof (exclude_list)); 14005331Samw sep = ","; 14015331Samw } 140211337SWilliam.Krier@Sun.COM sa_free_attr_string(value); 14035331Samw } 14045331Samw if (exclude_list[0] != '\0') 14056007Sthurlow (void) xmlSetProp(share, (xmlChar *)"exclude", 14065331Samw (xmlChar *)exclude_list); 14075331Samw } 14085331Samw 14095331Samw /* 14105331Samw * get_all_features(group) 14115331Samw * 14125331Samw * Walk through all the protocols on the group and collect all 14135331Samw * possible enabled features. This is the OR of all the featuresets. 14145331Samw */ 14155331Samw static uint64_t 14165331Samw get_all_features(sa_group_t group) 14175331Samw { 14185331Samw sa_optionset_t optionset; 14195331Samw uint64_t features = 0; 14205331Samw 14215331Samw for (optionset = sa_get_optionset(group, NULL); 14225331Samw optionset != NULL; 14235331Samw optionset = sa_get_next_optionset(optionset)) { 14245331Samw char *value; 14255331Samw value = sa_get_optionset_attr(optionset, "type"); 14265331Samw if (value == NULL) 14275331Samw continue; 14285331Samw features |= sa_proto_get_featureset(value); 14295331Samw sa_free_attr_string(value); 14305331Samw } 14315331Samw return (features); 14325331Samw } 14335331Samw 14345331Samw 14355331Samw /* 14365331Samw * _sa_add_share(group, sharepath, persist, *error, flags) 14375331Samw * 14385331Samw * Common code for all types of add_share. sa_add_share() is the 14393034Sdougm * public API, we also need to be able to do this when parsing legacy 14403034Sdougm * files and construction of the internal configuration while 14415331Samw * extracting config info from SMF. "flags" indicates if some 14425331Samw * protocols need relaxed rules while other don't. These values are 14435331Samw * the featureset values defined in libshare.h. 14443034Sdougm */ 14453034Sdougm 14463034Sdougm sa_share_t 14475331Samw _sa_add_share(sa_group_t group, char *sharepath, int persist, int *error, 14485331Samw uint64_t flags) 14493034Sdougm { 14503034Sdougm xmlNodePtr node = NULL; 14513034Sdougm int err; 14523034Sdougm 14533034Sdougm err = SA_OK; /* assume success */ 14543034Sdougm 14554327Sdougm node = xmlNewChild((xmlNodePtr)group, NULL, (xmlChar *)"share", NULL); 14565331Samw if (node == NULL) { 14575331Samw if (error != NULL) 14585331Samw *error = SA_NO_MEMORY; 14595331Samw return (node); 14605331Samw } 14615331Samw 14626007Sthurlow (void) xmlSetProp(node, (xmlChar *)"path", (xmlChar *)sharepath); 14636007Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", 14645331Samw persist ? (xmlChar *)"persist" : (xmlChar *)"transient"); 14655331Samw if (flags != 0) 14665331Samw mark_excluded_protos(group, node, flags); 14675331Samw if (persist != SA_SHARE_TRANSIENT) { 14685331Samw /* 14695331Samw * persistent shares come in two flavors: SMF and 14705331Samw * ZFS. Sort this one out based on target group and 14715331Samw * path type. Both NFS and SMB are supported. First, 14725331Samw * check to see if the protocol is enabled on the 14735331Samw * subgroup and then setup the share appropriately. 14745331Samw */ 14755331Samw if (sa_group_is_zfs(group) && 14765331Samw sa_path_is_zfs(sharepath)) { 14775331Samw if (sa_get_optionset(group, "nfs") != NULL) 14784327Sdougm err = sa_zfs_set_sharenfs(group, sharepath, 1); 14795331Samw else if (sa_get_optionset(group, "smb") != NULL) 14805331Samw err = sa_zfs_set_sharesmb(group, sharepath, 1); 14815331Samw } else { 14825331Samw sa_handle_impl_t impl_handle; 14835331Samw impl_handle = 14845331Samw (sa_handle_impl_t)sa_find_group_handle(group); 14855331Samw if (impl_handle != NULL) { 14865331Samw err = sa_commit_share(impl_handle->scfhandle, 14875331Samw group, (sa_share_t)node); 14884327Sdougm } else { 14895331Samw err = SA_SYSTEM_ERR; 14904327Sdougm } 14913034Sdougm } 14923034Sdougm } 14935331Samw if (err == SA_NO_PERMISSION && persist & SA_SHARE_PARSER) 14945331Samw /* called by the dfstab parser so could be a show */ 14955331Samw err = SA_OK; 14965331Samw 14975331Samw if (err != SA_OK) { 14985331Samw /* 14995331Samw * we couldn't commit to the repository so undo 15005331Samw * our internal state to reflect reality. 15015331Samw */ 15025331Samw xmlUnlinkNode(node); 15035331Samw xmlFreeNode(node); 15045331Samw node = NULL; 15055331Samw } 15065331Samw 15073034Sdougm if (error != NULL) 15084327Sdougm *error = err; 15095331Samw 15103034Sdougm return (node); 15113034Sdougm } 15123034Sdougm 15133034Sdougm /* 15143034Sdougm * sa_add_share(group, sharepath, persist, *error) 15153034Sdougm * 15163034Sdougm * Add a new share object to the specified group. The share will 15173034Sdougm * have the specified sharepath and will only be constructed if 15183034Sdougm * it is a valid path to be shared. NULL is returned on error 15193034Sdougm * and a detailed error value will be returned via the error 15203034Sdougm * pointer. 15213034Sdougm */ 15223034Sdougm sa_share_t 15233034Sdougm sa_add_share(sa_group_t group, char *sharepath, int persist, int *error) 15243034Sdougm { 15253034Sdougm xmlNodePtr node = NULL; 15263348Sdougm int strictness = SA_CHECK_NORMAL; 15273910Sdougm sa_handle_t handle; 15285331Samw uint64_t special = 0; 15295331Samw uint64_t features; 15303348Sdougm 15313348Sdougm /* 15323348Sdougm * If the share is to be permanent, use strict checking so a 15333348Sdougm * bad config doesn't get created. Transient shares only need 15343348Sdougm * to check against the currently active 15353348Sdougm * shares. SA_SHARE_PARSER is a modifier used internally to 15363348Sdougm * indicate that we are being called by the dfstab parser and 15373348Sdougm * that we need strict checking in all cases. Normally persist 15383348Sdougm * is in integer value but SA_SHARE_PARSER may be or'd into 15393348Sdougm * it as an override. 15403348Sdougm */ 15413348Sdougm if (persist & SA_SHARE_PARSER || persist == SA_SHARE_PERMANENT) 15424327Sdougm strictness = SA_CHECK_STRICT; 15433034Sdougm 15443910Sdougm handle = sa_find_group_handle(group); 15453910Sdougm 15465331Samw /* 15475331Samw * need to determine if the share is valid. The rules are: 15485331Samw * - The path must not already exist 15495331Samw * - The path must not be a subdir or parent dir of an 15505331Samw * existing path unless at least one protocol allows it. 15515331Samw * The sub/parent check is done in sa_check_path(). 15525331Samw */ 15535331Samw 15545331Samw if (sa_find_share(handle, sharepath) == NULL) { 15555331Samw *error = sa_check_path(group, sharepath, strictness); 15565331Samw features = get_all_features(group); 15575331Samw switch (*error) { 15585331Samw case SA_PATH_IS_SUBDIR: 15595331Samw if (features & SA_FEATURE_ALLOWSUBDIRS) 15605331Samw special |= SA_FEATURE_ALLOWSUBDIRS; 15615331Samw break; 15625331Samw case SA_PATH_IS_PARENTDIR: 15635331Samw if (features & SA_FEATURE_ALLOWPARDIRS) 15645331Samw special |= SA_FEATURE_ALLOWPARDIRS; 15655331Samw break; 15665331Samw } 15675331Samw if (*error == SA_OK || special != SA_FEATURE_NONE) 15685331Samw node = _sa_add_share(group, sharepath, persist, 15695331Samw error, special); 15705331Samw } else { 15715331Samw *error = SA_DUPLICATE_NAME; 15723034Sdougm } 15733034Sdougm 15743034Sdougm return ((sa_share_t)node); 15753034Sdougm } 15763034Sdougm 15773034Sdougm /* 15783034Sdougm * sa_enable_share(share, protocol) 15793034Sdougm * Enable the specified share to the specified protocol. 15803034Sdougm * If protocol is NULL, then all protocols. 15813034Sdougm */ 15823034Sdougm int 15833034Sdougm sa_enable_share(sa_share_t share, char *protocol) 15843034Sdougm { 15853034Sdougm char *sharepath; 15863034Sdougm struct stat st; 15875331Samw int err = SA_OK; 15885331Samw int ret; 15893034Sdougm 15903034Sdougm sharepath = sa_get_share_attr(share, "path"); 15915331Samw if (sharepath == NULL) 15925331Samw return (SA_NO_MEMORY); 15933034Sdougm if (stat(sharepath, &st) < 0) { 15944327Sdougm err = SA_NO_SUCH_PATH; 15953034Sdougm } else { 15964327Sdougm /* tell the server about the share */ 15974327Sdougm if (protocol != NULL) { 15985331Samw if (excluded_protocol(share, protocol)) 15995331Samw goto done; 16005331Samw 16014327Sdougm /* lookup protocol specific handler */ 16024327Sdougm err = sa_proto_share(protocol, share); 16034327Sdougm if (err == SA_OK) 16045331Samw (void) sa_set_share_attr(share, 16055331Samw "shared", "true"); 16064327Sdougm } else { 16075331Samw /* Tell all protocols about the share */ 16085331Samw sa_group_t group; 16095331Samw sa_optionset_t optionset; 16105331Samw 16115331Samw group = sa_get_parent_group(share); 16125331Samw 16135331Samw for (optionset = sa_get_optionset(group, NULL); 16145331Samw optionset != NULL; 16155331Samw optionset = sa_get_next_optionset(optionset)) { 16165331Samw char *proto; 16175331Samw proto = sa_get_optionset_attr(optionset, 16185331Samw "type"); 16195331Samw if (proto != NULL) { 16205331Samw if (!excluded_protocol(share, proto)) { 16215331Samw ret = sa_proto_share(proto, 16225331Samw share); 16235331Samw if (ret != SA_OK) 16245331Samw err = ret; 16255331Samw } 16265331Samw sa_free_attr_string(proto); 16275331Samw } 16285331Samw } 16294327Sdougm (void) sa_set_share_attr(share, "shared", "true"); 16304327Sdougm } 16313034Sdougm } 16325331Samw done: 16333034Sdougm if (sharepath != NULL) 16344327Sdougm sa_free_attr_string(sharepath); 16353034Sdougm return (err); 16363034Sdougm } 16373034Sdougm 16383034Sdougm /* 16393034Sdougm * sa_disable_share(share, protocol) 16405331Samw * Disable the specified share to the specified protocol. If 16415331Samw * protocol is NULL, then all protocols that are enabled for the 16425331Samw * share should be disabled. 16433034Sdougm */ 16443034Sdougm int 16453034Sdougm sa_disable_share(sa_share_t share, char *protocol) 16463034Sdougm { 16473034Sdougm char *path; 16485331Samw int err = SA_OK; 16493034Sdougm int ret = SA_OK; 16503034Sdougm 16513034Sdougm path = sa_get_share_attr(share, "path"); 16523034Sdougm 16533034Sdougm if (protocol != NULL) { 16544543Smarks ret = sa_proto_unshare(share, protocol, path); 16553034Sdougm } else { 16564327Sdougm /* need to do all protocols */ 16575331Samw sa_group_t group; 16585331Samw sa_optionset_t optionset; 16595331Samw 16605331Samw group = sa_get_parent_group(share); 16615331Samw 16625331Samw /* Tell all protocols about the share */ 16635331Samw for (optionset = sa_get_optionset(group, NULL); 16645331Samw optionset != NULL; 16655331Samw optionset = sa_get_next_optionset(optionset)) { 16665331Samw char *proto; 16675331Samw 16685331Samw proto = sa_get_optionset_attr(optionset, "type"); 16695331Samw if (proto != NULL) { 16705331Samw err = sa_proto_unshare(share, proto, path); 16715331Samw if (err != SA_OK) 16725331Samw ret = err; 16735331Samw sa_free_attr_string(proto); 16745331Samw } 16755331Samw } 16763034Sdougm } 16773034Sdougm if (ret == SA_OK) 16783034Sdougm (void) sa_set_share_attr(share, "shared", NULL); 16793034Sdougm if (path != NULL) 16804327Sdougm sa_free_attr_string(path); 16813034Sdougm return (ret); 16823034Sdougm } 16833034Sdougm 16843034Sdougm /* 16853034Sdougm * sa_remove_share(share) 16863034Sdougm * 16873034Sdougm * remove the specified share from its containing group. 16883034Sdougm * Remove from the SMF or ZFS configuration space. 16893034Sdougm */ 16903034Sdougm 16913034Sdougm int 16923034Sdougm sa_remove_share(sa_share_t share) 16933034Sdougm { 16943034Sdougm sa_group_t group; 16953034Sdougm int ret = SA_OK; 16963034Sdougm char *type; 16973034Sdougm int transient = 0; 16983034Sdougm char *groupname; 16993034Sdougm char *zfs; 17003034Sdougm 17013034Sdougm type = sa_get_share_attr(share, "type"); 17023034Sdougm group = sa_get_parent_group(share); 17033034Sdougm zfs = sa_get_group_attr(group, "zfs"); 17043034Sdougm groupname = sa_get_group_attr(group, "name"); 17053034Sdougm if (type != NULL && strcmp(type, "persist") != 0) 17064327Sdougm transient = 1; 17073034Sdougm if (type != NULL) 17084327Sdougm sa_free_attr_string(type); 17093034Sdougm 17103034Sdougm /* remove the node from its group then free the memory */ 17113034Sdougm 17123034Sdougm /* 17133034Sdougm * need to test if "busy" 17143034Sdougm */ 17153034Sdougm /* only do SMF action if permanent */ 17163034Sdougm if (!transient || zfs != NULL) { 17174327Sdougm /* remove from legacy dfstab as well as possible SMF */ 17185331Samw ret = sa_delete_legacy(share, NULL); 17194327Sdougm if (ret == SA_OK) { 17204327Sdougm if (!sa_group_is_zfs(group)) { 17214327Sdougm sa_handle_impl_t impl_handle; 17224327Sdougm impl_handle = (sa_handle_impl_t) 17234327Sdougm sa_find_group_handle(group); 17244327Sdougm if (impl_handle != NULL) { 17254327Sdougm ret = sa_delete_share( 17264327Sdougm impl_handle->scfhandle, group, 17274327Sdougm share); 17284327Sdougm } else { 17294327Sdougm ret = SA_SYSTEM_ERR; 17304327Sdougm } 17314327Sdougm } else { 17324327Sdougm char *sharepath = sa_get_share_attr(share, 17334327Sdougm "path"); 17344327Sdougm if (sharepath != NULL) { 17354327Sdougm ret = sa_zfs_set_sharenfs(group, 17364327Sdougm sharepath, 0); 17374327Sdougm sa_free_attr_string(sharepath); 17384327Sdougm } 17394327Sdougm } 17403034Sdougm } 17413034Sdougm } 17423034Sdougm if (groupname != NULL) 17434327Sdougm sa_free_attr_string(groupname); 17443034Sdougm if (zfs != NULL) 17454327Sdougm sa_free_attr_string(zfs); 17463034Sdougm 17473034Sdougm xmlUnlinkNode((xmlNodePtr)share); 17483034Sdougm xmlFreeNode((xmlNodePtr)share); 17493034Sdougm return (ret); 17503034Sdougm } 17513034Sdougm 17523034Sdougm /* 17533034Sdougm * sa_move_share(group, share) 17543034Sdougm * 17553034Sdougm * move the specified share to the specified group. Update SMF 17563034Sdougm * appropriately. 17573034Sdougm */ 17583034Sdougm 17593034Sdougm int 17603034Sdougm sa_move_share(sa_group_t group, sa_share_t share) 17613034Sdougm { 17623034Sdougm sa_group_t oldgroup; 17633034Sdougm int ret = SA_OK; 17643034Sdougm 17653034Sdougm /* remove the node from its group then free the memory */ 17663034Sdougm 17673034Sdougm oldgroup = sa_get_parent_group(share); 17683034Sdougm if (oldgroup != group) { 17694327Sdougm sa_handle_impl_t impl_handle; 17704327Sdougm xmlUnlinkNode((xmlNodePtr)share); 17713034Sdougm /* 17724327Sdougm * now that the share isn't in its old group, add to 17734327Sdougm * the new one 17743034Sdougm */ 17756007Sthurlow (void) xmlAddChild((xmlNodePtr)group, (xmlNodePtr)share); 17764327Sdougm /* need to deal with SMF */ 17774327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 17784327Sdougm if (impl_handle != NULL) { 17794327Sdougm /* 17804327Sdougm * need to remove from old group first and then add to 17814327Sdougm * new group. Ideally, we would do the other order but 17824327Sdougm * need to avoid having the share in two groups at the 17834327Sdougm * same time. 17844327Sdougm */ 17854327Sdougm ret = sa_delete_share(impl_handle->scfhandle, oldgroup, 17864327Sdougm share); 17874327Sdougm if (ret == SA_OK) 17884327Sdougm ret = sa_commit_share(impl_handle->scfhandle, 17894327Sdougm group, share); 17904327Sdougm } else { 17914327Sdougm ret = SA_SYSTEM_ERR; 17924327Sdougm } 17933034Sdougm } 17943034Sdougm return (ret); 17953034Sdougm } 17963034Sdougm 17973034Sdougm /* 17983034Sdougm * sa_get_parent_group(share) 17993034Sdougm * 18005331Samw * Return the containing group for the share. If a group was actually 18013034Sdougm * passed in, we don't want a parent so return NULL. 18023034Sdougm */ 18033034Sdougm 18043034Sdougm sa_group_t 18053034Sdougm sa_get_parent_group(sa_share_t share) 18063034Sdougm { 18073034Sdougm xmlNodePtr node = NULL; 18083034Sdougm if (share != NULL) { 18094327Sdougm node = ((xmlNodePtr)share)->parent; 18103034Sdougm /* 18113034Sdougm * make sure parent is a group and not sharecfg since 18123034Sdougm * we may be cheating and passing in a group. 18133034Sdougm * Eventually, groups of groups might come into being. 18143034Sdougm */ 18154327Sdougm if (node == NULL || 18164327Sdougm xmlStrcmp(node->name, (xmlChar *)"sharecfg") == 0) 18174327Sdougm node = NULL; 18183034Sdougm } 18193034Sdougm return ((sa_group_t)node); 18203034Sdougm } 18213034Sdougm 18223034Sdougm /* 18233910Sdougm * _sa_create_group(impl_handle, groupname) 18243034Sdougm * 18253034Sdougm * Create a group in the document. The caller will need to deal with 18263034Sdougm * configuration store and activation. 18273034Sdougm */ 18283034Sdougm 18293034Sdougm sa_group_t 18303910Sdougm _sa_create_group(sa_handle_impl_t impl_handle, char *groupname) 18313034Sdougm { 18323034Sdougm xmlNodePtr node = NULL; 18333034Sdougm 18343034Sdougm if (sa_valid_group_name(groupname)) { 18354327Sdougm node = xmlNewChild(impl_handle->tree, NULL, (xmlChar *)"group", 18364327Sdougm NULL); 18374327Sdougm if (node != NULL) { 18386007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 18394327Sdougm (xmlChar *)groupname); 18406007Sthurlow (void) xmlSetProp(node, (xmlChar *)"state", 18414327Sdougm (xmlChar *)"enabled"); 18424327Sdougm } 18433034Sdougm } 18443034Sdougm return ((sa_group_t)node); 18453034Sdougm } 18463034Sdougm 18473034Sdougm /* 18483034Sdougm * _sa_create_zfs_group(group, groupname) 18493034Sdougm * 18503034Sdougm * Create a ZFS subgroup under the specified group. This may 18513034Sdougm * eventually form the basis of general sub-groups, but is currently 18523034Sdougm * restricted to ZFS. 18533034Sdougm */ 18543034Sdougm sa_group_t 18553034Sdougm _sa_create_zfs_group(sa_group_t group, char *groupname) 18563034Sdougm { 18573034Sdougm xmlNodePtr node = NULL; 18583034Sdougm 18594327Sdougm node = xmlNewChild((xmlNodePtr)group, NULL, (xmlChar *)"group", NULL); 18603034Sdougm if (node != NULL) { 18616007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 18626007Sthurlow (xmlChar *)groupname); 18636007Sthurlow (void) xmlSetProp(node, (xmlChar *)"state", 18646007Sthurlow (xmlChar *)"enabled"); 18653034Sdougm } 18663034Sdougm 18673034Sdougm return ((sa_group_t)node); 18683034Sdougm } 18693034Sdougm 18703034Sdougm /* 18713034Sdougm * sa_create_group(groupname, *error) 18723034Sdougm * 18733034Sdougm * Create a new group with groupname. Need to validate that it is a 18743034Sdougm * legal name for SMF and the construct the SMF service instance of 18753034Sdougm * svc:/network/shares/group to implement the group. All necessary 18763034Sdougm * operational properties must be added to the group at this point 18773034Sdougm * (via the SMF transaction model). 18783034Sdougm */ 18793034Sdougm sa_group_t 18803910Sdougm sa_create_group(sa_handle_t handle, char *groupname, int *error) 18813034Sdougm { 18823034Sdougm xmlNodePtr node = NULL; 18833034Sdougm sa_group_t group; 18843034Sdougm int ret; 18854327Sdougm char rbacstr[SA_STRSIZE]; 18863910Sdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle; 18873034Sdougm 18883034Sdougm ret = SA_OK; 18893034Sdougm 18903910Sdougm if (impl_handle == NULL || impl_handle->scfhandle == NULL) { 18914327Sdougm ret = SA_SYSTEM_ERR; 18924327Sdougm goto err; 18933034Sdougm } 18943034Sdougm 18953910Sdougm group = sa_get_group(handle, groupname); 18963034Sdougm if (group != NULL) { 18974327Sdougm ret = SA_DUPLICATE_NAME; 18983034Sdougm } else { 18994327Sdougm if (sa_valid_group_name(groupname)) { 19004327Sdougm node = xmlNewChild(impl_handle->tree, NULL, 19014327Sdougm (xmlChar *)"group", NULL); 19024327Sdougm if (node != NULL) { 19036007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 19044327Sdougm (xmlChar *)groupname); 19054327Sdougm /* default to the group being enabled */ 19066007Sthurlow (void) xmlSetProp(node, (xmlChar *)"state", 19074327Sdougm (xmlChar *)"enabled"); 19084327Sdougm ret = sa_create_instance(impl_handle->scfhandle, 19094327Sdougm groupname); 19104327Sdougm if (ret == SA_OK) { 19114327Sdougm ret = sa_start_transaction( 19124327Sdougm impl_handle->scfhandle, 19134327Sdougm "operation"); 19144327Sdougm } 19154327Sdougm if (ret == SA_OK) { 19164327Sdougm ret = sa_set_property( 19174327Sdougm impl_handle->scfhandle, 19184327Sdougm "state", "enabled"); 19194327Sdougm if (ret == SA_OK) { 19204327Sdougm ret = sa_end_transaction( 19215951Sdougm impl_handle->scfhandle, 19225951Sdougm impl_handle); 19234327Sdougm } else { 19244327Sdougm sa_abort_transaction( 19254327Sdougm impl_handle->scfhandle); 19264327Sdougm } 19274327Sdougm } 19284327Sdougm if (ret == SA_OK) { 19294327Sdougm /* initialize the RBAC strings */ 19304327Sdougm ret = sa_start_transaction( 19314327Sdougm impl_handle->scfhandle, 19324327Sdougm "general"); 19334327Sdougm if (ret == SA_OK) { 19344327Sdougm (void) snprintf(rbacstr, 19354327Sdougm sizeof (rbacstr), "%s.%s", 19364327Sdougm SA_RBAC_MANAGE, groupname); 19374327Sdougm ret = sa_set_property( 19384327Sdougm impl_handle->scfhandle, 19393034Sdougm "action_authorization", 19403034Sdougm rbacstr); 19414327Sdougm } 19424327Sdougm if (ret == SA_OK) { 19434327Sdougm (void) snprintf(rbacstr, 19444327Sdougm sizeof (rbacstr), "%s.%s", 19454327Sdougm SA_RBAC_VALUE, groupname); 19464327Sdougm ret = sa_set_property( 19474327Sdougm impl_handle->scfhandle, 19483034Sdougm "value_authorization", 19493034Sdougm rbacstr); 19504327Sdougm } 19514327Sdougm if (ret == SA_OK) { 19524327Sdougm ret = sa_end_transaction( 19535951Sdougm impl_handle->scfhandle, 19545951Sdougm impl_handle); 19554327Sdougm } else { 19564327Sdougm sa_abort_transaction( 19574327Sdougm impl_handle->scfhandle); 19584327Sdougm } 19594327Sdougm } 19604327Sdougm if (ret != SA_OK) { 19614327Sdougm /* 19624327Sdougm * Couldn't commit the group 19634327Sdougm * so we need to undo 19644327Sdougm * internally. 19654327Sdougm */ 19664327Sdougm xmlUnlinkNode(node); 19674327Sdougm xmlFreeNode(node); 19684327Sdougm node = NULL; 19694327Sdougm } 19703034Sdougm } else { 19714327Sdougm ret = SA_NO_MEMORY; 19723034Sdougm } 19733034Sdougm } else { 19744327Sdougm ret = SA_INVALID_NAME; 19753034Sdougm } 19763034Sdougm } 19773034Sdougm err: 19783034Sdougm if (error != NULL) 19794327Sdougm *error = ret; 19803034Sdougm return ((sa_group_t)node); 19813034Sdougm } 19823034Sdougm 19833034Sdougm /* 19843034Sdougm * sa_remove_group(group) 19853034Sdougm * 19863034Sdougm * Remove the specified group. This deletes from the SMF repository. 19873034Sdougm * All property groups and properties are removed. 19883034Sdougm */ 19893034Sdougm 19903034Sdougm int 19913034Sdougm sa_remove_group(sa_group_t group) 19923034Sdougm { 19933034Sdougm char *name; 19943034Sdougm int ret = SA_OK; 19953910Sdougm sa_handle_impl_t impl_handle; 19963034Sdougm 19973910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 19983910Sdougm if (impl_handle != NULL) { 19994327Sdougm name = sa_get_group_attr(group, "name"); 20004327Sdougm if (name != NULL) { 20014327Sdougm ret = sa_delete_instance(impl_handle->scfhandle, name); 20024327Sdougm sa_free_attr_string(name); 20034327Sdougm } 20044327Sdougm xmlUnlinkNode((xmlNodePtr)group); /* make sure unlinked */ 20054327Sdougm xmlFreeNode((xmlNodePtr)group); /* now it is gone */ 20063910Sdougm } else { 20074327Sdougm ret = SA_SYSTEM_ERR; 20083034Sdougm } 20093034Sdougm return (ret); 20103034Sdougm } 20113034Sdougm 20123034Sdougm /* 20133034Sdougm * sa_update_config() 20143034Sdougm * 20153034Sdougm * Used to update legacy files that need to be updated in bulk 20163034Sdougm * Currently, this is a placeholder and will go away in a future 20173034Sdougm * release. 20183034Sdougm */ 20193034Sdougm 20203034Sdougm int 20213910Sdougm sa_update_config(sa_handle_t handle) 20223034Sdougm { 20233034Sdougm /* 20243034Sdougm * do legacy files first so we can tell when they change. 20253034Sdougm * This will go away when we start updating individual records 20263034Sdougm * rather than the whole file. 20273034Sdougm */ 20283910Sdougm update_legacy_config(handle); 20293034Sdougm return (SA_OK); 20303034Sdougm } 20313034Sdougm 20323034Sdougm /* 20333034Sdougm * get_node_attr(node, tag) 20343034Sdougm * 20355331Samw * Get the specified tag(attribute) if it exists on the node. This is 20363034Sdougm * used internally by a number of attribute oriented functions. 20373034Sdougm */ 20383034Sdougm 20393034Sdougm static char * 20403034Sdougm get_node_attr(void *nodehdl, char *tag) 20413034Sdougm { 20423034Sdougm xmlNodePtr node = (xmlNodePtr)nodehdl; 20433034Sdougm xmlChar *name = NULL; 20443034Sdougm 20454327Sdougm if (node != NULL) 20463034Sdougm name = xmlGetProp(node, (xmlChar *)tag); 20473034Sdougm return ((char *)name); 20483034Sdougm } 20493034Sdougm 20503034Sdougm /* 205111337SWilliam.Krier@Sun.COM * set_node_attr(node, tag) 20523034Sdougm * 20535331Samw * Set the specified tag(attribute) to the specified value This is 20543034Sdougm * used internally by a number of attribute oriented functions. It 20553034Sdougm * doesn't update the repository, only the internal document state. 20563034Sdougm */ 20573034Sdougm 20583034Sdougm void 20593034Sdougm set_node_attr(void *nodehdl, char *tag, char *value) 20603034Sdougm { 20613034Sdougm xmlNodePtr node = (xmlNodePtr)nodehdl; 20623034Sdougm if (node != NULL && tag != NULL) { 20634327Sdougm if (value != NULL) 20646007Sthurlow (void) xmlSetProp(node, (xmlChar *)tag, 20656007Sthurlow (xmlChar *)value); 20664327Sdougm else 20676007Sthurlow (void) xmlUnsetProp(node, (xmlChar *)tag); 20683034Sdougm } 20693034Sdougm } 20703034Sdougm 20713034Sdougm /* 20723034Sdougm * sa_get_group_attr(group, tag) 20733034Sdougm * 20743034Sdougm * Get the specied attribute, if defined, for the group. 20753034Sdougm */ 20763034Sdougm 20773034Sdougm char * 20783034Sdougm sa_get_group_attr(sa_group_t group, char *tag) 20793034Sdougm { 20803034Sdougm return (get_node_attr((void *)group, tag)); 20813034Sdougm } 20823034Sdougm 20833034Sdougm /* 20843034Sdougm * sa_set_group_attr(group, tag, value) 20853034Sdougm * 20863034Sdougm * set the specified tag/attribute on the group using value as its 20873034Sdougm * value. 20883034Sdougm * 20893034Sdougm * This will result in setting the property in the SMF repository as 20903034Sdougm * well as in the internal document. 20913034Sdougm */ 20923034Sdougm 20933034Sdougm int 20943034Sdougm sa_set_group_attr(sa_group_t group, char *tag, char *value) 20953034Sdougm { 20963034Sdougm int ret; 20973034Sdougm char *groupname; 20983910Sdougm sa_handle_impl_t impl_handle; 20993034Sdougm 21005331Samw /* 21015331Samw * ZFS group/subgroup doesn't need the handle so shortcut. 21025331Samw */ 21035331Samw if (sa_group_is_zfs(group)) { 21045331Samw set_node_attr((void *)group, tag, value); 21055331Samw return (SA_OK); 21065331Samw } 21075331Samw 21083910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 21093910Sdougm if (impl_handle != NULL) { 21104327Sdougm groupname = sa_get_group_attr(group, "name"); 21114327Sdougm ret = sa_get_instance(impl_handle->scfhandle, groupname); 21123910Sdougm if (ret == SA_OK) { 21134327Sdougm set_node_attr((void *)group, tag, value); 21144327Sdougm ret = sa_start_transaction(impl_handle->scfhandle, 21154327Sdougm "operation"); 21164327Sdougm if (ret == SA_OK) { 21174327Sdougm ret = sa_set_property(impl_handle->scfhandle, 21184327Sdougm tag, value); 21194327Sdougm if (ret == SA_OK) 21205885Sdougm ret = sa_end_transaction( 21215951Sdougm impl_handle->scfhandle, 21225951Sdougm impl_handle); 21234327Sdougm else 21244327Sdougm sa_abort_transaction( 21254327Sdougm impl_handle->scfhandle); 21264327Sdougm } 21275885Sdougm if (ret == SA_SYSTEM_ERR) 21285885Sdougm ret = SA_NO_PERMISSION; 21293034Sdougm } 21304327Sdougm if (groupname != NULL) 21314327Sdougm sa_free_attr_string(groupname); 21323910Sdougm } else { 21334327Sdougm ret = SA_SYSTEM_ERR; 21343034Sdougm } 21353034Sdougm return (ret); 21363034Sdougm } 21373034Sdougm 21383034Sdougm /* 21393034Sdougm * sa_get_share_attr(share, tag) 21403034Sdougm * 21413034Sdougm * Return the value of the tag/attribute set on the specified 21423034Sdougm * share. Returns NULL if the tag doesn't exist. 21433034Sdougm */ 21443034Sdougm 21453034Sdougm char * 21463034Sdougm sa_get_share_attr(sa_share_t share, char *tag) 21473034Sdougm { 21483034Sdougm return (get_node_attr((void *)share, tag)); 21493034Sdougm } 21503034Sdougm 21513034Sdougm /* 21523034Sdougm * _sa_set_share_description(share, description) 21533034Sdougm * 21545331Samw * Add a description tag with text contents to the specified share. A 21555331Samw * separate XML tag is used rather than a property. This can also be 21565331Samw * used with resources. 21573034Sdougm */ 21583034Sdougm 21593034Sdougm xmlNodePtr 21605331Samw _sa_set_share_description(void *share, char *content) 21613034Sdougm { 21623034Sdougm xmlNodePtr node; 21634327Sdougm node = xmlNewChild((xmlNodePtr)share, NULL, (xmlChar *)"description", 21644327Sdougm NULL); 21653034Sdougm xmlNodeSetContent(node, (xmlChar *)content); 21663034Sdougm return (node); 21673034Sdougm } 21683034Sdougm 21693034Sdougm /* 21703034Sdougm * sa_set_share_attr(share, tag, value) 21713034Sdougm * 21723034Sdougm * Set the share attribute specified by tag to the specified value. In 21733034Sdougm * the case of "resource", enforce a no duplicates in a group rule. If 21743034Sdougm * the share is not transient, commit the changes to the repository 21753034Sdougm * else just update the share internally. 21763034Sdougm */ 21773034Sdougm 21783034Sdougm int 21793034Sdougm sa_set_share_attr(sa_share_t share, char *tag, char *value) 21803034Sdougm { 21813034Sdougm sa_group_t group; 21823034Sdougm sa_share_t resource; 21833034Sdougm int ret = SA_OK; 21843034Sdougm 21853034Sdougm group = sa_get_parent_group(share); 21863034Sdougm 21873034Sdougm /* 21883034Sdougm * There are some attributes that may have specific 21893034Sdougm * restrictions on them. Initially, only "resource" has 21903034Sdougm * special meaning that needs to be checked. Only one instance 21913034Sdougm * of a resource name may exist within a group. 21923034Sdougm */ 21933034Sdougm 21943034Sdougm if (strcmp(tag, "resource") == 0) { 21954327Sdougm resource = sa_get_resource(group, value); 21964327Sdougm if (resource != share && resource != NULL) 21974327Sdougm ret = SA_DUPLICATE_NAME; 21983034Sdougm } 21993034Sdougm if (ret == SA_OK) { 22004327Sdougm set_node_attr((void *)share, tag, value); 22014327Sdougm if (group != NULL) { 22024327Sdougm char *type; 22034327Sdougm /* we can probably optimize this some */ 22044327Sdougm type = sa_get_share_attr(share, "type"); 22054327Sdougm if (type == NULL || strcmp(type, "transient") != 0) { 22064327Sdougm sa_handle_impl_t impl_handle; 22074327Sdougm impl_handle = 22084327Sdougm (sa_handle_impl_t)sa_find_group_handle( 22094327Sdougm group); 22104327Sdougm if (impl_handle != NULL) { 22114327Sdougm ret = sa_commit_share( 22124327Sdougm impl_handle->scfhandle, group, 22134327Sdougm share); 22144327Sdougm } else { 22154327Sdougm ret = SA_SYSTEM_ERR; 22164327Sdougm } 22174327Sdougm } 22184327Sdougm if (type != NULL) 22194327Sdougm sa_free_attr_string(type); 22203910Sdougm } 22213034Sdougm } 22223034Sdougm return (ret); 22233034Sdougm } 22243034Sdougm 22253034Sdougm /* 22263034Sdougm * sa_get_property_attr(prop, tag) 22273034Sdougm * 22283034Sdougm * Get the value of the specified property attribute. Standard 22293034Sdougm * attributes are "type" and "value". 22303034Sdougm */ 22313034Sdougm 22323034Sdougm char * 22333034Sdougm sa_get_property_attr(sa_property_t prop, char *tag) 22343034Sdougm { 22353034Sdougm return (get_node_attr((void *)prop, tag)); 22363034Sdougm } 22373034Sdougm 22383034Sdougm /* 22393034Sdougm * sa_get_optionset_attr(prop, tag) 22403034Sdougm * 22413034Sdougm * Get the value of the specified property attribute. Standard 22423034Sdougm * attribute is "type". 22433034Sdougm */ 22443034Sdougm 22453034Sdougm char * 22463034Sdougm sa_get_optionset_attr(sa_property_t optionset, char *tag) 22473034Sdougm { 22483034Sdougm return (get_node_attr((void *)optionset, tag)); 22493034Sdougm 22503034Sdougm } 22513034Sdougm 22523034Sdougm /* 22533034Sdougm * sa_set_optionset_attr(optionset, tag, value) 22543034Sdougm * 22553034Sdougm * Set the specified attribute(tag) to the specified value on the 22563034Sdougm * optionset. 22573034Sdougm */ 22583034Sdougm 22593034Sdougm void 22603034Sdougm sa_set_optionset_attr(sa_group_t optionset, char *tag, char *value) 22613034Sdougm { 22623034Sdougm set_node_attr((void *)optionset, tag, value); 22633034Sdougm } 22643034Sdougm 22653034Sdougm /* 22663034Sdougm * sa_free_attr_string(string) 22673034Sdougm * 22683034Sdougm * Free the string that was returned in one of the sa_get_*_attr() 22693034Sdougm * functions. 22703034Sdougm */ 22713034Sdougm 22723034Sdougm void 22733034Sdougm sa_free_attr_string(char *string) 22743034Sdougm { 22753034Sdougm xmlFree((xmlChar *)string); 22763034Sdougm } 22773034Sdougm 22783034Sdougm /* 22793034Sdougm * sa_get_optionset(group, proto) 22803034Sdougm * 22813034Sdougm * Return the optionset, if it exists, that is associated with the 22823034Sdougm * specified protocol. 22833034Sdougm */ 22843034Sdougm 22853034Sdougm sa_optionset_t 22863034Sdougm sa_get_optionset(void *group, char *proto) 22873034Sdougm { 22883034Sdougm xmlNodePtr node; 22893034Sdougm xmlChar *value = NULL; 22903034Sdougm 22913034Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 22924327Sdougm node = node->next) { 22933034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) { 22944327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 22954327Sdougm if (proto != NULL) { 22964327Sdougm if (value != NULL && 22974327Sdougm xmlStrcmp(value, (xmlChar *)proto) == 0) { 22984327Sdougm break; 22994327Sdougm } 23004327Sdougm if (value != NULL) { 23014327Sdougm xmlFree(value); 23024327Sdougm value = NULL; 23034327Sdougm } 23044327Sdougm } else { 23054327Sdougm break; 23063034Sdougm } 23073034Sdougm } 23083034Sdougm } 23093034Sdougm if (value != NULL) 23104327Sdougm xmlFree(value); 23113034Sdougm return ((sa_optionset_t)node); 23123034Sdougm } 23133034Sdougm 23143034Sdougm /* 23153034Sdougm * sa_get_next_optionset(optionset) 23163034Sdougm * 23173034Sdougm * Return the next optionset in the group. NULL if this was the last. 23183034Sdougm */ 23193034Sdougm 23203034Sdougm sa_optionset_t 23213034Sdougm sa_get_next_optionset(sa_optionset_t optionset) 23223034Sdougm { 23233034Sdougm xmlNodePtr node; 23243034Sdougm 23253034Sdougm for (node = ((xmlNodePtr)optionset)->next; node != NULL; 23264327Sdougm node = node->next) { 23273034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) { 23283034Sdougm break; 23293034Sdougm } 23303034Sdougm } 23313034Sdougm return ((sa_optionset_t)node); 23323034Sdougm } 23333034Sdougm 23343034Sdougm /* 23353034Sdougm * sa_get_security(group, sectype, proto) 23363034Sdougm * 23373034Sdougm * Return the security optionset. The internal name is a hold over 23383034Sdougm * from the implementation and will be changed before the API is 23393034Sdougm * finalized. This is really a named optionset that can be negotiated 23403034Sdougm * as a group of properties (like NFS security options). 23413034Sdougm */ 23423034Sdougm 23433034Sdougm sa_security_t 23443034Sdougm sa_get_security(sa_group_t group, char *sectype, char *proto) 23453034Sdougm { 23463034Sdougm xmlNodePtr node; 23473034Sdougm xmlChar *value = NULL; 23483034Sdougm 23493034Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 23504327Sdougm node = node->next) { 23514327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) { 23524327Sdougm if (proto != NULL) { 23534327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 23544327Sdougm if (value == NULL || 23554327Sdougm (value != NULL && 23564327Sdougm xmlStrcmp(value, (xmlChar *)proto) != 0)) { 23574327Sdougm /* it doesn't match so continue */ 23584327Sdougm xmlFree(value); 23594327Sdougm value = NULL; 23604327Sdougm continue; 23614327Sdougm } 23624327Sdougm } 23634327Sdougm if (value != NULL) { 23644327Sdougm xmlFree(value); 23654327Sdougm value = NULL; 23664327Sdougm } 23674327Sdougm /* potential match */ 23684327Sdougm if (sectype != NULL) { 23694327Sdougm value = xmlGetProp(node, (xmlChar *)"sectype"); 23704327Sdougm if (value != NULL && 23714327Sdougm xmlStrcmp(value, (xmlChar *)sectype) == 0) { 23724327Sdougm break; 23734327Sdougm } 23744327Sdougm } else { 23754327Sdougm break; 23764327Sdougm } 23773034Sdougm } 23783034Sdougm if (value != NULL) { 23794327Sdougm xmlFree(value); 23804327Sdougm value = NULL; 23813034Sdougm } 23823034Sdougm } 23833034Sdougm if (value != NULL) 23844327Sdougm xmlFree(value); 23853034Sdougm return ((sa_security_t)node); 23863034Sdougm } 23873034Sdougm 23883034Sdougm /* 23893034Sdougm * sa_get_next_security(security) 23903034Sdougm * 23913034Sdougm * Get the next security optionset if one exists. 23923034Sdougm */ 23933034Sdougm 23943034Sdougm sa_security_t 23953034Sdougm sa_get_next_security(sa_security_t security) 23963034Sdougm { 23973034Sdougm xmlNodePtr node; 23983034Sdougm 23993034Sdougm for (node = ((xmlNodePtr)security)->next; node != NULL; 24004327Sdougm node = node->next) { 24013034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) { 24023034Sdougm break; 24033034Sdougm } 24043034Sdougm } 24053034Sdougm return ((sa_security_t)node); 24063034Sdougm } 24073034Sdougm 24083034Sdougm /* 24093034Sdougm * sa_get_property(optionset, prop) 24103034Sdougm * 24113034Sdougm * Get the property object with the name specified in prop from the 24123034Sdougm * optionset. 24133034Sdougm */ 24143034Sdougm 24153034Sdougm sa_property_t 24163034Sdougm sa_get_property(sa_optionset_t optionset, char *prop) 24173034Sdougm { 24183034Sdougm xmlNodePtr node = (xmlNodePtr)optionset; 24193034Sdougm xmlChar *value = NULL; 24203034Sdougm 24213034Sdougm if (optionset == NULL) 24224327Sdougm return (NULL); 24233034Sdougm 24243034Sdougm for (node = node->children; node != NULL; 24254327Sdougm node = node->next) { 24264327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 24274327Sdougm if (prop == NULL) 24284327Sdougm break; 24294327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 24304327Sdougm if (value != NULL && 24314327Sdougm xmlStrcmp(value, (xmlChar *)prop) == 0) { 24324327Sdougm break; 24334327Sdougm } 24344327Sdougm if (value != NULL) { 24354327Sdougm xmlFree(value); 24364327Sdougm value = NULL; 24374327Sdougm } 24383034Sdougm } 24393034Sdougm } 24403034Sdougm if (value != NULL) 24413034Sdougm xmlFree(value); 24423034Sdougm if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"option") != 0) { 24434327Sdougm /* 24444327Sdougm * avoid a non option node -- it is possible to be a 24454327Sdougm * text node 24464327Sdougm */ 24474327Sdougm node = NULL; 24483034Sdougm } 24493034Sdougm return ((sa_property_t)node); 24503034Sdougm } 24513034Sdougm 24523034Sdougm /* 24533034Sdougm * sa_get_next_property(property) 24543034Sdougm * 24553034Sdougm * Get the next property following the specified property. NULL if 24563034Sdougm * this was the last. 24573034Sdougm */ 24583034Sdougm 24593034Sdougm sa_property_t 24603034Sdougm sa_get_next_property(sa_property_t property) 24613034Sdougm { 24623034Sdougm xmlNodePtr node; 24633034Sdougm 24643034Sdougm for (node = ((xmlNodePtr)property)->next; node != NULL; 24654327Sdougm node = node->next) { 24663034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 24673034Sdougm break; 24683034Sdougm } 24693034Sdougm } 24703034Sdougm return ((sa_property_t)node); 24713034Sdougm } 24723034Sdougm 24733034Sdougm /* 24743034Sdougm * sa_set_share_description(share, content) 24753034Sdougm * 24763034Sdougm * Set the description of share to content. 24773034Sdougm */ 24783034Sdougm 24793034Sdougm int 24803034Sdougm sa_set_share_description(sa_share_t share, char *content) 24813034Sdougm { 24823034Sdougm xmlNodePtr node; 24833034Sdougm sa_group_t group; 24843034Sdougm int ret = SA_OK; 24853034Sdougm 24863034Sdougm for (node = ((xmlNodePtr)share)->children; node != NULL; 24874327Sdougm node = node->next) { 24883034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 24893034Sdougm break; 24903034Sdougm } 24913034Sdougm } 24923034Sdougm /* no existing description but want to add */ 24933034Sdougm if (node == NULL && content != NULL) { 24943034Sdougm /* add a description */ 24954327Sdougm node = _sa_set_share_description(share, content); 24963034Sdougm } else if (node != NULL && content != NULL) { 24973034Sdougm /* update a description */ 24983034Sdougm xmlNodeSetContent(node, (xmlChar *)content); 24993034Sdougm } else if (node != NULL && content == NULL) { 25003034Sdougm /* remove an existing description */ 25013034Sdougm xmlUnlinkNode(node); 25023034Sdougm xmlFreeNode(node); 25033034Sdougm } 25045331Samw group = sa_get_parent_group(share); 25055331Samw if (group != NULL && sa_is_persistent(share)) { 25064327Sdougm sa_handle_impl_t impl_handle; 25074327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 25084327Sdougm if (impl_handle != NULL) { 25094327Sdougm ret = sa_commit_share(impl_handle->scfhandle, group, 25104327Sdougm share); 25114327Sdougm } else { 25124327Sdougm ret = SA_SYSTEM_ERR; 25134327Sdougm } 25143910Sdougm } 25153034Sdougm return (ret); 25163034Sdougm } 25173034Sdougm 25183034Sdougm /* 25193034Sdougm * fixproblemchars(string) 25203034Sdougm * 25213034Sdougm * don't want any newline or tab characters in the text since these 25223034Sdougm * could break display of data and legacy file formats. 25233034Sdougm */ 25243034Sdougm static void 25253034Sdougm fixproblemchars(char *str) 25263034Sdougm { 25273034Sdougm int c; 25283034Sdougm for (c = *str; c != '\0'; c = *++str) { 25294327Sdougm if (c == '\t' || c == '\n') 25304327Sdougm *str = ' '; 25314327Sdougm else if (c == '"') 25324327Sdougm *str = '\''; 25333034Sdougm } 25343034Sdougm } 25353034Sdougm 25363034Sdougm /* 25373034Sdougm * sa_get_share_description(share) 25383034Sdougm * 25393034Sdougm * Return the description text for the specified share if it 25403034Sdougm * exists. NULL if no description exists. 25413034Sdougm */ 25423034Sdougm 25433034Sdougm char * 25443034Sdougm sa_get_share_description(sa_share_t share) 25453034Sdougm { 25463034Sdougm xmlChar *description = NULL; 25473034Sdougm xmlNodePtr node; 25483034Sdougm 25493034Sdougm for (node = ((xmlNodePtr)share)->children; node != NULL; 25504327Sdougm node = node->next) { 25514327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 25524327Sdougm break; 25534327Sdougm } 25543034Sdougm } 25553034Sdougm if (node != NULL) { 25565331Samw description = xmlNodeGetContent(node); 25574327Sdougm fixproblemchars((char *)description); 25583034Sdougm } 25593034Sdougm return ((char *)description); 25603034Sdougm } 25613034Sdougm 25623034Sdougm /* 25633034Sdougm * sa_free(share_description(description) 25643034Sdougm * 25653034Sdougm * Free the description string. 25663034Sdougm */ 25673034Sdougm 25683034Sdougm void 25693034Sdougm sa_free_share_description(char *description) 25703034Sdougm { 25713034Sdougm xmlFree((xmlChar *)description); 25723034Sdougm } 25733034Sdougm 25743034Sdougm /* 25753034Sdougm * sa_create_optionset(group, proto) 25763034Sdougm * 25773034Sdougm * Create an optionset for the specified protocol in the specied 25783034Sdougm * group. This is manifested as a property group within SMF. 25793034Sdougm */ 25803034Sdougm 25813034Sdougm sa_optionset_t 25823034Sdougm sa_create_optionset(sa_group_t group, char *proto) 25833034Sdougm { 25843034Sdougm sa_optionset_t optionset; 25853034Sdougm sa_group_t parent = group; 25865331Samw sa_share_t share = NULL; 25875331Samw int err = SA_OK; 25885331Samw char *id = NULL; 25893034Sdougm 25903034Sdougm optionset = sa_get_optionset(group, proto); 25913034Sdougm if (optionset != NULL) { 25923034Sdougm /* can't have a duplicate protocol */ 25934327Sdougm optionset = NULL; 25943034Sdougm } else { 25955331Samw /* 25965331Samw * Account for resource names being slightly 25975331Samw * different. 25985331Samw */ 25995331Samw if (sa_is_share(group)) { 26005331Samw /* 26015331Samw * Transient shares do not have an "id" so not an 26025331Samw * error to not find one. 26035331Samw */ 26045331Samw id = sa_get_share_attr((sa_share_t)group, "id"); 26055331Samw } else if (sa_is_resource(group)) { 26065331Samw share = sa_get_resource_parent( 26075331Samw (sa_resource_t)group); 26085331Samw id = sa_get_resource_attr(share, "id"); 26095331Samw 26105331Samw /* id can be NULL if the group is transient (ZFS) */ 26115331Samw if (id == NULL && sa_is_persistent(group)) 26125331Samw err = SA_NO_MEMORY; 26135331Samw } 26145331Samw if (err == SA_NO_MEMORY) { 26155331Samw /* 26165331Samw * Couldn't get the id for the share or 26175331Samw * resource. While this could be a 26185331Samw * configuration issue, it is most likely an 26195331Samw * out of memory. In any case, fail the create. 26205331Samw */ 26215331Samw return (NULL); 26225331Samw } 26235331Samw 26244327Sdougm optionset = (sa_optionset_t)xmlNewChild((xmlNodePtr)group, 26254327Sdougm NULL, (xmlChar *)"optionset", NULL); 26263034Sdougm /* 26273034Sdougm * only put to repository if on a group and we were 26283034Sdougm * able to create an optionset. 26293034Sdougm */ 26304327Sdougm if (optionset != NULL) { 26314327Sdougm char oname[SA_STRSIZE]; 26324327Sdougm char *groupname; 26335331Samw 26345331Samw /* 26355331Samw * Need to get parent group in all cases, but also get 26365331Samw * the share if this is a resource. 26375331Samw */ 26385331Samw if (sa_is_share(group)) { 26394327Sdougm parent = sa_get_parent_group((sa_share_t)group); 26405331Samw } else if (sa_is_resource(group)) { 26415331Samw share = sa_get_resource_parent( 26425331Samw (sa_resource_t)group); 26435331Samw parent = sa_get_parent_group(share); 26445331Samw } 26454327Sdougm 26464327Sdougm sa_set_optionset_attr(optionset, "type", proto); 26473034Sdougm 26484327Sdougm (void) sa_optionset_name(optionset, oname, 26494327Sdougm sizeof (oname), id); 26504327Sdougm groupname = sa_get_group_attr(parent, "name"); 26515331Samw if (groupname != NULL && sa_is_persistent(group)) { 26524327Sdougm sa_handle_impl_t impl_handle; 26535331Samw impl_handle = 26545331Samw (sa_handle_impl_t)sa_find_group_handle( 26555331Samw group); 26564327Sdougm assert(impl_handle != NULL); 26574327Sdougm if (impl_handle != NULL) { 26584327Sdougm (void) sa_get_instance( 26595331Samw impl_handle->scfhandle, groupname); 26604327Sdougm (void) sa_create_pgroup( 26614327Sdougm impl_handle->scfhandle, oname); 26624327Sdougm } 26634327Sdougm } 26644327Sdougm if (groupname != NULL) 26654327Sdougm sa_free_attr_string(groupname); 26663034Sdougm } 26673034Sdougm } 26685331Samw 26695331Samw if (id != NULL) 26705331Samw sa_free_attr_string(id); 26713034Sdougm return (optionset); 26723034Sdougm } 26733034Sdougm 26743034Sdougm /* 26753034Sdougm * sa_get_property_parent(property) 26763034Sdougm * 26773034Sdougm * Given a property, return the object it is a property of. This will 26783034Sdougm * be an optionset of some type. 26793034Sdougm */ 26803034Sdougm 26813034Sdougm static sa_optionset_t 26823034Sdougm sa_get_property_parent(sa_property_t property) 26833034Sdougm { 26843034Sdougm xmlNodePtr node = NULL; 26853034Sdougm 26864327Sdougm if (property != NULL) 26874327Sdougm node = ((xmlNodePtr)property)->parent; 26883034Sdougm return ((sa_optionset_t)node); 26893034Sdougm } 26903034Sdougm 26913034Sdougm /* 26923034Sdougm * sa_get_optionset_parent(optionset) 26933034Sdougm * 26943034Sdougm * Return the parent of the specified optionset. This could be a group 26953034Sdougm * or a share. 26963034Sdougm */ 26973034Sdougm 26983034Sdougm static sa_group_t 26993034Sdougm sa_get_optionset_parent(sa_optionset_t optionset) 27003034Sdougm { 27013034Sdougm xmlNodePtr node = NULL; 27023034Sdougm 27034327Sdougm if (optionset != NULL) 27044327Sdougm node = ((xmlNodePtr)optionset)->parent; 27053034Sdougm return ((sa_group_t)node); 27063034Sdougm } 27073034Sdougm 27083034Sdougm /* 27093034Sdougm * zfs_needs_update(share) 27103034Sdougm * 27113034Sdougm * In order to avoid making multiple updates to a ZFS share when 27123034Sdougm * setting properties, the share attribute "changed" will be set to 27135331Samw * true when a property is added or modified. When done adding 27143034Sdougm * properties, we can then detect that an update is needed. We then 27153034Sdougm * clear the state here to detect additional changes. 27163034Sdougm */ 27173034Sdougm 27183034Sdougm static int 27193034Sdougm zfs_needs_update(sa_share_t share) 27203034Sdougm { 27213034Sdougm char *attr; 27223034Sdougm int result = 0; 27233034Sdougm 27243034Sdougm attr = sa_get_share_attr(share, "changed"); 27253034Sdougm if (attr != NULL) { 27264327Sdougm sa_free_attr_string(attr); 27273034Sdougm result = 1; 27283034Sdougm } 27293034Sdougm set_node_attr((void *)share, "changed", NULL); 27303034Sdougm return (result); 27313034Sdougm } 27323034Sdougm 27333034Sdougm /* 27343034Sdougm * zfs_set_update(share) 27353034Sdougm * 27363034Sdougm * Set the changed attribute of the share to true. 27373034Sdougm */ 27383034Sdougm 27393034Sdougm static void 27403034Sdougm zfs_set_update(sa_share_t share) 27413034Sdougm { 27423034Sdougm set_node_attr((void *)share, "changed", "true"); 27433034Sdougm } 27443034Sdougm 27453034Sdougm /* 27463034Sdougm * sa_commit_properties(optionset, clear) 27473034Sdougm * 27483034Sdougm * Check if SMF or ZFS config and either update or abort the pending 27493034Sdougm * changes. 27503034Sdougm */ 27513034Sdougm 27523034Sdougm int 27533034Sdougm sa_commit_properties(sa_optionset_t optionset, int clear) 27543034Sdougm { 27553034Sdougm sa_group_t group; 27563034Sdougm sa_group_t parent; 27573034Sdougm int zfs = 0; 27583034Sdougm int needsupdate = 0; 27593034Sdougm int ret = SA_OK; 27603910Sdougm sa_handle_impl_t impl_handle; 27613034Sdougm 27623034Sdougm group = sa_get_optionset_parent(optionset); 27633034Sdougm if (group != NULL && (sa_is_share(group) || is_zfs_group(group))) { 27644327Sdougm /* only update ZFS if on a share */ 27654327Sdougm parent = sa_get_parent_group(group); 27664327Sdougm zfs++; 27674327Sdougm if (parent != NULL && is_zfs_group(parent)) 27684327Sdougm needsupdate = zfs_needs_update(group); 27694327Sdougm else 27704327Sdougm zfs = 0; 27713034Sdougm } 27723034Sdougm if (zfs) { 27734327Sdougm if (!clear && needsupdate) 27744327Sdougm ret = sa_zfs_update((sa_share_t)group); 27753034Sdougm } else { 27764327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 27774327Sdougm if (impl_handle != NULL) { 27784327Sdougm if (clear) { 27794327Sdougm (void) sa_abort_transaction( 27804327Sdougm impl_handle->scfhandle); 27814327Sdougm } else { 27824327Sdougm ret = sa_end_transaction( 27835951Sdougm impl_handle->scfhandle, impl_handle); 27844327Sdougm } 27854327Sdougm } else { 27864327Sdougm ret = SA_SYSTEM_ERR; 27874327Sdougm } 27883034Sdougm } 27893034Sdougm return (ret); 27903034Sdougm } 27913034Sdougm 27923034Sdougm /* 27933034Sdougm * sa_destroy_optionset(optionset) 27943034Sdougm * 27955331Samw * Remove the optionset from its group. Update the repository to 27963034Sdougm * reflect this change. 27973034Sdougm */ 27983034Sdougm 27993034Sdougm int 28003034Sdougm sa_destroy_optionset(sa_optionset_t optionset) 28013034Sdougm { 28024327Sdougm char name[SA_STRSIZE]; 28033034Sdougm int len; 28043034Sdougm int ret; 28053034Sdougm char *id = NULL; 28063034Sdougm sa_group_t group; 28073034Sdougm int ispersist = 1; 28083034Sdougm 28093034Sdougm /* now delete the prop group */ 28103034Sdougm group = sa_get_optionset_parent(optionset); 28115331Samw if (group != NULL) { 28125331Samw if (sa_is_resource(group)) { 28135331Samw sa_resource_t resource = group; 28145331Samw sa_share_t share = sa_get_resource_parent(resource); 28155331Samw group = sa_get_parent_group(share); 28165331Samw id = sa_get_share_attr(share, "id"); 28175331Samw } else if (sa_is_share(group)) { 28185331Samw id = sa_get_share_attr((sa_share_t)group, "id"); 28195331Samw } 28205331Samw ispersist = sa_is_persistent(group); 28213034Sdougm } 28223034Sdougm if (ispersist) { 28234327Sdougm sa_handle_impl_t impl_handle; 28244327Sdougm len = sa_optionset_name(optionset, name, sizeof (name), id); 28254327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 28264327Sdougm if (impl_handle != NULL) { 28274327Sdougm if (len > 0) { 28284327Sdougm ret = sa_delete_pgroup(impl_handle->scfhandle, 28294327Sdougm name); 28304327Sdougm } 28314327Sdougm } else { 28324327Sdougm ret = SA_SYSTEM_ERR; 28333910Sdougm } 28343034Sdougm } 28353034Sdougm xmlUnlinkNode((xmlNodePtr)optionset); 28363034Sdougm xmlFreeNode((xmlNodePtr)optionset); 28373034Sdougm if (id != NULL) 28384327Sdougm sa_free_attr_string(id); 28393034Sdougm return (ret); 28403034Sdougm } 28413034Sdougm 28423034Sdougm /* private to the implementation */ 28433034Sdougm int 28443034Sdougm _sa_remove_optionset(sa_optionset_t optionset) 28453034Sdougm { 28463034Sdougm int ret = SA_OK; 28473034Sdougm 28483034Sdougm xmlUnlinkNode((xmlNodePtr)optionset); 28493034Sdougm xmlFreeNode((xmlNodePtr)optionset); 28503034Sdougm return (ret); 28513034Sdougm } 28523034Sdougm 28533034Sdougm /* 28543034Sdougm * sa_create_security(group, sectype, proto) 28553034Sdougm * 28563034Sdougm * Create a security optionset (one that has a type name and a 28573034Sdougm * proto). Security is left over from a pure NFS implementation. The 28583034Sdougm * naming will change in the future when the API is released. 28593034Sdougm */ 28603034Sdougm sa_security_t 28613034Sdougm sa_create_security(sa_group_t group, char *sectype, char *proto) 28623034Sdougm { 28633034Sdougm sa_security_t security; 28643034Sdougm char *id = NULL; 28653034Sdougm sa_group_t parent; 28663034Sdougm char *groupname = NULL; 28673034Sdougm 28683034Sdougm if (group != NULL && sa_is_share(group)) { 28694327Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 28704327Sdougm parent = sa_get_parent_group(group); 28714327Sdougm if (parent != NULL) 28724327Sdougm groupname = sa_get_group_attr(parent, "name"); 28733034Sdougm } else if (group != NULL) { 28744327Sdougm groupname = sa_get_group_attr(group, "name"); 28753034Sdougm } 28763034Sdougm 28773034Sdougm security = sa_get_security(group, sectype, proto); 28783034Sdougm if (security != NULL) { 28793034Sdougm /* can't have a duplicate security option */ 28803034Sdougm security = NULL; 28813034Sdougm } else { 28823034Sdougm security = (sa_security_t)xmlNewChild((xmlNodePtr)group, 28834327Sdougm NULL, (xmlChar *)"security", NULL); 28843034Sdougm if (security != NULL) { 28854327Sdougm char oname[SA_STRSIZE]; 28863034Sdougm sa_set_security_attr(security, "type", proto); 28873034Sdougm 28883034Sdougm sa_set_security_attr(security, "sectype", sectype); 28893034Sdougm (void) sa_security_name(security, oname, 28904327Sdougm sizeof (oname), id); 28915331Samw if (groupname != NULL && sa_is_persistent(group)) { 28924327Sdougm sa_handle_impl_t impl_handle; 28934327Sdougm impl_handle = 28944327Sdougm (sa_handle_impl_t)sa_find_group_handle( 28954327Sdougm group); 28964327Sdougm if (impl_handle != NULL) { 28974327Sdougm (void) sa_get_instance( 28984327Sdougm impl_handle->scfhandle, groupname); 28994327Sdougm (void) sa_create_pgroup( 29004327Sdougm impl_handle->scfhandle, oname); 29014327Sdougm } 29023034Sdougm } 29033034Sdougm } 29043034Sdougm } 290511337SWilliam.Krier@Sun.COM if (id != NULL) 290611337SWilliam.Krier@Sun.COM sa_free_attr_string(id); 29073034Sdougm if (groupname != NULL) 29084327Sdougm sa_free_attr_string(groupname); 29093034Sdougm return (security); 29103034Sdougm } 29113034Sdougm 29123034Sdougm /* 29133034Sdougm * sa_destroy_security(security) 29143034Sdougm * 29153034Sdougm * Remove the specified optionset from the document and the 29163034Sdougm * configuration. 29173034Sdougm */ 29183034Sdougm 29193034Sdougm int 29203034Sdougm sa_destroy_security(sa_security_t security) 29213034Sdougm { 29224327Sdougm char name[SA_STRSIZE]; 29233034Sdougm int len; 29243034Sdougm int ret = SA_OK; 29253034Sdougm char *id = NULL; 29263034Sdougm sa_group_t group; 29273034Sdougm int iszfs = 0; 29283034Sdougm int ispersist = 1; 29293034Sdougm 29303034Sdougm group = sa_get_optionset_parent(security); 29313034Sdougm 29323034Sdougm if (group != NULL) 29334327Sdougm iszfs = sa_group_is_zfs(group); 29343034Sdougm 29353034Sdougm if (group != NULL && !iszfs) { 29364327Sdougm if (sa_is_share(group)) 29375331Samw ispersist = sa_is_persistent(group); 29384327Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 29393034Sdougm } 29403034Sdougm if (ispersist) { 29414327Sdougm len = sa_security_name(security, name, sizeof (name), id); 29424327Sdougm if (!iszfs && len > 0) { 29434327Sdougm sa_handle_impl_t impl_handle; 29444327Sdougm impl_handle = 29454327Sdougm (sa_handle_impl_t)sa_find_group_handle(group); 29464327Sdougm if (impl_handle != NULL) { 29474327Sdougm ret = sa_delete_pgroup(impl_handle->scfhandle, 29484327Sdougm name); 29494327Sdougm } else { 29504327Sdougm ret = SA_SYSTEM_ERR; 29514327Sdougm } 29523910Sdougm } 29533034Sdougm } 29543034Sdougm xmlUnlinkNode((xmlNodePtr)security); 29553034Sdougm xmlFreeNode((xmlNodePtr)security); 29564327Sdougm if (iszfs) 29574327Sdougm ret = sa_zfs_update(group); 29583034Sdougm if (id != NULL) 29594327Sdougm sa_free_attr_string(id); 29603034Sdougm return (ret); 29613034Sdougm } 29623034Sdougm 29633034Sdougm /* 29643034Sdougm * sa_get_security_attr(optionset, tag) 29653034Sdougm * 29663034Sdougm * Return the specified attribute value from the optionset. 29673034Sdougm */ 29683034Sdougm 29693034Sdougm char * 29703034Sdougm sa_get_security_attr(sa_property_t optionset, char *tag) 29713034Sdougm { 29723034Sdougm return (get_node_attr((void *)optionset, tag)); 29733034Sdougm 29743034Sdougm } 29753034Sdougm 29763034Sdougm /* 29773034Sdougm * sa_set_security_attr(optionset, tag, value) 29783034Sdougm * 29793034Sdougm * Set the optioset attribute specied by tag to the specified value. 29803034Sdougm */ 29813034Sdougm 29823034Sdougm void 29833034Sdougm sa_set_security_attr(sa_group_t optionset, char *tag, char *value) 29843034Sdougm { 29853034Sdougm set_node_attr((void *)optionset, tag, value); 29863034Sdougm } 29873034Sdougm 29883034Sdougm /* 29893034Sdougm * is_nodetype(node, type) 29903034Sdougm * 29913034Sdougm * Check to see if node is of the type specified. 29923034Sdougm */ 29933034Sdougm 29943034Sdougm static int 29953034Sdougm is_nodetype(void *node, char *type) 29963034Sdougm { 29973034Sdougm return (strcmp((char *)((xmlNodePtr)node)->name, type) == 0); 29983034Sdougm } 29993034Sdougm 30004327Sdougm /* 30014327Sdougm * add_or_update() 30024327Sdougm * 30034327Sdougm * Add or update a property. Pulled out of sa_set_prop_by_prop for 30044327Sdougm * readability. 30054327Sdougm */ 30064327Sdougm static int 30074327Sdougm add_or_update(scfutilhandle_t *scf_handle, int type, scf_value_t *value, 30084327Sdougm scf_transaction_entry_t *entry, char *name, char *valstr) 30094327Sdougm { 30104327Sdougm int ret = SA_SYSTEM_ERR; 30114327Sdougm 30124327Sdougm if (value != NULL) { 30134327Sdougm if (type == SA_PROP_OP_ADD) 30144327Sdougm ret = scf_transaction_property_new(scf_handle->trans, 30154327Sdougm entry, name, SCF_TYPE_ASTRING); 30164327Sdougm else 30174327Sdougm ret = scf_transaction_property_change(scf_handle->trans, 30184327Sdougm entry, name, SCF_TYPE_ASTRING); 30194327Sdougm if (ret == 0) { 30204327Sdougm ret = scf_value_set_astring(value, valstr); 30214327Sdougm if (ret == 0) 30224327Sdougm ret = scf_entry_add_value(entry, value); 30234327Sdougm if (ret == 0) 30244327Sdougm return (ret); 30254327Sdougm scf_value_destroy(value); 30264327Sdougm } else { 30274327Sdougm scf_entry_destroy(entry); 30284327Sdougm } 30294327Sdougm } 30304327Sdougm return (SA_SYSTEM_ERR); 30314327Sdougm } 30324327Sdougm 30333034Sdougm /* 30343034Sdougm * sa_set_prop_by_prop(optionset, group, prop, type) 30353034Sdougm * 30363034Sdougm * Add/remove/update the specified property prop into the optionset or 30373034Sdougm * share. If a share, sort out which property group based on GUID. In 30383034Sdougm * all cases, the appropriate transaction is set (or ZFS share is 30393034Sdougm * marked as needing an update) 30403034Sdougm */ 30413034Sdougm 30423034Sdougm static int 30433034Sdougm sa_set_prop_by_prop(sa_optionset_t optionset, sa_group_t group, 30443034Sdougm sa_property_t prop, int type) 30453034Sdougm { 30463034Sdougm char *name; 30473034Sdougm char *valstr; 30483034Sdougm int ret = SA_OK; 30493034Sdougm scf_transaction_entry_t *entry; 30503034Sdougm scf_value_t *value; 30513034Sdougm int opttype; /* 1 == optionset, 0 == security */ 30523034Sdougm char *id = NULL; 30533034Sdougm int iszfs = 0; 30543034Sdougm sa_group_t parent = NULL; 30555331Samw sa_share_t share = NULL; 30563910Sdougm sa_handle_impl_t impl_handle; 30573910Sdougm scfutilhandle_t *scf_handle; 30583034Sdougm 30595331Samw if (!sa_is_persistent(group)) { 30603034Sdougm /* 30613034Sdougm * if the group/share is not persistent we don't need 30623034Sdougm * to do anything here 30633034Sdougm */ 30644327Sdougm return (SA_OK); 30653034Sdougm } 30663910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 30674327Sdougm if (impl_handle == NULL || impl_handle->scfhandle == NULL) 30684327Sdougm return (SA_SYSTEM_ERR); 30693910Sdougm scf_handle = impl_handle->scfhandle; 30703034Sdougm name = sa_get_property_attr(prop, "type"); 30713034Sdougm valstr = sa_get_property_attr(prop, "value"); 30723034Sdougm entry = scf_entry_create(scf_handle->handle); 30733034Sdougm opttype = is_nodetype((void *)optionset, "optionset"); 30743034Sdougm 30755331Samw /* 30765331Samw * Check for share vs. resource since they need slightly 30775331Samw * different treatment given the hierarchy. 30785331Samw */ 30793034Sdougm if (valstr != NULL && entry != NULL) { 30804327Sdougm if (sa_is_share(group)) { 30814327Sdougm parent = sa_get_parent_group(group); 30825331Samw share = (sa_share_t)group; 30834327Sdougm if (parent != NULL) 30844327Sdougm iszfs = is_zfs_group(parent); 30855331Samw } else if (sa_is_resource(group)) { 30865331Samw share = sa_get_parent_group(group); 30875331Samw if (share != NULL) 30885331Samw parent = sa_get_parent_group(share); 30894327Sdougm } else { 30904327Sdougm iszfs = is_zfs_group(group); 30913034Sdougm } 30924327Sdougm if (!iszfs) { 30934327Sdougm if (scf_handle->trans == NULL) { 30944327Sdougm char oname[SA_STRSIZE]; 30954327Sdougm char *groupname = NULL; 30965331Samw if (share != NULL) { 30975331Samw if (parent != NULL) 30984327Sdougm groupname = 30994327Sdougm sa_get_group_attr(parent, 31004327Sdougm "name"); 31015331Samw id = sa_get_share_attr( 31025331Samw (sa_share_t)share, "id"); 31034327Sdougm } else { 31044327Sdougm groupname = sa_get_group_attr(group, 31054327Sdougm "name"); 31064327Sdougm } 31074327Sdougm if (groupname != NULL) { 31084327Sdougm ret = sa_get_instance(scf_handle, 31094327Sdougm groupname); 31104327Sdougm sa_free_attr_string(groupname); 31114327Sdougm } 31124327Sdougm if (opttype) 31134327Sdougm (void) sa_optionset_name(optionset, 31144327Sdougm oname, sizeof (oname), id); 31154327Sdougm else 31164327Sdougm (void) sa_security_name(optionset, 31174327Sdougm oname, sizeof (oname), id); 31184327Sdougm ret = sa_start_transaction(scf_handle, oname); 311911337SWilliam.Krier@Sun.COM if (id != NULL) 312011337SWilliam.Krier@Sun.COM sa_free_attr_string(id); 31213910Sdougm } 31224327Sdougm if (ret == SA_OK) { 31234327Sdougm switch (type) { 31244327Sdougm case SA_PROP_OP_REMOVE: 31254327Sdougm ret = scf_transaction_property_delete( 31264327Sdougm scf_handle->trans, entry, name); 31274327Sdougm break; 31284327Sdougm case SA_PROP_OP_ADD: 31294327Sdougm case SA_PROP_OP_UPDATE: 31304327Sdougm value = scf_value_create( 31314327Sdougm scf_handle->handle); 31324327Sdougm ret = add_or_update(scf_handle, type, 31334327Sdougm value, entry, name, valstr); 31344327Sdougm break; 31353034Sdougm } 31363034Sdougm } 31374327Sdougm } else { 31384327Sdougm /* 31394327Sdougm * ZFS update. The calling function would have updated 31404327Sdougm * the internal XML structure. Just need to flag it as 31414327Sdougm * changed for ZFS. 31424327Sdougm */ 31434327Sdougm zfs_set_update((sa_share_t)group); 31444327Sdougm } 31453034Sdougm } 31463034Sdougm 31473034Sdougm if (name != NULL) 31484327Sdougm sa_free_attr_string(name); 31493034Sdougm if (valstr != NULL) 31504327Sdougm sa_free_attr_string(valstr); 31513034Sdougm else if (entry != NULL) 31524327Sdougm scf_entry_destroy(entry); 31533034Sdougm 31543034Sdougm if (ret == -1) 31554327Sdougm ret = SA_SYSTEM_ERR; 31563034Sdougm 31573034Sdougm return (ret); 31583034Sdougm } 31593034Sdougm 31603034Sdougm /* 31616007Sthurlow * sa_create_section(name, value) 31626007Sthurlow * 31636007Sthurlow * Create a new section with the specified name and extra data. 31646007Sthurlow */ 31656007Sthurlow 31666007Sthurlow sa_property_t 31676007Sthurlow sa_create_section(char *name, char *extra) 31686007Sthurlow { 31696007Sthurlow xmlNodePtr node; 31706007Sthurlow 31716007Sthurlow node = xmlNewNode(NULL, (xmlChar *)"section"); 31726007Sthurlow if (node != NULL) { 31736007Sthurlow if (name != NULL) 31746007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 31756007Sthurlow (xmlChar *)name); 31766007Sthurlow if (extra != NULL) 31776007Sthurlow (void) xmlSetProp(node, (xmlChar *)"extra", 31786007Sthurlow (xmlChar *)extra); 31796007Sthurlow } 31806007Sthurlow return ((sa_property_t)node); 31816007Sthurlow } 31826007Sthurlow 31836007Sthurlow void 31846007Sthurlow sa_set_section_attr(sa_property_t sect, char *name, char *value) 31856007Sthurlow { 31866007Sthurlow (void) xmlSetProp(sect, (xmlChar *)name, (xmlChar *)value); 31876007Sthurlow } 31886007Sthurlow 31896007Sthurlow /* 31906007Sthurlow * sa_create_property(section, name, value) 31913034Sdougm * 31923034Sdougm * Create a new property with the specified name and value. 31933034Sdougm */ 31943034Sdougm 31953034Sdougm sa_property_t 31963034Sdougm sa_create_property(char *name, char *value) 31973034Sdougm { 31983034Sdougm xmlNodePtr node; 31993034Sdougm 32003034Sdougm node = xmlNewNode(NULL, (xmlChar *)"option"); 32013034Sdougm if (node != NULL) { 32026007Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", (xmlChar *)name); 32036007Sthurlow (void) xmlSetProp(node, (xmlChar *)"value", (xmlChar *)value); 32043034Sdougm } 32053034Sdougm return ((sa_property_t)node); 32063034Sdougm } 32073034Sdougm 32083034Sdougm /* 32093034Sdougm * sa_add_property(object, property) 32103034Sdougm * 32113034Sdougm * Add the specified property to the object. Issue the appropriate 32123034Sdougm * transaction or mark a ZFS object as needing an update. 32133034Sdougm */ 32143034Sdougm 32153034Sdougm int 32163034Sdougm sa_add_property(void *object, sa_property_t property) 32173034Sdougm { 32183034Sdougm int ret = SA_OK; 32193034Sdougm sa_group_t parent; 32203034Sdougm sa_group_t group; 32213034Sdougm char *proto; 32226214Sdougm 32233034Sdougm if (property != NULL) { 32246271Sdougm sa_handle_t handle; 32256214Sdougm handle = sa_find_group_handle((sa_group_t)object); 32266271Sdougm /* It is legitimate to not find a handle */ 32276214Sdougm proto = sa_get_optionset_attr(object, "type"); 32286214Sdougm if ((ret = sa_valid_property(handle, object, proto, 32296214Sdougm property)) == SA_OK) { 32304327Sdougm property = (sa_property_t)xmlAddChild( 32314327Sdougm (xmlNodePtr)object, (xmlNodePtr)property); 32324327Sdougm } else { 32334327Sdougm if (proto != NULL) 32344327Sdougm sa_free_attr_string(proto); 32354327Sdougm return (ret); 32364327Sdougm } 32376214Sdougm if (proto != NULL) 32386214Sdougm sa_free_attr_string(proto); 32393034Sdougm } 32403034Sdougm 32413034Sdougm 32423034Sdougm parent = sa_get_parent_group(object); 32435331Samw if (!sa_is_persistent(parent)) 32444327Sdougm return (ret); 32455331Samw 32465331Samw if (sa_is_resource(parent)) { 32475331Samw /* 32485331Samw * Resources are children of share. Need to go up two 32495331Samw * levels to find the group but the parent needs to be 32505331Samw * the share at this point in order to get the "id". 32515331Samw */ 32525331Samw parent = sa_get_parent_group(parent); 32535331Samw group = sa_get_parent_group(parent); 32545331Samw } else if (sa_is_share(parent)) { 32555331Samw group = sa_get_parent_group(parent); 32565331Samw } else { 32575331Samw group = parent; 32583034Sdougm } 32593034Sdougm 32604327Sdougm if (property == NULL) { 32614327Sdougm ret = SA_NO_MEMORY; 32624327Sdougm } else { 32634327Sdougm char oname[SA_STRSIZE]; 32643034Sdougm 32654327Sdougm if (!is_zfs_group(group)) { 32664327Sdougm char *id = NULL; 32674327Sdougm sa_handle_impl_t impl_handle; 32684327Sdougm scfutilhandle_t *scf_handle; 32693910Sdougm 32704327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle( 32714327Sdougm group); 32724327Sdougm if (impl_handle == NULL || 32734327Sdougm impl_handle->scfhandle == NULL) 32744327Sdougm ret = SA_SYSTEM_ERR; 32754327Sdougm if (ret == SA_OK) { 32764327Sdougm scf_handle = impl_handle->scfhandle; 32774327Sdougm if (sa_is_share((sa_group_t)parent)) { 32784327Sdougm id = sa_get_share_attr( 32794327Sdougm (sa_share_t)parent, "id"); 32804327Sdougm } 32814327Sdougm if (scf_handle->trans == NULL) { 32824327Sdougm if (is_nodetype(object, "optionset")) { 32834327Sdougm (void) sa_optionset_name( 32844327Sdougm (sa_optionset_t)object, 32854327Sdougm oname, sizeof (oname), id); 32864327Sdougm } else { 32874327Sdougm (void) sa_security_name( 32884327Sdougm (sa_optionset_t)object, 32894327Sdougm oname, sizeof (oname), id); 32904327Sdougm } 32914327Sdougm ret = sa_start_transaction(scf_handle, 32924327Sdougm oname); 32934327Sdougm } 32944327Sdougm if (ret == SA_OK) { 32954327Sdougm char *name; 32964327Sdougm char *value; 32974327Sdougm name = sa_get_property_attr(property, 32984327Sdougm "type"); 32994327Sdougm value = sa_get_property_attr(property, 33004327Sdougm "value"); 33014327Sdougm if (name != NULL && value != NULL) { 33024327Sdougm if (scf_handle->scf_state == 33034327Sdougm SCH_STATE_INIT) { 33044327Sdougm ret = sa_set_property( 33054327Sdougm scf_handle, name, 33064327Sdougm value); 33074327Sdougm } 33084327Sdougm } else { 33094327Sdougm ret = SA_CONFIG_ERR; 33104327Sdougm } 33114327Sdougm if (name != NULL) 33124327Sdougm sa_free_attr_string( 33134327Sdougm name); 33144327Sdougm if (value != NULL) 33154327Sdougm sa_free_attr_string(value); 33164327Sdougm } 33174327Sdougm if (id != NULL) 33184327Sdougm sa_free_attr_string(id); 33194327Sdougm } 33204327Sdougm } else { 33214327Sdougm /* 33224327Sdougm * ZFS is a special case. We do want 33234327Sdougm * to allow editing property/security 33244327Sdougm * lists since we can have a better 33254327Sdougm * syntax and we also want to keep 33264327Sdougm * things consistent when possible. 33274327Sdougm * 33284327Sdougm * Right now, we defer until the 33294327Sdougm * sa_commit_properties so we can get 33304327Sdougm * them all at once. We do need to 33314327Sdougm * mark the share as "changed" 33324327Sdougm */ 33334327Sdougm zfs_set_update((sa_share_t)parent); 33343034Sdougm } 33353034Sdougm } 33363034Sdougm return (ret); 33373034Sdougm } 33383034Sdougm 33393034Sdougm /* 33403034Sdougm * sa_remove_property(property) 33413034Sdougm * 33423034Sdougm * Remove the specied property from its containing object. Update the 33433034Sdougm * repository as appropriate. 33443034Sdougm */ 33453034Sdougm 33463034Sdougm int 33473034Sdougm sa_remove_property(sa_property_t property) 33483034Sdougm { 33493034Sdougm int ret = SA_OK; 33503034Sdougm 33513034Sdougm if (property != NULL) { 33523034Sdougm sa_optionset_t optionset; 33533034Sdougm sa_group_t group; 33543034Sdougm optionset = sa_get_property_parent(property); 33553034Sdougm if (optionset != NULL) { 33564327Sdougm group = sa_get_optionset_parent(optionset); 33574327Sdougm if (group != NULL) { 33584327Sdougm ret = sa_set_prop_by_prop(optionset, group, 33594327Sdougm property, SA_PROP_OP_REMOVE); 33604327Sdougm } 33613034Sdougm } 33623034Sdougm xmlUnlinkNode((xmlNodePtr)property); 33633034Sdougm xmlFreeNode((xmlNodePtr)property); 33643034Sdougm } else { 33654327Sdougm ret = SA_NO_SUCH_PROP; 33663034Sdougm } 33673034Sdougm return (ret); 33683034Sdougm } 33693034Sdougm 33703034Sdougm /* 33713034Sdougm * sa_update_property(property, value) 33723034Sdougm * 33733034Sdougm * Update the specified property to the new value. If value is NULL, 33743034Sdougm * we currently treat this as a remove. 33753034Sdougm */ 33763034Sdougm 33773034Sdougm int 33783034Sdougm sa_update_property(sa_property_t property, char *value) 33793034Sdougm { 33803034Sdougm int ret = SA_OK; 33813034Sdougm if (value == NULL) { 33823034Sdougm return (sa_remove_property(property)); 33833034Sdougm } else { 33843034Sdougm sa_optionset_t optionset; 33853034Sdougm sa_group_t group; 33863034Sdougm set_node_attr((void *)property, "value", value); 33873034Sdougm optionset = sa_get_property_parent(property); 33883034Sdougm if (optionset != NULL) { 33894327Sdougm group = sa_get_optionset_parent(optionset); 33904327Sdougm if (group != NULL) { 33914327Sdougm ret = sa_set_prop_by_prop(optionset, group, 33924327Sdougm property, SA_PROP_OP_UPDATE); 33934327Sdougm } 33943034Sdougm } else { 33954327Sdougm ret = SA_NO_SUCH_PROP; 33963034Sdougm } 33973034Sdougm } 33983034Sdougm return (ret); 33993034Sdougm } 34003034Sdougm 34013034Sdougm /* 34026007Sthurlow * sa_get_protocol_section(propset, prop) 34036007Sthurlow * 34046007Sthurlow * Get the specified protocol specific section. These are global to 34056007Sthurlow * the protocol and not specific to a group or share. 34066007Sthurlow */ 34076007Sthurlow 34086007Sthurlow sa_protocol_properties_t 34096007Sthurlow sa_get_protocol_section(sa_protocol_properties_t propset, char *section) 34106007Sthurlow { 34116007Sthurlow xmlNodePtr node = (xmlNodePtr)propset; 34126007Sthurlow xmlChar *value = NULL; 34136007Sthurlow char *proto; 34146007Sthurlow 34156007Sthurlow proto = sa_get_optionset_attr(propset, "type"); 34168271SGordon.Ross@Sun.COM if ((sa_proto_get_featureset(proto) & SA_FEATURE_HAS_SECTIONS) == 0) { 34178271SGordon.Ross@Sun.COM if (proto != NULL) 34188271SGordon.Ross@Sun.COM sa_free_attr_string(proto); 34196007Sthurlow return (propset); 34208271SGordon.Ross@Sun.COM } 34216007Sthurlow 34226007Sthurlow for (node = node->children; node != NULL; 34236007Sthurlow node = node->next) { 34246007Sthurlow if (xmlStrcmp(node->name, (xmlChar *)"section") == 0) { 34256007Sthurlow if (section == NULL) 34266007Sthurlow break; 34276007Sthurlow value = xmlGetProp(node, (xmlChar *)"name"); 34286007Sthurlow if (value != NULL && 34296007Sthurlow xmlStrcasecmp(value, (xmlChar *)section) == 0) { 34306007Sthurlow break; 34316007Sthurlow } 34326007Sthurlow if (value != NULL) { 34336007Sthurlow xmlFree(value); 34346007Sthurlow value = NULL; 34356007Sthurlow } 34366007Sthurlow } 34376007Sthurlow } 34386007Sthurlow if (value != NULL) 34396007Sthurlow xmlFree(value); 34408271SGordon.Ross@Sun.COM if (proto != NULL) 34418271SGordon.Ross@Sun.COM sa_free_attr_string(proto); 34426007Sthurlow if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"section") != 0) { 34436007Sthurlow /* 34446007Sthurlow * avoid a non option node -- it is possible to be a 34456007Sthurlow * text node 34466007Sthurlow */ 34476007Sthurlow node = NULL; 34486007Sthurlow } 34496007Sthurlow return ((sa_protocol_properties_t)node); 34506007Sthurlow } 34516007Sthurlow 34526007Sthurlow /* 34536007Sthurlow * sa_get_next_protocol_section(prop, find) 34546007Sthurlow * 34556007Sthurlow * Get the next protocol specific section in the list. 34566007Sthurlow */ 34576007Sthurlow 34586007Sthurlow sa_property_t 34596007Sthurlow sa_get_next_protocol_section(sa_property_t prop, char *find) 34606007Sthurlow { 34616007Sthurlow xmlNodePtr node; 34626007Sthurlow xmlChar *value = NULL; 34636007Sthurlow char *proto; 34646007Sthurlow 34656007Sthurlow proto = sa_get_optionset_attr(prop, "type"); 34668271SGordon.Ross@Sun.COM if ((sa_proto_get_featureset(proto) & SA_FEATURE_HAS_SECTIONS) == 0) { 34678271SGordon.Ross@Sun.COM if (proto != NULL) 34688271SGordon.Ross@Sun.COM sa_free_attr_string(proto); 34696007Sthurlow return ((sa_property_t)NULL); 34708271SGordon.Ross@Sun.COM } 34716007Sthurlow 34726007Sthurlow for (node = ((xmlNodePtr)prop)->next; node != NULL; 34736007Sthurlow node = node->next) { 34746007Sthurlow if (xmlStrcmp(node->name, (xmlChar *)"section") == 0) { 34756007Sthurlow if (find == NULL) 34766007Sthurlow break; 34776007Sthurlow value = xmlGetProp(node, (xmlChar *)"name"); 34786007Sthurlow if (value != NULL && 34796007Sthurlow xmlStrcasecmp(value, (xmlChar *)find) == 0) { 34806007Sthurlow break; 34816007Sthurlow } 34826007Sthurlow if (value != NULL) { 34836007Sthurlow xmlFree(value); 34846007Sthurlow value = NULL; 34856007Sthurlow } 34866007Sthurlow 34876007Sthurlow } 34886007Sthurlow } 34896007Sthurlow if (value != NULL) 34906007Sthurlow xmlFree(value); 34918271SGordon.Ross@Sun.COM if (proto != NULL) 34928271SGordon.Ross@Sun.COM sa_free_attr_string(proto); 34936007Sthurlow return ((sa_property_t)node); 34946007Sthurlow } 34956007Sthurlow 34966007Sthurlow /* 34973034Sdougm * sa_get_protocol_property(propset, prop) 34983034Sdougm * 34993034Sdougm * Get the specified protocol specific property. These are global to 35003034Sdougm * the protocol and not specific to a group or share. 35013034Sdougm */ 35023034Sdougm 35033034Sdougm sa_property_t 35043034Sdougm sa_get_protocol_property(sa_protocol_properties_t propset, char *prop) 35053034Sdougm { 35063034Sdougm xmlNodePtr node = (xmlNodePtr)propset; 35073034Sdougm xmlChar *value = NULL; 35083034Sdougm 35096007Sthurlow if (propset == NULL) 35106007Sthurlow return (NULL); 35116007Sthurlow 35123034Sdougm for (node = node->children; node != NULL; 35134327Sdougm node = node->next) { 35144327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 35154327Sdougm if (prop == NULL) 35164327Sdougm break; 35174327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 35184327Sdougm if (value != NULL && 35194327Sdougm xmlStrcasecmp(value, (xmlChar *)prop) == 0) { 35204327Sdougm break; 35214327Sdougm } 35224327Sdougm if (value != NULL) { 35234327Sdougm xmlFree(value); 35244327Sdougm value = NULL; 35254327Sdougm } 35263034Sdougm } 35273034Sdougm } 35283034Sdougm if (value != NULL) 35293034Sdougm xmlFree(value); 35303034Sdougm if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"option") != 0) { 35314327Sdougm /* 35324327Sdougm * avoid a non option node -- it is possible to be a 35334327Sdougm * text node 35344327Sdougm */ 35354327Sdougm node = NULL; 35363034Sdougm } 35373034Sdougm return ((sa_property_t)node); 35383034Sdougm } 35393034Sdougm 35403034Sdougm /* 35413034Sdougm * sa_get_next_protocol_property(prop) 35423034Sdougm * 35433034Sdougm * Get the next protocol specific property in the list. 35443034Sdougm */ 35453034Sdougm 35463034Sdougm sa_property_t 35476007Sthurlow sa_get_next_protocol_property(sa_property_t prop, char *find) 35483034Sdougm { 35493034Sdougm xmlNodePtr node; 35506007Sthurlow xmlChar *value = NULL; 35513034Sdougm 35523034Sdougm for (node = ((xmlNodePtr)prop)->next; node != NULL; 35534327Sdougm node = node->next) { 35543034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 35556007Sthurlow if (find == NULL) 35566007Sthurlow break; 35576007Sthurlow value = xmlGetProp(node, (xmlChar *)"type"); 35586007Sthurlow if (value != NULL && 35596007Sthurlow xmlStrcasecmp(value, (xmlChar *)find) == 0) { 35606007Sthurlow break; 35616007Sthurlow } 35626007Sthurlow if (value != NULL) { 35636007Sthurlow xmlFree(value); 35646007Sthurlow value = NULL; 35656007Sthurlow } 35666007Sthurlow 35673034Sdougm } 35683034Sdougm } 35696007Sthurlow if (value != NULL) 35706007Sthurlow xmlFree(value); 35713034Sdougm return ((sa_property_t)node); 35723034Sdougm } 35733034Sdougm 35743034Sdougm /* 35753034Sdougm * sa_set_protocol_property(prop, value) 35763034Sdougm * 35773034Sdougm * Set the specified property to have the new value. The protocol 35783034Sdougm * specific plugin will then be called to update the property. 35793034Sdougm */ 35803034Sdougm 35813034Sdougm int 35826007Sthurlow sa_set_protocol_property(sa_property_t prop, char *section, char *value) 35833034Sdougm { 35843034Sdougm sa_protocol_properties_t propset; 35853034Sdougm char *proto; 35863034Sdougm int ret = SA_INVALID_PROTOCOL; 35873034Sdougm 35883034Sdougm propset = ((xmlNodePtr)prop)->parent; 35893034Sdougm if (propset != NULL) { 35904327Sdougm proto = sa_get_optionset_attr(propset, "type"); 35914327Sdougm if (proto != NULL) { 35926007Sthurlow if (section != NULL) 35936007Sthurlow set_node_attr((xmlNodePtr)prop, "section", 35946007Sthurlow section); 35954327Sdougm set_node_attr((xmlNodePtr)prop, "value", value); 35964327Sdougm ret = sa_proto_set_property(proto, prop); 35974327Sdougm sa_free_attr_string(proto); 35984327Sdougm } 35993034Sdougm } 36003034Sdougm return (ret); 36013034Sdougm } 36023034Sdougm 36033034Sdougm /* 36043034Sdougm * sa_add_protocol_property(propset, prop) 36053034Sdougm * 36065331Samw * Add a new property to the protocol specific property set. 36073034Sdougm */ 36083034Sdougm 36093034Sdougm int 36103034Sdougm sa_add_protocol_property(sa_protocol_properties_t propset, sa_property_t prop) 36113034Sdougm { 36123034Sdougm xmlNodePtr node; 36133034Sdougm 36143034Sdougm /* should check for legitimacy */ 36153034Sdougm node = xmlAddChild((xmlNodePtr)propset, (xmlNodePtr)prop); 36163034Sdougm if (node != NULL) 36174327Sdougm return (SA_OK); 36183034Sdougm return (SA_NO_MEMORY); 36193034Sdougm } 36203034Sdougm 36213034Sdougm /* 36223034Sdougm * sa_create_protocol_properties(proto) 36233034Sdougm * 36245331Samw * Create a protocol specific property set. 36253034Sdougm */ 36263034Sdougm 36273034Sdougm sa_protocol_properties_t 36283034Sdougm sa_create_protocol_properties(char *proto) 36293034Sdougm { 36303034Sdougm xmlNodePtr node; 36314327Sdougm 36323034Sdougm node = xmlNewNode(NULL, (xmlChar *)"propertyset"); 36334327Sdougm if (node != NULL) 36346007Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto); 36353034Sdougm return (node); 36363034Sdougm } 36375331Samw 36385331Samw /* 36395331Samw * sa_get_share_resource(share, resource) 36405331Samw * 36415331Samw * Get the named resource from the share, if it exists. If resource is 36425331Samw * NULL, get the first resource. 36435331Samw */ 36445331Samw 36455331Samw sa_resource_t 36465331Samw sa_get_share_resource(sa_share_t share, char *resource) 36475331Samw { 36485331Samw xmlNodePtr node = NULL; 36495331Samw xmlChar *name; 36505331Samw 36515331Samw if (share != NULL) { 36525331Samw for (node = ((xmlNodePtr)share)->children; node != NULL; 36535331Samw node = node->next) { 36545331Samw if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0) { 36555331Samw if (resource == NULL) { 36565331Samw /* 36575331Samw * We are looking for the first 36585331Samw * resource node and not a names 36595331Samw * resource. 36605331Samw */ 36615331Samw break; 36625331Samw } else { 36635331Samw /* is it the correct share? */ 36645331Samw name = xmlGetProp(node, 36655331Samw (xmlChar *)"name"); 36665331Samw if (name != NULL && 36675331Samw xmlStrcasecmp(name, 36685331Samw (xmlChar *)resource) == 0) { 36695331Samw xmlFree(name); 36705331Samw break; 36715331Samw } 36725331Samw xmlFree(name); 36735331Samw } 36745331Samw } 36755331Samw } 36765331Samw } 36775331Samw return ((sa_resource_t)node); 36785331Samw } 36795331Samw 36805331Samw /* 36815331Samw * sa_get_next_resource(resource) 36825331Samw * Return the next share following the specified share 36835331Samw * from the internal list of shares. Returns NULL if there 36845331Samw * are no more shares. The list is relative to the same 36855331Samw * group. 36865331Samw */ 36875331Samw sa_share_t 36885331Samw sa_get_next_resource(sa_resource_t resource) 36895331Samw { 36905331Samw xmlNodePtr node = NULL; 36915331Samw 36925331Samw if (resource != NULL) { 36935331Samw for (node = ((xmlNodePtr)resource)->next; node != NULL; 36945331Samw node = node->next) { 36955331Samw if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0) 36965331Samw break; 36975331Samw } 36985331Samw } 36995331Samw return ((sa_share_t)node); 37005331Samw } 37015331Samw 37025331Samw /* 37035331Samw * _sa_get_next_resource_index(share) 37045331Samw * 37055331Samw * get the next resource index number (one greater then current largest) 37065331Samw */ 37075331Samw 37085331Samw static int 37095331Samw _sa_get_next_resource_index(sa_share_t share) 37105331Samw { 37115331Samw sa_resource_t resource; 37125331Samw int index = 0; 37135331Samw char *id; 37145331Samw 37155331Samw for (resource = sa_get_share_resource(share, NULL); 37165331Samw resource != NULL; 37175331Samw resource = sa_get_next_resource(resource)) { 37185331Samw id = get_node_attr((void *)resource, "id"); 37195331Samw if (id != NULL) { 37205331Samw int val; 37215331Samw val = atoi(id); 37225331Samw if (val > index) 37235331Samw index = val; 37245331Samw sa_free_attr_string(id); 37255331Samw } 37265331Samw } 37275331Samw return (index + 1); 37285331Samw } 37295331Samw 37305331Samw 37315331Samw /* 37325331Samw * sa_add_resource(share, resource, persist, &err) 37335331Samw * 37345331Samw * Adds a new resource name associated with share. The resource name 37355331Samw * must be unique in the system and will be case insensitive (eventually). 37365331Samw */ 37375331Samw 37385331Samw sa_resource_t 37395331Samw sa_add_resource(sa_share_t share, char *resource, int persist, int *error) 37405331Samw { 37415331Samw xmlNodePtr node; 37425331Samw int err = SA_OK; 37435331Samw sa_resource_t res; 37445331Samw sa_group_t group; 37455331Samw sa_handle_t handle; 37465331Samw char istring[8]; /* just big enough for an integer value */ 37475331Samw int index; 37485331Samw 37495331Samw group = sa_get_parent_group(share); 37505331Samw handle = sa_find_group_handle(group); 37515331Samw res = sa_find_resource(handle, resource); 37525331Samw if (res != NULL) { 37535331Samw err = SA_DUPLICATE_NAME; 37545331Samw res = NULL; 37555331Samw } else { 37565331Samw node = xmlNewChild((xmlNodePtr)share, NULL, 37575331Samw (xmlChar *)"resource", NULL); 37585331Samw if (node != NULL) { 37596007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 37605331Samw (xmlChar *)resource); 37616007Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", persist ? 37625331Samw (xmlChar *)"persist" : (xmlChar *)"transient"); 37635331Samw if (persist != SA_SHARE_TRANSIENT) { 37645331Samw index = _sa_get_next_resource_index(share); 37655331Samw (void) snprintf(istring, sizeof (istring), "%d", 37665331Samw index); 37676007Sthurlow (void) xmlSetProp(node, (xmlChar *)"id", 37685331Samw (xmlChar *)istring); 37697483SDoug.McCallum@Sun.COM 37707483SDoug.McCallum@Sun.COM if (!sa_is_persistent((sa_group_t)share)) 37717483SDoug.McCallum@Sun.COM goto done; 37727483SDoug.McCallum@Sun.COM 37737483SDoug.McCallum@Sun.COM if (!sa_group_is_zfs(group)) { 37745331Samw /* ZFS doesn't use resource names */ 37755331Samw sa_handle_impl_t ihandle; 37767483SDoug.McCallum@Sun.COM 37775331Samw ihandle = (sa_handle_impl_t) 37785331Samw sa_find_group_handle( 37795331Samw group); 37805331Samw if (ihandle != NULL) 37815331Samw err = sa_commit_share( 37825331Samw ihandle->scfhandle, group, 37835331Samw share); 37845331Samw else 37855331Samw err = SA_SYSTEM_ERR; 37867483SDoug.McCallum@Sun.COM } else { 37877483SDoug.McCallum@Sun.COM err = sa_zfs_update((sa_share_t)group); 37885331Samw } 37895331Samw } 37905331Samw } 37915331Samw } 37927483SDoug.McCallum@Sun.COM done: 37935331Samw if (error != NULL) 37945331Samw *error = err; 37955331Samw return ((sa_resource_t)node); 37965331Samw } 37975331Samw 37985331Samw /* 37995331Samw * sa_remove_resource(resource) 38005331Samw * 38015331Samw * Remove the resource name from the share (and the system) 38025331Samw */ 38035331Samw 38045331Samw int 38055331Samw sa_remove_resource(sa_resource_t resource) 38065331Samw { 38075331Samw sa_share_t share; 38085331Samw sa_group_t group; 38095331Samw char *type; 38105331Samw int ret = SA_OK; 38117483SDoug.McCallum@Sun.COM boolean_t transient = B_FALSE; 38125521Sas200622 sa_optionset_t opt; 38135331Samw 38145331Samw share = sa_get_resource_parent(resource); 38155331Samw type = sa_get_share_attr(share, "type"); 38165331Samw group = sa_get_parent_group(share); 38175331Samw 38185331Samw 38195331Samw if (type != NULL) { 38205331Samw if (strcmp(type, "persist") != 0) 38217483SDoug.McCallum@Sun.COM transient = B_TRUE; 38225331Samw sa_free_attr_string(type); 38235331Samw } 38245331Samw 38255521Sas200622 /* Disable the resource for all protocols. */ 38265521Sas200622 (void) sa_disable_resource(resource, NULL); 38275521Sas200622 38285521Sas200622 /* Remove any optionsets from the resource. */ 38295521Sas200622 for (opt = sa_get_optionset(resource, NULL); 38305521Sas200622 opt != NULL; 38315521Sas200622 opt = sa_get_next_optionset(opt)) 38325521Sas200622 (void) sa_destroy_optionset(opt); 38335521Sas200622 38345331Samw /* Remove from the share */ 38355331Samw xmlUnlinkNode((xmlNode *)resource); 38365331Samw xmlFreeNode((xmlNode *)resource); 38375331Samw 38385331Samw /* only do SMF action if permanent and not ZFS */ 38397483SDoug.McCallum@Sun.COM if (transient) 38407483SDoug.McCallum@Sun.COM return (ret); 38417483SDoug.McCallum@Sun.COM 38427483SDoug.McCallum@Sun.COM if (!sa_group_is_zfs(group)) { 38435331Samw sa_handle_impl_t ihandle; 38445331Samw ihandle = (sa_handle_impl_t)sa_find_group_handle(group); 38455331Samw if (ihandle != NULL) 38465331Samw ret = sa_commit_share(ihandle->scfhandle, group, share); 38475331Samw else 38485331Samw ret = SA_SYSTEM_ERR; 38497483SDoug.McCallum@Sun.COM } else { 38507483SDoug.McCallum@Sun.COM ret = sa_zfs_update((sa_share_t)group); 38515331Samw } 38528845Samw@Sun.COM 38535331Samw return (ret); 38545331Samw } 38555331Samw 38565331Samw /* 38578845Samw@Sun.COM * proto_rename_resource(handle, group, resource, newname) 38585331Samw * 38595331Samw * Helper function for sa_rename_resource that notifies the protocol 38605331Samw * of a resource name change prior to a config repository update. 38615331Samw */ 38625331Samw static int 38635331Samw proto_rename_resource(sa_handle_t handle, sa_group_t group, 38645331Samw sa_resource_t resource, char *newname) 38655331Samw { 38665331Samw sa_optionset_t optionset; 38675331Samw int ret = SA_OK; 38685331Samw int err; 38695331Samw 38705331Samw for (optionset = sa_get_optionset(group, NULL); 38715331Samw optionset != NULL; 38725331Samw optionset = sa_get_next_optionset(optionset)) { 38735331Samw char *type; 38745331Samw type = sa_get_optionset_attr(optionset, "type"); 38755331Samw if (type != NULL) { 38765331Samw err = sa_proto_rename_resource(handle, type, resource, 38775331Samw newname); 38785331Samw if (err != SA_OK) 38795331Samw ret = err; 38805331Samw sa_free_attr_string(type); 38815331Samw } 38825331Samw } 38835331Samw return (ret); 38845331Samw } 38855331Samw 38865331Samw /* 38875331Samw * sa_rename_resource(resource, newname) 38885331Samw * 38895331Samw * Rename the resource to the new name, if it is unique. 38905331Samw */ 38915331Samw 38925331Samw int 38935331Samw sa_rename_resource(sa_resource_t resource, char *newname) 38945331Samw { 38955331Samw sa_share_t share; 38965331Samw sa_group_t group = NULL; 38975331Samw sa_resource_t target; 38985331Samw int ret = SA_CONFIG_ERR; 38995331Samw sa_handle_t handle = NULL; 39005331Samw 39015331Samw share = sa_get_resource_parent(resource); 39025331Samw if (share == NULL) 39035331Samw return (ret); 39045331Samw 39055331Samw group = sa_get_parent_group(share); 39065331Samw if (group == NULL) 39075331Samw return (ret); 39085331Samw 39095331Samw handle = (sa_handle_impl_t)sa_find_group_handle(group); 39105331Samw if (handle == NULL) 39115331Samw return (ret); 39125331Samw 39135331Samw target = sa_find_resource(handle, newname); 39145331Samw if (target != NULL) { 39155331Samw ret = SA_DUPLICATE_NAME; 39165331Samw } else { 39175331Samw /* 39185331Samw * Everything appears to be valid at this 39195331Samw * point. Change the name of the active share and then 39205331Samw * update the share in the appropriate repository. 39215331Samw */ 39225331Samw ret = proto_rename_resource(handle, group, resource, newname); 39235331Samw set_node_attr(resource, "name", newname); 39247483SDoug.McCallum@Sun.COM 39257483SDoug.McCallum@Sun.COM if (!sa_is_persistent((sa_group_t)share)) 39267483SDoug.McCallum@Sun.COM return (ret); 39277483SDoug.McCallum@Sun.COM 39287483SDoug.McCallum@Sun.COM if (!sa_group_is_zfs(group)) { 39295331Samw sa_handle_impl_t ihandle = (sa_handle_impl_t)handle; 39305331Samw ret = sa_commit_share(ihandle->scfhandle, group, 39315331Samw share); 39327483SDoug.McCallum@Sun.COM } else { 39337483SDoug.McCallum@Sun.COM ret = sa_zfs_update((sa_share_t)group); 39345331Samw } 39355331Samw } 39365331Samw return (ret); 39375331Samw } 39385331Samw 39395331Samw /* 39405331Samw * sa_get_resource_attr(resource, tag) 39415331Samw * 39425331Samw * Get the named attribute of the resource. "name" and "id" are 39435331Samw * currently defined. NULL if tag not defined. 39445331Samw */ 39455331Samw 39465331Samw char * 39475331Samw sa_get_resource_attr(sa_resource_t resource, char *tag) 39485331Samw { 39495331Samw return (get_node_attr((void *)resource, tag)); 39505331Samw } 39515331Samw 39525331Samw /* 39535331Samw * sa_set_resource_attr(resource, tag, value) 39545331Samw * 39555331Samw * Get the named attribute of the resource. "name" and "id" are 39565331Samw * currently defined. NULL if tag not defined. Currently we don't do 39575331Samw * much, but additional checking may be needed in the future. 39585331Samw */ 39595331Samw 39605331Samw int 39615331Samw sa_set_resource_attr(sa_resource_t resource, char *tag, char *value) 39625331Samw { 39635331Samw set_node_attr((void *)resource, tag, value); 39645331Samw return (SA_OK); 39655331Samw } 39665331Samw 39675331Samw /* 39685331Samw * sa_get_resource_parent(resource_t) 39695331Samw * 39705331Samw * Returns the share associated with the resource. 39715331Samw */ 39725331Samw 39735331Samw sa_share_t 39745331Samw sa_get_resource_parent(sa_resource_t resource) 39755331Samw { 39765331Samw sa_share_t share = NULL; 39775331Samw 39785331Samw if (resource != NULL) 39795331Samw share = (sa_share_t)((xmlNodePtr)resource)->parent; 39805331Samw return (share); 39815331Samw } 39825331Samw 39835331Samw /* 39845331Samw * find_resource(group, name) 39855331Samw * 39865331Samw * Find the resource within the group. 39875331Samw */ 39885331Samw 39895331Samw static sa_resource_t 39905331Samw find_resource(sa_group_t group, char *resname) 39915331Samw { 39925331Samw sa_share_t share; 39935331Samw sa_resource_t resource = NULL; 39945331Samw char *name; 39955331Samw 39965331Samw /* Iterate over all the shares and resources in the group. */ 39975331Samw for (share = sa_get_share(group, NULL); 39985331Samw share != NULL && resource == NULL; 39995331Samw share = sa_get_next_share(share)) { 40005331Samw for (resource = sa_get_share_resource(share, NULL); 40015331Samw resource != NULL; 40025331Samw resource = sa_get_next_resource(resource)) { 40035331Samw name = sa_get_resource_attr(resource, "name"); 40045331Samw if (name != NULL && xmlStrcasecmp((xmlChar*)name, 40055331Samw (xmlChar*)resname) == 0) { 40065331Samw sa_free_attr_string(name); 40075331Samw break; 40085331Samw } 40095331Samw if (name != NULL) { 40105331Samw sa_free_attr_string(name); 40115331Samw } 40125331Samw } 40135331Samw } 40145331Samw return (resource); 40155331Samw } 40165331Samw 40175331Samw /* 40185331Samw * sa_find_resource(name) 40195331Samw * 40205331Samw * Find the named resource in the system. 40215331Samw */ 40225331Samw 40235331Samw sa_resource_t 40245331Samw sa_find_resource(sa_handle_t handle, char *name) 40255331Samw { 40265331Samw sa_group_t group; 40275331Samw sa_group_t zgroup; 40285331Samw sa_resource_t resource = NULL; 40295331Samw 40305331Samw /* 40315331Samw * Iterate over all groups and zfs subgroups and check for 40325331Samw * resource name in them. 40335331Samw */ 40345331Samw for (group = sa_get_group(handle, NULL); group != NULL; 40355331Samw group = sa_get_next_group(group)) { 40365331Samw 40375331Samw if (is_zfs_group(group)) { 40385331Samw for (zgroup = 40395331Samw (sa_group_t)_sa_get_child_node((xmlNodePtr)group, 40405331Samw (xmlChar *)"group"); 40415331Samw zgroup != NULL && resource == NULL; 40425331Samw zgroup = sa_get_next_group(zgroup)) { 40435331Samw resource = find_resource(zgroup, name); 40445331Samw } 40455331Samw } else { 40465331Samw resource = find_resource(group, name); 40475331Samw } 40485331Samw if (resource != NULL) 40495331Samw break; 40505331Samw } 40515331Samw return (resource); 40525331Samw } 40535331Samw 40545331Samw /* 40555331Samw * sa_get_resource(group, resource) 40565331Samw * 40575331Samw * Search all the shares in the specified group for a share with a 40585331Samw * resource name matching the one specified. 40595331Samw * 40605331Samw * In the future, it may be advantageous to allow group to be NULL and 40615331Samw * search all groups but that isn't needed at present. 40625331Samw */ 40635331Samw 40645331Samw sa_resource_t 40655331Samw sa_get_resource(sa_group_t group, char *resource) 40665331Samw { 40675331Samw sa_share_t share = NULL; 40685331Samw sa_resource_t res = NULL; 40695331Samw 40705331Samw if (resource != NULL) { 40715331Samw for (share = sa_get_share(group, NULL); 40725331Samw share != NULL && res == NULL; 40735331Samw share = sa_get_next_share(share)) { 40745331Samw res = sa_get_share_resource(share, resource); 40755331Samw } 40765331Samw } 40775331Samw return (res); 40785331Samw } 40795331Samw 40805331Samw /* 40816270Sdougm * get_protocol_list(optionset, object) 40826270Sdougm * 40836270Sdougm * Get the protocol optionset list for the object and add them as 40846270Sdougm * properties to optionset. 40856270Sdougm */ 40866270Sdougm static int 40876270Sdougm get_protocol_list(sa_optionset_t optionset, void *object) 40886270Sdougm { 40896270Sdougm sa_property_t prop; 40906270Sdougm sa_optionset_t opts; 40916270Sdougm int ret = SA_OK; 40926270Sdougm 40936270Sdougm for (opts = sa_get_optionset(object, NULL); 40946270Sdougm opts != NULL; 40956270Sdougm opts = sa_get_next_optionset(opts)) { 40966270Sdougm char *type; 40976270Sdougm type = sa_get_optionset_attr(opts, "type"); 40986270Sdougm /* 40996270Sdougm * It is possible to have a non-protocol optionset. We 41006270Sdougm * skip any of those found. 41016270Sdougm */ 41026270Sdougm if (type == NULL) 41036270Sdougm continue; 41046270Sdougm prop = sa_create_property(type, "true"); 41056270Sdougm sa_free_attr_string(type); 41066270Sdougm if (prop != NULL) 41076270Sdougm prop = (sa_property_t)xmlAddChild((xmlNodePtr)optionset, 41086270Sdougm (xmlNodePtr)prop); 41096270Sdougm /* If prop is NULL, don't bother continuing */ 41106270Sdougm if (prop == NULL) { 41116270Sdougm ret = SA_NO_MEMORY; 41126270Sdougm break; 41136270Sdougm } 41146270Sdougm } 41156270Sdougm return (ret); 41166270Sdougm } 41176270Sdougm 41186270Sdougm /* 41196270Sdougm * sa_free_protoset(optionset) 41206270Sdougm * 41216270Sdougm * Free the protocol property optionset. 41226270Sdougm */ 41236270Sdougm static void 41246270Sdougm sa_free_protoset(sa_optionset_t optionset) 41256270Sdougm { 41266270Sdougm if (optionset != NULL) { 41276270Sdougm xmlUnlinkNode((xmlNodePtr) optionset); 41286270Sdougm xmlFreeNode((xmlNodePtr) optionset); 41296270Sdougm } 41306270Sdougm } 41316270Sdougm 41326270Sdougm /* 41336270Sdougm * sa_optionset_t sa_get_active_protocols(object) 41346270Sdougm * 41356270Sdougm * Return a list of the protocols that are active for the object. 41366270Sdougm * This is currently an internal helper function, but could be 41376270Sdougm * made visible if there is enough demand for it. 41386270Sdougm * 41396270Sdougm * The function finds the parent group and extracts the protocol 41406270Sdougm * optionsets creating a new optionset with the protocols as properties. 41416270Sdougm * 41426270Sdougm * The caller must free the returned optionset. 41436270Sdougm */ 41446270Sdougm 41456270Sdougm static sa_optionset_t 41466270Sdougm sa_get_active_protocols(void *object) 41476270Sdougm { 41486270Sdougm sa_optionset_t options; 41496270Sdougm sa_share_t share = NULL; 41506270Sdougm sa_group_t group = NULL; 41516270Sdougm sa_resource_t resource = NULL; 41526270Sdougm int ret = SA_OK; 41536270Sdougm 41546270Sdougm if (object == NULL) 41556270Sdougm return (NULL); 41566270Sdougm options = (sa_optionset_t)xmlNewNode(NULL, (xmlChar *)"optionset"); 41576270Sdougm if (options == NULL) 41586270Sdougm return (NULL); 41596270Sdougm 41606270Sdougm /* 41616270Sdougm * Find the objects up the tree that might have protocols 41626270Sdougm * enabled on them. 41636270Sdougm */ 41646270Sdougm if (sa_is_resource(object)) { 41656270Sdougm resource = (sa_resource_t)object; 41666270Sdougm share = sa_get_resource_parent(resource); 41676270Sdougm group = sa_get_parent_group(share); 41686270Sdougm } else if (sa_is_share(object)) { 41696270Sdougm share = (sa_share_t)object; 41706270Sdougm group = sa_get_parent_group(share); 41716270Sdougm } else { 41726270Sdougm group = (sa_group_t)group; 41736270Sdougm } 41746270Sdougm if (resource != NULL) 41756270Sdougm ret = get_protocol_list(options, resource); 41766270Sdougm if (ret == SA_OK && share != NULL) 41776270Sdougm ret = get_protocol_list(options, share); 41786270Sdougm if (ret == SA_OK && group != NULL) 41796270Sdougm ret = get_protocol_list(options, group); 41806270Sdougm 41816270Sdougm /* 41826270Sdougm * If there was an error, we won't have a complete list so 41836270Sdougm * abandon everything. The caller will have to deal with the 41846270Sdougm * issue. 41856270Sdougm */ 41866270Sdougm if (ret != SA_OK) { 41876270Sdougm sa_free_protoset(options); 41886270Sdougm options = NULL; 41896270Sdougm } 41906270Sdougm return (options); 41916270Sdougm } 41926270Sdougm 41936270Sdougm /* 41945331Samw * sa_enable_resource, protocol) 41955331Samw * Disable the specified share to the specified protocol. 41965331Samw * If protocol is NULL, then all protocols. 41975331Samw */ 41985331Samw int 41995331Samw sa_enable_resource(sa_resource_t resource, char *protocol) 42005331Samw { 42015331Samw int ret = SA_OK; 42025331Samw 42035331Samw if (protocol != NULL) { 42045331Samw ret = sa_proto_share_resource(protocol, resource); 42055331Samw } else { 42066270Sdougm sa_optionset_t protoset; 42076270Sdougm sa_property_t prop; 42086270Sdougm char *proto; 42096270Sdougm int err; 42106270Sdougm 42115331Samw /* need to do all protocols */ 42126270Sdougm protoset = sa_get_active_protocols(resource); 42136270Sdougm if (protoset == NULL) 42146270Sdougm return (SA_NO_MEMORY); 42156270Sdougm for (prop = sa_get_property(protoset, NULL); 42166270Sdougm prop != NULL; 42176270Sdougm prop = sa_get_next_property(prop)) { 42186270Sdougm proto = sa_get_property_attr(prop, "type"); 42196270Sdougm if (proto == NULL) { 42206270Sdougm ret = SA_NO_MEMORY; 42216270Sdougm continue; 42225331Samw } 42236270Sdougm err = sa_proto_share_resource(proto, resource); 42246270Sdougm if (err != SA_OK) 42256270Sdougm ret = err; 42266270Sdougm sa_free_attr_string(proto); 42275331Samw } 42286270Sdougm sa_free_protoset(protoset); 42295331Samw } 42305331Samw if (ret == SA_OK) 42315331Samw (void) sa_set_resource_attr(resource, "shared", NULL); 42325331Samw 42335331Samw return (ret); 42345331Samw } 42355331Samw 42365331Samw /* 42375331Samw * sa_disable_resource(resource, protocol) 42385331Samw * 42395331Samw * Disable the specified share for the specified protocol. If 42405331Samw * protocol is NULL, then all protocols. If the underlying 42415331Samw * protocol doesn't implement disable at the resource level, we 42425331Samw * disable at the share level. 42435331Samw */ 42445331Samw int 42455331Samw sa_disable_resource(sa_resource_t resource, char *protocol) 42465331Samw { 42475331Samw int ret = SA_OK; 42485331Samw 42495331Samw if (protocol != NULL) { 42505331Samw ret = sa_proto_unshare_resource(protocol, resource); 42515331Samw if (ret == SA_NOT_IMPLEMENTED) { 42525331Samw sa_share_t parent; 42535331Samw /* 42545331Samw * The protocol doesn't implement unshare 42555331Samw * resource. That implies that resource names are 42565331Samw * simple aliases for this protocol so we need to 42575331Samw * unshare the share. 42585331Samw */ 42595331Samw parent = sa_get_resource_parent(resource); 42605331Samw if (parent != NULL) 42615331Samw ret = sa_disable_share(parent, protocol); 42625331Samw else 42635331Samw ret = SA_CONFIG_ERR; 42645331Samw } 42655331Samw } else { 42666270Sdougm sa_optionset_t protoset; 42676270Sdougm sa_property_t prop; 42686270Sdougm char *proto; 42696270Sdougm int err; 42706270Sdougm 42715331Samw /* need to do all protocols */ 42726270Sdougm protoset = sa_get_active_protocols(resource); 42736270Sdougm if (protoset == NULL) 42746270Sdougm return (SA_NO_MEMORY); 42756270Sdougm for (prop = sa_get_property(protoset, NULL); 42766270Sdougm prop != NULL; 42776270Sdougm prop = sa_get_next_property(prop)) { 42786270Sdougm proto = sa_get_property_attr(prop, "type"); 42796270Sdougm if (proto == NULL) { 42806270Sdougm ret = SA_NO_MEMORY; 42816270Sdougm continue; 42825331Samw } 42836270Sdougm err = sa_proto_unshare_resource(proto, resource); 42846270Sdougm if (err == SA_NOT_SUPPORTED) { 42856270Sdougm sa_share_t parent; 42866270Sdougm parent = sa_get_resource_parent(resource); 42876270Sdougm if (parent != NULL) 42886270Sdougm err = sa_disable_share(parent, proto); 42896270Sdougm else 42906270Sdougm err = SA_CONFIG_ERR; 42916270Sdougm } 42926270Sdougm if (err != SA_OK) 42936270Sdougm ret = err; 42946270Sdougm sa_free_attr_string(proto); 42955331Samw } 42966270Sdougm sa_free_protoset(protoset); 42975331Samw } 42985331Samw if (ret == SA_OK) 42995331Samw (void) sa_set_resource_attr(resource, "shared", NULL); 43005331Samw 43015331Samw return (ret); 43025331Samw } 43035331Samw 43045331Samw /* 43055331Samw * sa_set_resource_description(resource, content) 43065331Samw * 43075331Samw * Set the description of share to content. 43085331Samw */ 43095331Samw 43105331Samw int 43115331Samw sa_set_resource_description(sa_resource_t resource, char *content) 43125331Samw { 43135331Samw xmlNodePtr node; 43145331Samw sa_group_t group; 43155331Samw sa_share_t share; 43165331Samw int ret = SA_OK; 43175331Samw 43185331Samw for (node = ((xmlNodePtr)resource)->children; 43195331Samw node != NULL; 43205331Samw node = node->next) { 43215331Samw if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 43225331Samw break; 43235331Samw } 43245331Samw } 43255331Samw 43265331Samw /* no existing description but want to add */ 43275331Samw if (node == NULL && content != NULL) { 43285331Samw /* add a description */ 43295331Samw node = _sa_set_share_description(resource, content); 43305331Samw } else if (node != NULL && content != NULL) { 43315331Samw /* update a description */ 43325331Samw xmlNodeSetContent(node, (xmlChar *)content); 43335331Samw } else if (node != NULL && content == NULL) { 43345331Samw /* remove an existing description */ 43355331Samw xmlUnlinkNode(node); 43365331Samw xmlFreeNode(node); 43375331Samw } 43385331Samw share = sa_get_resource_parent(resource); 43395331Samw group = sa_get_parent_group(share); 43405331Samw if (group != NULL && sa_is_persistent(share)) { 43415331Samw sa_handle_impl_t impl_handle; 43425331Samw impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 43435331Samw if (impl_handle != NULL) 43445331Samw ret = sa_commit_share(impl_handle->scfhandle, 43455331Samw group, share); 43465331Samw else 43475331Samw ret = SA_SYSTEM_ERR; 43485331Samw } 43495331Samw return (ret); 43505331Samw } 43515331Samw 43525331Samw /* 43535331Samw * sa_get_resource_description(share) 43545331Samw * 43555331Samw * Return the description text for the specified share if it 43565331Samw * exists. NULL if no description exists. 43575331Samw */ 43585331Samw 43595331Samw char * 43605331Samw sa_get_resource_description(sa_resource_t resource) 43615331Samw { 43625331Samw xmlChar *description = NULL; 43635331Samw xmlNodePtr node; 43645331Samw 43655331Samw for (node = ((xmlNodePtr)resource)->children; node != NULL; 43665331Samw node = node->next) { 43675331Samw if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) 43685331Samw break; 43695331Samw } 43705331Samw if (node != NULL) { 43715331Samw description = xmlNodeGetContent(node); 43725331Samw fixproblemchars((char *)description); 43735331Samw } 43745331Samw return ((char *)description); 43755331Samw } 4376