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 int sa_valid_property(void *, char *, sa_property_t); 733034Sdougm extern char *sa_fstype(char *); 743034Sdougm extern int sa_is_share(void *); 755331Samw extern int sa_is_resource(void *); 763034Sdougm extern ssize_t scf_max_name_len; /* defined in scfutil during initialization */ 773034Sdougm extern int sa_group_is_zfs(sa_group_t); 783034Sdougm extern int sa_path_is_zfs(char *); 793034Sdougm extern int sa_zfs_set_sharenfs(sa_group_t, char *, int); 805331Samw extern int sa_zfs_set_sharesmb(sa_group_t, char *, int); 813910Sdougm extern void update_legacy_config(sa_handle_t); 823034Sdougm extern int issubdir(char *, char *); 834327Sdougm extern int sa_zfs_init(sa_handle_impl_t); 843910Sdougm extern void sa_zfs_fini(sa_handle_impl_t); 853663Sdougm extern void sablocksigs(sigset_t *); 863663Sdougm extern void saunblocksigs(sigset_t *); 875331Samw static sa_group_t sa_get_optionset_parent(sa_optionset_t); 885331Samw static char *get_node_attr(void *, char *); 895951Sdougm extern void sa_update_sharetab_ts(sa_handle_t); 903034Sdougm 913910Sdougm /* 923910Sdougm * Data structures for finding/managing the document root to access 933910Sdougm * handle mapping. The list isn't expected to grow very large so a 943910Sdougm * simple list is acceptable. The purpose is to provide a way to start 953910Sdougm * with a group or share and find the library handle needed for 963910Sdougm * various operations. 973910Sdougm */ 983910Sdougm mutex_t sa_global_lock; 993910Sdougm struct doc2handle { 1003910Sdougm struct doc2handle *next; 1013910Sdougm xmlNodePtr root; 1023910Sdougm sa_handle_impl_t handle; 1033910Sdougm }; 1043910Sdougm 1054327Sdougm /* definitions used in a couple of property functions */ 1064327Sdougm #define SA_PROP_OP_REMOVE 1 1074327Sdougm #define SA_PROP_OP_ADD 2 1084327Sdougm #define SA_PROP_OP_UPDATE 3 1094327Sdougm 1103910Sdougm static struct doc2handle *sa_global_handles = NULL; 1113034Sdougm 1123034Sdougm /* helper functions */ 1133034Sdougm 1143910Sdougm /* 1153910Sdougm * sa_errorstr(err) 1163910Sdougm * 1173910Sdougm * convert an error value to an error string 1183910Sdougm */ 1193910Sdougm 1203034Sdougm char * 1213034Sdougm sa_errorstr(int err) 1223034Sdougm { 1233034Sdougm static char errstr[32]; 1243034Sdougm char *ret = NULL; 1253034Sdougm 1263034Sdougm switch (err) { 1273034Sdougm case SA_OK: 1284327Sdougm ret = dgettext(TEXT_DOMAIN, "ok"); 1294327Sdougm break; 1303034Sdougm case SA_NO_SUCH_PATH: 1314327Sdougm ret = dgettext(TEXT_DOMAIN, "path doesn't exist"); 1324327Sdougm break; 1333034Sdougm case SA_NO_MEMORY: 1344327Sdougm ret = dgettext(TEXT_DOMAIN, "no memory"); 1354327Sdougm break; 1363034Sdougm case SA_DUPLICATE_NAME: 1374327Sdougm ret = dgettext(TEXT_DOMAIN, "name in use"); 1384327Sdougm break; 1393034Sdougm case SA_BAD_PATH: 1404327Sdougm ret = dgettext(TEXT_DOMAIN, "bad path"); 1414327Sdougm break; 1423034Sdougm case SA_NO_SUCH_GROUP: 1434327Sdougm ret = dgettext(TEXT_DOMAIN, "no such group"); 1444327Sdougm break; 1453034Sdougm case SA_CONFIG_ERR: 1464327Sdougm ret = dgettext(TEXT_DOMAIN, "configuration error"); 1474327Sdougm break; 1483034Sdougm case SA_SYSTEM_ERR: 1494327Sdougm ret = dgettext(TEXT_DOMAIN, "system error"); 1504327Sdougm break; 1513034Sdougm case SA_SYNTAX_ERR: 1524327Sdougm ret = dgettext(TEXT_DOMAIN, "syntax error"); 1534327Sdougm break; 1543034Sdougm case SA_NO_PERMISSION: 1554327Sdougm ret = dgettext(TEXT_DOMAIN, "no permission"); 1564327Sdougm break; 1573034Sdougm case SA_BUSY: 1584327Sdougm ret = dgettext(TEXT_DOMAIN, "busy"); 1594327Sdougm break; 1603034Sdougm case SA_NO_SUCH_PROP: 1614327Sdougm ret = dgettext(TEXT_DOMAIN, "no such property"); 1624327Sdougm break; 1633034Sdougm case SA_INVALID_NAME: 1644327Sdougm ret = dgettext(TEXT_DOMAIN, "invalid name"); 1654327Sdougm break; 1663034Sdougm case SA_INVALID_PROTOCOL: 1674327Sdougm ret = dgettext(TEXT_DOMAIN, "invalid protocol"); 1684327Sdougm break; 1693034Sdougm case SA_NOT_ALLOWED: 1704327Sdougm ret = dgettext(TEXT_DOMAIN, "operation not allowed"); 1714327Sdougm break; 1723034Sdougm case SA_BAD_VALUE: 1734327Sdougm ret = dgettext(TEXT_DOMAIN, "bad property value"); 1744327Sdougm break; 1753034Sdougm case SA_INVALID_SECURITY: 1764327Sdougm ret = dgettext(TEXT_DOMAIN, "invalid security type"); 1774327Sdougm break; 1783034Sdougm case SA_NO_SUCH_SECURITY: 1794327Sdougm ret = dgettext(TEXT_DOMAIN, "security type not found"); 1804327Sdougm break; 1813034Sdougm case SA_VALUE_CONFLICT: 1824327Sdougm ret = dgettext(TEXT_DOMAIN, "property value conflict"); 1834327Sdougm break; 1843034Sdougm case SA_NOT_IMPLEMENTED: 1854327Sdougm ret = dgettext(TEXT_DOMAIN, "not implemented"); 1864327Sdougm break; 1873034Sdougm case SA_INVALID_PATH: 1884327Sdougm ret = dgettext(TEXT_DOMAIN, "invalid path"); 1894327Sdougm break; 1903034Sdougm case SA_NOT_SUPPORTED: 1914327Sdougm ret = dgettext(TEXT_DOMAIN, "operation not supported"); 1924327Sdougm break; 1933034Sdougm case SA_PROP_SHARE_ONLY: 1944327Sdougm ret = dgettext(TEXT_DOMAIN, "property not valid for group"); 1954327Sdougm break; 1963034Sdougm case SA_NOT_SHARED: 1974327Sdougm ret = dgettext(TEXT_DOMAIN, "not shared"); 1984327Sdougm break; 1995331Samw case SA_NO_SUCH_RESOURCE: 2005331Samw ret = dgettext(TEXT_DOMAIN, "no such resource"); 2015331Samw break; 2025331Samw case SA_RESOURCE_REQUIRED: 2035331Samw ret = dgettext(TEXT_DOMAIN, "resource name required"); 2045331Samw break; 2055331Samw case SA_MULTIPLE_ERROR: 2065331Samw ret = dgettext(TEXT_DOMAIN, "errors from multiple protocols"); 2075331Samw break; 2085331Samw case SA_PATH_IS_SUBDIR: 2095331Samw ret = dgettext(TEXT_DOMAIN, "path is a subpath of share"); 2105331Samw break; 2115331Samw case SA_PATH_IS_PARENTDIR: 2125331Samw ret = dgettext(TEXT_DOMAIN, "path is parent of a share"); 2135331Samw break; 214*6007Sthurlow case SA_NO_SECTION: 215*6007Sthurlow ret = dgettext(TEXT_DOMAIN, "protocol requires a section"); 216*6007Sthurlow break; 217*6007Sthurlow case SA_NO_PROPERTIES: 218*6007Sthurlow ret = dgettext(TEXT_DOMAIN, "properties not found"); 219*6007Sthurlow break; 220*6007Sthurlow case SA_NO_SUCH_SECTION: 221*6007Sthurlow ret = dgettext(TEXT_DOMAIN, "section not found"); 222*6007Sthurlow break; 223*6007Sthurlow case SA_PASSWORD_ENC: 224*6007Sthurlow ret = dgettext(TEXT_DOMAIN, "passwords must be encrypted"); 225*6007Sthurlow break; 2263034Sdougm default: 2274327Sdougm (void) snprintf(errstr, sizeof (errstr), 2284327Sdougm dgettext(TEXT_DOMAIN, "unknown %d"), err); 2294327Sdougm ret = errstr; 2303034Sdougm } 2313034Sdougm return (ret); 2323034Sdougm } 2333034Sdougm 2343034Sdougm /* 2353910Sdougm * Document root to active handle mapping functions. These are only 2363910Sdougm * used internally. A mutex is used to prevent access while the list 2373910Sdougm * is changing. In general, the list will be relatively short - one 2383910Sdougm * item per thread that has called sa_init(). 2393910Sdougm */ 2403910Sdougm 2413910Sdougm sa_handle_impl_t 2423910Sdougm get_handle_for_root(xmlNodePtr root) 2433910Sdougm { 2443910Sdougm struct doc2handle *item; 2453910Sdougm 2463910Sdougm (void) mutex_lock(&sa_global_lock); 2473910Sdougm for (item = sa_global_handles; item != NULL; item = item->next) { 2484327Sdougm if (item->root == root) 2494327Sdougm break; 2503910Sdougm } 2513910Sdougm (void) mutex_unlock(&sa_global_lock); 2523910Sdougm if (item != NULL) 2534327Sdougm return (item->handle); 2543910Sdougm return (NULL); 2553910Sdougm } 2563910Sdougm 2573910Sdougm static int 2583910Sdougm add_handle_for_root(xmlNodePtr root, sa_handle_impl_t handle) 2593910Sdougm { 2603910Sdougm struct doc2handle *item; 2613910Sdougm int ret = SA_NO_MEMORY; 2623910Sdougm 2633910Sdougm item = (struct doc2handle *)calloc(sizeof (struct doc2handle), 1); 2643910Sdougm if (item != NULL) { 2654327Sdougm item->root = root; 2664327Sdougm item->handle = handle; 2674327Sdougm (void) mutex_lock(&sa_global_lock); 2684327Sdougm item->next = sa_global_handles; 2694327Sdougm sa_global_handles = item; 2704327Sdougm (void) mutex_unlock(&sa_global_lock); 2714327Sdougm ret = SA_OK; 2723910Sdougm } 2733910Sdougm return (ret); 2743910Sdougm } 2753910Sdougm 2763910Sdougm /* 2773910Sdougm * remove_handle_for_root(root) 2783910Sdougm * 2793910Sdougm * Walks the list of handles and removes the one for this "root" from 2803910Sdougm * the list. It is up to the caller to free the data. 2813910Sdougm */ 2823910Sdougm 2833910Sdougm static void 2843910Sdougm remove_handle_for_root(xmlNodePtr root) 2853910Sdougm { 2863910Sdougm struct doc2handle *item, *prev; 2873910Sdougm 2883910Sdougm (void) mutex_lock(&sa_global_lock); 2893910Sdougm for (prev = NULL, item = sa_global_handles; item != NULL; 2904327Sdougm item = item->next) { 2914327Sdougm if (item->root == root) { 2924327Sdougm /* first in the list */ 2934327Sdougm if (prev == NULL) 2944327Sdougm sa_global_handles = sa_global_handles->next; 2954327Sdougm else 2964327Sdougm prev->next = item->next; 2974327Sdougm /* Item is out of the list so free the list structure */ 2984327Sdougm free(item); 2994327Sdougm break; 3003910Sdougm } 3014327Sdougm prev = item; 3023910Sdougm } 3033910Sdougm (void) mutex_unlock(&sa_global_lock); 3043910Sdougm } 3053910Sdougm 3063910Sdougm /* 3073910Sdougm * sa_find_group_handle(sa_group_t group) 3083910Sdougm * 3093910Sdougm * Find the sa_handle_t for the configuration associated with this 3103910Sdougm * group. 3113910Sdougm */ 3123910Sdougm sa_handle_t 3133910Sdougm sa_find_group_handle(sa_group_t group) 3143910Sdougm { 3153910Sdougm xmlNodePtr node = (xmlNodePtr)group; 3163910Sdougm sa_handle_t handle; 3173910Sdougm 3183910Sdougm while (node != NULL) { 3194327Sdougm if (strcmp((char *)(node->name), "sharecfg") == 0) { 3204327Sdougm /* have the root so get the handle */ 3214327Sdougm handle = (sa_handle_t)get_handle_for_root(node); 3224327Sdougm return (handle); 3234327Sdougm } 3244327Sdougm node = node->parent; 3253910Sdougm } 3263910Sdougm return (NULL); 3273910Sdougm } 3283910Sdougm 3293910Sdougm /* 3303034Sdougm * set_legacy_timestamp(root, path, timevalue) 3313034Sdougm * 3323034Sdougm * add the current timestamp value to the configuration for use in 3333034Sdougm * determining when to update the legacy files. For SMF, this 3343034Sdougm * property is kept in default/operation/legacy_timestamp 3353034Sdougm */ 3363034Sdougm 3373034Sdougm static void 3383034Sdougm set_legacy_timestamp(xmlNodePtr root, char *path, uint64_t tval) 3393034Sdougm { 3403034Sdougm xmlNodePtr node; 3413034Sdougm xmlChar *lpath = NULL; 3423910Sdougm sa_handle_impl_t handle; 3433910Sdougm 3443910Sdougm /* Have to have a handle or else we weren't initialized. */ 3453910Sdougm handle = get_handle_for_root(root); 3463910Sdougm if (handle == NULL) 3474327Sdougm return; 3483034Sdougm 3493034Sdougm for (node = root->xmlChildrenNode; node != NULL; 3504327Sdougm node = node->next) { 3514327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"legacy") == 0) { 3524327Sdougm /* a possible legacy node for this path */ 3534327Sdougm lpath = xmlGetProp(node, (xmlChar *)"path"); 3544327Sdougm if (lpath != NULL && 3554327Sdougm xmlStrcmp(lpath, (xmlChar *)path) == 0) { 3564327Sdougm xmlFree(lpath); 3574327Sdougm break; 3584327Sdougm } 3594327Sdougm if (lpath != NULL) 3604327Sdougm xmlFree(lpath); 3613034Sdougm } 3623034Sdougm } 3633034Sdougm if (node == NULL) { 3644327Sdougm /* need to create the first legacy timestamp node */ 3654327Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"legacy", NULL); 3663034Sdougm } 3673034Sdougm if (node != NULL) { 3684327Sdougm char tstring[32]; 3694327Sdougm int ret; 3703034Sdougm 3714327Sdougm (void) snprintf(tstring, sizeof (tstring), "%lld", tval); 372*6007Sthurlow (void) xmlSetProp(node, (xmlChar *)"timestamp", 373*6007Sthurlow (xmlChar *)tstring); 374*6007Sthurlow (void) xmlSetProp(node, (xmlChar *)"path", (xmlChar *)path); 3754327Sdougm /* now commit to SMF */ 3764327Sdougm ret = sa_get_instance(handle->scfhandle, "default"); 3773034Sdougm if (ret == SA_OK) { 3784327Sdougm ret = sa_start_transaction(handle->scfhandle, 3794327Sdougm "operation"); 3804327Sdougm if (ret == SA_OK) { 3814327Sdougm ret = sa_set_property(handle->scfhandle, 3824327Sdougm "legacy-timestamp", tstring); 3834327Sdougm if (ret == SA_OK) { 3844327Sdougm (void) sa_end_transaction( 3855951Sdougm handle->scfhandle, handle); 3864327Sdougm } else { 3874327Sdougm sa_abort_transaction(handle->scfhandle); 3884327Sdougm } 3894327Sdougm } 3903034Sdougm } 3913034Sdougm } 3923034Sdougm } 3933034Sdougm 3943034Sdougm /* 3953034Sdougm * is_shared(share) 3963034Sdougm * 3973034Sdougm * determine if the specified share is currently shared or not. 3983034Sdougm */ 3993034Sdougm static int 4003034Sdougm is_shared(sa_share_t share) 4013034Sdougm { 4023034Sdougm char *shared; 4033034Sdougm int result = 0; /* assume not */ 4043034Sdougm 4053034Sdougm shared = sa_get_share_attr(share, "shared"); 4063034Sdougm if (shared != NULL) { 4074327Sdougm if (strcmp(shared, "true") == 0) 4084327Sdougm result = 1; 4094327Sdougm sa_free_attr_string(shared); 4103034Sdougm } 4113034Sdougm return (result); 4123034Sdougm } 4133034Sdougm 4143034Sdougm /* 4155331Samw * excluded_protocol(share, proto) 4165331Samw * 4175331Samw * Returns B_TRUE if the specified protocol appears in the "exclude" 4185331Samw * property. This is used to prevent sharing special case shares 4195331Samw * (e.g. subdirs when SMB wants a subdir and NFS doesn't. B_FALSE is 4205331Samw * returned if the protocol isn't in the list. 4215331Samw */ 4225331Samw static boolean_t 4235331Samw excluded_protocol(sa_share_t share, char *proto) 4245331Samw { 4255331Samw char *protolist; 4265331Samw char *str; 4275331Samw char *token; 4285331Samw 4295331Samw protolist = sa_get_share_attr(share, "exclude"); 4305331Samw if (protolist != NULL) { 4315331Samw str = protolist; 4325331Samw while ((token = strtok(str, ",")) != NULL) { 4335331Samw if (strcmp(token, proto) == 0) { 4345331Samw sa_free_attr_string(protolist); 4355331Samw return (B_TRUE); 4365331Samw } 4375331Samw str = NULL; 4385331Samw } 4395331Samw sa_free_attr_string(protolist); 4405331Samw } 4415331Samw return (B_FALSE); 4425331Samw } 4435331Samw 4445331Samw /* 4453663Sdougm * checksubdirgroup(group, newpath, strictness) 4463348Sdougm * 4473663Sdougm * check all the specified newpath against all the paths in the 4483663Sdougm * group. This is a helper function for checksubdir to make it easier 4493663Sdougm * to also check ZFS subgroups. 4503663Sdougm * The strictness values mean: 4513348Sdougm * SA_CHECK_NORMAL == only check newpath against shares that are active 4523348Sdougm * SA_CHECK_STRICT == check newpath against both active shares and those 4533348Sdougm * stored in the repository 4543034Sdougm */ 4553034Sdougm static int 4563663Sdougm checksubdirgroup(sa_group_t group, char *newpath, int strictness) 4573034Sdougm { 4583034Sdougm sa_share_t share; 4593663Sdougm char *path; 4603663Sdougm int issub = SA_OK; 4615331Samw int subdir; 4625331Samw int parent; 4635331Samw 4645331Samw if (newpath == NULL) 4655331Samw return (SA_INVALID_PATH); 4663034Sdougm 4673663Sdougm for (share = sa_get_share(group, NULL); share != NULL; 4683663Sdougm share = sa_get_next_share(share)) { 4693034Sdougm /* 4703034Sdougm * The original behavior of share never checked 4713034Sdougm * against the permanent configuration 4723034Sdougm * (/etc/dfs/dfstab). PIT has a number of cases where 4733034Sdougm * it depends on this older behavior even though it 4743034Sdougm * could be considered incorrect. We may tighten this 4753034Sdougm * up in the future. 4763034Sdougm */ 4774327Sdougm if (strictness == SA_CHECK_NORMAL && !is_shared(share)) 4784327Sdougm continue; 4793034Sdougm 4804327Sdougm path = sa_get_share_attr(share, "path"); 4813348Sdougm /* 4823348Sdougm * If path is NULL, then a share is in the process of 4833348Sdougm * construction or someone has modified the property 4843663Sdougm * group inappropriately. It should be 4853663Sdougm * ignored. issubdir() comes from the original share 4863663Sdougm * implementation and does the difficult part of 4873663Sdougm * checking subdirectories. 4883348Sdougm */ 4894327Sdougm if (path == NULL) 4904327Sdougm continue; 4915331Samw 4925331Samw if (strcmp(path, newpath) == 0) { 4934327Sdougm issub = SA_INVALID_PATH; 4945331Samw } else { 4955331Samw subdir = issubdir(newpath, path); 4965331Samw parent = issubdir(path, newpath); 4975331Samw if (subdir || parent) { 4985331Samw sa_free_attr_string(path); 4995331Samw path = NULL; 5005331Samw return (subdir ? 5015331Samw SA_PATH_IS_SUBDIR : SA_PATH_IS_PARENTDIR); 5025331Samw } 5034327Sdougm } 5043034Sdougm sa_free_attr_string(path); 5053034Sdougm path = NULL; 5063663Sdougm } 5073663Sdougm return (issub); 5083663Sdougm } 5093663Sdougm 5103663Sdougm /* 5113663Sdougm * checksubdir(newpath, strictness) 5123663Sdougm * 5133663Sdougm * checksubdir determines if the specified path (newpath) is a 5143663Sdougm * subdirectory of another share. It calls checksubdirgroup() to do 5153663Sdougm * the complicated work. The strictness parameter determines how 5163663Sdougm * strict a check to make against the path. The strictness values 5173663Sdougm * mean: SA_CHECK_NORMAL == only check newpath against shares that are 5183663Sdougm * active SA_CHECK_STRICT == check newpath against both active shares 5193663Sdougm * and those * stored in the repository 5203663Sdougm */ 5213663Sdougm static int 5223910Sdougm checksubdir(sa_handle_t handle, char *newpath, int strictness) 5233663Sdougm { 5243663Sdougm sa_group_t group; 5255331Samw int issub = SA_OK; 5263663Sdougm char *path = NULL; 5273663Sdougm 5285331Samw for (group = sa_get_group(handle, NULL); 5295331Samw group != NULL && issub == SA_OK; 5305331Samw group = sa_get_next_group(group)) { 5314327Sdougm if (sa_group_is_zfs(group)) { 5324327Sdougm sa_group_t subgroup; 5334327Sdougm for (subgroup = sa_get_sub_group(group); 5345331Samw subgroup != NULL && issub == SA_OK; 5354327Sdougm subgroup = sa_get_next_group(subgroup)) 5364327Sdougm issub = checksubdirgroup(subgroup, newpath, 5374327Sdougm strictness); 5384327Sdougm } else { 5394327Sdougm issub = checksubdirgroup(group, newpath, strictness); 5404327Sdougm } 5413034Sdougm } 5423034Sdougm if (path != NULL) 5434327Sdougm sa_free_attr_string(path); 5443034Sdougm return (issub); 5453034Sdougm } 5463034Sdougm 5473034Sdougm /* 5483348Sdougm * validpath(path, strictness) 5493034Sdougm * determine if the provided path is valid for a share. It shouldn't 5503034Sdougm * be a sub-dir of an already shared path or the parent directory of a 5513034Sdougm * share path. 5523034Sdougm */ 5533034Sdougm static int 5543910Sdougm validpath(sa_handle_t handle, char *path, int strictness) 5553034Sdougm { 5563034Sdougm int error = SA_OK; 5573034Sdougm struct stat st; 5583034Sdougm sa_share_t share; 5593034Sdougm char *fstype; 5603034Sdougm 5614327Sdougm if (*path != '/') 5624327Sdougm return (SA_BAD_PATH); 5634327Sdougm 5643034Sdougm if (stat(path, &st) < 0) { 5654327Sdougm error = SA_NO_SUCH_PATH; 5663034Sdougm } else { 5674327Sdougm share = sa_find_share(handle, path); 5684327Sdougm if (share != NULL) 5694327Sdougm error = SA_DUPLICATE_NAME; 5704327Sdougm 5714327Sdougm if (error == SA_OK) { 5724327Sdougm /* 5734327Sdougm * check for special case with file system 5744327Sdougm * that might have restrictions. For now, ZFS 5754327Sdougm * is the only case since it has its own idea 5764327Sdougm * of how to configure shares. We do this 5774327Sdougm * before subdir checking since things like 5784327Sdougm * ZFS will do that for us. This should also 5794327Sdougm * be done via plugin interface. 5804327Sdougm */ 5814327Sdougm fstype = sa_fstype(path); 5824327Sdougm if (fstype != NULL && strcmp(fstype, "zfs") == 0) { 5834327Sdougm if (sa_zfs_is_shared(handle, path)) 5844327Sdougm error = SA_INVALID_NAME; 5854327Sdougm } 5864327Sdougm if (fstype != NULL) 5874327Sdougm sa_free_fstype(fstype); 5883034Sdougm } 5894327Sdougm if (error == SA_OK) 5904327Sdougm error = checksubdir(handle, path, strictness); 5913034Sdougm } 5923034Sdougm return (error); 5933034Sdougm } 5943034Sdougm 5953034Sdougm /* 5963034Sdougm * check to see if group/share is persistent. 5975331Samw * 5985331Samw * "group" can be either an sa_group_t or an sa_share_t. (void *) 5995331Samw * works since both thse types are also void *. 6003034Sdougm */ 6015331Samw int 6025331Samw sa_is_persistent(void *group) 6033034Sdougm { 6043034Sdougm char *type; 6053034Sdougm int persist = 1; 6063034Sdougm 6075331Samw type = sa_get_group_attr((sa_group_t)group, "type"); 6083034Sdougm if (type != NULL && strcmp(type, "transient") == 0) 6094327Sdougm persist = 0; 6103034Sdougm if (type != NULL) 6114327Sdougm sa_free_attr_string(type); 6123034Sdougm return (persist); 6133034Sdougm } 6143034Sdougm 6153034Sdougm /* 6163034Sdougm * sa_valid_group_name(name) 6173034Sdougm * 6183034Sdougm * check that the "name" contains only valid characters and otherwise 6193034Sdougm * fits the required naming conventions. Valid names must start with 6203034Sdougm * an alphabetic and the remainder may consist of only alphanumeric 6213034Sdougm * plus the '-' and '_' characters. This name limitation comes from 6223034Sdougm * inherent limitations in SMF. 6233034Sdougm */ 6243034Sdougm 6253034Sdougm int 6263034Sdougm sa_valid_group_name(char *name) 6273034Sdougm { 6283034Sdougm int ret = 1; 6293034Sdougm ssize_t len; 6303034Sdougm 6313034Sdougm if (name != NULL && isalpha(*name)) { 6324327Sdougm char c; 6334327Sdougm len = strlen(name); 6344327Sdougm if (len < (scf_max_name_len - sizeof ("group:"))) { 6354327Sdougm for (c = *name++; c != '\0' && ret != 0; c = *name++) { 6364327Sdougm if (!isalnum(c) && c != '-' && c != '_') 6374327Sdougm ret = 0; 6384327Sdougm } 6394327Sdougm } else { 6403034Sdougm ret = 0; 6413034Sdougm } 6424327Sdougm } else { 6433034Sdougm ret = 0; 6443034Sdougm } 6453034Sdougm return (ret); 6463034Sdougm } 6473034Sdougm 6483034Sdougm 6493034Sdougm /* 6503034Sdougm * is_zfs_group(group) 6513034Sdougm * Determine if the specified group is a ZFS sharenfs group 6523034Sdougm */ 6533034Sdougm static int 6543034Sdougm is_zfs_group(sa_group_t group) 6553034Sdougm { 6563034Sdougm int ret = 0; 6573034Sdougm xmlNodePtr parent; 6583034Sdougm xmlChar *zfs; 6593034Sdougm 6604327Sdougm if (strcmp((char *)((xmlNodePtr)group)->name, "share") == 0) 6614327Sdougm parent = (xmlNodePtr)sa_get_parent_group(group); 6624327Sdougm else 6634327Sdougm parent = (xmlNodePtr)group; 6643034Sdougm zfs = xmlGetProp(parent, (xmlChar *)"zfs"); 6653034Sdougm if (zfs != NULL) { 6664327Sdougm xmlFree(zfs); 6674327Sdougm ret = 1; 6683034Sdougm } 6693034Sdougm return (ret); 6703034Sdougm } 6713034Sdougm 6723034Sdougm /* 6735331Samw * sa_get_object_type(object) 6745331Samw * 6755331Samw * This function returns a numeric value representing the object 6765331Samw * type. This allows using simpler checks when doing type specific 6775331Samw * operations. 6785331Samw */ 6795331Samw 6805331Samw static int 6815331Samw sa_get_object_type(void *object) 6825331Samw { 6835331Samw xmlNodePtr node = (xmlNodePtr)object; 6845331Samw int type; 6855331Samw 6865331Samw if (xmlStrcmp(node->name, (xmlChar *)"group") == 0) 6875331Samw type = SA_TYPE_GROUP; 6885331Samw else if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) 6895331Samw type = SA_TYPE_SHARE; 6905331Samw else if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0) 6915331Samw type = SA_TYPE_RESOURCE; 6925331Samw else if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) 6935331Samw type = SA_TYPE_OPTIONSET; 6945331Samw else if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) 6955331Samw type = SA_TYPE_ALTSPACE; 6965331Samw else 6975331Samw assert(0); 6985331Samw return (type); 6995331Samw } 7005331Samw 7015331Samw /* 7023034Sdougm * sa_optionset_name(optionset, oname, len, id) 7033034Sdougm * return the SMF name for the optionset. If id is not NULL, it 7043034Sdougm * will have the GUID value for a share and should be used 7053034Sdougm * instead of the keyword "optionset" which is used for 7063034Sdougm * groups. If the optionset doesn't have a protocol type 7073034Sdougm * associated with it, "default" is used. This shouldn't happen 7083034Sdougm * at this point but may be desirable in the future if there are 7093034Sdougm * protocol independent properties added. The name is returned in 7103034Sdougm * oname. 7113034Sdougm */ 7123034Sdougm 7133034Sdougm static int 7143034Sdougm sa_optionset_name(sa_optionset_t optionset, char *oname, size_t len, char *id) 7153034Sdougm { 7163034Sdougm char *proto; 7175331Samw void *parent; 7185331Samw int ptype; 7193034Sdougm 7203034Sdougm if (id == NULL) 7214327Sdougm id = "optionset"; 7223034Sdougm 7235331Samw parent = sa_get_optionset_parent(optionset); 7245331Samw if (parent != NULL) { 7255331Samw ptype = sa_get_object_type(parent); 7265331Samw proto = sa_get_optionset_attr(optionset, "type"); 7275331Samw if (ptype != SA_TYPE_RESOURCE) { 7285331Samw len = snprintf(oname, len, "%s_%s", id, 7295331Samw proto ? proto : "default"); 7305331Samw } else { 7315331Samw char *index; 7325331Samw index = get_node_attr((void *)parent, "id"); 7335331Samw if (index != NULL) 7345331Samw len = snprintf(oname, len, "%s_%s_%s", id, 7355331Samw proto ? proto : "default", index); 7365331Samw else 7375331Samw len = 0; 7385331Samw } 7395331Samw 7405331Samw if (proto != NULL) 7415331Samw sa_free_attr_string(proto); 7425331Samw } else { 7435331Samw len = 0; 7445331Samw } 7453034Sdougm return (len); 7463034Sdougm } 7473034Sdougm 7483034Sdougm /* 7493034Sdougm * sa_security_name(optionset, oname, len, id) 7503034Sdougm * 7513034Sdougm * return the SMF name for the security. If id is not NULL, it will 7523034Sdougm * have the GUID value for a share and should be used instead of the 7533034Sdougm * keyword "optionset" which is used for groups. If the optionset 7543034Sdougm * doesn't have a protocol type associated with it, "default" is 7553034Sdougm * used. This shouldn't happen at this point but may be desirable in 7563034Sdougm * the future if there are protocol independent properties added. The 7573034Sdougm * name is returned in oname. The security type is also encoded into 7583034Sdougm * the name. In the future, this wil *be handled a bit differently. 7593034Sdougm */ 7603034Sdougm 7613034Sdougm static int 7623034Sdougm sa_security_name(sa_security_t security, char *oname, size_t len, char *id) 7633034Sdougm { 7643034Sdougm char *proto; 7653034Sdougm char *sectype; 7663034Sdougm 7673034Sdougm if (id == NULL) 7684327Sdougm id = "optionset"; 7693034Sdougm 7703034Sdougm proto = sa_get_security_attr(security, "type"); 7713034Sdougm sectype = sa_get_security_attr(security, "sectype"); 7724327Sdougm len = snprintf(oname, len, "%s_%s_%s", id, proto ? proto : "default", 7734327Sdougm sectype ? sectype : "default"); 7743034Sdougm if (proto != NULL) 7754327Sdougm sa_free_attr_string(proto); 7763034Sdougm if (sectype != NULL) 7774327Sdougm sa_free_attr_string(sectype); 7783034Sdougm return (len); 7793034Sdougm } 7803034Sdougm 7813034Sdougm /* 7824327Sdougm * verifydefgroupopts(handle) 7834327Sdougm * 7844327Sdougm * Make sure a "default" group exists and has default protocols enabled. 7854327Sdougm */ 7864327Sdougm static void 7874327Sdougm verifydefgroupopts(sa_handle_t handle) 7884327Sdougm { 7894327Sdougm sa_group_t defgrp; 7904327Sdougm sa_optionset_t opt; 7915331Samw 7924327Sdougm defgrp = sa_get_group(handle, "default"); 7934327Sdougm if (defgrp != NULL) { 7944327Sdougm opt = sa_get_optionset(defgrp, NULL); 7954327Sdougm /* 7964327Sdougm * NFS is the default for default group 7974327Sdougm */ 7984327Sdougm if (opt == NULL) 7994327Sdougm opt = sa_create_optionset(defgrp, "nfs"); 8004327Sdougm } 8014327Sdougm } 8024327Sdougm 8034327Sdougm /* 8043348Sdougm * sa_init(init_service) 8053034Sdougm * Initialize the API 8063034Sdougm * find all the shared objects 8073034Sdougm * init the tables with all objects 8083034Sdougm * read in the current configuration 8093034Sdougm */ 8103034Sdougm 8114327Sdougm #define GETPROP(prop) scf_simple_prop_next_astring(prop) 8124327Sdougm #define CHECKTSTAMP(st, tval) stat(SA_LEGACY_DFSTAB, &st) >= 0 && \ 8134327Sdougm tval != TSTAMP(st.st_ctim) 8144327Sdougm 8153910Sdougm sa_handle_t 8163034Sdougm sa_init(int init_service) 8173034Sdougm { 8183034Sdougm struct stat st; 8193034Sdougm int legacy = 0; 8203034Sdougm uint64_t tval = 0; 8213663Sdougm int lockfd; 8223663Sdougm sigset_t old; 8233663Sdougm int updatelegacy = B_FALSE; 8243663Sdougm scf_simple_prop_t *prop; 8253910Sdougm sa_handle_impl_t handle; 8263910Sdougm int err; 8273034Sdougm 8283910Sdougm handle = calloc(sizeof (struct sa_handle_impl), 1); 8293910Sdougm 8303910Sdougm if (handle != NULL) { 8314327Sdougm /* get protocol specific structures */ 8324327Sdougm (void) proto_plugin_init(); 8334327Sdougm if (init_service & SA_INIT_SHARE_API) { 8343663Sdougm /* 8354327Sdougm * initialize access into libzfs. We use this 8364327Sdougm * when collecting info about ZFS datasets and 8374327Sdougm * shares. 8383663Sdougm */ 8394327Sdougm if (sa_zfs_init(handle) == B_FALSE) { 8404327Sdougm free(handle); 8414327Sdougm (void) proto_plugin_fini(); 8424327Sdougm return (NULL); 8434327Sdougm } 8443663Sdougm /* 8454327Sdougm * since we want to use SMF, initialize an svc handle 8464327Sdougm * and find out what is there. 8473663Sdougm */ 8484327Sdougm handle->scfhandle = sa_scf_init(handle); 8494327Sdougm if (handle->scfhandle != NULL) { 8504327Sdougm /* 8514327Sdougm * Need to lock the extraction of the 8524327Sdougm * configuration if the dfstab file has 8534327Sdougm * changed. Lock everything now and release if 8544327Sdougm * not needed. Use a file that isn't being 8554327Sdougm * manipulated by other parts of the system in 8564327Sdougm * order to not interfere with locking. Using 8574327Sdougm * dfstab doesn't work. 8584327Sdougm */ 8594327Sdougm sablocksigs(&old); 8604327Sdougm lockfd = open(DFS_LOCK_FILE, O_RDWR); 8614327Sdougm if (lockfd >= 0) { 8624327Sdougm extern int errno; 8634327Sdougm errno = 0; 8644327Sdougm (void) lockf(lockfd, F_LOCK, 0); 8654327Sdougm /* 8664327Sdougm * Check whether we are going to need 8674327Sdougm * to merge any dfstab changes. This 8684327Sdougm * is done by comparing the value of 8694327Sdougm * legacy-timestamp with the current 8704327Sdougm * st_ctim of the file. If they are 8714327Sdougm * different, an update is needed and 8724327Sdougm * the file must remain locked until 8734327Sdougm * the merge is done in order to 8744327Sdougm * prevent multiple startups from 8754327Sdougm * changing the SMF repository at the 8764327Sdougm * same time. The first to get the 8774327Sdougm * lock will make any changes before 8784327Sdougm * the others can read the repository. 8794327Sdougm */ 8804327Sdougm prop = scf_simple_prop_get 8814327Sdougm (handle->scfhandle->handle, 8824327Sdougm (const char *)SA_SVC_FMRI_BASE 8834327Sdougm ":default", "operation", 8844327Sdougm "legacy-timestamp"); 8854327Sdougm if (prop != NULL) { 8864327Sdougm char *i64; 8874327Sdougm i64 = GETPROP(prop); 8884327Sdougm if (i64 != NULL) 8894327Sdougm tval = strtoull(i64, 8904327Sdougm NULL, 0); 8914327Sdougm if (CHECKTSTAMP(st, tval)) 8924327Sdougm updatelegacy = B_TRUE; 8934327Sdougm scf_simple_prop_free(prop); 8944327Sdougm } else { 8954327Sdougm /* 8964327Sdougm * We haven't set the 8974327Sdougm * timestamp before so do it. 8984327Sdougm */ 8994327Sdougm updatelegacy = B_TRUE; 9004327Sdougm } 9014327Sdougm } 9024327Sdougm if (updatelegacy == B_FALSE) { 9034327Sdougm /* Don't need the lock anymore */ 9044327Sdougm (void) lockf(lockfd, F_ULOCK, 0); 9054327Sdougm (void) close(lockfd); 9064327Sdougm } 9073973Sdougm 9084327Sdougm /* 9094327Sdougm * It is essential that the document tree and 9104327Sdougm * the internal list of roots to handles be 9114327Sdougm * setup before anything that might try to 9124327Sdougm * create a new object is called. The document 9134327Sdougm * tree is the combination of handle->doc and 9144327Sdougm * handle->tree. This allows searches, 9154327Sdougm * etc. when all you have is an object in the 9164327Sdougm * tree. 9174327Sdougm */ 9184327Sdougm handle->doc = xmlNewDoc((xmlChar *)"1.0"); 9194327Sdougm handle->tree = xmlNewNode(NULL, 9204327Sdougm (xmlChar *)"sharecfg"); 9214327Sdougm if (handle->doc != NULL && 9224327Sdougm handle->tree != NULL) { 923*6007Sthurlow (void) xmlDocSetRootElement(handle->doc, 9244327Sdougm handle->tree); 9254327Sdougm err = add_handle_for_root(handle->tree, 9264327Sdougm handle); 9274327Sdougm if (err == SA_OK) 9284327Sdougm err = sa_get_config( 9294327Sdougm handle->scfhandle, 9303973Sdougm handle->tree, handle); 9314327Sdougm } else { 9324327Sdougm if (handle->doc != NULL) 9334327Sdougm xmlFreeDoc(handle->doc); 9344327Sdougm if (handle->tree != NULL) 9354327Sdougm xmlFreeNode(handle->tree); 9364327Sdougm err = SA_NO_MEMORY; 9374327Sdougm } 9383973Sdougm 9394327Sdougm saunblocksigs(&old); 9403910Sdougm 9414327Sdougm if (err != SA_OK) { 9424327Sdougm /* 9434327Sdougm * If we couldn't add the tree handle 9444327Sdougm * to the list, then things are going 9454327Sdougm * to fail badly. Might as well undo 9464327Sdougm * everything now and fail the 9474327Sdougm * sa_init(). 9484327Sdougm */ 9494327Sdougm sa_fini(handle); 9504327Sdougm return (NULL); 9514327Sdougm } 9523910Sdougm 9534327Sdougm if (tval == 0) { 9544327Sdougm /* 9554327Sdougm * first time so make sure 9564327Sdougm * default is setup 9574327Sdougm */ 9584327Sdougm verifydefgroupopts(handle); 9594327Sdougm } 9603973Sdougm 9614524Sdougm if (updatelegacy == B_TRUE) { 9624524Sdougm sablocksigs(&old); 9634524Sdougm getlegacyconfig((sa_handle_t)handle, 9644524Sdougm SA_LEGACY_DFSTAB, &handle->tree); 9654524Sdougm if (stat(SA_LEGACY_DFSTAB, &st) >= 0) 9664524Sdougm set_legacy_timestamp( 9674524Sdougm handle->tree, 9684524Sdougm SA_LEGACY_DFSTAB, 9694524Sdougm TSTAMP(st.st_ctim)); 9704524Sdougm saunblocksigs(&old); 9714524Sdougm /* 9724524Sdougm * Safe to unlock now to allow 9734524Sdougm * others to run 9744524Sdougm */ 9754524Sdougm (void) lockf(lockfd, F_ULOCK, 0); 9764524Sdougm (void) close(lockfd); 9774524Sdougm } 9785951Sdougm /* Get sharetab timestamp */ 9795951Sdougm sa_update_sharetab_ts((sa_handle_t)handle); 9805951Sdougm 9815951Sdougm /* Get lastupdate (transaction) timestamp */ 9825951Sdougm prop = scf_simple_prop_get( 9835951Sdougm handle->scfhandle->handle, 9845951Sdougm (const char *)SA_SVC_FMRI_BASE ":default", 9855951Sdougm "state", "lastupdate"); 9865951Sdougm if (prop != NULL) { 9875951Sdougm char *str; 9885951Sdougm str = 9895951Sdougm scf_simple_prop_next_astring(prop); 9905951Sdougm if (str != NULL) 9915951Sdougm handle->tstrans = 9925951Sdougm strtoull(str, NULL, 0); 9935951Sdougm else 9945951Sdougm handle->tstrans = 0; 9955951Sdougm scf_simple_prop_free(prop); 9965951Sdougm } 9974524Sdougm legacy |= sa_get_zfs_shares(handle, "zfs"); 9984524Sdougm legacy |= gettransients(handle, &handle->tree); 9994327Sdougm } 10004327Sdougm } 10013034Sdougm } 10023910Sdougm return ((sa_handle_t)handle); 10033034Sdougm } 10043034Sdougm 10053034Sdougm /* 10063910Sdougm * sa_fini(handle) 10073034Sdougm * Uninitialize the API structures including the configuration 10083218Sdougm * data structures and ZFS related data. 10093034Sdougm */ 10103034Sdougm 10113034Sdougm void 10123910Sdougm sa_fini(sa_handle_t handle) 10133034Sdougm { 10143910Sdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle; 10153910Sdougm 10163910Sdougm if (impl_handle != NULL) { 10173910Sdougm /* 10183910Sdougm * Free the config trees and any other data structures 10193910Sdougm * used in the handle. 10203910Sdougm */ 10213910Sdougm if (impl_handle->doc != NULL) 10223910Sdougm xmlFreeDoc(impl_handle->doc); 10233910Sdougm sa_scf_fini(impl_handle->scfhandle); 10243910Sdougm sa_zfs_fini(impl_handle); 10253910Sdougm 10263910Sdougm /* Remove and free the entry in the global list. */ 10273910Sdougm remove_handle_for_root(impl_handle->tree); 10283910Sdougm 10293910Sdougm /* Make sure we free the handle */ 10303910Sdougm free(impl_handle); 10313910Sdougm 10323910Sdougm /* 10333910Sdougm * If this was the last handle to release, unload the 10343910Sdougm * plugins that were loaded. 10353910Sdougm */ 10363910Sdougm if (sa_global_handles == NULL) 10374327Sdougm (void) proto_plugin_fini(); 10383910Sdougm 10393034Sdougm } 10403034Sdougm } 10413034Sdougm 10423034Sdougm /* 10433034Sdougm * sa_get_protocols(char **protocol) 10443034Sdougm * Get array of protocols that are supported 10453034Sdougm * Returns pointer to an allocated and NULL terminated 10463034Sdougm * array of strings. Caller must free. 10473034Sdougm * This really should be determined dynamically. 10483034Sdougm * If there aren't any defined, return -1. 10493034Sdougm * Use free() to return memory. 10503034Sdougm */ 10513034Sdougm 10523034Sdougm int 10533034Sdougm sa_get_protocols(char ***protocols) 10543034Sdougm { 10553034Sdougm int numproto = -1; 10563034Sdougm 10573034Sdougm if (protocols != NULL) { 10584327Sdougm struct sa_proto_plugin *plug; 10594327Sdougm for (numproto = 0, plug = sap_proto_list; plug != NULL; 10604327Sdougm plug = plug->plugin_next) { 10614327Sdougm numproto++; 10624327Sdougm } 10633034Sdougm 10644327Sdougm *protocols = calloc(numproto + 1, sizeof (char *)); 10654327Sdougm if (*protocols != NULL) { 10664327Sdougm int ret = 0; 10674327Sdougm for (plug = sap_proto_list; plug != NULL; 10684327Sdougm plug = plug->plugin_next) { 10694327Sdougm /* faking for now */ 10704327Sdougm (*protocols)[ret++] = 10714327Sdougm plug->plugin_ops->sa_protocol; 10724327Sdougm } 10734327Sdougm } else { 10744327Sdougm numproto = -1; 10753034Sdougm } 10763034Sdougm } 10773034Sdougm return (numproto); 10783034Sdougm } 10793034Sdougm 10803034Sdougm /* 10813034Sdougm * find_group_by_name(node, group) 10823034Sdougm * 10833034Sdougm * search the XML document subtree specified by node to find the group 10843034Sdougm * specified by group. Searching subtree allows subgroups to be 10853034Sdougm * searched for. 10863034Sdougm */ 10873034Sdougm 10883034Sdougm static xmlNodePtr 10893034Sdougm find_group_by_name(xmlNodePtr node, xmlChar *group) 10903034Sdougm { 10913034Sdougm xmlChar *name = NULL; 10923034Sdougm 10933034Sdougm for (node = node->xmlChildrenNode; node != NULL; 10943034Sdougm node = node->next) { 10954327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"group") == 0) { 10964327Sdougm /* if no groupname, return the first found */ 10974327Sdougm if (group == NULL) 10984327Sdougm break; 10994327Sdougm name = xmlGetProp(node, (xmlChar *)"name"); 11004327Sdougm if (name != NULL && xmlStrcmp(name, group) == 0) 11014327Sdougm break; 11024327Sdougm if (name != NULL) { 11034327Sdougm xmlFree(name); 11044327Sdougm name = NULL; 11054327Sdougm } 11063034Sdougm } 11073034Sdougm } 11083034Sdougm if (name != NULL) 11094327Sdougm xmlFree(name); 11103034Sdougm return (node); 11113034Sdougm } 11123034Sdougm 11133034Sdougm /* 11143034Sdougm * sa_get_group(groupname) 11153034Sdougm * Return the "group" specified. If groupname is NULL, 11163034Sdougm * return the first group of the list of groups. 11173034Sdougm */ 11183034Sdougm sa_group_t 11193910Sdougm sa_get_group(sa_handle_t handle, char *groupname) 11203034Sdougm { 11213034Sdougm xmlNodePtr node = NULL; 11223034Sdougm char *subgroup = NULL; 11233034Sdougm char *group = NULL; 11243910Sdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle; 11253034Sdougm 11263910Sdougm if (impl_handle != NULL && impl_handle->tree != NULL) { 11274327Sdougm if (groupname != NULL) { 11284327Sdougm group = strdup(groupname); 11294345Sdougm if (group != NULL) { 11304345Sdougm subgroup = strchr(group, '/'); 11314345Sdougm if (subgroup != NULL) 11324345Sdougm *subgroup++ = '\0'; 11334345Sdougm } 11344327Sdougm } 11354345Sdougm /* 11364345Sdougm * We want to find the, possibly, named group. If 11374345Sdougm * group is not NULL, then lookup the name. If it is 11384345Sdougm * NULL, we only do the find if groupname is also 11394345Sdougm * NULL. This allows lookup of the "first" group in 11404345Sdougm * the internal list. 11414345Sdougm */ 11424345Sdougm if (group != NULL || groupname == NULL) 11434345Sdougm node = find_group_by_name(impl_handle->tree, 11444345Sdougm (xmlChar *)group); 11454345Sdougm 11464327Sdougm /* if a subgroup, find it before returning */ 11474327Sdougm if (subgroup != NULL && node != NULL) 11484327Sdougm node = find_group_by_name(node, (xmlChar *)subgroup); 11493034Sdougm } 11503034Sdougm if (node != NULL && (char *)group != NULL) 11514327Sdougm (void) sa_get_instance(impl_handle->scfhandle, (char *)group); 11523034Sdougm if (group != NULL) 11534327Sdougm free(group); 11543034Sdougm return ((sa_group_t)(node)); 11553034Sdougm } 11563034Sdougm 11573034Sdougm /* 11583034Sdougm * sa_get_next_group(group) 11593034Sdougm * Return the "next" group after the specified group from 11603034Sdougm * the internal group list. NULL if there are no more. 11613034Sdougm */ 11623034Sdougm sa_group_t 11633034Sdougm sa_get_next_group(sa_group_t group) 11643034Sdougm { 11653034Sdougm xmlNodePtr ngroup = NULL; 11663034Sdougm if (group != NULL) { 11674327Sdougm for (ngroup = ((xmlNodePtr)group)->next; ngroup != NULL; 11683034Sdougm ngroup = ngroup->next) { 11694327Sdougm if (xmlStrcmp(ngroup->name, (xmlChar *)"group") == 0) 11704327Sdougm break; 11714327Sdougm } 11723034Sdougm } 11733034Sdougm return ((sa_group_t)ngroup); 11743034Sdougm } 11753034Sdougm 11763034Sdougm /* 11773034Sdougm * sa_get_share(group, sharepath) 11783034Sdougm * Return the share object for the share specified. The share 11793034Sdougm * must be in the specified group. Return NULL if not found. 11803034Sdougm */ 11813034Sdougm sa_share_t 11823034Sdougm sa_get_share(sa_group_t group, char *sharepath) 11833034Sdougm { 11843034Sdougm xmlNodePtr node = NULL; 11853034Sdougm xmlChar *path; 11863034Sdougm 11873034Sdougm /* 11883034Sdougm * For future scalability, this should end up building a cache 11893034Sdougm * since it will get called regularly by the mountd and info 11903034Sdougm * services. 11913034Sdougm */ 11923034Sdougm if (group != NULL) { 11934327Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 11943034Sdougm node = node->next) { 11954327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) { 11964327Sdougm if (sharepath == NULL) { 11974327Sdougm break; 11984327Sdougm } else { 11994327Sdougm /* is it the correct share? */ 12004327Sdougm path = xmlGetProp(node, 12014327Sdougm (xmlChar *)"path"); 12024327Sdougm if (path != NULL && 12034327Sdougm xmlStrcmp(path, 12044327Sdougm (xmlChar *)sharepath) == 0) { 12054327Sdougm xmlFree(path); 12064327Sdougm break; 12074327Sdougm } 12084327Sdougm xmlFree(path); 12094327Sdougm } 12103034Sdougm } 12113034Sdougm } 12123034Sdougm } 12133034Sdougm return ((sa_share_t)node); 12143034Sdougm } 12153034Sdougm 12163034Sdougm /* 12173034Sdougm * sa_get_next_share(share) 12183034Sdougm * Return the next share following the specified share 12193034Sdougm * from the internal list of shares. Returns NULL if there 12203034Sdougm * are no more shares. The list is relative to the same 12213034Sdougm * group. 12223034Sdougm */ 12233034Sdougm sa_share_t 12243034Sdougm sa_get_next_share(sa_share_t share) 12253034Sdougm { 12263034Sdougm xmlNodePtr node = NULL; 12273034Sdougm 12283034Sdougm if (share != NULL) { 12294327Sdougm for (node = ((xmlNodePtr)share)->next; node != NULL; 12303034Sdougm node = node->next) { 12314327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) { 12324327Sdougm break; 12334327Sdougm } 12343034Sdougm } 12353034Sdougm } 12363034Sdougm return ((sa_share_t)node); 12373034Sdougm } 12383034Sdougm 12393034Sdougm /* 12403034Sdougm * _sa_get_child_node(node, type) 12413034Sdougm * 12423034Sdougm * find the child node of the specified node that has "type". This is 12433034Sdougm * used to implement several internal functions. 12443034Sdougm */ 12453034Sdougm 12463034Sdougm static xmlNodePtr 12473034Sdougm _sa_get_child_node(xmlNodePtr node, xmlChar *type) 12483034Sdougm { 12493034Sdougm xmlNodePtr child; 12503034Sdougm for (child = node->xmlChildrenNode; child != NULL; 12513034Sdougm child = child->next) 12524327Sdougm if (xmlStrcmp(child->name, type) == 0) 12534327Sdougm return (child); 12543034Sdougm return ((xmlNodePtr)NULL); 12553034Sdougm } 12563034Sdougm 12573034Sdougm /* 12583034Sdougm * find_share(group, path) 12593034Sdougm * 12603034Sdougm * Search all the shares in the specified group for one that has the 12613034Sdougm * specified path. 12623034Sdougm */ 12633034Sdougm 12643034Sdougm static sa_share_t 12653034Sdougm find_share(sa_group_t group, char *sharepath) 12663034Sdougm { 12673034Sdougm sa_share_t share; 12683034Sdougm char *path; 12693034Sdougm 12703034Sdougm for (share = sa_get_share(group, NULL); share != NULL; 12713034Sdougm share = sa_get_next_share(share)) { 12724327Sdougm path = sa_get_share_attr(share, "path"); 12734327Sdougm if (path != NULL && strcmp(path, sharepath) == 0) { 12744327Sdougm sa_free_attr_string(path); 12754327Sdougm break; 12764327Sdougm } 12774327Sdougm if (path != NULL) 12784327Sdougm sa_free_attr_string(path); 12793034Sdougm } 12803034Sdougm return (share); 12813034Sdougm } 12823034Sdougm 12833034Sdougm /* 12843034Sdougm * sa_get_sub_group(group) 12853034Sdougm * 12863034Sdougm * Get the first sub-group of group. The sa_get_next_group() function 12873034Sdougm * can be used to get the rest. This is currently only used for ZFS 12883034Sdougm * sub-groups but could be used to implement a more general mechanism. 12893034Sdougm */ 12903034Sdougm 12913034Sdougm sa_group_t 12923034Sdougm sa_get_sub_group(sa_group_t group) 12933034Sdougm { 12943034Sdougm return ((sa_group_t)_sa_get_child_node((xmlNodePtr)group, 12954327Sdougm (xmlChar *)"group")); 12963034Sdougm } 12973034Sdougm 12983034Sdougm /* 12993034Sdougm * sa_find_share(sharepath) 13003034Sdougm * Finds a share regardless of group. In the future, this 13013034Sdougm * function should utilize a cache and hash table of some kind. 13023034Sdougm * The current assumption is that a path will only be shared 13033034Sdougm * once. In the future, this may change as implementation of 13043034Sdougm * resource names comes into being. 13053034Sdougm */ 13063034Sdougm sa_share_t 13073910Sdougm sa_find_share(sa_handle_t handle, char *sharepath) 13083034Sdougm { 13093034Sdougm sa_group_t group; 13103034Sdougm sa_group_t zgroup; 13113034Sdougm sa_share_t share = NULL; 13123034Sdougm int done = 0; 13133034Sdougm 13143910Sdougm for (group = sa_get_group(handle, NULL); group != NULL && !done; 13154327Sdougm group = sa_get_next_group(group)) { 13164327Sdougm if (is_zfs_group(group)) { 13174327Sdougm for (zgroup = 13184327Sdougm (sa_group_t)_sa_get_child_node((xmlNodePtr)group, 13194327Sdougm (xmlChar *)"group"); 13204327Sdougm zgroup != NULL; 13214327Sdougm zgroup = sa_get_next_group(zgroup)) { 13224327Sdougm share = find_share(zgroup, sharepath); 13234327Sdougm if (share != NULL) 13244327Sdougm break; 13254327Sdougm } 13264327Sdougm } else { 13274327Sdougm share = find_share(group, sharepath); 13284327Sdougm } 13294327Sdougm if (share != NULL) 13303034Sdougm break; 13313034Sdougm } 13323034Sdougm return (share); 13333034Sdougm } 13343034Sdougm 13353034Sdougm /* 13363348Sdougm * sa_check_path(group, path, strictness) 13373034Sdougm * 13385331Samw * Check that path is a valid path relative to the group. Currently, 13393034Sdougm * we are ignoring the group and checking only the NFS rules. Later, 13403034Sdougm * we may want to use the group to then check against the protocols 13413348Sdougm * enabled on the group. The strictness values mean: 13423348Sdougm * SA_CHECK_NORMAL == only check newpath against shares that are active 13433348Sdougm * SA_CHECK_STRICT == check newpath against both active shares and those 13443348Sdougm * stored in the repository 13453034Sdougm */ 13463034Sdougm 13473034Sdougm int 13483348Sdougm sa_check_path(sa_group_t group, char *path, int strictness) 13493034Sdougm { 13503910Sdougm sa_handle_t handle; 13513910Sdougm 13523910Sdougm handle = sa_find_group_handle(group); 13533910Sdougm return (validpath(handle, path, strictness)); 13543034Sdougm } 13553034Sdougm 13563034Sdougm /* 13575331Samw * mark_excluded_protos(group, share, flags) 13583034Sdougm * 13595331Samw * Walk through all the protocols enabled for the group and check to 13605331Samw * see if the share has any of them should be in the exclude list 13615331Samw * based on the featureset of the protocol. If there are any, add the 13625331Samw * "exclude" property to the share. 13635331Samw */ 13645331Samw static void 13655331Samw mark_excluded_protos(sa_group_t group, xmlNodePtr share, uint64_t flags) 13665331Samw { 13675331Samw sa_optionset_t optionset; 13685331Samw char exclude_list[SA_STRSIZE]; 13695331Samw char *sep = ""; 13705331Samw 13715331Samw exclude_list[0] = '\0'; 13725331Samw for (optionset = sa_get_optionset(group, NULL); 13735331Samw optionset != NULL; 13745331Samw optionset = sa_get_next_optionset(optionset)) { 13755331Samw char *value; 13765331Samw uint64_t features; 13775331Samw value = sa_get_optionset_attr(optionset, "type"); 13785331Samw if (value == NULL) 13795331Samw continue; 13805331Samw features = sa_proto_get_featureset(value); 13815331Samw sa_free_attr_string(value); 13825331Samw if (!(features & flags)) { 13835331Samw (void) strlcat(exclude_list, sep, 13845331Samw sizeof (exclude_list)); 13855331Samw (void) strlcat(exclude_list, value, 13865331Samw sizeof (exclude_list)); 13875331Samw sep = ","; 13885331Samw } 13895331Samw } 13905331Samw if (exclude_list[0] != '\0') 1391*6007Sthurlow (void) xmlSetProp(share, (xmlChar *)"exclude", 13925331Samw (xmlChar *)exclude_list); 13935331Samw } 13945331Samw 13955331Samw /* 13965331Samw * get_all_features(group) 13975331Samw * 13985331Samw * Walk through all the protocols on the group and collect all 13995331Samw * possible enabled features. This is the OR of all the featuresets. 14005331Samw */ 14015331Samw static uint64_t 14025331Samw get_all_features(sa_group_t group) 14035331Samw { 14045331Samw sa_optionset_t optionset; 14055331Samw uint64_t features = 0; 14065331Samw 14075331Samw for (optionset = sa_get_optionset(group, NULL); 14085331Samw optionset != NULL; 14095331Samw optionset = sa_get_next_optionset(optionset)) { 14105331Samw char *value; 14115331Samw value = sa_get_optionset_attr(optionset, "type"); 14125331Samw if (value == NULL) 14135331Samw continue; 14145331Samw features |= sa_proto_get_featureset(value); 14155331Samw sa_free_attr_string(value); 14165331Samw } 14175331Samw return (features); 14185331Samw } 14195331Samw 14205331Samw 14215331Samw /* 14225331Samw * _sa_add_share(group, sharepath, persist, *error, flags) 14235331Samw * 14245331Samw * Common code for all types of add_share. sa_add_share() is the 14253034Sdougm * public API, we also need to be able to do this when parsing legacy 14263034Sdougm * files and construction of the internal configuration while 14275331Samw * extracting config info from SMF. "flags" indicates if some 14285331Samw * protocols need relaxed rules while other don't. These values are 14295331Samw * the featureset values defined in libshare.h. 14303034Sdougm */ 14313034Sdougm 14323034Sdougm sa_share_t 14335331Samw _sa_add_share(sa_group_t group, char *sharepath, int persist, int *error, 14345331Samw uint64_t flags) 14353034Sdougm { 14363034Sdougm xmlNodePtr node = NULL; 14373034Sdougm int err; 14383034Sdougm 14393034Sdougm err = SA_OK; /* assume success */ 14403034Sdougm 14414327Sdougm node = xmlNewChild((xmlNodePtr)group, NULL, (xmlChar *)"share", NULL); 14425331Samw if (node == NULL) { 14435331Samw if (error != NULL) 14445331Samw *error = SA_NO_MEMORY; 14455331Samw return (node); 14465331Samw } 14475331Samw 1448*6007Sthurlow (void) xmlSetProp(node, (xmlChar *)"path", (xmlChar *)sharepath); 1449*6007Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", 14505331Samw persist ? (xmlChar *)"persist" : (xmlChar *)"transient"); 14515331Samw if (flags != 0) 14525331Samw mark_excluded_protos(group, node, flags); 14535331Samw if (persist != SA_SHARE_TRANSIENT) { 14545331Samw /* 14555331Samw * persistent shares come in two flavors: SMF and 14565331Samw * ZFS. Sort this one out based on target group and 14575331Samw * path type. Both NFS and SMB are supported. First, 14585331Samw * check to see if the protocol is enabled on the 14595331Samw * subgroup and then setup the share appropriately. 14605331Samw */ 14615331Samw if (sa_group_is_zfs(group) && 14625331Samw sa_path_is_zfs(sharepath)) { 14635331Samw if (sa_get_optionset(group, "nfs") != NULL) 14644327Sdougm err = sa_zfs_set_sharenfs(group, sharepath, 1); 14655331Samw else if (sa_get_optionset(group, "smb") != NULL) 14665331Samw err = sa_zfs_set_sharesmb(group, sharepath, 1); 14675331Samw } else { 14685331Samw sa_handle_impl_t impl_handle; 14695331Samw impl_handle = 14705331Samw (sa_handle_impl_t)sa_find_group_handle(group); 14715331Samw if (impl_handle != NULL) { 14725331Samw err = sa_commit_share(impl_handle->scfhandle, 14735331Samw group, (sa_share_t)node); 14744327Sdougm } else { 14755331Samw err = SA_SYSTEM_ERR; 14764327Sdougm } 14773034Sdougm } 14783034Sdougm } 14795331Samw if (err == SA_NO_PERMISSION && persist & SA_SHARE_PARSER) 14805331Samw /* called by the dfstab parser so could be a show */ 14815331Samw err = SA_OK; 14825331Samw 14835331Samw if (err != SA_OK) { 14845331Samw /* 14855331Samw * we couldn't commit to the repository so undo 14865331Samw * our internal state to reflect reality. 14875331Samw */ 14885331Samw xmlUnlinkNode(node); 14895331Samw xmlFreeNode(node); 14905331Samw node = NULL; 14915331Samw } 14925331Samw 14933034Sdougm if (error != NULL) 14944327Sdougm *error = err; 14955331Samw 14963034Sdougm return (node); 14973034Sdougm } 14983034Sdougm 14993034Sdougm /* 15003034Sdougm * sa_add_share(group, sharepath, persist, *error) 15013034Sdougm * 15023034Sdougm * Add a new share object to the specified group. The share will 15033034Sdougm * have the specified sharepath and will only be constructed if 15043034Sdougm * it is a valid path to be shared. NULL is returned on error 15053034Sdougm * and a detailed error value will be returned via the error 15063034Sdougm * pointer. 15073034Sdougm */ 15083034Sdougm sa_share_t 15093034Sdougm sa_add_share(sa_group_t group, char *sharepath, int persist, int *error) 15103034Sdougm { 15113034Sdougm xmlNodePtr node = NULL; 15123348Sdougm int strictness = SA_CHECK_NORMAL; 15133910Sdougm sa_handle_t handle; 15145331Samw uint64_t special = 0; 15155331Samw uint64_t features; 15163348Sdougm 15173348Sdougm /* 15183348Sdougm * If the share is to be permanent, use strict checking so a 15193348Sdougm * bad config doesn't get created. Transient shares only need 15203348Sdougm * to check against the currently active 15213348Sdougm * shares. SA_SHARE_PARSER is a modifier used internally to 15223348Sdougm * indicate that we are being called by the dfstab parser and 15233348Sdougm * that we need strict checking in all cases. Normally persist 15243348Sdougm * is in integer value but SA_SHARE_PARSER may be or'd into 15253348Sdougm * it as an override. 15263348Sdougm */ 15273348Sdougm if (persist & SA_SHARE_PARSER || persist == SA_SHARE_PERMANENT) 15284327Sdougm strictness = SA_CHECK_STRICT; 15293034Sdougm 15303910Sdougm handle = sa_find_group_handle(group); 15313910Sdougm 15325331Samw /* 15335331Samw * need to determine if the share is valid. The rules are: 15345331Samw * - The path must not already exist 15355331Samw * - The path must not be a subdir or parent dir of an 15365331Samw * existing path unless at least one protocol allows it. 15375331Samw * The sub/parent check is done in sa_check_path(). 15385331Samw */ 15395331Samw 15405331Samw if (sa_find_share(handle, sharepath) == NULL) { 15415331Samw *error = sa_check_path(group, sharepath, strictness); 15425331Samw features = get_all_features(group); 15435331Samw switch (*error) { 15445331Samw case SA_PATH_IS_SUBDIR: 15455331Samw if (features & SA_FEATURE_ALLOWSUBDIRS) 15465331Samw special |= SA_FEATURE_ALLOWSUBDIRS; 15475331Samw break; 15485331Samw case SA_PATH_IS_PARENTDIR: 15495331Samw if (features & SA_FEATURE_ALLOWPARDIRS) 15505331Samw special |= SA_FEATURE_ALLOWPARDIRS; 15515331Samw break; 15525331Samw } 15535331Samw if (*error == SA_OK || special != SA_FEATURE_NONE) 15545331Samw node = _sa_add_share(group, sharepath, persist, 15555331Samw error, special); 15565331Samw } else { 15575331Samw *error = SA_DUPLICATE_NAME; 15583034Sdougm } 15593034Sdougm 15603034Sdougm return ((sa_share_t)node); 15613034Sdougm } 15623034Sdougm 15633034Sdougm /* 15643034Sdougm * sa_enable_share(share, protocol) 15653034Sdougm * Enable the specified share to the specified protocol. 15663034Sdougm * If protocol is NULL, then all protocols. 15673034Sdougm */ 15683034Sdougm int 15693034Sdougm sa_enable_share(sa_share_t share, char *protocol) 15703034Sdougm { 15713034Sdougm char *sharepath; 15723034Sdougm struct stat st; 15735331Samw int err = SA_OK; 15745331Samw int ret; 15753034Sdougm 15763034Sdougm sharepath = sa_get_share_attr(share, "path"); 15775331Samw if (sharepath == NULL) 15785331Samw return (SA_NO_MEMORY); 15793034Sdougm if (stat(sharepath, &st) < 0) { 15804327Sdougm err = SA_NO_SUCH_PATH; 15813034Sdougm } else { 15824327Sdougm /* tell the server about the share */ 15834327Sdougm if (protocol != NULL) { 15845331Samw if (excluded_protocol(share, protocol)) 15855331Samw goto done; 15865331Samw 15874327Sdougm /* lookup protocol specific handler */ 15884327Sdougm err = sa_proto_share(protocol, share); 15894327Sdougm if (err == SA_OK) 15905331Samw (void) sa_set_share_attr(share, 15915331Samw "shared", "true"); 15924327Sdougm } else { 15935331Samw /* Tell all protocols about the share */ 15945331Samw sa_group_t group; 15955331Samw sa_optionset_t optionset; 15965331Samw 15975331Samw group = sa_get_parent_group(share); 15985331Samw 15995331Samw for (optionset = sa_get_optionset(group, NULL); 16005331Samw optionset != NULL; 16015331Samw optionset = sa_get_next_optionset(optionset)) { 16025331Samw char *proto; 16035331Samw proto = sa_get_optionset_attr(optionset, 16045331Samw "type"); 16055331Samw if (proto != NULL) { 16065331Samw if (!excluded_protocol(share, proto)) { 16075331Samw ret = sa_proto_share(proto, 16085331Samw share); 16095331Samw if (ret != SA_OK) 16105331Samw err = ret; 16115331Samw } 16125331Samw sa_free_attr_string(proto); 16135331Samw } 16145331Samw } 16154327Sdougm (void) sa_set_share_attr(share, "shared", "true"); 16164327Sdougm } 16173034Sdougm } 16185331Samw done: 16193034Sdougm if (sharepath != NULL) 16204327Sdougm sa_free_attr_string(sharepath); 16213034Sdougm return (err); 16223034Sdougm } 16233034Sdougm 16243034Sdougm /* 16253034Sdougm * sa_disable_share(share, protocol) 16265331Samw * Disable the specified share to the specified protocol. If 16275331Samw * protocol is NULL, then all protocols that are enabled for the 16285331Samw * share should be disabled. 16293034Sdougm */ 16303034Sdougm int 16313034Sdougm sa_disable_share(sa_share_t share, char *protocol) 16323034Sdougm { 16333034Sdougm char *path; 16345331Samw int err = SA_OK; 16353034Sdougm int ret = SA_OK; 16363034Sdougm 16373034Sdougm path = sa_get_share_attr(share, "path"); 16383034Sdougm 16393034Sdougm if (protocol != NULL) { 16404543Smarks ret = sa_proto_unshare(share, protocol, path); 16413034Sdougm } else { 16424327Sdougm /* need to do all protocols */ 16435331Samw sa_group_t group; 16445331Samw sa_optionset_t optionset; 16455331Samw 16465331Samw group = sa_get_parent_group(share); 16475331Samw 16485331Samw /* Tell all protocols about the share */ 16495331Samw for (optionset = sa_get_optionset(group, NULL); 16505331Samw optionset != NULL; 16515331Samw optionset = sa_get_next_optionset(optionset)) { 16525331Samw char *proto; 16535331Samw 16545331Samw proto = sa_get_optionset_attr(optionset, "type"); 16555331Samw if (proto != NULL) { 16565331Samw err = sa_proto_unshare(share, proto, path); 16575331Samw if (err != SA_OK) 16585331Samw ret = err; 16595331Samw sa_free_attr_string(proto); 16605331Samw } 16615331Samw } 16623034Sdougm } 16633034Sdougm if (ret == SA_OK) 16643034Sdougm (void) sa_set_share_attr(share, "shared", NULL); 16653034Sdougm if (path != NULL) 16664327Sdougm sa_free_attr_string(path); 16673034Sdougm return (ret); 16683034Sdougm } 16693034Sdougm 16703034Sdougm /* 16713034Sdougm * sa_remove_share(share) 16723034Sdougm * 16733034Sdougm * remove the specified share from its containing group. 16743034Sdougm * Remove from the SMF or ZFS configuration space. 16753034Sdougm */ 16763034Sdougm 16773034Sdougm int 16783034Sdougm sa_remove_share(sa_share_t share) 16793034Sdougm { 16803034Sdougm sa_group_t group; 16813034Sdougm int ret = SA_OK; 16823034Sdougm char *type; 16833034Sdougm int transient = 0; 16843034Sdougm char *groupname; 16853034Sdougm char *zfs; 16863034Sdougm 16873034Sdougm type = sa_get_share_attr(share, "type"); 16883034Sdougm group = sa_get_parent_group(share); 16893034Sdougm zfs = sa_get_group_attr(group, "zfs"); 16903034Sdougm groupname = sa_get_group_attr(group, "name"); 16913034Sdougm if (type != NULL && strcmp(type, "persist") != 0) 16924327Sdougm transient = 1; 16933034Sdougm if (type != NULL) 16944327Sdougm sa_free_attr_string(type); 16953034Sdougm 16963034Sdougm /* remove the node from its group then free the memory */ 16973034Sdougm 16983034Sdougm /* 16993034Sdougm * need to test if "busy" 17003034Sdougm */ 17013034Sdougm /* only do SMF action if permanent */ 17023034Sdougm if (!transient || zfs != NULL) { 17034327Sdougm /* remove from legacy dfstab as well as possible SMF */ 17045331Samw ret = sa_delete_legacy(share, NULL); 17054327Sdougm if (ret == SA_OK) { 17064327Sdougm if (!sa_group_is_zfs(group)) { 17074327Sdougm sa_handle_impl_t impl_handle; 17084327Sdougm impl_handle = (sa_handle_impl_t) 17094327Sdougm sa_find_group_handle(group); 17104327Sdougm if (impl_handle != NULL) { 17114327Sdougm ret = sa_delete_share( 17124327Sdougm impl_handle->scfhandle, group, 17134327Sdougm share); 17144327Sdougm } else { 17154327Sdougm ret = SA_SYSTEM_ERR; 17164327Sdougm } 17174327Sdougm } else { 17184327Sdougm char *sharepath = sa_get_share_attr(share, 17194327Sdougm "path"); 17204327Sdougm if (sharepath != NULL) { 17214327Sdougm ret = sa_zfs_set_sharenfs(group, 17224327Sdougm sharepath, 0); 17234327Sdougm sa_free_attr_string(sharepath); 17244327Sdougm } 17254327Sdougm } 17263034Sdougm } 17273034Sdougm } 17283034Sdougm if (groupname != NULL) 17294327Sdougm sa_free_attr_string(groupname); 17303034Sdougm if (zfs != NULL) 17314327Sdougm sa_free_attr_string(zfs); 17323034Sdougm 17333034Sdougm xmlUnlinkNode((xmlNodePtr)share); 17343034Sdougm xmlFreeNode((xmlNodePtr)share); 17353034Sdougm return (ret); 17363034Sdougm } 17373034Sdougm 17383034Sdougm /* 17393034Sdougm * sa_move_share(group, share) 17403034Sdougm * 17413034Sdougm * move the specified share to the specified group. Update SMF 17423034Sdougm * appropriately. 17433034Sdougm */ 17443034Sdougm 17453034Sdougm int 17463034Sdougm sa_move_share(sa_group_t group, sa_share_t share) 17473034Sdougm { 17483034Sdougm sa_group_t oldgroup; 17493034Sdougm int ret = SA_OK; 17503034Sdougm 17513034Sdougm /* remove the node from its group then free the memory */ 17523034Sdougm 17533034Sdougm oldgroup = sa_get_parent_group(share); 17543034Sdougm if (oldgroup != group) { 17554327Sdougm sa_handle_impl_t impl_handle; 17564327Sdougm xmlUnlinkNode((xmlNodePtr)share); 17573034Sdougm /* 17584327Sdougm * now that the share isn't in its old group, add to 17594327Sdougm * the new one 17603034Sdougm */ 1761*6007Sthurlow (void) xmlAddChild((xmlNodePtr)group, (xmlNodePtr)share); 17624327Sdougm /* need to deal with SMF */ 17634327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 17644327Sdougm if (impl_handle != NULL) { 17654327Sdougm /* 17664327Sdougm * need to remove from old group first and then add to 17674327Sdougm * new group. Ideally, we would do the other order but 17684327Sdougm * need to avoid having the share in two groups at the 17694327Sdougm * same time. 17704327Sdougm */ 17714327Sdougm ret = sa_delete_share(impl_handle->scfhandle, oldgroup, 17724327Sdougm share); 17734327Sdougm if (ret == SA_OK) 17744327Sdougm ret = sa_commit_share(impl_handle->scfhandle, 17754327Sdougm group, share); 17764327Sdougm } else { 17774327Sdougm ret = SA_SYSTEM_ERR; 17784327Sdougm } 17793034Sdougm } 17803034Sdougm return (ret); 17813034Sdougm } 17823034Sdougm 17833034Sdougm /* 17843034Sdougm * sa_get_parent_group(share) 17853034Sdougm * 17865331Samw * Return the containing group for the share. If a group was actually 17873034Sdougm * passed in, we don't want a parent so return NULL. 17883034Sdougm */ 17893034Sdougm 17903034Sdougm sa_group_t 17913034Sdougm sa_get_parent_group(sa_share_t share) 17923034Sdougm { 17933034Sdougm xmlNodePtr node = NULL; 17943034Sdougm if (share != NULL) { 17954327Sdougm node = ((xmlNodePtr)share)->parent; 17963034Sdougm /* 17973034Sdougm * make sure parent is a group and not sharecfg since 17983034Sdougm * we may be cheating and passing in a group. 17993034Sdougm * Eventually, groups of groups might come into being. 18003034Sdougm */ 18014327Sdougm if (node == NULL || 18024327Sdougm xmlStrcmp(node->name, (xmlChar *)"sharecfg") == 0) 18034327Sdougm node = NULL; 18043034Sdougm } 18053034Sdougm return ((sa_group_t)node); 18063034Sdougm } 18073034Sdougm 18083034Sdougm /* 18093910Sdougm * _sa_create_group(impl_handle, groupname) 18103034Sdougm * 18113034Sdougm * Create a group in the document. The caller will need to deal with 18123034Sdougm * configuration store and activation. 18133034Sdougm */ 18143034Sdougm 18153034Sdougm sa_group_t 18163910Sdougm _sa_create_group(sa_handle_impl_t impl_handle, char *groupname) 18173034Sdougm { 18183034Sdougm xmlNodePtr node = NULL; 18193034Sdougm 18203034Sdougm if (sa_valid_group_name(groupname)) { 18214327Sdougm node = xmlNewChild(impl_handle->tree, NULL, (xmlChar *)"group", 18224327Sdougm NULL); 18234327Sdougm if (node != NULL) { 1824*6007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 18254327Sdougm (xmlChar *)groupname); 1826*6007Sthurlow (void) xmlSetProp(node, (xmlChar *)"state", 18274327Sdougm (xmlChar *)"enabled"); 18284327Sdougm } 18293034Sdougm } 18303034Sdougm return ((sa_group_t)node); 18313034Sdougm } 18323034Sdougm 18333034Sdougm /* 18343034Sdougm * _sa_create_zfs_group(group, groupname) 18353034Sdougm * 18363034Sdougm * Create a ZFS subgroup under the specified group. This may 18373034Sdougm * eventually form the basis of general sub-groups, but is currently 18383034Sdougm * restricted to ZFS. 18393034Sdougm */ 18403034Sdougm sa_group_t 18413034Sdougm _sa_create_zfs_group(sa_group_t group, char *groupname) 18423034Sdougm { 18433034Sdougm xmlNodePtr node = NULL; 18443034Sdougm 18454327Sdougm node = xmlNewChild((xmlNodePtr)group, NULL, (xmlChar *)"group", NULL); 18463034Sdougm if (node != NULL) { 1847*6007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 1848*6007Sthurlow (xmlChar *)groupname); 1849*6007Sthurlow (void) xmlSetProp(node, (xmlChar *)"state", 1850*6007Sthurlow (xmlChar *)"enabled"); 18513034Sdougm } 18523034Sdougm 18533034Sdougm return ((sa_group_t)node); 18543034Sdougm } 18553034Sdougm 18563034Sdougm /* 18573034Sdougm * sa_create_group(groupname, *error) 18583034Sdougm * 18593034Sdougm * Create a new group with groupname. Need to validate that it is a 18603034Sdougm * legal name for SMF and the construct the SMF service instance of 18613034Sdougm * svc:/network/shares/group to implement the group. All necessary 18623034Sdougm * operational properties must be added to the group at this point 18633034Sdougm * (via the SMF transaction model). 18643034Sdougm */ 18653034Sdougm sa_group_t 18663910Sdougm sa_create_group(sa_handle_t handle, char *groupname, int *error) 18673034Sdougm { 18683034Sdougm xmlNodePtr node = NULL; 18693034Sdougm sa_group_t group; 18703034Sdougm int ret; 18714327Sdougm char rbacstr[SA_STRSIZE]; 18723910Sdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle; 18733034Sdougm 18743034Sdougm ret = SA_OK; 18753034Sdougm 18763910Sdougm if (impl_handle == NULL || impl_handle->scfhandle == NULL) { 18774327Sdougm ret = SA_SYSTEM_ERR; 18784327Sdougm goto err; 18793034Sdougm } 18803034Sdougm 18813910Sdougm group = sa_get_group(handle, groupname); 18823034Sdougm if (group != NULL) { 18834327Sdougm ret = SA_DUPLICATE_NAME; 18843034Sdougm } else { 18854327Sdougm if (sa_valid_group_name(groupname)) { 18864327Sdougm node = xmlNewChild(impl_handle->tree, NULL, 18874327Sdougm (xmlChar *)"group", NULL); 18884327Sdougm if (node != NULL) { 1889*6007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 18904327Sdougm (xmlChar *)groupname); 18914327Sdougm /* default to the group being enabled */ 1892*6007Sthurlow (void) xmlSetProp(node, (xmlChar *)"state", 18934327Sdougm (xmlChar *)"enabled"); 18944327Sdougm ret = sa_create_instance(impl_handle->scfhandle, 18954327Sdougm groupname); 18964327Sdougm if (ret == SA_OK) { 18974327Sdougm ret = sa_start_transaction( 18984327Sdougm impl_handle->scfhandle, 18994327Sdougm "operation"); 19004327Sdougm } 19014327Sdougm if (ret == SA_OK) { 19024327Sdougm ret = sa_set_property( 19034327Sdougm impl_handle->scfhandle, 19044327Sdougm "state", "enabled"); 19054327Sdougm if (ret == SA_OK) { 19064327Sdougm ret = sa_end_transaction( 19075951Sdougm impl_handle->scfhandle, 19085951Sdougm impl_handle); 19094327Sdougm } else { 19104327Sdougm sa_abort_transaction( 19114327Sdougm impl_handle->scfhandle); 19124327Sdougm } 19134327Sdougm } 19144327Sdougm if (ret == SA_OK) { 19154327Sdougm /* initialize the RBAC strings */ 19164327Sdougm ret = sa_start_transaction( 19174327Sdougm impl_handle->scfhandle, 19184327Sdougm "general"); 19194327Sdougm if (ret == SA_OK) { 19204327Sdougm (void) snprintf(rbacstr, 19214327Sdougm sizeof (rbacstr), "%s.%s", 19224327Sdougm SA_RBAC_MANAGE, groupname); 19234327Sdougm ret = sa_set_property( 19244327Sdougm impl_handle->scfhandle, 19253034Sdougm "action_authorization", 19263034Sdougm rbacstr); 19274327Sdougm } 19284327Sdougm if (ret == SA_OK) { 19294327Sdougm (void) snprintf(rbacstr, 19304327Sdougm sizeof (rbacstr), "%s.%s", 19314327Sdougm SA_RBAC_VALUE, groupname); 19324327Sdougm ret = sa_set_property( 19334327Sdougm impl_handle->scfhandle, 19343034Sdougm "value_authorization", 19353034Sdougm rbacstr); 19364327Sdougm } 19374327Sdougm if (ret == SA_OK) { 19384327Sdougm ret = sa_end_transaction( 19395951Sdougm impl_handle->scfhandle, 19405951Sdougm impl_handle); 19414327Sdougm } else { 19424327Sdougm sa_abort_transaction( 19434327Sdougm impl_handle->scfhandle); 19444327Sdougm } 19454327Sdougm } 19464327Sdougm if (ret != SA_OK) { 19474327Sdougm /* 19484327Sdougm * Couldn't commit the group 19494327Sdougm * so we need to undo 19504327Sdougm * internally. 19514327Sdougm */ 19524327Sdougm xmlUnlinkNode(node); 19534327Sdougm xmlFreeNode(node); 19544327Sdougm node = NULL; 19554327Sdougm } 19563034Sdougm } else { 19574327Sdougm ret = SA_NO_MEMORY; 19583034Sdougm } 19593034Sdougm } else { 19604327Sdougm ret = SA_INVALID_NAME; 19613034Sdougm } 19623034Sdougm } 19633034Sdougm err: 19643034Sdougm if (error != NULL) 19654327Sdougm *error = ret; 19663034Sdougm return ((sa_group_t)node); 19673034Sdougm } 19683034Sdougm 19693034Sdougm /* 19703034Sdougm * sa_remove_group(group) 19713034Sdougm * 19723034Sdougm * Remove the specified group. This deletes from the SMF repository. 19733034Sdougm * All property groups and properties are removed. 19743034Sdougm */ 19753034Sdougm 19763034Sdougm int 19773034Sdougm sa_remove_group(sa_group_t group) 19783034Sdougm { 19793034Sdougm char *name; 19803034Sdougm int ret = SA_OK; 19813910Sdougm sa_handle_impl_t impl_handle; 19823034Sdougm 19833910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 19843910Sdougm if (impl_handle != NULL) { 19854327Sdougm name = sa_get_group_attr(group, "name"); 19864327Sdougm if (name != NULL) { 19874327Sdougm ret = sa_delete_instance(impl_handle->scfhandle, name); 19884327Sdougm sa_free_attr_string(name); 19894327Sdougm } 19904327Sdougm xmlUnlinkNode((xmlNodePtr)group); /* make sure unlinked */ 19914327Sdougm xmlFreeNode((xmlNodePtr)group); /* now it is gone */ 19923910Sdougm } else { 19934327Sdougm ret = SA_SYSTEM_ERR; 19943034Sdougm } 19953034Sdougm return (ret); 19963034Sdougm } 19973034Sdougm 19983034Sdougm /* 19993034Sdougm * sa_update_config() 20003034Sdougm * 20013034Sdougm * Used to update legacy files that need to be updated in bulk 20023034Sdougm * Currently, this is a placeholder and will go away in a future 20033034Sdougm * release. 20043034Sdougm */ 20053034Sdougm 20063034Sdougm int 20073910Sdougm sa_update_config(sa_handle_t handle) 20083034Sdougm { 20093034Sdougm /* 20103034Sdougm * do legacy files first so we can tell when they change. 20113034Sdougm * This will go away when we start updating individual records 20123034Sdougm * rather than the whole file. 20133034Sdougm */ 20143910Sdougm update_legacy_config(handle); 20153034Sdougm return (SA_OK); 20163034Sdougm } 20173034Sdougm 20183034Sdougm /* 20193034Sdougm * get_node_attr(node, tag) 20203034Sdougm * 20215331Samw * Get the specified tag(attribute) if it exists on the node. This is 20223034Sdougm * used internally by a number of attribute oriented functions. 20233034Sdougm */ 20243034Sdougm 20253034Sdougm static char * 20263034Sdougm get_node_attr(void *nodehdl, char *tag) 20273034Sdougm { 20283034Sdougm xmlNodePtr node = (xmlNodePtr)nodehdl; 20293034Sdougm xmlChar *name = NULL; 20303034Sdougm 20314327Sdougm if (node != NULL) 20323034Sdougm name = xmlGetProp(node, (xmlChar *)tag); 20333034Sdougm return ((char *)name); 20343034Sdougm } 20353034Sdougm 20363034Sdougm /* 20373034Sdougm * get_node_attr(node, tag) 20383034Sdougm * 20395331Samw * Set the specified tag(attribute) to the specified value This is 20403034Sdougm * used internally by a number of attribute oriented functions. It 20413034Sdougm * doesn't update the repository, only the internal document state. 20423034Sdougm */ 20433034Sdougm 20443034Sdougm void 20453034Sdougm set_node_attr(void *nodehdl, char *tag, char *value) 20463034Sdougm { 20473034Sdougm xmlNodePtr node = (xmlNodePtr)nodehdl; 20483034Sdougm if (node != NULL && tag != NULL) { 20494327Sdougm if (value != NULL) 2050*6007Sthurlow (void) xmlSetProp(node, (xmlChar *)tag, 2051*6007Sthurlow (xmlChar *)value); 20524327Sdougm else 2053*6007Sthurlow (void) xmlUnsetProp(node, (xmlChar *)tag); 20543034Sdougm } 20553034Sdougm } 20563034Sdougm 20573034Sdougm /* 20583034Sdougm * sa_get_group_attr(group, tag) 20593034Sdougm * 20603034Sdougm * Get the specied attribute, if defined, for the group. 20613034Sdougm */ 20623034Sdougm 20633034Sdougm char * 20643034Sdougm sa_get_group_attr(sa_group_t group, char *tag) 20653034Sdougm { 20663034Sdougm return (get_node_attr((void *)group, tag)); 20673034Sdougm } 20683034Sdougm 20693034Sdougm /* 20703034Sdougm * sa_set_group_attr(group, tag, value) 20713034Sdougm * 20723034Sdougm * set the specified tag/attribute on the group using value as its 20733034Sdougm * value. 20743034Sdougm * 20753034Sdougm * This will result in setting the property in the SMF repository as 20763034Sdougm * well as in the internal document. 20773034Sdougm */ 20783034Sdougm 20793034Sdougm int 20803034Sdougm sa_set_group_attr(sa_group_t group, char *tag, char *value) 20813034Sdougm { 20823034Sdougm int ret; 20833034Sdougm char *groupname; 20843910Sdougm sa_handle_impl_t impl_handle; 20853034Sdougm 20865331Samw /* 20875331Samw * ZFS group/subgroup doesn't need the handle so shortcut. 20885331Samw */ 20895331Samw if (sa_group_is_zfs(group)) { 20905331Samw set_node_attr((void *)group, tag, value); 20915331Samw return (SA_OK); 20925331Samw } 20935331Samw 20943910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 20953910Sdougm if (impl_handle != NULL) { 20964327Sdougm groupname = sa_get_group_attr(group, "name"); 20974327Sdougm ret = sa_get_instance(impl_handle->scfhandle, groupname); 20983910Sdougm if (ret == SA_OK) { 20994327Sdougm set_node_attr((void *)group, tag, value); 21004327Sdougm ret = sa_start_transaction(impl_handle->scfhandle, 21014327Sdougm "operation"); 21024327Sdougm if (ret == SA_OK) { 21034327Sdougm ret = sa_set_property(impl_handle->scfhandle, 21044327Sdougm tag, value); 21054327Sdougm if (ret == SA_OK) 21065885Sdougm ret = sa_end_transaction( 21075951Sdougm impl_handle->scfhandle, 21085951Sdougm impl_handle); 21094327Sdougm else 21104327Sdougm sa_abort_transaction( 21114327Sdougm impl_handle->scfhandle); 21124327Sdougm } 21135885Sdougm if (ret == SA_SYSTEM_ERR) 21145885Sdougm ret = SA_NO_PERMISSION; 21153034Sdougm } 21164327Sdougm if (groupname != NULL) 21174327Sdougm sa_free_attr_string(groupname); 21183910Sdougm } else { 21194327Sdougm ret = SA_SYSTEM_ERR; 21203034Sdougm } 21213034Sdougm return (ret); 21223034Sdougm } 21233034Sdougm 21243034Sdougm /* 21253034Sdougm * sa_get_share_attr(share, tag) 21263034Sdougm * 21273034Sdougm * Return the value of the tag/attribute set on the specified 21283034Sdougm * share. Returns NULL if the tag doesn't exist. 21293034Sdougm */ 21303034Sdougm 21313034Sdougm char * 21323034Sdougm sa_get_share_attr(sa_share_t share, char *tag) 21333034Sdougm { 21343034Sdougm return (get_node_attr((void *)share, tag)); 21353034Sdougm } 21363034Sdougm 21373034Sdougm /* 21383034Sdougm * _sa_set_share_description(share, description) 21393034Sdougm * 21405331Samw * Add a description tag with text contents to the specified share. A 21415331Samw * separate XML tag is used rather than a property. This can also be 21425331Samw * used with resources. 21433034Sdougm */ 21443034Sdougm 21453034Sdougm xmlNodePtr 21465331Samw _sa_set_share_description(void *share, char *content) 21473034Sdougm { 21483034Sdougm xmlNodePtr node; 21494327Sdougm node = xmlNewChild((xmlNodePtr)share, NULL, (xmlChar *)"description", 21504327Sdougm NULL); 21513034Sdougm xmlNodeSetContent(node, (xmlChar *)content); 21523034Sdougm return (node); 21533034Sdougm } 21543034Sdougm 21553034Sdougm /* 21563034Sdougm * sa_set_share_attr(share, tag, value) 21573034Sdougm * 21583034Sdougm * Set the share attribute specified by tag to the specified value. In 21593034Sdougm * the case of "resource", enforce a no duplicates in a group rule. If 21603034Sdougm * the share is not transient, commit the changes to the repository 21613034Sdougm * else just update the share internally. 21623034Sdougm */ 21633034Sdougm 21643034Sdougm int 21653034Sdougm sa_set_share_attr(sa_share_t share, char *tag, char *value) 21663034Sdougm { 21673034Sdougm sa_group_t group; 21683034Sdougm sa_share_t resource; 21693034Sdougm int ret = SA_OK; 21703034Sdougm 21713034Sdougm group = sa_get_parent_group(share); 21723034Sdougm 21733034Sdougm /* 21743034Sdougm * There are some attributes that may have specific 21753034Sdougm * restrictions on them. Initially, only "resource" has 21763034Sdougm * special meaning that needs to be checked. Only one instance 21773034Sdougm * of a resource name may exist within a group. 21783034Sdougm */ 21793034Sdougm 21803034Sdougm if (strcmp(tag, "resource") == 0) { 21814327Sdougm resource = sa_get_resource(group, value); 21824327Sdougm if (resource != share && resource != NULL) 21834327Sdougm ret = SA_DUPLICATE_NAME; 21843034Sdougm } 21853034Sdougm if (ret == SA_OK) { 21864327Sdougm set_node_attr((void *)share, tag, value); 21874327Sdougm if (group != NULL) { 21884327Sdougm char *type; 21894327Sdougm /* we can probably optimize this some */ 21904327Sdougm type = sa_get_share_attr(share, "type"); 21914327Sdougm if (type == NULL || strcmp(type, "transient") != 0) { 21924327Sdougm sa_handle_impl_t impl_handle; 21934327Sdougm impl_handle = 21944327Sdougm (sa_handle_impl_t)sa_find_group_handle( 21954327Sdougm group); 21964327Sdougm if (impl_handle != NULL) { 21974327Sdougm ret = sa_commit_share( 21984327Sdougm impl_handle->scfhandle, group, 21994327Sdougm share); 22004327Sdougm } else { 22014327Sdougm ret = SA_SYSTEM_ERR; 22024327Sdougm } 22034327Sdougm } 22044327Sdougm if (type != NULL) 22054327Sdougm sa_free_attr_string(type); 22063910Sdougm } 22073034Sdougm } 22083034Sdougm return (ret); 22093034Sdougm } 22103034Sdougm 22113034Sdougm /* 22123034Sdougm * sa_get_property_attr(prop, tag) 22133034Sdougm * 22143034Sdougm * Get the value of the specified property attribute. Standard 22153034Sdougm * attributes are "type" and "value". 22163034Sdougm */ 22173034Sdougm 22183034Sdougm char * 22193034Sdougm sa_get_property_attr(sa_property_t prop, char *tag) 22203034Sdougm { 22213034Sdougm return (get_node_attr((void *)prop, tag)); 22223034Sdougm } 22233034Sdougm 22243034Sdougm /* 22253034Sdougm * sa_get_optionset_attr(prop, tag) 22263034Sdougm * 22273034Sdougm * Get the value of the specified property attribute. Standard 22283034Sdougm * attribute is "type". 22293034Sdougm */ 22303034Sdougm 22313034Sdougm char * 22323034Sdougm sa_get_optionset_attr(sa_property_t optionset, char *tag) 22333034Sdougm { 22343034Sdougm return (get_node_attr((void *)optionset, tag)); 22353034Sdougm 22363034Sdougm } 22373034Sdougm 22383034Sdougm /* 22393034Sdougm * sa_set_optionset_attr(optionset, tag, value) 22403034Sdougm * 22413034Sdougm * Set the specified attribute(tag) to the specified value on the 22423034Sdougm * optionset. 22433034Sdougm */ 22443034Sdougm 22453034Sdougm void 22463034Sdougm sa_set_optionset_attr(sa_group_t optionset, char *tag, char *value) 22473034Sdougm { 22483034Sdougm set_node_attr((void *)optionset, tag, value); 22493034Sdougm } 22503034Sdougm 22513034Sdougm /* 22523034Sdougm * sa_free_attr_string(string) 22533034Sdougm * 22543034Sdougm * Free the string that was returned in one of the sa_get_*_attr() 22553034Sdougm * functions. 22563034Sdougm */ 22573034Sdougm 22583034Sdougm void 22593034Sdougm sa_free_attr_string(char *string) 22603034Sdougm { 22613034Sdougm xmlFree((xmlChar *)string); 22623034Sdougm } 22633034Sdougm 22643034Sdougm /* 22653034Sdougm * sa_get_optionset(group, proto) 22663034Sdougm * 22673034Sdougm * Return the optionset, if it exists, that is associated with the 22683034Sdougm * specified protocol. 22693034Sdougm */ 22703034Sdougm 22713034Sdougm sa_optionset_t 22723034Sdougm sa_get_optionset(void *group, char *proto) 22733034Sdougm { 22743034Sdougm xmlNodePtr node; 22753034Sdougm xmlChar *value = NULL; 22763034Sdougm 22773034Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 22784327Sdougm node = node->next) { 22793034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) { 22804327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 22814327Sdougm if (proto != NULL) { 22824327Sdougm if (value != NULL && 22834327Sdougm xmlStrcmp(value, (xmlChar *)proto) == 0) { 22844327Sdougm break; 22854327Sdougm } 22864327Sdougm if (value != NULL) { 22874327Sdougm xmlFree(value); 22884327Sdougm value = NULL; 22894327Sdougm } 22904327Sdougm } else { 22914327Sdougm break; 22923034Sdougm } 22933034Sdougm } 22943034Sdougm } 22953034Sdougm if (value != NULL) 22964327Sdougm xmlFree(value); 22973034Sdougm return ((sa_optionset_t)node); 22983034Sdougm } 22993034Sdougm 23003034Sdougm /* 23013034Sdougm * sa_get_next_optionset(optionset) 23023034Sdougm * 23033034Sdougm * Return the next optionset in the group. NULL if this was the last. 23043034Sdougm */ 23053034Sdougm 23063034Sdougm sa_optionset_t 23073034Sdougm sa_get_next_optionset(sa_optionset_t optionset) 23083034Sdougm { 23093034Sdougm xmlNodePtr node; 23103034Sdougm 23113034Sdougm for (node = ((xmlNodePtr)optionset)->next; node != NULL; 23124327Sdougm node = node->next) { 23133034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) { 23143034Sdougm break; 23153034Sdougm } 23163034Sdougm } 23173034Sdougm return ((sa_optionset_t)node); 23183034Sdougm } 23193034Sdougm 23203034Sdougm /* 23213034Sdougm * sa_get_security(group, sectype, proto) 23223034Sdougm * 23233034Sdougm * Return the security optionset. The internal name is a hold over 23243034Sdougm * from the implementation and will be changed before the API is 23253034Sdougm * finalized. This is really a named optionset that can be negotiated 23263034Sdougm * as a group of properties (like NFS security options). 23273034Sdougm */ 23283034Sdougm 23293034Sdougm sa_security_t 23303034Sdougm sa_get_security(sa_group_t group, char *sectype, char *proto) 23313034Sdougm { 23323034Sdougm xmlNodePtr node; 23333034Sdougm xmlChar *value = NULL; 23343034Sdougm 23353034Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 23364327Sdougm node = node->next) { 23374327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) { 23384327Sdougm if (proto != NULL) { 23394327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 23404327Sdougm if (value == NULL || 23414327Sdougm (value != NULL && 23424327Sdougm xmlStrcmp(value, (xmlChar *)proto) != 0)) { 23434327Sdougm /* it doesn't match so continue */ 23444327Sdougm xmlFree(value); 23454327Sdougm value = NULL; 23464327Sdougm continue; 23474327Sdougm } 23484327Sdougm } 23494327Sdougm if (value != NULL) { 23504327Sdougm xmlFree(value); 23514327Sdougm value = NULL; 23524327Sdougm } 23534327Sdougm /* potential match */ 23544327Sdougm if (sectype != NULL) { 23554327Sdougm value = xmlGetProp(node, (xmlChar *)"sectype"); 23564327Sdougm if (value != NULL && 23574327Sdougm xmlStrcmp(value, (xmlChar *)sectype) == 0) { 23584327Sdougm break; 23594327Sdougm } 23604327Sdougm } else { 23614327Sdougm break; 23624327Sdougm } 23633034Sdougm } 23643034Sdougm if (value != NULL) { 23654327Sdougm xmlFree(value); 23664327Sdougm value = NULL; 23673034Sdougm } 23683034Sdougm } 23693034Sdougm if (value != NULL) 23704327Sdougm xmlFree(value); 23713034Sdougm return ((sa_security_t)node); 23723034Sdougm } 23733034Sdougm 23743034Sdougm /* 23753034Sdougm * sa_get_next_security(security) 23763034Sdougm * 23773034Sdougm * Get the next security optionset if one exists. 23783034Sdougm */ 23793034Sdougm 23803034Sdougm sa_security_t 23813034Sdougm sa_get_next_security(sa_security_t security) 23823034Sdougm { 23833034Sdougm xmlNodePtr node; 23843034Sdougm 23853034Sdougm for (node = ((xmlNodePtr)security)->next; node != NULL; 23864327Sdougm node = node->next) { 23873034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) { 23883034Sdougm break; 23893034Sdougm } 23903034Sdougm } 23913034Sdougm return ((sa_security_t)node); 23923034Sdougm } 23933034Sdougm 23943034Sdougm /* 23953034Sdougm * sa_get_property(optionset, prop) 23963034Sdougm * 23973034Sdougm * Get the property object with the name specified in prop from the 23983034Sdougm * optionset. 23993034Sdougm */ 24003034Sdougm 24013034Sdougm sa_property_t 24023034Sdougm sa_get_property(sa_optionset_t optionset, char *prop) 24033034Sdougm { 24043034Sdougm xmlNodePtr node = (xmlNodePtr)optionset; 24053034Sdougm xmlChar *value = NULL; 24063034Sdougm 24073034Sdougm if (optionset == NULL) 24084327Sdougm return (NULL); 24093034Sdougm 24103034Sdougm for (node = node->children; node != NULL; 24114327Sdougm node = node->next) { 24124327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 24134327Sdougm if (prop == NULL) 24144327Sdougm break; 24154327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 24164327Sdougm if (value != NULL && 24174327Sdougm xmlStrcmp(value, (xmlChar *)prop) == 0) { 24184327Sdougm break; 24194327Sdougm } 24204327Sdougm if (value != NULL) { 24214327Sdougm xmlFree(value); 24224327Sdougm value = NULL; 24234327Sdougm } 24243034Sdougm } 24253034Sdougm } 24263034Sdougm if (value != NULL) 24273034Sdougm xmlFree(value); 24283034Sdougm if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"option") != 0) { 24294327Sdougm /* 24304327Sdougm * avoid a non option node -- it is possible to be a 24314327Sdougm * text node 24324327Sdougm */ 24334327Sdougm node = NULL; 24343034Sdougm } 24353034Sdougm return ((sa_property_t)node); 24363034Sdougm } 24373034Sdougm 24383034Sdougm /* 24393034Sdougm * sa_get_next_property(property) 24403034Sdougm * 24413034Sdougm * Get the next property following the specified property. NULL if 24423034Sdougm * this was the last. 24433034Sdougm */ 24443034Sdougm 24453034Sdougm sa_property_t 24463034Sdougm sa_get_next_property(sa_property_t property) 24473034Sdougm { 24483034Sdougm xmlNodePtr node; 24493034Sdougm 24503034Sdougm for (node = ((xmlNodePtr)property)->next; node != NULL; 24514327Sdougm node = node->next) { 24523034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 24533034Sdougm break; 24543034Sdougm } 24553034Sdougm } 24563034Sdougm return ((sa_property_t)node); 24573034Sdougm } 24583034Sdougm 24593034Sdougm /* 24603034Sdougm * sa_set_share_description(share, content) 24613034Sdougm * 24623034Sdougm * Set the description of share to content. 24633034Sdougm */ 24643034Sdougm 24653034Sdougm int 24663034Sdougm sa_set_share_description(sa_share_t share, char *content) 24673034Sdougm { 24683034Sdougm xmlNodePtr node; 24693034Sdougm sa_group_t group; 24703034Sdougm int ret = SA_OK; 24713034Sdougm 24723034Sdougm for (node = ((xmlNodePtr)share)->children; node != NULL; 24734327Sdougm node = node->next) { 24743034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 24753034Sdougm break; 24763034Sdougm } 24773034Sdougm } 24783034Sdougm /* no existing description but want to add */ 24793034Sdougm if (node == NULL && content != NULL) { 24803034Sdougm /* add a description */ 24814327Sdougm node = _sa_set_share_description(share, content); 24823034Sdougm } else if (node != NULL && content != NULL) { 24833034Sdougm /* update a description */ 24843034Sdougm xmlNodeSetContent(node, (xmlChar *)content); 24853034Sdougm } else if (node != NULL && content == NULL) { 24863034Sdougm /* remove an existing description */ 24873034Sdougm xmlUnlinkNode(node); 24883034Sdougm xmlFreeNode(node); 24893034Sdougm } 24905331Samw group = sa_get_parent_group(share); 24915331Samw if (group != NULL && sa_is_persistent(share)) { 24924327Sdougm sa_handle_impl_t impl_handle; 24934327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 24944327Sdougm if (impl_handle != NULL) { 24954327Sdougm ret = sa_commit_share(impl_handle->scfhandle, group, 24964327Sdougm share); 24974327Sdougm } else { 24984327Sdougm ret = SA_SYSTEM_ERR; 24994327Sdougm } 25003910Sdougm } 25013034Sdougm return (ret); 25023034Sdougm } 25033034Sdougm 25043034Sdougm /* 25053034Sdougm * fixproblemchars(string) 25063034Sdougm * 25073034Sdougm * don't want any newline or tab characters in the text since these 25083034Sdougm * could break display of data and legacy file formats. 25093034Sdougm */ 25103034Sdougm static void 25113034Sdougm fixproblemchars(char *str) 25123034Sdougm { 25133034Sdougm int c; 25143034Sdougm for (c = *str; c != '\0'; c = *++str) { 25154327Sdougm if (c == '\t' || c == '\n') 25164327Sdougm *str = ' '; 25174327Sdougm else if (c == '"') 25184327Sdougm *str = '\''; 25193034Sdougm } 25203034Sdougm } 25213034Sdougm 25223034Sdougm /* 25233034Sdougm * sa_get_share_description(share) 25243034Sdougm * 25253034Sdougm * Return the description text for the specified share if it 25263034Sdougm * exists. NULL if no description exists. 25273034Sdougm */ 25283034Sdougm 25293034Sdougm char * 25303034Sdougm sa_get_share_description(sa_share_t share) 25313034Sdougm { 25323034Sdougm xmlChar *description = NULL; 25333034Sdougm xmlNodePtr node; 25343034Sdougm 25353034Sdougm for (node = ((xmlNodePtr)share)->children; node != NULL; 25364327Sdougm node = node->next) { 25374327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 25384327Sdougm break; 25394327Sdougm } 25403034Sdougm } 25413034Sdougm if (node != NULL) { 25425331Samw description = xmlNodeGetContent(node); 25434327Sdougm fixproblemchars((char *)description); 25443034Sdougm } 25453034Sdougm return ((char *)description); 25463034Sdougm } 25473034Sdougm 25483034Sdougm /* 25493034Sdougm * sa_free(share_description(description) 25503034Sdougm * 25513034Sdougm * Free the description string. 25523034Sdougm */ 25533034Sdougm 25543034Sdougm void 25553034Sdougm sa_free_share_description(char *description) 25563034Sdougm { 25573034Sdougm xmlFree((xmlChar *)description); 25583034Sdougm } 25593034Sdougm 25603034Sdougm /* 25613034Sdougm * sa_create_optionset(group, proto) 25623034Sdougm * 25633034Sdougm * Create an optionset for the specified protocol in the specied 25643034Sdougm * group. This is manifested as a property group within SMF. 25653034Sdougm */ 25663034Sdougm 25673034Sdougm sa_optionset_t 25683034Sdougm sa_create_optionset(sa_group_t group, char *proto) 25693034Sdougm { 25703034Sdougm sa_optionset_t optionset; 25713034Sdougm sa_group_t parent = group; 25725331Samw sa_share_t share = NULL; 25735331Samw int err = SA_OK; 25745331Samw char *id = NULL; 25753034Sdougm 25763034Sdougm optionset = sa_get_optionset(group, proto); 25773034Sdougm if (optionset != NULL) { 25783034Sdougm /* can't have a duplicate protocol */ 25794327Sdougm optionset = NULL; 25803034Sdougm } else { 25815331Samw /* 25825331Samw * Account for resource names being slightly 25835331Samw * different. 25845331Samw */ 25855331Samw if (sa_is_share(group)) { 25865331Samw /* 25875331Samw * Transient shares do not have an "id" so not an 25885331Samw * error to not find one. 25895331Samw */ 25905331Samw id = sa_get_share_attr((sa_share_t)group, "id"); 25915331Samw } else if (sa_is_resource(group)) { 25925331Samw share = sa_get_resource_parent( 25935331Samw (sa_resource_t)group); 25945331Samw id = sa_get_resource_attr(share, "id"); 25955331Samw 25965331Samw /* id can be NULL if the group is transient (ZFS) */ 25975331Samw if (id == NULL && sa_is_persistent(group)) 25985331Samw err = SA_NO_MEMORY; 25995331Samw } 26005331Samw if (err == SA_NO_MEMORY) { 26015331Samw /* 26025331Samw * Couldn't get the id for the share or 26035331Samw * resource. While this could be a 26045331Samw * configuration issue, it is most likely an 26055331Samw * out of memory. In any case, fail the create. 26065331Samw */ 26075331Samw return (NULL); 26085331Samw } 26095331Samw 26104327Sdougm optionset = (sa_optionset_t)xmlNewChild((xmlNodePtr)group, 26114327Sdougm NULL, (xmlChar *)"optionset", NULL); 26123034Sdougm /* 26133034Sdougm * only put to repository if on a group and we were 26143034Sdougm * able to create an optionset. 26153034Sdougm */ 26164327Sdougm if (optionset != NULL) { 26174327Sdougm char oname[SA_STRSIZE]; 26184327Sdougm char *groupname; 26195331Samw 26205331Samw /* 26215331Samw * Need to get parent group in all cases, but also get 26225331Samw * the share if this is a resource. 26235331Samw */ 26245331Samw if (sa_is_share(group)) { 26254327Sdougm parent = sa_get_parent_group((sa_share_t)group); 26265331Samw } else if (sa_is_resource(group)) { 26275331Samw share = sa_get_resource_parent( 26285331Samw (sa_resource_t)group); 26295331Samw parent = sa_get_parent_group(share); 26305331Samw } 26314327Sdougm 26324327Sdougm sa_set_optionset_attr(optionset, "type", proto); 26333034Sdougm 26344327Sdougm (void) sa_optionset_name(optionset, oname, 26354327Sdougm sizeof (oname), id); 26364327Sdougm groupname = sa_get_group_attr(parent, "name"); 26375331Samw if (groupname != NULL && sa_is_persistent(group)) { 26384327Sdougm sa_handle_impl_t impl_handle; 26395331Samw impl_handle = 26405331Samw (sa_handle_impl_t)sa_find_group_handle( 26415331Samw group); 26424327Sdougm assert(impl_handle != NULL); 26434327Sdougm if (impl_handle != NULL) { 26444327Sdougm (void) sa_get_instance( 26455331Samw impl_handle->scfhandle, groupname); 26464327Sdougm (void) sa_create_pgroup( 26474327Sdougm impl_handle->scfhandle, oname); 26484327Sdougm } 26494327Sdougm } 26504327Sdougm if (groupname != NULL) 26514327Sdougm sa_free_attr_string(groupname); 26523034Sdougm } 26533034Sdougm } 26545331Samw 26555331Samw if (id != NULL) 26565331Samw sa_free_attr_string(id); 26573034Sdougm return (optionset); 26583034Sdougm } 26593034Sdougm 26603034Sdougm /* 26613034Sdougm * sa_get_property_parent(property) 26623034Sdougm * 26633034Sdougm * Given a property, return the object it is a property of. This will 26643034Sdougm * be an optionset of some type. 26653034Sdougm */ 26663034Sdougm 26673034Sdougm static sa_optionset_t 26683034Sdougm sa_get_property_parent(sa_property_t property) 26693034Sdougm { 26703034Sdougm xmlNodePtr node = NULL; 26713034Sdougm 26724327Sdougm if (property != NULL) 26734327Sdougm node = ((xmlNodePtr)property)->parent; 26743034Sdougm return ((sa_optionset_t)node); 26753034Sdougm } 26763034Sdougm 26773034Sdougm /* 26783034Sdougm * sa_get_optionset_parent(optionset) 26793034Sdougm * 26803034Sdougm * Return the parent of the specified optionset. This could be a group 26813034Sdougm * or a share. 26823034Sdougm */ 26833034Sdougm 26843034Sdougm static sa_group_t 26853034Sdougm sa_get_optionset_parent(sa_optionset_t optionset) 26863034Sdougm { 26873034Sdougm xmlNodePtr node = NULL; 26883034Sdougm 26894327Sdougm if (optionset != NULL) 26904327Sdougm node = ((xmlNodePtr)optionset)->parent; 26913034Sdougm return ((sa_group_t)node); 26923034Sdougm } 26933034Sdougm 26943034Sdougm /* 26953034Sdougm * zfs_needs_update(share) 26963034Sdougm * 26973034Sdougm * In order to avoid making multiple updates to a ZFS share when 26983034Sdougm * setting properties, the share attribute "changed" will be set to 26995331Samw * true when a property is added or modified. When done adding 27003034Sdougm * properties, we can then detect that an update is needed. We then 27013034Sdougm * clear the state here to detect additional changes. 27023034Sdougm */ 27033034Sdougm 27043034Sdougm static int 27053034Sdougm zfs_needs_update(sa_share_t share) 27063034Sdougm { 27073034Sdougm char *attr; 27083034Sdougm int result = 0; 27093034Sdougm 27103034Sdougm attr = sa_get_share_attr(share, "changed"); 27113034Sdougm if (attr != NULL) { 27124327Sdougm sa_free_attr_string(attr); 27133034Sdougm result = 1; 27143034Sdougm } 27153034Sdougm set_node_attr((void *)share, "changed", NULL); 27163034Sdougm return (result); 27173034Sdougm } 27183034Sdougm 27193034Sdougm /* 27203034Sdougm * zfs_set_update(share) 27213034Sdougm * 27223034Sdougm * Set the changed attribute of the share to true. 27233034Sdougm */ 27243034Sdougm 27253034Sdougm static void 27263034Sdougm zfs_set_update(sa_share_t share) 27273034Sdougm { 27283034Sdougm set_node_attr((void *)share, "changed", "true"); 27293034Sdougm } 27303034Sdougm 27313034Sdougm /* 27323034Sdougm * sa_commit_properties(optionset, clear) 27333034Sdougm * 27343034Sdougm * Check if SMF or ZFS config and either update or abort the pending 27353034Sdougm * changes. 27363034Sdougm */ 27373034Sdougm 27383034Sdougm int 27393034Sdougm sa_commit_properties(sa_optionset_t optionset, int clear) 27403034Sdougm { 27413034Sdougm sa_group_t group; 27423034Sdougm sa_group_t parent; 27433034Sdougm int zfs = 0; 27443034Sdougm int needsupdate = 0; 27453034Sdougm int ret = SA_OK; 27463910Sdougm sa_handle_impl_t impl_handle; 27473034Sdougm 27483034Sdougm group = sa_get_optionset_parent(optionset); 27493034Sdougm if (group != NULL && (sa_is_share(group) || is_zfs_group(group))) { 27504327Sdougm /* only update ZFS if on a share */ 27514327Sdougm parent = sa_get_parent_group(group); 27524327Sdougm zfs++; 27534327Sdougm if (parent != NULL && is_zfs_group(parent)) 27544327Sdougm needsupdate = zfs_needs_update(group); 27554327Sdougm else 27564327Sdougm zfs = 0; 27573034Sdougm } 27583034Sdougm if (zfs) { 27594327Sdougm if (!clear && needsupdate) 27604327Sdougm ret = sa_zfs_update((sa_share_t)group); 27613034Sdougm } else { 27624327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 27634327Sdougm if (impl_handle != NULL) { 27644327Sdougm if (clear) { 27654327Sdougm (void) sa_abort_transaction( 27664327Sdougm impl_handle->scfhandle); 27674327Sdougm } else { 27684327Sdougm ret = sa_end_transaction( 27695951Sdougm impl_handle->scfhandle, impl_handle); 27704327Sdougm } 27714327Sdougm } else { 27724327Sdougm ret = SA_SYSTEM_ERR; 27734327Sdougm } 27743034Sdougm } 27753034Sdougm return (ret); 27763034Sdougm } 27773034Sdougm 27783034Sdougm /* 27793034Sdougm * sa_destroy_optionset(optionset) 27803034Sdougm * 27815331Samw * Remove the optionset from its group. Update the repository to 27823034Sdougm * reflect this change. 27833034Sdougm */ 27843034Sdougm 27853034Sdougm int 27863034Sdougm sa_destroy_optionset(sa_optionset_t optionset) 27873034Sdougm { 27884327Sdougm char name[SA_STRSIZE]; 27893034Sdougm int len; 27903034Sdougm int ret; 27913034Sdougm char *id = NULL; 27923034Sdougm sa_group_t group; 27933034Sdougm int ispersist = 1; 27943034Sdougm 27953034Sdougm /* now delete the prop group */ 27963034Sdougm group = sa_get_optionset_parent(optionset); 27975331Samw if (group != NULL) { 27985331Samw if (sa_is_resource(group)) { 27995331Samw sa_resource_t resource = group; 28005331Samw sa_share_t share = sa_get_resource_parent(resource); 28015331Samw group = sa_get_parent_group(share); 28025331Samw id = sa_get_share_attr(share, "id"); 28035331Samw } else if (sa_is_share(group)) { 28045331Samw id = sa_get_share_attr((sa_share_t)group, "id"); 28055331Samw } 28065331Samw ispersist = sa_is_persistent(group); 28073034Sdougm } 28083034Sdougm if (ispersist) { 28094327Sdougm sa_handle_impl_t impl_handle; 28104327Sdougm len = sa_optionset_name(optionset, name, sizeof (name), id); 28114327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 28124327Sdougm if (impl_handle != NULL) { 28134327Sdougm if (len > 0) { 28144327Sdougm ret = sa_delete_pgroup(impl_handle->scfhandle, 28154327Sdougm name); 28164327Sdougm } 28174327Sdougm } else { 28184327Sdougm ret = SA_SYSTEM_ERR; 28193910Sdougm } 28203034Sdougm } 28213034Sdougm xmlUnlinkNode((xmlNodePtr)optionset); 28223034Sdougm xmlFreeNode((xmlNodePtr)optionset); 28233034Sdougm if (id != NULL) 28244327Sdougm sa_free_attr_string(id); 28253034Sdougm return (ret); 28263034Sdougm } 28273034Sdougm 28283034Sdougm /* private to the implementation */ 28293034Sdougm int 28303034Sdougm _sa_remove_optionset(sa_optionset_t optionset) 28313034Sdougm { 28323034Sdougm int ret = SA_OK; 28333034Sdougm 28343034Sdougm xmlUnlinkNode((xmlNodePtr)optionset); 28353034Sdougm xmlFreeNode((xmlNodePtr)optionset); 28363034Sdougm return (ret); 28373034Sdougm } 28383034Sdougm 28393034Sdougm /* 28403034Sdougm * sa_create_security(group, sectype, proto) 28413034Sdougm * 28423034Sdougm * Create a security optionset (one that has a type name and a 28433034Sdougm * proto). Security is left over from a pure NFS implementation. The 28443034Sdougm * naming will change in the future when the API is released. 28453034Sdougm */ 28463034Sdougm sa_security_t 28473034Sdougm sa_create_security(sa_group_t group, char *sectype, char *proto) 28483034Sdougm { 28493034Sdougm sa_security_t security; 28503034Sdougm char *id = NULL; 28513034Sdougm sa_group_t parent; 28523034Sdougm char *groupname = NULL; 28533034Sdougm 28543034Sdougm if (group != NULL && sa_is_share(group)) { 28554327Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 28564327Sdougm parent = sa_get_parent_group(group); 28574327Sdougm if (parent != NULL) 28584327Sdougm groupname = sa_get_group_attr(parent, "name"); 28593034Sdougm } else if (group != NULL) { 28604327Sdougm groupname = sa_get_group_attr(group, "name"); 28613034Sdougm } 28623034Sdougm 28633034Sdougm security = sa_get_security(group, sectype, proto); 28643034Sdougm if (security != NULL) { 28653034Sdougm /* can't have a duplicate security option */ 28663034Sdougm security = NULL; 28673034Sdougm } else { 28683034Sdougm security = (sa_security_t)xmlNewChild((xmlNodePtr)group, 28694327Sdougm NULL, (xmlChar *)"security", NULL); 28703034Sdougm if (security != NULL) { 28714327Sdougm char oname[SA_STRSIZE]; 28723034Sdougm sa_set_security_attr(security, "type", proto); 28733034Sdougm 28743034Sdougm sa_set_security_attr(security, "sectype", sectype); 28753034Sdougm (void) sa_security_name(security, oname, 28764327Sdougm sizeof (oname), id); 28775331Samw if (groupname != NULL && sa_is_persistent(group)) { 28784327Sdougm sa_handle_impl_t impl_handle; 28794327Sdougm impl_handle = 28804327Sdougm (sa_handle_impl_t)sa_find_group_handle( 28814327Sdougm group); 28824327Sdougm if (impl_handle != NULL) { 28834327Sdougm (void) sa_get_instance( 28844327Sdougm impl_handle->scfhandle, groupname); 28854327Sdougm (void) sa_create_pgroup( 28864327Sdougm impl_handle->scfhandle, oname); 28874327Sdougm } 28883034Sdougm } 28893034Sdougm } 28903034Sdougm } 28913034Sdougm if (groupname != NULL) 28924327Sdougm sa_free_attr_string(groupname); 28933034Sdougm return (security); 28943034Sdougm } 28953034Sdougm 28963034Sdougm /* 28973034Sdougm * sa_destroy_security(security) 28983034Sdougm * 28993034Sdougm * Remove the specified optionset from the document and the 29003034Sdougm * configuration. 29013034Sdougm */ 29023034Sdougm 29033034Sdougm int 29043034Sdougm sa_destroy_security(sa_security_t security) 29053034Sdougm { 29064327Sdougm char name[SA_STRSIZE]; 29073034Sdougm int len; 29083034Sdougm int ret = SA_OK; 29093034Sdougm char *id = NULL; 29103034Sdougm sa_group_t group; 29113034Sdougm int iszfs = 0; 29123034Sdougm int ispersist = 1; 29133034Sdougm 29143034Sdougm group = sa_get_optionset_parent(security); 29153034Sdougm 29163034Sdougm if (group != NULL) 29174327Sdougm iszfs = sa_group_is_zfs(group); 29183034Sdougm 29193034Sdougm if (group != NULL && !iszfs) { 29204327Sdougm if (sa_is_share(group)) 29215331Samw ispersist = sa_is_persistent(group); 29224327Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 29233034Sdougm } 29243034Sdougm if (ispersist) { 29254327Sdougm len = sa_security_name(security, name, sizeof (name), id); 29264327Sdougm if (!iszfs && len > 0) { 29274327Sdougm sa_handle_impl_t impl_handle; 29284327Sdougm impl_handle = 29294327Sdougm (sa_handle_impl_t)sa_find_group_handle(group); 29304327Sdougm if (impl_handle != NULL) { 29314327Sdougm ret = sa_delete_pgroup(impl_handle->scfhandle, 29324327Sdougm name); 29334327Sdougm } else { 29344327Sdougm ret = SA_SYSTEM_ERR; 29354327Sdougm } 29363910Sdougm } 29373034Sdougm } 29383034Sdougm xmlUnlinkNode((xmlNodePtr)security); 29393034Sdougm xmlFreeNode((xmlNodePtr)security); 29404327Sdougm if (iszfs) 29414327Sdougm ret = sa_zfs_update(group); 29423034Sdougm if (id != NULL) 29434327Sdougm sa_free_attr_string(id); 29443034Sdougm return (ret); 29453034Sdougm } 29463034Sdougm 29473034Sdougm /* 29483034Sdougm * sa_get_security_attr(optionset, tag) 29493034Sdougm * 29503034Sdougm * Return the specified attribute value from the optionset. 29513034Sdougm */ 29523034Sdougm 29533034Sdougm char * 29543034Sdougm sa_get_security_attr(sa_property_t optionset, char *tag) 29553034Sdougm { 29563034Sdougm return (get_node_attr((void *)optionset, tag)); 29573034Sdougm 29583034Sdougm } 29593034Sdougm 29603034Sdougm /* 29613034Sdougm * sa_set_security_attr(optionset, tag, value) 29623034Sdougm * 29633034Sdougm * Set the optioset attribute specied by tag to the specified value. 29643034Sdougm */ 29653034Sdougm 29663034Sdougm void 29673034Sdougm sa_set_security_attr(sa_group_t optionset, char *tag, char *value) 29683034Sdougm { 29693034Sdougm set_node_attr((void *)optionset, tag, value); 29703034Sdougm } 29713034Sdougm 29723034Sdougm /* 29733034Sdougm * is_nodetype(node, type) 29743034Sdougm * 29753034Sdougm * Check to see if node is of the type specified. 29763034Sdougm */ 29773034Sdougm 29783034Sdougm static int 29793034Sdougm is_nodetype(void *node, char *type) 29803034Sdougm { 29813034Sdougm return (strcmp((char *)((xmlNodePtr)node)->name, type) == 0); 29823034Sdougm } 29833034Sdougm 29844327Sdougm /* 29854327Sdougm * add_or_update() 29864327Sdougm * 29874327Sdougm * Add or update a property. Pulled out of sa_set_prop_by_prop for 29884327Sdougm * readability. 29894327Sdougm */ 29904327Sdougm static int 29914327Sdougm add_or_update(scfutilhandle_t *scf_handle, int type, scf_value_t *value, 29924327Sdougm scf_transaction_entry_t *entry, char *name, char *valstr) 29934327Sdougm { 29944327Sdougm int ret = SA_SYSTEM_ERR; 29954327Sdougm 29964327Sdougm if (value != NULL) { 29974327Sdougm if (type == SA_PROP_OP_ADD) 29984327Sdougm ret = scf_transaction_property_new(scf_handle->trans, 29994327Sdougm entry, name, SCF_TYPE_ASTRING); 30004327Sdougm else 30014327Sdougm ret = scf_transaction_property_change(scf_handle->trans, 30024327Sdougm entry, name, SCF_TYPE_ASTRING); 30034327Sdougm if (ret == 0) { 30044327Sdougm ret = scf_value_set_astring(value, valstr); 30054327Sdougm if (ret == 0) 30064327Sdougm ret = scf_entry_add_value(entry, value); 30074327Sdougm if (ret == 0) 30084327Sdougm return (ret); 30094327Sdougm scf_value_destroy(value); 30104327Sdougm } else { 30114327Sdougm scf_entry_destroy(entry); 30124327Sdougm } 30134327Sdougm } 30144327Sdougm return (SA_SYSTEM_ERR); 30154327Sdougm } 30164327Sdougm 30173034Sdougm /* 30183034Sdougm * sa_set_prop_by_prop(optionset, group, prop, type) 30193034Sdougm * 30203034Sdougm * Add/remove/update the specified property prop into the optionset or 30213034Sdougm * share. If a share, sort out which property group based on GUID. In 30223034Sdougm * all cases, the appropriate transaction is set (or ZFS share is 30233034Sdougm * marked as needing an update) 30243034Sdougm */ 30253034Sdougm 30263034Sdougm static int 30273034Sdougm sa_set_prop_by_prop(sa_optionset_t optionset, sa_group_t group, 30283034Sdougm sa_property_t prop, int type) 30293034Sdougm { 30303034Sdougm char *name; 30313034Sdougm char *valstr; 30323034Sdougm int ret = SA_OK; 30333034Sdougm scf_transaction_entry_t *entry; 30343034Sdougm scf_value_t *value; 30353034Sdougm int opttype; /* 1 == optionset, 0 == security */ 30363034Sdougm char *id = NULL; 30373034Sdougm int iszfs = 0; 30383034Sdougm sa_group_t parent = NULL; 30395331Samw sa_share_t share = NULL; 30403910Sdougm sa_handle_impl_t impl_handle; 30413910Sdougm scfutilhandle_t *scf_handle; 30423034Sdougm 30435331Samw if (!sa_is_persistent(group)) { 30443034Sdougm /* 30453034Sdougm * if the group/share is not persistent we don't need 30463034Sdougm * to do anything here 30473034Sdougm */ 30484327Sdougm return (SA_OK); 30493034Sdougm } 30503910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 30514327Sdougm if (impl_handle == NULL || impl_handle->scfhandle == NULL) 30524327Sdougm return (SA_SYSTEM_ERR); 30533910Sdougm scf_handle = impl_handle->scfhandle; 30543034Sdougm name = sa_get_property_attr(prop, "type"); 30553034Sdougm valstr = sa_get_property_attr(prop, "value"); 30563034Sdougm entry = scf_entry_create(scf_handle->handle); 30573034Sdougm opttype = is_nodetype((void *)optionset, "optionset"); 30583034Sdougm 30595331Samw /* 30605331Samw * Check for share vs. resource since they need slightly 30615331Samw * different treatment given the hierarchy. 30625331Samw */ 30633034Sdougm if (valstr != NULL && entry != NULL) { 30644327Sdougm if (sa_is_share(group)) { 30654327Sdougm parent = sa_get_parent_group(group); 30665331Samw share = (sa_share_t)group; 30674327Sdougm if (parent != NULL) 30684327Sdougm iszfs = is_zfs_group(parent); 30695331Samw } else if (sa_is_resource(group)) { 30705331Samw share = sa_get_parent_group(group); 30715331Samw if (share != NULL) 30725331Samw parent = sa_get_parent_group(share); 30734327Sdougm } else { 30744327Sdougm iszfs = is_zfs_group(group); 30753034Sdougm } 30764327Sdougm if (!iszfs) { 30774327Sdougm if (scf_handle->trans == NULL) { 30784327Sdougm char oname[SA_STRSIZE]; 30794327Sdougm char *groupname = NULL; 30805331Samw if (share != NULL) { 30815331Samw if (parent != NULL) 30824327Sdougm groupname = 30834327Sdougm sa_get_group_attr(parent, 30844327Sdougm "name"); 30855331Samw id = sa_get_share_attr( 30865331Samw (sa_share_t)share, "id"); 30874327Sdougm } else { 30884327Sdougm groupname = sa_get_group_attr(group, 30894327Sdougm "name"); 30904327Sdougm } 30914327Sdougm if (groupname != NULL) { 30924327Sdougm ret = sa_get_instance(scf_handle, 30934327Sdougm groupname); 30944327Sdougm sa_free_attr_string(groupname); 30954327Sdougm } 30964327Sdougm if (opttype) 30974327Sdougm (void) sa_optionset_name(optionset, 30984327Sdougm oname, sizeof (oname), id); 30994327Sdougm else 31004327Sdougm (void) sa_security_name(optionset, 31014327Sdougm oname, sizeof (oname), id); 31024327Sdougm ret = sa_start_transaction(scf_handle, oname); 31033910Sdougm } 31044327Sdougm if (ret == SA_OK) { 31054327Sdougm switch (type) { 31064327Sdougm case SA_PROP_OP_REMOVE: 31074327Sdougm ret = scf_transaction_property_delete( 31084327Sdougm scf_handle->trans, entry, name); 31094327Sdougm break; 31104327Sdougm case SA_PROP_OP_ADD: 31114327Sdougm case SA_PROP_OP_UPDATE: 31124327Sdougm value = scf_value_create( 31134327Sdougm scf_handle->handle); 31144327Sdougm ret = add_or_update(scf_handle, type, 31154327Sdougm value, entry, name, valstr); 31164327Sdougm break; 31173034Sdougm } 31183034Sdougm } 31194327Sdougm } else { 31204327Sdougm /* 31214327Sdougm * ZFS update. The calling function would have updated 31224327Sdougm * the internal XML structure. Just need to flag it as 31234327Sdougm * changed for ZFS. 31244327Sdougm */ 31254327Sdougm zfs_set_update((sa_share_t)group); 31264327Sdougm } 31273034Sdougm } 31283034Sdougm 31293034Sdougm if (name != NULL) 31304327Sdougm sa_free_attr_string(name); 31313034Sdougm if (valstr != NULL) 31324327Sdougm sa_free_attr_string(valstr); 31333034Sdougm else if (entry != NULL) 31344327Sdougm scf_entry_destroy(entry); 31353034Sdougm 31363034Sdougm if (ret == -1) 31374327Sdougm ret = SA_SYSTEM_ERR; 31383034Sdougm 31393034Sdougm return (ret); 31403034Sdougm } 31413034Sdougm 31423034Sdougm /* 3143*6007Sthurlow * sa_create_section(name, value) 3144*6007Sthurlow * 3145*6007Sthurlow * Create a new section with the specified name and extra data. 3146*6007Sthurlow */ 3147*6007Sthurlow 3148*6007Sthurlow sa_property_t 3149*6007Sthurlow sa_create_section(char *name, char *extra) 3150*6007Sthurlow { 3151*6007Sthurlow xmlNodePtr node; 3152*6007Sthurlow 3153*6007Sthurlow node = xmlNewNode(NULL, (xmlChar *)"section"); 3154*6007Sthurlow if (node != NULL) { 3155*6007Sthurlow if (name != NULL) 3156*6007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 3157*6007Sthurlow (xmlChar *)name); 3158*6007Sthurlow if (extra != NULL) 3159*6007Sthurlow (void) xmlSetProp(node, (xmlChar *)"extra", 3160*6007Sthurlow (xmlChar *)extra); 3161*6007Sthurlow } 3162*6007Sthurlow return ((sa_property_t)node); 3163*6007Sthurlow } 3164*6007Sthurlow 3165*6007Sthurlow void 3166*6007Sthurlow sa_set_section_attr(sa_property_t sect, char *name, char *value) 3167*6007Sthurlow { 3168*6007Sthurlow (void) xmlSetProp(sect, (xmlChar *)name, (xmlChar *)value); 3169*6007Sthurlow } 3170*6007Sthurlow 3171*6007Sthurlow /* 3172*6007Sthurlow * sa_create_property(section, name, value) 31733034Sdougm * 31743034Sdougm * Create a new property with the specified name and value. 31753034Sdougm */ 31763034Sdougm 31773034Sdougm sa_property_t 31783034Sdougm sa_create_property(char *name, char *value) 31793034Sdougm { 31803034Sdougm xmlNodePtr node; 31813034Sdougm 31823034Sdougm node = xmlNewNode(NULL, (xmlChar *)"option"); 31833034Sdougm if (node != NULL) { 3184*6007Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", (xmlChar *)name); 3185*6007Sthurlow (void) xmlSetProp(node, (xmlChar *)"value", (xmlChar *)value); 31863034Sdougm } 31873034Sdougm return ((sa_property_t)node); 31883034Sdougm } 31893034Sdougm 31903034Sdougm /* 31913034Sdougm * sa_add_property(object, property) 31923034Sdougm * 31933034Sdougm * Add the specified property to the object. Issue the appropriate 31943034Sdougm * transaction or mark a ZFS object as needing an update. 31953034Sdougm */ 31963034Sdougm 31973034Sdougm int 31983034Sdougm sa_add_property(void *object, sa_property_t property) 31993034Sdougm { 32003034Sdougm int ret = SA_OK; 32013034Sdougm sa_group_t parent; 32023034Sdougm sa_group_t group; 32033034Sdougm char *proto; 32043034Sdougm 32053034Sdougm proto = sa_get_optionset_attr(object, "type"); 32063034Sdougm if (property != NULL) { 32074327Sdougm if ((ret = sa_valid_property(object, proto, property)) == 32084327Sdougm SA_OK) { 32094327Sdougm property = (sa_property_t)xmlAddChild( 32104327Sdougm (xmlNodePtr)object, (xmlNodePtr)property); 32114327Sdougm } else { 32124327Sdougm if (proto != NULL) 32134327Sdougm sa_free_attr_string(proto); 32144327Sdougm return (ret); 32154327Sdougm } 32163034Sdougm } 32173034Sdougm 32183034Sdougm if (proto != NULL) 32194327Sdougm sa_free_attr_string(proto); 32203034Sdougm 32213034Sdougm parent = sa_get_parent_group(object); 32225331Samw if (!sa_is_persistent(parent)) 32234327Sdougm return (ret); 32245331Samw 32255331Samw if (sa_is_resource(parent)) { 32265331Samw /* 32275331Samw * Resources are children of share. Need to go up two 32285331Samw * levels to find the group but the parent needs to be 32295331Samw * the share at this point in order to get the "id". 32305331Samw */ 32315331Samw parent = sa_get_parent_group(parent); 32325331Samw group = sa_get_parent_group(parent); 32335331Samw } else if (sa_is_share(parent)) { 32345331Samw group = sa_get_parent_group(parent); 32355331Samw } else { 32365331Samw group = parent; 32373034Sdougm } 32383034Sdougm 32394327Sdougm if (property == NULL) { 32404327Sdougm ret = SA_NO_MEMORY; 32414327Sdougm } else { 32424327Sdougm char oname[SA_STRSIZE]; 32433034Sdougm 32444327Sdougm if (!is_zfs_group(group)) { 32454327Sdougm char *id = NULL; 32464327Sdougm sa_handle_impl_t impl_handle; 32474327Sdougm scfutilhandle_t *scf_handle; 32483910Sdougm 32494327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle( 32504327Sdougm group); 32514327Sdougm if (impl_handle == NULL || 32524327Sdougm impl_handle->scfhandle == NULL) 32534327Sdougm ret = SA_SYSTEM_ERR; 32544327Sdougm if (ret == SA_OK) { 32554327Sdougm scf_handle = impl_handle->scfhandle; 32564327Sdougm if (sa_is_share((sa_group_t)parent)) { 32574327Sdougm id = sa_get_share_attr( 32584327Sdougm (sa_share_t)parent, "id"); 32594327Sdougm } 32604327Sdougm if (scf_handle->trans == NULL) { 32614327Sdougm if (is_nodetype(object, "optionset")) { 32624327Sdougm (void) sa_optionset_name( 32634327Sdougm (sa_optionset_t)object, 32644327Sdougm oname, sizeof (oname), id); 32654327Sdougm } else { 32664327Sdougm (void) sa_security_name( 32674327Sdougm (sa_optionset_t)object, 32684327Sdougm oname, sizeof (oname), id); 32694327Sdougm } 32704327Sdougm ret = sa_start_transaction(scf_handle, 32714327Sdougm oname); 32724327Sdougm } 32734327Sdougm if (ret == SA_OK) { 32744327Sdougm char *name; 32754327Sdougm char *value; 32764327Sdougm name = sa_get_property_attr(property, 32774327Sdougm "type"); 32784327Sdougm value = sa_get_property_attr(property, 32794327Sdougm "value"); 32804327Sdougm if (name != NULL && value != NULL) { 32814327Sdougm if (scf_handle->scf_state == 32824327Sdougm SCH_STATE_INIT) { 32834327Sdougm ret = sa_set_property( 32844327Sdougm scf_handle, name, 32854327Sdougm value); 32864327Sdougm } 32874327Sdougm } else { 32884327Sdougm ret = SA_CONFIG_ERR; 32894327Sdougm } 32904327Sdougm if (name != NULL) 32914327Sdougm sa_free_attr_string( 32924327Sdougm name); 32934327Sdougm if (value != NULL) 32944327Sdougm sa_free_attr_string(value); 32954327Sdougm } 32964327Sdougm if (id != NULL) 32974327Sdougm sa_free_attr_string(id); 32984327Sdougm } 32994327Sdougm } else { 33004327Sdougm /* 33014327Sdougm * ZFS is a special case. We do want 33024327Sdougm * to allow editing property/security 33034327Sdougm * lists since we can have a better 33044327Sdougm * syntax and we also want to keep 33054327Sdougm * things consistent when possible. 33064327Sdougm * 33074327Sdougm * Right now, we defer until the 33084327Sdougm * sa_commit_properties so we can get 33094327Sdougm * them all at once. We do need to 33104327Sdougm * mark the share as "changed" 33114327Sdougm */ 33124327Sdougm zfs_set_update((sa_share_t)parent); 33133034Sdougm } 33143034Sdougm } 33153034Sdougm return (ret); 33163034Sdougm } 33173034Sdougm 33183034Sdougm /* 33193034Sdougm * sa_remove_property(property) 33203034Sdougm * 33213034Sdougm * Remove the specied property from its containing object. Update the 33223034Sdougm * repository as appropriate. 33233034Sdougm */ 33243034Sdougm 33253034Sdougm int 33263034Sdougm sa_remove_property(sa_property_t property) 33273034Sdougm { 33283034Sdougm int ret = SA_OK; 33293034Sdougm 33303034Sdougm if (property != NULL) { 33313034Sdougm sa_optionset_t optionset; 33323034Sdougm sa_group_t group; 33333034Sdougm optionset = sa_get_property_parent(property); 33343034Sdougm if (optionset != NULL) { 33354327Sdougm group = sa_get_optionset_parent(optionset); 33364327Sdougm if (group != NULL) { 33374327Sdougm ret = sa_set_prop_by_prop(optionset, group, 33384327Sdougm property, SA_PROP_OP_REMOVE); 33394327Sdougm } 33403034Sdougm } 33413034Sdougm xmlUnlinkNode((xmlNodePtr)property); 33423034Sdougm xmlFreeNode((xmlNodePtr)property); 33433034Sdougm } else { 33444327Sdougm ret = SA_NO_SUCH_PROP; 33453034Sdougm } 33463034Sdougm return (ret); 33473034Sdougm } 33483034Sdougm 33493034Sdougm /* 33503034Sdougm * sa_update_property(property, value) 33513034Sdougm * 33523034Sdougm * Update the specified property to the new value. If value is NULL, 33533034Sdougm * we currently treat this as a remove. 33543034Sdougm */ 33553034Sdougm 33563034Sdougm int 33573034Sdougm sa_update_property(sa_property_t property, char *value) 33583034Sdougm { 33593034Sdougm int ret = SA_OK; 33603034Sdougm if (value == NULL) { 33613034Sdougm return (sa_remove_property(property)); 33623034Sdougm } else { 33633034Sdougm sa_optionset_t optionset; 33643034Sdougm sa_group_t group; 33653034Sdougm set_node_attr((void *)property, "value", value); 33663034Sdougm optionset = sa_get_property_parent(property); 33673034Sdougm if (optionset != NULL) { 33684327Sdougm group = sa_get_optionset_parent(optionset); 33694327Sdougm if (group != NULL) { 33704327Sdougm ret = sa_set_prop_by_prop(optionset, group, 33714327Sdougm property, SA_PROP_OP_UPDATE); 33724327Sdougm } 33733034Sdougm } else { 33744327Sdougm ret = SA_NO_SUCH_PROP; 33753034Sdougm } 33763034Sdougm } 33773034Sdougm return (ret); 33783034Sdougm } 33793034Sdougm 33803034Sdougm /* 3381*6007Sthurlow * sa_get_protocol_section(propset, prop) 3382*6007Sthurlow * 3383*6007Sthurlow * Get the specified protocol specific section. These are global to 3384*6007Sthurlow * the protocol and not specific to a group or share. 3385*6007Sthurlow */ 3386*6007Sthurlow 3387*6007Sthurlow sa_protocol_properties_t 3388*6007Sthurlow sa_get_protocol_section(sa_protocol_properties_t propset, char *section) 3389*6007Sthurlow { 3390*6007Sthurlow xmlNodePtr node = (xmlNodePtr)propset; 3391*6007Sthurlow xmlChar *value = NULL; 3392*6007Sthurlow char *proto; 3393*6007Sthurlow 3394*6007Sthurlow proto = sa_get_optionset_attr(propset, "type"); 3395*6007Sthurlow if ((sa_proto_get_featureset(proto) & SA_FEATURE_HAS_SECTIONS) == 0) 3396*6007Sthurlow return (propset); 3397*6007Sthurlow 3398*6007Sthurlow for (node = node->children; node != NULL; 3399*6007Sthurlow node = node->next) { 3400*6007Sthurlow if (xmlStrcmp(node->name, (xmlChar *)"section") == 0) { 3401*6007Sthurlow if (section == NULL) 3402*6007Sthurlow break; 3403*6007Sthurlow value = xmlGetProp(node, (xmlChar *)"name"); 3404*6007Sthurlow if (value != NULL && 3405*6007Sthurlow xmlStrcasecmp(value, (xmlChar *)section) == 0) { 3406*6007Sthurlow break; 3407*6007Sthurlow } 3408*6007Sthurlow if (value != NULL) { 3409*6007Sthurlow xmlFree(value); 3410*6007Sthurlow value = NULL; 3411*6007Sthurlow } 3412*6007Sthurlow } 3413*6007Sthurlow } 3414*6007Sthurlow if (value != NULL) 3415*6007Sthurlow xmlFree(value); 3416*6007Sthurlow if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"section") != 0) { 3417*6007Sthurlow /* 3418*6007Sthurlow * avoid a non option node -- it is possible to be a 3419*6007Sthurlow * text node 3420*6007Sthurlow */ 3421*6007Sthurlow node = NULL; 3422*6007Sthurlow } 3423*6007Sthurlow return ((sa_protocol_properties_t)node); 3424*6007Sthurlow } 3425*6007Sthurlow 3426*6007Sthurlow /* 3427*6007Sthurlow * sa_get_next_protocol_section(prop, find) 3428*6007Sthurlow * 3429*6007Sthurlow * Get the next protocol specific section in the list. 3430*6007Sthurlow */ 3431*6007Sthurlow 3432*6007Sthurlow sa_property_t 3433*6007Sthurlow sa_get_next_protocol_section(sa_property_t prop, char *find) 3434*6007Sthurlow { 3435*6007Sthurlow xmlNodePtr node; 3436*6007Sthurlow xmlChar *value = NULL; 3437*6007Sthurlow char *proto; 3438*6007Sthurlow 3439*6007Sthurlow proto = sa_get_optionset_attr(prop, "type"); 3440*6007Sthurlow if ((sa_proto_get_featureset(proto) & SA_FEATURE_HAS_SECTIONS) == 0) 3441*6007Sthurlow return ((sa_property_t)NULL); 3442*6007Sthurlow 3443*6007Sthurlow for (node = ((xmlNodePtr)prop)->next; node != NULL; 3444*6007Sthurlow node = node->next) { 3445*6007Sthurlow if (xmlStrcmp(node->name, (xmlChar *)"section") == 0) { 3446*6007Sthurlow if (find == NULL) 3447*6007Sthurlow break; 3448*6007Sthurlow value = xmlGetProp(node, (xmlChar *)"name"); 3449*6007Sthurlow if (value != NULL && 3450*6007Sthurlow xmlStrcasecmp(value, (xmlChar *)find) == 0) { 3451*6007Sthurlow break; 3452*6007Sthurlow } 3453*6007Sthurlow if (value != NULL) { 3454*6007Sthurlow xmlFree(value); 3455*6007Sthurlow value = NULL; 3456*6007Sthurlow } 3457*6007Sthurlow 3458*6007Sthurlow } 3459*6007Sthurlow } 3460*6007Sthurlow if (value != NULL) 3461*6007Sthurlow xmlFree(value); 3462*6007Sthurlow return ((sa_property_t)node); 3463*6007Sthurlow } 3464*6007Sthurlow 3465*6007Sthurlow /* 34663034Sdougm * sa_get_protocol_property(propset, prop) 34673034Sdougm * 34683034Sdougm * Get the specified protocol specific property. These are global to 34693034Sdougm * the protocol and not specific to a group or share. 34703034Sdougm */ 34713034Sdougm 34723034Sdougm sa_property_t 34733034Sdougm sa_get_protocol_property(sa_protocol_properties_t propset, char *prop) 34743034Sdougm { 34753034Sdougm xmlNodePtr node = (xmlNodePtr)propset; 34763034Sdougm xmlChar *value = NULL; 34773034Sdougm 3478*6007Sthurlow if (propset == NULL) 3479*6007Sthurlow return (NULL); 3480*6007Sthurlow 34813034Sdougm for (node = node->children; node != NULL; 34824327Sdougm node = node->next) { 34834327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 34844327Sdougm if (prop == NULL) 34854327Sdougm break; 34864327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 34874327Sdougm if (value != NULL && 34884327Sdougm xmlStrcasecmp(value, (xmlChar *)prop) == 0) { 34894327Sdougm break; 34904327Sdougm } 34914327Sdougm if (value != NULL) { 34924327Sdougm xmlFree(value); 34934327Sdougm value = NULL; 34944327Sdougm } 34953034Sdougm } 34963034Sdougm } 34973034Sdougm if (value != NULL) 34983034Sdougm xmlFree(value); 34993034Sdougm if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"option") != 0) { 35004327Sdougm /* 35014327Sdougm * avoid a non option node -- it is possible to be a 35024327Sdougm * text node 35034327Sdougm */ 35044327Sdougm node = NULL; 35053034Sdougm } 35063034Sdougm return ((sa_property_t)node); 35073034Sdougm } 35083034Sdougm 35093034Sdougm /* 35103034Sdougm * sa_get_next_protocol_property(prop) 35113034Sdougm * 35123034Sdougm * Get the next protocol specific property in the list. 35133034Sdougm */ 35143034Sdougm 35153034Sdougm sa_property_t 3516*6007Sthurlow sa_get_next_protocol_property(sa_property_t prop, char *find) 35173034Sdougm { 35183034Sdougm xmlNodePtr node; 3519*6007Sthurlow xmlChar *value = NULL; 35203034Sdougm 35213034Sdougm for (node = ((xmlNodePtr)prop)->next; node != NULL; 35224327Sdougm node = node->next) { 35233034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 3524*6007Sthurlow if (find == NULL) 3525*6007Sthurlow break; 3526*6007Sthurlow value = xmlGetProp(node, (xmlChar *)"type"); 3527*6007Sthurlow if (value != NULL && 3528*6007Sthurlow xmlStrcasecmp(value, (xmlChar *)find) == 0) { 3529*6007Sthurlow break; 3530*6007Sthurlow } 3531*6007Sthurlow if (value != NULL) { 3532*6007Sthurlow xmlFree(value); 3533*6007Sthurlow value = NULL; 3534*6007Sthurlow } 3535*6007Sthurlow 35363034Sdougm } 35373034Sdougm } 3538*6007Sthurlow if (value != NULL) 3539*6007Sthurlow xmlFree(value); 35403034Sdougm return ((sa_property_t)node); 35413034Sdougm } 35423034Sdougm 35433034Sdougm /* 35443034Sdougm * sa_set_protocol_property(prop, value) 35453034Sdougm * 35463034Sdougm * Set the specified property to have the new value. The protocol 35473034Sdougm * specific plugin will then be called to update the property. 35483034Sdougm */ 35493034Sdougm 35503034Sdougm int 3551*6007Sthurlow sa_set_protocol_property(sa_property_t prop, char *section, char *value) 35523034Sdougm { 35533034Sdougm sa_protocol_properties_t propset; 35543034Sdougm char *proto; 35553034Sdougm int ret = SA_INVALID_PROTOCOL; 35563034Sdougm 35573034Sdougm propset = ((xmlNodePtr)prop)->parent; 35583034Sdougm if (propset != NULL) { 35594327Sdougm proto = sa_get_optionset_attr(propset, "type"); 35604327Sdougm if (proto != NULL) { 3561*6007Sthurlow if (section != NULL) 3562*6007Sthurlow set_node_attr((xmlNodePtr)prop, "section", 3563*6007Sthurlow section); 35644327Sdougm set_node_attr((xmlNodePtr)prop, "value", value); 35654327Sdougm ret = sa_proto_set_property(proto, prop); 35664327Sdougm sa_free_attr_string(proto); 35674327Sdougm } 35683034Sdougm } 35693034Sdougm return (ret); 35703034Sdougm } 35713034Sdougm 35723034Sdougm /* 35733034Sdougm * sa_add_protocol_property(propset, prop) 35743034Sdougm * 35755331Samw * Add a new property to the protocol specific property set. 35763034Sdougm */ 35773034Sdougm 35783034Sdougm int 35793034Sdougm sa_add_protocol_property(sa_protocol_properties_t propset, sa_property_t prop) 35803034Sdougm { 35813034Sdougm xmlNodePtr node; 35823034Sdougm 35833034Sdougm /* should check for legitimacy */ 35843034Sdougm node = xmlAddChild((xmlNodePtr)propset, (xmlNodePtr)prop); 35853034Sdougm if (node != NULL) 35864327Sdougm return (SA_OK); 35873034Sdougm return (SA_NO_MEMORY); 35883034Sdougm } 35893034Sdougm 35903034Sdougm /* 35913034Sdougm * sa_create_protocol_properties(proto) 35923034Sdougm * 35935331Samw * Create a protocol specific property set. 35943034Sdougm */ 35953034Sdougm 35963034Sdougm sa_protocol_properties_t 35973034Sdougm sa_create_protocol_properties(char *proto) 35983034Sdougm { 35993034Sdougm xmlNodePtr node; 36004327Sdougm 36013034Sdougm node = xmlNewNode(NULL, (xmlChar *)"propertyset"); 36024327Sdougm if (node != NULL) 3603*6007Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto); 36043034Sdougm return (node); 36053034Sdougm } 36065331Samw 36075331Samw /* 36085331Samw * sa_get_share_resource(share, resource) 36095331Samw * 36105331Samw * Get the named resource from the share, if it exists. If resource is 36115331Samw * NULL, get the first resource. 36125331Samw */ 36135331Samw 36145331Samw sa_resource_t 36155331Samw sa_get_share_resource(sa_share_t share, char *resource) 36165331Samw { 36175331Samw xmlNodePtr node = NULL; 36185331Samw xmlChar *name; 36195331Samw 36205331Samw if (share != NULL) { 36215331Samw for (node = ((xmlNodePtr)share)->children; node != NULL; 36225331Samw node = node->next) { 36235331Samw if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0) { 36245331Samw if (resource == NULL) { 36255331Samw /* 36265331Samw * We are looking for the first 36275331Samw * resource node and not a names 36285331Samw * resource. 36295331Samw */ 36305331Samw break; 36315331Samw } else { 36325331Samw /* is it the correct share? */ 36335331Samw name = xmlGetProp(node, 36345331Samw (xmlChar *)"name"); 36355331Samw if (name != NULL && 36365331Samw xmlStrcasecmp(name, 36375331Samw (xmlChar *)resource) == 0) { 36385331Samw xmlFree(name); 36395331Samw break; 36405331Samw } 36415331Samw xmlFree(name); 36425331Samw } 36435331Samw } 36445331Samw } 36455331Samw } 36465331Samw return ((sa_resource_t)node); 36475331Samw } 36485331Samw 36495331Samw /* 36505331Samw * sa_get_next_resource(resource) 36515331Samw * Return the next share following the specified share 36525331Samw * from the internal list of shares. Returns NULL if there 36535331Samw * are no more shares. The list is relative to the same 36545331Samw * group. 36555331Samw */ 36565331Samw sa_share_t 36575331Samw sa_get_next_resource(sa_resource_t resource) 36585331Samw { 36595331Samw xmlNodePtr node = NULL; 36605331Samw 36615331Samw if (resource != NULL) { 36625331Samw for (node = ((xmlNodePtr)resource)->next; node != NULL; 36635331Samw node = node->next) { 36645331Samw if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0) 36655331Samw break; 36665331Samw } 36675331Samw } 36685331Samw return ((sa_share_t)node); 36695331Samw } 36705331Samw 36715331Samw /* 36725331Samw * _sa_get_next_resource_index(share) 36735331Samw * 36745331Samw * get the next resource index number (one greater then current largest) 36755331Samw */ 36765331Samw 36775331Samw static int 36785331Samw _sa_get_next_resource_index(sa_share_t share) 36795331Samw { 36805331Samw sa_resource_t resource; 36815331Samw int index = 0; 36825331Samw char *id; 36835331Samw 36845331Samw for (resource = sa_get_share_resource(share, NULL); 36855331Samw resource != NULL; 36865331Samw resource = sa_get_next_resource(resource)) { 36875331Samw id = get_node_attr((void *)resource, "id"); 36885331Samw if (id != NULL) { 36895331Samw int val; 36905331Samw val = atoi(id); 36915331Samw if (val > index) 36925331Samw index = val; 36935331Samw sa_free_attr_string(id); 36945331Samw } 36955331Samw } 36965331Samw return (index + 1); 36975331Samw } 36985331Samw 36995331Samw 37005331Samw /* 37015331Samw * sa_add_resource(share, resource, persist, &err) 37025331Samw * 37035331Samw * Adds a new resource name associated with share. The resource name 37045331Samw * must be unique in the system and will be case insensitive (eventually). 37055331Samw */ 37065331Samw 37075331Samw sa_resource_t 37085331Samw sa_add_resource(sa_share_t share, char *resource, int persist, int *error) 37095331Samw { 37105331Samw xmlNodePtr node; 37115331Samw int err = SA_OK; 37125331Samw sa_resource_t res; 37135331Samw sa_group_t group; 37145331Samw sa_handle_t handle; 37155331Samw char istring[8]; /* just big enough for an integer value */ 37165331Samw int index; 37175331Samw 37185331Samw group = sa_get_parent_group(share); 37195331Samw handle = sa_find_group_handle(group); 37205331Samw res = sa_find_resource(handle, resource); 37215331Samw if (res != NULL) { 37225331Samw err = SA_DUPLICATE_NAME; 37235331Samw res = NULL; 37245331Samw } else { 37255331Samw node = xmlNewChild((xmlNodePtr)share, NULL, 37265331Samw (xmlChar *)"resource", NULL); 37275331Samw if (node != NULL) { 3728*6007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 37295331Samw (xmlChar *)resource); 3730*6007Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", persist ? 37315331Samw (xmlChar *)"persist" : (xmlChar *)"transient"); 37325331Samw if (persist != SA_SHARE_TRANSIENT) { 37335331Samw index = _sa_get_next_resource_index(share); 37345331Samw (void) snprintf(istring, sizeof (istring), "%d", 37355331Samw index); 3736*6007Sthurlow (void) xmlSetProp(node, (xmlChar *)"id", 37375331Samw (xmlChar *)istring); 37385331Samw if (!sa_group_is_zfs(group) && 37395331Samw sa_is_persistent((sa_group_t)share)) { 37405331Samw /* ZFS doesn't use resource names */ 37415331Samw sa_handle_impl_t ihandle; 37425331Samw ihandle = (sa_handle_impl_t) 37435331Samw sa_find_group_handle( 37445331Samw group); 37455331Samw if (ihandle != NULL) 37465331Samw err = sa_commit_share( 37475331Samw ihandle->scfhandle, group, 37485331Samw share); 37495331Samw else 37505331Samw err = SA_SYSTEM_ERR; 37515331Samw } 37525331Samw } 37535331Samw } 37545331Samw } 37555331Samw if (error != NULL) 37565331Samw *error = err; 37575331Samw return ((sa_resource_t)node); 37585331Samw } 37595331Samw 37605331Samw /* 37615331Samw * sa_remove_resource(resource) 37625331Samw * 37635331Samw * Remove the resource name from the share (and the system) 37645331Samw */ 37655331Samw 37665331Samw int 37675331Samw sa_remove_resource(sa_resource_t resource) 37685331Samw { 37695331Samw sa_share_t share; 37705331Samw sa_group_t group; 37715331Samw char *type; 37725331Samw int ret = SA_OK; 37735331Samw int transient = 0; 37745521Sas200622 sa_optionset_t opt; 37755331Samw 37765331Samw share = sa_get_resource_parent(resource); 37775331Samw type = sa_get_share_attr(share, "type"); 37785331Samw group = sa_get_parent_group(share); 37795331Samw 37805331Samw 37815331Samw if (type != NULL) { 37825331Samw if (strcmp(type, "persist") != 0) 37835331Samw transient = 1; 37845331Samw sa_free_attr_string(type); 37855331Samw } 37865331Samw 37875521Sas200622 /* Disable the resource for all protocols. */ 37885521Sas200622 (void) sa_disable_resource(resource, NULL); 37895521Sas200622 37905521Sas200622 /* Remove any optionsets from the resource. */ 37915521Sas200622 for (opt = sa_get_optionset(resource, NULL); 37925521Sas200622 opt != NULL; 37935521Sas200622 opt = sa_get_next_optionset(opt)) 37945521Sas200622 (void) sa_destroy_optionset(opt); 37955521Sas200622 37965331Samw /* Remove from the share */ 37975331Samw xmlUnlinkNode((xmlNode *)resource); 37985331Samw xmlFreeNode((xmlNode *)resource); 37995331Samw 38005331Samw /* only do SMF action if permanent and not ZFS */ 38015331Samw if (!transient && !sa_group_is_zfs(group)) { 38025331Samw sa_handle_impl_t ihandle; 38035331Samw ihandle = (sa_handle_impl_t)sa_find_group_handle(group); 38045331Samw if (ihandle != NULL) 38055331Samw ret = sa_commit_share(ihandle->scfhandle, group, share); 38065331Samw else 38075331Samw ret = SA_SYSTEM_ERR; 38085331Samw } 38095331Samw return (ret); 38105331Samw } 38115331Samw 38125331Samw /* 38135331Samw * proto_resource_rename(handle, group, resource, newname) 38145331Samw * 38155331Samw * Helper function for sa_rename_resource that notifies the protocol 38165331Samw * of a resource name change prior to a config repository update. 38175331Samw */ 38185331Samw static int 38195331Samw proto_rename_resource(sa_handle_t handle, sa_group_t group, 38205331Samw sa_resource_t resource, char *newname) 38215331Samw { 38225331Samw sa_optionset_t optionset; 38235331Samw int ret = SA_OK; 38245331Samw int err; 38255331Samw 38265331Samw for (optionset = sa_get_optionset(group, NULL); 38275331Samw optionset != NULL; 38285331Samw optionset = sa_get_next_optionset(optionset)) { 38295331Samw char *type; 38305331Samw type = sa_get_optionset_attr(optionset, "type"); 38315331Samw if (type != NULL) { 38325331Samw err = sa_proto_rename_resource(handle, type, resource, 38335331Samw newname); 38345331Samw if (err != SA_OK) 38355331Samw ret = err; 38365331Samw sa_free_attr_string(type); 38375331Samw } 38385331Samw } 38395331Samw return (ret); 38405331Samw } 38415331Samw 38425331Samw /* 38435331Samw * sa_rename_resource(resource, newname) 38445331Samw * 38455331Samw * Rename the resource to the new name, if it is unique. 38465331Samw */ 38475331Samw 38485331Samw int 38495331Samw sa_rename_resource(sa_resource_t resource, char *newname) 38505331Samw { 38515331Samw sa_share_t share; 38525331Samw sa_group_t group = NULL; 38535331Samw sa_resource_t target; 38545331Samw int ret = SA_CONFIG_ERR; 38555331Samw sa_handle_t handle = NULL; 38565331Samw 38575331Samw share = sa_get_resource_parent(resource); 38585331Samw if (share == NULL) 38595331Samw return (ret); 38605331Samw 38615331Samw group = sa_get_parent_group(share); 38625331Samw if (group == NULL) 38635331Samw return (ret); 38645331Samw 38655331Samw handle = (sa_handle_impl_t)sa_find_group_handle(group); 38665331Samw if (handle == NULL) 38675331Samw return (ret); 38685331Samw 38695331Samw target = sa_find_resource(handle, newname); 38705331Samw if (target != NULL) { 38715331Samw ret = SA_DUPLICATE_NAME; 38725331Samw } else { 38735331Samw /* 38745331Samw * Everything appears to be valid at this 38755331Samw * point. Change the name of the active share and then 38765331Samw * update the share in the appropriate repository. 38775331Samw */ 38785331Samw ret = proto_rename_resource(handle, group, resource, newname); 38795331Samw set_node_attr(resource, "name", newname); 38805331Samw if (!sa_group_is_zfs(group) && 38815331Samw sa_is_persistent((sa_group_t)share)) { 38825331Samw sa_handle_impl_t ihandle = (sa_handle_impl_t)handle; 38835331Samw ret = sa_commit_share(ihandle->scfhandle, group, 38845331Samw share); 38855331Samw } 38865331Samw } 38875331Samw return (ret); 38885331Samw } 38895331Samw 38905331Samw /* 38915331Samw * sa_get_resource_attr(resource, tag) 38925331Samw * 38935331Samw * Get the named attribute of the resource. "name" and "id" are 38945331Samw * currently defined. NULL if tag not defined. 38955331Samw */ 38965331Samw 38975331Samw char * 38985331Samw sa_get_resource_attr(sa_resource_t resource, char *tag) 38995331Samw { 39005331Samw return (get_node_attr((void *)resource, tag)); 39015331Samw } 39025331Samw 39035331Samw /* 39045331Samw * sa_set_resource_attr(resource, tag, value) 39055331Samw * 39065331Samw * Get the named attribute of the resource. "name" and "id" are 39075331Samw * currently defined. NULL if tag not defined. Currently we don't do 39085331Samw * much, but additional checking may be needed in the future. 39095331Samw */ 39105331Samw 39115331Samw int 39125331Samw sa_set_resource_attr(sa_resource_t resource, char *tag, char *value) 39135331Samw { 39145331Samw set_node_attr((void *)resource, tag, value); 39155331Samw return (SA_OK); 39165331Samw } 39175331Samw 39185331Samw /* 39195331Samw * sa_get_resource_parent(resource_t) 39205331Samw * 39215331Samw * Returns the share associated with the resource. 39225331Samw */ 39235331Samw 39245331Samw sa_share_t 39255331Samw sa_get_resource_parent(sa_resource_t resource) 39265331Samw { 39275331Samw sa_share_t share = NULL; 39285331Samw 39295331Samw if (resource != NULL) 39305331Samw share = (sa_share_t)((xmlNodePtr)resource)->parent; 39315331Samw return (share); 39325331Samw } 39335331Samw 39345331Samw /* 39355331Samw * find_resource(group, name) 39365331Samw * 39375331Samw * Find the resource within the group. 39385331Samw */ 39395331Samw 39405331Samw static sa_resource_t 39415331Samw find_resource(sa_group_t group, char *resname) 39425331Samw { 39435331Samw sa_share_t share; 39445331Samw sa_resource_t resource = NULL; 39455331Samw char *name; 39465331Samw 39475331Samw /* Iterate over all the shares and resources in the group. */ 39485331Samw for (share = sa_get_share(group, NULL); 39495331Samw share != NULL && resource == NULL; 39505331Samw share = sa_get_next_share(share)) { 39515331Samw for (resource = sa_get_share_resource(share, NULL); 39525331Samw resource != NULL; 39535331Samw resource = sa_get_next_resource(resource)) { 39545331Samw name = sa_get_resource_attr(resource, "name"); 39555331Samw if (name != NULL && xmlStrcasecmp((xmlChar*)name, 39565331Samw (xmlChar*)resname) == 0) { 39575331Samw sa_free_attr_string(name); 39585331Samw break; 39595331Samw } 39605331Samw if (name != NULL) { 39615331Samw sa_free_attr_string(name); 39625331Samw } 39635331Samw } 39645331Samw } 39655331Samw return (resource); 39665331Samw } 39675331Samw 39685331Samw /* 39695331Samw * sa_find_resource(name) 39705331Samw * 39715331Samw * Find the named resource in the system. 39725331Samw */ 39735331Samw 39745331Samw sa_resource_t 39755331Samw sa_find_resource(sa_handle_t handle, char *name) 39765331Samw { 39775331Samw sa_group_t group; 39785331Samw sa_group_t zgroup; 39795331Samw sa_resource_t resource = NULL; 39805331Samw 39815331Samw /* 39825331Samw * Iterate over all groups and zfs subgroups and check for 39835331Samw * resource name in them. 39845331Samw */ 39855331Samw for (group = sa_get_group(handle, NULL); group != NULL; 39865331Samw group = sa_get_next_group(group)) { 39875331Samw 39885331Samw if (is_zfs_group(group)) { 39895331Samw for (zgroup = 39905331Samw (sa_group_t)_sa_get_child_node((xmlNodePtr)group, 39915331Samw (xmlChar *)"group"); 39925331Samw zgroup != NULL && resource == NULL; 39935331Samw zgroup = sa_get_next_group(zgroup)) { 39945331Samw resource = find_resource(zgroup, name); 39955331Samw } 39965331Samw } else { 39975331Samw resource = find_resource(group, name); 39985331Samw } 39995331Samw if (resource != NULL) 40005331Samw break; 40015331Samw } 40025331Samw return (resource); 40035331Samw } 40045331Samw 40055331Samw /* 40065331Samw * sa_get_resource(group, resource) 40075331Samw * 40085331Samw * Search all the shares in the specified group for a share with a 40095331Samw * resource name matching the one specified. 40105331Samw * 40115331Samw * In the future, it may be advantageous to allow group to be NULL and 40125331Samw * search all groups but that isn't needed at present. 40135331Samw */ 40145331Samw 40155331Samw sa_resource_t 40165331Samw sa_get_resource(sa_group_t group, char *resource) 40175331Samw { 40185331Samw sa_share_t share = NULL; 40195331Samw sa_resource_t res = NULL; 40205331Samw 40215331Samw if (resource != NULL) { 40225331Samw for (share = sa_get_share(group, NULL); 40235331Samw share != NULL && res == NULL; 40245331Samw share = sa_get_next_share(share)) { 40255331Samw res = sa_get_share_resource(share, resource); 40265331Samw } 40275331Samw } 40285331Samw return (res); 40295331Samw } 40305331Samw 40315331Samw /* 40325331Samw * sa_enable_resource, protocol) 40335331Samw * Disable the specified share to the specified protocol. 40345331Samw * If protocol is NULL, then all protocols. 40355331Samw */ 40365331Samw int 40375331Samw sa_enable_resource(sa_resource_t resource, char *protocol) 40385331Samw { 40395331Samw int ret = SA_OK; 40405331Samw char **protocols; 40415331Samw int numproto; 40425331Samw 40435331Samw if (protocol != NULL) { 40445331Samw ret = sa_proto_share_resource(protocol, resource); 40455331Samw } else { 40465331Samw /* need to do all protocols */ 40475331Samw if ((numproto = sa_get_protocols(&protocols)) >= 0) { 40485331Samw int i, err; 40495331Samw for (i = 0; i < numproto; i++) { 40505331Samw err = sa_proto_share_resource( 40515331Samw protocols[i], resource); 40525331Samw if (err != SA_OK) 40535331Samw ret = err; 40545331Samw } 40555331Samw free(protocols); 40565331Samw } 40575331Samw } 40585331Samw if (ret == SA_OK) 40595331Samw (void) sa_set_resource_attr(resource, "shared", NULL); 40605331Samw 40615331Samw return (ret); 40625331Samw } 40635331Samw 40645331Samw /* 40655331Samw * sa_disable_resource(resource, protocol) 40665331Samw * 40675331Samw * Disable the specified share for the specified protocol. If 40685331Samw * protocol is NULL, then all protocols. If the underlying 40695331Samw * protocol doesn't implement disable at the resource level, we 40705331Samw * disable at the share level. 40715331Samw */ 40725331Samw int 40735331Samw sa_disable_resource(sa_resource_t resource, char *protocol) 40745331Samw { 40755331Samw int ret = SA_OK; 40765331Samw char **protocols; 40775331Samw int numproto; 40785331Samw 40795331Samw if (protocol != NULL) { 40805331Samw ret = sa_proto_unshare_resource(protocol, resource); 40815331Samw if (ret == SA_NOT_IMPLEMENTED) { 40825331Samw sa_share_t parent; 40835331Samw /* 40845331Samw * The protocol doesn't implement unshare 40855331Samw * resource. That implies that resource names are 40865331Samw * simple aliases for this protocol so we need to 40875331Samw * unshare the share. 40885331Samw */ 40895331Samw parent = sa_get_resource_parent(resource); 40905331Samw if (parent != NULL) 40915331Samw ret = sa_disable_share(parent, protocol); 40925331Samw else 40935331Samw ret = SA_CONFIG_ERR; 40945331Samw } 40955331Samw } else { 40965331Samw /* need to do all protocols */ 40975331Samw if ((numproto = sa_get_protocols(&protocols)) >= 0) { 40985331Samw int i, err; 40995331Samw for (i = 0; i < numproto; i++) { 41005331Samw err = sa_proto_unshare_resource(protocols[i], 41015331Samw resource); 41025331Samw if (err == SA_NOT_SUPPORTED) { 41035331Samw sa_share_t parent; 41045331Samw parent = sa_get_resource_parent( 41055331Samw resource); 41065331Samw if (parent != NULL) 41075331Samw err = sa_disable_share(parent, 41085331Samw protocols[i]); 41095331Samw else 41105331Samw err = SA_CONFIG_ERR; 41115331Samw } 41125331Samw if (err != SA_OK) 41135331Samw ret = err; 41145331Samw } 41155331Samw free(protocols); 41165331Samw } 41175331Samw } 41185331Samw if (ret == SA_OK) 41195331Samw (void) sa_set_resource_attr(resource, "shared", NULL); 41205331Samw 41215331Samw return (ret); 41225331Samw } 41235331Samw 41245331Samw /* 41255331Samw * sa_set_resource_description(resource, content) 41265331Samw * 41275331Samw * Set the description of share to content. 41285331Samw */ 41295331Samw 41305331Samw int 41315331Samw sa_set_resource_description(sa_resource_t resource, char *content) 41325331Samw { 41335331Samw xmlNodePtr node; 41345331Samw sa_group_t group; 41355331Samw sa_share_t share; 41365331Samw int ret = SA_OK; 41375331Samw 41385331Samw for (node = ((xmlNodePtr)resource)->children; 41395331Samw node != NULL; 41405331Samw node = node->next) { 41415331Samw if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 41425331Samw break; 41435331Samw } 41445331Samw } 41455331Samw 41465331Samw /* no existing description but want to add */ 41475331Samw if (node == NULL && content != NULL) { 41485331Samw /* add a description */ 41495331Samw node = _sa_set_share_description(resource, content); 41505331Samw } else if (node != NULL && content != NULL) { 41515331Samw /* update a description */ 41525331Samw xmlNodeSetContent(node, (xmlChar *)content); 41535331Samw } else if (node != NULL && content == NULL) { 41545331Samw /* remove an existing description */ 41555331Samw xmlUnlinkNode(node); 41565331Samw xmlFreeNode(node); 41575331Samw } 41585331Samw share = sa_get_resource_parent(resource); 41595331Samw group = sa_get_parent_group(share); 41605331Samw if (group != NULL && sa_is_persistent(share)) { 41615331Samw sa_handle_impl_t impl_handle; 41625331Samw impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 41635331Samw if (impl_handle != NULL) 41645331Samw ret = sa_commit_share(impl_handle->scfhandle, 41655331Samw group, share); 41665331Samw else 41675331Samw ret = SA_SYSTEM_ERR; 41685331Samw } 41695331Samw return (ret); 41705331Samw } 41715331Samw 41725331Samw /* 41735331Samw * sa_get_resource_description(share) 41745331Samw * 41755331Samw * Return the description text for the specified share if it 41765331Samw * exists. NULL if no description exists. 41775331Samw */ 41785331Samw 41795331Samw char * 41805331Samw sa_get_resource_description(sa_resource_t resource) 41815331Samw { 41825331Samw xmlChar *description = NULL; 41835331Samw xmlNodePtr node; 41845331Samw 41855331Samw for (node = ((xmlNodePtr)resource)->children; node != NULL; 41865331Samw node = node->next) { 41875331Samw if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) 41885331Samw break; 41895331Samw } 41905331Samw if (node != NULL) { 41915331Samw description = xmlNodeGetContent(node); 41925331Samw fixproblemchars((char *)description); 41935331Samw } 41945331Samw return ((char *)description); 41955331Samw } 4196