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) { 8306304Sdougm /* 8316304Sdougm * Get protocol specific structures, but only if this 8326304Sdougm * is the only handle. 8336304Sdougm */ 8346304Sdougm (void) mutex_lock(&sa_global_lock); 8356304Sdougm if (sa_global_handles == NULL) 8366304Sdougm (void) proto_plugin_init(); 8376304Sdougm (void) mutex_unlock(&sa_global_lock); 8384327Sdougm if (init_service & SA_INIT_SHARE_API) { 8393663Sdougm /* 8404327Sdougm * initialize access into libzfs. We use this 8414327Sdougm * when collecting info about ZFS datasets and 8424327Sdougm * shares. 8433663Sdougm */ 8444327Sdougm if (sa_zfs_init(handle) == B_FALSE) { 8454327Sdougm free(handle); 8464327Sdougm (void) proto_plugin_fini(); 8474327Sdougm return (NULL); 8484327Sdougm } 8493663Sdougm /* 8504327Sdougm * since we want to use SMF, initialize an svc handle 8514327Sdougm * and find out what is there. 8523663Sdougm */ 8534327Sdougm handle->scfhandle = sa_scf_init(handle); 8544327Sdougm if (handle->scfhandle != NULL) { 8554327Sdougm /* 8564327Sdougm * Need to lock the extraction of the 8574327Sdougm * configuration if the dfstab file has 8584327Sdougm * changed. Lock everything now and release if 8594327Sdougm * not needed. Use a file that isn't being 8604327Sdougm * manipulated by other parts of the system in 8614327Sdougm * order to not interfere with locking. Using 8624327Sdougm * dfstab doesn't work. 8634327Sdougm */ 8644327Sdougm sablocksigs(&old); 8654327Sdougm lockfd = open(DFS_LOCK_FILE, O_RDWR); 8664327Sdougm if (lockfd >= 0) { 8674327Sdougm extern int errno; 8684327Sdougm errno = 0; 8694327Sdougm (void) lockf(lockfd, F_LOCK, 0); 8704327Sdougm /* 8714327Sdougm * Check whether we are going to need 8724327Sdougm * to merge any dfstab changes. This 8734327Sdougm * is done by comparing the value of 8744327Sdougm * legacy-timestamp with the current 8754327Sdougm * st_ctim of the file. If they are 8764327Sdougm * different, an update is needed and 8774327Sdougm * the file must remain locked until 8784327Sdougm * the merge is done in order to 8794327Sdougm * prevent multiple startups from 8804327Sdougm * changing the SMF repository at the 8814327Sdougm * same time. The first to get the 8824327Sdougm * lock will make any changes before 8834327Sdougm * the others can read the repository. 8844327Sdougm */ 8854327Sdougm prop = scf_simple_prop_get 8864327Sdougm (handle->scfhandle->handle, 8874327Sdougm (const char *)SA_SVC_FMRI_BASE 8884327Sdougm ":default", "operation", 8894327Sdougm "legacy-timestamp"); 8904327Sdougm if (prop != NULL) { 8914327Sdougm char *i64; 8924327Sdougm i64 = GETPROP(prop); 8934327Sdougm if (i64 != NULL) 8944327Sdougm tval = strtoull(i64, 8954327Sdougm NULL, 0); 8964327Sdougm if (CHECKTSTAMP(st, tval)) 8974327Sdougm updatelegacy = B_TRUE; 8984327Sdougm scf_simple_prop_free(prop); 8994327Sdougm } else { 9004327Sdougm /* 9014327Sdougm * We haven't set the 9024327Sdougm * timestamp before so do it. 9034327Sdougm */ 9044327Sdougm updatelegacy = B_TRUE; 9054327Sdougm } 9064327Sdougm } 9074327Sdougm if (updatelegacy == B_FALSE) { 9084327Sdougm /* Don't need the lock anymore */ 9094327Sdougm (void) lockf(lockfd, F_ULOCK, 0); 9104327Sdougm (void) close(lockfd); 9114327Sdougm } 9123973Sdougm 9134327Sdougm /* 9144327Sdougm * It is essential that the document tree and 9154327Sdougm * the internal list of roots to handles be 9164327Sdougm * setup before anything that might try to 9174327Sdougm * create a new object is called. The document 9184327Sdougm * tree is the combination of handle->doc and 9194327Sdougm * handle->tree. This allows searches, 9204327Sdougm * etc. when all you have is an object in the 9214327Sdougm * tree. 9224327Sdougm */ 9234327Sdougm handle->doc = xmlNewDoc((xmlChar *)"1.0"); 9244327Sdougm handle->tree = xmlNewNode(NULL, 9254327Sdougm (xmlChar *)"sharecfg"); 9264327Sdougm if (handle->doc != NULL && 9274327Sdougm handle->tree != NULL) { 9286007Sthurlow (void) xmlDocSetRootElement(handle->doc, 9294327Sdougm handle->tree); 9304327Sdougm err = add_handle_for_root(handle->tree, 9314327Sdougm handle); 9324327Sdougm if (err == SA_OK) 9334327Sdougm err = sa_get_config( 9344327Sdougm handle->scfhandle, 9353973Sdougm handle->tree, handle); 9364327Sdougm } else { 9374327Sdougm if (handle->doc != NULL) 9384327Sdougm xmlFreeDoc(handle->doc); 9394327Sdougm if (handle->tree != NULL) 9404327Sdougm xmlFreeNode(handle->tree); 9414327Sdougm err = SA_NO_MEMORY; 9424327Sdougm } 9433973Sdougm 9444327Sdougm saunblocksigs(&old); 9453910Sdougm 9464327Sdougm if (err != SA_OK) { 9474327Sdougm /* 9484327Sdougm * If we couldn't add the tree handle 9494327Sdougm * to the list, then things are going 9504327Sdougm * to fail badly. Might as well undo 9514327Sdougm * everything now and fail the 9524327Sdougm * sa_init(). 9534327Sdougm */ 9544327Sdougm sa_fini(handle); 9554327Sdougm return (NULL); 9564327Sdougm } 9573910Sdougm 9584327Sdougm if (tval == 0) { 9594327Sdougm /* 9604327Sdougm * first time so make sure 9614327Sdougm * default is setup 9624327Sdougm */ 9634327Sdougm verifydefgroupopts(handle); 9644327Sdougm } 9653973Sdougm 9664524Sdougm if (updatelegacy == B_TRUE) { 9674524Sdougm sablocksigs(&old); 9684524Sdougm getlegacyconfig((sa_handle_t)handle, 9694524Sdougm SA_LEGACY_DFSTAB, &handle->tree); 9704524Sdougm if (stat(SA_LEGACY_DFSTAB, &st) >= 0) 9714524Sdougm set_legacy_timestamp( 9724524Sdougm handle->tree, 9734524Sdougm SA_LEGACY_DFSTAB, 9744524Sdougm TSTAMP(st.st_ctim)); 9754524Sdougm saunblocksigs(&old); 9764524Sdougm /* 9774524Sdougm * Safe to unlock now to allow 9784524Sdougm * others to run 9794524Sdougm */ 9804524Sdougm (void) lockf(lockfd, F_ULOCK, 0); 9814524Sdougm (void) close(lockfd); 9824524Sdougm } 9835951Sdougm /* Get sharetab timestamp */ 9845951Sdougm sa_update_sharetab_ts((sa_handle_t)handle); 9855951Sdougm 9865951Sdougm /* Get lastupdate (transaction) timestamp */ 9875951Sdougm prop = scf_simple_prop_get( 9885951Sdougm handle->scfhandle->handle, 9895951Sdougm (const char *)SA_SVC_FMRI_BASE ":default", 9905951Sdougm "state", "lastupdate"); 9915951Sdougm if (prop != NULL) { 9925951Sdougm char *str; 9935951Sdougm str = 9945951Sdougm scf_simple_prop_next_astring(prop); 9955951Sdougm if (str != NULL) 9965951Sdougm handle->tstrans = 9975951Sdougm strtoull(str, NULL, 0); 9985951Sdougm else 9995951Sdougm handle->tstrans = 0; 10005951Sdougm scf_simple_prop_free(prop); 10015951Sdougm } 10024524Sdougm legacy |= sa_get_zfs_shares(handle, "zfs"); 10034524Sdougm legacy |= gettransients(handle, &handle->tree); 10044327Sdougm } 10054327Sdougm } 10063034Sdougm } 10073910Sdougm return ((sa_handle_t)handle); 10083034Sdougm } 10093034Sdougm 10103034Sdougm /* 10113910Sdougm * sa_fini(handle) 10123034Sdougm * Uninitialize the API structures including the configuration 10133218Sdougm * data structures and ZFS related data. 10143034Sdougm */ 10153034Sdougm 10163034Sdougm void 10173910Sdougm sa_fini(sa_handle_t handle) 10183034Sdougm { 10193910Sdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle; 10203910Sdougm 10213910Sdougm if (impl_handle != NULL) { 10223910Sdougm /* 10233910Sdougm * Free the config trees and any other data structures 10243910Sdougm * used in the handle. 10253910Sdougm */ 10263910Sdougm if (impl_handle->doc != NULL) 10273910Sdougm xmlFreeDoc(impl_handle->doc); 10283910Sdougm 10293910Sdougm /* Remove and free the entry in the global list. */ 10303910Sdougm remove_handle_for_root(impl_handle->tree); 10313910Sdougm 10323910Sdougm /* 10333910Sdougm * If this was the last handle to release, unload the 10346304Sdougm * plugins that were loaded. Use a mutex in case 10356304Sdougm * another thread is reinitializing. 10363910Sdougm */ 10376304Sdougm (void) mutex_lock(&sa_global_lock); 10383910Sdougm if (sa_global_handles == NULL) 10394327Sdougm (void) proto_plugin_fini(); 10406304Sdougm (void) mutex_unlock(&sa_global_lock); 10413910Sdougm 1042*7010Sgwr sa_scf_fini(impl_handle->scfhandle); 1043*7010Sgwr sa_zfs_fini(impl_handle); 1044*7010Sgwr 1045*7010Sgwr /* Make sure we free the handle */ 1046*7010Sgwr free(impl_handle); 1047*7010Sgwr 10483034Sdougm } 10493034Sdougm } 10503034Sdougm 10513034Sdougm /* 10523034Sdougm * sa_get_protocols(char **protocol) 10533034Sdougm * Get array of protocols that are supported 10543034Sdougm * Returns pointer to an allocated and NULL terminated 10553034Sdougm * array of strings. Caller must free. 10563034Sdougm * This really should be determined dynamically. 10573034Sdougm * If there aren't any defined, return -1. 10583034Sdougm * Use free() to return memory. 10593034Sdougm */ 10603034Sdougm 10613034Sdougm int 10623034Sdougm sa_get_protocols(char ***protocols) 10633034Sdougm { 10643034Sdougm int numproto = -1; 10653034Sdougm 10663034Sdougm if (protocols != NULL) { 10674327Sdougm struct sa_proto_plugin *plug; 10684327Sdougm for (numproto = 0, plug = sap_proto_list; plug != NULL; 10694327Sdougm plug = plug->plugin_next) { 10704327Sdougm numproto++; 10714327Sdougm } 10723034Sdougm 10734327Sdougm *protocols = calloc(numproto + 1, sizeof (char *)); 10744327Sdougm if (*protocols != NULL) { 10754327Sdougm int ret = 0; 10764327Sdougm for (plug = sap_proto_list; plug != NULL; 10774327Sdougm plug = plug->plugin_next) { 10784327Sdougm /* faking for now */ 10794327Sdougm (*protocols)[ret++] = 10804327Sdougm plug->plugin_ops->sa_protocol; 10814327Sdougm } 10824327Sdougm } else { 10834327Sdougm numproto = -1; 10843034Sdougm } 10853034Sdougm } 10863034Sdougm return (numproto); 10873034Sdougm } 10883034Sdougm 10893034Sdougm /* 10903034Sdougm * find_group_by_name(node, group) 10913034Sdougm * 10923034Sdougm * search the XML document subtree specified by node to find the group 10933034Sdougm * specified by group. Searching subtree allows subgroups to be 10943034Sdougm * searched for. 10953034Sdougm */ 10963034Sdougm 10973034Sdougm static xmlNodePtr 10983034Sdougm find_group_by_name(xmlNodePtr node, xmlChar *group) 10993034Sdougm { 11003034Sdougm xmlChar *name = NULL; 11013034Sdougm 11023034Sdougm for (node = node->xmlChildrenNode; node != NULL; 11033034Sdougm node = node->next) { 11044327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"group") == 0) { 11054327Sdougm /* if no groupname, return the first found */ 11064327Sdougm if (group == NULL) 11074327Sdougm break; 11084327Sdougm name = xmlGetProp(node, (xmlChar *)"name"); 11094327Sdougm if (name != NULL && xmlStrcmp(name, group) == 0) 11104327Sdougm break; 11114327Sdougm if (name != NULL) { 11124327Sdougm xmlFree(name); 11134327Sdougm name = NULL; 11144327Sdougm } 11153034Sdougm } 11163034Sdougm } 11173034Sdougm if (name != NULL) 11184327Sdougm xmlFree(name); 11193034Sdougm return (node); 11203034Sdougm } 11213034Sdougm 11223034Sdougm /* 11233034Sdougm * sa_get_group(groupname) 11243034Sdougm * Return the "group" specified. If groupname is NULL, 11253034Sdougm * return the first group of the list of groups. 11263034Sdougm */ 11273034Sdougm sa_group_t 11283910Sdougm sa_get_group(sa_handle_t handle, char *groupname) 11293034Sdougm { 11303034Sdougm xmlNodePtr node = NULL; 11313034Sdougm char *subgroup = NULL; 11323034Sdougm char *group = NULL; 11333910Sdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle; 11343034Sdougm 11353910Sdougm if (impl_handle != NULL && impl_handle->tree != NULL) { 11364327Sdougm if (groupname != NULL) { 11374327Sdougm group = strdup(groupname); 11384345Sdougm if (group != NULL) { 11394345Sdougm subgroup = strchr(group, '/'); 11404345Sdougm if (subgroup != NULL) 11414345Sdougm *subgroup++ = '\0'; 11424345Sdougm } 11434327Sdougm } 11444345Sdougm /* 11454345Sdougm * We want to find the, possibly, named group. If 11464345Sdougm * group is not NULL, then lookup the name. If it is 11474345Sdougm * NULL, we only do the find if groupname is also 11484345Sdougm * NULL. This allows lookup of the "first" group in 11494345Sdougm * the internal list. 11504345Sdougm */ 11514345Sdougm if (group != NULL || groupname == NULL) 11524345Sdougm node = find_group_by_name(impl_handle->tree, 11534345Sdougm (xmlChar *)group); 11544345Sdougm 11554327Sdougm /* if a subgroup, find it before returning */ 11564327Sdougm if (subgroup != NULL && node != NULL) 11574327Sdougm node = find_group_by_name(node, (xmlChar *)subgroup); 11583034Sdougm } 11593034Sdougm if (node != NULL && (char *)group != NULL) 11604327Sdougm (void) sa_get_instance(impl_handle->scfhandle, (char *)group); 11613034Sdougm if (group != NULL) 11624327Sdougm free(group); 11633034Sdougm return ((sa_group_t)(node)); 11643034Sdougm } 11653034Sdougm 11663034Sdougm /* 11673034Sdougm * sa_get_next_group(group) 11683034Sdougm * Return the "next" group after the specified group from 11693034Sdougm * the internal group list. NULL if there are no more. 11703034Sdougm */ 11713034Sdougm sa_group_t 11723034Sdougm sa_get_next_group(sa_group_t group) 11733034Sdougm { 11743034Sdougm xmlNodePtr ngroup = NULL; 11753034Sdougm if (group != NULL) { 11764327Sdougm for (ngroup = ((xmlNodePtr)group)->next; ngroup != NULL; 11773034Sdougm ngroup = ngroup->next) { 11784327Sdougm if (xmlStrcmp(ngroup->name, (xmlChar *)"group") == 0) 11794327Sdougm break; 11804327Sdougm } 11813034Sdougm } 11823034Sdougm return ((sa_group_t)ngroup); 11833034Sdougm } 11843034Sdougm 11853034Sdougm /* 11863034Sdougm * sa_get_share(group, sharepath) 11873034Sdougm * Return the share object for the share specified. The share 11883034Sdougm * must be in the specified group. Return NULL if not found. 11893034Sdougm */ 11903034Sdougm sa_share_t 11913034Sdougm sa_get_share(sa_group_t group, char *sharepath) 11923034Sdougm { 11933034Sdougm xmlNodePtr node = NULL; 11943034Sdougm xmlChar *path; 11953034Sdougm 11963034Sdougm /* 11973034Sdougm * For future scalability, this should end up building a cache 11983034Sdougm * since it will get called regularly by the mountd and info 11993034Sdougm * services. 12003034Sdougm */ 12013034Sdougm if (group != NULL) { 12024327Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 12033034Sdougm node = node->next) { 12044327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) { 12054327Sdougm if (sharepath == NULL) { 12064327Sdougm break; 12074327Sdougm } else { 12084327Sdougm /* is it the correct share? */ 12094327Sdougm path = xmlGetProp(node, 12104327Sdougm (xmlChar *)"path"); 12114327Sdougm if (path != NULL && 12124327Sdougm xmlStrcmp(path, 12134327Sdougm (xmlChar *)sharepath) == 0) { 12144327Sdougm xmlFree(path); 12154327Sdougm break; 12164327Sdougm } 12174327Sdougm xmlFree(path); 12184327Sdougm } 12193034Sdougm } 12203034Sdougm } 12213034Sdougm } 12223034Sdougm return ((sa_share_t)node); 12233034Sdougm } 12243034Sdougm 12253034Sdougm /* 12263034Sdougm * sa_get_next_share(share) 12273034Sdougm * Return the next share following the specified share 12283034Sdougm * from the internal list of shares. Returns NULL if there 12293034Sdougm * are no more shares. The list is relative to the same 12303034Sdougm * group. 12313034Sdougm */ 12323034Sdougm sa_share_t 12333034Sdougm sa_get_next_share(sa_share_t share) 12343034Sdougm { 12353034Sdougm xmlNodePtr node = NULL; 12363034Sdougm 12373034Sdougm if (share != NULL) { 12384327Sdougm for (node = ((xmlNodePtr)share)->next; node != NULL; 12393034Sdougm node = node->next) { 12404327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) { 12414327Sdougm break; 12424327Sdougm } 12433034Sdougm } 12443034Sdougm } 12453034Sdougm return ((sa_share_t)node); 12463034Sdougm } 12473034Sdougm 12483034Sdougm /* 12493034Sdougm * _sa_get_child_node(node, type) 12503034Sdougm * 12513034Sdougm * find the child node of the specified node that has "type". This is 12523034Sdougm * used to implement several internal functions. 12533034Sdougm */ 12543034Sdougm 12553034Sdougm static xmlNodePtr 12563034Sdougm _sa_get_child_node(xmlNodePtr node, xmlChar *type) 12573034Sdougm { 12583034Sdougm xmlNodePtr child; 12593034Sdougm for (child = node->xmlChildrenNode; child != NULL; 12603034Sdougm child = child->next) 12614327Sdougm if (xmlStrcmp(child->name, type) == 0) 12624327Sdougm return (child); 12633034Sdougm return ((xmlNodePtr)NULL); 12643034Sdougm } 12653034Sdougm 12663034Sdougm /* 12673034Sdougm * find_share(group, path) 12683034Sdougm * 12693034Sdougm * Search all the shares in the specified group for one that has the 12703034Sdougm * specified path. 12713034Sdougm */ 12723034Sdougm 12733034Sdougm static sa_share_t 12743034Sdougm find_share(sa_group_t group, char *sharepath) 12753034Sdougm { 12763034Sdougm sa_share_t share; 12773034Sdougm char *path; 12783034Sdougm 12793034Sdougm for (share = sa_get_share(group, NULL); share != NULL; 12803034Sdougm share = sa_get_next_share(share)) { 12814327Sdougm path = sa_get_share_attr(share, "path"); 12824327Sdougm if (path != NULL && strcmp(path, sharepath) == 0) { 12834327Sdougm sa_free_attr_string(path); 12844327Sdougm break; 12854327Sdougm } 12864327Sdougm if (path != NULL) 12874327Sdougm sa_free_attr_string(path); 12883034Sdougm } 12893034Sdougm return (share); 12903034Sdougm } 12913034Sdougm 12923034Sdougm /* 12933034Sdougm * sa_get_sub_group(group) 12943034Sdougm * 12953034Sdougm * Get the first sub-group of group. The sa_get_next_group() function 12963034Sdougm * can be used to get the rest. This is currently only used for ZFS 12973034Sdougm * sub-groups but could be used to implement a more general mechanism. 12983034Sdougm */ 12993034Sdougm 13003034Sdougm sa_group_t 13013034Sdougm sa_get_sub_group(sa_group_t group) 13023034Sdougm { 13033034Sdougm return ((sa_group_t)_sa_get_child_node((xmlNodePtr)group, 13044327Sdougm (xmlChar *)"group")); 13053034Sdougm } 13063034Sdougm 13073034Sdougm /* 13083034Sdougm * sa_find_share(sharepath) 13093034Sdougm * Finds a share regardless of group. In the future, this 13103034Sdougm * function should utilize a cache and hash table of some kind. 13113034Sdougm * The current assumption is that a path will only be shared 13123034Sdougm * once. In the future, this may change as implementation of 13133034Sdougm * resource names comes into being. 13143034Sdougm */ 13153034Sdougm sa_share_t 13163910Sdougm sa_find_share(sa_handle_t handle, char *sharepath) 13173034Sdougm { 13183034Sdougm sa_group_t group; 13193034Sdougm sa_group_t zgroup; 13203034Sdougm sa_share_t share = NULL; 13213034Sdougm int done = 0; 13223034Sdougm 13233910Sdougm for (group = sa_get_group(handle, NULL); group != NULL && !done; 13244327Sdougm group = sa_get_next_group(group)) { 13254327Sdougm if (is_zfs_group(group)) { 13264327Sdougm for (zgroup = 13274327Sdougm (sa_group_t)_sa_get_child_node((xmlNodePtr)group, 13284327Sdougm (xmlChar *)"group"); 13294327Sdougm zgroup != NULL; 13304327Sdougm zgroup = sa_get_next_group(zgroup)) { 13314327Sdougm share = find_share(zgroup, sharepath); 13324327Sdougm if (share != NULL) 13334327Sdougm break; 13344327Sdougm } 13354327Sdougm } else { 13364327Sdougm share = find_share(group, sharepath); 13374327Sdougm } 13384327Sdougm if (share != NULL) 13393034Sdougm break; 13403034Sdougm } 13413034Sdougm return (share); 13423034Sdougm } 13433034Sdougm 13443034Sdougm /* 13453348Sdougm * sa_check_path(group, path, strictness) 13463034Sdougm * 13475331Samw * Check that path is a valid path relative to the group. Currently, 13483034Sdougm * we are ignoring the group and checking only the NFS rules. Later, 13493034Sdougm * we may want to use the group to then check against the protocols 13503348Sdougm * enabled on the group. The strictness values mean: 13513348Sdougm * SA_CHECK_NORMAL == only check newpath against shares that are active 13523348Sdougm * SA_CHECK_STRICT == check newpath against both active shares and those 13533348Sdougm * stored in the repository 13543034Sdougm */ 13553034Sdougm 13563034Sdougm int 13573348Sdougm sa_check_path(sa_group_t group, char *path, int strictness) 13583034Sdougm { 13593910Sdougm sa_handle_t handle; 13603910Sdougm 13613910Sdougm handle = sa_find_group_handle(group); 13623910Sdougm return (validpath(handle, path, strictness)); 13633034Sdougm } 13643034Sdougm 13653034Sdougm /* 13665331Samw * mark_excluded_protos(group, share, flags) 13673034Sdougm * 13685331Samw * Walk through all the protocols enabled for the group and check to 13695331Samw * see if the share has any of them should be in the exclude list 13705331Samw * based on the featureset of the protocol. If there are any, add the 13715331Samw * "exclude" property to the share. 13725331Samw */ 13735331Samw static void 13745331Samw mark_excluded_protos(sa_group_t group, xmlNodePtr share, uint64_t flags) 13755331Samw { 13765331Samw sa_optionset_t optionset; 13775331Samw char exclude_list[SA_STRSIZE]; 13785331Samw char *sep = ""; 13795331Samw 13805331Samw exclude_list[0] = '\0'; 13815331Samw for (optionset = sa_get_optionset(group, NULL); 13825331Samw optionset != NULL; 13835331Samw optionset = sa_get_next_optionset(optionset)) { 13845331Samw char *value; 13855331Samw uint64_t features; 13865331Samw value = sa_get_optionset_attr(optionset, "type"); 13875331Samw if (value == NULL) 13885331Samw continue; 13895331Samw features = sa_proto_get_featureset(value); 13905331Samw sa_free_attr_string(value); 13915331Samw if (!(features & flags)) { 13925331Samw (void) strlcat(exclude_list, sep, 13935331Samw sizeof (exclude_list)); 13945331Samw (void) strlcat(exclude_list, value, 13955331Samw sizeof (exclude_list)); 13965331Samw sep = ","; 13975331Samw } 13985331Samw } 13995331Samw if (exclude_list[0] != '\0') 14006007Sthurlow (void) xmlSetProp(share, (xmlChar *)"exclude", 14015331Samw (xmlChar *)exclude_list); 14025331Samw } 14035331Samw 14045331Samw /* 14055331Samw * get_all_features(group) 14065331Samw * 14075331Samw * Walk through all the protocols on the group and collect all 14085331Samw * possible enabled features. This is the OR of all the featuresets. 14095331Samw */ 14105331Samw static uint64_t 14115331Samw get_all_features(sa_group_t group) 14125331Samw { 14135331Samw sa_optionset_t optionset; 14145331Samw uint64_t features = 0; 14155331Samw 14165331Samw for (optionset = sa_get_optionset(group, NULL); 14175331Samw optionset != NULL; 14185331Samw optionset = sa_get_next_optionset(optionset)) { 14195331Samw char *value; 14205331Samw value = sa_get_optionset_attr(optionset, "type"); 14215331Samw if (value == NULL) 14225331Samw continue; 14235331Samw features |= sa_proto_get_featureset(value); 14245331Samw sa_free_attr_string(value); 14255331Samw } 14265331Samw return (features); 14275331Samw } 14285331Samw 14295331Samw 14305331Samw /* 14315331Samw * _sa_add_share(group, sharepath, persist, *error, flags) 14325331Samw * 14335331Samw * Common code for all types of add_share. sa_add_share() is the 14343034Sdougm * public API, we also need to be able to do this when parsing legacy 14353034Sdougm * files and construction of the internal configuration while 14365331Samw * extracting config info from SMF. "flags" indicates if some 14375331Samw * protocols need relaxed rules while other don't. These values are 14385331Samw * the featureset values defined in libshare.h. 14393034Sdougm */ 14403034Sdougm 14413034Sdougm sa_share_t 14425331Samw _sa_add_share(sa_group_t group, char *sharepath, int persist, int *error, 14435331Samw uint64_t flags) 14443034Sdougm { 14453034Sdougm xmlNodePtr node = NULL; 14463034Sdougm int err; 14473034Sdougm 14483034Sdougm err = SA_OK; /* assume success */ 14493034Sdougm 14504327Sdougm node = xmlNewChild((xmlNodePtr)group, NULL, (xmlChar *)"share", NULL); 14515331Samw if (node == NULL) { 14525331Samw if (error != NULL) 14535331Samw *error = SA_NO_MEMORY; 14545331Samw return (node); 14555331Samw } 14565331Samw 14576007Sthurlow (void) xmlSetProp(node, (xmlChar *)"path", (xmlChar *)sharepath); 14586007Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", 14595331Samw persist ? (xmlChar *)"persist" : (xmlChar *)"transient"); 14605331Samw if (flags != 0) 14615331Samw mark_excluded_protos(group, node, flags); 14625331Samw if (persist != SA_SHARE_TRANSIENT) { 14635331Samw /* 14645331Samw * persistent shares come in two flavors: SMF and 14655331Samw * ZFS. Sort this one out based on target group and 14665331Samw * path type. Both NFS and SMB are supported. First, 14675331Samw * check to see if the protocol is enabled on the 14685331Samw * subgroup and then setup the share appropriately. 14695331Samw */ 14705331Samw if (sa_group_is_zfs(group) && 14715331Samw sa_path_is_zfs(sharepath)) { 14725331Samw if (sa_get_optionset(group, "nfs") != NULL) 14734327Sdougm err = sa_zfs_set_sharenfs(group, sharepath, 1); 14745331Samw else if (sa_get_optionset(group, "smb") != NULL) 14755331Samw err = sa_zfs_set_sharesmb(group, sharepath, 1); 14765331Samw } else { 14775331Samw sa_handle_impl_t impl_handle; 14785331Samw impl_handle = 14795331Samw (sa_handle_impl_t)sa_find_group_handle(group); 14805331Samw if (impl_handle != NULL) { 14815331Samw err = sa_commit_share(impl_handle->scfhandle, 14825331Samw group, (sa_share_t)node); 14834327Sdougm } else { 14845331Samw err = SA_SYSTEM_ERR; 14854327Sdougm } 14863034Sdougm } 14873034Sdougm } 14885331Samw if (err == SA_NO_PERMISSION && persist & SA_SHARE_PARSER) 14895331Samw /* called by the dfstab parser so could be a show */ 14905331Samw err = SA_OK; 14915331Samw 14925331Samw if (err != SA_OK) { 14935331Samw /* 14945331Samw * we couldn't commit to the repository so undo 14955331Samw * our internal state to reflect reality. 14965331Samw */ 14975331Samw xmlUnlinkNode(node); 14985331Samw xmlFreeNode(node); 14995331Samw node = NULL; 15005331Samw } 15015331Samw 15023034Sdougm if (error != NULL) 15034327Sdougm *error = err; 15045331Samw 15053034Sdougm return (node); 15063034Sdougm } 15073034Sdougm 15083034Sdougm /* 15093034Sdougm * sa_add_share(group, sharepath, persist, *error) 15103034Sdougm * 15113034Sdougm * Add a new share object to the specified group. The share will 15123034Sdougm * have the specified sharepath and will only be constructed if 15133034Sdougm * it is a valid path to be shared. NULL is returned on error 15143034Sdougm * and a detailed error value will be returned via the error 15153034Sdougm * pointer. 15163034Sdougm */ 15173034Sdougm sa_share_t 15183034Sdougm sa_add_share(sa_group_t group, char *sharepath, int persist, int *error) 15193034Sdougm { 15203034Sdougm xmlNodePtr node = NULL; 15213348Sdougm int strictness = SA_CHECK_NORMAL; 15223910Sdougm sa_handle_t handle; 15235331Samw uint64_t special = 0; 15245331Samw uint64_t features; 15253348Sdougm 15263348Sdougm /* 15273348Sdougm * If the share is to be permanent, use strict checking so a 15283348Sdougm * bad config doesn't get created. Transient shares only need 15293348Sdougm * to check against the currently active 15303348Sdougm * shares. SA_SHARE_PARSER is a modifier used internally to 15313348Sdougm * indicate that we are being called by the dfstab parser and 15323348Sdougm * that we need strict checking in all cases. Normally persist 15333348Sdougm * is in integer value but SA_SHARE_PARSER may be or'd into 15343348Sdougm * it as an override. 15353348Sdougm */ 15363348Sdougm if (persist & SA_SHARE_PARSER || persist == SA_SHARE_PERMANENT) 15374327Sdougm strictness = SA_CHECK_STRICT; 15383034Sdougm 15393910Sdougm handle = sa_find_group_handle(group); 15403910Sdougm 15415331Samw /* 15425331Samw * need to determine if the share is valid. The rules are: 15435331Samw * - The path must not already exist 15445331Samw * - The path must not be a subdir or parent dir of an 15455331Samw * existing path unless at least one protocol allows it. 15465331Samw * The sub/parent check is done in sa_check_path(). 15475331Samw */ 15485331Samw 15495331Samw if (sa_find_share(handle, sharepath) == NULL) { 15505331Samw *error = sa_check_path(group, sharepath, strictness); 15515331Samw features = get_all_features(group); 15525331Samw switch (*error) { 15535331Samw case SA_PATH_IS_SUBDIR: 15545331Samw if (features & SA_FEATURE_ALLOWSUBDIRS) 15555331Samw special |= SA_FEATURE_ALLOWSUBDIRS; 15565331Samw break; 15575331Samw case SA_PATH_IS_PARENTDIR: 15585331Samw if (features & SA_FEATURE_ALLOWPARDIRS) 15595331Samw special |= SA_FEATURE_ALLOWPARDIRS; 15605331Samw break; 15615331Samw } 15625331Samw if (*error == SA_OK || special != SA_FEATURE_NONE) 15635331Samw node = _sa_add_share(group, sharepath, persist, 15645331Samw error, special); 15655331Samw } else { 15665331Samw *error = SA_DUPLICATE_NAME; 15673034Sdougm } 15683034Sdougm 15693034Sdougm return ((sa_share_t)node); 15703034Sdougm } 15713034Sdougm 15723034Sdougm /* 15733034Sdougm * sa_enable_share(share, protocol) 15743034Sdougm * Enable the specified share to the specified protocol. 15753034Sdougm * If protocol is NULL, then all protocols. 15763034Sdougm */ 15773034Sdougm int 15783034Sdougm sa_enable_share(sa_share_t share, char *protocol) 15793034Sdougm { 15803034Sdougm char *sharepath; 15813034Sdougm struct stat st; 15825331Samw int err = SA_OK; 15835331Samw int ret; 15843034Sdougm 15853034Sdougm sharepath = sa_get_share_attr(share, "path"); 15865331Samw if (sharepath == NULL) 15875331Samw return (SA_NO_MEMORY); 15883034Sdougm if (stat(sharepath, &st) < 0) { 15894327Sdougm err = SA_NO_SUCH_PATH; 15903034Sdougm } else { 15914327Sdougm /* tell the server about the share */ 15924327Sdougm if (protocol != NULL) { 15935331Samw if (excluded_protocol(share, protocol)) 15945331Samw goto done; 15955331Samw 15964327Sdougm /* lookup protocol specific handler */ 15974327Sdougm err = sa_proto_share(protocol, share); 15984327Sdougm if (err == SA_OK) 15995331Samw (void) sa_set_share_attr(share, 16005331Samw "shared", "true"); 16014327Sdougm } else { 16025331Samw /* Tell all protocols about the share */ 16035331Samw sa_group_t group; 16045331Samw sa_optionset_t optionset; 16055331Samw 16065331Samw group = sa_get_parent_group(share); 16075331Samw 16085331Samw for (optionset = sa_get_optionset(group, NULL); 16095331Samw optionset != NULL; 16105331Samw optionset = sa_get_next_optionset(optionset)) { 16115331Samw char *proto; 16125331Samw proto = sa_get_optionset_attr(optionset, 16135331Samw "type"); 16145331Samw if (proto != NULL) { 16155331Samw if (!excluded_protocol(share, proto)) { 16165331Samw ret = sa_proto_share(proto, 16175331Samw share); 16185331Samw if (ret != SA_OK) 16195331Samw err = ret; 16205331Samw } 16215331Samw sa_free_attr_string(proto); 16225331Samw } 16235331Samw } 16244327Sdougm (void) sa_set_share_attr(share, "shared", "true"); 16254327Sdougm } 16263034Sdougm } 16275331Samw done: 16283034Sdougm if (sharepath != NULL) 16294327Sdougm sa_free_attr_string(sharepath); 16303034Sdougm return (err); 16313034Sdougm } 16323034Sdougm 16333034Sdougm /* 16343034Sdougm * sa_disable_share(share, protocol) 16355331Samw * Disable the specified share to the specified protocol. If 16365331Samw * protocol is NULL, then all protocols that are enabled for the 16375331Samw * share should be disabled. 16383034Sdougm */ 16393034Sdougm int 16403034Sdougm sa_disable_share(sa_share_t share, char *protocol) 16413034Sdougm { 16423034Sdougm char *path; 16435331Samw int err = SA_OK; 16443034Sdougm int ret = SA_OK; 16453034Sdougm 16463034Sdougm path = sa_get_share_attr(share, "path"); 16473034Sdougm 16483034Sdougm if (protocol != NULL) { 16494543Smarks ret = sa_proto_unshare(share, protocol, path); 16503034Sdougm } else { 16514327Sdougm /* need to do all protocols */ 16525331Samw sa_group_t group; 16535331Samw sa_optionset_t optionset; 16545331Samw 16555331Samw group = sa_get_parent_group(share); 16565331Samw 16575331Samw /* Tell all protocols about the share */ 16585331Samw for (optionset = sa_get_optionset(group, NULL); 16595331Samw optionset != NULL; 16605331Samw optionset = sa_get_next_optionset(optionset)) { 16615331Samw char *proto; 16625331Samw 16635331Samw proto = sa_get_optionset_attr(optionset, "type"); 16645331Samw if (proto != NULL) { 16655331Samw err = sa_proto_unshare(share, proto, path); 16665331Samw if (err != SA_OK) 16675331Samw ret = err; 16685331Samw sa_free_attr_string(proto); 16695331Samw } 16705331Samw } 16713034Sdougm } 16723034Sdougm if (ret == SA_OK) 16733034Sdougm (void) sa_set_share_attr(share, "shared", NULL); 16743034Sdougm if (path != NULL) 16754327Sdougm sa_free_attr_string(path); 16763034Sdougm return (ret); 16773034Sdougm } 16783034Sdougm 16793034Sdougm /* 16803034Sdougm * sa_remove_share(share) 16813034Sdougm * 16823034Sdougm * remove the specified share from its containing group. 16833034Sdougm * Remove from the SMF or ZFS configuration space. 16843034Sdougm */ 16853034Sdougm 16863034Sdougm int 16873034Sdougm sa_remove_share(sa_share_t share) 16883034Sdougm { 16893034Sdougm sa_group_t group; 16903034Sdougm int ret = SA_OK; 16913034Sdougm char *type; 16923034Sdougm int transient = 0; 16933034Sdougm char *groupname; 16943034Sdougm char *zfs; 16953034Sdougm 16963034Sdougm type = sa_get_share_attr(share, "type"); 16973034Sdougm group = sa_get_parent_group(share); 16983034Sdougm zfs = sa_get_group_attr(group, "zfs"); 16993034Sdougm groupname = sa_get_group_attr(group, "name"); 17003034Sdougm if (type != NULL && strcmp(type, "persist") != 0) 17014327Sdougm transient = 1; 17023034Sdougm if (type != NULL) 17034327Sdougm sa_free_attr_string(type); 17043034Sdougm 17053034Sdougm /* remove the node from its group then free the memory */ 17063034Sdougm 17073034Sdougm /* 17083034Sdougm * need to test if "busy" 17093034Sdougm */ 17103034Sdougm /* only do SMF action if permanent */ 17113034Sdougm if (!transient || zfs != NULL) { 17124327Sdougm /* remove from legacy dfstab as well as possible SMF */ 17135331Samw ret = sa_delete_legacy(share, NULL); 17144327Sdougm if (ret == SA_OK) { 17154327Sdougm if (!sa_group_is_zfs(group)) { 17164327Sdougm sa_handle_impl_t impl_handle; 17174327Sdougm impl_handle = (sa_handle_impl_t) 17184327Sdougm sa_find_group_handle(group); 17194327Sdougm if (impl_handle != NULL) { 17204327Sdougm ret = sa_delete_share( 17214327Sdougm impl_handle->scfhandle, group, 17224327Sdougm share); 17234327Sdougm } else { 17244327Sdougm ret = SA_SYSTEM_ERR; 17254327Sdougm } 17264327Sdougm } else { 17274327Sdougm char *sharepath = sa_get_share_attr(share, 17284327Sdougm "path"); 17294327Sdougm if (sharepath != NULL) { 17304327Sdougm ret = sa_zfs_set_sharenfs(group, 17314327Sdougm sharepath, 0); 17324327Sdougm sa_free_attr_string(sharepath); 17334327Sdougm } 17344327Sdougm } 17353034Sdougm } 17363034Sdougm } 17373034Sdougm if (groupname != NULL) 17384327Sdougm sa_free_attr_string(groupname); 17393034Sdougm if (zfs != NULL) 17404327Sdougm sa_free_attr_string(zfs); 17413034Sdougm 17423034Sdougm xmlUnlinkNode((xmlNodePtr)share); 17433034Sdougm xmlFreeNode((xmlNodePtr)share); 17443034Sdougm return (ret); 17453034Sdougm } 17463034Sdougm 17473034Sdougm /* 17483034Sdougm * sa_move_share(group, share) 17493034Sdougm * 17503034Sdougm * move the specified share to the specified group. Update SMF 17513034Sdougm * appropriately. 17523034Sdougm */ 17533034Sdougm 17543034Sdougm int 17553034Sdougm sa_move_share(sa_group_t group, sa_share_t share) 17563034Sdougm { 17573034Sdougm sa_group_t oldgroup; 17583034Sdougm int ret = SA_OK; 17593034Sdougm 17603034Sdougm /* remove the node from its group then free the memory */ 17613034Sdougm 17623034Sdougm oldgroup = sa_get_parent_group(share); 17633034Sdougm if (oldgroup != group) { 17644327Sdougm sa_handle_impl_t impl_handle; 17654327Sdougm xmlUnlinkNode((xmlNodePtr)share); 17663034Sdougm /* 17674327Sdougm * now that the share isn't in its old group, add to 17684327Sdougm * the new one 17693034Sdougm */ 17706007Sthurlow (void) xmlAddChild((xmlNodePtr)group, (xmlNodePtr)share); 17714327Sdougm /* need to deal with SMF */ 17724327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 17734327Sdougm if (impl_handle != NULL) { 17744327Sdougm /* 17754327Sdougm * need to remove from old group first and then add to 17764327Sdougm * new group. Ideally, we would do the other order but 17774327Sdougm * need to avoid having the share in two groups at the 17784327Sdougm * same time. 17794327Sdougm */ 17804327Sdougm ret = sa_delete_share(impl_handle->scfhandle, oldgroup, 17814327Sdougm share); 17824327Sdougm if (ret == SA_OK) 17834327Sdougm ret = sa_commit_share(impl_handle->scfhandle, 17844327Sdougm group, share); 17854327Sdougm } else { 17864327Sdougm ret = SA_SYSTEM_ERR; 17874327Sdougm } 17883034Sdougm } 17893034Sdougm return (ret); 17903034Sdougm } 17913034Sdougm 17923034Sdougm /* 17933034Sdougm * sa_get_parent_group(share) 17943034Sdougm * 17955331Samw * Return the containing group for the share. If a group was actually 17963034Sdougm * passed in, we don't want a parent so return NULL. 17973034Sdougm */ 17983034Sdougm 17993034Sdougm sa_group_t 18003034Sdougm sa_get_parent_group(sa_share_t share) 18013034Sdougm { 18023034Sdougm xmlNodePtr node = NULL; 18033034Sdougm if (share != NULL) { 18044327Sdougm node = ((xmlNodePtr)share)->parent; 18053034Sdougm /* 18063034Sdougm * make sure parent is a group and not sharecfg since 18073034Sdougm * we may be cheating and passing in a group. 18083034Sdougm * Eventually, groups of groups might come into being. 18093034Sdougm */ 18104327Sdougm if (node == NULL || 18114327Sdougm xmlStrcmp(node->name, (xmlChar *)"sharecfg") == 0) 18124327Sdougm node = NULL; 18133034Sdougm } 18143034Sdougm return ((sa_group_t)node); 18153034Sdougm } 18163034Sdougm 18173034Sdougm /* 18183910Sdougm * _sa_create_group(impl_handle, groupname) 18193034Sdougm * 18203034Sdougm * Create a group in the document. The caller will need to deal with 18213034Sdougm * configuration store and activation. 18223034Sdougm */ 18233034Sdougm 18243034Sdougm sa_group_t 18253910Sdougm _sa_create_group(sa_handle_impl_t impl_handle, char *groupname) 18263034Sdougm { 18273034Sdougm xmlNodePtr node = NULL; 18283034Sdougm 18293034Sdougm if (sa_valid_group_name(groupname)) { 18304327Sdougm node = xmlNewChild(impl_handle->tree, NULL, (xmlChar *)"group", 18314327Sdougm NULL); 18324327Sdougm if (node != NULL) { 18336007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 18344327Sdougm (xmlChar *)groupname); 18356007Sthurlow (void) xmlSetProp(node, (xmlChar *)"state", 18364327Sdougm (xmlChar *)"enabled"); 18374327Sdougm } 18383034Sdougm } 18393034Sdougm return ((sa_group_t)node); 18403034Sdougm } 18413034Sdougm 18423034Sdougm /* 18433034Sdougm * _sa_create_zfs_group(group, groupname) 18443034Sdougm * 18453034Sdougm * Create a ZFS subgroup under the specified group. This may 18463034Sdougm * eventually form the basis of general sub-groups, but is currently 18473034Sdougm * restricted to ZFS. 18483034Sdougm */ 18493034Sdougm sa_group_t 18503034Sdougm _sa_create_zfs_group(sa_group_t group, char *groupname) 18513034Sdougm { 18523034Sdougm xmlNodePtr node = NULL; 18533034Sdougm 18544327Sdougm node = xmlNewChild((xmlNodePtr)group, NULL, (xmlChar *)"group", NULL); 18553034Sdougm if (node != NULL) { 18566007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 18576007Sthurlow (xmlChar *)groupname); 18586007Sthurlow (void) xmlSetProp(node, (xmlChar *)"state", 18596007Sthurlow (xmlChar *)"enabled"); 18603034Sdougm } 18613034Sdougm 18623034Sdougm return ((sa_group_t)node); 18633034Sdougm } 18643034Sdougm 18653034Sdougm /* 18663034Sdougm * sa_create_group(groupname, *error) 18673034Sdougm * 18683034Sdougm * Create a new group with groupname. Need to validate that it is a 18693034Sdougm * legal name for SMF and the construct the SMF service instance of 18703034Sdougm * svc:/network/shares/group to implement the group. All necessary 18713034Sdougm * operational properties must be added to the group at this point 18723034Sdougm * (via the SMF transaction model). 18733034Sdougm */ 18743034Sdougm sa_group_t 18753910Sdougm sa_create_group(sa_handle_t handle, char *groupname, int *error) 18763034Sdougm { 18773034Sdougm xmlNodePtr node = NULL; 18783034Sdougm sa_group_t group; 18793034Sdougm int ret; 18804327Sdougm char rbacstr[SA_STRSIZE]; 18813910Sdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle; 18823034Sdougm 18833034Sdougm ret = SA_OK; 18843034Sdougm 18853910Sdougm if (impl_handle == NULL || impl_handle->scfhandle == NULL) { 18864327Sdougm ret = SA_SYSTEM_ERR; 18874327Sdougm goto err; 18883034Sdougm } 18893034Sdougm 18903910Sdougm group = sa_get_group(handle, groupname); 18913034Sdougm if (group != NULL) { 18924327Sdougm ret = SA_DUPLICATE_NAME; 18933034Sdougm } else { 18944327Sdougm if (sa_valid_group_name(groupname)) { 18954327Sdougm node = xmlNewChild(impl_handle->tree, NULL, 18964327Sdougm (xmlChar *)"group", NULL); 18974327Sdougm if (node != NULL) { 18986007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 18994327Sdougm (xmlChar *)groupname); 19004327Sdougm /* default to the group being enabled */ 19016007Sthurlow (void) xmlSetProp(node, (xmlChar *)"state", 19024327Sdougm (xmlChar *)"enabled"); 19034327Sdougm ret = sa_create_instance(impl_handle->scfhandle, 19044327Sdougm groupname); 19054327Sdougm if (ret == SA_OK) { 19064327Sdougm ret = sa_start_transaction( 19074327Sdougm impl_handle->scfhandle, 19084327Sdougm "operation"); 19094327Sdougm } 19104327Sdougm if (ret == SA_OK) { 19114327Sdougm ret = sa_set_property( 19124327Sdougm impl_handle->scfhandle, 19134327Sdougm "state", "enabled"); 19144327Sdougm if (ret == SA_OK) { 19154327Sdougm ret = sa_end_transaction( 19165951Sdougm impl_handle->scfhandle, 19175951Sdougm impl_handle); 19184327Sdougm } else { 19194327Sdougm sa_abort_transaction( 19204327Sdougm impl_handle->scfhandle); 19214327Sdougm } 19224327Sdougm } 19234327Sdougm if (ret == SA_OK) { 19244327Sdougm /* initialize the RBAC strings */ 19254327Sdougm ret = sa_start_transaction( 19264327Sdougm impl_handle->scfhandle, 19274327Sdougm "general"); 19284327Sdougm if (ret == SA_OK) { 19294327Sdougm (void) snprintf(rbacstr, 19304327Sdougm sizeof (rbacstr), "%s.%s", 19314327Sdougm SA_RBAC_MANAGE, groupname); 19324327Sdougm ret = sa_set_property( 19334327Sdougm impl_handle->scfhandle, 19343034Sdougm "action_authorization", 19353034Sdougm rbacstr); 19364327Sdougm } 19374327Sdougm if (ret == SA_OK) { 19384327Sdougm (void) snprintf(rbacstr, 19394327Sdougm sizeof (rbacstr), "%s.%s", 19404327Sdougm SA_RBAC_VALUE, groupname); 19414327Sdougm ret = sa_set_property( 19424327Sdougm impl_handle->scfhandle, 19433034Sdougm "value_authorization", 19443034Sdougm rbacstr); 19454327Sdougm } 19464327Sdougm if (ret == SA_OK) { 19474327Sdougm ret = sa_end_transaction( 19485951Sdougm impl_handle->scfhandle, 19495951Sdougm impl_handle); 19504327Sdougm } else { 19514327Sdougm sa_abort_transaction( 19524327Sdougm impl_handle->scfhandle); 19534327Sdougm } 19544327Sdougm } 19554327Sdougm if (ret != SA_OK) { 19564327Sdougm /* 19574327Sdougm * Couldn't commit the group 19584327Sdougm * so we need to undo 19594327Sdougm * internally. 19604327Sdougm */ 19614327Sdougm xmlUnlinkNode(node); 19624327Sdougm xmlFreeNode(node); 19634327Sdougm node = NULL; 19644327Sdougm } 19653034Sdougm } else { 19664327Sdougm ret = SA_NO_MEMORY; 19673034Sdougm } 19683034Sdougm } else { 19694327Sdougm ret = SA_INVALID_NAME; 19703034Sdougm } 19713034Sdougm } 19723034Sdougm err: 19733034Sdougm if (error != NULL) 19744327Sdougm *error = ret; 19753034Sdougm return ((sa_group_t)node); 19763034Sdougm } 19773034Sdougm 19783034Sdougm /* 19793034Sdougm * sa_remove_group(group) 19803034Sdougm * 19813034Sdougm * Remove the specified group. This deletes from the SMF repository. 19823034Sdougm * All property groups and properties are removed. 19833034Sdougm */ 19843034Sdougm 19853034Sdougm int 19863034Sdougm sa_remove_group(sa_group_t group) 19873034Sdougm { 19883034Sdougm char *name; 19893034Sdougm int ret = SA_OK; 19903910Sdougm sa_handle_impl_t impl_handle; 19913034Sdougm 19923910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 19933910Sdougm if (impl_handle != NULL) { 19944327Sdougm name = sa_get_group_attr(group, "name"); 19954327Sdougm if (name != NULL) { 19964327Sdougm ret = sa_delete_instance(impl_handle->scfhandle, name); 19974327Sdougm sa_free_attr_string(name); 19984327Sdougm } 19994327Sdougm xmlUnlinkNode((xmlNodePtr)group); /* make sure unlinked */ 20004327Sdougm xmlFreeNode((xmlNodePtr)group); /* now it is gone */ 20013910Sdougm } else { 20024327Sdougm ret = SA_SYSTEM_ERR; 20033034Sdougm } 20043034Sdougm return (ret); 20053034Sdougm } 20063034Sdougm 20073034Sdougm /* 20083034Sdougm * sa_update_config() 20093034Sdougm * 20103034Sdougm * Used to update legacy files that need to be updated in bulk 20113034Sdougm * Currently, this is a placeholder and will go away in a future 20123034Sdougm * release. 20133034Sdougm */ 20143034Sdougm 20153034Sdougm int 20163910Sdougm sa_update_config(sa_handle_t handle) 20173034Sdougm { 20183034Sdougm /* 20193034Sdougm * do legacy files first so we can tell when they change. 20203034Sdougm * This will go away when we start updating individual records 20213034Sdougm * rather than the whole file. 20223034Sdougm */ 20233910Sdougm update_legacy_config(handle); 20243034Sdougm return (SA_OK); 20253034Sdougm } 20263034Sdougm 20273034Sdougm /* 20283034Sdougm * get_node_attr(node, tag) 20293034Sdougm * 20305331Samw * Get the specified tag(attribute) if it exists on the node. This is 20313034Sdougm * used internally by a number of attribute oriented functions. 20323034Sdougm */ 20333034Sdougm 20343034Sdougm static char * 20353034Sdougm get_node_attr(void *nodehdl, char *tag) 20363034Sdougm { 20373034Sdougm xmlNodePtr node = (xmlNodePtr)nodehdl; 20383034Sdougm xmlChar *name = NULL; 20393034Sdougm 20404327Sdougm if (node != NULL) 20413034Sdougm name = xmlGetProp(node, (xmlChar *)tag); 20423034Sdougm return ((char *)name); 20433034Sdougm } 20443034Sdougm 20453034Sdougm /* 20463034Sdougm * get_node_attr(node, tag) 20473034Sdougm * 20485331Samw * Set the specified tag(attribute) to the specified value This is 20493034Sdougm * used internally by a number of attribute oriented functions. It 20503034Sdougm * doesn't update the repository, only the internal document state. 20513034Sdougm */ 20523034Sdougm 20533034Sdougm void 20543034Sdougm set_node_attr(void *nodehdl, char *tag, char *value) 20553034Sdougm { 20563034Sdougm xmlNodePtr node = (xmlNodePtr)nodehdl; 20573034Sdougm if (node != NULL && tag != NULL) { 20584327Sdougm if (value != NULL) 20596007Sthurlow (void) xmlSetProp(node, (xmlChar *)tag, 20606007Sthurlow (xmlChar *)value); 20614327Sdougm else 20626007Sthurlow (void) xmlUnsetProp(node, (xmlChar *)tag); 20633034Sdougm } 20643034Sdougm } 20653034Sdougm 20663034Sdougm /* 20673034Sdougm * sa_get_group_attr(group, tag) 20683034Sdougm * 20693034Sdougm * Get the specied attribute, if defined, for the group. 20703034Sdougm */ 20713034Sdougm 20723034Sdougm char * 20733034Sdougm sa_get_group_attr(sa_group_t group, char *tag) 20743034Sdougm { 20753034Sdougm return (get_node_attr((void *)group, tag)); 20763034Sdougm } 20773034Sdougm 20783034Sdougm /* 20793034Sdougm * sa_set_group_attr(group, tag, value) 20803034Sdougm * 20813034Sdougm * set the specified tag/attribute on the group using value as its 20823034Sdougm * value. 20833034Sdougm * 20843034Sdougm * This will result in setting the property in the SMF repository as 20853034Sdougm * well as in the internal document. 20863034Sdougm */ 20873034Sdougm 20883034Sdougm int 20893034Sdougm sa_set_group_attr(sa_group_t group, char *tag, char *value) 20903034Sdougm { 20913034Sdougm int ret; 20923034Sdougm char *groupname; 20933910Sdougm sa_handle_impl_t impl_handle; 20943034Sdougm 20955331Samw /* 20965331Samw * ZFS group/subgroup doesn't need the handle so shortcut. 20975331Samw */ 20985331Samw if (sa_group_is_zfs(group)) { 20995331Samw set_node_attr((void *)group, tag, value); 21005331Samw return (SA_OK); 21015331Samw } 21025331Samw 21033910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 21043910Sdougm if (impl_handle != NULL) { 21054327Sdougm groupname = sa_get_group_attr(group, "name"); 21064327Sdougm ret = sa_get_instance(impl_handle->scfhandle, groupname); 21073910Sdougm if (ret == SA_OK) { 21084327Sdougm set_node_attr((void *)group, tag, value); 21094327Sdougm ret = sa_start_transaction(impl_handle->scfhandle, 21104327Sdougm "operation"); 21114327Sdougm if (ret == SA_OK) { 21124327Sdougm ret = sa_set_property(impl_handle->scfhandle, 21134327Sdougm tag, value); 21144327Sdougm if (ret == SA_OK) 21155885Sdougm ret = sa_end_transaction( 21165951Sdougm impl_handle->scfhandle, 21175951Sdougm impl_handle); 21184327Sdougm else 21194327Sdougm sa_abort_transaction( 21204327Sdougm impl_handle->scfhandle); 21214327Sdougm } 21225885Sdougm if (ret == SA_SYSTEM_ERR) 21235885Sdougm ret = SA_NO_PERMISSION; 21243034Sdougm } 21254327Sdougm if (groupname != NULL) 21264327Sdougm sa_free_attr_string(groupname); 21273910Sdougm } else { 21284327Sdougm ret = SA_SYSTEM_ERR; 21293034Sdougm } 21303034Sdougm return (ret); 21313034Sdougm } 21323034Sdougm 21333034Sdougm /* 21343034Sdougm * sa_get_share_attr(share, tag) 21353034Sdougm * 21363034Sdougm * Return the value of the tag/attribute set on the specified 21373034Sdougm * share. Returns NULL if the tag doesn't exist. 21383034Sdougm */ 21393034Sdougm 21403034Sdougm char * 21413034Sdougm sa_get_share_attr(sa_share_t share, char *tag) 21423034Sdougm { 21433034Sdougm return (get_node_attr((void *)share, tag)); 21443034Sdougm } 21453034Sdougm 21463034Sdougm /* 21473034Sdougm * _sa_set_share_description(share, description) 21483034Sdougm * 21495331Samw * Add a description tag with text contents to the specified share. A 21505331Samw * separate XML tag is used rather than a property. This can also be 21515331Samw * used with resources. 21523034Sdougm */ 21533034Sdougm 21543034Sdougm xmlNodePtr 21555331Samw _sa_set_share_description(void *share, char *content) 21563034Sdougm { 21573034Sdougm xmlNodePtr node; 21584327Sdougm node = xmlNewChild((xmlNodePtr)share, NULL, (xmlChar *)"description", 21594327Sdougm NULL); 21603034Sdougm xmlNodeSetContent(node, (xmlChar *)content); 21613034Sdougm return (node); 21623034Sdougm } 21633034Sdougm 21643034Sdougm /* 21653034Sdougm * sa_set_share_attr(share, tag, value) 21663034Sdougm * 21673034Sdougm * Set the share attribute specified by tag to the specified value. In 21683034Sdougm * the case of "resource", enforce a no duplicates in a group rule. If 21693034Sdougm * the share is not transient, commit the changes to the repository 21703034Sdougm * else just update the share internally. 21713034Sdougm */ 21723034Sdougm 21733034Sdougm int 21743034Sdougm sa_set_share_attr(sa_share_t share, char *tag, char *value) 21753034Sdougm { 21763034Sdougm sa_group_t group; 21773034Sdougm sa_share_t resource; 21783034Sdougm int ret = SA_OK; 21793034Sdougm 21803034Sdougm group = sa_get_parent_group(share); 21813034Sdougm 21823034Sdougm /* 21833034Sdougm * There are some attributes that may have specific 21843034Sdougm * restrictions on them. Initially, only "resource" has 21853034Sdougm * special meaning that needs to be checked. Only one instance 21863034Sdougm * of a resource name may exist within a group. 21873034Sdougm */ 21883034Sdougm 21893034Sdougm if (strcmp(tag, "resource") == 0) { 21904327Sdougm resource = sa_get_resource(group, value); 21914327Sdougm if (resource != share && resource != NULL) 21924327Sdougm ret = SA_DUPLICATE_NAME; 21933034Sdougm } 21943034Sdougm if (ret == SA_OK) { 21954327Sdougm set_node_attr((void *)share, tag, value); 21964327Sdougm if (group != NULL) { 21974327Sdougm char *type; 21984327Sdougm /* we can probably optimize this some */ 21994327Sdougm type = sa_get_share_attr(share, "type"); 22004327Sdougm if (type == NULL || strcmp(type, "transient") != 0) { 22014327Sdougm sa_handle_impl_t impl_handle; 22024327Sdougm impl_handle = 22034327Sdougm (sa_handle_impl_t)sa_find_group_handle( 22044327Sdougm group); 22054327Sdougm if (impl_handle != NULL) { 22064327Sdougm ret = sa_commit_share( 22074327Sdougm impl_handle->scfhandle, group, 22084327Sdougm share); 22094327Sdougm } else { 22104327Sdougm ret = SA_SYSTEM_ERR; 22114327Sdougm } 22124327Sdougm } 22134327Sdougm if (type != NULL) 22144327Sdougm sa_free_attr_string(type); 22153910Sdougm } 22163034Sdougm } 22173034Sdougm return (ret); 22183034Sdougm } 22193034Sdougm 22203034Sdougm /* 22213034Sdougm * sa_get_property_attr(prop, tag) 22223034Sdougm * 22233034Sdougm * Get the value of the specified property attribute. Standard 22243034Sdougm * attributes are "type" and "value". 22253034Sdougm */ 22263034Sdougm 22273034Sdougm char * 22283034Sdougm sa_get_property_attr(sa_property_t prop, char *tag) 22293034Sdougm { 22303034Sdougm return (get_node_attr((void *)prop, tag)); 22313034Sdougm } 22323034Sdougm 22333034Sdougm /* 22343034Sdougm * sa_get_optionset_attr(prop, tag) 22353034Sdougm * 22363034Sdougm * Get the value of the specified property attribute. Standard 22373034Sdougm * attribute is "type". 22383034Sdougm */ 22393034Sdougm 22403034Sdougm char * 22413034Sdougm sa_get_optionset_attr(sa_property_t optionset, char *tag) 22423034Sdougm { 22433034Sdougm return (get_node_attr((void *)optionset, tag)); 22443034Sdougm 22453034Sdougm } 22463034Sdougm 22473034Sdougm /* 22483034Sdougm * sa_set_optionset_attr(optionset, tag, value) 22493034Sdougm * 22503034Sdougm * Set the specified attribute(tag) to the specified value on the 22513034Sdougm * optionset. 22523034Sdougm */ 22533034Sdougm 22543034Sdougm void 22553034Sdougm sa_set_optionset_attr(sa_group_t optionset, char *tag, char *value) 22563034Sdougm { 22573034Sdougm set_node_attr((void *)optionset, tag, value); 22583034Sdougm } 22593034Sdougm 22603034Sdougm /* 22613034Sdougm * sa_free_attr_string(string) 22623034Sdougm * 22633034Sdougm * Free the string that was returned in one of the sa_get_*_attr() 22643034Sdougm * functions. 22653034Sdougm */ 22663034Sdougm 22673034Sdougm void 22683034Sdougm sa_free_attr_string(char *string) 22693034Sdougm { 22703034Sdougm xmlFree((xmlChar *)string); 22713034Sdougm } 22723034Sdougm 22733034Sdougm /* 22743034Sdougm * sa_get_optionset(group, proto) 22753034Sdougm * 22763034Sdougm * Return the optionset, if it exists, that is associated with the 22773034Sdougm * specified protocol. 22783034Sdougm */ 22793034Sdougm 22803034Sdougm sa_optionset_t 22813034Sdougm sa_get_optionset(void *group, char *proto) 22823034Sdougm { 22833034Sdougm xmlNodePtr node; 22843034Sdougm xmlChar *value = NULL; 22853034Sdougm 22863034Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 22874327Sdougm node = node->next) { 22883034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) { 22894327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 22904327Sdougm if (proto != NULL) { 22914327Sdougm if (value != NULL && 22924327Sdougm xmlStrcmp(value, (xmlChar *)proto) == 0) { 22934327Sdougm break; 22944327Sdougm } 22954327Sdougm if (value != NULL) { 22964327Sdougm xmlFree(value); 22974327Sdougm value = NULL; 22984327Sdougm } 22994327Sdougm } else { 23004327Sdougm break; 23013034Sdougm } 23023034Sdougm } 23033034Sdougm } 23043034Sdougm if (value != NULL) 23054327Sdougm xmlFree(value); 23063034Sdougm return ((sa_optionset_t)node); 23073034Sdougm } 23083034Sdougm 23093034Sdougm /* 23103034Sdougm * sa_get_next_optionset(optionset) 23113034Sdougm * 23123034Sdougm * Return the next optionset in the group. NULL if this was the last. 23133034Sdougm */ 23143034Sdougm 23153034Sdougm sa_optionset_t 23163034Sdougm sa_get_next_optionset(sa_optionset_t optionset) 23173034Sdougm { 23183034Sdougm xmlNodePtr node; 23193034Sdougm 23203034Sdougm for (node = ((xmlNodePtr)optionset)->next; node != NULL; 23214327Sdougm node = node->next) { 23223034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) { 23233034Sdougm break; 23243034Sdougm } 23253034Sdougm } 23263034Sdougm return ((sa_optionset_t)node); 23273034Sdougm } 23283034Sdougm 23293034Sdougm /* 23303034Sdougm * sa_get_security(group, sectype, proto) 23313034Sdougm * 23323034Sdougm * Return the security optionset. The internal name is a hold over 23333034Sdougm * from the implementation and will be changed before the API is 23343034Sdougm * finalized. This is really a named optionset that can be negotiated 23353034Sdougm * as a group of properties (like NFS security options). 23363034Sdougm */ 23373034Sdougm 23383034Sdougm sa_security_t 23393034Sdougm sa_get_security(sa_group_t group, char *sectype, char *proto) 23403034Sdougm { 23413034Sdougm xmlNodePtr node; 23423034Sdougm xmlChar *value = NULL; 23433034Sdougm 23443034Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 23454327Sdougm node = node->next) { 23464327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) { 23474327Sdougm if (proto != NULL) { 23484327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 23494327Sdougm if (value == NULL || 23504327Sdougm (value != NULL && 23514327Sdougm xmlStrcmp(value, (xmlChar *)proto) != 0)) { 23524327Sdougm /* it doesn't match so continue */ 23534327Sdougm xmlFree(value); 23544327Sdougm value = NULL; 23554327Sdougm continue; 23564327Sdougm } 23574327Sdougm } 23584327Sdougm if (value != NULL) { 23594327Sdougm xmlFree(value); 23604327Sdougm value = NULL; 23614327Sdougm } 23624327Sdougm /* potential match */ 23634327Sdougm if (sectype != NULL) { 23644327Sdougm value = xmlGetProp(node, (xmlChar *)"sectype"); 23654327Sdougm if (value != NULL && 23664327Sdougm xmlStrcmp(value, (xmlChar *)sectype) == 0) { 23674327Sdougm break; 23684327Sdougm } 23694327Sdougm } else { 23704327Sdougm break; 23714327Sdougm } 23723034Sdougm } 23733034Sdougm if (value != NULL) { 23744327Sdougm xmlFree(value); 23754327Sdougm value = NULL; 23763034Sdougm } 23773034Sdougm } 23783034Sdougm if (value != NULL) 23794327Sdougm xmlFree(value); 23803034Sdougm return ((sa_security_t)node); 23813034Sdougm } 23823034Sdougm 23833034Sdougm /* 23843034Sdougm * sa_get_next_security(security) 23853034Sdougm * 23863034Sdougm * Get the next security optionset if one exists. 23873034Sdougm */ 23883034Sdougm 23893034Sdougm sa_security_t 23903034Sdougm sa_get_next_security(sa_security_t security) 23913034Sdougm { 23923034Sdougm xmlNodePtr node; 23933034Sdougm 23943034Sdougm for (node = ((xmlNodePtr)security)->next; node != NULL; 23954327Sdougm node = node->next) { 23963034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) { 23973034Sdougm break; 23983034Sdougm } 23993034Sdougm } 24003034Sdougm return ((sa_security_t)node); 24013034Sdougm } 24023034Sdougm 24033034Sdougm /* 24043034Sdougm * sa_get_property(optionset, prop) 24053034Sdougm * 24063034Sdougm * Get the property object with the name specified in prop from the 24073034Sdougm * optionset. 24083034Sdougm */ 24093034Sdougm 24103034Sdougm sa_property_t 24113034Sdougm sa_get_property(sa_optionset_t optionset, char *prop) 24123034Sdougm { 24133034Sdougm xmlNodePtr node = (xmlNodePtr)optionset; 24143034Sdougm xmlChar *value = NULL; 24153034Sdougm 24163034Sdougm if (optionset == NULL) 24174327Sdougm return (NULL); 24183034Sdougm 24193034Sdougm for (node = node->children; node != NULL; 24204327Sdougm node = node->next) { 24214327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 24224327Sdougm if (prop == NULL) 24234327Sdougm break; 24244327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 24254327Sdougm if (value != NULL && 24264327Sdougm xmlStrcmp(value, (xmlChar *)prop) == 0) { 24274327Sdougm break; 24284327Sdougm } 24294327Sdougm if (value != NULL) { 24304327Sdougm xmlFree(value); 24314327Sdougm value = NULL; 24324327Sdougm } 24333034Sdougm } 24343034Sdougm } 24353034Sdougm if (value != NULL) 24363034Sdougm xmlFree(value); 24373034Sdougm if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"option") != 0) { 24384327Sdougm /* 24394327Sdougm * avoid a non option node -- it is possible to be a 24404327Sdougm * text node 24414327Sdougm */ 24424327Sdougm node = NULL; 24433034Sdougm } 24443034Sdougm return ((sa_property_t)node); 24453034Sdougm } 24463034Sdougm 24473034Sdougm /* 24483034Sdougm * sa_get_next_property(property) 24493034Sdougm * 24503034Sdougm * Get the next property following the specified property. NULL if 24513034Sdougm * this was the last. 24523034Sdougm */ 24533034Sdougm 24543034Sdougm sa_property_t 24553034Sdougm sa_get_next_property(sa_property_t property) 24563034Sdougm { 24573034Sdougm xmlNodePtr node; 24583034Sdougm 24593034Sdougm for (node = ((xmlNodePtr)property)->next; node != NULL; 24604327Sdougm node = node->next) { 24613034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 24623034Sdougm break; 24633034Sdougm } 24643034Sdougm } 24653034Sdougm return ((sa_property_t)node); 24663034Sdougm } 24673034Sdougm 24683034Sdougm /* 24693034Sdougm * sa_set_share_description(share, content) 24703034Sdougm * 24713034Sdougm * Set the description of share to content. 24723034Sdougm */ 24733034Sdougm 24743034Sdougm int 24753034Sdougm sa_set_share_description(sa_share_t share, char *content) 24763034Sdougm { 24773034Sdougm xmlNodePtr node; 24783034Sdougm sa_group_t group; 24793034Sdougm int ret = SA_OK; 24803034Sdougm 24813034Sdougm for (node = ((xmlNodePtr)share)->children; node != NULL; 24824327Sdougm node = node->next) { 24833034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 24843034Sdougm break; 24853034Sdougm } 24863034Sdougm } 24873034Sdougm /* no existing description but want to add */ 24883034Sdougm if (node == NULL && content != NULL) { 24893034Sdougm /* add a description */ 24904327Sdougm node = _sa_set_share_description(share, content); 24913034Sdougm } else if (node != NULL && content != NULL) { 24923034Sdougm /* update a description */ 24933034Sdougm xmlNodeSetContent(node, (xmlChar *)content); 24943034Sdougm } else if (node != NULL && content == NULL) { 24953034Sdougm /* remove an existing description */ 24963034Sdougm xmlUnlinkNode(node); 24973034Sdougm xmlFreeNode(node); 24983034Sdougm } 24995331Samw group = sa_get_parent_group(share); 25005331Samw if (group != NULL && sa_is_persistent(share)) { 25014327Sdougm sa_handle_impl_t impl_handle; 25024327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 25034327Sdougm if (impl_handle != NULL) { 25044327Sdougm ret = sa_commit_share(impl_handle->scfhandle, group, 25054327Sdougm share); 25064327Sdougm } else { 25074327Sdougm ret = SA_SYSTEM_ERR; 25084327Sdougm } 25093910Sdougm } 25103034Sdougm return (ret); 25113034Sdougm } 25123034Sdougm 25133034Sdougm /* 25143034Sdougm * fixproblemchars(string) 25153034Sdougm * 25163034Sdougm * don't want any newline or tab characters in the text since these 25173034Sdougm * could break display of data and legacy file formats. 25183034Sdougm */ 25193034Sdougm static void 25203034Sdougm fixproblemchars(char *str) 25213034Sdougm { 25223034Sdougm int c; 25233034Sdougm for (c = *str; c != '\0'; c = *++str) { 25244327Sdougm if (c == '\t' || c == '\n') 25254327Sdougm *str = ' '; 25264327Sdougm else if (c == '"') 25274327Sdougm *str = '\''; 25283034Sdougm } 25293034Sdougm } 25303034Sdougm 25313034Sdougm /* 25323034Sdougm * sa_get_share_description(share) 25333034Sdougm * 25343034Sdougm * Return the description text for the specified share if it 25353034Sdougm * exists. NULL if no description exists. 25363034Sdougm */ 25373034Sdougm 25383034Sdougm char * 25393034Sdougm sa_get_share_description(sa_share_t share) 25403034Sdougm { 25413034Sdougm xmlChar *description = NULL; 25423034Sdougm xmlNodePtr node; 25433034Sdougm 25443034Sdougm for (node = ((xmlNodePtr)share)->children; node != NULL; 25454327Sdougm node = node->next) { 25464327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 25474327Sdougm break; 25484327Sdougm } 25493034Sdougm } 25503034Sdougm if (node != NULL) { 25515331Samw description = xmlNodeGetContent(node); 25524327Sdougm fixproblemchars((char *)description); 25533034Sdougm } 25543034Sdougm return ((char *)description); 25553034Sdougm } 25563034Sdougm 25573034Sdougm /* 25583034Sdougm * sa_free(share_description(description) 25593034Sdougm * 25603034Sdougm * Free the description string. 25613034Sdougm */ 25623034Sdougm 25633034Sdougm void 25643034Sdougm sa_free_share_description(char *description) 25653034Sdougm { 25663034Sdougm xmlFree((xmlChar *)description); 25673034Sdougm } 25683034Sdougm 25693034Sdougm /* 25703034Sdougm * sa_create_optionset(group, proto) 25713034Sdougm * 25723034Sdougm * Create an optionset for the specified protocol in the specied 25733034Sdougm * group. This is manifested as a property group within SMF. 25743034Sdougm */ 25753034Sdougm 25763034Sdougm sa_optionset_t 25773034Sdougm sa_create_optionset(sa_group_t group, char *proto) 25783034Sdougm { 25793034Sdougm sa_optionset_t optionset; 25803034Sdougm sa_group_t parent = group; 25815331Samw sa_share_t share = NULL; 25825331Samw int err = SA_OK; 25835331Samw char *id = NULL; 25843034Sdougm 25853034Sdougm optionset = sa_get_optionset(group, proto); 25863034Sdougm if (optionset != NULL) { 25873034Sdougm /* can't have a duplicate protocol */ 25884327Sdougm optionset = NULL; 25893034Sdougm } else { 25905331Samw /* 25915331Samw * Account for resource names being slightly 25925331Samw * different. 25935331Samw */ 25945331Samw if (sa_is_share(group)) { 25955331Samw /* 25965331Samw * Transient shares do not have an "id" so not an 25975331Samw * error to not find one. 25985331Samw */ 25995331Samw id = sa_get_share_attr((sa_share_t)group, "id"); 26005331Samw } else if (sa_is_resource(group)) { 26015331Samw share = sa_get_resource_parent( 26025331Samw (sa_resource_t)group); 26035331Samw id = sa_get_resource_attr(share, "id"); 26045331Samw 26055331Samw /* id can be NULL if the group is transient (ZFS) */ 26065331Samw if (id == NULL && sa_is_persistent(group)) 26075331Samw err = SA_NO_MEMORY; 26085331Samw } 26095331Samw if (err == SA_NO_MEMORY) { 26105331Samw /* 26115331Samw * Couldn't get the id for the share or 26125331Samw * resource. While this could be a 26135331Samw * configuration issue, it is most likely an 26145331Samw * out of memory. In any case, fail the create. 26155331Samw */ 26165331Samw return (NULL); 26175331Samw } 26185331Samw 26194327Sdougm optionset = (sa_optionset_t)xmlNewChild((xmlNodePtr)group, 26204327Sdougm NULL, (xmlChar *)"optionset", NULL); 26213034Sdougm /* 26223034Sdougm * only put to repository if on a group and we were 26233034Sdougm * able to create an optionset. 26243034Sdougm */ 26254327Sdougm if (optionset != NULL) { 26264327Sdougm char oname[SA_STRSIZE]; 26274327Sdougm char *groupname; 26285331Samw 26295331Samw /* 26305331Samw * Need to get parent group in all cases, but also get 26315331Samw * the share if this is a resource. 26325331Samw */ 26335331Samw if (sa_is_share(group)) { 26344327Sdougm parent = sa_get_parent_group((sa_share_t)group); 26355331Samw } else if (sa_is_resource(group)) { 26365331Samw share = sa_get_resource_parent( 26375331Samw (sa_resource_t)group); 26385331Samw parent = sa_get_parent_group(share); 26395331Samw } 26404327Sdougm 26414327Sdougm sa_set_optionset_attr(optionset, "type", proto); 26423034Sdougm 26434327Sdougm (void) sa_optionset_name(optionset, oname, 26444327Sdougm sizeof (oname), id); 26454327Sdougm groupname = sa_get_group_attr(parent, "name"); 26465331Samw if (groupname != NULL && sa_is_persistent(group)) { 26474327Sdougm sa_handle_impl_t impl_handle; 26485331Samw impl_handle = 26495331Samw (sa_handle_impl_t)sa_find_group_handle( 26505331Samw group); 26514327Sdougm assert(impl_handle != NULL); 26524327Sdougm if (impl_handle != NULL) { 26534327Sdougm (void) sa_get_instance( 26545331Samw impl_handle->scfhandle, groupname); 26554327Sdougm (void) sa_create_pgroup( 26564327Sdougm impl_handle->scfhandle, oname); 26574327Sdougm } 26584327Sdougm } 26594327Sdougm if (groupname != NULL) 26604327Sdougm sa_free_attr_string(groupname); 26613034Sdougm } 26623034Sdougm } 26635331Samw 26645331Samw if (id != NULL) 26655331Samw sa_free_attr_string(id); 26663034Sdougm return (optionset); 26673034Sdougm } 26683034Sdougm 26693034Sdougm /* 26703034Sdougm * sa_get_property_parent(property) 26713034Sdougm * 26723034Sdougm * Given a property, return the object it is a property of. This will 26733034Sdougm * be an optionset of some type. 26743034Sdougm */ 26753034Sdougm 26763034Sdougm static sa_optionset_t 26773034Sdougm sa_get_property_parent(sa_property_t property) 26783034Sdougm { 26793034Sdougm xmlNodePtr node = NULL; 26803034Sdougm 26814327Sdougm if (property != NULL) 26824327Sdougm node = ((xmlNodePtr)property)->parent; 26833034Sdougm return ((sa_optionset_t)node); 26843034Sdougm } 26853034Sdougm 26863034Sdougm /* 26873034Sdougm * sa_get_optionset_parent(optionset) 26883034Sdougm * 26893034Sdougm * Return the parent of the specified optionset. This could be a group 26903034Sdougm * or a share. 26913034Sdougm */ 26923034Sdougm 26933034Sdougm static sa_group_t 26943034Sdougm sa_get_optionset_parent(sa_optionset_t optionset) 26953034Sdougm { 26963034Sdougm xmlNodePtr node = NULL; 26973034Sdougm 26984327Sdougm if (optionset != NULL) 26994327Sdougm node = ((xmlNodePtr)optionset)->parent; 27003034Sdougm return ((sa_group_t)node); 27013034Sdougm } 27023034Sdougm 27033034Sdougm /* 27043034Sdougm * zfs_needs_update(share) 27053034Sdougm * 27063034Sdougm * In order to avoid making multiple updates to a ZFS share when 27073034Sdougm * setting properties, the share attribute "changed" will be set to 27085331Samw * true when a property is added or modified. When done adding 27093034Sdougm * properties, we can then detect that an update is needed. We then 27103034Sdougm * clear the state here to detect additional changes. 27113034Sdougm */ 27123034Sdougm 27133034Sdougm static int 27143034Sdougm zfs_needs_update(sa_share_t share) 27153034Sdougm { 27163034Sdougm char *attr; 27173034Sdougm int result = 0; 27183034Sdougm 27193034Sdougm attr = sa_get_share_attr(share, "changed"); 27203034Sdougm if (attr != NULL) { 27214327Sdougm sa_free_attr_string(attr); 27223034Sdougm result = 1; 27233034Sdougm } 27243034Sdougm set_node_attr((void *)share, "changed", NULL); 27253034Sdougm return (result); 27263034Sdougm } 27273034Sdougm 27283034Sdougm /* 27293034Sdougm * zfs_set_update(share) 27303034Sdougm * 27313034Sdougm * Set the changed attribute of the share to true. 27323034Sdougm */ 27333034Sdougm 27343034Sdougm static void 27353034Sdougm zfs_set_update(sa_share_t share) 27363034Sdougm { 27373034Sdougm set_node_attr((void *)share, "changed", "true"); 27383034Sdougm } 27393034Sdougm 27403034Sdougm /* 27413034Sdougm * sa_commit_properties(optionset, clear) 27423034Sdougm * 27433034Sdougm * Check if SMF or ZFS config and either update or abort the pending 27443034Sdougm * changes. 27453034Sdougm */ 27463034Sdougm 27473034Sdougm int 27483034Sdougm sa_commit_properties(sa_optionset_t optionset, int clear) 27493034Sdougm { 27503034Sdougm sa_group_t group; 27513034Sdougm sa_group_t parent; 27523034Sdougm int zfs = 0; 27533034Sdougm int needsupdate = 0; 27543034Sdougm int ret = SA_OK; 27553910Sdougm sa_handle_impl_t impl_handle; 27563034Sdougm 27573034Sdougm group = sa_get_optionset_parent(optionset); 27583034Sdougm if (group != NULL && (sa_is_share(group) || is_zfs_group(group))) { 27594327Sdougm /* only update ZFS if on a share */ 27604327Sdougm parent = sa_get_parent_group(group); 27614327Sdougm zfs++; 27624327Sdougm if (parent != NULL && is_zfs_group(parent)) 27634327Sdougm needsupdate = zfs_needs_update(group); 27644327Sdougm else 27654327Sdougm zfs = 0; 27663034Sdougm } 27673034Sdougm if (zfs) { 27684327Sdougm if (!clear && needsupdate) 27694327Sdougm ret = sa_zfs_update((sa_share_t)group); 27703034Sdougm } else { 27714327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 27724327Sdougm if (impl_handle != NULL) { 27734327Sdougm if (clear) { 27744327Sdougm (void) sa_abort_transaction( 27754327Sdougm impl_handle->scfhandle); 27764327Sdougm } else { 27774327Sdougm ret = sa_end_transaction( 27785951Sdougm impl_handle->scfhandle, impl_handle); 27794327Sdougm } 27804327Sdougm } else { 27814327Sdougm ret = SA_SYSTEM_ERR; 27824327Sdougm } 27833034Sdougm } 27843034Sdougm return (ret); 27853034Sdougm } 27863034Sdougm 27873034Sdougm /* 27883034Sdougm * sa_destroy_optionset(optionset) 27893034Sdougm * 27905331Samw * Remove the optionset from its group. Update the repository to 27913034Sdougm * reflect this change. 27923034Sdougm */ 27933034Sdougm 27943034Sdougm int 27953034Sdougm sa_destroy_optionset(sa_optionset_t optionset) 27963034Sdougm { 27974327Sdougm char name[SA_STRSIZE]; 27983034Sdougm int len; 27993034Sdougm int ret; 28003034Sdougm char *id = NULL; 28013034Sdougm sa_group_t group; 28023034Sdougm int ispersist = 1; 28033034Sdougm 28043034Sdougm /* now delete the prop group */ 28053034Sdougm group = sa_get_optionset_parent(optionset); 28065331Samw if (group != NULL) { 28075331Samw if (sa_is_resource(group)) { 28085331Samw sa_resource_t resource = group; 28095331Samw sa_share_t share = sa_get_resource_parent(resource); 28105331Samw group = sa_get_parent_group(share); 28115331Samw id = sa_get_share_attr(share, "id"); 28125331Samw } else if (sa_is_share(group)) { 28135331Samw id = sa_get_share_attr((sa_share_t)group, "id"); 28145331Samw } 28155331Samw ispersist = sa_is_persistent(group); 28163034Sdougm } 28173034Sdougm if (ispersist) { 28184327Sdougm sa_handle_impl_t impl_handle; 28194327Sdougm len = sa_optionset_name(optionset, name, sizeof (name), id); 28204327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 28214327Sdougm if (impl_handle != NULL) { 28224327Sdougm if (len > 0) { 28234327Sdougm ret = sa_delete_pgroup(impl_handle->scfhandle, 28244327Sdougm name); 28254327Sdougm } 28264327Sdougm } else { 28274327Sdougm ret = SA_SYSTEM_ERR; 28283910Sdougm } 28293034Sdougm } 28303034Sdougm xmlUnlinkNode((xmlNodePtr)optionset); 28313034Sdougm xmlFreeNode((xmlNodePtr)optionset); 28323034Sdougm if (id != NULL) 28334327Sdougm sa_free_attr_string(id); 28343034Sdougm return (ret); 28353034Sdougm } 28363034Sdougm 28373034Sdougm /* private to the implementation */ 28383034Sdougm int 28393034Sdougm _sa_remove_optionset(sa_optionset_t optionset) 28403034Sdougm { 28413034Sdougm int ret = SA_OK; 28423034Sdougm 28433034Sdougm xmlUnlinkNode((xmlNodePtr)optionset); 28443034Sdougm xmlFreeNode((xmlNodePtr)optionset); 28453034Sdougm return (ret); 28463034Sdougm } 28473034Sdougm 28483034Sdougm /* 28493034Sdougm * sa_create_security(group, sectype, proto) 28503034Sdougm * 28513034Sdougm * Create a security optionset (one that has a type name and a 28523034Sdougm * proto). Security is left over from a pure NFS implementation. The 28533034Sdougm * naming will change in the future when the API is released. 28543034Sdougm */ 28553034Sdougm sa_security_t 28563034Sdougm sa_create_security(sa_group_t group, char *sectype, char *proto) 28573034Sdougm { 28583034Sdougm sa_security_t security; 28593034Sdougm char *id = NULL; 28603034Sdougm sa_group_t parent; 28613034Sdougm char *groupname = NULL; 28623034Sdougm 28633034Sdougm if (group != NULL && sa_is_share(group)) { 28644327Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 28654327Sdougm parent = sa_get_parent_group(group); 28664327Sdougm if (parent != NULL) 28674327Sdougm groupname = sa_get_group_attr(parent, "name"); 28683034Sdougm } else if (group != NULL) { 28694327Sdougm groupname = sa_get_group_attr(group, "name"); 28703034Sdougm } 28713034Sdougm 28723034Sdougm security = sa_get_security(group, sectype, proto); 28733034Sdougm if (security != NULL) { 28743034Sdougm /* can't have a duplicate security option */ 28753034Sdougm security = NULL; 28763034Sdougm } else { 28773034Sdougm security = (sa_security_t)xmlNewChild((xmlNodePtr)group, 28784327Sdougm NULL, (xmlChar *)"security", NULL); 28793034Sdougm if (security != NULL) { 28804327Sdougm char oname[SA_STRSIZE]; 28813034Sdougm sa_set_security_attr(security, "type", proto); 28823034Sdougm 28833034Sdougm sa_set_security_attr(security, "sectype", sectype); 28843034Sdougm (void) sa_security_name(security, oname, 28854327Sdougm sizeof (oname), id); 28865331Samw if (groupname != NULL && sa_is_persistent(group)) { 28874327Sdougm sa_handle_impl_t impl_handle; 28884327Sdougm impl_handle = 28894327Sdougm (sa_handle_impl_t)sa_find_group_handle( 28904327Sdougm group); 28914327Sdougm if (impl_handle != NULL) { 28924327Sdougm (void) sa_get_instance( 28934327Sdougm impl_handle->scfhandle, groupname); 28944327Sdougm (void) sa_create_pgroup( 28954327Sdougm impl_handle->scfhandle, oname); 28964327Sdougm } 28973034Sdougm } 28983034Sdougm } 28993034Sdougm } 29003034Sdougm if (groupname != NULL) 29014327Sdougm sa_free_attr_string(groupname); 29023034Sdougm return (security); 29033034Sdougm } 29043034Sdougm 29053034Sdougm /* 29063034Sdougm * sa_destroy_security(security) 29073034Sdougm * 29083034Sdougm * Remove the specified optionset from the document and the 29093034Sdougm * configuration. 29103034Sdougm */ 29113034Sdougm 29123034Sdougm int 29133034Sdougm sa_destroy_security(sa_security_t security) 29143034Sdougm { 29154327Sdougm char name[SA_STRSIZE]; 29163034Sdougm int len; 29173034Sdougm int ret = SA_OK; 29183034Sdougm char *id = NULL; 29193034Sdougm sa_group_t group; 29203034Sdougm int iszfs = 0; 29213034Sdougm int ispersist = 1; 29223034Sdougm 29233034Sdougm group = sa_get_optionset_parent(security); 29243034Sdougm 29253034Sdougm if (group != NULL) 29264327Sdougm iszfs = sa_group_is_zfs(group); 29273034Sdougm 29283034Sdougm if (group != NULL && !iszfs) { 29294327Sdougm if (sa_is_share(group)) 29305331Samw ispersist = sa_is_persistent(group); 29314327Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 29323034Sdougm } 29333034Sdougm if (ispersist) { 29344327Sdougm len = sa_security_name(security, name, sizeof (name), id); 29354327Sdougm if (!iszfs && len > 0) { 29364327Sdougm sa_handle_impl_t impl_handle; 29374327Sdougm impl_handle = 29384327Sdougm (sa_handle_impl_t)sa_find_group_handle(group); 29394327Sdougm if (impl_handle != NULL) { 29404327Sdougm ret = sa_delete_pgroup(impl_handle->scfhandle, 29414327Sdougm name); 29424327Sdougm } else { 29434327Sdougm ret = SA_SYSTEM_ERR; 29444327Sdougm } 29453910Sdougm } 29463034Sdougm } 29473034Sdougm xmlUnlinkNode((xmlNodePtr)security); 29483034Sdougm xmlFreeNode((xmlNodePtr)security); 29494327Sdougm if (iszfs) 29504327Sdougm ret = sa_zfs_update(group); 29513034Sdougm if (id != NULL) 29524327Sdougm sa_free_attr_string(id); 29533034Sdougm return (ret); 29543034Sdougm } 29553034Sdougm 29563034Sdougm /* 29573034Sdougm * sa_get_security_attr(optionset, tag) 29583034Sdougm * 29593034Sdougm * Return the specified attribute value from the optionset. 29603034Sdougm */ 29613034Sdougm 29623034Sdougm char * 29633034Sdougm sa_get_security_attr(sa_property_t optionset, char *tag) 29643034Sdougm { 29653034Sdougm return (get_node_attr((void *)optionset, tag)); 29663034Sdougm 29673034Sdougm } 29683034Sdougm 29693034Sdougm /* 29703034Sdougm * sa_set_security_attr(optionset, tag, value) 29713034Sdougm * 29723034Sdougm * Set the optioset attribute specied by tag to the specified value. 29733034Sdougm */ 29743034Sdougm 29753034Sdougm void 29763034Sdougm sa_set_security_attr(sa_group_t optionset, char *tag, char *value) 29773034Sdougm { 29783034Sdougm set_node_attr((void *)optionset, tag, value); 29793034Sdougm } 29803034Sdougm 29813034Sdougm /* 29823034Sdougm * is_nodetype(node, type) 29833034Sdougm * 29843034Sdougm * Check to see if node is of the type specified. 29853034Sdougm */ 29863034Sdougm 29873034Sdougm static int 29883034Sdougm is_nodetype(void *node, char *type) 29893034Sdougm { 29903034Sdougm return (strcmp((char *)((xmlNodePtr)node)->name, type) == 0); 29913034Sdougm } 29923034Sdougm 29934327Sdougm /* 29944327Sdougm * add_or_update() 29954327Sdougm * 29964327Sdougm * Add or update a property. Pulled out of sa_set_prop_by_prop for 29974327Sdougm * readability. 29984327Sdougm */ 29994327Sdougm static int 30004327Sdougm add_or_update(scfutilhandle_t *scf_handle, int type, scf_value_t *value, 30014327Sdougm scf_transaction_entry_t *entry, char *name, char *valstr) 30024327Sdougm { 30034327Sdougm int ret = SA_SYSTEM_ERR; 30044327Sdougm 30054327Sdougm if (value != NULL) { 30064327Sdougm if (type == SA_PROP_OP_ADD) 30074327Sdougm ret = scf_transaction_property_new(scf_handle->trans, 30084327Sdougm entry, name, SCF_TYPE_ASTRING); 30094327Sdougm else 30104327Sdougm ret = scf_transaction_property_change(scf_handle->trans, 30114327Sdougm entry, name, SCF_TYPE_ASTRING); 30124327Sdougm if (ret == 0) { 30134327Sdougm ret = scf_value_set_astring(value, valstr); 30144327Sdougm if (ret == 0) 30154327Sdougm ret = scf_entry_add_value(entry, value); 30164327Sdougm if (ret == 0) 30174327Sdougm return (ret); 30184327Sdougm scf_value_destroy(value); 30194327Sdougm } else { 30204327Sdougm scf_entry_destroy(entry); 30214327Sdougm } 30224327Sdougm } 30234327Sdougm return (SA_SYSTEM_ERR); 30244327Sdougm } 30254327Sdougm 30263034Sdougm /* 30273034Sdougm * sa_set_prop_by_prop(optionset, group, prop, type) 30283034Sdougm * 30293034Sdougm * Add/remove/update the specified property prop into the optionset or 30303034Sdougm * share. If a share, sort out which property group based on GUID. In 30313034Sdougm * all cases, the appropriate transaction is set (or ZFS share is 30323034Sdougm * marked as needing an update) 30333034Sdougm */ 30343034Sdougm 30353034Sdougm static int 30363034Sdougm sa_set_prop_by_prop(sa_optionset_t optionset, sa_group_t group, 30373034Sdougm sa_property_t prop, int type) 30383034Sdougm { 30393034Sdougm char *name; 30403034Sdougm char *valstr; 30413034Sdougm int ret = SA_OK; 30423034Sdougm scf_transaction_entry_t *entry; 30433034Sdougm scf_value_t *value; 30443034Sdougm int opttype; /* 1 == optionset, 0 == security */ 30453034Sdougm char *id = NULL; 30463034Sdougm int iszfs = 0; 30473034Sdougm sa_group_t parent = NULL; 30485331Samw sa_share_t share = NULL; 30493910Sdougm sa_handle_impl_t impl_handle; 30503910Sdougm scfutilhandle_t *scf_handle; 30513034Sdougm 30525331Samw if (!sa_is_persistent(group)) { 30533034Sdougm /* 30543034Sdougm * if the group/share is not persistent we don't need 30553034Sdougm * to do anything here 30563034Sdougm */ 30574327Sdougm return (SA_OK); 30583034Sdougm } 30593910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 30604327Sdougm if (impl_handle == NULL || impl_handle->scfhandle == NULL) 30614327Sdougm return (SA_SYSTEM_ERR); 30623910Sdougm scf_handle = impl_handle->scfhandle; 30633034Sdougm name = sa_get_property_attr(prop, "type"); 30643034Sdougm valstr = sa_get_property_attr(prop, "value"); 30653034Sdougm entry = scf_entry_create(scf_handle->handle); 30663034Sdougm opttype = is_nodetype((void *)optionset, "optionset"); 30673034Sdougm 30685331Samw /* 30695331Samw * Check for share vs. resource since they need slightly 30705331Samw * different treatment given the hierarchy. 30715331Samw */ 30723034Sdougm if (valstr != NULL && entry != NULL) { 30734327Sdougm if (sa_is_share(group)) { 30744327Sdougm parent = sa_get_parent_group(group); 30755331Samw share = (sa_share_t)group; 30764327Sdougm if (parent != NULL) 30774327Sdougm iszfs = is_zfs_group(parent); 30785331Samw } else if (sa_is_resource(group)) { 30795331Samw share = sa_get_parent_group(group); 30805331Samw if (share != NULL) 30815331Samw parent = sa_get_parent_group(share); 30824327Sdougm } else { 30834327Sdougm iszfs = is_zfs_group(group); 30843034Sdougm } 30854327Sdougm if (!iszfs) { 30864327Sdougm if (scf_handle->trans == NULL) { 30874327Sdougm char oname[SA_STRSIZE]; 30884327Sdougm char *groupname = NULL; 30895331Samw if (share != NULL) { 30905331Samw if (parent != NULL) 30914327Sdougm groupname = 30924327Sdougm sa_get_group_attr(parent, 30934327Sdougm "name"); 30945331Samw id = sa_get_share_attr( 30955331Samw (sa_share_t)share, "id"); 30964327Sdougm } else { 30974327Sdougm groupname = sa_get_group_attr(group, 30984327Sdougm "name"); 30994327Sdougm } 31004327Sdougm if (groupname != NULL) { 31014327Sdougm ret = sa_get_instance(scf_handle, 31024327Sdougm groupname); 31034327Sdougm sa_free_attr_string(groupname); 31044327Sdougm } 31054327Sdougm if (opttype) 31064327Sdougm (void) sa_optionset_name(optionset, 31074327Sdougm oname, sizeof (oname), id); 31084327Sdougm else 31094327Sdougm (void) sa_security_name(optionset, 31104327Sdougm oname, sizeof (oname), id); 31114327Sdougm ret = sa_start_transaction(scf_handle, oname); 31123910Sdougm } 31134327Sdougm if (ret == SA_OK) { 31144327Sdougm switch (type) { 31154327Sdougm case SA_PROP_OP_REMOVE: 31164327Sdougm ret = scf_transaction_property_delete( 31174327Sdougm scf_handle->trans, entry, name); 31184327Sdougm break; 31194327Sdougm case SA_PROP_OP_ADD: 31204327Sdougm case SA_PROP_OP_UPDATE: 31214327Sdougm value = scf_value_create( 31224327Sdougm scf_handle->handle); 31234327Sdougm ret = add_or_update(scf_handle, type, 31244327Sdougm value, entry, name, valstr); 31254327Sdougm break; 31263034Sdougm } 31273034Sdougm } 31284327Sdougm } else { 31294327Sdougm /* 31304327Sdougm * ZFS update. The calling function would have updated 31314327Sdougm * the internal XML structure. Just need to flag it as 31324327Sdougm * changed for ZFS. 31334327Sdougm */ 31344327Sdougm zfs_set_update((sa_share_t)group); 31354327Sdougm } 31363034Sdougm } 31373034Sdougm 31383034Sdougm if (name != NULL) 31394327Sdougm sa_free_attr_string(name); 31403034Sdougm if (valstr != NULL) 31414327Sdougm sa_free_attr_string(valstr); 31423034Sdougm else if (entry != NULL) 31434327Sdougm scf_entry_destroy(entry); 31443034Sdougm 31453034Sdougm if (ret == -1) 31464327Sdougm ret = SA_SYSTEM_ERR; 31473034Sdougm 31483034Sdougm return (ret); 31493034Sdougm } 31503034Sdougm 31513034Sdougm /* 31526007Sthurlow * sa_create_section(name, value) 31536007Sthurlow * 31546007Sthurlow * Create a new section with the specified name and extra data. 31556007Sthurlow */ 31566007Sthurlow 31576007Sthurlow sa_property_t 31586007Sthurlow sa_create_section(char *name, char *extra) 31596007Sthurlow { 31606007Sthurlow xmlNodePtr node; 31616007Sthurlow 31626007Sthurlow node = xmlNewNode(NULL, (xmlChar *)"section"); 31636007Sthurlow if (node != NULL) { 31646007Sthurlow if (name != NULL) 31656007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 31666007Sthurlow (xmlChar *)name); 31676007Sthurlow if (extra != NULL) 31686007Sthurlow (void) xmlSetProp(node, (xmlChar *)"extra", 31696007Sthurlow (xmlChar *)extra); 31706007Sthurlow } 31716007Sthurlow return ((sa_property_t)node); 31726007Sthurlow } 31736007Sthurlow 31746007Sthurlow void 31756007Sthurlow sa_set_section_attr(sa_property_t sect, char *name, char *value) 31766007Sthurlow { 31776007Sthurlow (void) xmlSetProp(sect, (xmlChar *)name, (xmlChar *)value); 31786007Sthurlow } 31796007Sthurlow 31806007Sthurlow /* 31816007Sthurlow * sa_create_property(section, name, value) 31823034Sdougm * 31833034Sdougm * Create a new property with the specified name and value. 31843034Sdougm */ 31853034Sdougm 31863034Sdougm sa_property_t 31873034Sdougm sa_create_property(char *name, char *value) 31883034Sdougm { 31893034Sdougm xmlNodePtr node; 31903034Sdougm 31913034Sdougm node = xmlNewNode(NULL, (xmlChar *)"option"); 31923034Sdougm if (node != NULL) { 31936007Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", (xmlChar *)name); 31946007Sthurlow (void) xmlSetProp(node, (xmlChar *)"value", (xmlChar *)value); 31953034Sdougm } 31963034Sdougm return ((sa_property_t)node); 31973034Sdougm } 31983034Sdougm 31993034Sdougm /* 32003034Sdougm * sa_add_property(object, property) 32013034Sdougm * 32023034Sdougm * Add the specified property to the object. Issue the appropriate 32033034Sdougm * transaction or mark a ZFS object as needing an update. 32043034Sdougm */ 32053034Sdougm 32063034Sdougm int 32073034Sdougm sa_add_property(void *object, sa_property_t property) 32083034Sdougm { 32093034Sdougm int ret = SA_OK; 32103034Sdougm sa_group_t parent; 32113034Sdougm sa_group_t group; 32123034Sdougm char *proto; 32136214Sdougm 32143034Sdougm if (property != NULL) { 32156271Sdougm sa_handle_t handle; 32166214Sdougm handle = sa_find_group_handle((sa_group_t)object); 32176271Sdougm /* It is legitimate to not find a handle */ 32186214Sdougm proto = sa_get_optionset_attr(object, "type"); 32196214Sdougm if ((ret = sa_valid_property(handle, object, proto, 32206214Sdougm property)) == SA_OK) { 32214327Sdougm property = (sa_property_t)xmlAddChild( 32224327Sdougm (xmlNodePtr)object, (xmlNodePtr)property); 32234327Sdougm } else { 32244327Sdougm if (proto != NULL) 32254327Sdougm sa_free_attr_string(proto); 32264327Sdougm return (ret); 32274327Sdougm } 32286214Sdougm if (proto != NULL) 32296214Sdougm sa_free_attr_string(proto); 32303034Sdougm } 32313034Sdougm 32323034Sdougm 32333034Sdougm parent = sa_get_parent_group(object); 32345331Samw if (!sa_is_persistent(parent)) 32354327Sdougm return (ret); 32365331Samw 32375331Samw if (sa_is_resource(parent)) { 32385331Samw /* 32395331Samw * Resources are children of share. Need to go up two 32405331Samw * levels to find the group but the parent needs to be 32415331Samw * the share at this point in order to get the "id". 32425331Samw */ 32435331Samw parent = sa_get_parent_group(parent); 32445331Samw group = sa_get_parent_group(parent); 32455331Samw } else if (sa_is_share(parent)) { 32465331Samw group = sa_get_parent_group(parent); 32475331Samw } else { 32485331Samw group = parent; 32493034Sdougm } 32503034Sdougm 32514327Sdougm if (property == NULL) { 32524327Sdougm ret = SA_NO_MEMORY; 32534327Sdougm } else { 32544327Sdougm char oname[SA_STRSIZE]; 32553034Sdougm 32564327Sdougm if (!is_zfs_group(group)) { 32574327Sdougm char *id = NULL; 32584327Sdougm sa_handle_impl_t impl_handle; 32594327Sdougm scfutilhandle_t *scf_handle; 32603910Sdougm 32614327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle( 32624327Sdougm group); 32634327Sdougm if (impl_handle == NULL || 32644327Sdougm impl_handle->scfhandle == NULL) 32654327Sdougm ret = SA_SYSTEM_ERR; 32664327Sdougm if (ret == SA_OK) { 32674327Sdougm scf_handle = impl_handle->scfhandle; 32684327Sdougm if (sa_is_share((sa_group_t)parent)) { 32694327Sdougm id = sa_get_share_attr( 32704327Sdougm (sa_share_t)parent, "id"); 32714327Sdougm } 32724327Sdougm if (scf_handle->trans == NULL) { 32734327Sdougm if (is_nodetype(object, "optionset")) { 32744327Sdougm (void) sa_optionset_name( 32754327Sdougm (sa_optionset_t)object, 32764327Sdougm oname, sizeof (oname), id); 32774327Sdougm } else { 32784327Sdougm (void) sa_security_name( 32794327Sdougm (sa_optionset_t)object, 32804327Sdougm oname, sizeof (oname), id); 32814327Sdougm } 32824327Sdougm ret = sa_start_transaction(scf_handle, 32834327Sdougm oname); 32844327Sdougm } 32854327Sdougm if (ret == SA_OK) { 32864327Sdougm char *name; 32874327Sdougm char *value; 32884327Sdougm name = sa_get_property_attr(property, 32894327Sdougm "type"); 32904327Sdougm value = sa_get_property_attr(property, 32914327Sdougm "value"); 32924327Sdougm if (name != NULL && value != NULL) { 32934327Sdougm if (scf_handle->scf_state == 32944327Sdougm SCH_STATE_INIT) { 32954327Sdougm ret = sa_set_property( 32964327Sdougm scf_handle, name, 32974327Sdougm value); 32984327Sdougm } 32994327Sdougm } else { 33004327Sdougm ret = SA_CONFIG_ERR; 33014327Sdougm } 33024327Sdougm if (name != NULL) 33034327Sdougm sa_free_attr_string( 33044327Sdougm name); 33054327Sdougm if (value != NULL) 33064327Sdougm sa_free_attr_string(value); 33074327Sdougm } 33084327Sdougm if (id != NULL) 33094327Sdougm sa_free_attr_string(id); 33104327Sdougm } 33114327Sdougm } else { 33124327Sdougm /* 33134327Sdougm * ZFS is a special case. We do want 33144327Sdougm * to allow editing property/security 33154327Sdougm * lists since we can have a better 33164327Sdougm * syntax and we also want to keep 33174327Sdougm * things consistent when possible. 33184327Sdougm * 33194327Sdougm * Right now, we defer until the 33204327Sdougm * sa_commit_properties so we can get 33214327Sdougm * them all at once. We do need to 33224327Sdougm * mark the share as "changed" 33234327Sdougm */ 33244327Sdougm zfs_set_update((sa_share_t)parent); 33253034Sdougm } 33263034Sdougm } 33273034Sdougm return (ret); 33283034Sdougm } 33293034Sdougm 33303034Sdougm /* 33313034Sdougm * sa_remove_property(property) 33323034Sdougm * 33333034Sdougm * Remove the specied property from its containing object. Update the 33343034Sdougm * repository as appropriate. 33353034Sdougm */ 33363034Sdougm 33373034Sdougm int 33383034Sdougm sa_remove_property(sa_property_t property) 33393034Sdougm { 33403034Sdougm int ret = SA_OK; 33413034Sdougm 33423034Sdougm if (property != NULL) { 33433034Sdougm sa_optionset_t optionset; 33443034Sdougm sa_group_t group; 33453034Sdougm optionset = sa_get_property_parent(property); 33463034Sdougm if (optionset != NULL) { 33474327Sdougm group = sa_get_optionset_parent(optionset); 33484327Sdougm if (group != NULL) { 33494327Sdougm ret = sa_set_prop_by_prop(optionset, group, 33504327Sdougm property, SA_PROP_OP_REMOVE); 33514327Sdougm } 33523034Sdougm } 33533034Sdougm xmlUnlinkNode((xmlNodePtr)property); 33543034Sdougm xmlFreeNode((xmlNodePtr)property); 33553034Sdougm } else { 33564327Sdougm ret = SA_NO_SUCH_PROP; 33573034Sdougm } 33583034Sdougm return (ret); 33593034Sdougm } 33603034Sdougm 33613034Sdougm /* 33623034Sdougm * sa_update_property(property, value) 33633034Sdougm * 33643034Sdougm * Update the specified property to the new value. If value is NULL, 33653034Sdougm * we currently treat this as a remove. 33663034Sdougm */ 33673034Sdougm 33683034Sdougm int 33693034Sdougm sa_update_property(sa_property_t property, char *value) 33703034Sdougm { 33713034Sdougm int ret = SA_OK; 33723034Sdougm if (value == NULL) { 33733034Sdougm return (sa_remove_property(property)); 33743034Sdougm } else { 33753034Sdougm sa_optionset_t optionset; 33763034Sdougm sa_group_t group; 33773034Sdougm set_node_attr((void *)property, "value", value); 33783034Sdougm optionset = sa_get_property_parent(property); 33793034Sdougm if (optionset != NULL) { 33804327Sdougm group = sa_get_optionset_parent(optionset); 33814327Sdougm if (group != NULL) { 33824327Sdougm ret = sa_set_prop_by_prop(optionset, group, 33834327Sdougm property, SA_PROP_OP_UPDATE); 33844327Sdougm } 33853034Sdougm } else { 33864327Sdougm ret = SA_NO_SUCH_PROP; 33873034Sdougm } 33883034Sdougm } 33893034Sdougm return (ret); 33903034Sdougm } 33913034Sdougm 33923034Sdougm /* 33936007Sthurlow * sa_get_protocol_section(propset, prop) 33946007Sthurlow * 33956007Sthurlow * Get the specified protocol specific section. These are global to 33966007Sthurlow * the protocol and not specific to a group or share. 33976007Sthurlow */ 33986007Sthurlow 33996007Sthurlow sa_protocol_properties_t 34006007Sthurlow sa_get_protocol_section(sa_protocol_properties_t propset, char *section) 34016007Sthurlow { 34026007Sthurlow xmlNodePtr node = (xmlNodePtr)propset; 34036007Sthurlow xmlChar *value = NULL; 34046007Sthurlow char *proto; 34056007Sthurlow 34066007Sthurlow proto = sa_get_optionset_attr(propset, "type"); 34076007Sthurlow if ((sa_proto_get_featureset(proto) & SA_FEATURE_HAS_SECTIONS) == 0) 34086007Sthurlow return (propset); 34096007Sthurlow 34106007Sthurlow for (node = node->children; node != NULL; 34116007Sthurlow node = node->next) { 34126007Sthurlow if (xmlStrcmp(node->name, (xmlChar *)"section") == 0) { 34136007Sthurlow if (section == NULL) 34146007Sthurlow break; 34156007Sthurlow value = xmlGetProp(node, (xmlChar *)"name"); 34166007Sthurlow if (value != NULL && 34176007Sthurlow xmlStrcasecmp(value, (xmlChar *)section) == 0) { 34186007Sthurlow break; 34196007Sthurlow } 34206007Sthurlow if (value != NULL) { 34216007Sthurlow xmlFree(value); 34226007Sthurlow value = NULL; 34236007Sthurlow } 34246007Sthurlow } 34256007Sthurlow } 34266007Sthurlow if (value != NULL) 34276007Sthurlow xmlFree(value); 34286007Sthurlow if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"section") != 0) { 34296007Sthurlow /* 34306007Sthurlow * avoid a non option node -- it is possible to be a 34316007Sthurlow * text node 34326007Sthurlow */ 34336007Sthurlow node = NULL; 34346007Sthurlow } 34356007Sthurlow return ((sa_protocol_properties_t)node); 34366007Sthurlow } 34376007Sthurlow 34386007Sthurlow /* 34396007Sthurlow * sa_get_next_protocol_section(prop, find) 34406007Sthurlow * 34416007Sthurlow * Get the next protocol specific section in the list. 34426007Sthurlow */ 34436007Sthurlow 34446007Sthurlow sa_property_t 34456007Sthurlow sa_get_next_protocol_section(sa_property_t prop, char *find) 34466007Sthurlow { 34476007Sthurlow xmlNodePtr node; 34486007Sthurlow xmlChar *value = NULL; 34496007Sthurlow char *proto; 34506007Sthurlow 34516007Sthurlow proto = sa_get_optionset_attr(prop, "type"); 34526007Sthurlow if ((sa_proto_get_featureset(proto) & SA_FEATURE_HAS_SECTIONS) == 0) 34536007Sthurlow return ((sa_property_t)NULL); 34546007Sthurlow 34556007Sthurlow for (node = ((xmlNodePtr)prop)->next; node != NULL; 34566007Sthurlow node = node->next) { 34576007Sthurlow if (xmlStrcmp(node->name, (xmlChar *)"section") == 0) { 34586007Sthurlow if (find == NULL) 34596007Sthurlow break; 34606007Sthurlow value = xmlGetProp(node, (xmlChar *)"name"); 34616007Sthurlow if (value != NULL && 34626007Sthurlow xmlStrcasecmp(value, (xmlChar *)find) == 0) { 34636007Sthurlow break; 34646007Sthurlow } 34656007Sthurlow if (value != NULL) { 34666007Sthurlow xmlFree(value); 34676007Sthurlow value = NULL; 34686007Sthurlow } 34696007Sthurlow 34706007Sthurlow } 34716007Sthurlow } 34726007Sthurlow if (value != NULL) 34736007Sthurlow xmlFree(value); 34746007Sthurlow return ((sa_property_t)node); 34756007Sthurlow } 34766007Sthurlow 34776007Sthurlow /* 34783034Sdougm * sa_get_protocol_property(propset, prop) 34793034Sdougm * 34803034Sdougm * Get the specified protocol specific property. These are global to 34813034Sdougm * the protocol and not specific to a group or share. 34823034Sdougm */ 34833034Sdougm 34843034Sdougm sa_property_t 34853034Sdougm sa_get_protocol_property(sa_protocol_properties_t propset, char *prop) 34863034Sdougm { 34873034Sdougm xmlNodePtr node = (xmlNodePtr)propset; 34883034Sdougm xmlChar *value = NULL; 34893034Sdougm 34906007Sthurlow if (propset == NULL) 34916007Sthurlow return (NULL); 34926007Sthurlow 34933034Sdougm for (node = node->children; node != NULL; 34944327Sdougm node = node->next) { 34954327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 34964327Sdougm if (prop == NULL) 34974327Sdougm break; 34984327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 34994327Sdougm if (value != NULL && 35004327Sdougm xmlStrcasecmp(value, (xmlChar *)prop) == 0) { 35014327Sdougm break; 35024327Sdougm } 35034327Sdougm if (value != NULL) { 35044327Sdougm xmlFree(value); 35054327Sdougm value = NULL; 35064327Sdougm } 35073034Sdougm } 35083034Sdougm } 35093034Sdougm if (value != NULL) 35103034Sdougm xmlFree(value); 35113034Sdougm if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"option") != 0) { 35124327Sdougm /* 35134327Sdougm * avoid a non option node -- it is possible to be a 35144327Sdougm * text node 35154327Sdougm */ 35164327Sdougm node = NULL; 35173034Sdougm } 35183034Sdougm return ((sa_property_t)node); 35193034Sdougm } 35203034Sdougm 35213034Sdougm /* 35223034Sdougm * sa_get_next_protocol_property(prop) 35233034Sdougm * 35243034Sdougm * Get the next protocol specific property in the list. 35253034Sdougm */ 35263034Sdougm 35273034Sdougm sa_property_t 35286007Sthurlow sa_get_next_protocol_property(sa_property_t prop, char *find) 35293034Sdougm { 35303034Sdougm xmlNodePtr node; 35316007Sthurlow xmlChar *value = NULL; 35323034Sdougm 35333034Sdougm for (node = ((xmlNodePtr)prop)->next; node != NULL; 35344327Sdougm node = node->next) { 35353034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 35366007Sthurlow if (find == NULL) 35376007Sthurlow break; 35386007Sthurlow value = xmlGetProp(node, (xmlChar *)"type"); 35396007Sthurlow if (value != NULL && 35406007Sthurlow xmlStrcasecmp(value, (xmlChar *)find) == 0) { 35416007Sthurlow break; 35426007Sthurlow } 35436007Sthurlow if (value != NULL) { 35446007Sthurlow xmlFree(value); 35456007Sthurlow value = NULL; 35466007Sthurlow } 35476007Sthurlow 35483034Sdougm } 35493034Sdougm } 35506007Sthurlow if (value != NULL) 35516007Sthurlow xmlFree(value); 35523034Sdougm return ((sa_property_t)node); 35533034Sdougm } 35543034Sdougm 35553034Sdougm /* 35563034Sdougm * sa_set_protocol_property(prop, value) 35573034Sdougm * 35583034Sdougm * Set the specified property to have the new value. The protocol 35593034Sdougm * specific plugin will then be called to update the property. 35603034Sdougm */ 35613034Sdougm 35623034Sdougm int 35636007Sthurlow sa_set_protocol_property(sa_property_t prop, char *section, char *value) 35643034Sdougm { 35653034Sdougm sa_protocol_properties_t propset; 35663034Sdougm char *proto; 35673034Sdougm int ret = SA_INVALID_PROTOCOL; 35683034Sdougm 35693034Sdougm propset = ((xmlNodePtr)prop)->parent; 35703034Sdougm if (propset != NULL) { 35714327Sdougm proto = sa_get_optionset_attr(propset, "type"); 35724327Sdougm if (proto != NULL) { 35736007Sthurlow if (section != NULL) 35746007Sthurlow set_node_attr((xmlNodePtr)prop, "section", 35756007Sthurlow section); 35764327Sdougm set_node_attr((xmlNodePtr)prop, "value", value); 35774327Sdougm ret = sa_proto_set_property(proto, prop); 35784327Sdougm sa_free_attr_string(proto); 35794327Sdougm } 35803034Sdougm } 35813034Sdougm return (ret); 35823034Sdougm } 35833034Sdougm 35843034Sdougm /* 35853034Sdougm * sa_add_protocol_property(propset, prop) 35863034Sdougm * 35875331Samw * Add a new property to the protocol specific property set. 35883034Sdougm */ 35893034Sdougm 35903034Sdougm int 35913034Sdougm sa_add_protocol_property(sa_protocol_properties_t propset, sa_property_t prop) 35923034Sdougm { 35933034Sdougm xmlNodePtr node; 35943034Sdougm 35953034Sdougm /* should check for legitimacy */ 35963034Sdougm node = xmlAddChild((xmlNodePtr)propset, (xmlNodePtr)prop); 35973034Sdougm if (node != NULL) 35984327Sdougm return (SA_OK); 35993034Sdougm return (SA_NO_MEMORY); 36003034Sdougm } 36013034Sdougm 36023034Sdougm /* 36033034Sdougm * sa_create_protocol_properties(proto) 36043034Sdougm * 36055331Samw * Create a protocol specific property set. 36063034Sdougm */ 36073034Sdougm 36083034Sdougm sa_protocol_properties_t 36093034Sdougm sa_create_protocol_properties(char *proto) 36103034Sdougm { 36113034Sdougm xmlNodePtr node; 36124327Sdougm 36133034Sdougm node = xmlNewNode(NULL, (xmlChar *)"propertyset"); 36144327Sdougm if (node != NULL) 36156007Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto); 36163034Sdougm return (node); 36173034Sdougm } 36185331Samw 36195331Samw /* 36205331Samw * sa_get_share_resource(share, resource) 36215331Samw * 36225331Samw * Get the named resource from the share, if it exists. If resource is 36235331Samw * NULL, get the first resource. 36245331Samw */ 36255331Samw 36265331Samw sa_resource_t 36275331Samw sa_get_share_resource(sa_share_t share, char *resource) 36285331Samw { 36295331Samw xmlNodePtr node = NULL; 36305331Samw xmlChar *name; 36315331Samw 36325331Samw if (share != NULL) { 36335331Samw for (node = ((xmlNodePtr)share)->children; node != NULL; 36345331Samw node = node->next) { 36355331Samw if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0) { 36365331Samw if (resource == NULL) { 36375331Samw /* 36385331Samw * We are looking for the first 36395331Samw * resource node and not a names 36405331Samw * resource. 36415331Samw */ 36425331Samw break; 36435331Samw } else { 36445331Samw /* is it the correct share? */ 36455331Samw name = xmlGetProp(node, 36465331Samw (xmlChar *)"name"); 36475331Samw if (name != NULL && 36485331Samw xmlStrcasecmp(name, 36495331Samw (xmlChar *)resource) == 0) { 36505331Samw xmlFree(name); 36515331Samw break; 36525331Samw } 36535331Samw xmlFree(name); 36545331Samw } 36555331Samw } 36565331Samw } 36575331Samw } 36585331Samw return ((sa_resource_t)node); 36595331Samw } 36605331Samw 36615331Samw /* 36625331Samw * sa_get_next_resource(resource) 36635331Samw * Return the next share following the specified share 36645331Samw * from the internal list of shares. Returns NULL if there 36655331Samw * are no more shares. The list is relative to the same 36665331Samw * group. 36675331Samw */ 36685331Samw sa_share_t 36695331Samw sa_get_next_resource(sa_resource_t resource) 36705331Samw { 36715331Samw xmlNodePtr node = NULL; 36725331Samw 36735331Samw if (resource != NULL) { 36745331Samw for (node = ((xmlNodePtr)resource)->next; node != NULL; 36755331Samw node = node->next) { 36765331Samw if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0) 36775331Samw break; 36785331Samw } 36795331Samw } 36805331Samw return ((sa_share_t)node); 36815331Samw } 36825331Samw 36835331Samw /* 36845331Samw * _sa_get_next_resource_index(share) 36855331Samw * 36865331Samw * get the next resource index number (one greater then current largest) 36875331Samw */ 36885331Samw 36895331Samw static int 36905331Samw _sa_get_next_resource_index(sa_share_t share) 36915331Samw { 36925331Samw sa_resource_t resource; 36935331Samw int index = 0; 36945331Samw char *id; 36955331Samw 36965331Samw for (resource = sa_get_share_resource(share, NULL); 36975331Samw resource != NULL; 36985331Samw resource = sa_get_next_resource(resource)) { 36995331Samw id = get_node_attr((void *)resource, "id"); 37005331Samw if (id != NULL) { 37015331Samw int val; 37025331Samw val = atoi(id); 37035331Samw if (val > index) 37045331Samw index = val; 37055331Samw sa_free_attr_string(id); 37065331Samw } 37075331Samw } 37085331Samw return (index + 1); 37095331Samw } 37105331Samw 37115331Samw 37125331Samw /* 37135331Samw * sa_add_resource(share, resource, persist, &err) 37145331Samw * 37155331Samw * Adds a new resource name associated with share. The resource name 37165331Samw * must be unique in the system and will be case insensitive (eventually). 37175331Samw */ 37185331Samw 37195331Samw sa_resource_t 37205331Samw sa_add_resource(sa_share_t share, char *resource, int persist, int *error) 37215331Samw { 37225331Samw xmlNodePtr node; 37235331Samw int err = SA_OK; 37245331Samw sa_resource_t res; 37255331Samw sa_group_t group; 37265331Samw sa_handle_t handle; 37275331Samw char istring[8]; /* just big enough for an integer value */ 37285331Samw int index; 37295331Samw 37305331Samw group = sa_get_parent_group(share); 37315331Samw handle = sa_find_group_handle(group); 37325331Samw res = sa_find_resource(handle, resource); 37335331Samw if (res != NULL) { 37345331Samw err = SA_DUPLICATE_NAME; 37355331Samw res = NULL; 37365331Samw } else { 37375331Samw node = xmlNewChild((xmlNodePtr)share, NULL, 37385331Samw (xmlChar *)"resource", NULL); 37395331Samw if (node != NULL) { 37406007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 37415331Samw (xmlChar *)resource); 37426007Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", persist ? 37435331Samw (xmlChar *)"persist" : (xmlChar *)"transient"); 37445331Samw if (persist != SA_SHARE_TRANSIENT) { 37455331Samw index = _sa_get_next_resource_index(share); 37465331Samw (void) snprintf(istring, sizeof (istring), "%d", 37475331Samw index); 37486007Sthurlow (void) xmlSetProp(node, (xmlChar *)"id", 37495331Samw (xmlChar *)istring); 37505331Samw if (!sa_group_is_zfs(group) && 37515331Samw sa_is_persistent((sa_group_t)share)) { 37525331Samw /* ZFS doesn't use resource names */ 37535331Samw sa_handle_impl_t ihandle; 37545331Samw ihandle = (sa_handle_impl_t) 37555331Samw sa_find_group_handle( 37565331Samw group); 37575331Samw if (ihandle != NULL) 37585331Samw err = sa_commit_share( 37595331Samw ihandle->scfhandle, group, 37605331Samw share); 37615331Samw else 37625331Samw err = SA_SYSTEM_ERR; 37635331Samw } 37645331Samw } 37655331Samw } 37665331Samw } 37675331Samw if (error != NULL) 37685331Samw *error = err; 37695331Samw return ((sa_resource_t)node); 37705331Samw } 37715331Samw 37725331Samw /* 37735331Samw * sa_remove_resource(resource) 37745331Samw * 37755331Samw * Remove the resource name from the share (and the system) 37765331Samw */ 37775331Samw 37785331Samw int 37795331Samw sa_remove_resource(sa_resource_t resource) 37805331Samw { 37815331Samw sa_share_t share; 37825331Samw sa_group_t group; 37835331Samw char *type; 37845331Samw int ret = SA_OK; 37855331Samw int transient = 0; 37865521Sas200622 sa_optionset_t opt; 37875331Samw 37885331Samw share = sa_get_resource_parent(resource); 37895331Samw type = sa_get_share_attr(share, "type"); 37905331Samw group = sa_get_parent_group(share); 37915331Samw 37925331Samw 37935331Samw if (type != NULL) { 37945331Samw if (strcmp(type, "persist") != 0) 37955331Samw transient = 1; 37965331Samw sa_free_attr_string(type); 37975331Samw } 37985331Samw 37995521Sas200622 /* Disable the resource for all protocols. */ 38005521Sas200622 (void) sa_disable_resource(resource, NULL); 38015521Sas200622 38025521Sas200622 /* Remove any optionsets from the resource. */ 38035521Sas200622 for (opt = sa_get_optionset(resource, NULL); 38045521Sas200622 opt != NULL; 38055521Sas200622 opt = sa_get_next_optionset(opt)) 38065521Sas200622 (void) sa_destroy_optionset(opt); 38075521Sas200622 38085331Samw /* Remove from the share */ 38095331Samw xmlUnlinkNode((xmlNode *)resource); 38105331Samw xmlFreeNode((xmlNode *)resource); 38115331Samw 38125331Samw /* only do SMF action if permanent and not ZFS */ 38135331Samw if (!transient && !sa_group_is_zfs(group)) { 38145331Samw sa_handle_impl_t ihandle; 38155331Samw ihandle = (sa_handle_impl_t)sa_find_group_handle(group); 38165331Samw if (ihandle != NULL) 38175331Samw ret = sa_commit_share(ihandle->scfhandle, group, share); 38185331Samw else 38195331Samw ret = SA_SYSTEM_ERR; 38205331Samw } 38215331Samw return (ret); 38225331Samw } 38235331Samw 38245331Samw /* 38255331Samw * proto_resource_rename(handle, group, resource, newname) 38265331Samw * 38275331Samw * Helper function for sa_rename_resource that notifies the protocol 38285331Samw * of a resource name change prior to a config repository update. 38295331Samw */ 38305331Samw static int 38315331Samw proto_rename_resource(sa_handle_t handle, sa_group_t group, 38325331Samw sa_resource_t resource, char *newname) 38335331Samw { 38345331Samw sa_optionset_t optionset; 38355331Samw int ret = SA_OK; 38365331Samw int err; 38375331Samw 38385331Samw for (optionset = sa_get_optionset(group, NULL); 38395331Samw optionset != NULL; 38405331Samw optionset = sa_get_next_optionset(optionset)) { 38415331Samw char *type; 38425331Samw type = sa_get_optionset_attr(optionset, "type"); 38435331Samw if (type != NULL) { 38445331Samw err = sa_proto_rename_resource(handle, type, resource, 38455331Samw newname); 38465331Samw if (err != SA_OK) 38475331Samw ret = err; 38485331Samw sa_free_attr_string(type); 38495331Samw } 38505331Samw } 38515331Samw return (ret); 38525331Samw } 38535331Samw 38545331Samw /* 38555331Samw * sa_rename_resource(resource, newname) 38565331Samw * 38575331Samw * Rename the resource to the new name, if it is unique. 38585331Samw */ 38595331Samw 38605331Samw int 38615331Samw sa_rename_resource(sa_resource_t resource, char *newname) 38625331Samw { 38635331Samw sa_share_t share; 38645331Samw sa_group_t group = NULL; 38655331Samw sa_resource_t target; 38665331Samw int ret = SA_CONFIG_ERR; 38675331Samw sa_handle_t handle = NULL; 38685331Samw 38695331Samw share = sa_get_resource_parent(resource); 38705331Samw if (share == NULL) 38715331Samw return (ret); 38725331Samw 38735331Samw group = sa_get_parent_group(share); 38745331Samw if (group == NULL) 38755331Samw return (ret); 38765331Samw 38775331Samw handle = (sa_handle_impl_t)sa_find_group_handle(group); 38785331Samw if (handle == NULL) 38795331Samw return (ret); 38805331Samw 38815331Samw target = sa_find_resource(handle, newname); 38825331Samw if (target != NULL) { 38835331Samw ret = SA_DUPLICATE_NAME; 38845331Samw } else { 38855331Samw /* 38865331Samw * Everything appears to be valid at this 38875331Samw * point. Change the name of the active share and then 38885331Samw * update the share in the appropriate repository. 38895331Samw */ 38905331Samw ret = proto_rename_resource(handle, group, resource, newname); 38915331Samw set_node_attr(resource, "name", newname); 38925331Samw if (!sa_group_is_zfs(group) && 38935331Samw sa_is_persistent((sa_group_t)share)) { 38945331Samw sa_handle_impl_t ihandle = (sa_handle_impl_t)handle; 38955331Samw ret = sa_commit_share(ihandle->scfhandle, group, 38965331Samw share); 38975331Samw } 38985331Samw } 38995331Samw return (ret); 39005331Samw } 39015331Samw 39025331Samw /* 39035331Samw * sa_get_resource_attr(resource, tag) 39045331Samw * 39055331Samw * Get the named attribute of the resource. "name" and "id" are 39065331Samw * currently defined. NULL if tag not defined. 39075331Samw */ 39085331Samw 39095331Samw char * 39105331Samw sa_get_resource_attr(sa_resource_t resource, char *tag) 39115331Samw { 39125331Samw return (get_node_attr((void *)resource, tag)); 39135331Samw } 39145331Samw 39155331Samw /* 39165331Samw * sa_set_resource_attr(resource, tag, value) 39175331Samw * 39185331Samw * Get the named attribute of the resource. "name" and "id" are 39195331Samw * currently defined. NULL if tag not defined. Currently we don't do 39205331Samw * much, but additional checking may be needed in the future. 39215331Samw */ 39225331Samw 39235331Samw int 39245331Samw sa_set_resource_attr(sa_resource_t resource, char *tag, char *value) 39255331Samw { 39265331Samw set_node_attr((void *)resource, tag, value); 39275331Samw return (SA_OK); 39285331Samw } 39295331Samw 39305331Samw /* 39315331Samw * sa_get_resource_parent(resource_t) 39325331Samw * 39335331Samw * Returns the share associated with the resource. 39345331Samw */ 39355331Samw 39365331Samw sa_share_t 39375331Samw sa_get_resource_parent(sa_resource_t resource) 39385331Samw { 39395331Samw sa_share_t share = NULL; 39405331Samw 39415331Samw if (resource != NULL) 39425331Samw share = (sa_share_t)((xmlNodePtr)resource)->parent; 39435331Samw return (share); 39445331Samw } 39455331Samw 39465331Samw /* 39475331Samw * find_resource(group, name) 39485331Samw * 39495331Samw * Find the resource within the group. 39505331Samw */ 39515331Samw 39525331Samw static sa_resource_t 39535331Samw find_resource(sa_group_t group, char *resname) 39545331Samw { 39555331Samw sa_share_t share; 39565331Samw sa_resource_t resource = NULL; 39575331Samw char *name; 39585331Samw 39595331Samw /* Iterate over all the shares and resources in the group. */ 39605331Samw for (share = sa_get_share(group, NULL); 39615331Samw share != NULL && resource == NULL; 39625331Samw share = sa_get_next_share(share)) { 39635331Samw for (resource = sa_get_share_resource(share, NULL); 39645331Samw resource != NULL; 39655331Samw resource = sa_get_next_resource(resource)) { 39665331Samw name = sa_get_resource_attr(resource, "name"); 39675331Samw if (name != NULL && xmlStrcasecmp((xmlChar*)name, 39685331Samw (xmlChar*)resname) == 0) { 39695331Samw sa_free_attr_string(name); 39705331Samw break; 39715331Samw } 39725331Samw if (name != NULL) { 39735331Samw sa_free_attr_string(name); 39745331Samw } 39755331Samw } 39765331Samw } 39775331Samw return (resource); 39785331Samw } 39795331Samw 39805331Samw /* 39815331Samw * sa_find_resource(name) 39825331Samw * 39835331Samw * Find the named resource in the system. 39845331Samw */ 39855331Samw 39865331Samw sa_resource_t 39875331Samw sa_find_resource(sa_handle_t handle, char *name) 39885331Samw { 39895331Samw sa_group_t group; 39905331Samw sa_group_t zgroup; 39915331Samw sa_resource_t resource = NULL; 39925331Samw 39935331Samw /* 39945331Samw * Iterate over all groups and zfs subgroups and check for 39955331Samw * resource name in them. 39965331Samw */ 39975331Samw for (group = sa_get_group(handle, NULL); group != NULL; 39985331Samw group = sa_get_next_group(group)) { 39995331Samw 40005331Samw if (is_zfs_group(group)) { 40015331Samw for (zgroup = 40025331Samw (sa_group_t)_sa_get_child_node((xmlNodePtr)group, 40035331Samw (xmlChar *)"group"); 40045331Samw zgroup != NULL && resource == NULL; 40055331Samw zgroup = sa_get_next_group(zgroup)) { 40065331Samw resource = find_resource(zgroup, name); 40075331Samw } 40085331Samw } else { 40095331Samw resource = find_resource(group, name); 40105331Samw } 40115331Samw if (resource != NULL) 40125331Samw break; 40135331Samw } 40145331Samw return (resource); 40155331Samw } 40165331Samw 40175331Samw /* 40185331Samw * sa_get_resource(group, resource) 40195331Samw * 40205331Samw * Search all the shares in the specified group for a share with a 40215331Samw * resource name matching the one specified. 40225331Samw * 40235331Samw * In the future, it may be advantageous to allow group to be NULL and 40245331Samw * search all groups but that isn't needed at present. 40255331Samw */ 40265331Samw 40275331Samw sa_resource_t 40285331Samw sa_get_resource(sa_group_t group, char *resource) 40295331Samw { 40305331Samw sa_share_t share = NULL; 40315331Samw sa_resource_t res = NULL; 40325331Samw 40335331Samw if (resource != NULL) { 40345331Samw for (share = sa_get_share(group, NULL); 40355331Samw share != NULL && res == NULL; 40365331Samw share = sa_get_next_share(share)) { 40375331Samw res = sa_get_share_resource(share, resource); 40385331Samw } 40395331Samw } 40405331Samw return (res); 40415331Samw } 40425331Samw 40435331Samw /* 40446270Sdougm * get_protocol_list(optionset, object) 40456270Sdougm * 40466270Sdougm * Get the protocol optionset list for the object and add them as 40476270Sdougm * properties to optionset. 40486270Sdougm */ 40496270Sdougm static int 40506270Sdougm get_protocol_list(sa_optionset_t optionset, void *object) 40516270Sdougm { 40526270Sdougm sa_property_t prop; 40536270Sdougm sa_optionset_t opts; 40546270Sdougm int ret = SA_OK; 40556270Sdougm 40566270Sdougm for (opts = sa_get_optionset(object, NULL); 40576270Sdougm opts != NULL; 40586270Sdougm opts = sa_get_next_optionset(opts)) { 40596270Sdougm char *type; 40606270Sdougm type = sa_get_optionset_attr(opts, "type"); 40616270Sdougm /* 40626270Sdougm * It is possible to have a non-protocol optionset. We 40636270Sdougm * skip any of those found. 40646270Sdougm */ 40656270Sdougm if (type == NULL) 40666270Sdougm continue; 40676270Sdougm prop = sa_create_property(type, "true"); 40686270Sdougm sa_free_attr_string(type); 40696270Sdougm if (prop != NULL) 40706270Sdougm prop = (sa_property_t)xmlAddChild((xmlNodePtr)optionset, 40716270Sdougm (xmlNodePtr)prop); 40726270Sdougm /* If prop is NULL, don't bother continuing */ 40736270Sdougm if (prop == NULL) { 40746270Sdougm ret = SA_NO_MEMORY; 40756270Sdougm break; 40766270Sdougm } 40776270Sdougm } 40786270Sdougm return (ret); 40796270Sdougm } 40806270Sdougm 40816270Sdougm /* 40826270Sdougm * sa_free_protoset(optionset) 40836270Sdougm * 40846270Sdougm * Free the protocol property optionset. 40856270Sdougm */ 40866270Sdougm static void 40876270Sdougm sa_free_protoset(sa_optionset_t optionset) 40886270Sdougm { 40896270Sdougm if (optionset != NULL) { 40906270Sdougm xmlUnlinkNode((xmlNodePtr) optionset); 40916270Sdougm xmlFreeNode((xmlNodePtr) optionset); 40926270Sdougm } 40936270Sdougm } 40946270Sdougm 40956270Sdougm /* 40966270Sdougm * sa_optionset_t sa_get_active_protocols(object) 40976270Sdougm * 40986270Sdougm * Return a list of the protocols that are active for the object. 40996270Sdougm * This is currently an internal helper function, but could be 41006270Sdougm * made visible if there is enough demand for it. 41016270Sdougm * 41026270Sdougm * The function finds the parent group and extracts the protocol 41036270Sdougm * optionsets creating a new optionset with the protocols as properties. 41046270Sdougm * 41056270Sdougm * The caller must free the returned optionset. 41066270Sdougm */ 41076270Sdougm 41086270Sdougm static sa_optionset_t 41096270Sdougm sa_get_active_protocols(void *object) 41106270Sdougm { 41116270Sdougm sa_optionset_t options; 41126270Sdougm sa_share_t share = NULL; 41136270Sdougm sa_group_t group = NULL; 41146270Sdougm sa_resource_t resource = NULL; 41156270Sdougm int ret = SA_OK; 41166270Sdougm 41176270Sdougm if (object == NULL) 41186270Sdougm return (NULL); 41196270Sdougm options = (sa_optionset_t)xmlNewNode(NULL, (xmlChar *)"optionset"); 41206270Sdougm if (options == NULL) 41216270Sdougm return (NULL); 41226270Sdougm 41236270Sdougm /* 41246270Sdougm * Find the objects up the tree that might have protocols 41256270Sdougm * enabled on them. 41266270Sdougm */ 41276270Sdougm if (sa_is_resource(object)) { 41286270Sdougm resource = (sa_resource_t)object; 41296270Sdougm share = sa_get_resource_parent(resource); 41306270Sdougm group = sa_get_parent_group(share); 41316270Sdougm } else if (sa_is_share(object)) { 41326270Sdougm share = (sa_share_t)object; 41336270Sdougm group = sa_get_parent_group(share); 41346270Sdougm } else { 41356270Sdougm group = (sa_group_t)group; 41366270Sdougm } 41376270Sdougm if (resource != NULL) 41386270Sdougm ret = get_protocol_list(options, resource); 41396270Sdougm if (ret == SA_OK && share != NULL) 41406270Sdougm ret = get_protocol_list(options, share); 41416270Sdougm if (ret == SA_OK && group != NULL) 41426270Sdougm ret = get_protocol_list(options, group); 41436270Sdougm 41446270Sdougm /* 41456270Sdougm * If there was an error, we won't have a complete list so 41466270Sdougm * abandon everything. The caller will have to deal with the 41476270Sdougm * issue. 41486270Sdougm */ 41496270Sdougm if (ret != SA_OK) { 41506270Sdougm sa_free_protoset(options); 41516270Sdougm options = NULL; 41526270Sdougm } 41536270Sdougm return (options); 41546270Sdougm } 41556270Sdougm 41566270Sdougm /* 41575331Samw * sa_enable_resource, protocol) 41585331Samw * Disable the specified share to the specified protocol. 41595331Samw * If protocol is NULL, then all protocols. 41605331Samw */ 41615331Samw int 41625331Samw sa_enable_resource(sa_resource_t resource, char *protocol) 41635331Samw { 41645331Samw int ret = SA_OK; 41655331Samw 41665331Samw if (protocol != NULL) { 41675331Samw ret = sa_proto_share_resource(protocol, resource); 41685331Samw } else { 41696270Sdougm sa_optionset_t protoset; 41706270Sdougm sa_property_t prop; 41716270Sdougm char *proto; 41726270Sdougm int err; 41736270Sdougm 41745331Samw /* need to do all protocols */ 41756270Sdougm protoset = sa_get_active_protocols(resource); 41766270Sdougm if (protoset == NULL) 41776270Sdougm return (SA_NO_MEMORY); 41786270Sdougm for (prop = sa_get_property(protoset, NULL); 41796270Sdougm prop != NULL; 41806270Sdougm prop = sa_get_next_property(prop)) { 41816270Sdougm proto = sa_get_property_attr(prop, "type"); 41826270Sdougm if (proto == NULL) { 41836270Sdougm ret = SA_NO_MEMORY; 41846270Sdougm continue; 41855331Samw } 41866270Sdougm err = sa_proto_share_resource(proto, resource); 41876270Sdougm if (err != SA_OK) 41886270Sdougm ret = err; 41896270Sdougm sa_free_attr_string(proto); 41905331Samw } 41916270Sdougm sa_free_protoset(protoset); 41925331Samw } 41935331Samw if (ret == SA_OK) 41945331Samw (void) sa_set_resource_attr(resource, "shared", NULL); 41955331Samw 41965331Samw return (ret); 41975331Samw } 41985331Samw 41995331Samw /* 42005331Samw * sa_disable_resource(resource, protocol) 42015331Samw * 42025331Samw * Disable the specified share for the specified protocol. If 42035331Samw * protocol is NULL, then all protocols. If the underlying 42045331Samw * protocol doesn't implement disable at the resource level, we 42055331Samw * disable at the share level. 42065331Samw */ 42075331Samw int 42085331Samw sa_disable_resource(sa_resource_t resource, char *protocol) 42095331Samw { 42105331Samw int ret = SA_OK; 42115331Samw 42125331Samw if (protocol != NULL) { 42135331Samw ret = sa_proto_unshare_resource(protocol, resource); 42145331Samw if (ret == SA_NOT_IMPLEMENTED) { 42155331Samw sa_share_t parent; 42165331Samw /* 42175331Samw * The protocol doesn't implement unshare 42185331Samw * resource. That implies that resource names are 42195331Samw * simple aliases for this protocol so we need to 42205331Samw * unshare the share. 42215331Samw */ 42225331Samw parent = sa_get_resource_parent(resource); 42235331Samw if (parent != NULL) 42245331Samw ret = sa_disable_share(parent, protocol); 42255331Samw else 42265331Samw ret = SA_CONFIG_ERR; 42275331Samw } 42285331Samw } else { 42296270Sdougm sa_optionset_t protoset; 42306270Sdougm sa_property_t prop; 42316270Sdougm char *proto; 42326270Sdougm int err; 42336270Sdougm 42345331Samw /* need to do all protocols */ 42356270Sdougm protoset = sa_get_active_protocols(resource); 42366270Sdougm if (protoset == NULL) 42376270Sdougm return (SA_NO_MEMORY); 42386270Sdougm for (prop = sa_get_property(protoset, NULL); 42396270Sdougm prop != NULL; 42406270Sdougm prop = sa_get_next_property(prop)) { 42416270Sdougm proto = sa_get_property_attr(prop, "type"); 42426270Sdougm if (proto == NULL) { 42436270Sdougm ret = SA_NO_MEMORY; 42446270Sdougm continue; 42455331Samw } 42466270Sdougm err = sa_proto_unshare_resource(proto, resource); 42476270Sdougm if (err == SA_NOT_SUPPORTED) { 42486270Sdougm sa_share_t parent; 42496270Sdougm parent = sa_get_resource_parent(resource); 42506270Sdougm if (parent != NULL) 42516270Sdougm err = sa_disable_share(parent, proto); 42526270Sdougm else 42536270Sdougm err = SA_CONFIG_ERR; 42546270Sdougm } 42556270Sdougm if (err != SA_OK) 42566270Sdougm ret = err; 42576270Sdougm sa_free_attr_string(proto); 42585331Samw } 42596270Sdougm sa_free_protoset(protoset); 42605331Samw } 42615331Samw if (ret == SA_OK) 42625331Samw (void) sa_set_resource_attr(resource, "shared", NULL); 42635331Samw 42645331Samw return (ret); 42655331Samw } 42665331Samw 42675331Samw /* 42685331Samw * sa_set_resource_description(resource, content) 42695331Samw * 42705331Samw * Set the description of share to content. 42715331Samw */ 42725331Samw 42735331Samw int 42745331Samw sa_set_resource_description(sa_resource_t resource, char *content) 42755331Samw { 42765331Samw xmlNodePtr node; 42775331Samw sa_group_t group; 42785331Samw sa_share_t share; 42795331Samw int ret = SA_OK; 42805331Samw 42815331Samw for (node = ((xmlNodePtr)resource)->children; 42825331Samw node != NULL; 42835331Samw node = node->next) { 42845331Samw if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 42855331Samw break; 42865331Samw } 42875331Samw } 42885331Samw 42895331Samw /* no existing description but want to add */ 42905331Samw if (node == NULL && content != NULL) { 42915331Samw /* add a description */ 42925331Samw node = _sa_set_share_description(resource, content); 42935331Samw } else if (node != NULL && content != NULL) { 42945331Samw /* update a description */ 42955331Samw xmlNodeSetContent(node, (xmlChar *)content); 42965331Samw } else if (node != NULL && content == NULL) { 42975331Samw /* remove an existing description */ 42985331Samw xmlUnlinkNode(node); 42995331Samw xmlFreeNode(node); 43005331Samw } 43015331Samw share = sa_get_resource_parent(resource); 43025331Samw group = sa_get_parent_group(share); 43035331Samw if (group != NULL && sa_is_persistent(share)) { 43045331Samw sa_handle_impl_t impl_handle; 43055331Samw impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 43065331Samw if (impl_handle != NULL) 43075331Samw ret = sa_commit_share(impl_handle->scfhandle, 43085331Samw group, share); 43095331Samw else 43105331Samw ret = SA_SYSTEM_ERR; 43115331Samw } 43125331Samw return (ret); 43135331Samw } 43145331Samw 43155331Samw /* 43165331Samw * sa_get_resource_description(share) 43175331Samw * 43185331Samw * Return the description text for the specified share if it 43195331Samw * exists. NULL if no description exists. 43205331Samw */ 43215331Samw 43225331Samw char * 43235331Samw sa_get_resource_description(sa_resource_t resource) 43245331Samw { 43255331Samw xmlChar *description = NULL; 43265331Samw xmlNodePtr node; 43275331Samw 43285331Samw for (node = ((xmlNodePtr)resource)->children; node != NULL; 43295331Samw node = node->next) { 43305331Samw if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) 43315331Samw break; 43325331Samw } 43335331Samw if (node != NULL) { 43345331Samw description = xmlNodeGetContent(node); 43355331Samw fixproblemchars((char *)description); 43365331Samw } 43375331Samw return ((char *)description); 43385331Samw } 4339