13034Sdougm /* 23034Sdougm * CDDL HEADER START 33034Sdougm * 43034Sdougm * The contents of this file are subject to the terms of the 53034Sdougm * Common Development and Distribution License (the "License"). 63034Sdougm * You may not use this file except in compliance with the License. 73034Sdougm * 83034Sdougm * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 93034Sdougm * or http://www.opensolaris.org/os/licensing. 103034Sdougm * See the License for the specific language governing permissions 113034Sdougm * and limitations under the License. 123034Sdougm * 133034Sdougm * When distributing Covered Code, include this CDDL HEADER in each 143034Sdougm * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 153034Sdougm * If applicable, add the following below this CDDL HEADER, with the 163034Sdougm * fields enclosed by brackets "[]" replaced with your own identifying 173034Sdougm * information: Portions Copyright [yyyy] [name of copyright owner] 183034Sdougm * 193034Sdougm * CDDL HEADER END 203034Sdougm */ 213034Sdougm 223034Sdougm /* 235772Sas200622 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 243034Sdougm * Use is subject to license terms. 253034Sdougm */ 263034Sdougm 273034Sdougm #pragma ident "%Z%%M% %I% %E% SMI" 283034Sdougm 293034Sdougm /* 303034Sdougm * Share control API 313034Sdougm */ 323034Sdougm #include <stdio.h> 333034Sdougm #include <string.h> 343034Sdougm #include <ctype.h> 353034Sdougm #include <sys/types.h> 363034Sdougm #include <sys/stat.h> 373663Sdougm #include <fcntl.h> 383034Sdougm #include <unistd.h> 393034Sdougm #include <libxml/parser.h> 403034Sdougm #include <libxml/tree.h> 413034Sdougm #include "libshare.h" 423034Sdougm #include "libshare_impl.h" 433034Sdougm #include <libscf.h> 443034Sdougm #include "scfutil.h" 453034Sdougm #include <ctype.h> 463034Sdougm #include <libintl.h> 473910Sdougm #include <thread.h> 483910Sdougm #include <synch.h> 493034Sdougm 503663Sdougm #define DFS_LOCK_FILE "/etc/dfs/fstypes" 514327Sdougm #define SA_STRSIZE 256 /* max string size for names */ 523663Sdougm 533034Sdougm /* 545331Samw * internal object type values returned by sa_get_object_type() 555331Samw */ 565331Samw #define SA_TYPE_UNKNOWN 0 575331Samw #define SA_TYPE_GROUP 1 585331Samw #define SA_TYPE_SHARE 2 595331Samw #define SA_TYPE_RESOURCE 3 605331Samw #define SA_TYPE_OPTIONSET 4 615331Samw #define SA_TYPE_ALTSPACE 5 625331Samw 635331Samw /* 643034Sdougm * internal data structures 653034Sdougm */ 663034Sdougm 673034Sdougm extern struct sa_proto_plugin *sap_proto_list; 683034Sdougm 693034Sdougm /* current SMF/SVC repository handle */ 703910Sdougm extern void getlegacyconfig(sa_handle_t, char *, xmlNodePtr *); 713910Sdougm extern int gettransients(sa_handle_impl_t, xmlNodePtr *); 723034Sdougm extern char *sa_fstype(char *); 733034Sdougm extern int sa_is_share(void *); 745331Samw extern int sa_is_resource(void *); 753034Sdougm extern ssize_t scf_max_name_len; /* defined in scfutil during initialization */ 763034Sdougm extern int sa_group_is_zfs(sa_group_t); 773034Sdougm extern int sa_path_is_zfs(char *); 783034Sdougm extern int sa_zfs_set_sharenfs(sa_group_t, char *, int); 795331Samw extern int sa_zfs_set_sharesmb(sa_group_t, char *, int); 803910Sdougm extern void update_legacy_config(sa_handle_t); 813034Sdougm extern int issubdir(char *, char *); 824327Sdougm extern int sa_zfs_init(sa_handle_impl_t); 833910Sdougm extern void sa_zfs_fini(sa_handle_impl_t); 843663Sdougm extern void sablocksigs(sigset_t *); 853663Sdougm extern void saunblocksigs(sigset_t *); 865331Samw static sa_group_t sa_get_optionset_parent(sa_optionset_t); 875331Samw static char *get_node_attr(void *, char *); 885951Sdougm extern void sa_update_sharetab_ts(sa_handle_t); 893034Sdougm 903910Sdougm /* 913910Sdougm * Data structures for finding/managing the document root to access 923910Sdougm * handle mapping. The list isn't expected to grow very large so a 933910Sdougm * simple list is acceptable. The purpose is to provide a way to start 943910Sdougm * with a group or share and find the library handle needed for 953910Sdougm * various operations. 963910Sdougm */ 973910Sdougm mutex_t sa_global_lock; 983910Sdougm struct doc2handle { 993910Sdougm struct doc2handle *next; 1003910Sdougm xmlNodePtr root; 1013910Sdougm sa_handle_impl_t handle; 1023910Sdougm }; 1033910Sdougm 1044327Sdougm /* definitions used in a couple of property functions */ 1054327Sdougm #define SA_PROP_OP_REMOVE 1 1064327Sdougm #define SA_PROP_OP_ADD 2 1074327Sdougm #define SA_PROP_OP_UPDATE 3 1084327Sdougm 1093910Sdougm static struct doc2handle *sa_global_handles = NULL; 1103034Sdougm 1113034Sdougm /* helper functions */ 1123034Sdougm 1133910Sdougm /* 1143910Sdougm * sa_errorstr(err) 1153910Sdougm * 1163910Sdougm * convert an error value to an error string 1173910Sdougm */ 1183910Sdougm 1193034Sdougm char * 1203034Sdougm sa_errorstr(int err) 1213034Sdougm { 1223034Sdougm static char errstr[32]; 1233034Sdougm char *ret = NULL; 1243034Sdougm 1253034Sdougm switch (err) { 1263034Sdougm case SA_OK: 1274327Sdougm ret = dgettext(TEXT_DOMAIN, "ok"); 1284327Sdougm break; 1293034Sdougm case SA_NO_SUCH_PATH: 1304327Sdougm ret = dgettext(TEXT_DOMAIN, "path doesn't exist"); 1314327Sdougm break; 1323034Sdougm case SA_NO_MEMORY: 1334327Sdougm ret = dgettext(TEXT_DOMAIN, "no memory"); 1344327Sdougm break; 1353034Sdougm case SA_DUPLICATE_NAME: 1364327Sdougm ret = dgettext(TEXT_DOMAIN, "name in use"); 1374327Sdougm break; 1383034Sdougm case SA_BAD_PATH: 1394327Sdougm ret = dgettext(TEXT_DOMAIN, "bad path"); 1404327Sdougm break; 1413034Sdougm case SA_NO_SUCH_GROUP: 1424327Sdougm ret = dgettext(TEXT_DOMAIN, "no such group"); 1434327Sdougm break; 1443034Sdougm case SA_CONFIG_ERR: 1454327Sdougm ret = dgettext(TEXT_DOMAIN, "configuration error"); 1464327Sdougm break; 1473034Sdougm case SA_SYSTEM_ERR: 1484327Sdougm ret = dgettext(TEXT_DOMAIN, "system error"); 1494327Sdougm break; 1503034Sdougm case SA_SYNTAX_ERR: 1514327Sdougm ret = dgettext(TEXT_DOMAIN, "syntax error"); 1524327Sdougm break; 1533034Sdougm case SA_NO_PERMISSION: 1544327Sdougm ret = dgettext(TEXT_DOMAIN, "no permission"); 1554327Sdougm break; 1563034Sdougm case SA_BUSY: 1574327Sdougm ret = dgettext(TEXT_DOMAIN, "busy"); 1584327Sdougm break; 1593034Sdougm case SA_NO_SUCH_PROP: 1604327Sdougm ret = dgettext(TEXT_DOMAIN, "no such property"); 1614327Sdougm break; 1623034Sdougm case SA_INVALID_NAME: 1634327Sdougm ret = dgettext(TEXT_DOMAIN, "invalid name"); 1644327Sdougm break; 1653034Sdougm case SA_INVALID_PROTOCOL: 1664327Sdougm ret = dgettext(TEXT_DOMAIN, "invalid protocol"); 1674327Sdougm break; 1683034Sdougm case SA_NOT_ALLOWED: 1694327Sdougm ret = dgettext(TEXT_DOMAIN, "operation not allowed"); 1704327Sdougm break; 1713034Sdougm case SA_BAD_VALUE: 1724327Sdougm ret = dgettext(TEXT_DOMAIN, "bad property value"); 1734327Sdougm break; 1743034Sdougm case SA_INVALID_SECURITY: 1754327Sdougm ret = dgettext(TEXT_DOMAIN, "invalid security type"); 1764327Sdougm break; 1773034Sdougm case SA_NO_SUCH_SECURITY: 1784327Sdougm ret = dgettext(TEXT_DOMAIN, "security type not found"); 1794327Sdougm break; 1803034Sdougm case SA_VALUE_CONFLICT: 1814327Sdougm ret = dgettext(TEXT_DOMAIN, "property value conflict"); 1824327Sdougm break; 1833034Sdougm case SA_NOT_IMPLEMENTED: 1844327Sdougm ret = dgettext(TEXT_DOMAIN, "not implemented"); 1854327Sdougm break; 1863034Sdougm case SA_INVALID_PATH: 1874327Sdougm ret = dgettext(TEXT_DOMAIN, "invalid path"); 1884327Sdougm break; 1893034Sdougm case SA_NOT_SUPPORTED: 1904327Sdougm ret = dgettext(TEXT_DOMAIN, "operation not supported"); 1914327Sdougm break; 1923034Sdougm case SA_PROP_SHARE_ONLY: 1934327Sdougm ret = dgettext(TEXT_DOMAIN, "property not valid for group"); 1944327Sdougm break; 1953034Sdougm case SA_NOT_SHARED: 1964327Sdougm ret = dgettext(TEXT_DOMAIN, "not shared"); 1974327Sdougm break; 1985331Samw case SA_NO_SUCH_RESOURCE: 1995331Samw ret = dgettext(TEXT_DOMAIN, "no such resource"); 2005331Samw break; 2015331Samw case SA_RESOURCE_REQUIRED: 2025331Samw ret = dgettext(TEXT_DOMAIN, "resource name required"); 2035331Samw break; 2045331Samw case SA_MULTIPLE_ERROR: 2055331Samw ret = dgettext(TEXT_DOMAIN, "errors from multiple protocols"); 2065331Samw break; 2075331Samw case SA_PATH_IS_SUBDIR: 2085331Samw ret = dgettext(TEXT_DOMAIN, "path is a subpath of share"); 2095331Samw break; 2105331Samw case SA_PATH_IS_PARENTDIR: 2115331Samw ret = dgettext(TEXT_DOMAIN, "path is parent of a share"); 2125331Samw break; 2136007Sthurlow case SA_NO_SECTION: 2146007Sthurlow ret = dgettext(TEXT_DOMAIN, "protocol requires a section"); 2156007Sthurlow break; 2166007Sthurlow case SA_NO_PROPERTIES: 2176007Sthurlow ret = dgettext(TEXT_DOMAIN, "properties not found"); 2186007Sthurlow break; 2196007Sthurlow case SA_NO_SUCH_SECTION: 2206007Sthurlow ret = dgettext(TEXT_DOMAIN, "section not found"); 2216007Sthurlow break; 2226007Sthurlow case SA_PASSWORD_ENC: 2236007Sthurlow ret = dgettext(TEXT_DOMAIN, "passwords must be encrypted"); 2246007Sthurlow break; 2253034Sdougm default: 2264327Sdougm (void) snprintf(errstr, sizeof (errstr), 2274327Sdougm dgettext(TEXT_DOMAIN, "unknown %d"), err); 2284327Sdougm ret = errstr; 2293034Sdougm } 2303034Sdougm return (ret); 2313034Sdougm } 2323034Sdougm 2333034Sdougm /* 2343910Sdougm * Document root to active handle mapping functions. These are only 2353910Sdougm * used internally. A mutex is used to prevent access while the list 2363910Sdougm * is changing. In general, the list will be relatively short - one 2373910Sdougm * item per thread that has called sa_init(). 2383910Sdougm */ 2393910Sdougm 2403910Sdougm sa_handle_impl_t 2413910Sdougm get_handle_for_root(xmlNodePtr root) 2423910Sdougm { 2433910Sdougm struct doc2handle *item; 2443910Sdougm 2453910Sdougm (void) mutex_lock(&sa_global_lock); 2463910Sdougm for (item = sa_global_handles; item != NULL; item = item->next) { 2474327Sdougm if (item->root == root) 2484327Sdougm break; 2493910Sdougm } 2503910Sdougm (void) mutex_unlock(&sa_global_lock); 2513910Sdougm if (item != NULL) 2524327Sdougm return (item->handle); 2533910Sdougm return (NULL); 2543910Sdougm } 2553910Sdougm 2563910Sdougm static int 2573910Sdougm add_handle_for_root(xmlNodePtr root, sa_handle_impl_t handle) 2583910Sdougm { 2593910Sdougm struct doc2handle *item; 2603910Sdougm int ret = SA_NO_MEMORY; 2613910Sdougm 2623910Sdougm item = (struct doc2handle *)calloc(sizeof (struct doc2handle), 1); 2633910Sdougm if (item != NULL) { 2644327Sdougm item->root = root; 2654327Sdougm item->handle = handle; 2664327Sdougm (void) mutex_lock(&sa_global_lock); 2674327Sdougm item->next = sa_global_handles; 2684327Sdougm sa_global_handles = item; 2694327Sdougm (void) mutex_unlock(&sa_global_lock); 2704327Sdougm ret = SA_OK; 2713910Sdougm } 2723910Sdougm return (ret); 2733910Sdougm } 2743910Sdougm 2753910Sdougm /* 2763910Sdougm * remove_handle_for_root(root) 2773910Sdougm * 2783910Sdougm * Walks the list of handles and removes the one for this "root" from 2793910Sdougm * the list. It is up to the caller to free the data. 2803910Sdougm */ 2813910Sdougm 2823910Sdougm static void 2833910Sdougm remove_handle_for_root(xmlNodePtr root) 2843910Sdougm { 2853910Sdougm struct doc2handle *item, *prev; 2863910Sdougm 2873910Sdougm (void) mutex_lock(&sa_global_lock); 2883910Sdougm for (prev = NULL, item = sa_global_handles; item != NULL; 2894327Sdougm item = item->next) { 2904327Sdougm if (item->root == root) { 2914327Sdougm /* first in the list */ 2924327Sdougm if (prev == NULL) 2934327Sdougm sa_global_handles = sa_global_handles->next; 2944327Sdougm else 2954327Sdougm prev->next = item->next; 2964327Sdougm /* Item is out of the list so free the list structure */ 2974327Sdougm free(item); 2984327Sdougm break; 2993910Sdougm } 3004327Sdougm prev = item; 3013910Sdougm } 3023910Sdougm (void) mutex_unlock(&sa_global_lock); 3033910Sdougm } 3043910Sdougm 3053910Sdougm /* 3063910Sdougm * sa_find_group_handle(sa_group_t group) 3073910Sdougm * 3083910Sdougm * Find the sa_handle_t for the configuration associated with this 3093910Sdougm * group. 3103910Sdougm */ 3113910Sdougm sa_handle_t 3123910Sdougm sa_find_group_handle(sa_group_t group) 3133910Sdougm { 3143910Sdougm xmlNodePtr node = (xmlNodePtr)group; 3153910Sdougm sa_handle_t handle; 3163910Sdougm 3173910Sdougm while (node != NULL) { 3184327Sdougm if (strcmp((char *)(node->name), "sharecfg") == 0) { 3194327Sdougm /* have the root so get the handle */ 3204327Sdougm handle = (sa_handle_t)get_handle_for_root(node); 3214327Sdougm return (handle); 3224327Sdougm } 3234327Sdougm node = node->parent; 3243910Sdougm } 3253910Sdougm return (NULL); 3263910Sdougm } 3273910Sdougm 3283910Sdougm /* 3293034Sdougm * set_legacy_timestamp(root, path, timevalue) 3303034Sdougm * 3313034Sdougm * add the current timestamp value to the configuration for use in 3323034Sdougm * determining when to update the legacy files. For SMF, this 3333034Sdougm * property is kept in default/operation/legacy_timestamp 3343034Sdougm */ 3353034Sdougm 3363034Sdougm static void 3373034Sdougm set_legacy_timestamp(xmlNodePtr root, char *path, uint64_t tval) 3383034Sdougm { 3393034Sdougm xmlNodePtr node; 3403034Sdougm xmlChar *lpath = NULL; 3413910Sdougm sa_handle_impl_t handle; 3423910Sdougm 3433910Sdougm /* Have to have a handle or else we weren't initialized. */ 3443910Sdougm handle = get_handle_for_root(root); 3453910Sdougm if (handle == NULL) 3464327Sdougm return; 3473034Sdougm 3483034Sdougm for (node = root->xmlChildrenNode; node != NULL; 3494327Sdougm node = node->next) { 3504327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"legacy") == 0) { 3514327Sdougm /* a possible legacy node for this path */ 3524327Sdougm lpath = xmlGetProp(node, (xmlChar *)"path"); 3534327Sdougm if (lpath != NULL && 3544327Sdougm xmlStrcmp(lpath, (xmlChar *)path) == 0) { 3554327Sdougm xmlFree(lpath); 3564327Sdougm break; 3574327Sdougm } 3584327Sdougm if (lpath != NULL) 3594327Sdougm xmlFree(lpath); 3603034Sdougm } 3613034Sdougm } 3623034Sdougm if (node == NULL) { 3634327Sdougm /* need to create the first legacy timestamp node */ 3644327Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"legacy", NULL); 3653034Sdougm } 3663034Sdougm if (node != NULL) { 3674327Sdougm char tstring[32]; 3684327Sdougm int ret; 3693034Sdougm 3704327Sdougm (void) snprintf(tstring, sizeof (tstring), "%lld", tval); 3716007Sthurlow (void) xmlSetProp(node, (xmlChar *)"timestamp", 3726007Sthurlow (xmlChar *)tstring); 3736007Sthurlow (void) xmlSetProp(node, (xmlChar *)"path", (xmlChar *)path); 3744327Sdougm /* now commit to SMF */ 3754327Sdougm ret = sa_get_instance(handle->scfhandle, "default"); 3763034Sdougm if (ret == SA_OK) { 3774327Sdougm ret = sa_start_transaction(handle->scfhandle, 3784327Sdougm "operation"); 3794327Sdougm if (ret == SA_OK) { 3804327Sdougm ret = sa_set_property(handle->scfhandle, 3814327Sdougm "legacy-timestamp", tstring); 3824327Sdougm if (ret == SA_OK) { 3834327Sdougm (void) sa_end_transaction( 3845951Sdougm handle->scfhandle, handle); 3854327Sdougm } else { 3864327Sdougm sa_abort_transaction(handle->scfhandle); 3874327Sdougm } 3884327Sdougm } 3893034Sdougm } 3903034Sdougm } 3913034Sdougm } 3923034Sdougm 3933034Sdougm /* 3943034Sdougm * is_shared(share) 3953034Sdougm * 3963034Sdougm * determine if the specified share is currently shared or not. 3973034Sdougm */ 3983034Sdougm static int 3993034Sdougm is_shared(sa_share_t share) 4003034Sdougm { 4013034Sdougm char *shared; 4023034Sdougm int result = 0; /* assume not */ 4033034Sdougm 4043034Sdougm shared = sa_get_share_attr(share, "shared"); 4053034Sdougm if (shared != NULL) { 4064327Sdougm if (strcmp(shared, "true") == 0) 4074327Sdougm result = 1; 4084327Sdougm sa_free_attr_string(shared); 4093034Sdougm } 4103034Sdougm return (result); 4113034Sdougm } 4123034Sdougm 4133034Sdougm /* 4145331Samw * excluded_protocol(share, proto) 4155331Samw * 4165331Samw * Returns B_TRUE if the specified protocol appears in the "exclude" 4175331Samw * property. This is used to prevent sharing special case shares 4185331Samw * (e.g. subdirs when SMB wants a subdir and NFS doesn't. B_FALSE is 4195331Samw * returned if the protocol isn't in the list. 4205331Samw */ 4215331Samw static boolean_t 4225331Samw excluded_protocol(sa_share_t share, char *proto) 4235331Samw { 4245331Samw char *protolist; 4255331Samw char *str; 4265331Samw char *token; 4275331Samw 4285331Samw protolist = sa_get_share_attr(share, "exclude"); 4295331Samw if (protolist != NULL) { 4305331Samw str = protolist; 4315331Samw while ((token = strtok(str, ",")) != NULL) { 4325331Samw if (strcmp(token, proto) == 0) { 4335331Samw sa_free_attr_string(protolist); 4345331Samw return (B_TRUE); 4355331Samw } 4365331Samw str = NULL; 4375331Samw } 4385331Samw sa_free_attr_string(protolist); 4395331Samw } 4405331Samw return (B_FALSE); 4415331Samw } 4425331Samw 4435331Samw /* 4443663Sdougm * checksubdirgroup(group, newpath, strictness) 4453348Sdougm * 4463663Sdougm * check all the specified newpath against all the paths in the 4473663Sdougm * group. This is a helper function for checksubdir to make it easier 4483663Sdougm * to also check ZFS subgroups. 4493663Sdougm * The strictness values mean: 4503348Sdougm * SA_CHECK_NORMAL == only check newpath against shares that are active 4513348Sdougm * SA_CHECK_STRICT == check newpath against both active shares and those 4523348Sdougm * stored in the repository 4533034Sdougm */ 4543034Sdougm static int 4553663Sdougm checksubdirgroup(sa_group_t group, char *newpath, int strictness) 4563034Sdougm { 4573034Sdougm sa_share_t share; 4583663Sdougm char *path; 4593663Sdougm int issub = SA_OK; 4605331Samw int subdir; 4615331Samw int parent; 4625331Samw 4635331Samw if (newpath == NULL) 4645331Samw return (SA_INVALID_PATH); 4653034Sdougm 4663663Sdougm for (share = sa_get_share(group, NULL); share != NULL; 4673663Sdougm share = sa_get_next_share(share)) { 4683034Sdougm /* 4693034Sdougm * The original behavior of share never checked 4703034Sdougm * against the permanent configuration 4713034Sdougm * (/etc/dfs/dfstab). PIT has a number of cases where 4723034Sdougm * it depends on this older behavior even though it 4733034Sdougm * could be considered incorrect. We may tighten this 4743034Sdougm * up in the future. 4753034Sdougm */ 4764327Sdougm if (strictness == SA_CHECK_NORMAL && !is_shared(share)) 4774327Sdougm continue; 4783034Sdougm 4794327Sdougm path = sa_get_share_attr(share, "path"); 4803348Sdougm /* 4813348Sdougm * If path is NULL, then a share is in the process of 4823348Sdougm * construction or someone has modified the property 4833663Sdougm * group inappropriately. It should be 4843663Sdougm * ignored. issubdir() comes from the original share 4853663Sdougm * implementation and does the difficult part of 4863663Sdougm * checking subdirectories. 4873348Sdougm */ 4884327Sdougm if (path == NULL) 4894327Sdougm continue; 4905331Samw 4915331Samw if (strcmp(path, newpath) == 0) { 4924327Sdougm issub = SA_INVALID_PATH; 4935331Samw } else { 4945331Samw subdir = issubdir(newpath, path); 4955331Samw parent = issubdir(path, newpath); 4965331Samw if (subdir || parent) { 4975331Samw sa_free_attr_string(path); 4985331Samw path = NULL; 4995331Samw return (subdir ? 5005331Samw SA_PATH_IS_SUBDIR : SA_PATH_IS_PARENTDIR); 5015331Samw } 5024327Sdougm } 5033034Sdougm sa_free_attr_string(path); 5043034Sdougm path = NULL; 5053663Sdougm } 5063663Sdougm return (issub); 5073663Sdougm } 5083663Sdougm 5093663Sdougm /* 5103663Sdougm * checksubdir(newpath, strictness) 5113663Sdougm * 5123663Sdougm * checksubdir determines if the specified path (newpath) is a 5133663Sdougm * subdirectory of another share. It calls checksubdirgroup() to do 5143663Sdougm * the complicated work. The strictness parameter determines how 5153663Sdougm * strict a check to make against the path. The strictness values 5163663Sdougm * mean: SA_CHECK_NORMAL == only check newpath against shares that are 5173663Sdougm * active SA_CHECK_STRICT == check newpath against both active shares 5183663Sdougm * and those * stored in the repository 5193663Sdougm */ 5203663Sdougm static int 5213910Sdougm checksubdir(sa_handle_t handle, char *newpath, int strictness) 5223663Sdougm { 5233663Sdougm sa_group_t group; 5245331Samw int issub = SA_OK; 5253663Sdougm char *path = NULL; 5263663Sdougm 5275331Samw for (group = sa_get_group(handle, NULL); 5285331Samw group != NULL && issub == SA_OK; 5295331Samw group = sa_get_next_group(group)) { 5304327Sdougm if (sa_group_is_zfs(group)) { 5314327Sdougm sa_group_t subgroup; 5324327Sdougm for (subgroup = sa_get_sub_group(group); 5335331Samw subgroup != NULL && issub == SA_OK; 5344327Sdougm subgroup = sa_get_next_group(subgroup)) 5354327Sdougm issub = checksubdirgroup(subgroup, newpath, 5364327Sdougm strictness); 5374327Sdougm } else { 5384327Sdougm issub = checksubdirgroup(group, newpath, strictness); 5394327Sdougm } 5403034Sdougm } 5413034Sdougm if (path != NULL) 5424327Sdougm sa_free_attr_string(path); 5433034Sdougm return (issub); 5443034Sdougm } 5453034Sdougm 5463034Sdougm /* 5473348Sdougm * validpath(path, strictness) 5483034Sdougm * determine if the provided path is valid for a share. It shouldn't 5493034Sdougm * be a sub-dir of an already shared path or the parent directory of a 5503034Sdougm * share path. 5513034Sdougm */ 5523034Sdougm static int 5533910Sdougm validpath(sa_handle_t handle, char *path, int strictness) 5543034Sdougm { 5553034Sdougm int error = SA_OK; 5563034Sdougm struct stat st; 5573034Sdougm sa_share_t share; 5583034Sdougm char *fstype; 5593034Sdougm 5604327Sdougm if (*path != '/') 5614327Sdougm return (SA_BAD_PATH); 5624327Sdougm 5633034Sdougm if (stat(path, &st) < 0) { 5644327Sdougm error = SA_NO_SUCH_PATH; 5653034Sdougm } else { 5664327Sdougm share = sa_find_share(handle, path); 5674327Sdougm if (share != NULL) 5684327Sdougm error = SA_DUPLICATE_NAME; 5694327Sdougm 5704327Sdougm if (error == SA_OK) { 5714327Sdougm /* 5724327Sdougm * check for special case with file system 5734327Sdougm * that might have restrictions. For now, ZFS 5744327Sdougm * is the only case since it has its own idea 5754327Sdougm * of how to configure shares. We do this 5764327Sdougm * before subdir checking since things like 5774327Sdougm * ZFS will do that for us. This should also 5784327Sdougm * be done via plugin interface. 5794327Sdougm */ 5804327Sdougm fstype = sa_fstype(path); 5814327Sdougm if (fstype != NULL && strcmp(fstype, "zfs") == 0) { 5824327Sdougm if (sa_zfs_is_shared(handle, path)) 5834327Sdougm error = SA_INVALID_NAME; 5844327Sdougm } 5854327Sdougm if (fstype != NULL) 5864327Sdougm sa_free_fstype(fstype); 5873034Sdougm } 5884327Sdougm if (error == SA_OK) 5894327Sdougm error = checksubdir(handle, path, strictness); 5903034Sdougm } 5913034Sdougm return (error); 5923034Sdougm } 5933034Sdougm 5943034Sdougm /* 5953034Sdougm * check to see if group/share is persistent. 5965331Samw * 5975331Samw * "group" can be either an sa_group_t or an sa_share_t. (void *) 5985331Samw * works since both thse types are also void *. 5993034Sdougm */ 6005331Samw int 6015331Samw sa_is_persistent(void *group) 6023034Sdougm { 6033034Sdougm char *type; 6043034Sdougm int persist = 1; 6053034Sdougm 6065331Samw type = sa_get_group_attr((sa_group_t)group, "type"); 6073034Sdougm if (type != NULL && strcmp(type, "transient") == 0) 6084327Sdougm persist = 0; 6093034Sdougm if (type != NULL) 6104327Sdougm sa_free_attr_string(type); 6113034Sdougm return (persist); 6123034Sdougm } 6133034Sdougm 6143034Sdougm /* 6153034Sdougm * sa_valid_group_name(name) 6163034Sdougm * 6173034Sdougm * check that the "name" contains only valid characters and otherwise 6183034Sdougm * fits the required naming conventions. Valid names must start with 6193034Sdougm * an alphabetic and the remainder may consist of only alphanumeric 6203034Sdougm * plus the '-' and '_' characters. This name limitation comes from 6213034Sdougm * inherent limitations in SMF. 6223034Sdougm */ 6233034Sdougm 6243034Sdougm int 6253034Sdougm sa_valid_group_name(char *name) 6263034Sdougm { 6273034Sdougm int ret = 1; 6283034Sdougm ssize_t len; 6293034Sdougm 6303034Sdougm if (name != NULL && isalpha(*name)) { 6314327Sdougm char c; 6324327Sdougm len = strlen(name); 6334327Sdougm if (len < (scf_max_name_len - sizeof ("group:"))) { 6344327Sdougm for (c = *name++; c != '\0' && ret != 0; c = *name++) { 6354327Sdougm if (!isalnum(c) && c != '-' && c != '_') 6364327Sdougm ret = 0; 6374327Sdougm } 6384327Sdougm } else { 6393034Sdougm ret = 0; 6403034Sdougm } 6414327Sdougm } else { 6423034Sdougm ret = 0; 6433034Sdougm } 6443034Sdougm return (ret); 6453034Sdougm } 6463034Sdougm 6473034Sdougm 6483034Sdougm /* 6493034Sdougm * is_zfs_group(group) 6503034Sdougm * Determine if the specified group is a ZFS sharenfs group 6513034Sdougm */ 6523034Sdougm static int 6533034Sdougm is_zfs_group(sa_group_t group) 6543034Sdougm { 6553034Sdougm int ret = 0; 6563034Sdougm xmlNodePtr parent; 6573034Sdougm xmlChar *zfs; 6583034Sdougm 6594327Sdougm if (strcmp((char *)((xmlNodePtr)group)->name, "share") == 0) 6604327Sdougm parent = (xmlNodePtr)sa_get_parent_group(group); 6614327Sdougm else 6624327Sdougm parent = (xmlNodePtr)group; 6633034Sdougm zfs = xmlGetProp(parent, (xmlChar *)"zfs"); 6643034Sdougm if (zfs != NULL) { 6654327Sdougm xmlFree(zfs); 6664327Sdougm ret = 1; 6673034Sdougm } 6683034Sdougm return (ret); 6693034Sdougm } 6703034Sdougm 6713034Sdougm /* 6725331Samw * sa_get_object_type(object) 6735331Samw * 6745331Samw * This function returns a numeric value representing the object 6755331Samw * type. This allows using simpler checks when doing type specific 6765331Samw * operations. 6775331Samw */ 6785331Samw 6795331Samw static int 6805331Samw sa_get_object_type(void *object) 6815331Samw { 6825331Samw xmlNodePtr node = (xmlNodePtr)object; 6835331Samw int type; 6845331Samw 6855331Samw if (xmlStrcmp(node->name, (xmlChar *)"group") == 0) 6865331Samw type = SA_TYPE_GROUP; 6875331Samw else if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) 6885331Samw type = SA_TYPE_SHARE; 6895331Samw else if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0) 6905331Samw type = SA_TYPE_RESOURCE; 6915331Samw else if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) 6925331Samw type = SA_TYPE_OPTIONSET; 6935331Samw else if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) 6945331Samw type = SA_TYPE_ALTSPACE; 6955331Samw else 6965331Samw assert(0); 6975331Samw return (type); 6985331Samw } 6995331Samw 7005331Samw /* 7013034Sdougm * sa_optionset_name(optionset, oname, len, id) 7023034Sdougm * return the SMF name for the optionset. If id is not NULL, it 7033034Sdougm * will have the GUID value for a share and should be used 7043034Sdougm * instead of the keyword "optionset" which is used for 7053034Sdougm * groups. If the optionset doesn't have a protocol type 7063034Sdougm * associated with it, "default" is used. This shouldn't happen 7073034Sdougm * at this point but may be desirable in the future if there are 7083034Sdougm * protocol independent properties added. The name is returned in 7093034Sdougm * oname. 7103034Sdougm */ 7113034Sdougm 7123034Sdougm static int 7133034Sdougm sa_optionset_name(sa_optionset_t optionset, char *oname, size_t len, char *id) 7143034Sdougm { 7153034Sdougm char *proto; 7165331Samw void *parent; 7175331Samw int ptype; 7183034Sdougm 7193034Sdougm if (id == NULL) 7204327Sdougm id = "optionset"; 7213034Sdougm 7225331Samw parent = sa_get_optionset_parent(optionset); 7235331Samw if (parent != NULL) { 7245331Samw ptype = sa_get_object_type(parent); 7255331Samw proto = sa_get_optionset_attr(optionset, "type"); 7265331Samw if (ptype != SA_TYPE_RESOURCE) { 7275331Samw len = snprintf(oname, len, "%s_%s", id, 7285331Samw proto ? proto : "default"); 7295331Samw } else { 7305331Samw char *index; 7315331Samw index = get_node_attr((void *)parent, "id"); 7325331Samw if (index != NULL) 7335331Samw len = snprintf(oname, len, "%s_%s_%s", id, 7345331Samw proto ? proto : "default", index); 7355331Samw else 7365331Samw len = 0; 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) { 8304327Sdougm /* get protocol specific structures */ 8314327Sdougm (void) proto_plugin_init(); 8324327Sdougm if (init_service & SA_INIT_SHARE_API) { 8333663Sdougm /* 8344327Sdougm * initialize access into libzfs. We use this 8354327Sdougm * when collecting info about ZFS datasets and 8364327Sdougm * shares. 8373663Sdougm */ 8384327Sdougm if (sa_zfs_init(handle) == B_FALSE) { 8394327Sdougm free(handle); 8404327Sdougm (void) proto_plugin_fini(); 8414327Sdougm return (NULL); 8424327Sdougm } 8433663Sdougm /* 8444327Sdougm * since we want to use SMF, initialize an svc handle 8454327Sdougm * and find out what is there. 8463663Sdougm */ 8474327Sdougm handle->scfhandle = sa_scf_init(handle); 8484327Sdougm if (handle->scfhandle != NULL) { 8494327Sdougm /* 8504327Sdougm * Need to lock the extraction of the 8514327Sdougm * configuration if the dfstab file has 8524327Sdougm * changed. Lock everything now and release if 8534327Sdougm * not needed. Use a file that isn't being 8544327Sdougm * manipulated by other parts of the system in 8554327Sdougm * order to not interfere with locking. Using 8564327Sdougm * dfstab doesn't work. 8574327Sdougm */ 8584327Sdougm sablocksigs(&old); 8594327Sdougm lockfd = open(DFS_LOCK_FILE, O_RDWR); 8604327Sdougm if (lockfd >= 0) { 8614327Sdougm extern int errno; 8624327Sdougm errno = 0; 8634327Sdougm (void) lockf(lockfd, F_LOCK, 0); 8644327Sdougm /* 8654327Sdougm * Check whether we are going to need 8664327Sdougm * to merge any dfstab changes. This 8674327Sdougm * is done by comparing the value of 8684327Sdougm * legacy-timestamp with the current 8694327Sdougm * st_ctim of the file. If they are 8704327Sdougm * different, an update is needed and 8714327Sdougm * the file must remain locked until 8724327Sdougm * the merge is done in order to 8734327Sdougm * prevent multiple startups from 8744327Sdougm * changing the SMF repository at the 8754327Sdougm * same time. The first to get the 8764327Sdougm * lock will make any changes before 8774327Sdougm * the others can read the repository. 8784327Sdougm */ 8794327Sdougm prop = scf_simple_prop_get 8804327Sdougm (handle->scfhandle->handle, 8814327Sdougm (const char *)SA_SVC_FMRI_BASE 8824327Sdougm ":default", "operation", 8834327Sdougm "legacy-timestamp"); 8844327Sdougm if (prop != NULL) { 8854327Sdougm char *i64; 8864327Sdougm i64 = GETPROP(prop); 8874327Sdougm if (i64 != NULL) 8884327Sdougm tval = strtoull(i64, 8894327Sdougm NULL, 0); 8904327Sdougm if (CHECKTSTAMP(st, tval)) 8914327Sdougm updatelegacy = B_TRUE; 8924327Sdougm scf_simple_prop_free(prop); 8934327Sdougm } else { 8944327Sdougm /* 8954327Sdougm * We haven't set the 8964327Sdougm * timestamp before so do it. 8974327Sdougm */ 8984327Sdougm updatelegacy = B_TRUE; 8994327Sdougm } 9004327Sdougm } 9014327Sdougm if (updatelegacy == B_FALSE) { 9024327Sdougm /* Don't need the lock anymore */ 9034327Sdougm (void) lockf(lockfd, F_ULOCK, 0); 9044327Sdougm (void) close(lockfd); 9054327Sdougm } 9063973Sdougm 9074327Sdougm /* 9084327Sdougm * It is essential that the document tree and 9094327Sdougm * the internal list of roots to handles be 9104327Sdougm * setup before anything that might try to 9114327Sdougm * create a new object is called. The document 9124327Sdougm * tree is the combination of handle->doc and 9134327Sdougm * handle->tree. This allows searches, 9144327Sdougm * etc. when all you have is an object in the 9154327Sdougm * tree. 9164327Sdougm */ 9174327Sdougm handle->doc = xmlNewDoc((xmlChar *)"1.0"); 9184327Sdougm handle->tree = xmlNewNode(NULL, 9194327Sdougm (xmlChar *)"sharecfg"); 9204327Sdougm if (handle->doc != NULL && 9214327Sdougm handle->tree != NULL) { 9226007Sthurlow (void) xmlDocSetRootElement(handle->doc, 9234327Sdougm handle->tree); 9244327Sdougm err = add_handle_for_root(handle->tree, 9254327Sdougm handle); 9264327Sdougm if (err == SA_OK) 9274327Sdougm err = sa_get_config( 9284327Sdougm handle->scfhandle, 9293973Sdougm handle->tree, handle); 9304327Sdougm } else { 9314327Sdougm if (handle->doc != NULL) 9324327Sdougm xmlFreeDoc(handle->doc); 9334327Sdougm if (handle->tree != NULL) 9344327Sdougm xmlFreeNode(handle->tree); 9354327Sdougm err = SA_NO_MEMORY; 9364327Sdougm } 9373973Sdougm 9384327Sdougm saunblocksigs(&old); 9393910Sdougm 9404327Sdougm if (err != SA_OK) { 9414327Sdougm /* 9424327Sdougm * If we couldn't add the tree handle 9434327Sdougm * to the list, then things are going 9444327Sdougm * to fail badly. Might as well undo 9454327Sdougm * everything now and fail the 9464327Sdougm * sa_init(). 9474327Sdougm */ 9484327Sdougm sa_fini(handle); 9494327Sdougm return (NULL); 9504327Sdougm } 9513910Sdougm 9524327Sdougm if (tval == 0) { 9534327Sdougm /* 9544327Sdougm * first time so make sure 9554327Sdougm * default is setup 9564327Sdougm */ 9574327Sdougm verifydefgroupopts(handle); 9584327Sdougm } 9593973Sdougm 9604524Sdougm if (updatelegacy == B_TRUE) { 9614524Sdougm sablocksigs(&old); 9624524Sdougm getlegacyconfig((sa_handle_t)handle, 9634524Sdougm SA_LEGACY_DFSTAB, &handle->tree); 9644524Sdougm if (stat(SA_LEGACY_DFSTAB, &st) >= 0) 9654524Sdougm set_legacy_timestamp( 9664524Sdougm handle->tree, 9674524Sdougm SA_LEGACY_DFSTAB, 9684524Sdougm TSTAMP(st.st_ctim)); 9694524Sdougm saunblocksigs(&old); 9704524Sdougm /* 9714524Sdougm * Safe to unlock now to allow 9724524Sdougm * others to run 9734524Sdougm */ 9744524Sdougm (void) lockf(lockfd, F_ULOCK, 0); 9754524Sdougm (void) close(lockfd); 9764524Sdougm } 9775951Sdougm /* Get sharetab timestamp */ 9785951Sdougm sa_update_sharetab_ts((sa_handle_t)handle); 9795951Sdougm 9805951Sdougm /* Get lastupdate (transaction) timestamp */ 9815951Sdougm prop = scf_simple_prop_get( 9825951Sdougm handle->scfhandle->handle, 9835951Sdougm (const char *)SA_SVC_FMRI_BASE ":default", 9845951Sdougm "state", "lastupdate"); 9855951Sdougm if (prop != NULL) { 9865951Sdougm char *str; 9875951Sdougm str = 9885951Sdougm scf_simple_prop_next_astring(prop); 9895951Sdougm if (str != NULL) 9905951Sdougm handle->tstrans = 9915951Sdougm strtoull(str, NULL, 0); 9925951Sdougm else 9935951Sdougm handle->tstrans = 0; 9945951Sdougm scf_simple_prop_free(prop); 9955951Sdougm } 9964524Sdougm legacy |= sa_get_zfs_shares(handle, "zfs"); 9974524Sdougm legacy |= gettransients(handle, &handle->tree); 9984327Sdougm } 9994327Sdougm } 10003034Sdougm } 10013910Sdougm return ((sa_handle_t)handle); 10023034Sdougm } 10033034Sdougm 10043034Sdougm /* 10053910Sdougm * sa_fini(handle) 10063034Sdougm * Uninitialize the API structures including the configuration 10073218Sdougm * data structures and ZFS related data. 10083034Sdougm */ 10093034Sdougm 10103034Sdougm void 10113910Sdougm sa_fini(sa_handle_t handle) 10123034Sdougm { 10133910Sdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle; 10143910Sdougm 10153910Sdougm if (impl_handle != NULL) { 10163910Sdougm /* 10173910Sdougm * Free the config trees and any other data structures 10183910Sdougm * used in the handle. 10193910Sdougm */ 10203910Sdougm if (impl_handle->doc != NULL) 10213910Sdougm xmlFreeDoc(impl_handle->doc); 10223910Sdougm sa_scf_fini(impl_handle->scfhandle); 10233910Sdougm sa_zfs_fini(impl_handle); 10243910Sdougm 10253910Sdougm /* Remove and free the entry in the global list. */ 10263910Sdougm remove_handle_for_root(impl_handle->tree); 10273910Sdougm 10283910Sdougm /* Make sure we free the handle */ 10293910Sdougm free(impl_handle); 10303910Sdougm 10313910Sdougm /* 10323910Sdougm * If this was the last handle to release, unload the 10333910Sdougm * plugins that were loaded. 10343910Sdougm */ 10353910Sdougm if (sa_global_handles == NULL) 10364327Sdougm (void) proto_plugin_fini(); 10373910Sdougm 10383034Sdougm } 10393034Sdougm } 10403034Sdougm 10413034Sdougm /* 10423034Sdougm * sa_get_protocols(char **protocol) 10433034Sdougm * Get array of protocols that are supported 10443034Sdougm * Returns pointer to an allocated and NULL terminated 10453034Sdougm * array of strings. Caller must free. 10463034Sdougm * This really should be determined dynamically. 10473034Sdougm * If there aren't any defined, return -1. 10483034Sdougm * Use free() to return memory. 10493034Sdougm */ 10503034Sdougm 10513034Sdougm int 10523034Sdougm sa_get_protocols(char ***protocols) 10533034Sdougm { 10543034Sdougm int numproto = -1; 10553034Sdougm 10563034Sdougm if (protocols != NULL) { 10574327Sdougm struct sa_proto_plugin *plug; 10584327Sdougm for (numproto = 0, plug = sap_proto_list; plug != NULL; 10594327Sdougm plug = plug->plugin_next) { 10604327Sdougm numproto++; 10614327Sdougm } 10623034Sdougm 10634327Sdougm *protocols = calloc(numproto + 1, sizeof (char *)); 10644327Sdougm if (*protocols != NULL) { 10654327Sdougm int ret = 0; 10664327Sdougm for (plug = sap_proto_list; plug != NULL; 10674327Sdougm plug = plug->plugin_next) { 10684327Sdougm /* faking for now */ 10694327Sdougm (*protocols)[ret++] = 10704327Sdougm plug->plugin_ops->sa_protocol; 10714327Sdougm } 10724327Sdougm } else { 10734327Sdougm numproto = -1; 10743034Sdougm } 10753034Sdougm } 10763034Sdougm return (numproto); 10773034Sdougm } 10783034Sdougm 10793034Sdougm /* 10803034Sdougm * find_group_by_name(node, group) 10813034Sdougm * 10823034Sdougm * search the XML document subtree specified by node to find the group 10833034Sdougm * specified by group. Searching subtree allows subgroups to be 10843034Sdougm * searched for. 10853034Sdougm */ 10863034Sdougm 10873034Sdougm static xmlNodePtr 10883034Sdougm find_group_by_name(xmlNodePtr node, xmlChar *group) 10893034Sdougm { 10903034Sdougm xmlChar *name = NULL; 10913034Sdougm 10923034Sdougm for (node = node->xmlChildrenNode; node != NULL; 10933034Sdougm node = node->next) { 10944327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"group") == 0) { 10954327Sdougm /* if no groupname, return the first found */ 10964327Sdougm if (group == NULL) 10974327Sdougm break; 10984327Sdougm name = xmlGetProp(node, (xmlChar *)"name"); 10994327Sdougm if (name != NULL && xmlStrcmp(name, group) == 0) 11004327Sdougm break; 11014327Sdougm if (name != NULL) { 11024327Sdougm xmlFree(name); 11034327Sdougm name = NULL; 11044327Sdougm } 11053034Sdougm } 11063034Sdougm } 11073034Sdougm if (name != NULL) 11084327Sdougm xmlFree(name); 11093034Sdougm return (node); 11103034Sdougm } 11113034Sdougm 11123034Sdougm /* 11133034Sdougm * sa_get_group(groupname) 11143034Sdougm * Return the "group" specified. If groupname is NULL, 11153034Sdougm * return the first group of the list of groups. 11163034Sdougm */ 11173034Sdougm sa_group_t 11183910Sdougm sa_get_group(sa_handle_t handle, char *groupname) 11193034Sdougm { 11203034Sdougm xmlNodePtr node = NULL; 11213034Sdougm char *subgroup = NULL; 11223034Sdougm char *group = NULL; 11233910Sdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle; 11243034Sdougm 11253910Sdougm if (impl_handle != NULL && impl_handle->tree != NULL) { 11264327Sdougm if (groupname != NULL) { 11274327Sdougm group = strdup(groupname); 11284345Sdougm if (group != NULL) { 11294345Sdougm subgroup = strchr(group, '/'); 11304345Sdougm if (subgroup != NULL) 11314345Sdougm *subgroup++ = '\0'; 11324345Sdougm } 11334327Sdougm } 11344345Sdougm /* 11354345Sdougm * We want to find the, possibly, named group. If 11364345Sdougm * group is not NULL, then lookup the name. If it is 11374345Sdougm * NULL, we only do the find if groupname is also 11384345Sdougm * NULL. This allows lookup of the "first" group in 11394345Sdougm * the internal list. 11404345Sdougm */ 11414345Sdougm if (group != NULL || groupname == NULL) 11424345Sdougm node = find_group_by_name(impl_handle->tree, 11434345Sdougm (xmlChar *)group); 11444345Sdougm 11454327Sdougm /* if a subgroup, find it before returning */ 11464327Sdougm if (subgroup != NULL && node != NULL) 11474327Sdougm node = find_group_by_name(node, (xmlChar *)subgroup); 11483034Sdougm } 11493034Sdougm if (node != NULL && (char *)group != NULL) 11504327Sdougm (void) sa_get_instance(impl_handle->scfhandle, (char *)group); 11513034Sdougm if (group != NULL) 11524327Sdougm free(group); 11533034Sdougm return ((sa_group_t)(node)); 11543034Sdougm } 11553034Sdougm 11563034Sdougm /* 11573034Sdougm * sa_get_next_group(group) 11583034Sdougm * Return the "next" group after the specified group from 11593034Sdougm * the internal group list. NULL if there are no more. 11603034Sdougm */ 11613034Sdougm sa_group_t 11623034Sdougm sa_get_next_group(sa_group_t group) 11633034Sdougm { 11643034Sdougm xmlNodePtr ngroup = NULL; 11653034Sdougm if (group != NULL) { 11664327Sdougm for (ngroup = ((xmlNodePtr)group)->next; ngroup != NULL; 11673034Sdougm ngroup = ngroup->next) { 11684327Sdougm if (xmlStrcmp(ngroup->name, (xmlChar *)"group") == 0) 11694327Sdougm break; 11704327Sdougm } 11713034Sdougm } 11723034Sdougm return ((sa_group_t)ngroup); 11733034Sdougm } 11743034Sdougm 11753034Sdougm /* 11763034Sdougm * sa_get_share(group, sharepath) 11773034Sdougm * Return the share object for the share specified. The share 11783034Sdougm * must be in the specified group. Return NULL if not found. 11793034Sdougm */ 11803034Sdougm sa_share_t 11813034Sdougm sa_get_share(sa_group_t group, char *sharepath) 11823034Sdougm { 11833034Sdougm xmlNodePtr node = NULL; 11843034Sdougm xmlChar *path; 11853034Sdougm 11863034Sdougm /* 11873034Sdougm * For future scalability, this should end up building a cache 11883034Sdougm * since it will get called regularly by the mountd and info 11893034Sdougm * services. 11903034Sdougm */ 11913034Sdougm if (group != NULL) { 11924327Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 11933034Sdougm node = node->next) { 11944327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) { 11954327Sdougm if (sharepath == NULL) { 11964327Sdougm break; 11974327Sdougm } else { 11984327Sdougm /* is it the correct share? */ 11994327Sdougm path = xmlGetProp(node, 12004327Sdougm (xmlChar *)"path"); 12014327Sdougm if (path != NULL && 12024327Sdougm xmlStrcmp(path, 12034327Sdougm (xmlChar *)sharepath) == 0) { 12044327Sdougm xmlFree(path); 12054327Sdougm break; 12064327Sdougm } 12074327Sdougm xmlFree(path); 12084327Sdougm } 12093034Sdougm } 12103034Sdougm } 12113034Sdougm } 12123034Sdougm return ((sa_share_t)node); 12133034Sdougm } 12143034Sdougm 12153034Sdougm /* 12163034Sdougm * sa_get_next_share(share) 12173034Sdougm * Return the next share following the specified share 12183034Sdougm * from the internal list of shares. Returns NULL if there 12193034Sdougm * are no more shares. The list is relative to the same 12203034Sdougm * group. 12213034Sdougm */ 12223034Sdougm sa_share_t 12233034Sdougm sa_get_next_share(sa_share_t share) 12243034Sdougm { 12253034Sdougm xmlNodePtr node = NULL; 12263034Sdougm 12273034Sdougm if (share != NULL) { 12284327Sdougm for (node = ((xmlNodePtr)share)->next; node != NULL; 12293034Sdougm node = node->next) { 12304327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) { 12314327Sdougm break; 12324327Sdougm } 12333034Sdougm } 12343034Sdougm } 12353034Sdougm return ((sa_share_t)node); 12363034Sdougm } 12373034Sdougm 12383034Sdougm /* 12393034Sdougm * _sa_get_child_node(node, type) 12403034Sdougm * 12413034Sdougm * find the child node of the specified node that has "type". This is 12423034Sdougm * used to implement several internal functions. 12433034Sdougm */ 12443034Sdougm 12453034Sdougm static xmlNodePtr 12463034Sdougm _sa_get_child_node(xmlNodePtr node, xmlChar *type) 12473034Sdougm { 12483034Sdougm xmlNodePtr child; 12493034Sdougm for (child = node->xmlChildrenNode; child != NULL; 12503034Sdougm child = child->next) 12514327Sdougm if (xmlStrcmp(child->name, type) == 0) 12524327Sdougm return (child); 12533034Sdougm return ((xmlNodePtr)NULL); 12543034Sdougm } 12553034Sdougm 12563034Sdougm /* 12573034Sdougm * find_share(group, path) 12583034Sdougm * 12593034Sdougm * Search all the shares in the specified group for one that has the 12603034Sdougm * specified path. 12613034Sdougm */ 12623034Sdougm 12633034Sdougm static sa_share_t 12643034Sdougm find_share(sa_group_t group, char *sharepath) 12653034Sdougm { 12663034Sdougm sa_share_t share; 12673034Sdougm char *path; 12683034Sdougm 12693034Sdougm for (share = sa_get_share(group, NULL); share != NULL; 12703034Sdougm share = sa_get_next_share(share)) { 12714327Sdougm path = sa_get_share_attr(share, "path"); 12724327Sdougm if (path != NULL && strcmp(path, sharepath) == 0) { 12734327Sdougm sa_free_attr_string(path); 12744327Sdougm break; 12754327Sdougm } 12764327Sdougm if (path != NULL) 12774327Sdougm sa_free_attr_string(path); 12783034Sdougm } 12793034Sdougm return (share); 12803034Sdougm } 12813034Sdougm 12823034Sdougm /* 12833034Sdougm * sa_get_sub_group(group) 12843034Sdougm * 12853034Sdougm * Get the first sub-group of group. The sa_get_next_group() function 12863034Sdougm * can be used to get the rest. This is currently only used for ZFS 12873034Sdougm * sub-groups but could be used to implement a more general mechanism. 12883034Sdougm */ 12893034Sdougm 12903034Sdougm sa_group_t 12913034Sdougm sa_get_sub_group(sa_group_t group) 12923034Sdougm { 12933034Sdougm return ((sa_group_t)_sa_get_child_node((xmlNodePtr)group, 12944327Sdougm (xmlChar *)"group")); 12953034Sdougm } 12963034Sdougm 12973034Sdougm /* 12983034Sdougm * sa_find_share(sharepath) 12993034Sdougm * Finds a share regardless of group. In the future, this 13003034Sdougm * function should utilize a cache and hash table of some kind. 13013034Sdougm * The current assumption is that a path will only be shared 13023034Sdougm * once. In the future, this may change as implementation of 13033034Sdougm * resource names comes into being. 13043034Sdougm */ 13053034Sdougm sa_share_t 13063910Sdougm sa_find_share(sa_handle_t handle, char *sharepath) 13073034Sdougm { 13083034Sdougm sa_group_t group; 13093034Sdougm sa_group_t zgroup; 13103034Sdougm sa_share_t share = NULL; 13113034Sdougm int done = 0; 13123034Sdougm 13133910Sdougm for (group = sa_get_group(handle, NULL); group != NULL && !done; 13144327Sdougm group = sa_get_next_group(group)) { 13154327Sdougm if (is_zfs_group(group)) { 13164327Sdougm for (zgroup = 13174327Sdougm (sa_group_t)_sa_get_child_node((xmlNodePtr)group, 13184327Sdougm (xmlChar *)"group"); 13194327Sdougm zgroup != NULL; 13204327Sdougm zgroup = sa_get_next_group(zgroup)) { 13214327Sdougm share = find_share(zgroup, sharepath); 13224327Sdougm if (share != NULL) 13234327Sdougm break; 13244327Sdougm } 13254327Sdougm } else { 13264327Sdougm share = find_share(group, sharepath); 13274327Sdougm } 13284327Sdougm if (share != NULL) 13293034Sdougm break; 13303034Sdougm } 13313034Sdougm return (share); 13323034Sdougm } 13333034Sdougm 13343034Sdougm /* 13353348Sdougm * sa_check_path(group, path, strictness) 13363034Sdougm * 13375331Samw * Check that path is a valid path relative to the group. Currently, 13383034Sdougm * we are ignoring the group and checking only the NFS rules. Later, 13393034Sdougm * we may want to use the group to then check against the protocols 13403348Sdougm * enabled on the group. The strictness values mean: 13413348Sdougm * SA_CHECK_NORMAL == only check newpath against shares that are active 13423348Sdougm * SA_CHECK_STRICT == check newpath against both active shares and those 13433348Sdougm * stored in the repository 13443034Sdougm */ 13453034Sdougm 13463034Sdougm int 13473348Sdougm sa_check_path(sa_group_t group, char *path, int strictness) 13483034Sdougm { 13493910Sdougm sa_handle_t handle; 13503910Sdougm 13513910Sdougm handle = sa_find_group_handle(group); 13523910Sdougm return (validpath(handle, path, strictness)); 13533034Sdougm } 13543034Sdougm 13553034Sdougm /* 13565331Samw * mark_excluded_protos(group, share, flags) 13573034Sdougm * 13585331Samw * Walk through all the protocols enabled for the group and check to 13595331Samw * see if the share has any of them should be in the exclude list 13605331Samw * based on the featureset of the protocol. If there are any, add the 13615331Samw * "exclude" property to the share. 13625331Samw */ 13635331Samw static void 13645331Samw mark_excluded_protos(sa_group_t group, xmlNodePtr share, uint64_t flags) 13655331Samw { 13665331Samw sa_optionset_t optionset; 13675331Samw char exclude_list[SA_STRSIZE]; 13685331Samw char *sep = ""; 13695331Samw 13705331Samw exclude_list[0] = '\0'; 13715331Samw for (optionset = sa_get_optionset(group, NULL); 13725331Samw optionset != NULL; 13735331Samw optionset = sa_get_next_optionset(optionset)) { 13745331Samw char *value; 13755331Samw uint64_t features; 13765331Samw value = sa_get_optionset_attr(optionset, "type"); 13775331Samw if (value == NULL) 13785331Samw continue; 13795331Samw features = sa_proto_get_featureset(value); 13805331Samw sa_free_attr_string(value); 13815331Samw if (!(features & flags)) { 13825331Samw (void) strlcat(exclude_list, sep, 13835331Samw sizeof (exclude_list)); 13845331Samw (void) strlcat(exclude_list, value, 13855331Samw sizeof (exclude_list)); 13865331Samw sep = ","; 13875331Samw } 13885331Samw } 13895331Samw if (exclude_list[0] != '\0') 13906007Sthurlow (void) xmlSetProp(share, (xmlChar *)"exclude", 13915331Samw (xmlChar *)exclude_list); 13925331Samw } 13935331Samw 13945331Samw /* 13955331Samw * get_all_features(group) 13965331Samw * 13975331Samw * Walk through all the protocols on the group and collect all 13985331Samw * possible enabled features. This is the OR of all the featuresets. 13995331Samw */ 14005331Samw static uint64_t 14015331Samw get_all_features(sa_group_t group) 14025331Samw { 14035331Samw sa_optionset_t optionset; 14045331Samw uint64_t features = 0; 14055331Samw 14065331Samw for (optionset = sa_get_optionset(group, NULL); 14075331Samw optionset != NULL; 14085331Samw optionset = sa_get_next_optionset(optionset)) { 14095331Samw char *value; 14105331Samw value = sa_get_optionset_attr(optionset, "type"); 14115331Samw if (value == NULL) 14125331Samw continue; 14135331Samw features |= sa_proto_get_featureset(value); 14145331Samw sa_free_attr_string(value); 14155331Samw } 14165331Samw return (features); 14175331Samw } 14185331Samw 14195331Samw 14205331Samw /* 14215331Samw * _sa_add_share(group, sharepath, persist, *error, flags) 14225331Samw * 14235331Samw * Common code for all types of add_share. sa_add_share() is the 14243034Sdougm * public API, we also need to be able to do this when parsing legacy 14253034Sdougm * files and construction of the internal configuration while 14265331Samw * extracting config info from SMF. "flags" indicates if some 14275331Samw * protocols need relaxed rules while other don't. These values are 14285331Samw * the featureset values defined in libshare.h. 14293034Sdougm */ 14303034Sdougm 14313034Sdougm sa_share_t 14325331Samw _sa_add_share(sa_group_t group, char *sharepath, int persist, int *error, 14335331Samw uint64_t flags) 14343034Sdougm { 14353034Sdougm xmlNodePtr node = NULL; 14363034Sdougm int err; 14373034Sdougm 14383034Sdougm err = SA_OK; /* assume success */ 14393034Sdougm 14404327Sdougm node = xmlNewChild((xmlNodePtr)group, NULL, (xmlChar *)"share", NULL); 14415331Samw if (node == NULL) { 14425331Samw if (error != NULL) 14435331Samw *error = SA_NO_MEMORY; 14445331Samw return (node); 14455331Samw } 14465331Samw 14476007Sthurlow (void) xmlSetProp(node, (xmlChar *)"path", (xmlChar *)sharepath); 14486007Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", 14495331Samw persist ? (xmlChar *)"persist" : (xmlChar *)"transient"); 14505331Samw if (flags != 0) 14515331Samw mark_excluded_protos(group, node, flags); 14525331Samw if (persist != SA_SHARE_TRANSIENT) { 14535331Samw /* 14545331Samw * persistent shares come in two flavors: SMF and 14555331Samw * ZFS. Sort this one out based on target group and 14565331Samw * path type. Both NFS and SMB are supported. First, 14575331Samw * check to see if the protocol is enabled on the 14585331Samw * subgroup and then setup the share appropriately. 14595331Samw */ 14605331Samw if (sa_group_is_zfs(group) && 14615331Samw sa_path_is_zfs(sharepath)) { 14625331Samw if (sa_get_optionset(group, "nfs") != NULL) 14634327Sdougm err = sa_zfs_set_sharenfs(group, sharepath, 1); 14645331Samw else if (sa_get_optionset(group, "smb") != NULL) 14655331Samw err = sa_zfs_set_sharesmb(group, sharepath, 1); 14665331Samw } else { 14675331Samw sa_handle_impl_t impl_handle; 14685331Samw impl_handle = 14695331Samw (sa_handle_impl_t)sa_find_group_handle(group); 14705331Samw if (impl_handle != NULL) { 14715331Samw err = sa_commit_share(impl_handle->scfhandle, 14725331Samw group, (sa_share_t)node); 14734327Sdougm } else { 14745331Samw err = SA_SYSTEM_ERR; 14754327Sdougm } 14763034Sdougm } 14773034Sdougm } 14785331Samw if (err == SA_NO_PERMISSION && persist & SA_SHARE_PARSER) 14795331Samw /* called by the dfstab parser so could be a show */ 14805331Samw err = SA_OK; 14815331Samw 14825331Samw if (err != SA_OK) { 14835331Samw /* 14845331Samw * we couldn't commit to the repository so undo 14855331Samw * our internal state to reflect reality. 14865331Samw */ 14875331Samw xmlUnlinkNode(node); 14885331Samw xmlFreeNode(node); 14895331Samw node = NULL; 14905331Samw } 14915331Samw 14923034Sdougm if (error != NULL) 14934327Sdougm *error = err; 14945331Samw 14953034Sdougm return (node); 14963034Sdougm } 14973034Sdougm 14983034Sdougm /* 14993034Sdougm * sa_add_share(group, sharepath, persist, *error) 15003034Sdougm * 15013034Sdougm * Add a new share object to the specified group. The share will 15023034Sdougm * have the specified sharepath and will only be constructed if 15033034Sdougm * it is a valid path to be shared. NULL is returned on error 15043034Sdougm * and a detailed error value will be returned via the error 15053034Sdougm * pointer. 15063034Sdougm */ 15073034Sdougm sa_share_t 15083034Sdougm sa_add_share(sa_group_t group, char *sharepath, int persist, int *error) 15093034Sdougm { 15103034Sdougm xmlNodePtr node = NULL; 15113348Sdougm int strictness = SA_CHECK_NORMAL; 15123910Sdougm sa_handle_t handle; 15135331Samw uint64_t special = 0; 15145331Samw uint64_t features; 15153348Sdougm 15163348Sdougm /* 15173348Sdougm * If the share is to be permanent, use strict checking so a 15183348Sdougm * bad config doesn't get created. Transient shares only need 15193348Sdougm * to check against the currently active 15203348Sdougm * shares. SA_SHARE_PARSER is a modifier used internally to 15213348Sdougm * indicate that we are being called by the dfstab parser and 15223348Sdougm * that we need strict checking in all cases. Normally persist 15233348Sdougm * is in integer value but SA_SHARE_PARSER may be or'd into 15243348Sdougm * it as an override. 15253348Sdougm */ 15263348Sdougm if (persist & SA_SHARE_PARSER || persist == SA_SHARE_PERMANENT) 15274327Sdougm strictness = SA_CHECK_STRICT; 15283034Sdougm 15293910Sdougm handle = sa_find_group_handle(group); 15303910Sdougm 15315331Samw /* 15325331Samw * need to determine if the share is valid. The rules are: 15335331Samw * - The path must not already exist 15345331Samw * - The path must not be a subdir or parent dir of an 15355331Samw * existing path unless at least one protocol allows it. 15365331Samw * The sub/parent check is done in sa_check_path(). 15375331Samw */ 15385331Samw 15395331Samw if (sa_find_share(handle, sharepath) == NULL) { 15405331Samw *error = sa_check_path(group, sharepath, strictness); 15415331Samw features = get_all_features(group); 15425331Samw switch (*error) { 15435331Samw case SA_PATH_IS_SUBDIR: 15445331Samw if (features & SA_FEATURE_ALLOWSUBDIRS) 15455331Samw special |= SA_FEATURE_ALLOWSUBDIRS; 15465331Samw break; 15475331Samw case SA_PATH_IS_PARENTDIR: 15485331Samw if (features & SA_FEATURE_ALLOWPARDIRS) 15495331Samw special |= SA_FEATURE_ALLOWPARDIRS; 15505331Samw break; 15515331Samw } 15525331Samw if (*error == SA_OK || special != SA_FEATURE_NONE) 15535331Samw node = _sa_add_share(group, sharepath, persist, 15545331Samw error, special); 15555331Samw } else { 15565331Samw *error = SA_DUPLICATE_NAME; 15573034Sdougm } 15583034Sdougm 15593034Sdougm return ((sa_share_t)node); 15603034Sdougm } 15613034Sdougm 15623034Sdougm /* 15633034Sdougm * sa_enable_share(share, protocol) 15643034Sdougm * Enable the specified share to the specified protocol. 15653034Sdougm * If protocol is NULL, then all protocols. 15663034Sdougm */ 15673034Sdougm int 15683034Sdougm sa_enable_share(sa_share_t share, char *protocol) 15693034Sdougm { 15703034Sdougm char *sharepath; 15713034Sdougm struct stat st; 15725331Samw int err = SA_OK; 15735331Samw int ret; 15743034Sdougm 15753034Sdougm sharepath = sa_get_share_attr(share, "path"); 15765331Samw if (sharepath == NULL) 15775331Samw return (SA_NO_MEMORY); 15783034Sdougm if (stat(sharepath, &st) < 0) { 15794327Sdougm err = SA_NO_SUCH_PATH; 15803034Sdougm } else { 15814327Sdougm /* tell the server about the share */ 15824327Sdougm if (protocol != NULL) { 15835331Samw if (excluded_protocol(share, protocol)) 15845331Samw goto done; 15855331Samw 15864327Sdougm /* lookup protocol specific handler */ 15874327Sdougm err = sa_proto_share(protocol, share); 15884327Sdougm if (err == SA_OK) 15895331Samw (void) sa_set_share_attr(share, 15905331Samw "shared", "true"); 15914327Sdougm } else { 15925331Samw /* Tell all protocols about the share */ 15935331Samw sa_group_t group; 15945331Samw sa_optionset_t optionset; 15955331Samw 15965331Samw group = sa_get_parent_group(share); 15975331Samw 15985331Samw for (optionset = sa_get_optionset(group, NULL); 15995331Samw optionset != NULL; 16005331Samw optionset = sa_get_next_optionset(optionset)) { 16015331Samw char *proto; 16025331Samw proto = sa_get_optionset_attr(optionset, 16035331Samw "type"); 16045331Samw if (proto != NULL) { 16055331Samw if (!excluded_protocol(share, proto)) { 16065331Samw ret = sa_proto_share(proto, 16075331Samw share); 16085331Samw if (ret != SA_OK) 16095331Samw err = ret; 16105331Samw } 16115331Samw sa_free_attr_string(proto); 16125331Samw } 16135331Samw } 16144327Sdougm (void) sa_set_share_attr(share, "shared", "true"); 16154327Sdougm } 16163034Sdougm } 16175331Samw done: 16183034Sdougm if (sharepath != NULL) 16194327Sdougm sa_free_attr_string(sharepath); 16203034Sdougm return (err); 16213034Sdougm } 16223034Sdougm 16233034Sdougm /* 16243034Sdougm * sa_disable_share(share, protocol) 16255331Samw * Disable the specified share to the specified protocol. If 16265331Samw * protocol is NULL, then all protocols that are enabled for the 16275331Samw * share should be disabled. 16283034Sdougm */ 16293034Sdougm int 16303034Sdougm sa_disable_share(sa_share_t share, char *protocol) 16313034Sdougm { 16323034Sdougm char *path; 16335331Samw int err = SA_OK; 16343034Sdougm int ret = SA_OK; 16353034Sdougm 16363034Sdougm path = sa_get_share_attr(share, "path"); 16373034Sdougm 16383034Sdougm if (protocol != NULL) { 16394543Smarks ret = sa_proto_unshare(share, protocol, path); 16403034Sdougm } else { 16414327Sdougm /* need to do all protocols */ 16425331Samw sa_group_t group; 16435331Samw sa_optionset_t optionset; 16445331Samw 16455331Samw group = sa_get_parent_group(share); 16465331Samw 16475331Samw /* Tell all protocols about the share */ 16485331Samw for (optionset = sa_get_optionset(group, NULL); 16495331Samw optionset != NULL; 16505331Samw optionset = sa_get_next_optionset(optionset)) { 16515331Samw char *proto; 16525331Samw 16535331Samw proto = sa_get_optionset_attr(optionset, "type"); 16545331Samw if (proto != NULL) { 16555331Samw err = sa_proto_unshare(share, proto, path); 16565331Samw if (err != SA_OK) 16575331Samw ret = err; 16585331Samw sa_free_attr_string(proto); 16595331Samw } 16605331Samw } 16613034Sdougm } 16623034Sdougm if (ret == SA_OK) 16633034Sdougm (void) sa_set_share_attr(share, "shared", NULL); 16643034Sdougm if (path != NULL) 16654327Sdougm sa_free_attr_string(path); 16663034Sdougm return (ret); 16673034Sdougm } 16683034Sdougm 16693034Sdougm /* 16703034Sdougm * sa_remove_share(share) 16713034Sdougm * 16723034Sdougm * remove the specified share from its containing group. 16733034Sdougm * Remove from the SMF or ZFS configuration space. 16743034Sdougm */ 16753034Sdougm 16763034Sdougm int 16773034Sdougm sa_remove_share(sa_share_t share) 16783034Sdougm { 16793034Sdougm sa_group_t group; 16803034Sdougm int ret = SA_OK; 16813034Sdougm char *type; 16823034Sdougm int transient = 0; 16833034Sdougm char *groupname; 16843034Sdougm char *zfs; 16853034Sdougm 16863034Sdougm type = sa_get_share_attr(share, "type"); 16873034Sdougm group = sa_get_parent_group(share); 16883034Sdougm zfs = sa_get_group_attr(group, "zfs"); 16893034Sdougm groupname = sa_get_group_attr(group, "name"); 16903034Sdougm if (type != NULL && strcmp(type, "persist") != 0) 16914327Sdougm transient = 1; 16923034Sdougm if (type != NULL) 16934327Sdougm sa_free_attr_string(type); 16943034Sdougm 16953034Sdougm /* remove the node from its group then free the memory */ 16963034Sdougm 16973034Sdougm /* 16983034Sdougm * need to test if "busy" 16993034Sdougm */ 17003034Sdougm /* only do SMF action if permanent */ 17013034Sdougm if (!transient || zfs != NULL) { 17024327Sdougm /* remove from legacy dfstab as well as possible SMF */ 17035331Samw ret = sa_delete_legacy(share, NULL); 17044327Sdougm if (ret == SA_OK) { 17054327Sdougm if (!sa_group_is_zfs(group)) { 17064327Sdougm sa_handle_impl_t impl_handle; 17074327Sdougm impl_handle = (sa_handle_impl_t) 17084327Sdougm sa_find_group_handle(group); 17094327Sdougm if (impl_handle != NULL) { 17104327Sdougm ret = sa_delete_share( 17114327Sdougm impl_handle->scfhandle, group, 17124327Sdougm share); 17134327Sdougm } else { 17144327Sdougm ret = SA_SYSTEM_ERR; 17154327Sdougm } 17164327Sdougm } else { 17174327Sdougm char *sharepath = sa_get_share_attr(share, 17184327Sdougm "path"); 17194327Sdougm if (sharepath != NULL) { 17204327Sdougm ret = sa_zfs_set_sharenfs(group, 17214327Sdougm sharepath, 0); 17224327Sdougm sa_free_attr_string(sharepath); 17234327Sdougm } 17244327Sdougm } 17253034Sdougm } 17263034Sdougm } 17273034Sdougm if (groupname != NULL) 17284327Sdougm sa_free_attr_string(groupname); 17293034Sdougm if (zfs != NULL) 17304327Sdougm sa_free_attr_string(zfs); 17313034Sdougm 17323034Sdougm xmlUnlinkNode((xmlNodePtr)share); 17333034Sdougm xmlFreeNode((xmlNodePtr)share); 17343034Sdougm return (ret); 17353034Sdougm } 17363034Sdougm 17373034Sdougm /* 17383034Sdougm * sa_move_share(group, share) 17393034Sdougm * 17403034Sdougm * move the specified share to the specified group. Update SMF 17413034Sdougm * appropriately. 17423034Sdougm */ 17433034Sdougm 17443034Sdougm int 17453034Sdougm sa_move_share(sa_group_t group, sa_share_t share) 17463034Sdougm { 17473034Sdougm sa_group_t oldgroup; 17483034Sdougm int ret = SA_OK; 17493034Sdougm 17503034Sdougm /* remove the node from its group then free the memory */ 17513034Sdougm 17523034Sdougm oldgroup = sa_get_parent_group(share); 17533034Sdougm if (oldgroup != group) { 17544327Sdougm sa_handle_impl_t impl_handle; 17554327Sdougm xmlUnlinkNode((xmlNodePtr)share); 17563034Sdougm /* 17574327Sdougm * now that the share isn't in its old group, add to 17584327Sdougm * the new one 17593034Sdougm */ 17606007Sthurlow (void) xmlAddChild((xmlNodePtr)group, (xmlNodePtr)share); 17614327Sdougm /* need to deal with SMF */ 17624327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 17634327Sdougm if (impl_handle != NULL) { 17644327Sdougm /* 17654327Sdougm * need to remove from old group first and then add to 17664327Sdougm * new group. Ideally, we would do the other order but 17674327Sdougm * need to avoid having the share in two groups at the 17684327Sdougm * same time. 17694327Sdougm */ 17704327Sdougm ret = sa_delete_share(impl_handle->scfhandle, oldgroup, 17714327Sdougm share); 17724327Sdougm if (ret == SA_OK) 17734327Sdougm ret = sa_commit_share(impl_handle->scfhandle, 17744327Sdougm group, share); 17754327Sdougm } else { 17764327Sdougm ret = SA_SYSTEM_ERR; 17774327Sdougm } 17783034Sdougm } 17793034Sdougm return (ret); 17803034Sdougm } 17813034Sdougm 17823034Sdougm /* 17833034Sdougm * sa_get_parent_group(share) 17843034Sdougm * 17855331Samw * Return the containing group for the share. If a group was actually 17863034Sdougm * passed in, we don't want a parent so return NULL. 17873034Sdougm */ 17883034Sdougm 17893034Sdougm sa_group_t 17903034Sdougm sa_get_parent_group(sa_share_t share) 17913034Sdougm { 17923034Sdougm xmlNodePtr node = NULL; 17933034Sdougm if (share != NULL) { 17944327Sdougm node = ((xmlNodePtr)share)->parent; 17953034Sdougm /* 17963034Sdougm * make sure parent is a group and not sharecfg since 17973034Sdougm * we may be cheating and passing in a group. 17983034Sdougm * Eventually, groups of groups might come into being. 17993034Sdougm */ 18004327Sdougm if (node == NULL || 18014327Sdougm xmlStrcmp(node->name, (xmlChar *)"sharecfg") == 0) 18024327Sdougm node = NULL; 18033034Sdougm } 18043034Sdougm return ((sa_group_t)node); 18053034Sdougm } 18063034Sdougm 18073034Sdougm /* 18083910Sdougm * _sa_create_group(impl_handle, groupname) 18093034Sdougm * 18103034Sdougm * Create a group in the document. The caller will need to deal with 18113034Sdougm * configuration store and activation. 18123034Sdougm */ 18133034Sdougm 18143034Sdougm sa_group_t 18153910Sdougm _sa_create_group(sa_handle_impl_t impl_handle, char *groupname) 18163034Sdougm { 18173034Sdougm xmlNodePtr node = NULL; 18183034Sdougm 18193034Sdougm if (sa_valid_group_name(groupname)) { 18204327Sdougm node = xmlNewChild(impl_handle->tree, NULL, (xmlChar *)"group", 18214327Sdougm NULL); 18224327Sdougm if (node != NULL) { 18236007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 18244327Sdougm (xmlChar *)groupname); 18256007Sthurlow (void) xmlSetProp(node, (xmlChar *)"state", 18264327Sdougm (xmlChar *)"enabled"); 18274327Sdougm } 18283034Sdougm } 18293034Sdougm return ((sa_group_t)node); 18303034Sdougm } 18313034Sdougm 18323034Sdougm /* 18333034Sdougm * _sa_create_zfs_group(group, groupname) 18343034Sdougm * 18353034Sdougm * Create a ZFS subgroup under the specified group. This may 18363034Sdougm * eventually form the basis of general sub-groups, but is currently 18373034Sdougm * restricted to ZFS. 18383034Sdougm */ 18393034Sdougm sa_group_t 18403034Sdougm _sa_create_zfs_group(sa_group_t group, char *groupname) 18413034Sdougm { 18423034Sdougm xmlNodePtr node = NULL; 18433034Sdougm 18444327Sdougm node = xmlNewChild((xmlNodePtr)group, NULL, (xmlChar *)"group", NULL); 18453034Sdougm if (node != NULL) { 18466007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 18476007Sthurlow (xmlChar *)groupname); 18486007Sthurlow (void) xmlSetProp(node, (xmlChar *)"state", 18496007Sthurlow (xmlChar *)"enabled"); 18503034Sdougm } 18513034Sdougm 18523034Sdougm return ((sa_group_t)node); 18533034Sdougm } 18543034Sdougm 18553034Sdougm /* 18563034Sdougm * sa_create_group(groupname, *error) 18573034Sdougm * 18583034Sdougm * Create a new group with groupname. Need to validate that it is a 18593034Sdougm * legal name for SMF and the construct the SMF service instance of 18603034Sdougm * svc:/network/shares/group to implement the group. All necessary 18613034Sdougm * operational properties must be added to the group at this point 18623034Sdougm * (via the SMF transaction model). 18633034Sdougm */ 18643034Sdougm sa_group_t 18653910Sdougm sa_create_group(sa_handle_t handle, char *groupname, int *error) 18663034Sdougm { 18673034Sdougm xmlNodePtr node = NULL; 18683034Sdougm sa_group_t group; 18693034Sdougm int ret; 18704327Sdougm char rbacstr[SA_STRSIZE]; 18713910Sdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle; 18723034Sdougm 18733034Sdougm ret = SA_OK; 18743034Sdougm 18753910Sdougm if (impl_handle == NULL || impl_handle->scfhandle == NULL) { 18764327Sdougm ret = SA_SYSTEM_ERR; 18774327Sdougm goto err; 18783034Sdougm } 18793034Sdougm 18803910Sdougm group = sa_get_group(handle, groupname); 18813034Sdougm if (group != NULL) { 18824327Sdougm ret = SA_DUPLICATE_NAME; 18833034Sdougm } else { 18844327Sdougm if (sa_valid_group_name(groupname)) { 18854327Sdougm node = xmlNewChild(impl_handle->tree, NULL, 18864327Sdougm (xmlChar *)"group", NULL); 18874327Sdougm if (node != NULL) { 18886007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 18894327Sdougm (xmlChar *)groupname); 18904327Sdougm /* default to the group being enabled */ 18916007Sthurlow (void) xmlSetProp(node, (xmlChar *)"state", 18924327Sdougm (xmlChar *)"enabled"); 18934327Sdougm ret = sa_create_instance(impl_handle->scfhandle, 18944327Sdougm groupname); 18954327Sdougm if (ret == SA_OK) { 18964327Sdougm ret = sa_start_transaction( 18974327Sdougm impl_handle->scfhandle, 18984327Sdougm "operation"); 18994327Sdougm } 19004327Sdougm if (ret == SA_OK) { 19014327Sdougm ret = sa_set_property( 19024327Sdougm impl_handle->scfhandle, 19034327Sdougm "state", "enabled"); 19044327Sdougm if (ret == SA_OK) { 19054327Sdougm ret = sa_end_transaction( 19065951Sdougm impl_handle->scfhandle, 19075951Sdougm impl_handle); 19084327Sdougm } else { 19094327Sdougm sa_abort_transaction( 19104327Sdougm impl_handle->scfhandle); 19114327Sdougm } 19124327Sdougm } 19134327Sdougm if (ret == SA_OK) { 19144327Sdougm /* initialize the RBAC strings */ 19154327Sdougm ret = sa_start_transaction( 19164327Sdougm impl_handle->scfhandle, 19174327Sdougm "general"); 19184327Sdougm if (ret == SA_OK) { 19194327Sdougm (void) snprintf(rbacstr, 19204327Sdougm sizeof (rbacstr), "%s.%s", 19214327Sdougm SA_RBAC_MANAGE, groupname); 19224327Sdougm ret = sa_set_property( 19234327Sdougm impl_handle->scfhandle, 19243034Sdougm "action_authorization", 19253034Sdougm rbacstr); 19264327Sdougm } 19274327Sdougm if (ret == SA_OK) { 19284327Sdougm (void) snprintf(rbacstr, 19294327Sdougm sizeof (rbacstr), "%s.%s", 19304327Sdougm SA_RBAC_VALUE, groupname); 19314327Sdougm ret = sa_set_property( 19324327Sdougm impl_handle->scfhandle, 19333034Sdougm "value_authorization", 19343034Sdougm rbacstr); 19354327Sdougm } 19364327Sdougm if (ret == SA_OK) { 19374327Sdougm ret = sa_end_transaction( 19385951Sdougm impl_handle->scfhandle, 19395951Sdougm impl_handle); 19404327Sdougm } else { 19414327Sdougm sa_abort_transaction( 19424327Sdougm impl_handle->scfhandle); 19434327Sdougm } 19444327Sdougm } 19454327Sdougm if (ret != SA_OK) { 19464327Sdougm /* 19474327Sdougm * Couldn't commit the group 19484327Sdougm * so we need to undo 19494327Sdougm * internally. 19504327Sdougm */ 19514327Sdougm xmlUnlinkNode(node); 19524327Sdougm xmlFreeNode(node); 19534327Sdougm node = NULL; 19544327Sdougm } 19553034Sdougm } else { 19564327Sdougm ret = SA_NO_MEMORY; 19573034Sdougm } 19583034Sdougm } else { 19594327Sdougm ret = SA_INVALID_NAME; 19603034Sdougm } 19613034Sdougm } 19623034Sdougm err: 19633034Sdougm if (error != NULL) 19644327Sdougm *error = ret; 19653034Sdougm return ((sa_group_t)node); 19663034Sdougm } 19673034Sdougm 19683034Sdougm /* 19693034Sdougm * sa_remove_group(group) 19703034Sdougm * 19713034Sdougm * Remove the specified group. This deletes from the SMF repository. 19723034Sdougm * All property groups and properties are removed. 19733034Sdougm */ 19743034Sdougm 19753034Sdougm int 19763034Sdougm sa_remove_group(sa_group_t group) 19773034Sdougm { 19783034Sdougm char *name; 19793034Sdougm int ret = SA_OK; 19803910Sdougm sa_handle_impl_t impl_handle; 19813034Sdougm 19823910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 19833910Sdougm if (impl_handle != NULL) { 19844327Sdougm name = sa_get_group_attr(group, "name"); 19854327Sdougm if (name != NULL) { 19864327Sdougm ret = sa_delete_instance(impl_handle->scfhandle, name); 19874327Sdougm sa_free_attr_string(name); 19884327Sdougm } 19894327Sdougm xmlUnlinkNode((xmlNodePtr)group); /* make sure unlinked */ 19904327Sdougm xmlFreeNode((xmlNodePtr)group); /* now it is gone */ 19913910Sdougm } else { 19924327Sdougm ret = SA_SYSTEM_ERR; 19933034Sdougm } 19943034Sdougm return (ret); 19953034Sdougm } 19963034Sdougm 19973034Sdougm /* 19983034Sdougm * sa_update_config() 19993034Sdougm * 20003034Sdougm * Used to update legacy files that need to be updated in bulk 20013034Sdougm * Currently, this is a placeholder and will go away in a future 20023034Sdougm * release. 20033034Sdougm */ 20043034Sdougm 20053034Sdougm int 20063910Sdougm sa_update_config(sa_handle_t handle) 20073034Sdougm { 20083034Sdougm /* 20093034Sdougm * do legacy files first so we can tell when they change. 20103034Sdougm * This will go away when we start updating individual records 20113034Sdougm * rather than the whole file. 20123034Sdougm */ 20133910Sdougm update_legacy_config(handle); 20143034Sdougm return (SA_OK); 20153034Sdougm } 20163034Sdougm 20173034Sdougm /* 20183034Sdougm * get_node_attr(node, tag) 20193034Sdougm * 20205331Samw * Get the specified tag(attribute) if it exists on the node. This is 20213034Sdougm * used internally by a number of attribute oriented functions. 20223034Sdougm */ 20233034Sdougm 20243034Sdougm static char * 20253034Sdougm get_node_attr(void *nodehdl, char *tag) 20263034Sdougm { 20273034Sdougm xmlNodePtr node = (xmlNodePtr)nodehdl; 20283034Sdougm xmlChar *name = NULL; 20293034Sdougm 20304327Sdougm if (node != NULL) 20313034Sdougm name = xmlGetProp(node, (xmlChar *)tag); 20323034Sdougm return ((char *)name); 20333034Sdougm } 20343034Sdougm 20353034Sdougm /* 20363034Sdougm * get_node_attr(node, tag) 20373034Sdougm * 20385331Samw * Set the specified tag(attribute) to the specified value This is 20393034Sdougm * used internally by a number of attribute oriented functions. It 20403034Sdougm * doesn't update the repository, only the internal document state. 20413034Sdougm */ 20423034Sdougm 20433034Sdougm void 20443034Sdougm set_node_attr(void *nodehdl, char *tag, char *value) 20453034Sdougm { 20463034Sdougm xmlNodePtr node = (xmlNodePtr)nodehdl; 20473034Sdougm if (node != NULL && tag != NULL) { 20484327Sdougm if (value != NULL) 20496007Sthurlow (void) xmlSetProp(node, (xmlChar *)tag, 20506007Sthurlow (xmlChar *)value); 20514327Sdougm else 20526007Sthurlow (void) xmlUnsetProp(node, (xmlChar *)tag); 20533034Sdougm } 20543034Sdougm } 20553034Sdougm 20563034Sdougm /* 20573034Sdougm * sa_get_group_attr(group, tag) 20583034Sdougm * 20593034Sdougm * Get the specied attribute, if defined, for the group. 20603034Sdougm */ 20613034Sdougm 20623034Sdougm char * 20633034Sdougm sa_get_group_attr(sa_group_t group, char *tag) 20643034Sdougm { 20653034Sdougm return (get_node_attr((void *)group, tag)); 20663034Sdougm } 20673034Sdougm 20683034Sdougm /* 20693034Sdougm * sa_set_group_attr(group, tag, value) 20703034Sdougm * 20713034Sdougm * set the specified tag/attribute on the group using value as its 20723034Sdougm * value. 20733034Sdougm * 20743034Sdougm * This will result in setting the property in the SMF repository as 20753034Sdougm * well as in the internal document. 20763034Sdougm */ 20773034Sdougm 20783034Sdougm int 20793034Sdougm sa_set_group_attr(sa_group_t group, char *tag, char *value) 20803034Sdougm { 20813034Sdougm int ret; 20823034Sdougm char *groupname; 20833910Sdougm sa_handle_impl_t impl_handle; 20843034Sdougm 20855331Samw /* 20865331Samw * ZFS group/subgroup doesn't need the handle so shortcut. 20875331Samw */ 20885331Samw if (sa_group_is_zfs(group)) { 20895331Samw set_node_attr((void *)group, tag, value); 20905331Samw return (SA_OK); 20915331Samw } 20925331Samw 20933910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 20943910Sdougm if (impl_handle != NULL) { 20954327Sdougm groupname = sa_get_group_attr(group, "name"); 20964327Sdougm ret = sa_get_instance(impl_handle->scfhandle, groupname); 20973910Sdougm if (ret == SA_OK) { 20984327Sdougm set_node_attr((void *)group, tag, value); 20994327Sdougm ret = sa_start_transaction(impl_handle->scfhandle, 21004327Sdougm "operation"); 21014327Sdougm if (ret == SA_OK) { 21024327Sdougm ret = sa_set_property(impl_handle->scfhandle, 21034327Sdougm tag, value); 21044327Sdougm if (ret == SA_OK) 21055885Sdougm ret = sa_end_transaction( 21065951Sdougm impl_handle->scfhandle, 21075951Sdougm impl_handle); 21084327Sdougm else 21094327Sdougm sa_abort_transaction( 21104327Sdougm impl_handle->scfhandle); 21114327Sdougm } 21125885Sdougm if (ret == SA_SYSTEM_ERR) 21135885Sdougm ret = SA_NO_PERMISSION; 21143034Sdougm } 21154327Sdougm if (groupname != NULL) 21164327Sdougm sa_free_attr_string(groupname); 21173910Sdougm } else { 21184327Sdougm ret = SA_SYSTEM_ERR; 21193034Sdougm } 21203034Sdougm return (ret); 21213034Sdougm } 21223034Sdougm 21233034Sdougm /* 21243034Sdougm * sa_get_share_attr(share, tag) 21253034Sdougm * 21263034Sdougm * Return the value of the tag/attribute set on the specified 21273034Sdougm * share. Returns NULL if the tag doesn't exist. 21283034Sdougm */ 21293034Sdougm 21303034Sdougm char * 21313034Sdougm sa_get_share_attr(sa_share_t share, char *tag) 21323034Sdougm { 21333034Sdougm return (get_node_attr((void *)share, tag)); 21343034Sdougm } 21353034Sdougm 21363034Sdougm /* 21373034Sdougm * _sa_set_share_description(share, description) 21383034Sdougm * 21395331Samw * Add a description tag with text contents to the specified share. A 21405331Samw * separate XML tag is used rather than a property. This can also be 21415331Samw * used with resources. 21423034Sdougm */ 21433034Sdougm 21443034Sdougm xmlNodePtr 21455331Samw _sa_set_share_description(void *share, char *content) 21463034Sdougm { 21473034Sdougm xmlNodePtr node; 21484327Sdougm node = xmlNewChild((xmlNodePtr)share, NULL, (xmlChar *)"description", 21494327Sdougm NULL); 21503034Sdougm xmlNodeSetContent(node, (xmlChar *)content); 21513034Sdougm return (node); 21523034Sdougm } 21533034Sdougm 21543034Sdougm /* 21553034Sdougm * sa_set_share_attr(share, tag, value) 21563034Sdougm * 21573034Sdougm * Set the share attribute specified by tag to the specified value. In 21583034Sdougm * the case of "resource", enforce a no duplicates in a group rule. If 21593034Sdougm * the share is not transient, commit the changes to the repository 21603034Sdougm * else just update the share internally. 21613034Sdougm */ 21623034Sdougm 21633034Sdougm int 21643034Sdougm sa_set_share_attr(sa_share_t share, char *tag, char *value) 21653034Sdougm { 21663034Sdougm sa_group_t group; 21673034Sdougm sa_share_t resource; 21683034Sdougm int ret = SA_OK; 21693034Sdougm 21703034Sdougm group = sa_get_parent_group(share); 21713034Sdougm 21723034Sdougm /* 21733034Sdougm * There are some attributes that may have specific 21743034Sdougm * restrictions on them. Initially, only "resource" has 21753034Sdougm * special meaning that needs to be checked. Only one instance 21763034Sdougm * of a resource name may exist within a group. 21773034Sdougm */ 21783034Sdougm 21793034Sdougm if (strcmp(tag, "resource") == 0) { 21804327Sdougm resource = sa_get_resource(group, value); 21814327Sdougm if (resource != share && resource != NULL) 21824327Sdougm ret = SA_DUPLICATE_NAME; 21833034Sdougm } 21843034Sdougm if (ret == SA_OK) { 21854327Sdougm set_node_attr((void *)share, tag, value); 21864327Sdougm if (group != NULL) { 21874327Sdougm char *type; 21884327Sdougm /* we can probably optimize this some */ 21894327Sdougm type = sa_get_share_attr(share, "type"); 21904327Sdougm if (type == NULL || strcmp(type, "transient") != 0) { 21914327Sdougm sa_handle_impl_t impl_handle; 21924327Sdougm impl_handle = 21934327Sdougm (sa_handle_impl_t)sa_find_group_handle( 21944327Sdougm group); 21954327Sdougm if (impl_handle != NULL) { 21964327Sdougm ret = sa_commit_share( 21974327Sdougm impl_handle->scfhandle, group, 21984327Sdougm share); 21994327Sdougm } else { 22004327Sdougm ret = SA_SYSTEM_ERR; 22014327Sdougm } 22024327Sdougm } 22034327Sdougm if (type != NULL) 22044327Sdougm sa_free_attr_string(type); 22053910Sdougm } 22063034Sdougm } 22073034Sdougm return (ret); 22083034Sdougm } 22093034Sdougm 22103034Sdougm /* 22113034Sdougm * sa_get_property_attr(prop, tag) 22123034Sdougm * 22133034Sdougm * Get the value of the specified property attribute. Standard 22143034Sdougm * attributes are "type" and "value". 22153034Sdougm */ 22163034Sdougm 22173034Sdougm char * 22183034Sdougm sa_get_property_attr(sa_property_t prop, char *tag) 22193034Sdougm { 22203034Sdougm return (get_node_attr((void *)prop, tag)); 22213034Sdougm } 22223034Sdougm 22233034Sdougm /* 22243034Sdougm * sa_get_optionset_attr(prop, tag) 22253034Sdougm * 22263034Sdougm * Get the value of the specified property attribute. Standard 22273034Sdougm * attribute is "type". 22283034Sdougm */ 22293034Sdougm 22303034Sdougm char * 22313034Sdougm sa_get_optionset_attr(sa_property_t optionset, char *tag) 22323034Sdougm { 22333034Sdougm return (get_node_attr((void *)optionset, tag)); 22343034Sdougm 22353034Sdougm } 22363034Sdougm 22373034Sdougm /* 22383034Sdougm * sa_set_optionset_attr(optionset, tag, value) 22393034Sdougm * 22403034Sdougm * Set the specified attribute(tag) to the specified value on the 22413034Sdougm * optionset. 22423034Sdougm */ 22433034Sdougm 22443034Sdougm void 22453034Sdougm sa_set_optionset_attr(sa_group_t optionset, char *tag, char *value) 22463034Sdougm { 22473034Sdougm set_node_attr((void *)optionset, tag, value); 22483034Sdougm } 22493034Sdougm 22503034Sdougm /* 22513034Sdougm * sa_free_attr_string(string) 22523034Sdougm * 22533034Sdougm * Free the string that was returned in one of the sa_get_*_attr() 22543034Sdougm * functions. 22553034Sdougm */ 22563034Sdougm 22573034Sdougm void 22583034Sdougm sa_free_attr_string(char *string) 22593034Sdougm { 22603034Sdougm xmlFree((xmlChar *)string); 22613034Sdougm } 22623034Sdougm 22633034Sdougm /* 22643034Sdougm * sa_get_optionset(group, proto) 22653034Sdougm * 22663034Sdougm * Return the optionset, if it exists, that is associated with the 22673034Sdougm * specified protocol. 22683034Sdougm */ 22693034Sdougm 22703034Sdougm sa_optionset_t 22713034Sdougm sa_get_optionset(void *group, char *proto) 22723034Sdougm { 22733034Sdougm xmlNodePtr node; 22743034Sdougm xmlChar *value = NULL; 22753034Sdougm 22763034Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 22774327Sdougm node = node->next) { 22783034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) { 22794327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 22804327Sdougm if (proto != NULL) { 22814327Sdougm if (value != NULL && 22824327Sdougm xmlStrcmp(value, (xmlChar *)proto) == 0) { 22834327Sdougm break; 22844327Sdougm } 22854327Sdougm if (value != NULL) { 22864327Sdougm xmlFree(value); 22874327Sdougm value = NULL; 22884327Sdougm } 22894327Sdougm } else { 22904327Sdougm break; 22913034Sdougm } 22923034Sdougm } 22933034Sdougm } 22943034Sdougm if (value != NULL) 22954327Sdougm xmlFree(value); 22963034Sdougm return ((sa_optionset_t)node); 22973034Sdougm } 22983034Sdougm 22993034Sdougm /* 23003034Sdougm * sa_get_next_optionset(optionset) 23013034Sdougm * 23023034Sdougm * Return the next optionset in the group. NULL if this was the last. 23033034Sdougm */ 23043034Sdougm 23053034Sdougm sa_optionset_t 23063034Sdougm sa_get_next_optionset(sa_optionset_t optionset) 23073034Sdougm { 23083034Sdougm xmlNodePtr node; 23093034Sdougm 23103034Sdougm for (node = ((xmlNodePtr)optionset)->next; node != NULL; 23114327Sdougm node = node->next) { 23123034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) { 23133034Sdougm break; 23143034Sdougm } 23153034Sdougm } 23163034Sdougm return ((sa_optionset_t)node); 23173034Sdougm } 23183034Sdougm 23193034Sdougm /* 23203034Sdougm * sa_get_security(group, sectype, proto) 23213034Sdougm * 23223034Sdougm * Return the security optionset. The internal name is a hold over 23233034Sdougm * from the implementation and will be changed before the API is 23243034Sdougm * finalized. This is really a named optionset that can be negotiated 23253034Sdougm * as a group of properties (like NFS security options). 23263034Sdougm */ 23273034Sdougm 23283034Sdougm sa_security_t 23293034Sdougm sa_get_security(sa_group_t group, char *sectype, char *proto) 23303034Sdougm { 23313034Sdougm xmlNodePtr node; 23323034Sdougm xmlChar *value = NULL; 23333034Sdougm 23343034Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 23354327Sdougm node = node->next) { 23364327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) { 23374327Sdougm if (proto != NULL) { 23384327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 23394327Sdougm if (value == NULL || 23404327Sdougm (value != NULL && 23414327Sdougm xmlStrcmp(value, (xmlChar *)proto) != 0)) { 23424327Sdougm /* it doesn't match so continue */ 23434327Sdougm xmlFree(value); 23444327Sdougm value = NULL; 23454327Sdougm continue; 23464327Sdougm } 23474327Sdougm } 23484327Sdougm if (value != NULL) { 23494327Sdougm xmlFree(value); 23504327Sdougm value = NULL; 23514327Sdougm } 23524327Sdougm /* potential match */ 23534327Sdougm if (sectype != NULL) { 23544327Sdougm value = xmlGetProp(node, (xmlChar *)"sectype"); 23554327Sdougm if (value != NULL && 23564327Sdougm xmlStrcmp(value, (xmlChar *)sectype) == 0) { 23574327Sdougm break; 23584327Sdougm } 23594327Sdougm } else { 23604327Sdougm break; 23614327Sdougm } 23623034Sdougm } 23633034Sdougm if (value != NULL) { 23644327Sdougm xmlFree(value); 23654327Sdougm value = NULL; 23663034Sdougm } 23673034Sdougm } 23683034Sdougm if (value != NULL) 23694327Sdougm xmlFree(value); 23703034Sdougm return ((sa_security_t)node); 23713034Sdougm } 23723034Sdougm 23733034Sdougm /* 23743034Sdougm * sa_get_next_security(security) 23753034Sdougm * 23763034Sdougm * Get the next security optionset if one exists. 23773034Sdougm */ 23783034Sdougm 23793034Sdougm sa_security_t 23803034Sdougm sa_get_next_security(sa_security_t security) 23813034Sdougm { 23823034Sdougm xmlNodePtr node; 23833034Sdougm 23843034Sdougm for (node = ((xmlNodePtr)security)->next; node != NULL; 23854327Sdougm node = node->next) { 23863034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) { 23873034Sdougm break; 23883034Sdougm } 23893034Sdougm } 23903034Sdougm return ((sa_security_t)node); 23913034Sdougm } 23923034Sdougm 23933034Sdougm /* 23943034Sdougm * sa_get_property(optionset, prop) 23953034Sdougm * 23963034Sdougm * Get the property object with the name specified in prop from the 23973034Sdougm * optionset. 23983034Sdougm */ 23993034Sdougm 24003034Sdougm sa_property_t 24013034Sdougm sa_get_property(sa_optionset_t optionset, char *prop) 24023034Sdougm { 24033034Sdougm xmlNodePtr node = (xmlNodePtr)optionset; 24043034Sdougm xmlChar *value = NULL; 24053034Sdougm 24063034Sdougm if (optionset == NULL) 24074327Sdougm return (NULL); 24083034Sdougm 24093034Sdougm for (node = node->children; node != NULL; 24104327Sdougm node = node->next) { 24114327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 24124327Sdougm if (prop == NULL) 24134327Sdougm break; 24144327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 24154327Sdougm if (value != NULL && 24164327Sdougm xmlStrcmp(value, (xmlChar *)prop) == 0) { 24174327Sdougm break; 24184327Sdougm } 24194327Sdougm if (value != NULL) { 24204327Sdougm xmlFree(value); 24214327Sdougm value = NULL; 24224327Sdougm } 24233034Sdougm } 24243034Sdougm } 24253034Sdougm if (value != NULL) 24263034Sdougm xmlFree(value); 24273034Sdougm if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"option") != 0) { 24284327Sdougm /* 24294327Sdougm * avoid a non option node -- it is possible to be a 24304327Sdougm * text node 24314327Sdougm */ 24324327Sdougm node = NULL; 24333034Sdougm } 24343034Sdougm return ((sa_property_t)node); 24353034Sdougm } 24363034Sdougm 24373034Sdougm /* 24383034Sdougm * sa_get_next_property(property) 24393034Sdougm * 24403034Sdougm * Get the next property following the specified property. NULL if 24413034Sdougm * this was the last. 24423034Sdougm */ 24433034Sdougm 24443034Sdougm sa_property_t 24453034Sdougm sa_get_next_property(sa_property_t property) 24463034Sdougm { 24473034Sdougm xmlNodePtr node; 24483034Sdougm 24493034Sdougm for (node = ((xmlNodePtr)property)->next; node != NULL; 24504327Sdougm node = node->next) { 24513034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 24523034Sdougm break; 24533034Sdougm } 24543034Sdougm } 24553034Sdougm return ((sa_property_t)node); 24563034Sdougm } 24573034Sdougm 24583034Sdougm /* 24593034Sdougm * sa_set_share_description(share, content) 24603034Sdougm * 24613034Sdougm * Set the description of share to content. 24623034Sdougm */ 24633034Sdougm 24643034Sdougm int 24653034Sdougm sa_set_share_description(sa_share_t share, char *content) 24663034Sdougm { 24673034Sdougm xmlNodePtr node; 24683034Sdougm sa_group_t group; 24693034Sdougm int ret = SA_OK; 24703034Sdougm 24713034Sdougm for (node = ((xmlNodePtr)share)->children; node != NULL; 24724327Sdougm node = node->next) { 24733034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 24743034Sdougm break; 24753034Sdougm } 24763034Sdougm } 24773034Sdougm /* no existing description but want to add */ 24783034Sdougm if (node == NULL && content != NULL) { 24793034Sdougm /* add a description */ 24804327Sdougm node = _sa_set_share_description(share, content); 24813034Sdougm } else if (node != NULL && content != NULL) { 24823034Sdougm /* update a description */ 24833034Sdougm xmlNodeSetContent(node, (xmlChar *)content); 24843034Sdougm } else if (node != NULL && content == NULL) { 24853034Sdougm /* remove an existing description */ 24863034Sdougm xmlUnlinkNode(node); 24873034Sdougm xmlFreeNode(node); 24883034Sdougm } 24895331Samw group = sa_get_parent_group(share); 24905331Samw if (group != NULL && sa_is_persistent(share)) { 24914327Sdougm sa_handle_impl_t impl_handle; 24924327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 24934327Sdougm if (impl_handle != NULL) { 24944327Sdougm ret = sa_commit_share(impl_handle->scfhandle, group, 24954327Sdougm share); 24964327Sdougm } else { 24974327Sdougm ret = SA_SYSTEM_ERR; 24984327Sdougm } 24993910Sdougm } 25003034Sdougm return (ret); 25013034Sdougm } 25023034Sdougm 25033034Sdougm /* 25043034Sdougm * fixproblemchars(string) 25053034Sdougm * 25063034Sdougm * don't want any newline or tab characters in the text since these 25073034Sdougm * could break display of data and legacy file formats. 25083034Sdougm */ 25093034Sdougm static void 25103034Sdougm fixproblemchars(char *str) 25113034Sdougm { 25123034Sdougm int c; 25133034Sdougm for (c = *str; c != '\0'; c = *++str) { 25144327Sdougm if (c == '\t' || c == '\n') 25154327Sdougm *str = ' '; 25164327Sdougm else if (c == '"') 25174327Sdougm *str = '\''; 25183034Sdougm } 25193034Sdougm } 25203034Sdougm 25213034Sdougm /* 25223034Sdougm * sa_get_share_description(share) 25233034Sdougm * 25243034Sdougm * Return the description text for the specified share if it 25253034Sdougm * exists. NULL if no description exists. 25263034Sdougm */ 25273034Sdougm 25283034Sdougm char * 25293034Sdougm sa_get_share_description(sa_share_t share) 25303034Sdougm { 25313034Sdougm xmlChar *description = NULL; 25323034Sdougm xmlNodePtr node; 25333034Sdougm 25343034Sdougm for (node = ((xmlNodePtr)share)->children; node != NULL; 25354327Sdougm node = node->next) { 25364327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 25374327Sdougm break; 25384327Sdougm } 25393034Sdougm } 25403034Sdougm if (node != NULL) { 25415331Samw description = xmlNodeGetContent(node); 25424327Sdougm fixproblemchars((char *)description); 25433034Sdougm } 25443034Sdougm return ((char *)description); 25453034Sdougm } 25463034Sdougm 25473034Sdougm /* 25483034Sdougm * sa_free(share_description(description) 25493034Sdougm * 25503034Sdougm * Free the description string. 25513034Sdougm */ 25523034Sdougm 25533034Sdougm void 25543034Sdougm sa_free_share_description(char *description) 25553034Sdougm { 25563034Sdougm xmlFree((xmlChar *)description); 25573034Sdougm } 25583034Sdougm 25593034Sdougm /* 25603034Sdougm * sa_create_optionset(group, proto) 25613034Sdougm * 25623034Sdougm * Create an optionset for the specified protocol in the specied 25633034Sdougm * group. This is manifested as a property group within SMF. 25643034Sdougm */ 25653034Sdougm 25663034Sdougm sa_optionset_t 25673034Sdougm sa_create_optionset(sa_group_t group, char *proto) 25683034Sdougm { 25693034Sdougm sa_optionset_t optionset; 25703034Sdougm sa_group_t parent = group; 25715331Samw sa_share_t share = NULL; 25725331Samw int err = SA_OK; 25735331Samw char *id = NULL; 25743034Sdougm 25753034Sdougm optionset = sa_get_optionset(group, proto); 25763034Sdougm if (optionset != NULL) { 25773034Sdougm /* can't have a duplicate protocol */ 25784327Sdougm optionset = NULL; 25793034Sdougm } else { 25805331Samw /* 25815331Samw * Account for resource names being slightly 25825331Samw * different. 25835331Samw */ 25845331Samw if (sa_is_share(group)) { 25855331Samw /* 25865331Samw * Transient shares do not have an "id" so not an 25875331Samw * error to not find one. 25885331Samw */ 25895331Samw id = sa_get_share_attr((sa_share_t)group, "id"); 25905331Samw } else if (sa_is_resource(group)) { 25915331Samw share = sa_get_resource_parent( 25925331Samw (sa_resource_t)group); 25935331Samw id = sa_get_resource_attr(share, "id"); 25945331Samw 25955331Samw /* id can be NULL if the group is transient (ZFS) */ 25965331Samw if (id == NULL && sa_is_persistent(group)) 25975331Samw err = SA_NO_MEMORY; 25985331Samw } 25995331Samw if (err == SA_NO_MEMORY) { 26005331Samw /* 26015331Samw * Couldn't get the id for the share or 26025331Samw * resource. While this could be a 26035331Samw * configuration issue, it is most likely an 26045331Samw * out of memory. In any case, fail the create. 26055331Samw */ 26065331Samw return (NULL); 26075331Samw } 26085331Samw 26094327Sdougm optionset = (sa_optionset_t)xmlNewChild((xmlNodePtr)group, 26104327Sdougm NULL, (xmlChar *)"optionset", NULL); 26113034Sdougm /* 26123034Sdougm * only put to repository if on a group and we were 26133034Sdougm * able to create an optionset. 26143034Sdougm */ 26154327Sdougm if (optionset != NULL) { 26164327Sdougm char oname[SA_STRSIZE]; 26174327Sdougm char *groupname; 26185331Samw 26195331Samw /* 26205331Samw * Need to get parent group in all cases, but also get 26215331Samw * the share if this is a resource. 26225331Samw */ 26235331Samw if (sa_is_share(group)) { 26244327Sdougm parent = sa_get_parent_group((sa_share_t)group); 26255331Samw } else if (sa_is_resource(group)) { 26265331Samw share = sa_get_resource_parent( 26275331Samw (sa_resource_t)group); 26285331Samw parent = sa_get_parent_group(share); 26295331Samw } 26304327Sdougm 26314327Sdougm sa_set_optionset_attr(optionset, "type", proto); 26323034Sdougm 26334327Sdougm (void) sa_optionset_name(optionset, oname, 26344327Sdougm sizeof (oname), id); 26354327Sdougm groupname = sa_get_group_attr(parent, "name"); 26365331Samw if (groupname != NULL && sa_is_persistent(group)) { 26374327Sdougm sa_handle_impl_t impl_handle; 26385331Samw impl_handle = 26395331Samw (sa_handle_impl_t)sa_find_group_handle( 26405331Samw group); 26414327Sdougm assert(impl_handle != NULL); 26424327Sdougm if (impl_handle != NULL) { 26434327Sdougm (void) sa_get_instance( 26445331Samw impl_handle->scfhandle, groupname); 26454327Sdougm (void) sa_create_pgroup( 26464327Sdougm impl_handle->scfhandle, oname); 26474327Sdougm } 26484327Sdougm } 26494327Sdougm if (groupname != NULL) 26504327Sdougm sa_free_attr_string(groupname); 26513034Sdougm } 26523034Sdougm } 26535331Samw 26545331Samw if (id != NULL) 26555331Samw sa_free_attr_string(id); 26563034Sdougm return (optionset); 26573034Sdougm } 26583034Sdougm 26593034Sdougm /* 26603034Sdougm * sa_get_property_parent(property) 26613034Sdougm * 26623034Sdougm * Given a property, return the object it is a property of. This will 26633034Sdougm * be an optionset of some type. 26643034Sdougm */ 26653034Sdougm 26663034Sdougm static sa_optionset_t 26673034Sdougm sa_get_property_parent(sa_property_t property) 26683034Sdougm { 26693034Sdougm xmlNodePtr node = NULL; 26703034Sdougm 26714327Sdougm if (property != NULL) 26724327Sdougm node = ((xmlNodePtr)property)->parent; 26733034Sdougm return ((sa_optionset_t)node); 26743034Sdougm } 26753034Sdougm 26763034Sdougm /* 26773034Sdougm * sa_get_optionset_parent(optionset) 26783034Sdougm * 26793034Sdougm * Return the parent of the specified optionset. This could be a group 26803034Sdougm * or a share. 26813034Sdougm */ 26823034Sdougm 26833034Sdougm static sa_group_t 26843034Sdougm sa_get_optionset_parent(sa_optionset_t optionset) 26853034Sdougm { 26863034Sdougm xmlNodePtr node = NULL; 26873034Sdougm 26884327Sdougm if (optionset != NULL) 26894327Sdougm node = ((xmlNodePtr)optionset)->parent; 26903034Sdougm return ((sa_group_t)node); 26913034Sdougm } 26923034Sdougm 26933034Sdougm /* 26943034Sdougm * zfs_needs_update(share) 26953034Sdougm * 26963034Sdougm * In order to avoid making multiple updates to a ZFS share when 26973034Sdougm * setting properties, the share attribute "changed" will be set to 26985331Samw * true when a property is added or modified. When done adding 26993034Sdougm * properties, we can then detect that an update is needed. We then 27003034Sdougm * clear the state here to detect additional changes. 27013034Sdougm */ 27023034Sdougm 27033034Sdougm static int 27043034Sdougm zfs_needs_update(sa_share_t share) 27053034Sdougm { 27063034Sdougm char *attr; 27073034Sdougm int result = 0; 27083034Sdougm 27093034Sdougm attr = sa_get_share_attr(share, "changed"); 27103034Sdougm if (attr != NULL) { 27114327Sdougm sa_free_attr_string(attr); 27123034Sdougm result = 1; 27133034Sdougm } 27143034Sdougm set_node_attr((void *)share, "changed", NULL); 27153034Sdougm return (result); 27163034Sdougm } 27173034Sdougm 27183034Sdougm /* 27193034Sdougm * zfs_set_update(share) 27203034Sdougm * 27213034Sdougm * Set the changed attribute of the share to true. 27223034Sdougm */ 27233034Sdougm 27243034Sdougm static void 27253034Sdougm zfs_set_update(sa_share_t share) 27263034Sdougm { 27273034Sdougm set_node_attr((void *)share, "changed", "true"); 27283034Sdougm } 27293034Sdougm 27303034Sdougm /* 27313034Sdougm * sa_commit_properties(optionset, clear) 27323034Sdougm * 27333034Sdougm * Check if SMF or ZFS config and either update or abort the pending 27343034Sdougm * changes. 27353034Sdougm */ 27363034Sdougm 27373034Sdougm int 27383034Sdougm sa_commit_properties(sa_optionset_t optionset, int clear) 27393034Sdougm { 27403034Sdougm sa_group_t group; 27413034Sdougm sa_group_t parent; 27423034Sdougm int zfs = 0; 27433034Sdougm int needsupdate = 0; 27443034Sdougm int ret = SA_OK; 27453910Sdougm sa_handle_impl_t impl_handle; 27463034Sdougm 27473034Sdougm group = sa_get_optionset_parent(optionset); 27483034Sdougm if (group != NULL && (sa_is_share(group) || is_zfs_group(group))) { 27494327Sdougm /* only update ZFS if on a share */ 27504327Sdougm parent = sa_get_parent_group(group); 27514327Sdougm zfs++; 27524327Sdougm if (parent != NULL && is_zfs_group(parent)) 27534327Sdougm needsupdate = zfs_needs_update(group); 27544327Sdougm else 27554327Sdougm zfs = 0; 27563034Sdougm } 27573034Sdougm if (zfs) { 27584327Sdougm if (!clear && needsupdate) 27594327Sdougm ret = sa_zfs_update((sa_share_t)group); 27603034Sdougm } else { 27614327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 27624327Sdougm if (impl_handle != NULL) { 27634327Sdougm if (clear) { 27644327Sdougm (void) sa_abort_transaction( 27654327Sdougm impl_handle->scfhandle); 27664327Sdougm } else { 27674327Sdougm ret = sa_end_transaction( 27685951Sdougm impl_handle->scfhandle, impl_handle); 27694327Sdougm } 27704327Sdougm } else { 27714327Sdougm ret = SA_SYSTEM_ERR; 27724327Sdougm } 27733034Sdougm } 27743034Sdougm return (ret); 27753034Sdougm } 27763034Sdougm 27773034Sdougm /* 27783034Sdougm * sa_destroy_optionset(optionset) 27793034Sdougm * 27805331Samw * Remove the optionset from its group. Update the repository to 27813034Sdougm * reflect this change. 27823034Sdougm */ 27833034Sdougm 27843034Sdougm int 27853034Sdougm sa_destroy_optionset(sa_optionset_t optionset) 27863034Sdougm { 27874327Sdougm char name[SA_STRSIZE]; 27883034Sdougm int len; 27893034Sdougm int ret; 27903034Sdougm char *id = NULL; 27913034Sdougm sa_group_t group; 27923034Sdougm int ispersist = 1; 27933034Sdougm 27943034Sdougm /* now delete the prop group */ 27953034Sdougm group = sa_get_optionset_parent(optionset); 27965331Samw if (group != NULL) { 27975331Samw if (sa_is_resource(group)) { 27985331Samw sa_resource_t resource = group; 27995331Samw sa_share_t share = sa_get_resource_parent(resource); 28005331Samw group = sa_get_parent_group(share); 28015331Samw id = sa_get_share_attr(share, "id"); 28025331Samw } else if (sa_is_share(group)) { 28035331Samw id = sa_get_share_attr((sa_share_t)group, "id"); 28045331Samw } 28055331Samw ispersist = sa_is_persistent(group); 28063034Sdougm } 28073034Sdougm if (ispersist) { 28084327Sdougm sa_handle_impl_t impl_handle; 28094327Sdougm len = sa_optionset_name(optionset, name, sizeof (name), id); 28104327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 28114327Sdougm if (impl_handle != NULL) { 28124327Sdougm if (len > 0) { 28134327Sdougm ret = sa_delete_pgroup(impl_handle->scfhandle, 28144327Sdougm name); 28154327Sdougm } 28164327Sdougm } else { 28174327Sdougm ret = SA_SYSTEM_ERR; 28183910Sdougm } 28193034Sdougm } 28203034Sdougm xmlUnlinkNode((xmlNodePtr)optionset); 28213034Sdougm xmlFreeNode((xmlNodePtr)optionset); 28223034Sdougm if (id != NULL) 28234327Sdougm sa_free_attr_string(id); 28243034Sdougm return (ret); 28253034Sdougm } 28263034Sdougm 28273034Sdougm /* private to the implementation */ 28283034Sdougm int 28293034Sdougm _sa_remove_optionset(sa_optionset_t optionset) 28303034Sdougm { 28313034Sdougm int ret = SA_OK; 28323034Sdougm 28333034Sdougm xmlUnlinkNode((xmlNodePtr)optionset); 28343034Sdougm xmlFreeNode((xmlNodePtr)optionset); 28353034Sdougm return (ret); 28363034Sdougm } 28373034Sdougm 28383034Sdougm /* 28393034Sdougm * sa_create_security(group, sectype, proto) 28403034Sdougm * 28413034Sdougm * Create a security optionset (one that has a type name and a 28423034Sdougm * proto). Security is left over from a pure NFS implementation. The 28433034Sdougm * naming will change in the future when the API is released. 28443034Sdougm */ 28453034Sdougm sa_security_t 28463034Sdougm sa_create_security(sa_group_t group, char *sectype, char *proto) 28473034Sdougm { 28483034Sdougm sa_security_t security; 28493034Sdougm char *id = NULL; 28503034Sdougm sa_group_t parent; 28513034Sdougm char *groupname = NULL; 28523034Sdougm 28533034Sdougm if (group != NULL && sa_is_share(group)) { 28544327Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 28554327Sdougm parent = sa_get_parent_group(group); 28564327Sdougm if (parent != NULL) 28574327Sdougm groupname = sa_get_group_attr(parent, "name"); 28583034Sdougm } else if (group != NULL) { 28594327Sdougm groupname = sa_get_group_attr(group, "name"); 28603034Sdougm } 28613034Sdougm 28623034Sdougm security = sa_get_security(group, sectype, proto); 28633034Sdougm if (security != NULL) { 28643034Sdougm /* can't have a duplicate security option */ 28653034Sdougm security = NULL; 28663034Sdougm } else { 28673034Sdougm security = (sa_security_t)xmlNewChild((xmlNodePtr)group, 28684327Sdougm NULL, (xmlChar *)"security", NULL); 28693034Sdougm if (security != NULL) { 28704327Sdougm char oname[SA_STRSIZE]; 28713034Sdougm sa_set_security_attr(security, "type", proto); 28723034Sdougm 28733034Sdougm sa_set_security_attr(security, "sectype", sectype); 28743034Sdougm (void) sa_security_name(security, oname, 28754327Sdougm sizeof (oname), id); 28765331Samw if (groupname != NULL && sa_is_persistent(group)) { 28774327Sdougm sa_handle_impl_t impl_handle; 28784327Sdougm impl_handle = 28794327Sdougm (sa_handle_impl_t)sa_find_group_handle( 28804327Sdougm group); 28814327Sdougm if (impl_handle != NULL) { 28824327Sdougm (void) sa_get_instance( 28834327Sdougm impl_handle->scfhandle, groupname); 28844327Sdougm (void) sa_create_pgroup( 28854327Sdougm impl_handle->scfhandle, oname); 28864327Sdougm } 28873034Sdougm } 28883034Sdougm } 28893034Sdougm } 28903034Sdougm if (groupname != NULL) 28914327Sdougm sa_free_attr_string(groupname); 28923034Sdougm return (security); 28933034Sdougm } 28943034Sdougm 28953034Sdougm /* 28963034Sdougm * sa_destroy_security(security) 28973034Sdougm * 28983034Sdougm * Remove the specified optionset from the document and the 28993034Sdougm * configuration. 29003034Sdougm */ 29013034Sdougm 29023034Sdougm int 29033034Sdougm sa_destroy_security(sa_security_t security) 29043034Sdougm { 29054327Sdougm char name[SA_STRSIZE]; 29063034Sdougm int len; 29073034Sdougm int ret = SA_OK; 29083034Sdougm char *id = NULL; 29093034Sdougm sa_group_t group; 29103034Sdougm int iszfs = 0; 29113034Sdougm int ispersist = 1; 29123034Sdougm 29133034Sdougm group = sa_get_optionset_parent(security); 29143034Sdougm 29153034Sdougm if (group != NULL) 29164327Sdougm iszfs = sa_group_is_zfs(group); 29173034Sdougm 29183034Sdougm if (group != NULL && !iszfs) { 29194327Sdougm if (sa_is_share(group)) 29205331Samw ispersist = sa_is_persistent(group); 29214327Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 29223034Sdougm } 29233034Sdougm if (ispersist) { 29244327Sdougm len = sa_security_name(security, name, sizeof (name), id); 29254327Sdougm if (!iszfs && len > 0) { 29264327Sdougm sa_handle_impl_t impl_handle; 29274327Sdougm impl_handle = 29284327Sdougm (sa_handle_impl_t)sa_find_group_handle(group); 29294327Sdougm if (impl_handle != NULL) { 29304327Sdougm ret = sa_delete_pgroup(impl_handle->scfhandle, 29314327Sdougm name); 29324327Sdougm } else { 29334327Sdougm ret = SA_SYSTEM_ERR; 29344327Sdougm } 29353910Sdougm } 29363034Sdougm } 29373034Sdougm xmlUnlinkNode((xmlNodePtr)security); 29383034Sdougm xmlFreeNode((xmlNodePtr)security); 29394327Sdougm if (iszfs) 29404327Sdougm ret = sa_zfs_update(group); 29413034Sdougm if (id != NULL) 29424327Sdougm sa_free_attr_string(id); 29433034Sdougm return (ret); 29443034Sdougm } 29453034Sdougm 29463034Sdougm /* 29473034Sdougm * sa_get_security_attr(optionset, tag) 29483034Sdougm * 29493034Sdougm * Return the specified attribute value from the optionset. 29503034Sdougm */ 29513034Sdougm 29523034Sdougm char * 29533034Sdougm sa_get_security_attr(sa_property_t optionset, char *tag) 29543034Sdougm { 29553034Sdougm return (get_node_attr((void *)optionset, tag)); 29563034Sdougm 29573034Sdougm } 29583034Sdougm 29593034Sdougm /* 29603034Sdougm * sa_set_security_attr(optionset, tag, value) 29613034Sdougm * 29623034Sdougm * Set the optioset attribute specied by tag to the specified value. 29633034Sdougm */ 29643034Sdougm 29653034Sdougm void 29663034Sdougm sa_set_security_attr(sa_group_t optionset, char *tag, char *value) 29673034Sdougm { 29683034Sdougm set_node_attr((void *)optionset, tag, value); 29693034Sdougm } 29703034Sdougm 29713034Sdougm /* 29723034Sdougm * is_nodetype(node, type) 29733034Sdougm * 29743034Sdougm * Check to see if node is of the type specified. 29753034Sdougm */ 29763034Sdougm 29773034Sdougm static int 29783034Sdougm is_nodetype(void *node, char *type) 29793034Sdougm { 29803034Sdougm return (strcmp((char *)((xmlNodePtr)node)->name, type) == 0); 29813034Sdougm } 29823034Sdougm 29834327Sdougm /* 29844327Sdougm * add_or_update() 29854327Sdougm * 29864327Sdougm * Add or update a property. Pulled out of sa_set_prop_by_prop for 29874327Sdougm * readability. 29884327Sdougm */ 29894327Sdougm static int 29904327Sdougm add_or_update(scfutilhandle_t *scf_handle, int type, scf_value_t *value, 29914327Sdougm scf_transaction_entry_t *entry, char *name, char *valstr) 29924327Sdougm { 29934327Sdougm int ret = SA_SYSTEM_ERR; 29944327Sdougm 29954327Sdougm if (value != NULL) { 29964327Sdougm if (type == SA_PROP_OP_ADD) 29974327Sdougm ret = scf_transaction_property_new(scf_handle->trans, 29984327Sdougm entry, name, SCF_TYPE_ASTRING); 29994327Sdougm else 30004327Sdougm ret = scf_transaction_property_change(scf_handle->trans, 30014327Sdougm entry, name, SCF_TYPE_ASTRING); 30024327Sdougm if (ret == 0) { 30034327Sdougm ret = scf_value_set_astring(value, valstr); 30044327Sdougm if (ret == 0) 30054327Sdougm ret = scf_entry_add_value(entry, value); 30064327Sdougm if (ret == 0) 30074327Sdougm return (ret); 30084327Sdougm scf_value_destroy(value); 30094327Sdougm } else { 30104327Sdougm scf_entry_destroy(entry); 30114327Sdougm } 30124327Sdougm } 30134327Sdougm return (SA_SYSTEM_ERR); 30144327Sdougm } 30154327Sdougm 30163034Sdougm /* 30173034Sdougm * sa_set_prop_by_prop(optionset, group, prop, type) 30183034Sdougm * 30193034Sdougm * Add/remove/update the specified property prop into the optionset or 30203034Sdougm * share. If a share, sort out which property group based on GUID. In 30213034Sdougm * all cases, the appropriate transaction is set (or ZFS share is 30223034Sdougm * marked as needing an update) 30233034Sdougm */ 30243034Sdougm 30253034Sdougm static int 30263034Sdougm sa_set_prop_by_prop(sa_optionset_t optionset, sa_group_t group, 30273034Sdougm sa_property_t prop, int type) 30283034Sdougm { 30293034Sdougm char *name; 30303034Sdougm char *valstr; 30313034Sdougm int ret = SA_OK; 30323034Sdougm scf_transaction_entry_t *entry; 30333034Sdougm scf_value_t *value; 30343034Sdougm int opttype; /* 1 == optionset, 0 == security */ 30353034Sdougm char *id = NULL; 30363034Sdougm int iszfs = 0; 30373034Sdougm sa_group_t parent = NULL; 30385331Samw sa_share_t share = NULL; 30393910Sdougm sa_handle_impl_t impl_handle; 30403910Sdougm scfutilhandle_t *scf_handle; 30413034Sdougm 30425331Samw if (!sa_is_persistent(group)) { 30433034Sdougm /* 30443034Sdougm * if the group/share is not persistent we don't need 30453034Sdougm * to do anything here 30463034Sdougm */ 30474327Sdougm return (SA_OK); 30483034Sdougm } 30493910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 30504327Sdougm if (impl_handle == NULL || impl_handle->scfhandle == NULL) 30514327Sdougm return (SA_SYSTEM_ERR); 30523910Sdougm scf_handle = impl_handle->scfhandle; 30533034Sdougm name = sa_get_property_attr(prop, "type"); 30543034Sdougm valstr = sa_get_property_attr(prop, "value"); 30553034Sdougm entry = scf_entry_create(scf_handle->handle); 30563034Sdougm opttype = is_nodetype((void *)optionset, "optionset"); 30573034Sdougm 30585331Samw /* 30595331Samw * Check for share vs. resource since they need slightly 30605331Samw * different treatment given the hierarchy. 30615331Samw */ 30623034Sdougm if (valstr != NULL && entry != NULL) { 30634327Sdougm if (sa_is_share(group)) { 30644327Sdougm parent = sa_get_parent_group(group); 30655331Samw share = (sa_share_t)group; 30664327Sdougm if (parent != NULL) 30674327Sdougm iszfs = is_zfs_group(parent); 30685331Samw } else if (sa_is_resource(group)) { 30695331Samw share = sa_get_parent_group(group); 30705331Samw if (share != NULL) 30715331Samw parent = sa_get_parent_group(share); 30724327Sdougm } else { 30734327Sdougm iszfs = is_zfs_group(group); 30743034Sdougm } 30754327Sdougm if (!iszfs) { 30764327Sdougm if (scf_handle->trans == NULL) { 30774327Sdougm char oname[SA_STRSIZE]; 30784327Sdougm char *groupname = NULL; 30795331Samw if (share != NULL) { 30805331Samw if (parent != NULL) 30814327Sdougm groupname = 30824327Sdougm sa_get_group_attr(parent, 30834327Sdougm "name"); 30845331Samw id = sa_get_share_attr( 30855331Samw (sa_share_t)share, "id"); 30864327Sdougm } else { 30874327Sdougm groupname = sa_get_group_attr(group, 30884327Sdougm "name"); 30894327Sdougm } 30904327Sdougm if (groupname != NULL) { 30914327Sdougm ret = sa_get_instance(scf_handle, 30924327Sdougm groupname); 30934327Sdougm sa_free_attr_string(groupname); 30944327Sdougm } 30954327Sdougm if (opttype) 30964327Sdougm (void) sa_optionset_name(optionset, 30974327Sdougm oname, sizeof (oname), id); 30984327Sdougm else 30994327Sdougm (void) sa_security_name(optionset, 31004327Sdougm oname, sizeof (oname), id); 31014327Sdougm ret = sa_start_transaction(scf_handle, oname); 31023910Sdougm } 31034327Sdougm if (ret == SA_OK) { 31044327Sdougm switch (type) { 31054327Sdougm case SA_PROP_OP_REMOVE: 31064327Sdougm ret = scf_transaction_property_delete( 31074327Sdougm scf_handle->trans, entry, name); 31084327Sdougm break; 31094327Sdougm case SA_PROP_OP_ADD: 31104327Sdougm case SA_PROP_OP_UPDATE: 31114327Sdougm value = scf_value_create( 31124327Sdougm scf_handle->handle); 31134327Sdougm ret = add_or_update(scf_handle, type, 31144327Sdougm value, entry, name, valstr); 31154327Sdougm break; 31163034Sdougm } 31173034Sdougm } 31184327Sdougm } else { 31194327Sdougm /* 31204327Sdougm * ZFS update. The calling function would have updated 31214327Sdougm * the internal XML structure. Just need to flag it as 31224327Sdougm * changed for ZFS. 31234327Sdougm */ 31244327Sdougm zfs_set_update((sa_share_t)group); 31254327Sdougm } 31263034Sdougm } 31273034Sdougm 31283034Sdougm if (name != NULL) 31294327Sdougm sa_free_attr_string(name); 31303034Sdougm if (valstr != NULL) 31314327Sdougm sa_free_attr_string(valstr); 31323034Sdougm else if (entry != NULL) 31334327Sdougm scf_entry_destroy(entry); 31343034Sdougm 31353034Sdougm if (ret == -1) 31364327Sdougm ret = SA_SYSTEM_ERR; 31373034Sdougm 31383034Sdougm return (ret); 31393034Sdougm } 31403034Sdougm 31413034Sdougm /* 31426007Sthurlow * sa_create_section(name, value) 31436007Sthurlow * 31446007Sthurlow * Create a new section with the specified name and extra data. 31456007Sthurlow */ 31466007Sthurlow 31476007Sthurlow sa_property_t 31486007Sthurlow sa_create_section(char *name, char *extra) 31496007Sthurlow { 31506007Sthurlow xmlNodePtr node; 31516007Sthurlow 31526007Sthurlow node = xmlNewNode(NULL, (xmlChar *)"section"); 31536007Sthurlow if (node != NULL) { 31546007Sthurlow if (name != NULL) 31556007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 31566007Sthurlow (xmlChar *)name); 31576007Sthurlow if (extra != NULL) 31586007Sthurlow (void) xmlSetProp(node, (xmlChar *)"extra", 31596007Sthurlow (xmlChar *)extra); 31606007Sthurlow } 31616007Sthurlow return ((sa_property_t)node); 31626007Sthurlow } 31636007Sthurlow 31646007Sthurlow void 31656007Sthurlow sa_set_section_attr(sa_property_t sect, char *name, char *value) 31666007Sthurlow { 31676007Sthurlow (void) xmlSetProp(sect, (xmlChar *)name, (xmlChar *)value); 31686007Sthurlow } 31696007Sthurlow 31706007Sthurlow /* 31716007Sthurlow * sa_create_property(section, name, value) 31723034Sdougm * 31733034Sdougm * Create a new property with the specified name and value. 31743034Sdougm */ 31753034Sdougm 31763034Sdougm sa_property_t 31773034Sdougm sa_create_property(char *name, char *value) 31783034Sdougm { 31793034Sdougm xmlNodePtr node; 31803034Sdougm 31813034Sdougm node = xmlNewNode(NULL, (xmlChar *)"option"); 31823034Sdougm if (node != NULL) { 31836007Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", (xmlChar *)name); 31846007Sthurlow (void) xmlSetProp(node, (xmlChar *)"value", (xmlChar *)value); 31853034Sdougm } 31863034Sdougm return ((sa_property_t)node); 31873034Sdougm } 31883034Sdougm 31893034Sdougm /* 31903034Sdougm * sa_add_property(object, property) 31913034Sdougm * 31923034Sdougm * Add the specified property to the object. Issue the appropriate 31933034Sdougm * transaction or mark a ZFS object as needing an update. 31943034Sdougm */ 31953034Sdougm 31963034Sdougm int 31973034Sdougm sa_add_property(void *object, sa_property_t property) 31983034Sdougm { 31993034Sdougm int ret = SA_OK; 32003034Sdougm sa_group_t parent; 32013034Sdougm sa_group_t group; 32023034Sdougm char *proto; 32036214Sdougm sa_handle_t handle; 32046214Sdougm 32053034Sdougm if (property != NULL) { 32066214Sdougm handle = sa_find_group_handle((sa_group_t)object); 32076214Sdougm if (handle == NULL) 32086214Sdougm return (SA_CONFIG_ERR); 32096214Sdougm proto = sa_get_optionset_attr(object, "type"); 32106214Sdougm if ((ret = sa_valid_property(handle, object, proto, 32116214Sdougm property)) == SA_OK) { 32124327Sdougm property = (sa_property_t)xmlAddChild( 32134327Sdougm (xmlNodePtr)object, (xmlNodePtr)property); 32144327Sdougm } else { 32154327Sdougm if (proto != NULL) 32164327Sdougm sa_free_attr_string(proto); 32174327Sdougm return (ret); 32184327Sdougm } 32196214Sdougm if (proto != NULL) 32206214Sdougm sa_free_attr_string(proto); 32213034Sdougm } 32223034Sdougm 32233034Sdougm 32243034Sdougm parent = sa_get_parent_group(object); 32255331Samw if (!sa_is_persistent(parent)) 32264327Sdougm return (ret); 32275331Samw 32285331Samw if (sa_is_resource(parent)) { 32295331Samw /* 32305331Samw * Resources are children of share. Need to go up two 32315331Samw * levels to find the group but the parent needs to be 32325331Samw * the share at this point in order to get the "id". 32335331Samw */ 32345331Samw parent = sa_get_parent_group(parent); 32355331Samw group = sa_get_parent_group(parent); 32365331Samw } else if (sa_is_share(parent)) { 32375331Samw group = sa_get_parent_group(parent); 32385331Samw } else { 32395331Samw group = parent; 32403034Sdougm } 32413034Sdougm 32424327Sdougm if (property == NULL) { 32434327Sdougm ret = SA_NO_MEMORY; 32444327Sdougm } else { 32454327Sdougm char oname[SA_STRSIZE]; 32463034Sdougm 32474327Sdougm if (!is_zfs_group(group)) { 32484327Sdougm char *id = NULL; 32494327Sdougm sa_handle_impl_t impl_handle; 32504327Sdougm scfutilhandle_t *scf_handle; 32513910Sdougm 32524327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle( 32534327Sdougm group); 32544327Sdougm if (impl_handle == NULL || 32554327Sdougm impl_handle->scfhandle == NULL) 32564327Sdougm ret = SA_SYSTEM_ERR; 32574327Sdougm if (ret == SA_OK) { 32584327Sdougm scf_handle = impl_handle->scfhandle; 32594327Sdougm if (sa_is_share((sa_group_t)parent)) { 32604327Sdougm id = sa_get_share_attr( 32614327Sdougm (sa_share_t)parent, "id"); 32624327Sdougm } 32634327Sdougm if (scf_handle->trans == NULL) { 32644327Sdougm if (is_nodetype(object, "optionset")) { 32654327Sdougm (void) sa_optionset_name( 32664327Sdougm (sa_optionset_t)object, 32674327Sdougm oname, sizeof (oname), id); 32684327Sdougm } else { 32694327Sdougm (void) sa_security_name( 32704327Sdougm (sa_optionset_t)object, 32714327Sdougm oname, sizeof (oname), id); 32724327Sdougm } 32734327Sdougm ret = sa_start_transaction(scf_handle, 32744327Sdougm oname); 32754327Sdougm } 32764327Sdougm if (ret == SA_OK) { 32774327Sdougm char *name; 32784327Sdougm char *value; 32794327Sdougm name = sa_get_property_attr(property, 32804327Sdougm "type"); 32814327Sdougm value = sa_get_property_attr(property, 32824327Sdougm "value"); 32834327Sdougm if (name != NULL && value != NULL) { 32844327Sdougm if (scf_handle->scf_state == 32854327Sdougm SCH_STATE_INIT) { 32864327Sdougm ret = sa_set_property( 32874327Sdougm scf_handle, name, 32884327Sdougm value); 32894327Sdougm } 32904327Sdougm } else { 32914327Sdougm ret = SA_CONFIG_ERR; 32924327Sdougm } 32934327Sdougm if (name != NULL) 32944327Sdougm sa_free_attr_string( 32954327Sdougm name); 32964327Sdougm if (value != NULL) 32974327Sdougm sa_free_attr_string(value); 32984327Sdougm } 32994327Sdougm if (id != NULL) 33004327Sdougm sa_free_attr_string(id); 33014327Sdougm } 33024327Sdougm } else { 33034327Sdougm /* 33044327Sdougm * ZFS is a special case. We do want 33054327Sdougm * to allow editing property/security 33064327Sdougm * lists since we can have a better 33074327Sdougm * syntax and we also want to keep 33084327Sdougm * things consistent when possible. 33094327Sdougm * 33104327Sdougm * Right now, we defer until the 33114327Sdougm * sa_commit_properties so we can get 33124327Sdougm * them all at once. We do need to 33134327Sdougm * mark the share as "changed" 33144327Sdougm */ 33154327Sdougm zfs_set_update((sa_share_t)parent); 33163034Sdougm } 33173034Sdougm } 33183034Sdougm return (ret); 33193034Sdougm } 33203034Sdougm 33213034Sdougm /* 33223034Sdougm * sa_remove_property(property) 33233034Sdougm * 33243034Sdougm * Remove the specied property from its containing object. Update the 33253034Sdougm * repository as appropriate. 33263034Sdougm */ 33273034Sdougm 33283034Sdougm int 33293034Sdougm sa_remove_property(sa_property_t property) 33303034Sdougm { 33313034Sdougm int ret = SA_OK; 33323034Sdougm 33333034Sdougm if (property != NULL) { 33343034Sdougm sa_optionset_t optionset; 33353034Sdougm sa_group_t group; 33363034Sdougm optionset = sa_get_property_parent(property); 33373034Sdougm if (optionset != NULL) { 33384327Sdougm group = sa_get_optionset_parent(optionset); 33394327Sdougm if (group != NULL) { 33404327Sdougm ret = sa_set_prop_by_prop(optionset, group, 33414327Sdougm property, SA_PROP_OP_REMOVE); 33424327Sdougm } 33433034Sdougm } 33443034Sdougm xmlUnlinkNode((xmlNodePtr)property); 33453034Sdougm xmlFreeNode((xmlNodePtr)property); 33463034Sdougm } else { 33474327Sdougm ret = SA_NO_SUCH_PROP; 33483034Sdougm } 33493034Sdougm return (ret); 33503034Sdougm } 33513034Sdougm 33523034Sdougm /* 33533034Sdougm * sa_update_property(property, value) 33543034Sdougm * 33553034Sdougm * Update the specified property to the new value. If value is NULL, 33563034Sdougm * we currently treat this as a remove. 33573034Sdougm */ 33583034Sdougm 33593034Sdougm int 33603034Sdougm sa_update_property(sa_property_t property, char *value) 33613034Sdougm { 33623034Sdougm int ret = SA_OK; 33633034Sdougm if (value == NULL) { 33643034Sdougm return (sa_remove_property(property)); 33653034Sdougm } else { 33663034Sdougm sa_optionset_t optionset; 33673034Sdougm sa_group_t group; 33683034Sdougm set_node_attr((void *)property, "value", value); 33693034Sdougm optionset = sa_get_property_parent(property); 33703034Sdougm if (optionset != NULL) { 33714327Sdougm group = sa_get_optionset_parent(optionset); 33724327Sdougm if (group != NULL) { 33734327Sdougm ret = sa_set_prop_by_prop(optionset, group, 33744327Sdougm property, SA_PROP_OP_UPDATE); 33754327Sdougm } 33763034Sdougm } else { 33774327Sdougm ret = SA_NO_SUCH_PROP; 33783034Sdougm } 33793034Sdougm } 33803034Sdougm return (ret); 33813034Sdougm } 33823034Sdougm 33833034Sdougm /* 33846007Sthurlow * sa_get_protocol_section(propset, prop) 33856007Sthurlow * 33866007Sthurlow * Get the specified protocol specific section. These are global to 33876007Sthurlow * the protocol and not specific to a group or share. 33886007Sthurlow */ 33896007Sthurlow 33906007Sthurlow sa_protocol_properties_t 33916007Sthurlow sa_get_protocol_section(sa_protocol_properties_t propset, char *section) 33926007Sthurlow { 33936007Sthurlow xmlNodePtr node = (xmlNodePtr)propset; 33946007Sthurlow xmlChar *value = NULL; 33956007Sthurlow char *proto; 33966007Sthurlow 33976007Sthurlow proto = sa_get_optionset_attr(propset, "type"); 33986007Sthurlow if ((sa_proto_get_featureset(proto) & SA_FEATURE_HAS_SECTIONS) == 0) 33996007Sthurlow return (propset); 34006007Sthurlow 34016007Sthurlow for (node = node->children; node != NULL; 34026007Sthurlow node = node->next) { 34036007Sthurlow if (xmlStrcmp(node->name, (xmlChar *)"section") == 0) { 34046007Sthurlow if (section == NULL) 34056007Sthurlow break; 34066007Sthurlow value = xmlGetProp(node, (xmlChar *)"name"); 34076007Sthurlow if (value != NULL && 34086007Sthurlow xmlStrcasecmp(value, (xmlChar *)section) == 0) { 34096007Sthurlow break; 34106007Sthurlow } 34116007Sthurlow if (value != NULL) { 34126007Sthurlow xmlFree(value); 34136007Sthurlow value = NULL; 34146007Sthurlow } 34156007Sthurlow } 34166007Sthurlow } 34176007Sthurlow if (value != NULL) 34186007Sthurlow xmlFree(value); 34196007Sthurlow if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"section") != 0) { 34206007Sthurlow /* 34216007Sthurlow * avoid a non option node -- it is possible to be a 34226007Sthurlow * text node 34236007Sthurlow */ 34246007Sthurlow node = NULL; 34256007Sthurlow } 34266007Sthurlow return ((sa_protocol_properties_t)node); 34276007Sthurlow } 34286007Sthurlow 34296007Sthurlow /* 34306007Sthurlow * sa_get_next_protocol_section(prop, find) 34316007Sthurlow * 34326007Sthurlow * Get the next protocol specific section in the list. 34336007Sthurlow */ 34346007Sthurlow 34356007Sthurlow sa_property_t 34366007Sthurlow sa_get_next_protocol_section(sa_property_t prop, char *find) 34376007Sthurlow { 34386007Sthurlow xmlNodePtr node; 34396007Sthurlow xmlChar *value = NULL; 34406007Sthurlow char *proto; 34416007Sthurlow 34426007Sthurlow proto = sa_get_optionset_attr(prop, "type"); 34436007Sthurlow if ((sa_proto_get_featureset(proto) & SA_FEATURE_HAS_SECTIONS) == 0) 34446007Sthurlow return ((sa_property_t)NULL); 34456007Sthurlow 34466007Sthurlow for (node = ((xmlNodePtr)prop)->next; node != NULL; 34476007Sthurlow node = node->next) { 34486007Sthurlow if (xmlStrcmp(node->name, (xmlChar *)"section") == 0) { 34496007Sthurlow if (find == NULL) 34506007Sthurlow break; 34516007Sthurlow value = xmlGetProp(node, (xmlChar *)"name"); 34526007Sthurlow if (value != NULL && 34536007Sthurlow xmlStrcasecmp(value, (xmlChar *)find) == 0) { 34546007Sthurlow break; 34556007Sthurlow } 34566007Sthurlow if (value != NULL) { 34576007Sthurlow xmlFree(value); 34586007Sthurlow value = NULL; 34596007Sthurlow } 34606007Sthurlow 34616007Sthurlow } 34626007Sthurlow } 34636007Sthurlow if (value != NULL) 34646007Sthurlow xmlFree(value); 34656007Sthurlow return ((sa_property_t)node); 34666007Sthurlow } 34676007Sthurlow 34686007Sthurlow /* 34693034Sdougm * sa_get_protocol_property(propset, prop) 34703034Sdougm * 34713034Sdougm * Get the specified protocol specific property. These are global to 34723034Sdougm * the protocol and not specific to a group or share. 34733034Sdougm */ 34743034Sdougm 34753034Sdougm sa_property_t 34763034Sdougm sa_get_protocol_property(sa_protocol_properties_t propset, char *prop) 34773034Sdougm { 34783034Sdougm xmlNodePtr node = (xmlNodePtr)propset; 34793034Sdougm xmlChar *value = NULL; 34803034Sdougm 34816007Sthurlow if (propset == NULL) 34826007Sthurlow return (NULL); 34836007Sthurlow 34843034Sdougm for (node = node->children; node != NULL; 34854327Sdougm node = node->next) { 34864327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 34874327Sdougm if (prop == NULL) 34884327Sdougm break; 34894327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 34904327Sdougm if (value != NULL && 34914327Sdougm xmlStrcasecmp(value, (xmlChar *)prop) == 0) { 34924327Sdougm break; 34934327Sdougm } 34944327Sdougm if (value != NULL) { 34954327Sdougm xmlFree(value); 34964327Sdougm value = NULL; 34974327Sdougm } 34983034Sdougm } 34993034Sdougm } 35003034Sdougm if (value != NULL) 35013034Sdougm xmlFree(value); 35023034Sdougm if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"option") != 0) { 35034327Sdougm /* 35044327Sdougm * avoid a non option node -- it is possible to be a 35054327Sdougm * text node 35064327Sdougm */ 35074327Sdougm node = NULL; 35083034Sdougm } 35093034Sdougm return ((sa_property_t)node); 35103034Sdougm } 35113034Sdougm 35123034Sdougm /* 35133034Sdougm * sa_get_next_protocol_property(prop) 35143034Sdougm * 35153034Sdougm * Get the next protocol specific property in the list. 35163034Sdougm */ 35173034Sdougm 35183034Sdougm sa_property_t 35196007Sthurlow sa_get_next_protocol_property(sa_property_t prop, char *find) 35203034Sdougm { 35213034Sdougm xmlNodePtr node; 35226007Sthurlow xmlChar *value = NULL; 35233034Sdougm 35243034Sdougm for (node = ((xmlNodePtr)prop)->next; node != NULL; 35254327Sdougm node = node->next) { 35263034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 35276007Sthurlow if (find == NULL) 35286007Sthurlow break; 35296007Sthurlow value = xmlGetProp(node, (xmlChar *)"type"); 35306007Sthurlow if (value != NULL && 35316007Sthurlow xmlStrcasecmp(value, (xmlChar *)find) == 0) { 35326007Sthurlow break; 35336007Sthurlow } 35346007Sthurlow if (value != NULL) { 35356007Sthurlow xmlFree(value); 35366007Sthurlow value = NULL; 35376007Sthurlow } 35386007Sthurlow 35393034Sdougm } 35403034Sdougm } 35416007Sthurlow if (value != NULL) 35426007Sthurlow xmlFree(value); 35433034Sdougm return ((sa_property_t)node); 35443034Sdougm } 35453034Sdougm 35463034Sdougm /* 35473034Sdougm * sa_set_protocol_property(prop, value) 35483034Sdougm * 35493034Sdougm * Set the specified property to have the new value. The protocol 35503034Sdougm * specific plugin will then be called to update the property. 35513034Sdougm */ 35523034Sdougm 35533034Sdougm int 35546007Sthurlow sa_set_protocol_property(sa_property_t prop, char *section, char *value) 35553034Sdougm { 35563034Sdougm sa_protocol_properties_t propset; 35573034Sdougm char *proto; 35583034Sdougm int ret = SA_INVALID_PROTOCOL; 35593034Sdougm 35603034Sdougm propset = ((xmlNodePtr)prop)->parent; 35613034Sdougm if (propset != NULL) { 35624327Sdougm proto = sa_get_optionset_attr(propset, "type"); 35634327Sdougm if (proto != NULL) { 35646007Sthurlow if (section != NULL) 35656007Sthurlow set_node_attr((xmlNodePtr)prop, "section", 35666007Sthurlow section); 35674327Sdougm set_node_attr((xmlNodePtr)prop, "value", value); 35684327Sdougm ret = sa_proto_set_property(proto, prop); 35694327Sdougm sa_free_attr_string(proto); 35704327Sdougm } 35713034Sdougm } 35723034Sdougm return (ret); 35733034Sdougm } 35743034Sdougm 35753034Sdougm /* 35763034Sdougm * sa_add_protocol_property(propset, prop) 35773034Sdougm * 35785331Samw * Add a new property to the protocol specific property set. 35793034Sdougm */ 35803034Sdougm 35813034Sdougm int 35823034Sdougm sa_add_protocol_property(sa_protocol_properties_t propset, sa_property_t prop) 35833034Sdougm { 35843034Sdougm xmlNodePtr node; 35853034Sdougm 35863034Sdougm /* should check for legitimacy */ 35873034Sdougm node = xmlAddChild((xmlNodePtr)propset, (xmlNodePtr)prop); 35883034Sdougm if (node != NULL) 35894327Sdougm return (SA_OK); 35903034Sdougm return (SA_NO_MEMORY); 35913034Sdougm } 35923034Sdougm 35933034Sdougm /* 35943034Sdougm * sa_create_protocol_properties(proto) 35953034Sdougm * 35965331Samw * Create a protocol specific property set. 35973034Sdougm */ 35983034Sdougm 35993034Sdougm sa_protocol_properties_t 36003034Sdougm sa_create_protocol_properties(char *proto) 36013034Sdougm { 36023034Sdougm xmlNodePtr node; 36034327Sdougm 36043034Sdougm node = xmlNewNode(NULL, (xmlChar *)"propertyset"); 36054327Sdougm if (node != NULL) 36066007Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto); 36073034Sdougm return (node); 36083034Sdougm } 36095331Samw 36105331Samw /* 36115331Samw * sa_get_share_resource(share, resource) 36125331Samw * 36135331Samw * Get the named resource from the share, if it exists. If resource is 36145331Samw * NULL, get the first resource. 36155331Samw */ 36165331Samw 36175331Samw sa_resource_t 36185331Samw sa_get_share_resource(sa_share_t share, char *resource) 36195331Samw { 36205331Samw xmlNodePtr node = NULL; 36215331Samw xmlChar *name; 36225331Samw 36235331Samw if (share != NULL) { 36245331Samw for (node = ((xmlNodePtr)share)->children; node != NULL; 36255331Samw node = node->next) { 36265331Samw if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0) { 36275331Samw if (resource == NULL) { 36285331Samw /* 36295331Samw * We are looking for the first 36305331Samw * resource node and not a names 36315331Samw * resource. 36325331Samw */ 36335331Samw break; 36345331Samw } else { 36355331Samw /* is it the correct share? */ 36365331Samw name = xmlGetProp(node, 36375331Samw (xmlChar *)"name"); 36385331Samw if (name != NULL && 36395331Samw xmlStrcasecmp(name, 36405331Samw (xmlChar *)resource) == 0) { 36415331Samw xmlFree(name); 36425331Samw break; 36435331Samw } 36445331Samw xmlFree(name); 36455331Samw } 36465331Samw } 36475331Samw } 36485331Samw } 36495331Samw return ((sa_resource_t)node); 36505331Samw } 36515331Samw 36525331Samw /* 36535331Samw * sa_get_next_resource(resource) 36545331Samw * Return the next share following the specified share 36555331Samw * from the internal list of shares. Returns NULL if there 36565331Samw * are no more shares. The list is relative to the same 36575331Samw * group. 36585331Samw */ 36595331Samw sa_share_t 36605331Samw sa_get_next_resource(sa_resource_t resource) 36615331Samw { 36625331Samw xmlNodePtr node = NULL; 36635331Samw 36645331Samw if (resource != NULL) { 36655331Samw for (node = ((xmlNodePtr)resource)->next; node != NULL; 36665331Samw node = node->next) { 36675331Samw if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0) 36685331Samw break; 36695331Samw } 36705331Samw } 36715331Samw return ((sa_share_t)node); 36725331Samw } 36735331Samw 36745331Samw /* 36755331Samw * _sa_get_next_resource_index(share) 36765331Samw * 36775331Samw * get the next resource index number (one greater then current largest) 36785331Samw */ 36795331Samw 36805331Samw static int 36815331Samw _sa_get_next_resource_index(sa_share_t share) 36825331Samw { 36835331Samw sa_resource_t resource; 36845331Samw int index = 0; 36855331Samw char *id; 36865331Samw 36875331Samw for (resource = sa_get_share_resource(share, NULL); 36885331Samw resource != NULL; 36895331Samw resource = sa_get_next_resource(resource)) { 36905331Samw id = get_node_attr((void *)resource, "id"); 36915331Samw if (id != NULL) { 36925331Samw int val; 36935331Samw val = atoi(id); 36945331Samw if (val > index) 36955331Samw index = val; 36965331Samw sa_free_attr_string(id); 36975331Samw } 36985331Samw } 36995331Samw return (index + 1); 37005331Samw } 37015331Samw 37025331Samw 37035331Samw /* 37045331Samw * sa_add_resource(share, resource, persist, &err) 37055331Samw * 37065331Samw * Adds a new resource name associated with share. The resource name 37075331Samw * must be unique in the system and will be case insensitive (eventually). 37085331Samw */ 37095331Samw 37105331Samw sa_resource_t 37115331Samw sa_add_resource(sa_share_t share, char *resource, int persist, int *error) 37125331Samw { 37135331Samw xmlNodePtr node; 37145331Samw int err = SA_OK; 37155331Samw sa_resource_t res; 37165331Samw sa_group_t group; 37175331Samw sa_handle_t handle; 37185331Samw char istring[8]; /* just big enough for an integer value */ 37195331Samw int index; 37205331Samw 37215331Samw group = sa_get_parent_group(share); 37225331Samw handle = sa_find_group_handle(group); 37235331Samw res = sa_find_resource(handle, resource); 37245331Samw if (res != NULL) { 37255331Samw err = SA_DUPLICATE_NAME; 37265331Samw res = NULL; 37275331Samw } else { 37285331Samw node = xmlNewChild((xmlNodePtr)share, NULL, 37295331Samw (xmlChar *)"resource", NULL); 37305331Samw if (node != NULL) { 37316007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 37325331Samw (xmlChar *)resource); 37336007Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", persist ? 37345331Samw (xmlChar *)"persist" : (xmlChar *)"transient"); 37355331Samw if (persist != SA_SHARE_TRANSIENT) { 37365331Samw index = _sa_get_next_resource_index(share); 37375331Samw (void) snprintf(istring, sizeof (istring), "%d", 37385331Samw index); 37396007Sthurlow (void) xmlSetProp(node, (xmlChar *)"id", 37405331Samw (xmlChar *)istring); 37415331Samw if (!sa_group_is_zfs(group) && 37425331Samw sa_is_persistent((sa_group_t)share)) { 37435331Samw /* ZFS doesn't use resource names */ 37445331Samw sa_handle_impl_t ihandle; 37455331Samw ihandle = (sa_handle_impl_t) 37465331Samw sa_find_group_handle( 37475331Samw group); 37485331Samw if (ihandle != NULL) 37495331Samw err = sa_commit_share( 37505331Samw ihandle->scfhandle, group, 37515331Samw share); 37525331Samw else 37535331Samw err = SA_SYSTEM_ERR; 37545331Samw } 37555331Samw } 37565331Samw } 37575331Samw } 37585331Samw if (error != NULL) 37595331Samw *error = err; 37605331Samw return ((sa_resource_t)node); 37615331Samw } 37625331Samw 37635331Samw /* 37645331Samw * sa_remove_resource(resource) 37655331Samw * 37665331Samw * Remove the resource name from the share (and the system) 37675331Samw */ 37685331Samw 37695331Samw int 37705331Samw sa_remove_resource(sa_resource_t resource) 37715331Samw { 37725331Samw sa_share_t share; 37735331Samw sa_group_t group; 37745331Samw char *type; 37755331Samw int ret = SA_OK; 37765331Samw int transient = 0; 37775521Sas200622 sa_optionset_t opt; 37785331Samw 37795331Samw share = sa_get_resource_parent(resource); 37805331Samw type = sa_get_share_attr(share, "type"); 37815331Samw group = sa_get_parent_group(share); 37825331Samw 37835331Samw 37845331Samw if (type != NULL) { 37855331Samw if (strcmp(type, "persist") != 0) 37865331Samw transient = 1; 37875331Samw sa_free_attr_string(type); 37885331Samw } 37895331Samw 37905521Sas200622 /* Disable the resource for all protocols. */ 37915521Sas200622 (void) sa_disable_resource(resource, NULL); 37925521Sas200622 37935521Sas200622 /* Remove any optionsets from the resource. */ 37945521Sas200622 for (opt = sa_get_optionset(resource, NULL); 37955521Sas200622 opt != NULL; 37965521Sas200622 opt = sa_get_next_optionset(opt)) 37975521Sas200622 (void) sa_destroy_optionset(opt); 37985521Sas200622 37995331Samw /* Remove from the share */ 38005331Samw xmlUnlinkNode((xmlNode *)resource); 38015331Samw xmlFreeNode((xmlNode *)resource); 38025331Samw 38035331Samw /* only do SMF action if permanent and not ZFS */ 38045331Samw if (!transient && !sa_group_is_zfs(group)) { 38055331Samw sa_handle_impl_t ihandle; 38065331Samw ihandle = (sa_handle_impl_t)sa_find_group_handle(group); 38075331Samw if (ihandle != NULL) 38085331Samw ret = sa_commit_share(ihandle->scfhandle, group, share); 38095331Samw else 38105331Samw ret = SA_SYSTEM_ERR; 38115331Samw } 38125331Samw return (ret); 38135331Samw } 38145331Samw 38155331Samw /* 38165331Samw * proto_resource_rename(handle, group, resource, newname) 38175331Samw * 38185331Samw * Helper function for sa_rename_resource that notifies the protocol 38195331Samw * of a resource name change prior to a config repository update. 38205331Samw */ 38215331Samw static int 38225331Samw proto_rename_resource(sa_handle_t handle, sa_group_t group, 38235331Samw sa_resource_t resource, char *newname) 38245331Samw { 38255331Samw sa_optionset_t optionset; 38265331Samw int ret = SA_OK; 38275331Samw int err; 38285331Samw 38295331Samw for (optionset = sa_get_optionset(group, NULL); 38305331Samw optionset != NULL; 38315331Samw optionset = sa_get_next_optionset(optionset)) { 38325331Samw char *type; 38335331Samw type = sa_get_optionset_attr(optionset, "type"); 38345331Samw if (type != NULL) { 38355331Samw err = sa_proto_rename_resource(handle, type, resource, 38365331Samw newname); 38375331Samw if (err != SA_OK) 38385331Samw ret = err; 38395331Samw sa_free_attr_string(type); 38405331Samw } 38415331Samw } 38425331Samw return (ret); 38435331Samw } 38445331Samw 38455331Samw /* 38465331Samw * sa_rename_resource(resource, newname) 38475331Samw * 38485331Samw * Rename the resource to the new name, if it is unique. 38495331Samw */ 38505331Samw 38515331Samw int 38525331Samw sa_rename_resource(sa_resource_t resource, char *newname) 38535331Samw { 38545331Samw sa_share_t share; 38555331Samw sa_group_t group = NULL; 38565331Samw sa_resource_t target; 38575331Samw int ret = SA_CONFIG_ERR; 38585331Samw sa_handle_t handle = NULL; 38595331Samw 38605331Samw share = sa_get_resource_parent(resource); 38615331Samw if (share == NULL) 38625331Samw return (ret); 38635331Samw 38645331Samw group = sa_get_parent_group(share); 38655331Samw if (group == NULL) 38665331Samw return (ret); 38675331Samw 38685331Samw handle = (sa_handle_impl_t)sa_find_group_handle(group); 38695331Samw if (handle == NULL) 38705331Samw return (ret); 38715331Samw 38725331Samw target = sa_find_resource(handle, newname); 38735331Samw if (target != NULL) { 38745331Samw ret = SA_DUPLICATE_NAME; 38755331Samw } else { 38765331Samw /* 38775331Samw * Everything appears to be valid at this 38785331Samw * point. Change the name of the active share and then 38795331Samw * update the share in the appropriate repository. 38805331Samw */ 38815331Samw ret = proto_rename_resource(handle, group, resource, newname); 38825331Samw set_node_attr(resource, "name", newname); 38835331Samw if (!sa_group_is_zfs(group) && 38845331Samw sa_is_persistent((sa_group_t)share)) { 38855331Samw sa_handle_impl_t ihandle = (sa_handle_impl_t)handle; 38865331Samw ret = sa_commit_share(ihandle->scfhandle, group, 38875331Samw share); 38885331Samw } 38895331Samw } 38905331Samw return (ret); 38915331Samw } 38925331Samw 38935331Samw /* 38945331Samw * sa_get_resource_attr(resource, tag) 38955331Samw * 38965331Samw * Get the named attribute of the resource. "name" and "id" are 38975331Samw * currently defined. NULL if tag not defined. 38985331Samw */ 38995331Samw 39005331Samw char * 39015331Samw sa_get_resource_attr(sa_resource_t resource, char *tag) 39025331Samw { 39035331Samw return (get_node_attr((void *)resource, tag)); 39045331Samw } 39055331Samw 39065331Samw /* 39075331Samw * sa_set_resource_attr(resource, tag, value) 39085331Samw * 39095331Samw * Get the named attribute of the resource. "name" and "id" are 39105331Samw * currently defined. NULL if tag not defined. Currently we don't do 39115331Samw * much, but additional checking may be needed in the future. 39125331Samw */ 39135331Samw 39145331Samw int 39155331Samw sa_set_resource_attr(sa_resource_t resource, char *tag, char *value) 39165331Samw { 39175331Samw set_node_attr((void *)resource, tag, value); 39185331Samw return (SA_OK); 39195331Samw } 39205331Samw 39215331Samw /* 39225331Samw * sa_get_resource_parent(resource_t) 39235331Samw * 39245331Samw * Returns the share associated with the resource. 39255331Samw */ 39265331Samw 39275331Samw sa_share_t 39285331Samw sa_get_resource_parent(sa_resource_t resource) 39295331Samw { 39305331Samw sa_share_t share = NULL; 39315331Samw 39325331Samw if (resource != NULL) 39335331Samw share = (sa_share_t)((xmlNodePtr)resource)->parent; 39345331Samw return (share); 39355331Samw } 39365331Samw 39375331Samw /* 39385331Samw * find_resource(group, name) 39395331Samw * 39405331Samw * Find the resource within the group. 39415331Samw */ 39425331Samw 39435331Samw static sa_resource_t 39445331Samw find_resource(sa_group_t group, char *resname) 39455331Samw { 39465331Samw sa_share_t share; 39475331Samw sa_resource_t resource = NULL; 39485331Samw char *name; 39495331Samw 39505331Samw /* Iterate over all the shares and resources in the group. */ 39515331Samw for (share = sa_get_share(group, NULL); 39525331Samw share != NULL && resource == NULL; 39535331Samw share = sa_get_next_share(share)) { 39545331Samw for (resource = sa_get_share_resource(share, NULL); 39555331Samw resource != NULL; 39565331Samw resource = sa_get_next_resource(resource)) { 39575331Samw name = sa_get_resource_attr(resource, "name"); 39585331Samw if (name != NULL && xmlStrcasecmp((xmlChar*)name, 39595331Samw (xmlChar*)resname) == 0) { 39605331Samw sa_free_attr_string(name); 39615331Samw break; 39625331Samw } 39635331Samw if (name != NULL) { 39645331Samw sa_free_attr_string(name); 39655331Samw } 39665331Samw } 39675331Samw } 39685331Samw return (resource); 39695331Samw } 39705331Samw 39715331Samw /* 39725331Samw * sa_find_resource(name) 39735331Samw * 39745331Samw * Find the named resource in the system. 39755331Samw */ 39765331Samw 39775331Samw sa_resource_t 39785331Samw sa_find_resource(sa_handle_t handle, char *name) 39795331Samw { 39805331Samw sa_group_t group; 39815331Samw sa_group_t zgroup; 39825331Samw sa_resource_t resource = NULL; 39835331Samw 39845331Samw /* 39855331Samw * Iterate over all groups and zfs subgroups and check for 39865331Samw * resource name in them. 39875331Samw */ 39885331Samw for (group = sa_get_group(handle, NULL); group != NULL; 39895331Samw group = sa_get_next_group(group)) { 39905331Samw 39915331Samw if (is_zfs_group(group)) { 39925331Samw for (zgroup = 39935331Samw (sa_group_t)_sa_get_child_node((xmlNodePtr)group, 39945331Samw (xmlChar *)"group"); 39955331Samw zgroup != NULL && resource == NULL; 39965331Samw zgroup = sa_get_next_group(zgroup)) { 39975331Samw resource = find_resource(zgroup, name); 39985331Samw } 39995331Samw } else { 40005331Samw resource = find_resource(group, name); 40015331Samw } 40025331Samw if (resource != NULL) 40035331Samw break; 40045331Samw } 40055331Samw return (resource); 40065331Samw } 40075331Samw 40085331Samw /* 40095331Samw * sa_get_resource(group, resource) 40105331Samw * 40115331Samw * Search all the shares in the specified group for a share with a 40125331Samw * resource name matching the one specified. 40135331Samw * 40145331Samw * In the future, it may be advantageous to allow group to be NULL and 40155331Samw * search all groups but that isn't needed at present. 40165331Samw */ 40175331Samw 40185331Samw sa_resource_t 40195331Samw sa_get_resource(sa_group_t group, char *resource) 40205331Samw { 40215331Samw sa_share_t share = NULL; 40225331Samw sa_resource_t res = NULL; 40235331Samw 40245331Samw if (resource != NULL) { 40255331Samw for (share = sa_get_share(group, NULL); 40265331Samw share != NULL && res == NULL; 40275331Samw share = sa_get_next_share(share)) { 40285331Samw res = sa_get_share_resource(share, resource); 40295331Samw } 40305331Samw } 40315331Samw return (res); 40325331Samw } 40335331Samw 40345331Samw /* 4035*6270Sdougm * get_protocol_list(optionset, object) 4036*6270Sdougm * 4037*6270Sdougm * Get the protocol optionset list for the object and add them as 4038*6270Sdougm * properties to optionset. 4039*6270Sdougm */ 4040*6270Sdougm static int 4041*6270Sdougm get_protocol_list(sa_optionset_t optionset, void *object) 4042*6270Sdougm { 4043*6270Sdougm sa_property_t prop; 4044*6270Sdougm sa_optionset_t opts; 4045*6270Sdougm int ret = SA_OK; 4046*6270Sdougm 4047*6270Sdougm for (opts = sa_get_optionset(object, NULL); 4048*6270Sdougm opts != NULL; 4049*6270Sdougm opts = sa_get_next_optionset(opts)) { 4050*6270Sdougm char *type; 4051*6270Sdougm type = sa_get_optionset_attr(opts, "type"); 4052*6270Sdougm /* 4053*6270Sdougm * It is possible to have a non-protocol optionset. We 4054*6270Sdougm * skip any of those found. 4055*6270Sdougm */ 4056*6270Sdougm if (type == NULL) 4057*6270Sdougm continue; 4058*6270Sdougm prop = sa_create_property(type, "true"); 4059*6270Sdougm sa_free_attr_string(type); 4060*6270Sdougm if (prop != NULL) 4061*6270Sdougm prop = (sa_property_t)xmlAddChild((xmlNodePtr)optionset, 4062*6270Sdougm (xmlNodePtr)prop); 4063*6270Sdougm /* If prop is NULL, don't bother continuing */ 4064*6270Sdougm if (prop == NULL) { 4065*6270Sdougm ret = SA_NO_MEMORY; 4066*6270Sdougm break; 4067*6270Sdougm } 4068*6270Sdougm } 4069*6270Sdougm return (ret); 4070*6270Sdougm } 4071*6270Sdougm 4072*6270Sdougm /* 4073*6270Sdougm * sa_free_protoset(optionset) 4074*6270Sdougm * 4075*6270Sdougm * Free the protocol property optionset. 4076*6270Sdougm */ 4077*6270Sdougm static void 4078*6270Sdougm sa_free_protoset(sa_optionset_t optionset) 4079*6270Sdougm { 4080*6270Sdougm if (optionset != NULL) { 4081*6270Sdougm xmlUnlinkNode((xmlNodePtr) optionset); 4082*6270Sdougm xmlFreeNode((xmlNodePtr) optionset); 4083*6270Sdougm } 4084*6270Sdougm } 4085*6270Sdougm 4086*6270Sdougm /* 4087*6270Sdougm * sa_optionset_t sa_get_active_protocols(object) 4088*6270Sdougm * 4089*6270Sdougm * Return a list of the protocols that are active for the object. 4090*6270Sdougm * This is currently an internal helper function, but could be 4091*6270Sdougm * made visible if there is enough demand for it. 4092*6270Sdougm * 4093*6270Sdougm * The function finds the parent group and extracts the protocol 4094*6270Sdougm * optionsets creating a new optionset with the protocols as properties. 4095*6270Sdougm * 4096*6270Sdougm * The caller must free the returned optionset. 4097*6270Sdougm */ 4098*6270Sdougm 4099*6270Sdougm static sa_optionset_t 4100*6270Sdougm sa_get_active_protocols(void *object) 4101*6270Sdougm { 4102*6270Sdougm sa_optionset_t options; 4103*6270Sdougm sa_share_t share = NULL; 4104*6270Sdougm sa_group_t group = NULL; 4105*6270Sdougm sa_resource_t resource = NULL; 4106*6270Sdougm int ret = SA_OK; 4107*6270Sdougm 4108*6270Sdougm if (object == NULL) 4109*6270Sdougm return (NULL); 4110*6270Sdougm options = (sa_optionset_t)xmlNewNode(NULL, (xmlChar *)"optionset"); 4111*6270Sdougm if (options == NULL) 4112*6270Sdougm return (NULL); 4113*6270Sdougm 4114*6270Sdougm /* 4115*6270Sdougm * Find the objects up the tree that might have protocols 4116*6270Sdougm * enabled on them. 4117*6270Sdougm */ 4118*6270Sdougm if (sa_is_resource(object)) { 4119*6270Sdougm resource = (sa_resource_t)object; 4120*6270Sdougm share = sa_get_resource_parent(resource); 4121*6270Sdougm group = sa_get_parent_group(share); 4122*6270Sdougm } else if (sa_is_share(object)) { 4123*6270Sdougm share = (sa_share_t)object; 4124*6270Sdougm group = sa_get_parent_group(share); 4125*6270Sdougm } else { 4126*6270Sdougm group = (sa_group_t)group; 4127*6270Sdougm } 4128*6270Sdougm if (resource != NULL) 4129*6270Sdougm ret = get_protocol_list(options, resource); 4130*6270Sdougm if (ret == SA_OK && share != NULL) 4131*6270Sdougm ret = get_protocol_list(options, share); 4132*6270Sdougm if (ret == SA_OK && group != NULL) 4133*6270Sdougm ret = get_protocol_list(options, group); 4134*6270Sdougm 4135*6270Sdougm /* 4136*6270Sdougm * If there was an error, we won't have a complete list so 4137*6270Sdougm * abandon everything. The caller will have to deal with the 4138*6270Sdougm * issue. 4139*6270Sdougm */ 4140*6270Sdougm if (ret != SA_OK) { 4141*6270Sdougm sa_free_protoset(options); 4142*6270Sdougm options = NULL; 4143*6270Sdougm } 4144*6270Sdougm return (options); 4145*6270Sdougm } 4146*6270Sdougm 4147*6270Sdougm /* 41485331Samw * sa_enable_resource, protocol) 41495331Samw * Disable the specified share to the specified protocol. 41505331Samw * If protocol is NULL, then all protocols. 41515331Samw */ 41525331Samw int 41535331Samw sa_enable_resource(sa_resource_t resource, char *protocol) 41545331Samw { 41555331Samw int ret = SA_OK; 41565331Samw 41575331Samw if (protocol != NULL) { 41585331Samw ret = sa_proto_share_resource(protocol, resource); 41595331Samw } else { 4160*6270Sdougm sa_optionset_t protoset; 4161*6270Sdougm sa_property_t prop; 4162*6270Sdougm char *proto; 4163*6270Sdougm int err; 4164*6270Sdougm 41655331Samw /* need to do all protocols */ 4166*6270Sdougm protoset = sa_get_active_protocols(resource); 4167*6270Sdougm if (protoset == NULL) 4168*6270Sdougm return (SA_NO_MEMORY); 4169*6270Sdougm for (prop = sa_get_property(protoset, NULL); 4170*6270Sdougm prop != NULL; 4171*6270Sdougm prop = sa_get_next_property(prop)) { 4172*6270Sdougm proto = sa_get_property_attr(prop, "type"); 4173*6270Sdougm if (proto == NULL) { 4174*6270Sdougm ret = SA_NO_MEMORY; 4175*6270Sdougm continue; 41765331Samw } 4177*6270Sdougm err = sa_proto_share_resource(proto, resource); 4178*6270Sdougm if (err != SA_OK) 4179*6270Sdougm ret = err; 4180*6270Sdougm sa_free_attr_string(proto); 41815331Samw } 4182*6270Sdougm sa_free_protoset(protoset); 41835331Samw } 41845331Samw if (ret == SA_OK) 41855331Samw (void) sa_set_resource_attr(resource, "shared", NULL); 41865331Samw 41875331Samw return (ret); 41885331Samw } 41895331Samw 41905331Samw /* 41915331Samw * sa_disable_resource(resource, protocol) 41925331Samw * 41935331Samw * Disable the specified share for the specified protocol. If 41945331Samw * protocol is NULL, then all protocols. If the underlying 41955331Samw * protocol doesn't implement disable at the resource level, we 41965331Samw * disable at the share level. 41975331Samw */ 41985331Samw int 41995331Samw sa_disable_resource(sa_resource_t resource, char *protocol) 42005331Samw { 42015331Samw int ret = SA_OK; 42025331Samw 42035331Samw if (protocol != NULL) { 42045331Samw ret = sa_proto_unshare_resource(protocol, resource); 42055331Samw if (ret == SA_NOT_IMPLEMENTED) { 42065331Samw sa_share_t parent; 42075331Samw /* 42085331Samw * The protocol doesn't implement unshare 42095331Samw * resource. That implies that resource names are 42105331Samw * simple aliases for this protocol so we need to 42115331Samw * unshare the share. 42125331Samw */ 42135331Samw parent = sa_get_resource_parent(resource); 42145331Samw if (parent != NULL) 42155331Samw ret = sa_disable_share(parent, protocol); 42165331Samw else 42175331Samw ret = SA_CONFIG_ERR; 42185331Samw } 42195331Samw } else { 4220*6270Sdougm sa_optionset_t protoset; 4221*6270Sdougm sa_property_t prop; 4222*6270Sdougm char *proto; 4223*6270Sdougm int err; 4224*6270Sdougm 42255331Samw /* need to do all protocols */ 4226*6270Sdougm protoset = sa_get_active_protocols(resource); 4227*6270Sdougm if (protoset == NULL) 4228*6270Sdougm return (SA_NO_MEMORY); 4229*6270Sdougm for (prop = sa_get_property(protoset, NULL); 4230*6270Sdougm prop != NULL; 4231*6270Sdougm prop = sa_get_next_property(prop)) { 4232*6270Sdougm proto = sa_get_property_attr(prop, "type"); 4233*6270Sdougm if (proto == NULL) { 4234*6270Sdougm ret = SA_NO_MEMORY; 4235*6270Sdougm continue; 42365331Samw } 4237*6270Sdougm err = sa_proto_unshare_resource(proto, resource); 4238*6270Sdougm if (err == SA_NOT_SUPPORTED) { 4239*6270Sdougm sa_share_t parent; 4240*6270Sdougm parent = sa_get_resource_parent(resource); 4241*6270Sdougm if (parent != NULL) 4242*6270Sdougm err = sa_disable_share(parent, proto); 4243*6270Sdougm else 4244*6270Sdougm err = SA_CONFIG_ERR; 4245*6270Sdougm } 4246*6270Sdougm if (err != SA_OK) 4247*6270Sdougm ret = err; 4248*6270Sdougm sa_free_attr_string(proto); 42495331Samw } 4250*6270Sdougm sa_free_protoset(protoset); 42515331Samw } 42525331Samw if (ret == SA_OK) 42535331Samw (void) sa_set_resource_attr(resource, "shared", NULL); 42545331Samw 42555331Samw return (ret); 42565331Samw } 42575331Samw 42585331Samw /* 42595331Samw * sa_set_resource_description(resource, content) 42605331Samw * 42615331Samw * Set the description of share to content. 42625331Samw */ 42635331Samw 42645331Samw int 42655331Samw sa_set_resource_description(sa_resource_t resource, char *content) 42665331Samw { 42675331Samw xmlNodePtr node; 42685331Samw sa_group_t group; 42695331Samw sa_share_t share; 42705331Samw int ret = SA_OK; 42715331Samw 42725331Samw for (node = ((xmlNodePtr)resource)->children; 42735331Samw node != NULL; 42745331Samw node = node->next) { 42755331Samw if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 42765331Samw break; 42775331Samw } 42785331Samw } 42795331Samw 42805331Samw /* no existing description but want to add */ 42815331Samw if (node == NULL && content != NULL) { 42825331Samw /* add a description */ 42835331Samw node = _sa_set_share_description(resource, content); 42845331Samw } else if (node != NULL && content != NULL) { 42855331Samw /* update a description */ 42865331Samw xmlNodeSetContent(node, (xmlChar *)content); 42875331Samw } else if (node != NULL && content == NULL) { 42885331Samw /* remove an existing description */ 42895331Samw xmlUnlinkNode(node); 42905331Samw xmlFreeNode(node); 42915331Samw } 42925331Samw share = sa_get_resource_parent(resource); 42935331Samw group = sa_get_parent_group(share); 42945331Samw if (group != NULL && sa_is_persistent(share)) { 42955331Samw sa_handle_impl_t impl_handle; 42965331Samw impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 42975331Samw if (impl_handle != NULL) 42985331Samw ret = sa_commit_share(impl_handle->scfhandle, 42995331Samw group, share); 43005331Samw else 43015331Samw ret = SA_SYSTEM_ERR; 43025331Samw } 43035331Samw return (ret); 43045331Samw } 43055331Samw 43065331Samw /* 43075331Samw * sa_get_resource_description(share) 43085331Samw * 43095331Samw * Return the description text for the specified share if it 43105331Samw * exists. NULL if no description exists. 43115331Samw */ 43125331Samw 43135331Samw char * 43145331Samw sa_get_resource_description(sa_resource_t resource) 43155331Samw { 43165331Samw xmlChar *description = NULL; 43175331Samw xmlNodePtr node; 43185331Samw 43195331Samw for (node = ((xmlNodePtr)resource)->children; node != NULL; 43205331Samw node = node->next) { 43215331Samw if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) 43225331Samw break; 43235331Samw } 43245331Samw if (node != NULL) { 43255331Samw description = xmlNodeGetContent(node); 43265331Samw fixproblemchars((char *)description); 43275331Samw } 43285331Samw return ((char *)description); 43295331Samw } 4330