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) { 830*6304Sdougm /* 831*6304Sdougm * Get protocol specific structures, but only if this 832*6304Sdougm * is the only handle. 833*6304Sdougm */ 834*6304Sdougm (void) mutex_lock(&sa_global_lock); 835*6304Sdougm if (sa_global_handles == NULL) 836*6304Sdougm (void) proto_plugin_init(); 837*6304Sdougm (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 sa_scf_fini(impl_handle->scfhandle); 10293910Sdougm sa_zfs_fini(impl_handle); 10303910Sdougm 10313910Sdougm /* Remove and free the entry in the global list. */ 10323910Sdougm remove_handle_for_root(impl_handle->tree); 10333910Sdougm 10343910Sdougm /* Make sure we free the handle */ 10353910Sdougm free(impl_handle); 10363910Sdougm 10373910Sdougm /* 10383910Sdougm * If this was the last handle to release, unload the 1039*6304Sdougm * plugins that were loaded. Use a mutex in case 1040*6304Sdougm * another thread is reinitializing. 10413910Sdougm */ 1042*6304Sdougm (void) mutex_lock(&sa_global_lock); 10433910Sdougm if (sa_global_handles == NULL) 10444327Sdougm (void) proto_plugin_fini(); 1045*6304Sdougm (void) mutex_unlock(&sa_global_lock); 10463910Sdougm 10473034Sdougm } 10483034Sdougm } 10493034Sdougm 10503034Sdougm /* 10513034Sdougm * sa_get_protocols(char **protocol) 10523034Sdougm * Get array of protocols that are supported 10533034Sdougm * Returns pointer to an allocated and NULL terminated 10543034Sdougm * array of strings. Caller must free. 10553034Sdougm * This really should be determined dynamically. 10563034Sdougm * If there aren't any defined, return -1. 10573034Sdougm * Use free() to return memory. 10583034Sdougm */ 10593034Sdougm 10603034Sdougm int 10613034Sdougm sa_get_protocols(char ***protocols) 10623034Sdougm { 10633034Sdougm int numproto = -1; 10643034Sdougm 10653034Sdougm if (protocols != NULL) { 10664327Sdougm struct sa_proto_plugin *plug; 10674327Sdougm for (numproto = 0, plug = sap_proto_list; plug != NULL; 10684327Sdougm plug = plug->plugin_next) { 10694327Sdougm numproto++; 10704327Sdougm } 10713034Sdougm 10724327Sdougm *protocols = calloc(numproto + 1, sizeof (char *)); 10734327Sdougm if (*protocols != NULL) { 10744327Sdougm int ret = 0; 10754327Sdougm for (plug = sap_proto_list; plug != NULL; 10764327Sdougm plug = plug->plugin_next) { 10774327Sdougm /* faking for now */ 10784327Sdougm (*protocols)[ret++] = 10794327Sdougm plug->plugin_ops->sa_protocol; 10804327Sdougm } 10814327Sdougm } else { 10824327Sdougm numproto = -1; 10833034Sdougm } 10843034Sdougm } 10853034Sdougm return (numproto); 10863034Sdougm } 10873034Sdougm 10883034Sdougm /* 10893034Sdougm * find_group_by_name(node, group) 10903034Sdougm * 10913034Sdougm * search the XML document subtree specified by node to find the group 10923034Sdougm * specified by group. Searching subtree allows subgroups to be 10933034Sdougm * searched for. 10943034Sdougm */ 10953034Sdougm 10963034Sdougm static xmlNodePtr 10973034Sdougm find_group_by_name(xmlNodePtr node, xmlChar *group) 10983034Sdougm { 10993034Sdougm xmlChar *name = NULL; 11003034Sdougm 11013034Sdougm for (node = node->xmlChildrenNode; node != NULL; 11023034Sdougm node = node->next) { 11034327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"group") == 0) { 11044327Sdougm /* if no groupname, return the first found */ 11054327Sdougm if (group == NULL) 11064327Sdougm break; 11074327Sdougm name = xmlGetProp(node, (xmlChar *)"name"); 11084327Sdougm if (name != NULL && xmlStrcmp(name, group) == 0) 11094327Sdougm break; 11104327Sdougm if (name != NULL) { 11114327Sdougm xmlFree(name); 11124327Sdougm name = NULL; 11134327Sdougm } 11143034Sdougm } 11153034Sdougm } 11163034Sdougm if (name != NULL) 11174327Sdougm xmlFree(name); 11183034Sdougm return (node); 11193034Sdougm } 11203034Sdougm 11213034Sdougm /* 11223034Sdougm * sa_get_group(groupname) 11233034Sdougm * Return the "group" specified. If groupname is NULL, 11243034Sdougm * return the first group of the list of groups. 11253034Sdougm */ 11263034Sdougm sa_group_t 11273910Sdougm sa_get_group(sa_handle_t handle, char *groupname) 11283034Sdougm { 11293034Sdougm xmlNodePtr node = NULL; 11303034Sdougm char *subgroup = NULL; 11313034Sdougm char *group = NULL; 11323910Sdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle; 11333034Sdougm 11343910Sdougm if (impl_handle != NULL && impl_handle->tree != NULL) { 11354327Sdougm if (groupname != NULL) { 11364327Sdougm group = strdup(groupname); 11374345Sdougm if (group != NULL) { 11384345Sdougm subgroup = strchr(group, '/'); 11394345Sdougm if (subgroup != NULL) 11404345Sdougm *subgroup++ = '\0'; 11414345Sdougm } 11424327Sdougm } 11434345Sdougm /* 11444345Sdougm * We want to find the, possibly, named group. If 11454345Sdougm * group is not NULL, then lookup the name. If it is 11464345Sdougm * NULL, we only do the find if groupname is also 11474345Sdougm * NULL. This allows lookup of the "first" group in 11484345Sdougm * the internal list. 11494345Sdougm */ 11504345Sdougm if (group != NULL || groupname == NULL) 11514345Sdougm node = find_group_by_name(impl_handle->tree, 11524345Sdougm (xmlChar *)group); 11534345Sdougm 11544327Sdougm /* if a subgroup, find it before returning */ 11554327Sdougm if (subgroup != NULL && node != NULL) 11564327Sdougm node = find_group_by_name(node, (xmlChar *)subgroup); 11573034Sdougm } 11583034Sdougm if (node != NULL && (char *)group != NULL) 11594327Sdougm (void) sa_get_instance(impl_handle->scfhandle, (char *)group); 11603034Sdougm if (group != NULL) 11614327Sdougm free(group); 11623034Sdougm return ((sa_group_t)(node)); 11633034Sdougm } 11643034Sdougm 11653034Sdougm /* 11663034Sdougm * sa_get_next_group(group) 11673034Sdougm * Return the "next" group after the specified group from 11683034Sdougm * the internal group list. NULL if there are no more. 11693034Sdougm */ 11703034Sdougm sa_group_t 11713034Sdougm sa_get_next_group(sa_group_t group) 11723034Sdougm { 11733034Sdougm xmlNodePtr ngroup = NULL; 11743034Sdougm if (group != NULL) { 11754327Sdougm for (ngroup = ((xmlNodePtr)group)->next; ngroup != NULL; 11763034Sdougm ngroup = ngroup->next) { 11774327Sdougm if (xmlStrcmp(ngroup->name, (xmlChar *)"group") == 0) 11784327Sdougm break; 11794327Sdougm } 11803034Sdougm } 11813034Sdougm return ((sa_group_t)ngroup); 11823034Sdougm } 11833034Sdougm 11843034Sdougm /* 11853034Sdougm * sa_get_share(group, sharepath) 11863034Sdougm * Return the share object for the share specified. The share 11873034Sdougm * must be in the specified group. Return NULL if not found. 11883034Sdougm */ 11893034Sdougm sa_share_t 11903034Sdougm sa_get_share(sa_group_t group, char *sharepath) 11913034Sdougm { 11923034Sdougm xmlNodePtr node = NULL; 11933034Sdougm xmlChar *path; 11943034Sdougm 11953034Sdougm /* 11963034Sdougm * For future scalability, this should end up building a cache 11973034Sdougm * since it will get called regularly by the mountd and info 11983034Sdougm * services. 11993034Sdougm */ 12003034Sdougm if (group != NULL) { 12014327Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 12023034Sdougm node = node->next) { 12034327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) { 12044327Sdougm if (sharepath == NULL) { 12054327Sdougm break; 12064327Sdougm } else { 12074327Sdougm /* is it the correct share? */ 12084327Sdougm path = xmlGetProp(node, 12094327Sdougm (xmlChar *)"path"); 12104327Sdougm if (path != NULL && 12114327Sdougm xmlStrcmp(path, 12124327Sdougm (xmlChar *)sharepath) == 0) { 12134327Sdougm xmlFree(path); 12144327Sdougm break; 12154327Sdougm } 12164327Sdougm xmlFree(path); 12174327Sdougm } 12183034Sdougm } 12193034Sdougm } 12203034Sdougm } 12213034Sdougm return ((sa_share_t)node); 12223034Sdougm } 12233034Sdougm 12243034Sdougm /* 12253034Sdougm * sa_get_next_share(share) 12263034Sdougm * Return the next share following the specified share 12273034Sdougm * from the internal list of shares. Returns NULL if there 12283034Sdougm * are no more shares. The list is relative to the same 12293034Sdougm * group. 12303034Sdougm */ 12313034Sdougm sa_share_t 12323034Sdougm sa_get_next_share(sa_share_t share) 12333034Sdougm { 12343034Sdougm xmlNodePtr node = NULL; 12353034Sdougm 12363034Sdougm if (share != NULL) { 12374327Sdougm for (node = ((xmlNodePtr)share)->next; node != NULL; 12383034Sdougm node = node->next) { 12394327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) { 12404327Sdougm break; 12414327Sdougm } 12423034Sdougm } 12433034Sdougm } 12443034Sdougm return ((sa_share_t)node); 12453034Sdougm } 12463034Sdougm 12473034Sdougm /* 12483034Sdougm * _sa_get_child_node(node, type) 12493034Sdougm * 12503034Sdougm * find the child node of the specified node that has "type". This is 12513034Sdougm * used to implement several internal functions. 12523034Sdougm */ 12533034Sdougm 12543034Sdougm static xmlNodePtr 12553034Sdougm _sa_get_child_node(xmlNodePtr node, xmlChar *type) 12563034Sdougm { 12573034Sdougm xmlNodePtr child; 12583034Sdougm for (child = node->xmlChildrenNode; child != NULL; 12593034Sdougm child = child->next) 12604327Sdougm if (xmlStrcmp(child->name, type) == 0) 12614327Sdougm return (child); 12623034Sdougm return ((xmlNodePtr)NULL); 12633034Sdougm } 12643034Sdougm 12653034Sdougm /* 12663034Sdougm * find_share(group, path) 12673034Sdougm * 12683034Sdougm * Search all the shares in the specified group for one that has the 12693034Sdougm * specified path. 12703034Sdougm */ 12713034Sdougm 12723034Sdougm static sa_share_t 12733034Sdougm find_share(sa_group_t group, char *sharepath) 12743034Sdougm { 12753034Sdougm sa_share_t share; 12763034Sdougm char *path; 12773034Sdougm 12783034Sdougm for (share = sa_get_share(group, NULL); share != NULL; 12793034Sdougm share = sa_get_next_share(share)) { 12804327Sdougm path = sa_get_share_attr(share, "path"); 12814327Sdougm if (path != NULL && strcmp(path, sharepath) == 0) { 12824327Sdougm sa_free_attr_string(path); 12834327Sdougm break; 12844327Sdougm } 12854327Sdougm if (path != NULL) 12864327Sdougm sa_free_attr_string(path); 12873034Sdougm } 12883034Sdougm return (share); 12893034Sdougm } 12903034Sdougm 12913034Sdougm /* 12923034Sdougm * sa_get_sub_group(group) 12933034Sdougm * 12943034Sdougm * Get the first sub-group of group. The sa_get_next_group() function 12953034Sdougm * can be used to get the rest. This is currently only used for ZFS 12963034Sdougm * sub-groups but could be used to implement a more general mechanism. 12973034Sdougm */ 12983034Sdougm 12993034Sdougm sa_group_t 13003034Sdougm sa_get_sub_group(sa_group_t group) 13013034Sdougm { 13023034Sdougm return ((sa_group_t)_sa_get_child_node((xmlNodePtr)group, 13034327Sdougm (xmlChar *)"group")); 13043034Sdougm } 13053034Sdougm 13063034Sdougm /* 13073034Sdougm * sa_find_share(sharepath) 13083034Sdougm * Finds a share regardless of group. In the future, this 13093034Sdougm * function should utilize a cache and hash table of some kind. 13103034Sdougm * The current assumption is that a path will only be shared 13113034Sdougm * once. In the future, this may change as implementation of 13123034Sdougm * resource names comes into being. 13133034Sdougm */ 13143034Sdougm sa_share_t 13153910Sdougm sa_find_share(sa_handle_t handle, char *sharepath) 13163034Sdougm { 13173034Sdougm sa_group_t group; 13183034Sdougm sa_group_t zgroup; 13193034Sdougm sa_share_t share = NULL; 13203034Sdougm int done = 0; 13213034Sdougm 13223910Sdougm for (group = sa_get_group(handle, NULL); group != NULL && !done; 13234327Sdougm group = sa_get_next_group(group)) { 13244327Sdougm if (is_zfs_group(group)) { 13254327Sdougm for (zgroup = 13264327Sdougm (sa_group_t)_sa_get_child_node((xmlNodePtr)group, 13274327Sdougm (xmlChar *)"group"); 13284327Sdougm zgroup != NULL; 13294327Sdougm zgroup = sa_get_next_group(zgroup)) { 13304327Sdougm share = find_share(zgroup, sharepath); 13314327Sdougm if (share != NULL) 13324327Sdougm break; 13334327Sdougm } 13344327Sdougm } else { 13354327Sdougm share = find_share(group, sharepath); 13364327Sdougm } 13374327Sdougm if (share != NULL) 13383034Sdougm break; 13393034Sdougm } 13403034Sdougm return (share); 13413034Sdougm } 13423034Sdougm 13433034Sdougm /* 13443348Sdougm * sa_check_path(group, path, strictness) 13453034Sdougm * 13465331Samw * Check that path is a valid path relative to the group. Currently, 13473034Sdougm * we are ignoring the group and checking only the NFS rules. Later, 13483034Sdougm * we may want to use the group to then check against the protocols 13493348Sdougm * enabled on the group. The strictness values mean: 13503348Sdougm * SA_CHECK_NORMAL == only check newpath against shares that are active 13513348Sdougm * SA_CHECK_STRICT == check newpath against both active shares and those 13523348Sdougm * stored in the repository 13533034Sdougm */ 13543034Sdougm 13553034Sdougm int 13563348Sdougm sa_check_path(sa_group_t group, char *path, int strictness) 13573034Sdougm { 13583910Sdougm sa_handle_t handle; 13593910Sdougm 13603910Sdougm handle = sa_find_group_handle(group); 13613910Sdougm return (validpath(handle, path, strictness)); 13623034Sdougm } 13633034Sdougm 13643034Sdougm /* 13655331Samw * mark_excluded_protos(group, share, flags) 13663034Sdougm * 13675331Samw * Walk through all the protocols enabled for the group and check to 13685331Samw * see if the share has any of them should be in the exclude list 13695331Samw * based on the featureset of the protocol. If there are any, add the 13705331Samw * "exclude" property to the share. 13715331Samw */ 13725331Samw static void 13735331Samw mark_excluded_protos(sa_group_t group, xmlNodePtr share, uint64_t flags) 13745331Samw { 13755331Samw sa_optionset_t optionset; 13765331Samw char exclude_list[SA_STRSIZE]; 13775331Samw char *sep = ""; 13785331Samw 13795331Samw exclude_list[0] = '\0'; 13805331Samw for (optionset = sa_get_optionset(group, NULL); 13815331Samw optionset != NULL; 13825331Samw optionset = sa_get_next_optionset(optionset)) { 13835331Samw char *value; 13845331Samw uint64_t features; 13855331Samw value = sa_get_optionset_attr(optionset, "type"); 13865331Samw if (value == NULL) 13875331Samw continue; 13885331Samw features = sa_proto_get_featureset(value); 13895331Samw sa_free_attr_string(value); 13905331Samw if (!(features & flags)) { 13915331Samw (void) strlcat(exclude_list, sep, 13925331Samw sizeof (exclude_list)); 13935331Samw (void) strlcat(exclude_list, value, 13945331Samw sizeof (exclude_list)); 13955331Samw sep = ","; 13965331Samw } 13975331Samw } 13985331Samw if (exclude_list[0] != '\0') 13996007Sthurlow (void) xmlSetProp(share, (xmlChar *)"exclude", 14005331Samw (xmlChar *)exclude_list); 14015331Samw } 14025331Samw 14035331Samw /* 14045331Samw * get_all_features(group) 14055331Samw * 14065331Samw * Walk through all the protocols on the group and collect all 14075331Samw * possible enabled features. This is the OR of all the featuresets. 14085331Samw */ 14095331Samw static uint64_t 14105331Samw get_all_features(sa_group_t group) 14115331Samw { 14125331Samw sa_optionset_t optionset; 14135331Samw uint64_t features = 0; 14145331Samw 14155331Samw for (optionset = sa_get_optionset(group, NULL); 14165331Samw optionset != NULL; 14175331Samw optionset = sa_get_next_optionset(optionset)) { 14185331Samw char *value; 14195331Samw value = sa_get_optionset_attr(optionset, "type"); 14205331Samw if (value == NULL) 14215331Samw continue; 14225331Samw features |= sa_proto_get_featureset(value); 14235331Samw sa_free_attr_string(value); 14245331Samw } 14255331Samw return (features); 14265331Samw } 14275331Samw 14285331Samw 14295331Samw /* 14305331Samw * _sa_add_share(group, sharepath, persist, *error, flags) 14315331Samw * 14325331Samw * Common code for all types of add_share. sa_add_share() is the 14333034Sdougm * public API, we also need to be able to do this when parsing legacy 14343034Sdougm * files and construction of the internal configuration while 14355331Samw * extracting config info from SMF. "flags" indicates if some 14365331Samw * protocols need relaxed rules while other don't. These values are 14375331Samw * the featureset values defined in libshare.h. 14383034Sdougm */ 14393034Sdougm 14403034Sdougm sa_share_t 14415331Samw _sa_add_share(sa_group_t group, char *sharepath, int persist, int *error, 14425331Samw uint64_t flags) 14433034Sdougm { 14443034Sdougm xmlNodePtr node = NULL; 14453034Sdougm int err; 14463034Sdougm 14473034Sdougm err = SA_OK; /* assume success */ 14483034Sdougm 14494327Sdougm node = xmlNewChild((xmlNodePtr)group, NULL, (xmlChar *)"share", NULL); 14505331Samw if (node == NULL) { 14515331Samw if (error != NULL) 14525331Samw *error = SA_NO_MEMORY; 14535331Samw return (node); 14545331Samw } 14555331Samw 14566007Sthurlow (void) xmlSetProp(node, (xmlChar *)"path", (xmlChar *)sharepath); 14576007Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", 14585331Samw persist ? (xmlChar *)"persist" : (xmlChar *)"transient"); 14595331Samw if (flags != 0) 14605331Samw mark_excluded_protos(group, node, flags); 14615331Samw if (persist != SA_SHARE_TRANSIENT) { 14625331Samw /* 14635331Samw * persistent shares come in two flavors: SMF and 14645331Samw * ZFS. Sort this one out based on target group and 14655331Samw * path type. Both NFS and SMB are supported. First, 14665331Samw * check to see if the protocol is enabled on the 14675331Samw * subgroup and then setup the share appropriately. 14685331Samw */ 14695331Samw if (sa_group_is_zfs(group) && 14705331Samw sa_path_is_zfs(sharepath)) { 14715331Samw if (sa_get_optionset(group, "nfs") != NULL) 14724327Sdougm err = sa_zfs_set_sharenfs(group, sharepath, 1); 14735331Samw else if (sa_get_optionset(group, "smb") != NULL) 14745331Samw err = sa_zfs_set_sharesmb(group, sharepath, 1); 14755331Samw } else { 14765331Samw sa_handle_impl_t impl_handle; 14775331Samw impl_handle = 14785331Samw (sa_handle_impl_t)sa_find_group_handle(group); 14795331Samw if (impl_handle != NULL) { 14805331Samw err = sa_commit_share(impl_handle->scfhandle, 14815331Samw group, (sa_share_t)node); 14824327Sdougm } else { 14835331Samw err = SA_SYSTEM_ERR; 14844327Sdougm } 14853034Sdougm } 14863034Sdougm } 14875331Samw if (err == SA_NO_PERMISSION && persist & SA_SHARE_PARSER) 14885331Samw /* called by the dfstab parser so could be a show */ 14895331Samw err = SA_OK; 14905331Samw 14915331Samw if (err != SA_OK) { 14925331Samw /* 14935331Samw * we couldn't commit to the repository so undo 14945331Samw * our internal state to reflect reality. 14955331Samw */ 14965331Samw xmlUnlinkNode(node); 14975331Samw xmlFreeNode(node); 14985331Samw node = NULL; 14995331Samw } 15005331Samw 15013034Sdougm if (error != NULL) 15024327Sdougm *error = err; 15035331Samw 15043034Sdougm return (node); 15053034Sdougm } 15063034Sdougm 15073034Sdougm /* 15083034Sdougm * sa_add_share(group, sharepath, persist, *error) 15093034Sdougm * 15103034Sdougm * Add a new share object to the specified group. The share will 15113034Sdougm * have the specified sharepath and will only be constructed if 15123034Sdougm * it is a valid path to be shared. NULL is returned on error 15133034Sdougm * and a detailed error value will be returned via the error 15143034Sdougm * pointer. 15153034Sdougm */ 15163034Sdougm sa_share_t 15173034Sdougm sa_add_share(sa_group_t group, char *sharepath, int persist, int *error) 15183034Sdougm { 15193034Sdougm xmlNodePtr node = NULL; 15203348Sdougm int strictness = SA_CHECK_NORMAL; 15213910Sdougm sa_handle_t handle; 15225331Samw uint64_t special = 0; 15235331Samw uint64_t features; 15243348Sdougm 15253348Sdougm /* 15263348Sdougm * If the share is to be permanent, use strict checking so a 15273348Sdougm * bad config doesn't get created. Transient shares only need 15283348Sdougm * to check against the currently active 15293348Sdougm * shares. SA_SHARE_PARSER is a modifier used internally to 15303348Sdougm * indicate that we are being called by the dfstab parser and 15313348Sdougm * that we need strict checking in all cases. Normally persist 15323348Sdougm * is in integer value but SA_SHARE_PARSER may be or'd into 15333348Sdougm * it as an override. 15343348Sdougm */ 15353348Sdougm if (persist & SA_SHARE_PARSER || persist == SA_SHARE_PERMANENT) 15364327Sdougm strictness = SA_CHECK_STRICT; 15373034Sdougm 15383910Sdougm handle = sa_find_group_handle(group); 15393910Sdougm 15405331Samw /* 15415331Samw * need to determine if the share is valid. The rules are: 15425331Samw * - The path must not already exist 15435331Samw * - The path must not be a subdir or parent dir of an 15445331Samw * existing path unless at least one protocol allows it. 15455331Samw * The sub/parent check is done in sa_check_path(). 15465331Samw */ 15475331Samw 15485331Samw if (sa_find_share(handle, sharepath) == NULL) { 15495331Samw *error = sa_check_path(group, sharepath, strictness); 15505331Samw features = get_all_features(group); 15515331Samw switch (*error) { 15525331Samw case SA_PATH_IS_SUBDIR: 15535331Samw if (features & SA_FEATURE_ALLOWSUBDIRS) 15545331Samw special |= SA_FEATURE_ALLOWSUBDIRS; 15555331Samw break; 15565331Samw case SA_PATH_IS_PARENTDIR: 15575331Samw if (features & SA_FEATURE_ALLOWPARDIRS) 15585331Samw special |= SA_FEATURE_ALLOWPARDIRS; 15595331Samw break; 15605331Samw } 15615331Samw if (*error == SA_OK || special != SA_FEATURE_NONE) 15625331Samw node = _sa_add_share(group, sharepath, persist, 15635331Samw error, special); 15645331Samw } else { 15655331Samw *error = SA_DUPLICATE_NAME; 15663034Sdougm } 15673034Sdougm 15683034Sdougm return ((sa_share_t)node); 15693034Sdougm } 15703034Sdougm 15713034Sdougm /* 15723034Sdougm * sa_enable_share(share, protocol) 15733034Sdougm * Enable the specified share to the specified protocol. 15743034Sdougm * If protocol is NULL, then all protocols. 15753034Sdougm */ 15763034Sdougm int 15773034Sdougm sa_enable_share(sa_share_t share, char *protocol) 15783034Sdougm { 15793034Sdougm char *sharepath; 15803034Sdougm struct stat st; 15815331Samw int err = SA_OK; 15825331Samw int ret; 15833034Sdougm 15843034Sdougm sharepath = sa_get_share_attr(share, "path"); 15855331Samw if (sharepath == NULL) 15865331Samw return (SA_NO_MEMORY); 15873034Sdougm if (stat(sharepath, &st) < 0) { 15884327Sdougm err = SA_NO_SUCH_PATH; 15893034Sdougm } else { 15904327Sdougm /* tell the server about the share */ 15914327Sdougm if (protocol != NULL) { 15925331Samw if (excluded_protocol(share, protocol)) 15935331Samw goto done; 15945331Samw 15954327Sdougm /* lookup protocol specific handler */ 15964327Sdougm err = sa_proto_share(protocol, share); 15974327Sdougm if (err == SA_OK) 15985331Samw (void) sa_set_share_attr(share, 15995331Samw "shared", "true"); 16004327Sdougm } else { 16015331Samw /* Tell all protocols about the share */ 16025331Samw sa_group_t group; 16035331Samw sa_optionset_t optionset; 16045331Samw 16055331Samw group = sa_get_parent_group(share); 16065331Samw 16075331Samw for (optionset = sa_get_optionset(group, NULL); 16085331Samw optionset != NULL; 16095331Samw optionset = sa_get_next_optionset(optionset)) { 16105331Samw char *proto; 16115331Samw proto = sa_get_optionset_attr(optionset, 16125331Samw "type"); 16135331Samw if (proto != NULL) { 16145331Samw if (!excluded_protocol(share, proto)) { 16155331Samw ret = sa_proto_share(proto, 16165331Samw share); 16175331Samw if (ret != SA_OK) 16185331Samw err = ret; 16195331Samw } 16205331Samw sa_free_attr_string(proto); 16215331Samw } 16225331Samw } 16234327Sdougm (void) sa_set_share_attr(share, "shared", "true"); 16244327Sdougm } 16253034Sdougm } 16265331Samw done: 16273034Sdougm if (sharepath != NULL) 16284327Sdougm sa_free_attr_string(sharepath); 16293034Sdougm return (err); 16303034Sdougm } 16313034Sdougm 16323034Sdougm /* 16333034Sdougm * sa_disable_share(share, protocol) 16345331Samw * Disable the specified share to the specified protocol. If 16355331Samw * protocol is NULL, then all protocols that are enabled for the 16365331Samw * share should be disabled. 16373034Sdougm */ 16383034Sdougm int 16393034Sdougm sa_disable_share(sa_share_t share, char *protocol) 16403034Sdougm { 16413034Sdougm char *path; 16425331Samw int err = SA_OK; 16433034Sdougm int ret = SA_OK; 16443034Sdougm 16453034Sdougm path = sa_get_share_attr(share, "path"); 16463034Sdougm 16473034Sdougm if (protocol != NULL) { 16484543Smarks ret = sa_proto_unshare(share, protocol, path); 16493034Sdougm } else { 16504327Sdougm /* need to do all protocols */ 16515331Samw sa_group_t group; 16525331Samw sa_optionset_t optionset; 16535331Samw 16545331Samw group = sa_get_parent_group(share); 16555331Samw 16565331Samw /* Tell all protocols about the share */ 16575331Samw for (optionset = sa_get_optionset(group, NULL); 16585331Samw optionset != NULL; 16595331Samw optionset = sa_get_next_optionset(optionset)) { 16605331Samw char *proto; 16615331Samw 16625331Samw proto = sa_get_optionset_attr(optionset, "type"); 16635331Samw if (proto != NULL) { 16645331Samw err = sa_proto_unshare(share, proto, path); 16655331Samw if (err != SA_OK) 16665331Samw ret = err; 16675331Samw sa_free_attr_string(proto); 16685331Samw } 16695331Samw } 16703034Sdougm } 16713034Sdougm if (ret == SA_OK) 16723034Sdougm (void) sa_set_share_attr(share, "shared", NULL); 16733034Sdougm if (path != NULL) 16744327Sdougm sa_free_attr_string(path); 16753034Sdougm return (ret); 16763034Sdougm } 16773034Sdougm 16783034Sdougm /* 16793034Sdougm * sa_remove_share(share) 16803034Sdougm * 16813034Sdougm * remove the specified share from its containing group. 16823034Sdougm * Remove from the SMF or ZFS configuration space. 16833034Sdougm */ 16843034Sdougm 16853034Sdougm int 16863034Sdougm sa_remove_share(sa_share_t share) 16873034Sdougm { 16883034Sdougm sa_group_t group; 16893034Sdougm int ret = SA_OK; 16903034Sdougm char *type; 16913034Sdougm int transient = 0; 16923034Sdougm char *groupname; 16933034Sdougm char *zfs; 16943034Sdougm 16953034Sdougm type = sa_get_share_attr(share, "type"); 16963034Sdougm group = sa_get_parent_group(share); 16973034Sdougm zfs = sa_get_group_attr(group, "zfs"); 16983034Sdougm groupname = sa_get_group_attr(group, "name"); 16993034Sdougm if (type != NULL && strcmp(type, "persist") != 0) 17004327Sdougm transient = 1; 17013034Sdougm if (type != NULL) 17024327Sdougm sa_free_attr_string(type); 17033034Sdougm 17043034Sdougm /* remove the node from its group then free the memory */ 17053034Sdougm 17063034Sdougm /* 17073034Sdougm * need to test if "busy" 17083034Sdougm */ 17093034Sdougm /* only do SMF action if permanent */ 17103034Sdougm if (!transient || zfs != NULL) { 17114327Sdougm /* remove from legacy dfstab as well as possible SMF */ 17125331Samw ret = sa_delete_legacy(share, NULL); 17134327Sdougm if (ret == SA_OK) { 17144327Sdougm if (!sa_group_is_zfs(group)) { 17154327Sdougm sa_handle_impl_t impl_handle; 17164327Sdougm impl_handle = (sa_handle_impl_t) 17174327Sdougm sa_find_group_handle(group); 17184327Sdougm if (impl_handle != NULL) { 17194327Sdougm ret = sa_delete_share( 17204327Sdougm impl_handle->scfhandle, group, 17214327Sdougm share); 17224327Sdougm } else { 17234327Sdougm ret = SA_SYSTEM_ERR; 17244327Sdougm } 17254327Sdougm } else { 17264327Sdougm char *sharepath = sa_get_share_attr(share, 17274327Sdougm "path"); 17284327Sdougm if (sharepath != NULL) { 17294327Sdougm ret = sa_zfs_set_sharenfs(group, 17304327Sdougm sharepath, 0); 17314327Sdougm sa_free_attr_string(sharepath); 17324327Sdougm } 17334327Sdougm } 17343034Sdougm } 17353034Sdougm } 17363034Sdougm if (groupname != NULL) 17374327Sdougm sa_free_attr_string(groupname); 17383034Sdougm if (zfs != NULL) 17394327Sdougm sa_free_attr_string(zfs); 17403034Sdougm 17413034Sdougm xmlUnlinkNode((xmlNodePtr)share); 17423034Sdougm xmlFreeNode((xmlNodePtr)share); 17433034Sdougm return (ret); 17443034Sdougm } 17453034Sdougm 17463034Sdougm /* 17473034Sdougm * sa_move_share(group, share) 17483034Sdougm * 17493034Sdougm * move the specified share to the specified group. Update SMF 17503034Sdougm * appropriately. 17513034Sdougm */ 17523034Sdougm 17533034Sdougm int 17543034Sdougm sa_move_share(sa_group_t group, sa_share_t share) 17553034Sdougm { 17563034Sdougm sa_group_t oldgroup; 17573034Sdougm int ret = SA_OK; 17583034Sdougm 17593034Sdougm /* remove the node from its group then free the memory */ 17603034Sdougm 17613034Sdougm oldgroup = sa_get_parent_group(share); 17623034Sdougm if (oldgroup != group) { 17634327Sdougm sa_handle_impl_t impl_handle; 17644327Sdougm xmlUnlinkNode((xmlNodePtr)share); 17653034Sdougm /* 17664327Sdougm * now that the share isn't in its old group, add to 17674327Sdougm * the new one 17683034Sdougm */ 17696007Sthurlow (void) xmlAddChild((xmlNodePtr)group, (xmlNodePtr)share); 17704327Sdougm /* need to deal with SMF */ 17714327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 17724327Sdougm if (impl_handle != NULL) { 17734327Sdougm /* 17744327Sdougm * need to remove from old group first and then add to 17754327Sdougm * new group. Ideally, we would do the other order but 17764327Sdougm * need to avoid having the share in two groups at the 17774327Sdougm * same time. 17784327Sdougm */ 17794327Sdougm ret = sa_delete_share(impl_handle->scfhandle, oldgroup, 17804327Sdougm share); 17814327Sdougm if (ret == SA_OK) 17824327Sdougm ret = sa_commit_share(impl_handle->scfhandle, 17834327Sdougm group, share); 17844327Sdougm } else { 17854327Sdougm ret = SA_SYSTEM_ERR; 17864327Sdougm } 17873034Sdougm } 17883034Sdougm return (ret); 17893034Sdougm } 17903034Sdougm 17913034Sdougm /* 17923034Sdougm * sa_get_parent_group(share) 17933034Sdougm * 17945331Samw * Return the containing group for the share. If a group was actually 17953034Sdougm * passed in, we don't want a parent so return NULL. 17963034Sdougm */ 17973034Sdougm 17983034Sdougm sa_group_t 17993034Sdougm sa_get_parent_group(sa_share_t share) 18003034Sdougm { 18013034Sdougm xmlNodePtr node = NULL; 18023034Sdougm if (share != NULL) { 18034327Sdougm node = ((xmlNodePtr)share)->parent; 18043034Sdougm /* 18053034Sdougm * make sure parent is a group and not sharecfg since 18063034Sdougm * we may be cheating and passing in a group. 18073034Sdougm * Eventually, groups of groups might come into being. 18083034Sdougm */ 18094327Sdougm if (node == NULL || 18104327Sdougm xmlStrcmp(node->name, (xmlChar *)"sharecfg") == 0) 18114327Sdougm node = NULL; 18123034Sdougm } 18133034Sdougm return ((sa_group_t)node); 18143034Sdougm } 18153034Sdougm 18163034Sdougm /* 18173910Sdougm * _sa_create_group(impl_handle, groupname) 18183034Sdougm * 18193034Sdougm * Create a group in the document. The caller will need to deal with 18203034Sdougm * configuration store and activation. 18213034Sdougm */ 18223034Sdougm 18233034Sdougm sa_group_t 18243910Sdougm _sa_create_group(sa_handle_impl_t impl_handle, char *groupname) 18253034Sdougm { 18263034Sdougm xmlNodePtr node = NULL; 18273034Sdougm 18283034Sdougm if (sa_valid_group_name(groupname)) { 18294327Sdougm node = xmlNewChild(impl_handle->tree, NULL, (xmlChar *)"group", 18304327Sdougm NULL); 18314327Sdougm if (node != NULL) { 18326007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 18334327Sdougm (xmlChar *)groupname); 18346007Sthurlow (void) xmlSetProp(node, (xmlChar *)"state", 18354327Sdougm (xmlChar *)"enabled"); 18364327Sdougm } 18373034Sdougm } 18383034Sdougm return ((sa_group_t)node); 18393034Sdougm } 18403034Sdougm 18413034Sdougm /* 18423034Sdougm * _sa_create_zfs_group(group, groupname) 18433034Sdougm * 18443034Sdougm * Create a ZFS subgroup under the specified group. This may 18453034Sdougm * eventually form the basis of general sub-groups, but is currently 18463034Sdougm * restricted to ZFS. 18473034Sdougm */ 18483034Sdougm sa_group_t 18493034Sdougm _sa_create_zfs_group(sa_group_t group, char *groupname) 18503034Sdougm { 18513034Sdougm xmlNodePtr node = NULL; 18523034Sdougm 18534327Sdougm node = xmlNewChild((xmlNodePtr)group, NULL, (xmlChar *)"group", NULL); 18543034Sdougm if (node != NULL) { 18556007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 18566007Sthurlow (xmlChar *)groupname); 18576007Sthurlow (void) xmlSetProp(node, (xmlChar *)"state", 18586007Sthurlow (xmlChar *)"enabled"); 18593034Sdougm } 18603034Sdougm 18613034Sdougm return ((sa_group_t)node); 18623034Sdougm } 18633034Sdougm 18643034Sdougm /* 18653034Sdougm * sa_create_group(groupname, *error) 18663034Sdougm * 18673034Sdougm * Create a new group with groupname. Need to validate that it is a 18683034Sdougm * legal name for SMF and the construct the SMF service instance of 18693034Sdougm * svc:/network/shares/group to implement the group. All necessary 18703034Sdougm * operational properties must be added to the group at this point 18713034Sdougm * (via the SMF transaction model). 18723034Sdougm */ 18733034Sdougm sa_group_t 18743910Sdougm sa_create_group(sa_handle_t handle, char *groupname, int *error) 18753034Sdougm { 18763034Sdougm xmlNodePtr node = NULL; 18773034Sdougm sa_group_t group; 18783034Sdougm int ret; 18794327Sdougm char rbacstr[SA_STRSIZE]; 18803910Sdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle; 18813034Sdougm 18823034Sdougm ret = SA_OK; 18833034Sdougm 18843910Sdougm if (impl_handle == NULL || impl_handle->scfhandle == NULL) { 18854327Sdougm ret = SA_SYSTEM_ERR; 18864327Sdougm goto err; 18873034Sdougm } 18883034Sdougm 18893910Sdougm group = sa_get_group(handle, groupname); 18903034Sdougm if (group != NULL) { 18914327Sdougm ret = SA_DUPLICATE_NAME; 18923034Sdougm } else { 18934327Sdougm if (sa_valid_group_name(groupname)) { 18944327Sdougm node = xmlNewChild(impl_handle->tree, NULL, 18954327Sdougm (xmlChar *)"group", NULL); 18964327Sdougm if (node != NULL) { 18976007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 18984327Sdougm (xmlChar *)groupname); 18994327Sdougm /* default to the group being enabled */ 19006007Sthurlow (void) xmlSetProp(node, (xmlChar *)"state", 19014327Sdougm (xmlChar *)"enabled"); 19024327Sdougm ret = sa_create_instance(impl_handle->scfhandle, 19034327Sdougm groupname); 19044327Sdougm if (ret == SA_OK) { 19054327Sdougm ret = sa_start_transaction( 19064327Sdougm impl_handle->scfhandle, 19074327Sdougm "operation"); 19084327Sdougm } 19094327Sdougm if (ret == SA_OK) { 19104327Sdougm ret = sa_set_property( 19114327Sdougm impl_handle->scfhandle, 19124327Sdougm "state", "enabled"); 19134327Sdougm if (ret == SA_OK) { 19144327Sdougm ret = sa_end_transaction( 19155951Sdougm impl_handle->scfhandle, 19165951Sdougm impl_handle); 19174327Sdougm } else { 19184327Sdougm sa_abort_transaction( 19194327Sdougm impl_handle->scfhandle); 19204327Sdougm } 19214327Sdougm } 19224327Sdougm if (ret == SA_OK) { 19234327Sdougm /* initialize the RBAC strings */ 19244327Sdougm ret = sa_start_transaction( 19254327Sdougm impl_handle->scfhandle, 19264327Sdougm "general"); 19274327Sdougm if (ret == SA_OK) { 19284327Sdougm (void) snprintf(rbacstr, 19294327Sdougm sizeof (rbacstr), "%s.%s", 19304327Sdougm SA_RBAC_MANAGE, groupname); 19314327Sdougm ret = sa_set_property( 19324327Sdougm impl_handle->scfhandle, 19333034Sdougm "action_authorization", 19343034Sdougm rbacstr); 19354327Sdougm } 19364327Sdougm if (ret == SA_OK) { 19374327Sdougm (void) snprintf(rbacstr, 19384327Sdougm sizeof (rbacstr), "%s.%s", 19394327Sdougm SA_RBAC_VALUE, groupname); 19404327Sdougm ret = sa_set_property( 19414327Sdougm impl_handle->scfhandle, 19423034Sdougm "value_authorization", 19433034Sdougm rbacstr); 19444327Sdougm } 19454327Sdougm if (ret == SA_OK) { 19464327Sdougm ret = sa_end_transaction( 19475951Sdougm impl_handle->scfhandle, 19485951Sdougm impl_handle); 19494327Sdougm } else { 19504327Sdougm sa_abort_transaction( 19514327Sdougm impl_handle->scfhandle); 19524327Sdougm } 19534327Sdougm } 19544327Sdougm if (ret != SA_OK) { 19554327Sdougm /* 19564327Sdougm * Couldn't commit the group 19574327Sdougm * so we need to undo 19584327Sdougm * internally. 19594327Sdougm */ 19604327Sdougm xmlUnlinkNode(node); 19614327Sdougm xmlFreeNode(node); 19624327Sdougm node = NULL; 19634327Sdougm } 19643034Sdougm } else { 19654327Sdougm ret = SA_NO_MEMORY; 19663034Sdougm } 19673034Sdougm } else { 19684327Sdougm ret = SA_INVALID_NAME; 19693034Sdougm } 19703034Sdougm } 19713034Sdougm err: 19723034Sdougm if (error != NULL) 19734327Sdougm *error = ret; 19743034Sdougm return ((sa_group_t)node); 19753034Sdougm } 19763034Sdougm 19773034Sdougm /* 19783034Sdougm * sa_remove_group(group) 19793034Sdougm * 19803034Sdougm * Remove the specified group. This deletes from the SMF repository. 19813034Sdougm * All property groups and properties are removed. 19823034Sdougm */ 19833034Sdougm 19843034Sdougm int 19853034Sdougm sa_remove_group(sa_group_t group) 19863034Sdougm { 19873034Sdougm char *name; 19883034Sdougm int ret = SA_OK; 19893910Sdougm sa_handle_impl_t impl_handle; 19903034Sdougm 19913910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 19923910Sdougm if (impl_handle != NULL) { 19934327Sdougm name = sa_get_group_attr(group, "name"); 19944327Sdougm if (name != NULL) { 19954327Sdougm ret = sa_delete_instance(impl_handle->scfhandle, name); 19964327Sdougm sa_free_attr_string(name); 19974327Sdougm } 19984327Sdougm xmlUnlinkNode((xmlNodePtr)group); /* make sure unlinked */ 19994327Sdougm xmlFreeNode((xmlNodePtr)group); /* now it is gone */ 20003910Sdougm } else { 20014327Sdougm ret = SA_SYSTEM_ERR; 20023034Sdougm } 20033034Sdougm return (ret); 20043034Sdougm } 20053034Sdougm 20063034Sdougm /* 20073034Sdougm * sa_update_config() 20083034Sdougm * 20093034Sdougm * Used to update legacy files that need to be updated in bulk 20103034Sdougm * Currently, this is a placeholder and will go away in a future 20113034Sdougm * release. 20123034Sdougm */ 20133034Sdougm 20143034Sdougm int 20153910Sdougm sa_update_config(sa_handle_t handle) 20163034Sdougm { 20173034Sdougm /* 20183034Sdougm * do legacy files first so we can tell when they change. 20193034Sdougm * This will go away when we start updating individual records 20203034Sdougm * rather than the whole file. 20213034Sdougm */ 20223910Sdougm update_legacy_config(handle); 20233034Sdougm return (SA_OK); 20243034Sdougm } 20253034Sdougm 20263034Sdougm /* 20273034Sdougm * get_node_attr(node, tag) 20283034Sdougm * 20295331Samw * Get the specified tag(attribute) if it exists on the node. This is 20303034Sdougm * used internally by a number of attribute oriented functions. 20313034Sdougm */ 20323034Sdougm 20333034Sdougm static char * 20343034Sdougm get_node_attr(void *nodehdl, char *tag) 20353034Sdougm { 20363034Sdougm xmlNodePtr node = (xmlNodePtr)nodehdl; 20373034Sdougm xmlChar *name = NULL; 20383034Sdougm 20394327Sdougm if (node != NULL) 20403034Sdougm name = xmlGetProp(node, (xmlChar *)tag); 20413034Sdougm return ((char *)name); 20423034Sdougm } 20433034Sdougm 20443034Sdougm /* 20453034Sdougm * get_node_attr(node, tag) 20463034Sdougm * 20475331Samw * Set the specified tag(attribute) to the specified value This is 20483034Sdougm * used internally by a number of attribute oriented functions. It 20493034Sdougm * doesn't update the repository, only the internal document state. 20503034Sdougm */ 20513034Sdougm 20523034Sdougm void 20533034Sdougm set_node_attr(void *nodehdl, char *tag, char *value) 20543034Sdougm { 20553034Sdougm xmlNodePtr node = (xmlNodePtr)nodehdl; 20563034Sdougm if (node != NULL && tag != NULL) { 20574327Sdougm if (value != NULL) 20586007Sthurlow (void) xmlSetProp(node, (xmlChar *)tag, 20596007Sthurlow (xmlChar *)value); 20604327Sdougm else 20616007Sthurlow (void) xmlUnsetProp(node, (xmlChar *)tag); 20623034Sdougm } 20633034Sdougm } 20643034Sdougm 20653034Sdougm /* 20663034Sdougm * sa_get_group_attr(group, tag) 20673034Sdougm * 20683034Sdougm * Get the specied attribute, if defined, for the group. 20693034Sdougm */ 20703034Sdougm 20713034Sdougm char * 20723034Sdougm sa_get_group_attr(sa_group_t group, char *tag) 20733034Sdougm { 20743034Sdougm return (get_node_attr((void *)group, tag)); 20753034Sdougm } 20763034Sdougm 20773034Sdougm /* 20783034Sdougm * sa_set_group_attr(group, tag, value) 20793034Sdougm * 20803034Sdougm * set the specified tag/attribute on the group using value as its 20813034Sdougm * value. 20823034Sdougm * 20833034Sdougm * This will result in setting the property in the SMF repository as 20843034Sdougm * well as in the internal document. 20853034Sdougm */ 20863034Sdougm 20873034Sdougm int 20883034Sdougm sa_set_group_attr(sa_group_t group, char *tag, char *value) 20893034Sdougm { 20903034Sdougm int ret; 20913034Sdougm char *groupname; 20923910Sdougm sa_handle_impl_t impl_handle; 20933034Sdougm 20945331Samw /* 20955331Samw * ZFS group/subgroup doesn't need the handle so shortcut. 20965331Samw */ 20975331Samw if (sa_group_is_zfs(group)) { 20985331Samw set_node_attr((void *)group, tag, value); 20995331Samw return (SA_OK); 21005331Samw } 21015331Samw 21023910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 21033910Sdougm if (impl_handle != NULL) { 21044327Sdougm groupname = sa_get_group_attr(group, "name"); 21054327Sdougm ret = sa_get_instance(impl_handle->scfhandle, groupname); 21063910Sdougm if (ret == SA_OK) { 21074327Sdougm set_node_attr((void *)group, tag, value); 21084327Sdougm ret = sa_start_transaction(impl_handle->scfhandle, 21094327Sdougm "operation"); 21104327Sdougm if (ret == SA_OK) { 21114327Sdougm ret = sa_set_property(impl_handle->scfhandle, 21124327Sdougm tag, value); 21134327Sdougm if (ret == SA_OK) 21145885Sdougm ret = sa_end_transaction( 21155951Sdougm impl_handle->scfhandle, 21165951Sdougm impl_handle); 21174327Sdougm else 21184327Sdougm sa_abort_transaction( 21194327Sdougm impl_handle->scfhandle); 21204327Sdougm } 21215885Sdougm if (ret == SA_SYSTEM_ERR) 21225885Sdougm ret = SA_NO_PERMISSION; 21233034Sdougm } 21244327Sdougm if (groupname != NULL) 21254327Sdougm sa_free_attr_string(groupname); 21263910Sdougm } else { 21274327Sdougm ret = SA_SYSTEM_ERR; 21283034Sdougm } 21293034Sdougm return (ret); 21303034Sdougm } 21313034Sdougm 21323034Sdougm /* 21333034Sdougm * sa_get_share_attr(share, tag) 21343034Sdougm * 21353034Sdougm * Return the value of the tag/attribute set on the specified 21363034Sdougm * share. Returns NULL if the tag doesn't exist. 21373034Sdougm */ 21383034Sdougm 21393034Sdougm char * 21403034Sdougm sa_get_share_attr(sa_share_t share, char *tag) 21413034Sdougm { 21423034Sdougm return (get_node_attr((void *)share, tag)); 21433034Sdougm } 21443034Sdougm 21453034Sdougm /* 21463034Sdougm * _sa_set_share_description(share, description) 21473034Sdougm * 21485331Samw * Add a description tag with text contents to the specified share. A 21495331Samw * separate XML tag is used rather than a property. This can also be 21505331Samw * used with resources. 21513034Sdougm */ 21523034Sdougm 21533034Sdougm xmlNodePtr 21545331Samw _sa_set_share_description(void *share, char *content) 21553034Sdougm { 21563034Sdougm xmlNodePtr node; 21574327Sdougm node = xmlNewChild((xmlNodePtr)share, NULL, (xmlChar *)"description", 21584327Sdougm NULL); 21593034Sdougm xmlNodeSetContent(node, (xmlChar *)content); 21603034Sdougm return (node); 21613034Sdougm } 21623034Sdougm 21633034Sdougm /* 21643034Sdougm * sa_set_share_attr(share, tag, value) 21653034Sdougm * 21663034Sdougm * Set the share attribute specified by tag to the specified value. In 21673034Sdougm * the case of "resource", enforce a no duplicates in a group rule. If 21683034Sdougm * the share is not transient, commit the changes to the repository 21693034Sdougm * else just update the share internally. 21703034Sdougm */ 21713034Sdougm 21723034Sdougm int 21733034Sdougm sa_set_share_attr(sa_share_t share, char *tag, char *value) 21743034Sdougm { 21753034Sdougm sa_group_t group; 21763034Sdougm sa_share_t resource; 21773034Sdougm int ret = SA_OK; 21783034Sdougm 21793034Sdougm group = sa_get_parent_group(share); 21803034Sdougm 21813034Sdougm /* 21823034Sdougm * There are some attributes that may have specific 21833034Sdougm * restrictions on them. Initially, only "resource" has 21843034Sdougm * special meaning that needs to be checked. Only one instance 21853034Sdougm * of a resource name may exist within a group. 21863034Sdougm */ 21873034Sdougm 21883034Sdougm if (strcmp(tag, "resource") == 0) { 21894327Sdougm resource = sa_get_resource(group, value); 21904327Sdougm if (resource != share && resource != NULL) 21914327Sdougm ret = SA_DUPLICATE_NAME; 21923034Sdougm } 21933034Sdougm if (ret == SA_OK) { 21944327Sdougm set_node_attr((void *)share, tag, value); 21954327Sdougm if (group != NULL) { 21964327Sdougm char *type; 21974327Sdougm /* we can probably optimize this some */ 21984327Sdougm type = sa_get_share_attr(share, "type"); 21994327Sdougm if (type == NULL || strcmp(type, "transient") != 0) { 22004327Sdougm sa_handle_impl_t impl_handle; 22014327Sdougm impl_handle = 22024327Sdougm (sa_handle_impl_t)sa_find_group_handle( 22034327Sdougm group); 22044327Sdougm if (impl_handle != NULL) { 22054327Sdougm ret = sa_commit_share( 22064327Sdougm impl_handle->scfhandle, group, 22074327Sdougm share); 22084327Sdougm } else { 22094327Sdougm ret = SA_SYSTEM_ERR; 22104327Sdougm } 22114327Sdougm } 22124327Sdougm if (type != NULL) 22134327Sdougm sa_free_attr_string(type); 22143910Sdougm } 22153034Sdougm } 22163034Sdougm return (ret); 22173034Sdougm } 22183034Sdougm 22193034Sdougm /* 22203034Sdougm * sa_get_property_attr(prop, tag) 22213034Sdougm * 22223034Sdougm * Get the value of the specified property attribute. Standard 22233034Sdougm * attributes are "type" and "value". 22243034Sdougm */ 22253034Sdougm 22263034Sdougm char * 22273034Sdougm sa_get_property_attr(sa_property_t prop, char *tag) 22283034Sdougm { 22293034Sdougm return (get_node_attr((void *)prop, tag)); 22303034Sdougm } 22313034Sdougm 22323034Sdougm /* 22333034Sdougm * sa_get_optionset_attr(prop, tag) 22343034Sdougm * 22353034Sdougm * Get the value of the specified property attribute. Standard 22363034Sdougm * attribute is "type". 22373034Sdougm */ 22383034Sdougm 22393034Sdougm char * 22403034Sdougm sa_get_optionset_attr(sa_property_t optionset, char *tag) 22413034Sdougm { 22423034Sdougm return (get_node_attr((void *)optionset, tag)); 22433034Sdougm 22443034Sdougm } 22453034Sdougm 22463034Sdougm /* 22473034Sdougm * sa_set_optionset_attr(optionset, tag, value) 22483034Sdougm * 22493034Sdougm * Set the specified attribute(tag) to the specified value on the 22503034Sdougm * optionset. 22513034Sdougm */ 22523034Sdougm 22533034Sdougm void 22543034Sdougm sa_set_optionset_attr(sa_group_t optionset, char *tag, char *value) 22553034Sdougm { 22563034Sdougm set_node_attr((void *)optionset, tag, value); 22573034Sdougm } 22583034Sdougm 22593034Sdougm /* 22603034Sdougm * sa_free_attr_string(string) 22613034Sdougm * 22623034Sdougm * Free the string that was returned in one of the sa_get_*_attr() 22633034Sdougm * functions. 22643034Sdougm */ 22653034Sdougm 22663034Sdougm void 22673034Sdougm sa_free_attr_string(char *string) 22683034Sdougm { 22693034Sdougm xmlFree((xmlChar *)string); 22703034Sdougm } 22713034Sdougm 22723034Sdougm /* 22733034Sdougm * sa_get_optionset(group, proto) 22743034Sdougm * 22753034Sdougm * Return the optionset, if it exists, that is associated with the 22763034Sdougm * specified protocol. 22773034Sdougm */ 22783034Sdougm 22793034Sdougm sa_optionset_t 22803034Sdougm sa_get_optionset(void *group, char *proto) 22813034Sdougm { 22823034Sdougm xmlNodePtr node; 22833034Sdougm xmlChar *value = NULL; 22843034Sdougm 22853034Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 22864327Sdougm node = node->next) { 22873034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) { 22884327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 22894327Sdougm if (proto != NULL) { 22904327Sdougm if (value != NULL && 22914327Sdougm xmlStrcmp(value, (xmlChar *)proto) == 0) { 22924327Sdougm break; 22934327Sdougm } 22944327Sdougm if (value != NULL) { 22954327Sdougm xmlFree(value); 22964327Sdougm value = NULL; 22974327Sdougm } 22984327Sdougm } else { 22994327Sdougm break; 23003034Sdougm } 23013034Sdougm } 23023034Sdougm } 23033034Sdougm if (value != NULL) 23044327Sdougm xmlFree(value); 23053034Sdougm return ((sa_optionset_t)node); 23063034Sdougm } 23073034Sdougm 23083034Sdougm /* 23093034Sdougm * sa_get_next_optionset(optionset) 23103034Sdougm * 23113034Sdougm * Return the next optionset in the group. NULL if this was the last. 23123034Sdougm */ 23133034Sdougm 23143034Sdougm sa_optionset_t 23153034Sdougm sa_get_next_optionset(sa_optionset_t optionset) 23163034Sdougm { 23173034Sdougm xmlNodePtr node; 23183034Sdougm 23193034Sdougm for (node = ((xmlNodePtr)optionset)->next; node != NULL; 23204327Sdougm node = node->next) { 23213034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) { 23223034Sdougm break; 23233034Sdougm } 23243034Sdougm } 23253034Sdougm return ((sa_optionset_t)node); 23263034Sdougm } 23273034Sdougm 23283034Sdougm /* 23293034Sdougm * sa_get_security(group, sectype, proto) 23303034Sdougm * 23313034Sdougm * Return the security optionset. The internal name is a hold over 23323034Sdougm * from the implementation and will be changed before the API is 23333034Sdougm * finalized. This is really a named optionset that can be negotiated 23343034Sdougm * as a group of properties (like NFS security options). 23353034Sdougm */ 23363034Sdougm 23373034Sdougm sa_security_t 23383034Sdougm sa_get_security(sa_group_t group, char *sectype, char *proto) 23393034Sdougm { 23403034Sdougm xmlNodePtr node; 23413034Sdougm xmlChar *value = NULL; 23423034Sdougm 23433034Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 23444327Sdougm node = node->next) { 23454327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) { 23464327Sdougm if (proto != NULL) { 23474327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 23484327Sdougm if (value == NULL || 23494327Sdougm (value != NULL && 23504327Sdougm xmlStrcmp(value, (xmlChar *)proto) != 0)) { 23514327Sdougm /* it doesn't match so continue */ 23524327Sdougm xmlFree(value); 23534327Sdougm value = NULL; 23544327Sdougm continue; 23554327Sdougm } 23564327Sdougm } 23574327Sdougm if (value != NULL) { 23584327Sdougm xmlFree(value); 23594327Sdougm value = NULL; 23604327Sdougm } 23614327Sdougm /* potential match */ 23624327Sdougm if (sectype != NULL) { 23634327Sdougm value = xmlGetProp(node, (xmlChar *)"sectype"); 23644327Sdougm if (value != NULL && 23654327Sdougm xmlStrcmp(value, (xmlChar *)sectype) == 0) { 23664327Sdougm break; 23674327Sdougm } 23684327Sdougm } else { 23694327Sdougm break; 23704327Sdougm } 23713034Sdougm } 23723034Sdougm if (value != NULL) { 23734327Sdougm xmlFree(value); 23744327Sdougm value = NULL; 23753034Sdougm } 23763034Sdougm } 23773034Sdougm if (value != NULL) 23784327Sdougm xmlFree(value); 23793034Sdougm return ((sa_security_t)node); 23803034Sdougm } 23813034Sdougm 23823034Sdougm /* 23833034Sdougm * sa_get_next_security(security) 23843034Sdougm * 23853034Sdougm * Get the next security optionset if one exists. 23863034Sdougm */ 23873034Sdougm 23883034Sdougm sa_security_t 23893034Sdougm sa_get_next_security(sa_security_t security) 23903034Sdougm { 23913034Sdougm xmlNodePtr node; 23923034Sdougm 23933034Sdougm for (node = ((xmlNodePtr)security)->next; node != NULL; 23944327Sdougm node = node->next) { 23953034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) { 23963034Sdougm break; 23973034Sdougm } 23983034Sdougm } 23993034Sdougm return ((sa_security_t)node); 24003034Sdougm } 24013034Sdougm 24023034Sdougm /* 24033034Sdougm * sa_get_property(optionset, prop) 24043034Sdougm * 24053034Sdougm * Get the property object with the name specified in prop from the 24063034Sdougm * optionset. 24073034Sdougm */ 24083034Sdougm 24093034Sdougm sa_property_t 24103034Sdougm sa_get_property(sa_optionset_t optionset, char *prop) 24113034Sdougm { 24123034Sdougm xmlNodePtr node = (xmlNodePtr)optionset; 24133034Sdougm xmlChar *value = NULL; 24143034Sdougm 24153034Sdougm if (optionset == NULL) 24164327Sdougm return (NULL); 24173034Sdougm 24183034Sdougm for (node = node->children; node != NULL; 24194327Sdougm node = node->next) { 24204327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 24214327Sdougm if (prop == NULL) 24224327Sdougm break; 24234327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 24244327Sdougm if (value != NULL && 24254327Sdougm xmlStrcmp(value, (xmlChar *)prop) == 0) { 24264327Sdougm break; 24274327Sdougm } 24284327Sdougm if (value != NULL) { 24294327Sdougm xmlFree(value); 24304327Sdougm value = NULL; 24314327Sdougm } 24323034Sdougm } 24333034Sdougm } 24343034Sdougm if (value != NULL) 24353034Sdougm xmlFree(value); 24363034Sdougm if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"option") != 0) { 24374327Sdougm /* 24384327Sdougm * avoid a non option node -- it is possible to be a 24394327Sdougm * text node 24404327Sdougm */ 24414327Sdougm node = NULL; 24423034Sdougm } 24433034Sdougm return ((sa_property_t)node); 24443034Sdougm } 24453034Sdougm 24463034Sdougm /* 24473034Sdougm * sa_get_next_property(property) 24483034Sdougm * 24493034Sdougm * Get the next property following the specified property. NULL if 24503034Sdougm * this was the last. 24513034Sdougm */ 24523034Sdougm 24533034Sdougm sa_property_t 24543034Sdougm sa_get_next_property(sa_property_t property) 24553034Sdougm { 24563034Sdougm xmlNodePtr node; 24573034Sdougm 24583034Sdougm for (node = ((xmlNodePtr)property)->next; node != NULL; 24594327Sdougm node = node->next) { 24603034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 24613034Sdougm break; 24623034Sdougm } 24633034Sdougm } 24643034Sdougm return ((sa_property_t)node); 24653034Sdougm } 24663034Sdougm 24673034Sdougm /* 24683034Sdougm * sa_set_share_description(share, content) 24693034Sdougm * 24703034Sdougm * Set the description of share to content. 24713034Sdougm */ 24723034Sdougm 24733034Sdougm int 24743034Sdougm sa_set_share_description(sa_share_t share, char *content) 24753034Sdougm { 24763034Sdougm xmlNodePtr node; 24773034Sdougm sa_group_t group; 24783034Sdougm int ret = SA_OK; 24793034Sdougm 24803034Sdougm for (node = ((xmlNodePtr)share)->children; node != NULL; 24814327Sdougm node = node->next) { 24823034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 24833034Sdougm break; 24843034Sdougm } 24853034Sdougm } 24863034Sdougm /* no existing description but want to add */ 24873034Sdougm if (node == NULL && content != NULL) { 24883034Sdougm /* add a description */ 24894327Sdougm node = _sa_set_share_description(share, content); 24903034Sdougm } else if (node != NULL && content != NULL) { 24913034Sdougm /* update a description */ 24923034Sdougm xmlNodeSetContent(node, (xmlChar *)content); 24933034Sdougm } else if (node != NULL && content == NULL) { 24943034Sdougm /* remove an existing description */ 24953034Sdougm xmlUnlinkNode(node); 24963034Sdougm xmlFreeNode(node); 24973034Sdougm } 24985331Samw group = sa_get_parent_group(share); 24995331Samw if (group != NULL && sa_is_persistent(share)) { 25004327Sdougm sa_handle_impl_t impl_handle; 25014327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 25024327Sdougm if (impl_handle != NULL) { 25034327Sdougm ret = sa_commit_share(impl_handle->scfhandle, group, 25044327Sdougm share); 25054327Sdougm } else { 25064327Sdougm ret = SA_SYSTEM_ERR; 25074327Sdougm } 25083910Sdougm } 25093034Sdougm return (ret); 25103034Sdougm } 25113034Sdougm 25123034Sdougm /* 25133034Sdougm * fixproblemchars(string) 25143034Sdougm * 25153034Sdougm * don't want any newline or tab characters in the text since these 25163034Sdougm * could break display of data and legacy file formats. 25173034Sdougm */ 25183034Sdougm static void 25193034Sdougm fixproblemchars(char *str) 25203034Sdougm { 25213034Sdougm int c; 25223034Sdougm for (c = *str; c != '\0'; c = *++str) { 25234327Sdougm if (c == '\t' || c == '\n') 25244327Sdougm *str = ' '; 25254327Sdougm else if (c == '"') 25264327Sdougm *str = '\''; 25273034Sdougm } 25283034Sdougm } 25293034Sdougm 25303034Sdougm /* 25313034Sdougm * sa_get_share_description(share) 25323034Sdougm * 25333034Sdougm * Return the description text for the specified share if it 25343034Sdougm * exists. NULL if no description exists. 25353034Sdougm */ 25363034Sdougm 25373034Sdougm char * 25383034Sdougm sa_get_share_description(sa_share_t share) 25393034Sdougm { 25403034Sdougm xmlChar *description = NULL; 25413034Sdougm xmlNodePtr node; 25423034Sdougm 25433034Sdougm for (node = ((xmlNodePtr)share)->children; node != NULL; 25444327Sdougm node = node->next) { 25454327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 25464327Sdougm break; 25474327Sdougm } 25483034Sdougm } 25493034Sdougm if (node != NULL) { 25505331Samw description = xmlNodeGetContent(node); 25514327Sdougm fixproblemchars((char *)description); 25523034Sdougm } 25533034Sdougm return ((char *)description); 25543034Sdougm } 25553034Sdougm 25563034Sdougm /* 25573034Sdougm * sa_free(share_description(description) 25583034Sdougm * 25593034Sdougm * Free the description string. 25603034Sdougm */ 25613034Sdougm 25623034Sdougm void 25633034Sdougm sa_free_share_description(char *description) 25643034Sdougm { 25653034Sdougm xmlFree((xmlChar *)description); 25663034Sdougm } 25673034Sdougm 25683034Sdougm /* 25693034Sdougm * sa_create_optionset(group, proto) 25703034Sdougm * 25713034Sdougm * Create an optionset for the specified protocol in the specied 25723034Sdougm * group. This is manifested as a property group within SMF. 25733034Sdougm */ 25743034Sdougm 25753034Sdougm sa_optionset_t 25763034Sdougm sa_create_optionset(sa_group_t group, char *proto) 25773034Sdougm { 25783034Sdougm sa_optionset_t optionset; 25793034Sdougm sa_group_t parent = group; 25805331Samw sa_share_t share = NULL; 25815331Samw int err = SA_OK; 25825331Samw char *id = NULL; 25833034Sdougm 25843034Sdougm optionset = sa_get_optionset(group, proto); 25853034Sdougm if (optionset != NULL) { 25863034Sdougm /* can't have a duplicate protocol */ 25874327Sdougm optionset = NULL; 25883034Sdougm } else { 25895331Samw /* 25905331Samw * Account for resource names being slightly 25915331Samw * different. 25925331Samw */ 25935331Samw if (sa_is_share(group)) { 25945331Samw /* 25955331Samw * Transient shares do not have an "id" so not an 25965331Samw * error to not find one. 25975331Samw */ 25985331Samw id = sa_get_share_attr((sa_share_t)group, "id"); 25995331Samw } else if (sa_is_resource(group)) { 26005331Samw share = sa_get_resource_parent( 26015331Samw (sa_resource_t)group); 26025331Samw id = sa_get_resource_attr(share, "id"); 26035331Samw 26045331Samw /* id can be NULL if the group is transient (ZFS) */ 26055331Samw if (id == NULL && sa_is_persistent(group)) 26065331Samw err = SA_NO_MEMORY; 26075331Samw } 26085331Samw if (err == SA_NO_MEMORY) { 26095331Samw /* 26105331Samw * Couldn't get the id for the share or 26115331Samw * resource. While this could be a 26125331Samw * configuration issue, it is most likely an 26135331Samw * out of memory. In any case, fail the create. 26145331Samw */ 26155331Samw return (NULL); 26165331Samw } 26175331Samw 26184327Sdougm optionset = (sa_optionset_t)xmlNewChild((xmlNodePtr)group, 26194327Sdougm NULL, (xmlChar *)"optionset", NULL); 26203034Sdougm /* 26213034Sdougm * only put to repository if on a group and we were 26223034Sdougm * able to create an optionset. 26233034Sdougm */ 26244327Sdougm if (optionset != NULL) { 26254327Sdougm char oname[SA_STRSIZE]; 26264327Sdougm char *groupname; 26275331Samw 26285331Samw /* 26295331Samw * Need to get parent group in all cases, but also get 26305331Samw * the share if this is a resource. 26315331Samw */ 26325331Samw if (sa_is_share(group)) { 26334327Sdougm parent = sa_get_parent_group((sa_share_t)group); 26345331Samw } else if (sa_is_resource(group)) { 26355331Samw share = sa_get_resource_parent( 26365331Samw (sa_resource_t)group); 26375331Samw parent = sa_get_parent_group(share); 26385331Samw } 26394327Sdougm 26404327Sdougm sa_set_optionset_attr(optionset, "type", proto); 26413034Sdougm 26424327Sdougm (void) sa_optionset_name(optionset, oname, 26434327Sdougm sizeof (oname), id); 26444327Sdougm groupname = sa_get_group_attr(parent, "name"); 26455331Samw if (groupname != NULL && sa_is_persistent(group)) { 26464327Sdougm sa_handle_impl_t impl_handle; 26475331Samw impl_handle = 26485331Samw (sa_handle_impl_t)sa_find_group_handle( 26495331Samw group); 26504327Sdougm assert(impl_handle != NULL); 26514327Sdougm if (impl_handle != NULL) { 26524327Sdougm (void) sa_get_instance( 26535331Samw impl_handle->scfhandle, groupname); 26544327Sdougm (void) sa_create_pgroup( 26554327Sdougm impl_handle->scfhandle, oname); 26564327Sdougm } 26574327Sdougm } 26584327Sdougm if (groupname != NULL) 26594327Sdougm sa_free_attr_string(groupname); 26603034Sdougm } 26613034Sdougm } 26625331Samw 26635331Samw if (id != NULL) 26645331Samw sa_free_attr_string(id); 26653034Sdougm return (optionset); 26663034Sdougm } 26673034Sdougm 26683034Sdougm /* 26693034Sdougm * sa_get_property_parent(property) 26703034Sdougm * 26713034Sdougm * Given a property, return the object it is a property of. This will 26723034Sdougm * be an optionset of some type. 26733034Sdougm */ 26743034Sdougm 26753034Sdougm static sa_optionset_t 26763034Sdougm sa_get_property_parent(sa_property_t property) 26773034Sdougm { 26783034Sdougm xmlNodePtr node = NULL; 26793034Sdougm 26804327Sdougm if (property != NULL) 26814327Sdougm node = ((xmlNodePtr)property)->parent; 26823034Sdougm return ((sa_optionset_t)node); 26833034Sdougm } 26843034Sdougm 26853034Sdougm /* 26863034Sdougm * sa_get_optionset_parent(optionset) 26873034Sdougm * 26883034Sdougm * Return the parent of the specified optionset. This could be a group 26893034Sdougm * or a share. 26903034Sdougm */ 26913034Sdougm 26923034Sdougm static sa_group_t 26933034Sdougm sa_get_optionset_parent(sa_optionset_t optionset) 26943034Sdougm { 26953034Sdougm xmlNodePtr node = NULL; 26963034Sdougm 26974327Sdougm if (optionset != NULL) 26984327Sdougm node = ((xmlNodePtr)optionset)->parent; 26993034Sdougm return ((sa_group_t)node); 27003034Sdougm } 27013034Sdougm 27023034Sdougm /* 27033034Sdougm * zfs_needs_update(share) 27043034Sdougm * 27053034Sdougm * In order to avoid making multiple updates to a ZFS share when 27063034Sdougm * setting properties, the share attribute "changed" will be set to 27075331Samw * true when a property is added or modified. When done adding 27083034Sdougm * properties, we can then detect that an update is needed. We then 27093034Sdougm * clear the state here to detect additional changes. 27103034Sdougm */ 27113034Sdougm 27123034Sdougm static int 27133034Sdougm zfs_needs_update(sa_share_t share) 27143034Sdougm { 27153034Sdougm char *attr; 27163034Sdougm int result = 0; 27173034Sdougm 27183034Sdougm attr = sa_get_share_attr(share, "changed"); 27193034Sdougm if (attr != NULL) { 27204327Sdougm sa_free_attr_string(attr); 27213034Sdougm result = 1; 27223034Sdougm } 27233034Sdougm set_node_attr((void *)share, "changed", NULL); 27243034Sdougm return (result); 27253034Sdougm } 27263034Sdougm 27273034Sdougm /* 27283034Sdougm * zfs_set_update(share) 27293034Sdougm * 27303034Sdougm * Set the changed attribute of the share to true. 27313034Sdougm */ 27323034Sdougm 27333034Sdougm static void 27343034Sdougm zfs_set_update(sa_share_t share) 27353034Sdougm { 27363034Sdougm set_node_attr((void *)share, "changed", "true"); 27373034Sdougm } 27383034Sdougm 27393034Sdougm /* 27403034Sdougm * sa_commit_properties(optionset, clear) 27413034Sdougm * 27423034Sdougm * Check if SMF or ZFS config and either update or abort the pending 27433034Sdougm * changes. 27443034Sdougm */ 27453034Sdougm 27463034Sdougm int 27473034Sdougm sa_commit_properties(sa_optionset_t optionset, int clear) 27483034Sdougm { 27493034Sdougm sa_group_t group; 27503034Sdougm sa_group_t parent; 27513034Sdougm int zfs = 0; 27523034Sdougm int needsupdate = 0; 27533034Sdougm int ret = SA_OK; 27543910Sdougm sa_handle_impl_t impl_handle; 27553034Sdougm 27563034Sdougm group = sa_get_optionset_parent(optionset); 27573034Sdougm if (group != NULL && (sa_is_share(group) || is_zfs_group(group))) { 27584327Sdougm /* only update ZFS if on a share */ 27594327Sdougm parent = sa_get_parent_group(group); 27604327Sdougm zfs++; 27614327Sdougm if (parent != NULL && is_zfs_group(parent)) 27624327Sdougm needsupdate = zfs_needs_update(group); 27634327Sdougm else 27644327Sdougm zfs = 0; 27653034Sdougm } 27663034Sdougm if (zfs) { 27674327Sdougm if (!clear && needsupdate) 27684327Sdougm ret = sa_zfs_update((sa_share_t)group); 27693034Sdougm } else { 27704327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 27714327Sdougm if (impl_handle != NULL) { 27724327Sdougm if (clear) { 27734327Sdougm (void) sa_abort_transaction( 27744327Sdougm impl_handle->scfhandle); 27754327Sdougm } else { 27764327Sdougm ret = sa_end_transaction( 27775951Sdougm impl_handle->scfhandle, impl_handle); 27784327Sdougm } 27794327Sdougm } else { 27804327Sdougm ret = SA_SYSTEM_ERR; 27814327Sdougm } 27823034Sdougm } 27833034Sdougm return (ret); 27843034Sdougm } 27853034Sdougm 27863034Sdougm /* 27873034Sdougm * sa_destroy_optionset(optionset) 27883034Sdougm * 27895331Samw * Remove the optionset from its group. Update the repository to 27903034Sdougm * reflect this change. 27913034Sdougm */ 27923034Sdougm 27933034Sdougm int 27943034Sdougm sa_destroy_optionset(sa_optionset_t optionset) 27953034Sdougm { 27964327Sdougm char name[SA_STRSIZE]; 27973034Sdougm int len; 27983034Sdougm int ret; 27993034Sdougm char *id = NULL; 28003034Sdougm sa_group_t group; 28013034Sdougm int ispersist = 1; 28023034Sdougm 28033034Sdougm /* now delete the prop group */ 28043034Sdougm group = sa_get_optionset_parent(optionset); 28055331Samw if (group != NULL) { 28065331Samw if (sa_is_resource(group)) { 28075331Samw sa_resource_t resource = group; 28085331Samw sa_share_t share = sa_get_resource_parent(resource); 28095331Samw group = sa_get_parent_group(share); 28105331Samw id = sa_get_share_attr(share, "id"); 28115331Samw } else if (sa_is_share(group)) { 28125331Samw id = sa_get_share_attr((sa_share_t)group, "id"); 28135331Samw } 28145331Samw ispersist = sa_is_persistent(group); 28153034Sdougm } 28163034Sdougm if (ispersist) { 28174327Sdougm sa_handle_impl_t impl_handle; 28184327Sdougm len = sa_optionset_name(optionset, name, sizeof (name), id); 28194327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 28204327Sdougm if (impl_handle != NULL) { 28214327Sdougm if (len > 0) { 28224327Sdougm ret = sa_delete_pgroup(impl_handle->scfhandle, 28234327Sdougm name); 28244327Sdougm } 28254327Sdougm } else { 28264327Sdougm ret = SA_SYSTEM_ERR; 28273910Sdougm } 28283034Sdougm } 28293034Sdougm xmlUnlinkNode((xmlNodePtr)optionset); 28303034Sdougm xmlFreeNode((xmlNodePtr)optionset); 28313034Sdougm if (id != NULL) 28324327Sdougm sa_free_attr_string(id); 28333034Sdougm return (ret); 28343034Sdougm } 28353034Sdougm 28363034Sdougm /* private to the implementation */ 28373034Sdougm int 28383034Sdougm _sa_remove_optionset(sa_optionset_t optionset) 28393034Sdougm { 28403034Sdougm int ret = SA_OK; 28413034Sdougm 28423034Sdougm xmlUnlinkNode((xmlNodePtr)optionset); 28433034Sdougm xmlFreeNode((xmlNodePtr)optionset); 28443034Sdougm return (ret); 28453034Sdougm } 28463034Sdougm 28473034Sdougm /* 28483034Sdougm * sa_create_security(group, sectype, proto) 28493034Sdougm * 28503034Sdougm * Create a security optionset (one that has a type name and a 28513034Sdougm * proto). Security is left over from a pure NFS implementation. The 28523034Sdougm * naming will change in the future when the API is released. 28533034Sdougm */ 28543034Sdougm sa_security_t 28553034Sdougm sa_create_security(sa_group_t group, char *sectype, char *proto) 28563034Sdougm { 28573034Sdougm sa_security_t security; 28583034Sdougm char *id = NULL; 28593034Sdougm sa_group_t parent; 28603034Sdougm char *groupname = NULL; 28613034Sdougm 28623034Sdougm if (group != NULL && sa_is_share(group)) { 28634327Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 28644327Sdougm parent = sa_get_parent_group(group); 28654327Sdougm if (parent != NULL) 28664327Sdougm groupname = sa_get_group_attr(parent, "name"); 28673034Sdougm } else if (group != NULL) { 28684327Sdougm groupname = sa_get_group_attr(group, "name"); 28693034Sdougm } 28703034Sdougm 28713034Sdougm security = sa_get_security(group, sectype, proto); 28723034Sdougm if (security != NULL) { 28733034Sdougm /* can't have a duplicate security option */ 28743034Sdougm security = NULL; 28753034Sdougm } else { 28763034Sdougm security = (sa_security_t)xmlNewChild((xmlNodePtr)group, 28774327Sdougm NULL, (xmlChar *)"security", NULL); 28783034Sdougm if (security != NULL) { 28794327Sdougm char oname[SA_STRSIZE]; 28803034Sdougm sa_set_security_attr(security, "type", proto); 28813034Sdougm 28823034Sdougm sa_set_security_attr(security, "sectype", sectype); 28833034Sdougm (void) sa_security_name(security, oname, 28844327Sdougm sizeof (oname), id); 28855331Samw if (groupname != NULL && sa_is_persistent(group)) { 28864327Sdougm sa_handle_impl_t impl_handle; 28874327Sdougm impl_handle = 28884327Sdougm (sa_handle_impl_t)sa_find_group_handle( 28894327Sdougm group); 28904327Sdougm if (impl_handle != NULL) { 28914327Sdougm (void) sa_get_instance( 28924327Sdougm impl_handle->scfhandle, groupname); 28934327Sdougm (void) sa_create_pgroup( 28944327Sdougm impl_handle->scfhandle, oname); 28954327Sdougm } 28963034Sdougm } 28973034Sdougm } 28983034Sdougm } 28993034Sdougm if (groupname != NULL) 29004327Sdougm sa_free_attr_string(groupname); 29013034Sdougm return (security); 29023034Sdougm } 29033034Sdougm 29043034Sdougm /* 29053034Sdougm * sa_destroy_security(security) 29063034Sdougm * 29073034Sdougm * Remove the specified optionset from the document and the 29083034Sdougm * configuration. 29093034Sdougm */ 29103034Sdougm 29113034Sdougm int 29123034Sdougm sa_destroy_security(sa_security_t security) 29133034Sdougm { 29144327Sdougm char name[SA_STRSIZE]; 29153034Sdougm int len; 29163034Sdougm int ret = SA_OK; 29173034Sdougm char *id = NULL; 29183034Sdougm sa_group_t group; 29193034Sdougm int iszfs = 0; 29203034Sdougm int ispersist = 1; 29213034Sdougm 29223034Sdougm group = sa_get_optionset_parent(security); 29233034Sdougm 29243034Sdougm if (group != NULL) 29254327Sdougm iszfs = sa_group_is_zfs(group); 29263034Sdougm 29273034Sdougm if (group != NULL && !iszfs) { 29284327Sdougm if (sa_is_share(group)) 29295331Samw ispersist = sa_is_persistent(group); 29304327Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 29313034Sdougm } 29323034Sdougm if (ispersist) { 29334327Sdougm len = sa_security_name(security, name, sizeof (name), id); 29344327Sdougm if (!iszfs && len > 0) { 29354327Sdougm sa_handle_impl_t impl_handle; 29364327Sdougm impl_handle = 29374327Sdougm (sa_handle_impl_t)sa_find_group_handle(group); 29384327Sdougm if (impl_handle != NULL) { 29394327Sdougm ret = sa_delete_pgroup(impl_handle->scfhandle, 29404327Sdougm name); 29414327Sdougm } else { 29424327Sdougm ret = SA_SYSTEM_ERR; 29434327Sdougm } 29443910Sdougm } 29453034Sdougm } 29463034Sdougm xmlUnlinkNode((xmlNodePtr)security); 29473034Sdougm xmlFreeNode((xmlNodePtr)security); 29484327Sdougm if (iszfs) 29494327Sdougm ret = sa_zfs_update(group); 29503034Sdougm if (id != NULL) 29514327Sdougm sa_free_attr_string(id); 29523034Sdougm return (ret); 29533034Sdougm } 29543034Sdougm 29553034Sdougm /* 29563034Sdougm * sa_get_security_attr(optionset, tag) 29573034Sdougm * 29583034Sdougm * Return the specified attribute value from the optionset. 29593034Sdougm */ 29603034Sdougm 29613034Sdougm char * 29623034Sdougm sa_get_security_attr(sa_property_t optionset, char *tag) 29633034Sdougm { 29643034Sdougm return (get_node_attr((void *)optionset, tag)); 29653034Sdougm 29663034Sdougm } 29673034Sdougm 29683034Sdougm /* 29693034Sdougm * sa_set_security_attr(optionset, tag, value) 29703034Sdougm * 29713034Sdougm * Set the optioset attribute specied by tag to the specified value. 29723034Sdougm */ 29733034Sdougm 29743034Sdougm void 29753034Sdougm sa_set_security_attr(sa_group_t optionset, char *tag, char *value) 29763034Sdougm { 29773034Sdougm set_node_attr((void *)optionset, tag, value); 29783034Sdougm } 29793034Sdougm 29803034Sdougm /* 29813034Sdougm * is_nodetype(node, type) 29823034Sdougm * 29833034Sdougm * Check to see if node is of the type specified. 29843034Sdougm */ 29853034Sdougm 29863034Sdougm static int 29873034Sdougm is_nodetype(void *node, char *type) 29883034Sdougm { 29893034Sdougm return (strcmp((char *)((xmlNodePtr)node)->name, type) == 0); 29903034Sdougm } 29913034Sdougm 29924327Sdougm /* 29934327Sdougm * add_or_update() 29944327Sdougm * 29954327Sdougm * Add or update a property. Pulled out of sa_set_prop_by_prop for 29964327Sdougm * readability. 29974327Sdougm */ 29984327Sdougm static int 29994327Sdougm add_or_update(scfutilhandle_t *scf_handle, int type, scf_value_t *value, 30004327Sdougm scf_transaction_entry_t *entry, char *name, char *valstr) 30014327Sdougm { 30024327Sdougm int ret = SA_SYSTEM_ERR; 30034327Sdougm 30044327Sdougm if (value != NULL) { 30054327Sdougm if (type == SA_PROP_OP_ADD) 30064327Sdougm ret = scf_transaction_property_new(scf_handle->trans, 30074327Sdougm entry, name, SCF_TYPE_ASTRING); 30084327Sdougm else 30094327Sdougm ret = scf_transaction_property_change(scf_handle->trans, 30104327Sdougm entry, name, SCF_TYPE_ASTRING); 30114327Sdougm if (ret == 0) { 30124327Sdougm ret = scf_value_set_astring(value, valstr); 30134327Sdougm if (ret == 0) 30144327Sdougm ret = scf_entry_add_value(entry, value); 30154327Sdougm if (ret == 0) 30164327Sdougm return (ret); 30174327Sdougm scf_value_destroy(value); 30184327Sdougm } else { 30194327Sdougm scf_entry_destroy(entry); 30204327Sdougm } 30214327Sdougm } 30224327Sdougm return (SA_SYSTEM_ERR); 30234327Sdougm } 30244327Sdougm 30253034Sdougm /* 30263034Sdougm * sa_set_prop_by_prop(optionset, group, prop, type) 30273034Sdougm * 30283034Sdougm * Add/remove/update the specified property prop into the optionset or 30293034Sdougm * share. If a share, sort out which property group based on GUID. In 30303034Sdougm * all cases, the appropriate transaction is set (or ZFS share is 30313034Sdougm * marked as needing an update) 30323034Sdougm */ 30333034Sdougm 30343034Sdougm static int 30353034Sdougm sa_set_prop_by_prop(sa_optionset_t optionset, sa_group_t group, 30363034Sdougm sa_property_t prop, int type) 30373034Sdougm { 30383034Sdougm char *name; 30393034Sdougm char *valstr; 30403034Sdougm int ret = SA_OK; 30413034Sdougm scf_transaction_entry_t *entry; 30423034Sdougm scf_value_t *value; 30433034Sdougm int opttype; /* 1 == optionset, 0 == security */ 30443034Sdougm char *id = NULL; 30453034Sdougm int iszfs = 0; 30463034Sdougm sa_group_t parent = NULL; 30475331Samw sa_share_t share = NULL; 30483910Sdougm sa_handle_impl_t impl_handle; 30493910Sdougm scfutilhandle_t *scf_handle; 30503034Sdougm 30515331Samw if (!sa_is_persistent(group)) { 30523034Sdougm /* 30533034Sdougm * if the group/share is not persistent we don't need 30543034Sdougm * to do anything here 30553034Sdougm */ 30564327Sdougm return (SA_OK); 30573034Sdougm } 30583910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 30594327Sdougm if (impl_handle == NULL || impl_handle->scfhandle == NULL) 30604327Sdougm return (SA_SYSTEM_ERR); 30613910Sdougm scf_handle = impl_handle->scfhandle; 30623034Sdougm name = sa_get_property_attr(prop, "type"); 30633034Sdougm valstr = sa_get_property_attr(prop, "value"); 30643034Sdougm entry = scf_entry_create(scf_handle->handle); 30653034Sdougm opttype = is_nodetype((void *)optionset, "optionset"); 30663034Sdougm 30675331Samw /* 30685331Samw * Check for share vs. resource since they need slightly 30695331Samw * different treatment given the hierarchy. 30705331Samw */ 30713034Sdougm if (valstr != NULL && entry != NULL) { 30724327Sdougm if (sa_is_share(group)) { 30734327Sdougm parent = sa_get_parent_group(group); 30745331Samw share = (sa_share_t)group; 30754327Sdougm if (parent != NULL) 30764327Sdougm iszfs = is_zfs_group(parent); 30775331Samw } else if (sa_is_resource(group)) { 30785331Samw share = sa_get_parent_group(group); 30795331Samw if (share != NULL) 30805331Samw parent = sa_get_parent_group(share); 30814327Sdougm } else { 30824327Sdougm iszfs = is_zfs_group(group); 30833034Sdougm } 30844327Sdougm if (!iszfs) { 30854327Sdougm if (scf_handle->trans == NULL) { 30864327Sdougm char oname[SA_STRSIZE]; 30874327Sdougm char *groupname = NULL; 30885331Samw if (share != NULL) { 30895331Samw if (parent != NULL) 30904327Sdougm groupname = 30914327Sdougm sa_get_group_attr(parent, 30924327Sdougm "name"); 30935331Samw id = sa_get_share_attr( 30945331Samw (sa_share_t)share, "id"); 30954327Sdougm } else { 30964327Sdougm groupname = sa_get_group_attr(group, 30974327Sdougm "name"); 30984327Sdougm } 30994327Sdougm if (groupname != NULL) { 31004327Sdougm ret = sa_get_instance(scf_handle, 31014327Sdougm groupname); 31024327Sdougm sa_free_attr_string(groupname); 31034327Sdougm } 31044327Sdougm if (opttype) 31054327Sdougm (void) sa_optionset_name(optionset, 31064327Sdougm oname, sizeof (oname), id); 31074327Sdougm else 31084327Sdougm (void) sa_security_name(optionset, 31094327Sdougm oname, sizeof (oname), id); 31104327Sdougm ret = sa_start_transaction(scf_handle, oname); 31113910Sdougm } 31124327Sdougm if (ret == SA_OK) { 31134327Sdougm switch (type) { 31144327Sdougm case SA_PROP_OP_REMOVE: 31154327Sdougm ret = scf_transaction_property_delete( 31164327Sdougm scf_handle->trans, entry, name); 31174327Sdougm break; 31184327Sdougm case SA_PROP_OP_ADD: 31194327Sdougm case SA_PROP_OP_UPDATE: 31204327Sdougm value = scf_value_create( 31214327Sdougm scf_handle->handle); 31224327Sdougm ret = add_or_update(scf_handle, type, 31234327Sdougm value, entry, name, valstr); 31244327Sdougm break; 31253034Sdougm } 31263034Sdougm } 31274327Sdougm } else { 31284327Sdougm /* 31294327Sdougm * ZFS update. The calling function would have updated 31304327Sdougm * the internal XML structure. Just need to flag it as 31314327Sdougm * changed for ZFS. 31324327Sdougm */ 31334327Sdougm zfs_set_update((sa_share_t)group); 31344327Sdougm } 31353034Sdougm } 31363034Sdougm 31373034Sdougm if (name != NULL) 31384327Sdougm sa_free_attr_string(name); 31393034Sdougm if (valstr != NULL) 31404327Sdougm sa_free_attr_string(valstr); 31413034Sdougm else if (entry != NULL) 31424327Sdougm scf_entry_destroy(entry); 31433034Sdougm 31443034Sdougm if (ret == -1) 31454327Sdougm ret = SA_SYSTEM_ERR; 31463034Sdougm 31473034Sdougm return (ret); 31483034Sdougm } 31493034Sdougm 31503034Sdougm /* 31516007Sthurlow * sa_create_section(name, value) 31526007Sthurlow * 31536007Sthurlow * Create a new section with the specified name and extra data. 31546007Sthurlow */ 31556007Sthurlow 31566007Sthurlow sa_property_t 31576007Sthurlow sa_create_section(char *name, char *extra) 31586007Sthurlow { 31596007Sthurlow xmlNodePtr node; 31606007Sthurlow 31616007Sthurlow node = xmlNewNode(NULL, (xmlChar *)"section"); 31626007Sthurlow if (node != NULL) { 31636007Sthurlow if (name != NULL) 31646007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 31656007Sthurlow (xmlChar *)name); 31666007Sthurlow if (extra != NULL) 31676007Sthurlow (void) xmlSetProp(node, (xmlChar *)"extra", 31686007Sthurlow (xmlChar *)extra); 31696007Sthurlow } 31706007Sthurlow return ((sa_property_t)node); 31716007Sthurlow } 31726007Sthurlow 31736007Sthurlow void 31746007Sthurlow sa_set_section_attr(sa_property_t sect, char *name, char *value) 31756007Sthurlow { 31766007Sthurlow (void) xmlSetProp(sect, (xmlChar *)name, (xmlChar *)value); 31776007Sthurlow } 31786007Sthurlow 31796007Sthurlow /* 31806007Sthurlow * sa_create_property(section, name, value) 31813034Sdougm * 31823034Sdougm * Create a new property with the specified name and value. 31833034Sdougm */ 31843034Sdougm 31853034Sdougm sa_property_t 31863034Sdougm sa_create_property(char *name, char *value) 31873034Sdougm { 31883034Sdougm xmlNodePtr node; 31893034Sdougm 31903034Sdougm node = xmlNewNode(NULL, (xmlChar *)"option"); 31913034Sdougm if (node != NULL) { 31926007Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", (xmlChar *)name); 31936007Sthurlow (void) xmlSetProp(node, (xmlChar *)"value", (xmlChar *)value); 31943034Sdougm } 31953034Sdougm return ((sa_property_t)node); 31963034Sdougm } 31973034Sdougm 31983034Sdougm /* 31993034Sdougm * sa_add_property(object, property) 32003034Sdougm * 32013034Sdougm * Add the specified property to the object. Issue the appropriate 32023034Sdougm * transaction or mark a ZFS object as needing an update. 32033034Sdougm */ 32043034Sdougm 32053034Sdougm int 32063034Sdougm sa_add_property(void *object, sa_property_t property) 32073034Sdougm { 32083034Sdougm int ret = SA_OK; 32093034Sdougm sa_group_t parent; 32103034Sdougm sa_group_t group; 32113034Sdougm char *proto; 32126214Sdougm 32133034Sdougm if (property != NULL) { 32146271Sdougm sa_handle_t handle; 32156214Sdougm handle = sa_find_group_handle((sa_group_t)object); 32166271Sdougm /* It is legitimate to not find a handle */ 32176214Sdougm proto = sa_get_optionset_attr(object, "type"); 32186214Sdougm if ((ret = sa_valid_property(handle, object, proto, 32196214Sdougm property)) == SA_OK) { 32204327Sdougm property = (sa_property_t)xmlAddChild( 32214327Sdougm (xmlNodePtr)object, (xmlNodePtr)property); 32224327Sdougm } else { 32234327Sdougm if (proto != NULL) 32244327Sdougm sa_free_attr_string(proto); 32254327Sdougm return (ret); 32264327Sdougm } 32276214Sdougm if (proto != NULL) 32286214Sdougm sa_free_attr_string(proto); 32293034Sdougm } 32303034Sdougm 32313034Sdougm 32323034Sdougm parent = sa_get_parent_group(object); 32335331Samw if (!sa_is_persistent(parent)) 32344327Sdougm return (ret); 32355331Samw 32365331Samw if (sa_is_resource(parent)) { 32375331Samw /* 32385331Samw * Resources are children of share. Need to go up two 32395331Samw * levels to find the group but the parent needs to be 32405331Samw * the share at this point in order to get the "id". 32415331Samw */ 32425331Samw parent = sa_get_parent_group(parent); 32435331Samw group = sa_get_parent_group(parent); 32445331Samw } else if (sa_is_share(parent)) { 32455331Samw group = sa_get_parent_group(parent); 32465331Samw } else { 32475331Samw group = parent; 32483034Sdougm } 32493034Sdougm 32504327Sdougm if (property == NULL) { 32514327Sdougm ret = SA_NO_MEMORY; 32524327Sdougm } else { 32534327Sdougm char oname[SA_STRSIZE]; 32543034Sdougm 32554327Sdougm if (!is_zfs_group(group)) { 32564327Sdougm char *id = NULL; 32574327Sdougm sa_handle_impl_t impl_handle; 32584327Sdougm scfutilhandle_t *scf_handle; 32593910Sdougm 32604327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle( 32614327Sdougm group); 32624327Sdougm if (impl_handle == NULL || 32634327Sdougm impl_handle->scfhandle == NULL) 32644327Sdougm ret = SA_SYSTEM_ERR; 32654327Sdougm if (ret == SA_OK) { 32664327Sdougm scf_handle = impl_handle->scfhandle; 32674327Sdougm if (sa_is_share((sa_group_t)parent)) { 32684327Sdougm id = sa_get_share_attr( 32694327Sdougm (sa_share_t)parent, "id"); 32704327Sdougm } 32714327Sdougm if (scf_handle->trans == NULL) { 32724327Sdougm if (is_nodetype(object, "optionset")) { 32734327Sdougm (void) sa_optionset_name( 32744327Sdougm (sa_optionset_t)object, 32754327Sdougm oname, sizeof (oname), id); 32764327Sdougm } else { 32774327Sdougm (void) sa_security_name( 32784327Sdougm (sa_optionset_t)object, 32794327Sdougm oname, sizeof (oname), id); 32804327Sdougm } 32814327Sdougm ret = sa_start_transaction(scf_handle, 32824327Sdougm oname); 32834327Sdougm } 32844327Sdougm if (ret == SA_OK) { 32854327Sdougm char *name; 32864327Sdougm char *value; 32874327Sdougm name = sa_get_property_attr(property, 32884327Sdougm "type"); 32894327Sdougm value = sa_get_property_attr(property, 32904327Sdougm "value"); 32914327Sdougm if (name != NULL && value != NULL) { 32924327Sdougm if (scf_handle->scf_state == 32934327Sdougm SCH_STATE_INIT) { 32944327Sdougm ret = sa_set_property( 32954327Sdougm scf_handle, name, 32964327Sdougm value); 32974327Sdougm } 32984327Sdougm } else { 32994327Sdougm ret = SA_CONFIG_ERR; 33004327Sdougm } 33014327Sdougm if (name != NULL) 33024327Sdougm sa_free_attr_string( 33034327Sdougm name); 33044327Sdougm if (value != NULL) 33054327Sdougm sa_free_attr_string(value); 33064327Sdougm } 33074327Sdougm if (id != NULL) 33084327Sdougm sa_free_attr_string(id); 33094327Sdougm } 33104327Sdougm } else { 33114327Sdougm /* 33124327Sdougm * ZFS is a special case. We do want 33134327Sdougm * to allow editing property/security 33144327Sdougm * lists since we can have a better 33154327Sdougm * syntax and we also want to keep 33164327Sdougm * things consistent when possible. 33174327Sdougm * 33184327Sdougm * Right now, we defer until the 33194327Sdougm * sa_commit_properties so we can get 33204327Sdougm * them all at once. We do need to 33214327Sdougm * mark the share as "changed" 33224327Sdougm */ 33234327Sdougm zfs_set_update((sa_share_t)parent); 33243034Sdougm } 33253034Sdougm } 33263034Sdougm return (ret); 33273034Sdougm } 33283034Sdougm 33293034Sdougm /* 33303034Sdougm * sa_remove_property(property) 33313034Sdougm * 33323034Sdougm * Remove the specied property from its containing object. Update the 33333034Sdougm * repository as appropriate. 33343034Sdougm */ 33353034Sdougm 33363034Sdougm int 33373034Sdougm sa_remove_property(sa_property_t property) 33383034Sdougm { 33393034Sdougm int ret = SA_OK; 33403034Sdougm 33413034Sdougm if (property != NULL) { 33423034Sdougm sa_optionset_t optionset; 33433034Sdougm sa_group_t group; 33443034Sdougm optionset = sa_get_property_parent(property); 33453034Sdougm if (optionset != NULL) { 33464327Sdougm group = sa_get_optionset_parent(optionset); 33474327Sdougm if (group != NULL) { 33484327Sdougm ret = sa_set_prop_by_prop(optionset, group, 33494327Sdougm property, SA_PROP_OP_REMOVE); 33504327Sdougm } 33513034Sdougm } 33523034Sdougm xmlUnlinkNode((xmlNodePtr)property); 33533034Sdougm xmlFreeNode((xmlNodePtr)property); 33543034Sdougm } else { 33554327Sdougm ret = SA_NO_SUCH_PROP; 33563034Sdougm } 33573034Sdougm return (ret); 33583034Sdougm } 33593034Sdougm 33603034Sdougm /* 33613034Sdougm * sa_update_property(property, value) 33623034Sdougm * 33633034Sdougm * Update the specified property to the new value. If value is NULL, 33643034Sdougm * we currently treat this as a remove. 33653034Sdougm */ 33663034Sdougm 33673034Sdougm int 33683034Sdougm sa_update_property(sa_property_t property, char *value) 33693034Sdougm { 33703034Sdougm int ret = SA_OK; 33713034Sdougm if (value == NULL) { 33723034Sdougm return (sa_remove_property(property)); 33733034Sdougm } else { 33743034Sdougm sa_optionset_t optionset; 33753034Sdougm sa_group_t group; 33763034Sdougm set_node_attr((void *)property, "value", value); 33773034Sdougm optionset = sa_get_property_parent(property); 33783034Sdougm if (optionset != NULL) { 33794327Sdougm group = sa_get_optionset_parent(optionset); 33804327Sdougm if (group != NULL) { 33814327Sdougm ret = sa_set_prop_by_prop(optionset, group, 33824327Sdougm property, SA_PROP_OP_UPDATE); 33834327Sdougm } 33843034Sdougm } else { 33854327Sdougm ret = SA_NO_SUCH_PROP; 33863034Sdougm } 33873034Sdougm } 33883034Sdougm return (ret); 33893034Sdougm } 33903034Sdougm 33913034Sdougm /* 33926007Sthurlow * sa_get_protocol_section(propset, prop) 33936007Sthurlow * 33946007Sthurlow * Get the specified protocol specific section. These are global to 33956007Sthurlow * the protocol and not specific to a group or share. 33966007Sthurlow */ 33976007Sthurlow 33986007Sthurlow sa_protocol_properties_t 33996007Sthurlow sa_get_protocol_section(sa_protocol_properties_t propset, char *section) 34006007Sthurlow { 34016007Sthurlow xmlNodePtr node = (xmlNodePtr)propset; 34026007Sthurlow xmlChar *value = NULL; 34036007Sthurlow char *proto; 34046007Sthurlow 34056007Sthurlow proto = sa_get_optionset_attr(propset, "type"); 34066007Sthurlow if ((sa_proto_get_featureset(proto) & SA_FEATURE_HAS_SECTIONS) == 0) 34076007Sthurlow return (propset); 34086007Sthurlow 34096007Sthurlow for (node = node->children; node != NULL; 34106007Sthurlow node = node->next) { 34116007Sthurlow if (xmlStrcmp(node->name, (xmlChar *)"section") == 0) { 34126007Sthurlow if (section == NULL) 34136007Sthurlow break; 34146007Sthurlow value = xmlGetProp(node, (xmlChar *)"name"); 34156007Sthurlow if (value != NULL && 34166007Sthurlow xmlStrcasecmp(value, (xmlChar *)section) == 0) { 34176007Sthurlow break; 34186007Sthurlow } 34196007Sthurlow if (value != NULL) { 34206007Sthurlow xmlFree(value); 34216007Sthurlow value = NULL; 34226007Sthurlow } 34236007Sthurlow } 34246007Sthurlow } 34256007Sthurlow if (value != NULL) 34266007Sthurlow xmlFree(value); 34276007Sthurlow if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"section") != 0) { 34286007Sthurlow /* 34296007Sthurlow * avoid a non option node -- it is possible to be a 34306007Sthurlow * text node 34316007Sthurlow */ 34326007Sthurlow node = NULL; 34336007Sthurlow } 34346007Sthurlow return ((sa_protocol_properties_t)node); 34356007Sthurlow } 34366007Sthurlow 34376007Sthurlow /* 34386007Sthurlow * sa_get_next_protocol_section(prop, find) 34396007Sthurlow * 34406007Sthurlow * Get the next protocol specific section in the list. 34416007Sthurlow */ 34426007Sthurlow 34436007Sthurlow sa_property_t 34446007Sthurlow sa_get_next_protocol_section(sa_property_t prop, char *find) 34456007Sthurlow { 34466007Sthurlow xmlNodePtr node; 34476007Sthurlow xmlChar *value = NULL; 34486007Sthurlow char *proto; 34496007Sthurlow 34506007Sthurlow proto = sa_get_optionset_attr(prop, "type"); 34516007Sthurlow if ((sa_proto_get_featureset(proto) & SA_FEATURE_HAS_SECTIONS) == 0) 34526007Sthurlow return ((sa_property_t)NULL); 34536007Sthurlow 34546007Sthurlow for (node = ((xmlNodePtr)prop)->next; node != NULL; 34556007Sthurlow node = node->next) { 34566007Sthurlow if (xmlStrcmp(node->name, (xmlChar *)"section") == 0) { 34576007Sthurlow if (find == NULL) 34586007Sthurlow break; 34596007Sthurlow value = xmlGetProp(node, (xmlChar *)"name"); 34606007Sthurlow if (value != NULL && 34616007Sthurlow xmlStrcasecmp(value, (xmlChar *)find) == 0) { 34626007Sthurlow break; 34636007Sthurlow } 34646007Sthurlow if (value != NULL) { 34656007Sthurlow xmlFree(value); 34666007Sthurlow value = NULL; 34676007Sthurlow } 34686007Sthurlow 34696007Sthurlow } 34706007Sthurlow } 34716007Sthurlow if (value != NULL) 34726007Sthurlow xmlFree(value); 34736007Sthurlow return ((sa_property_t)node); 34746007Sthurlow } 34756007Sthurlow 34766007Sthurlow /* 34773034Sdougm * sa_get_protocol_property(propset, prop) 34783034Sdougm * 34793034Sdougm * Get the specified protocol specific property. These are global to 34803034Sdougm * the protocol and not specific to a group or share. 34813034Sdougm */ 34823034Sdougm 34833034Sdougm sa_property_t 34843034Sdougm sa_get_protocol_property(sa_protocol_properties_t propset, char *prop) 34853034Sdougm { 34863034Sdougm xmlNodePtr node = (xmlNodePtr)propset; 34873034Sdougm xmlChar *value = NULL; 34883034Sdougm 34896007Sthurlow if (propset == NULL) 34906007Sthurlow return (NULL); 34916007Sthurlow 34923034Sdougm for (node = node->children; node != NULL; 34934327Sdougm node = node->next) { 34944327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 34954327Sdougm if (prop == NULL) 34964327Sdougm break; 34974327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 34984327Sdougm if (value != NULL && 34994327Sdougm xmlStrcasecmp(value, (xmlChar *)prop) == 0) { 35004327Sdougm break; 35014327Sdougm } 35024327Sdougm if (value != NULL) { 35034327Sdougm xmlFree(value); 35044327Sdougm value = NULL; 35054327Sdougm } 35063034Sdougm } 35073034Sdougm } 35083034Sdougm if (value != NULL) 35093034Sdougm xmlFree(value); 35103034Sdougm if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"option") != 0) { 35114327Sdougm /* 35124327Sdougm * avoid a non option node -- it is possible to be a 35134327Sdougm * text node 35144327Sdougm */ 35154327Sdougm node = NULL; 35163034Sdougm } 35173034Sdougm return ((sa_property_t)node); 35183034Sdougm } 35193034Sdougm 35203034Sdougm /* 35213034Sdougm * sa_get_next_protocol_property(prop) 35223034Sdougm * 35233034Sdougm * Get the next protocol specific property in the list. 35243034Sdougm */ 35253034Sdougm 35263034Sdougm sa_property_t 35276007Sthurlow sa_get_next_protocol_property(sa_property_t prop, char *find) 35283034Sdougm { 35293034Sdougm xmlNodePtr node; 35306007Sthurlow xmlChar *value = NULL; 35313034Sdougm 35323034Sdougm for (node = ((xmlNodePtr)prop)->next; node != NULL; 35334327Sdougm node = node->next) { 35343034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 35356007Sthurlow if (find == NULL) 35366007Sthurlow break; 35376007Sthurlow value = xmlGetProp(node, (xmlChar *)"type"); 35386007Sthurlow if (value != NULL && 35396007Sthurlow xmlStrcasecmp(value, (xmlChar *)find) == 0) { 35406007Sthurlow break; 35416007Sthurlow } 35426007Sthurlow if (value != NULL) { 35436007Sthurlow xmlFree(value); 35446007Sthurlow value = NULL; 35456007Sthurlow } 35466007Sthurlow 35473034Sdougm } 35483034Sdougm } 35496007Sthurlow if (value != NULL) 35506007Sthurlow xmlFree(value); 35513034Sdougm return ((sa_property_t)node); 35523034Sdougm } 35533034Sdougm 35543034Sdougm /* 35553034Sdougm * sa_set_protocol_property(prop, value) 35563034Sdougm * 35573034Sdougm * Set the specified property to have the new value. The protocol 35583034Sdougm * specific plugin will then be called to update the property. 35593034Sdougm */ 35603034Sdougm 35613034Sdougm int 35626007Sthurlow sa_set_protocol_property(sa_property_t prop, char *section, char *value) 35633034Sdougm { 35643034Sdougm sa_protocol_properties_t propset; 35653034Sdougm char *proto; 35663034Sdougm int ret = SA_INVALID_PROTOCOL; 35673034Sdougm 35683034Sdougm propset = ((xmlNodePtr)prop)->parent; 35693034Sdougm if (propset != NULL) { 35704327Sdougm proto = sa_get_optionset_attr(propset, "type"); 35714327Sdougm if (proto != NULL) { 35726007Sthurlow if (section != NULL) 35736007Sthurlow set_node_attr((xmlNodePtr)prop, "section", 35746007Sthurlow section); 35754327Sdougm set_node_attr((xmlNodePtr)prop, "value", value); 35764327Sdougm ret = sa_proto_set_property(proto, prop); 35774327Sdougm sa_free_attr_string(proto); 35784327Sdougm } 35793034Sdougm } 35803034Sdougm return (ret); 35813034Sdougm } 35823034Sdougm 35833034Sdougm /* 35843034Sdougm * sa_add_protocol_property(propset, prop) 35853034Sdougm * 35865331Samw * Add a new property to the protocol specific property set. 35873034Sdougm */ 35883034Sdougm 35893034Sdougm int 35903034Sdougm sa_add_protocol_property(sa_protocol_properties_t propset, sa_property_t prop) 35913034Sdougm { 35923034Sdougm xmlNodePtr node; 35933034Sdougm 35943034Sdougm /* should check for legitimacy */ 35953034Sdougm node = xmlAddChild((xmlNodePtr)propset, (xmlNodePtr)prop); 35963034Sdougm if (node != NULL) 35974327Sdougm return (SA_OK); 35983034Sdougm return (SA_NO_MEMORY); 35993034Sdougm } 36003034Sdougm 36013034Sdougm /* 36023034Sdougm * sa_create_protocol_properties(proto) 36033034Sdougm * 36045331Samw * Create a protocol specific property set. 36053034Sdougm */ 36063034Sdougm 36073034Sdougm sa_protocol_properties_t 36083034Sdougm sa_create_protocol_properties(char *proto) 36093034Sdougm { 36103034Sdougm xmlNodePtr node; 36114327Sdougm 36123034Sdougm node = xmlNewNode(NULL, (xmlChar *)"propertyset"); 36134327Sdougm if (node != NULL) 36146007Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto); 36153034Sdougm return (node); 36163034Sdougm } 36175331Samw 36185331Samw /* 36195331Samw * sa_get_share_resource(share, resource) 36205331Samw * 36215331Samw * Get the named resource from the share, if it exists. If resource is 36225331Samw * NULL, get the first resource. 36235331Samw */ 36245331Samw 36255331Samw sa_resource_t 36265331Samw sa_get_share_resource(sa_share_t share, char *resource) 36275331Samw { 36285331Samw xmlNodePtr node = NULL; 36295331Samw xmlChar *name; 36305331Samw 36315331Samw if (share != NULL) { 36325331Samw for (node = ((xmlNodePtr)share)->children; node != NULL; 36335331Samw node = node->next) { 36345331Samw if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0) { 36355331Samw if (resource == NULL) { 36365331Samw /* 36375331Samw * We are looking for the first 36385331Samw * resource node and not a names 36395331Samw * resource. 36405331Samw */ 36415331Samw break; 36425331Samw } else { 36435331Samw /* is it the correct share? */ 36445331Samw name = xmlGetProp(node, 36455331Samw (xmlChar *)"name"); 36465331Samw if (name != NULL && 36475331Samw xmlStrcasecmp(name, 36485331Samw (xmlChar *)resource) == 0) { 36495331Samw xmlFree(name); 36505331Samw break; 36515331Samw } 36525331Samw xmlFree(name); 36535331Samw } 36545331Samw } 36555331Samw } 36565331Samw } 36575331Samw return ((sa_resource_t)node); 36585331Samw } 36595331Samw 36605331Samw /* 36615331Samw * sa_get_next_resource(resource) 36625331Samw * Return the next share following the specified share 36635331Samw * from the internal list of shares. Returns NULL if there 36645331Samw * are no more shares. The list is relative to the same 36655331Samw * group. 36665331Samw */ 36675331Samw sa_share_t 36685331Samw sa_get_next_resource(sa_resource_t resource) 36695331Samw { 36705331Samw xmlNodePtr node = NULL; 36715331Samw 36725331Samw if (resource != NULL) { 36735331Samw for (node = ((xmlNodePtr)resource)->next; node != NULL; 36745331Samw node = node->next) { 36755331Samw if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0) 36765331Samw break; 36775331Samw } 36785331Samw } 36795331Samw return ((sa_share_t)node); 36805331Samw } 36815331Samw 36825331Samw /* 36835331Samw * _sa_get_next_resource_index(share) 36845331Samw * 36855331Samw * get the next resource index number (one greater then current largest) 36865331Samw */ 36875331Samw 36885331Samw static int 36895331Samw _sa_get_next_resource_index(sa_share_t share) 36905331Samw { 36915331Samw sa_resource_t resource; 36925331Samw int index = 0; 36935331Samw char *id; 36945331Samw 36955331Samw for (resource = sa_get_share_resource(share, NULL); 36965331Samw resource != NULL; 36975331Samw resource = sa_get_next_resource(resource)) { 36985331Samw id = get_node_attr((void *)resource, "id"); 36995331Samw if (id != NULL) { 37005331Samw int val; 37015331Samw val = atoi(id); 37025331Samw if (val > index) 37035331Samw index = val; 37045331Samw sa_free_attr_string(id); 37055331Samw } 37065331Samw } 37075331Samw return (index + 1); 37085331Samw } 37095331Samw 37105331Samw 37115331Samw /* 37125331Samw * sa_add_resource(share, resource, persist, &err) 37135331Samw * 37145331Samw * Adds a new resource name associated with share. The resource name 37155331Samw * must be unique in the system and will be case insensitive (eventually). 37165331Samw */ 37175331Samw 37185331Samw sa_resource_t 37195331Samw sa_add_resource(sa_share_t share, char *resource, int persist, int *error) 37205331Samw { 37215331Samw xmlNodePtr node; 37225331Samw int err = SA_OK; 37235331Samw sa_resource_t res; 37245331Samw sa_group_t group; 37255331Samw sa_handle_t handle; 37265331Samw char istring[8]; /* just big enough for an integer value */ 37275331Samw int index; 37285331Samw 37295331Samw group = sa_get_parent_group(share); 37305331Samw handle = sa_find_group_handle(group); 37315331Samw res = sa_find_resource(handle, resource); 37325331Samw if (res != NULL) { 37335331Samw err = SA_DUPLICATE_NAME; 37345331Samw res = NULL; 37355331Samw } else { 37365331Samw node = xmlNewChild((xmlNodePtr)share, NULL, 37375331Samw (xmlChar *)"resource", NULL); 37385331Samw if (node != NULL) { 37396007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 37405331Samw (xmlChar *)resource); 37416007Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", persist ? 37425331Samw (xmlChar *)"persist" : (xmlChar *)"transient"); 37435331Samw if (persist != SA_SHARE_TRANSIENT) { 37445331Samw index = _sa_get_next_resource_index(share); 37455331Samw (void) snprintf(istring, sizeof (istring), "%d", 37465331Samw index); 37476007Sthurlow (void) xmlSetProp(node, (xmlChar *)"id", 37485331Samw (xmlChar *)istring); 37495331Samw if (!sa_group_is_zfs(group) && 37505331Samw sa_is_persistent((sa_group_t)share)) { 37515331Samw /* ZFS doesn't use resource names */ 37525331Samw sa_handle_impl_t ihandle; 37535331Samw ihandle = (sa_handle_impl_t) 37545331Samw sa_find_group_handle( 37555331Samw group); 37565331Samw if (ihandle != NULL) 37575331Samw err = sa_commit_share( 37585331Samw ihandle->scfhandle, group, 37595331Samw share); 37605331Samw else 37615331Samw err = SA_SYSTEM_ERR; 37625331Samw } 37635331Samw } 37645331Samw } 37655331Samw } 37665331Samw if (error != NULL) 37675331Samw *error = err; 37685331Samw return ((sa_resource_t)node); 37695331Samw } 37705331Samw 37715331Samw /* 37725331Samw * sa_remove_resource(resource) 37735331Samw * 37745331Samw * Remove the resource name from the share (and the system) 37755331Samw */ 37765331Samw 37775331Samw int 37785331Samw sa_remove_resource(sa_resource_t resource) 37795331Samw { 37805331Samw sa_share_t share; 37815331Samw sa_group_t group; 37825331Samw char *type; 37835331Samw int ret = SA_OK; 37845331Samw int transient = 0; 37855521Sas200622 sa_optionset_t opt; 37865331Samw 37875331Samw share = sa_get_resource_parent(resource); 37885331Samw type = sa_get_share_attr(share, "type"); 37895331Samw group = sa_get_parent_group(share); 37905331Samw 37915331Samw 37925331Samw if (type != NULL) { 37935331Samw if (strcmp(type, "persist") != 0) 37945331Samw transient = 1; 37955331Samw sa_free_attr_string(type); 37965331Samw } 37975331Samw 37985521Sas200622 /* Disable the resource for all protocols. */ 37995521Sas200622 (void) sa_disable_resource(resource, NULL); 38005521Sas200622 38015521Sas200622 /* Remove any optionsets from the resource. */ 38025521Sas200622 for (opt = sa_get_optionset(resource, NULL); 38035521Sas200622 opt != NULL; 38045521Sas200622 opt = sa_get_next_optionset(opt)) 38055521Sas200622 (void) sa_destroy_optionset(opt); 38065521Sas200622 38075331Samw /* Remove from the share */ 38085331Samw xmlUnlinkNode((xmlNode *)resource); 38095331Samw xmlFreeNode((xmlNode *)resource); 38105331Samw 38115331Samw /* only do SMF action if permanent and not ZFS */ 38125331Samw if (!transient && !sa_group_is_zfs(group)) { 38135331Samw sa_handle_impl_t ihandle; 38145331Samw ihandle = (sa_handle_impl_t)sa_find_group_handle(group); 38155331Samw if (ihandle != NULL) 38165331Samw ret = sa_commit_share(ihandle->scfhandle, group, share); 38175331Samw else 38185331Samw ret = SA_SYSTEM_ERR; 38195331Samw } 38205331Samw return (ret); 38215331Samw } 38225331Samw 38235331Samw /* 38245331Samw * proto_resource_rename(handle, group, resource, newname) 38255331Samw * 38265331Samw * Helper function for sa_rename_resource that notifies the protocol 38275331Samw * of a resource name change prior to a config repository update. 38285331Samw */ 38295331Samw static int 38305331Samw proto_rename_resource(sa_handle_t handle, sa_group_t group, 38315331Samw sa_resource_t resource, char *newname) 38325331Samw { 38335331Samw sa_optionset_t optionset; 38345331Samw int ret = SA_OK; 38355331Samw int err; 38365331Samw 38375331Samw for (optionset = sa_get_optionset(group, NULL); 38385331Samw optionset != NULL; 38395331Samw optionset = sa_get_next_optionset(optionset)) { 38405331Samw char *type; 38415331Samw type = sa_get_optionset_attr(optionset, "type"); 38425331Samw if (type != NULL) { 38435331Samw err = sa_proto_rename_resource(handle, type, resource, 38445331Samw newname); 38455331Samw if (err != SA_OK) 38465331Samw ret = err; 38475331Samw sa_free_attr_string(type); 38485331Samw } 38495331Samw } 38505331Samw return (ret); 38515331Samw } 38525331Samw 38535331Samw /* 38545331Samw * sa_rename_resource(resource, newname) 38555331Samw * 38565331Samw * Rename the resource to the new name, if it is unique. 38575331Samw */ 38585331Samw 38595331Samw int 38605331Samw sa_rename_resource(sa_resource_t resource, char *newname) 38615331Samw { 38625331Samw sa_share_t share; 38635331Samw sa_group_t group = NULL; 38645331Samw sa_resource_t target; 38655331Samw int ret = SA_CONFIG_ERR; 38665331Samw sa_handle_t handle = NULL; 38675331Samw 38685331Samw share = sa_get_resource_parent(resource); 38695331Samw if (share == NULL) 38705331Samw return (ret); 38715331Samw 38725331Samw group = sa_get_parent_group(share); 38735331Samw if (group == NULL) 38745331Samw return (ret); 38755331Samw 38765331Samw handle = (sa_handle_impl_t)sa_find_group_handle(group); 38775331Samw if (handle == NULL) 38785331Samw return (ret); 38795331Samw 38805331Samw target = sa_find_resource(handle, newname); 38815331Samw if (target != NULL) { 38825331Samw ret = SA_DUPLICATE_NAME; 38835331Samw } else { 38845331Samw /* 38855331Samw * Everything appears to be valid at this 38865331Samw * point. Change the name of the active share and then 38875331Samw * update the share in the appropriate repository. 38885331Samw */ 38895331Samw ret = proto_rename_resource(handle, group, resource, newname); 38905331Samw set_node_attr(resource, "name", newname); 38915331Samw if (!sa_group_is_zfs(group) && 38925331Samw sa_is_persistent((sa_group_t)share)) { 38935331Samw sa_handle_impl_t ihandle = (sa_handle_impl_t)handle; 38945331Samw ret = sa_commit_share(ihandle->scfhandle, group, 38955331Samw share); 38965331Samw } 38975331Samw } 38985331Samw return (ret); 38995331Samw } 39005331Samw 39015331Samw /* 39025331Samw * sa_get_resource_attr(resource, tag) 39035331Samw * 39045331Samw * Get the named attribute of the resource. "name" and "id" are 39055331Samw * currently defined. NULL if tag not defined. 39065331Samw */ 39075331Samw 39085331Samw char * 39095331Samw sa_get_resource_attr(sa_resource_t resource, char *tag) 39105331Samw { 39115331Samw return (get_node_attr((void *)resource, tag)); 39125331Samw } 39135331Samw 39145331Samw /* 39155331Samw * sa_set_resource_attr(resource, tag, value) 39165331Samw * 39175331Samw * Get the named attribute of the resource. "name" and "id" are 39185331Samw * currently defined. NULL if tag not defined. Currently we don't do 39195331Samw * much, but additional checking may be needed in the future. 39205331Samw */ 39215331Samw 39225331Samw int 39235331Samw sa_set_resource_attr(sa_resource_t resource, char *tag, char *value) 39245331Samw { 39255331Samw set_node_attr((void *)resource, tag, value); 39265331Samw return (SA_OK); 39275331Samw } 39285331Samw 39295331Samw /* 39305331Samw * sa_get_resource_parent(resource_t) 39315331Samw * 39325331Samw * Returns the share associated with the resource. 39335331Samw */ 39345331Samw 39355331Samw sa_share_t 39365331Samw sa_get_resource_parent(sa_resource_t resource) 39375331Samw { 39385331Samw sa_share_t share = NULL; 39395331Samw 39405331Samw if (resource != NULL) 39415331Samw share = (sa_share_t)((xmlNodePtr)resource)->parent; 39425331Samw return (share); 39435331Samw } 39445331Samw 39455331Samw /* 39465331Samw * find_resource(group, name) 39475331Samw * 39485331Samw * Find the resource within the group. 39495331Samw */ 39505331Samw 39515331Samw static sa_resource_t 39525331Samw find_resource(sa_group_t group, char *resname) 39535331Samw { 39545331Samw sa_share_t share; 39555331Samw sa_resource_t resource = NULL; 39565331Samw char *name; 39575331Samw 39585331Samw /* Iterate over all the shares and resources in the group. */ 39595331Samw for (share = sa_get_share(group, NULL); 39605331Samw share != NULL && resource == NULL; 39615331Samw share = sa_get_next_share(share)) { 39625331Samw for (resource = sa_get_share_resource(share, NULL); 39635331Samw resource != NULL; 39645331Samw resource = sa_get_next_resource(resource)) { 39655331Samw name = sa_get_resource_attr(resource, "name"); 39665331Samw if (name != NULL && xmlStrcasecmp((xmlChar*)name, 39675331Samw (xmlChar*)resname) == 0) { 39685331Samw sa_free_attr_string(name); 39695331Samw break; 39705331Samw } 39715331Samw if (name != NULL) { 39725331Samw sa_free_attr_string(name); 39735331Samw } 39745331Samw } 39755331Samw } 39765331Samw return (resource); 39775331Samw } 39785331Samw 39795331Samw /* 39805331Samw * sa_find_resource(name) 39815331Samw * 39825331Samw * Find the named resource in the system. 39835331Samw */ 39845331Samw 39855331Samw sa_resource_t 39865331Samw sa_find_resource(sa_handle_t handle, char *name) 39875331Samw { 39885331Samw sa_group_t group; 39895331Samw sa_group_t zgroup; 39905331Samw sa_resource_t resource = NULL; 39915331Samw 39925331Samw /* 39935331Samw * Iterate over all groups and zfs subgroups and check for 39945331Samw * resource name in them. 39955331Samw */ 39965331Samw for (group = sa_get_group(handle, NULL); group != NULL; 39975331Samw group = sa_get_next_group(group)) { 39985331Samw 39995331Samw if (is_zfs_group(group)) { 40005331Samw for (zgroup = 40015331Samw (sa_group_t)_sa_get_child_node((xmlNodePtr)group, 40025331Samw (xmlChar *)"group"); 40035331Samw zgroup != NULL && resource == NULL; 40045331Samw zgroup = sa_get_next_group(zgroup)) { 40055331Samw resource = find_resource(zgroup, name); 40065331Samw } 40075331Samw } else { 40085331Samw resource = find_resource(group, name); 40095331Samw } 40105331Samw if (resource != NULL) 40115331Samw break; 40125331Samw } 40135331Samw return (resource); 40145331Samw } 40155331Samw 40165331Samw /* 40175331Samw * sa_get_resource(group, resource) 40185331Samw * 40195331Samw * Search all the shares in the specified group for a share with a 40205331Samw * resource name matching the one specified. 40215331Samw * 40225331Samw * In the future, it may be advantageous to allow group to be NULL and 40235331Samw * search all groups but that isn't needed at present. 40245331Samw */ 40255331Samw 40265331Samw sa_resource_t 40275331Samw sa_get_resource(sa_group_t group, char *resource) 40285331Samw { 40295331Samw sa_share_t share = NULL; 40305331Samw sa_resource_t res = NULL; 40315331Samw 40325331Samw if (resource != NULL) { 40335331Samw for (share = sa_get_share(group, NULL); 40345331Samw share != NULL && res == NULL; 40355331Samw share = sa_get_next_share(share)) { 40365331Samw res = sa_get_share_resource(share, resource); 40375331Samw } 40385331Samw } 40395331Samw return (res); 40405331Samw } 40415331Samw 40425331Samw /* 40436270Sdougm * get_protocol_list(optionset, object) 40446270Sdougm * 40456270Sdougm * Get the protocol optionset list for the object and add them as 40466270Sdougm * properties to optionset. 40476270Sdougm */ 40486270Sdougm static int 40496270Sdougm get_protocol_list(sa_optionset_t optionset, void *object) 40506270Sdougm { 40516270Sdougm sa_property_t prop; 40526270Sdougm sa_optionset_t opts; 40536270Sdougm int ret = SA_OK; 40546270Sdougm 40556270Sdougm for (opts = sa_get_optionset(object, NULL); 40566270Sdougm opts != NULL; 40576270Sdougm opts = sa_get_next_optionset(opts)) { 40586270Sdougm char *type; 40596270Sdougm type = sa_get_optionset_attr(opts, "type"); 40606270Sdougm /* 40616270Sdougm * It is possible to have a non-protocol optionset. We 40626270Sdougm * skip any of those found. 40636270Sdougm */ 40646270Sdougm if (type == NULL) 40656270Sdougm continue; 40666270Sdougm prop = sa_create_property(type, "true"); 40676270Sdougm sa_free_attr_string(type); 40686270Sdougm if (prop != NULL) 40696270Sdougm prop = (sa_property_t)xmlAddChild((xmlNodePtr)optionset, 40706270Sdougm (xmlNodePtr)prop); 40716270Sdougm /* If prop is NULL, don't bother continuing */ 40726270Sdougm if (prop == NULL) { 40736270Sdougm ret = SA_NO_MEMORY; 40746270Sdougm break; 40756270Sdougm } 40766270Sdougm } 40776270Sdougm return (ret); 40786270Sdougm } 40796270Sdougm 40806270Sdougm /* 40816270Sdougm * sa_free_protoset(optionset) 40826270Sdougm * 40836270Sdougm * Free the protocol property optionset. 40846270Sdougm */ 40856270Sdougm static void 40866270Sdougm sa_free_protoset(sa_optionset_t optionset) 40876270Sdougm { 40886270Sdougm if (optionset != NULL) { 40896270Sdougm xmlUnlinkNode((xmlNodePtr) optionset); 40906270Sdougm xmlFreeNode((xmlNodePtr) optionset); 40916270Sdougm } 40926270Sdougm } 40936270Sdougm 40946270Sdougm /* 40956270Sdougm * sa_optionset_t sa_get_active_protocols(object) 40966270Sdougm * 40976270Sdougm * Return a list of the protocols that are active for the object. 40986270Sdougm * This is currently an internal helper function, but could be 40996270Sdougm * made visible if there is enough demand for it. 41006270Sdougm * 41016270Sdougm * The function finds the parent group and extracts the protocol 41026270Sdougm * optionsets creating a new optionset with the protocols as properties. 41036270Sdougm * 41046270Sdougm * The caller must free the returned optionset. 41056270Sdougm */ 41066270Sdougm 41076270Sdougm static sa_optionset_t 41086270Sdougm sa_get_active_protocols(void *object) 41096270Sdougm { 41106270Sdougm sa_optionset_t options; 41116270Sdougm sa_share_t share = NULL; 41126270Sdougm sa_group_t group = NULL; 41136270Sdougm sa_resource_t resource = NULL; 41146270Sdougm int ret = SA_OK; 41156270Sdougm 41166270Sdougm if (object == NULL) 41176270Sdougm return (NULL); 41186270Sdougm options = (sa_optionset_t)xmlNewNode(NULL, (xmlChar *)"optionset"); 41196270Sdougm if (options == NULL) 41206270Sdougm return (NULL); 41216270Sdougm 41226270Sdougm /* 41236270Sdougm * Find the objects up the tree that might have protocols 41246270Sdougm * enabled on them. 41256270Sdougm */ 41266270Sdougm if (sa_is_resource(object)) { 41276270Sdougm resource = (sa_resource_t)object; 41286270Sdougm share = sa_get_resource_parent(resource); 41296270Sdougm group = sa_get_parent_group(share); 41306270Sdougm } else if (sa_is_share(object)) { 41316270Sdougm share = (sa_share_t)object; 41326270Sdougm group = sa_get_parent_group(share); 41336270Sdougm } else { 41346270Sdougm group = (sa_group_t)group; 41356270Sdougm } 41366270Sdougm if (resource != NULL) 41376270Sdougm ret = get_protocol_list(options, resource); 41386270Sdougm if (ret == SA_OK && share != NULL) 41396270Sdougm ret = get_protocol_list(options, share); 41406270Sdougm if (ret == SA_OK && group != NULL) 41416270Sdougm ret = get_protocol_list(options, group); 41426270Sdougm 41436270Sdougm /* 41446270Sdougm * If there was an error, we won't have a complete list so 41456270Sdougm * abandon everything. The caller will have to deal with the 41466270Sdougm * issue. 41476270Sdougm */ 41486270Sdougm if (ret != SA_OK) { 41496270Sdougm sa_free_protoset(options); 41506270Sdougm options = NULL; 41516270Sdougm } 41526270Sdougm return (options); 41536270Sdougm } 41546270Sdougm 41556270Sdougm /* 41565331Samw * sa_enable_resource, protocol) 41575331Samw * Disable the specified share to the specified protocol. 41585331Samw * If protocol is NULL, then all protocols. 41595331Samw */ 41605331Samw int 41615331Samw sa_enable_resource(sa_resource_t resource, char *protocol) 41625331Samw { 41635331Samw int ret = SA_OK; 41645331Samw 41655331Samw if (protocol != NULL) { 41665331Samw ret = sa_proto_share_resource(protocol, resource); 41675331Samw } else { 41686270Sdougm sa_optionset_t protoset; 41696270Sdougm sa_property_t prop; 41706270Sdougm char *proto; 41716270Sdougm int err; 41726270Sdougm 41735331Samw /* need to do all protocols */ 41746270Sdougm protoset = sa_get_active_protocols(resource); 41756270Sdougm if (protoset == NULL) 41766270Sdougm return (SA_NO_MEMORY); 41776270Sdougm for (prop = sa_get_property(protoset, NULL); 41786270Sdougm prop != NULL; 41796270Sdougm prop = sa_get_next_property(prop)) { 41806270Sdougm proto = sa_get_property_attr(prop, "type"); 41816270Sdougm if (proto == NULL) { 41826270Sdougm ret = SA_NO_MEMORY; 41836270Sdougm continue; 41845331Samw } 41856270Sdougm err = sa_proto_share_resource(proto, resource); 41866270Sdougm if (err != SA_OK) 41876270Sdougm ret = err; 41886270Sdougm sa_free_attr_string(proto); 41895331Samw } 41906270Sdougm sa_free_protoset(protoset); 41915331Samw } 41925331Samw if (ret == SA_OK) 41935331Samw (void) sa_set_resource_attr(resource, "shared", NULL); 41945331Samw 41955331Samw return (ret); 41965331Samw } 41975331Samw 41985331Samw /* 41995331Samw * sa_disable_resource(resource, protocol) 42005331Samw * 42015331Samw * Disable the specified share for the specified protocol. If 42025331Samw * protocol is NULL, then all protocols. If the underlying 42035331Samw * protocol doesn't implement disable at the resource level, we 42045331Samw * disable at the share level. 42055331Samw */ 42065331Samw int 42075331Samw sa_disable_resource(sa_resource_t resource, char *protocol) 42085331Samw { 42095331Samw int ret = SA_OK; 42105331Samw 42115331Samw if (protocol != NULL) { 42125331Samw ret = sa_proto_unshare_resource(protocol, resource); 42135331Samw if (ret == SA_NOT_IMPLEMENTED) { 42145331Samw sa_share_t parent; 42155331Samw /* 42165331Samw * The protocol doesn't implement unshare 42175331Samw * resource. That implies that resource names are 42185331Samw * simple aliases for this protocol so we need to 42195331Samw * unshare the share. 42205331Samw */ 42215331Samw parent = sa_get_resource_parent(resource); 42225331Samw if (parent != NULL) 42235331Samw ret = sa_disable_share(parent, protocol); 42245331Samw else 42255331Samw ret = SA_CONFIG_ERR; 42265331Samw } 42275331Samw } else { 42286270Sdougm sa_optionset_t protoset; 42296270Sdougm sa_property_t prop; 42306270Sdougm char *proto; 42316270Sdougm int err; 42326270Sdougm 42335331Samw /* need to do all protocols */ 42346270Sdougm protoset = sa_get_active_protocols(resource); 42356270Sdougm if (protoset == NULL) 42366270Sdougm return (SA_NO_MEMORY); 42376270Sdougm for (prop = sa_get_property(protoset, NULL); 42386270Sdougm prop != NULL; 42396270Sdougm prop = sa_get_next_property(prop)) { 42406270Sdougm proto = sa_get_property_attr(prop, "type"); 42416270Sdougm if (proto == NULL) { 42426270Sdougm ret = SA_NO_MEMORY; 42436270Sdougm continue; 42445331Samw } 42456270Sdougm err = sa_proto_unshare_resource(proto, resource); 42466270Sdougm if (err == SA_NOT_SUPPORTED) { 42476270Sdougm sa_share_t parent; 42486270Sdougm parent = sa_get_resource_parent(resource); 42496270Sdougm if (parent != NULL) 42506270Sdougm err = sa_disable_share(parent, proto); 42516270Sdougm else 42526270Sdougm err = SA_CONFIG_ERR; 42536270Sdougm } 42546270Sdougm if (err != SA_OK) 42556270Sdougm ret = err; 42566270Sdougm sa_free_attr_string(proto); 42575331Samw } 42586270Sdougm sa_free_protoset(protoset); 42595331Samw } 42605331Samw if (ret == SA_OK) 42615331Samw (void) sa_set_resource_attr(resource, "shared", NULL); 42625331Samw 42635331Samw return (ret); 42645331Samw } 42655331Samw 42665331Samw /* 42675331Samw * sa_set_resource_description(resource, content) 42685331Samw * 42695331Samw * Set the description of share to content. 42705331Samw */ 42715331Samw 42725331Samw int 42735331Samw sa_set_resource_description(sa_resource_t resource, char *content) 42745331Samw { 42755331Samw xmlNodePtr node; 42765331Samw sa_group_t group; 42775331Samw sa_share_t share; 42785331Samw int ret = SA_OK; 42795331Samw 42805331Samw for (node = ((xmlNodePtr)resource)->children; 42815331Samw node != NULL; 42825331Samw node = node->next) { 42835331Samw if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 42845331Samw break; 42855331Samw } 42865331Samw } 42875331Samw 42885331Samw /* no existing description but want to add */ 42895331Samw if (node == NULL && content != NULL) { 42905331Samw /* add a description */ 42915331Samw node = _sa_set_share_description(resource, content); 42925331Samw } else if (node != NULL && content != NULL) { 42935331Samw /* update a description */ 42945331Samw xmlNodeSetContent(node, (xmlChar *)content); 42955331Samw } else if (node != NULL && content == NULL) { 42965331Samw /* remove an existing description */ 42975331Samw xmlUnlinkNode(node); 42985331Samw xmlFreeNode(node); 42995331Samw } 43005331Samw share = sa_get_resource_parent(resource); 43015331Samw group = sa_get_parent_group(share); 43025331Samw if (group != NULL && sa_is_persistent(share)) { 43035331Samw sa_handle_impl_t impl_handle; 43045331Samw impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 43055331Samw if (impl_handle != NULL) 43065331Samw ret = sa_commit_share(impl_handle->scfhandle, 43075331Samw group, share); 43085331Samw else 43095331Samw ret = SA_SYSTEM_ERR; 43105331Samw } 43115331Samw return (ret); 43125331Samw } 43135331Samw 43145331Samw /* 43155331Samw * sa_get_resource_description(share) 43165331Samw * 43175331Samw * Return the description text for the specified share if it 43185331Samw * exists. NULL if no description exists. 43195331Samw */ 43205331Samw 43215331Samw char * 43225331Samw sa_get_resource_description(sa_resource_t resource) 43235331Samw { 43245331Samw xmlChar *description = NULL; 43255331Samw xmlNodePtr node; 43265331Samw 43275331Samw for (node = ((xmlNodePtr)resource)->children; node != NULL; 43285331Samw node = node->next) { 43295331Samw if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) 43305331Samw break; 43315331Samw } 43325331Samw if (node != NULL) { 43335331Samw description = xmlNodeGetContent(node); 43345331Samw fixproblemchars((char *)description); 43355331Samw } 43365331Samw return ((char *)description); 43375331Samw } 4338