13034Sdougm /* 23034Sdougm * CDDL HEADER START 33034Sdougm * 43034Sdougm * The contents of this file are subject to the terms of the 53034Sdougm * Common Development and Distribution License (the "License"). 63034Sdougm * You may not use this file except in compliance with the License. 73034Sdougm * 83034Sdougm * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 93034Sdougm * or http://www.opensolaris.org/os/licensing. 103034Sdougm * See the License for the specific language governing permissions 113034Sdougm * and limitations under the License. 123034Sdougm * 133034Sdougm * When distributing Covered Code, include this CDDL HEADER in each 143034Sdougm * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 153034Sdougm * If applicable, add the following below this CDDL HEADER, with the 163034Sdougm * fields enclosed by brackets "[]" replaced with your own identifying 173034Sdougm * information: Portions Copyright [yyyy] [name of copyright owner] 183034Sdougm * 193034Sdougm * CDDL HEADER END 203034Sdougm */ 213034Sdougm 223034Sdougm /* 23*12508Samw@Sun.COM * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. 243034Sdougm */ 253034Sdougm 263034Sdougm /* 273034Sdougm * Share control API 283034Sdougm */ 293034Sdougm #include <stdio.h> 303034Sdougm #include <string.h> 313034Sdougm #include <ctype.h> 323034Sdougm #include <sys/types.h> 333034Sdougm #include <sys/stat.h> 343663Sdougm #include <fcntl.h> 353034Sdougm #include <unistd.h> 363034Sdougm #include <libxml/parser.h> 373034Sdougm #include <libxml/tree.h> 383034Sdougm #include "libshare.h" 393034Sdougm #include "libshare_impl.h" 403034Sdougm #include <libscf.h> 413034Sdougm #include "scfutil.h" 423034Sdougm #include <ctype.h> 433034Sdougm #include <libintl.h> 443910Sdougm #include <thread.h> 453910Sdougm #include <synch.h> 463034Sdougm 473663Sdougm #define DFS_LOCK_FILE "/etc/dfs/fstypes" 484327Sdougm #define SA_STRSIZE 256 /* max string size for names */ 493663Sdougm 503034Sdougm /* 515331Samw * internal object type values returned by sa_get_object_type() 525331Samw */ 535331Samw #define SA_TYPE_UNKNOWN 0 545331Samw #define SA_TYPE_GROUP 1 555331Samw #define SA_TYPE_SHARE 2 565331Samw #define SA_TYPE_RESOURCE 3 575331Samw #define SA_TYPE_OPTIONSET 4 585331Samw #define SA_TYPE_ALTSPACE 5 595331Samw 605331Samw /* 613034Sdougm * internal data structures 623034Sdougm */ 633034Sdougm 643034Sdougm extern struct sa_proto_plugin *sap_proto_list; 653034Sdougm 663034Sdougm /* current SMF/SVC repository handle */ 673910Sdougm extern void getlegacyconfig(sa_handle_t, char *, xmlNodePtr *); 683910Sdougm extern int gettransients(sa_handle_impl_t, xmlNodePtr *); 693034Sdougm extern char *sa_fstype(char *); 703034Sdougm extern int sa_is_share(void *); 715331Samw extern int sa_is_resource(void *); 723034Sdougm extern ssize_t scf_max_name_len; /* defined in scfutil during initialization */ 733034Sdougm extern int sa_group_is_zfs(sa_group_t); 743034Sdougm extern int sa_path_is_zfs(char *); 753034Sdougm extern int sa_zfs_set_sharenfs(sa_group_t, char *, int); 765331Samw extern int sa_zfs_set_sharesmb(sa_group_t, char *, int); 773910Sdougm extern void update_legacy_config(sa_handle_t); 783034Sdougm extern int issubdir(char *, char *); 794327Sdougm extern int sa_zfs_init(sa_handle_impl_t); 803910Sdougm extern void sa_zfs_fini(sa_handle_impl_t); 813663Sdougm extern void sablocksigs(sigset_t *); 823663Sdougm extern void saunblocksigs(sigset_t *); 835331Samw static sa_group_t sa_get_optionset_parent(sa_optionset_t); 845331Samw static char *get_node_attr(void *, char *); 855951Sdougm extern void sa_update_sharetab_ts(sa_handle_t); 863034Sdougm 873910Sdougm /* 883910Sdougm * Data structures for finding/managing the document root to access 893910Sdougm * handle mapping. The list isn't expected to grow very large so a 903910Sdougm * simple list is acceptable. The purpose is to provide a way to start 913910Sdougm * with a group or share and find the library handle needed for 923910Sdougm * various operations. 933910Sdougm */ 943910Sdougm mutex_t sa_global_lock; 953910Sdougm struct doc2handle { 963910Sdougm struct doc2handle *next; 973910Sdougm xmlNodePtr root; 983910Sdougm sa_handle_impl_t handle; 993910Sdougm }; 1003910Sdougm 101*12508Samw@Sun.COM mutex_t sa_dfstab_lock; 102*12508Samw@Sun.COM 1034327Sdougm /* definitions used in a couple of property functions */ 1044327Sdougm #define SA_PROP_OP_REMOVE 1 1054327Sdougm #define SA_PROP_OP_ADD 2 1064327Sdougm #define SA_PROP_OP_UPDATE 3 1074327Sdougm 1083910Sdougm static struct doc2handle *sa_global_handles = NULL; 1093034Sdougm 1103034Sdougm /* helper functions */ 1113034Sdougm 1123910Sdougm /* 1133910Sdougm * sa_errorstr(err) 1143910Sdougm * 1153910Sdougm * convert an error value to an error string 1163910Sdougm */ 1173910Sdougm 1183034Sdougm char * 1193034Sdougm sa_errorstr(int err) 1203034Sdougm { 1213034Sdougm static char errstr[32]; 1223034Sdougm char *ret = NULL; 1233034Sdougm 1243034Sdougm switch (err) { 1253034Sdougm case SA_OK: 1264327Sdougm ret = dgettext(TEXT_DOMAIN, "ok"); 1274327Sdougm break; 1283034Sdougm case SA_NO_SUCH_PATH: 1294327Sdougm ret = dgettext(TEXT_DOMAIN, "path doesn't exist"); 1304327Sdougm break; 1313034Sdougm case SA_NO_MEMORY: 1324327Sdougm ret = dgettext(TEXT_DOMAIN, "no memory"); 1334327Sdougm break; 1343034Sdougm case SA_DUPLICATE_NAME: 1354327Sdougm ret = dgettext(TEXT_DOMAIN, "name in use"); 1364327Sdougm break; 1373034Sdougm case SA_BAD_PATH: 1384327Sdougm ret = dgettext(TEXT_DOMAIN, "bad path"); 1394327Sdougm break; 1403034Sdougm case SA_NO_SUCH_GROUP: 1414327Sdougm ret = dgettext(TEXT_DOMAIN, "no such group"); 1424327Sdougm break; 1433034Sdougm case SA_CONFIG_ERR: 1444327Sdougm ret = dgettext(TEXT_DOMAIN, "configuration error"); 1454327Sdougm break; 1463034Sdougm case SA_SYSTEM_ERR: 1474327Sdougm ret = dgettext(TEXT_DOMAIN, "system error"); 1484327Sdougm break; 1493034Sdougm case SA_SYNTAX_ERR: 1504327Sdougm ret = dgettext(TEXT_DOMAIN, "syntax error"); 1514327Sdougm break; 1523034Sdougm case SA_NO_PERMISSION: 1534327Sdougm ret = dgettext(TEXT_DOMAIN, "no permission"); 1544327Sdougm break; 1553034Sdougm case SA_BUSY: 1564327Sdougm ret = dgettext(TEXT_DOMAIN, "busy"); 1574327Sdougm break; 1583034Sdougm case SA_NO_SUCH_PROP: 1594327Sdougm ret = dgettext(TEXT_DOMAIN, "no such property"); 1604327Sdougm break; 1613034Sdougm case SA_INVALID_NAME: 1624327Sdougm ret = dgettext(TEXT_DOMAIN, "invalid name"); 1634327Sdougm break; 1643034Sdougm case SA_INVALID_PROTOCOL: 1654327Sdougm ret = dgettext(TEXT_DOMAIN, "invalid protocol"); 1664327Sdougm break; 1673034Sdougm case SA_NOT_ALLOWED: 1684327Sdougm ret = dgettext(TEXT_DOMAIN, "operation not allowed"); 1694327Sdougm break; 1703034Sdougm case SA_BAD_VALUE: 1714327Sdougm ret = dgettext(TEXT_DOMAIN, "bad property value"); 1724327Sdougm break; 1733034Sdougm case SA_INVALID_SECURITY: 1744327Sdougm ret = dgettext(TEXT_DOMAIN, "invalid security type"); 1754327Sdougm break; 1763034Sdougm case SA_NO_SUCH_SECURITY: 1774327Sdougm ret = dgettext(TEXT_DOMAIN, "security type not found"); 1784327Sdougm break; 1793034Sdougm case SA_VALUE_CONFLICT: 1804327Sdougm ret = dgettext(TEXT_DOMAIN, "property value conflict"); 1814327Sdougm break; 1823034Sdougm case SA_NOT_IMPLEMENTED: 1834327Sdougm ret = dgettext(TEXT_DOMAIN, "not implemented"); 1844327Sdougm break; 1853034Sdougm case SA_INVALID_PATH: 1864327Sdougm ret = dgettext(TEXT_DOMAIN, "invalid path"); 1874327Sdougm break; 1883034Sdougm case SA_NOT_SUPPORTED: 1894327Sdougm ret = dgettext(TEXT_DOMAIN, "operation not supported"); 1904327Sdougm break; 1913034Sdougm case SA_PROP_SHARE_ONLY: 1924327Sdougm ret = dgettext(TEXT_DOMAIN, "property not valid for group"); 1934327Sdougm break; 1943034Sdougm case SA_NOT_SHARED: 1954327Sdougm ret = dgettext(TEXT_DOMAIN, "not shared"); 1964327Sdougm break; 1975331Samw case SA_NO_SUCH_RESOURCE: 1985331Samw ret = dgettext(TEXT_DOMAIN, "no such resource"); 1995331Samw break; 2005331Samw case SA_RESOURCE_REQUIRED: 2015331Samw ret = dgettext(TEXT_DOMAIN, "resource name required"); 2025331Samw break; 2035331Samw case SA_MULTIPLE_ERROR: 2045331Samw ret = dgettext(TEXT_DOMAIN, "errors from multiple protocols"); 2055331Samw break; 2065331Samw case SA_PATH_IS_SUBDIR: 2075331Samw ret = dgettext(TEXT_DOMAIN, "path is a subpath of share"); 2085331Samw break; 2095331Samw case SA_PATH_IS_PARENTDIR: 2105331Samw ret = dgettext(TEXT_DOMAIN, "path is parent of a share"); 2115331Samw break; 2126007Sthurlow case SA_NO_SECTION: 2136007Sthurlow ret = dgettext(TEXT_DOMAIN, "protocol requires a section"); 2146007Sthurlow break; 2156007Sthurlow case SA_NO_PROPERTIES: 2166007Sthurlow ret = dgettext(TEXT_DOMAIN, "properties not found"); 2176007Sthurlow break; 2186007Sthurlow case SA_NO_SUCH_SECTION: 2196007Sthurlow ret = dgettext(TEXT_DOMAIN, "section not found"); 2206007Sthurlow break; 2216007Sthurlow case SA_PASSWORD_ENC: 2226007Sthurlow ret = dgettext(TEXT_DOMAIN, "passwords must be encrypted"); 2236007Sthurlow break; 2243034Sdougm default: 2254327Sdougm (void) snprintf(errstr, sizeof (errstr), 2264327Sdougm dgettext(TEXT_DOMAIN, "unknown %d"), err); 2274327Sdougm ret = errstr; 2283034Sdougm } 2293034Sdougm return (ret); 2303034Sdougm } 2313034Sdougm 2323034Sdougm /* 2333910Sdougm * Document root to active handle mapping functions. These are only 2343910Sdougm * used internally. A mutex is used to prevent access while the list 2353910Sdougm * is changing. In general, the list will be relatively short - one 2363910Sdougm * item per thread that has called sa_init(). 2373910Sdougm */ 2383910Sdougm 2393910Sdougm sa_handle_impl_t 2403910Sdougm get_handle_for_root(xmlNodePtr root) 2413910Sdougm { 2423910Sdougm struct doc2handle *item; 2433910Sdougm 2443910Sdougm (void) mutex_lock(&sa_global_lock); 2453910Sdougm for (item = sa_global_handles; item != NULL; item = item->next) { 2464327Sdougm if (item->root == root) 2474327Sdougm break; 2483910Sdougm } 2493910Sdougm (void) mutex_unlock(&sa_global_lock); 2503910Sdougm if (item != NULL) 2514327Sdougm return (item->handle); 2523910Sdougm return (NULL); 2533910Sdougm } 2543910Sdougm 2553910Sdougm static int 2563910Sdougm add_handle_for_root(xmlNodePtr root, sa_handle_impl_t handle) 2573910Sdougm { 2583910Sdougm struct doc2handle *item; 2593910Sdougm int ret = SA_NO_MEMORY; 2603910Sdougm 2613910Sdougm item = (struct doc2handle *)calloc(sizeof (struct doc2handle), 1); 2623910Sdougm if (item != NULL) { 2634327Sdougm item->root = root; 2644327Sdougm item->handle = handle; 2654327Sdougm (void) mutex_lock(&sa_global_lock); 2664327Sdougm item->next = sa_global_handles; 2674327Sdougm sa_global_handles = item; 2684327Sdougm (void) mutex_unlock(&sa_global_lock); 2694327Sdougm ret = SA_OK; 2703910Sdougm } 2713910Sdougm return (ret); 2723910Sdougm } 2733910Sdougm 2743910Sdougm /* 2753910Sdougm * remove_handle_for_root(root) 2763910Sdougm * 2773910Sdougm * Walks the list of handles and removes the one for this "root" from 2783910Sdougm * the list. It is up to the caller to free the data. 2793910Sdougm */ 2803910Sdougm 2813910Sdougm static void 2823910Sdougm remove_handle_for_root(xmlNodePtr root) 2833910Sdougm { 2843910Sdougm struct doc2handle *item, *prev; 2853910Sdougm 2863910Sdougm (void) mutex_lock(&sa_global_lock); 2873910Sdougm for (prev = NULL, item = sa_global_handles; item != NULL; 2884327Sdougm item = item->next) { 2894327Sdougm if (item->root == root) { 2904327Sdougm /* first in the list */ 2914327Sdougm if (prev == NULL) 2924327Sdougm sa_global_handles = sa_global_handles->next; 2934327Sdougm else 2944327Sdougm prev->next = item->next; 2954327Sdougm /* Item is out of the list so free the list structure */ 2964327Sdougm free(item); 2974327Sdougm break; 2983910Sdougm } 2994327Sdougm prev = item; 3003910Sdougm } 3013910Sdougm (void) mutex_unlock(&sa_global_lock); 3023910Sdougm } 3033910Sdougm 3043910Sdougm /* 3053910Sdougm * sa_find_group_handle(sa_group_t group) 3063910Sdougm * 3073910Sdougm * Find the sa_handle_t for the configuration associated with this 3083910Sdougm * group. 3093910Sdougm */ 3103910Sdougm sa_handle_t 3113910Sdougm sa_find_group_handle(sa_group_t group) 3123910Sdougm { 3133910Sdougm xmlNodePtr node = (xmlNodePtr)group; 3143910Sdougm sa_handle_t handle; 3153910Sdougm 3163910Sdougm while (node != NULL) { 3174327Sdougm if (strcmp((char *)(node->name), "sharecfg") == 0) { 3184327Sdougm /* have the root so get the handle */ 3194327Sdougm handle = (sa_handle_t)get_handle_for_root(node); 3204327Sdougm return (handle); 3214327Sdougm } 3224327Sdougm node = node->parent; 3233910Sdougm } 3243910Sdougm return (NULL); 3253910Sdougm } 3263910Sdougm 3273910Sdougm /* 3283034Sdougm * set_legacy_timestamp(root, path, timevalue) 3293034Sdougm * 3303034Sdougm * add the current timestamp value to the configuration for use in 3313034Sdougm * determining when to update the legacy files. For SMF, this 3323034Sdougm * property is kept in default/operation/legacy_timestamp 3333034Sdougm */ 3343034Sdougm 3353034Sdougm static void 3363034Sdougm set_legacy_timestamp(xmlNodePtr root, char *path, uint64_t tval) 3373034Sdougm { 3383034Sdougm xmlNodePtr node; 3393034Sdougm xmlChar *lpath = NULL; 3403910Sdougm sa_handle_impl_t handle; 3413910Sdougm 3423910Sdougm /* Have to have a handle or else we weren't initialized. */ 3433910Sdougm handle = get_handle_for_root(root); 3443910Sdougm if (handle == NULL) 3454327Sdougm return; 3463034Sdougm 3473034Sdougm for (node = root->xmlChildrenNode; node != NULL; 3484327Sdougm node = node->next) { 3494327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"legacy") == 0) { 3504327Sdougm /* a possible legacy node for this path */ 3514327Sdougm lpath = xmlGetProp(node, (xmlChar *)"path"); 3524327Sdougm if (lpath != NULL && 3534327Sdougm xmlStrcmp(lpath, (xmlChar *)path) == 0) { 3544327Sdougm xmlFree(lpath); 3554327Sdougm break; 3564327Sdougm } 3574327Sdougm if (lpath != NULL) 3584327Sdougm xmlFree(lpath); 3593034Sdougm } 3603034Sdougm } 3613034Sdougm if (node == NULL) { 3624327Sdougm /* need to create the first legacy timestamp node */ 3634327Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"legacy", NULL); 3643034Sdougm } 3653034Sdougm if (node != NULL) { 3664327Sdougm char tstring[32]; 3674327Sdougm int ret; 3683034Sdougm 3694327Sdougm (void) snprintf(tstring, sizeof (tstring), "%lld", tval); 3706007Sthurlow (void) xmlSetProp(node, (xmlChar *)"timestamp", 3716007Sthurlow (xmlChar *)tstring); 3726007Sthurlow (void) xmlSetProp(node, (xmlChar *)"path", (xmlChar *)path); 3734327Sdougm /* now commit to SMF */ 3744327Sdougm ret = sa_get_instance(handle->scfhandle, "default"); 3753034Sdougm if (ret == SA_OK) { 3764327Sdougm ret = sa_start_transaction(handle->scfhandle, 3774327Sdougm "operation"); 3784327Sdougm if (ret == SA_OK) { 3794327Sdougm ret = sa_set_property(handle->scfhandle, 3804327Sdougm "legacy-timestamp", tstring); 3814327Sdougm if (ret == SA_OK) { 3824327Sdougm (void) sa_end_transaction( 3835951Sdougm handle->scfhandle, handle); 3844327Sdougm } else { 3854327Sdougm sa_abort_transaction(handle->scfhandle); 3864327Sdougm } 3874327Sdougm } 3883034Sdougm } 3893034Sdougm } 3903034Sdougm } 3913034Sdougm 3923034Sdougm /* 3933034Sdougm * is_shared(share) 3943034Sdougm * 3953034Sdougm * determine if the specified share is currently shared or not. 3963034Sdougm */ 3973034Sdougm static int 3983034Sdougm is_shared(sa_share_t share) 3993034Sdougm { 4003034Sdougm char *shared; 4013034Sdougm int result = 0; /* assume not */ 4023034Sdougm 4033034Sdougm shared = sa_get_share_attr(share, "shared"); 4043034Sdougm if (shared != NULL) { 4054327Sdougm if (strcmp(shared, "true") == 0) 4064327Sdougm result = 1; 4074327Sdougm sa_free_attr_string(shared); 4083034Sdougm } 4093034Sdougm return (result); 4103034Sdougm } 4113034Sdougm 4123034Sdougm /* 4135331Samw * excluded_protocol(share, proto) 4145331Samw * 4155331Samw * Returns B_TRUE if the specified protocol appears in the "exclude" 4165331Samw * property. This is used to prevent sharing special case shares 4175331Samw * (e.g. subdirs when SMB wants a subdir and NFS doesn't. B_FALSE is 4185331Samw * returned if the protocol isn't in the list. 4195331Samw */ 4205331Samw static boolean_t 4215331Samw excluded_protocol(sa_share_t share, char *proto) 4225331Samw { 4235331Samw char *protolist; 4245331Samw char *str; 4255331Samw char *token; 4265331Samw 4275331Samw protolist = sa_get_share_attr(share, "exclude"); 4285331Samw if (protolist != NULL) { 4295331Samw str = protolist; 4305331Samw while ((token = strtok(str, ",")) != NULL) { 4315331Samw if (strcmp(token, proto) == 0) { 4325331Samw sa_free_attr_string(protolist); 4335331Samw return (B_TRUE); 4345331Samw } 4355331Samw str = NULL; 4365331Samw } 4375331Samw sa_free_attr_string(protolist); 4385331Samw } 4395331Samw return (B_FALSE); 4405331Samw } 4415331Samw 4425331Samw /* 4433663Sdougm * checksubdirgroup(group, newpath, strictness) 4443348Sdougm * 4453663Sdougm * check all the specified newpath against all the paths in the 4463663Sdougm * group. This is a helper function for checksubdir to make it easier 4473663Sdougm * to also check ZFS subgroups. 4483663Sdougm * The strictness values mean: 4493348Sdougm * SA_CHECK_NORMAL == only check newpath against shares that are active 4503348Sdougm * SA_CHECK_STRICT == check newpath against both active shares and those 4513348Sdougm * stored in the repository 4523034Sdougm */ 4533034Sdougm static int 4543663Sdougm checksubdirgroup(sa_group_t group, char *newpath, int strictness) 4553034Sdougm { 4563034Sdougm sa_share_t share; 4573663Sdougm char *path; 4583663Sdougm int issub = SA_OK; 4595331Samw int subdir; 4605331Samw int parent; 4615331Samw 4625331Samw if (newpath == NULL) 4635331Samw return (SA_INVALID_PATH); 4643034Sdougm 4653663Sdougm for (share = sa_get_share(group, NULL); share != NULL; 4663663Sdougm share = sa_get_next_share(share)) { 4673034Sdougm /* 4683034Sdougm * The original behavior of share never checked 4693034Sdougm * against the permanent configuration 4703034Sdougm * (/etc/dfs/dfstab). PIT has a number of cases where 4713034Sdougm * it depends on this older behavior even though it 4723034Sdougm * could be considered incorrect. We may tighten this 4733034Sdougm * up in the future. 4743034Sdougm */ 4754327Sdougm if (strictness == SA_CHECK_NORMAL && !is_shared(share)) 4764327Sdougm continue; 4773034Sdougm 4784327Sdougm path = sa_get_share_attr(share, "path"); 4793348Sdougm /* 4803348Sdougm * If path is NULL, then a share is in the process of 4813348Sdougm * construction or someone has modified the property 4823663Sdougm * group inappropriately. It should be 4833663Sdougm * ignored. issubdir() comes from the original share 4843663Sdougm * implementation and does the difficult part of 4853663Sdougm * checking subdirectories. 4863348Sdougm */ 4874327Sdougm if (path == NULL) 4884327Sdougm continue; 4895331Samw 4905331Samw if (strcmp(path, newpath) == 0) { 4914327Sdougm issub = SA_INVALID_PATH; 4925331Samw } else { 4935331Samw subdir = issubdir(newpath, path); 4945331Samw parent = issubdir(path, newpath); 4955331Samw if (subdir || parent) { 4965331Samw sa_free_attr_string(path); 4975331Samw path = NULL; 4985331Samw return (subdir ? 4995331Samw SA_PATH_IS_SUBDIR : SA_PATH_IS_PARENTDIR); 5005331Samw } 5014327Sdougm } 5023034Sdougm sa_free_attr_string(path); 5033034Sdougm path = NULL; 5043663Sdougm } 5053663Sdougm return (issub); 5063663Sdougm } 5073663Sdougm 5083663Sdougm /* 5093663Sdougm * checksubdir(newpath, strictness) 5103663Sdougm * 5113663Sdougm * checksubdir determines if the specified path (newpath) is a 5123663Sdougm * subdirectory of another share. It calls checksubdirgroup() to do 5133663Sdougm * the complicated work. The strictness parameter determines how 5143663Sdougm * strict a check to make against the path. The strictness values 5153663Sdougm * mean: SA_CHECK_NORMAL == only check newpath against shares that are 5163663Sdougm * active SA_CHECK_STRICT == check newpath against both active shares 5173663Sdougm * and those * stored in the repository 5183663Sdougm */ 5193663Sdougm static int 5203910Sdougm checksubdir(sa_handle_t handle, char *newpath, int strictness) 5213663Sdougm { 5223663Sdougm sa_group_t group; 5235331Samw int issub = SA_OK; 5243663Sdougm char *path = NULL; 5253663Sdougm 5265331Samw for (group = sa_get_group(handle, NULL); 5275331Samw group != NULL && issub == SA_OK; 5285331Samw group = sa_get_next_group(group)) { 5294327Sdougm if (sa_group_is_zfs(group)) { 5304327Sdougm sa_group_t subgroup; 5314327Sdougm for (subgroup = sa_get_sub_group(group); 5325331Samw subgroup != NULL && issub == SA_OK; 5334327Sdougm subgroup = sa_get_next_group(subgroup)) 5344327Sdougm issub = checksubdirgroup(subgroup, newpath, 5354327Sdougm strictness); 5364327Sdougm } else { 5374327Sdougm issub = checksubdirgroup(group, newpath, strictness); 5384327Sdougm } 5393034Sdougm } 5403034Sdougm if (path != NULL) 5414327Sdougm sa_free_attr_string(path); 5423034Sdougm return (issub); 5433034Sdougm } 5443034Sdougm 5453034Sdougm /* 5463348Sdougm * validpath(path, strictness) 5473034Sdougm * determine if the provided path is valid for a share. It shouldn't 5483034Sdougm * be a sub-dir of an already shared path or the parent directory of a 5493034Sdougm * share path. 5503034Sdougm */ 5513034Sdougm static int 5523910Sdougm validpath(sa_handle_t handle, char *path, int strictness) 5533034Sdougm { 5543034Sdougm int error = SA_OK; 5553034Sdougm struct stat st; 5563034Sdougm sa_share_t share; 5573034Sdougm char *fstype; 5583034Sdougm 5594327Sdougm if (*path != '/') 5604327Sdougm return (SA_BAD_PATH); 5614327Sdougm 5623034Sdougm if (stat(path, &st) < 0) { 5634327Sdougm error = SA_NO_SUCH_PATH; 5643034Sdougm } else { 5654327Sdougm share = sa_find_share(handle, path); 5664327Sdougm if (share != NULL) 5674327Sdougm error = SA_DUPLICATE_NAME; 5684327Sdougm 5694327Sdougm if (error == SA_OK) { 5704327Sdougm /* 5714327Sdougm * check for special case with file system 5724327Sdougm * that might have restrictions. For now, ZFS 5734327Sdougm * is the only case since it has its own idea 5744327Sdougm * of how to configure shares. We do this 5754327Sdougm * before subdir checking since things like 5764327Sdougm * ZFS will do that for us. This should also 5774327Sdougm * be done via plugin interface. 5784327Sdougm */ 5794327Sdougm fstype = sa_fstype(path); 5804327Sdougm if (fstype != NULL && strcmp(fstype, "zfs") == 0) { 5814327Sdougm if (sa_zfs_is_shared(handle, path)) 5824327Sdougm error = SA_INVALID_NAME; 5834327Sdougm } 5844327Sdougm if (fstype != NULL) 5854327Sdougm sa_free_fstype(fstype); 5863034Sdougm } 5874327Sdougm if (error == SA_OK) 5884327Sdougm error = checksubdir(handle, path, strictness); 5893034Sdougm } 5903034Sdougm return (error); 5913034Sdougm } 5923034Sdougm 5933034Sdougm /* 5943034Sdougm * check to see if group/share is persistent. 5955331Samw * 5965331Samw * "group" can be either an sa_group_t or an sa_share_t. (void *) 5975331Samw * works since both thse types are also void *. 598*12508Samw@Sun.COM * If the share is a ZFS share, mark it as persistent. 5993034Sdougm */ 6005331Samw int 6015331Samw sa_is_persistent(void *group) 6023034Sdougm { 6033034Sdougm char *type; 6043034Sdougm int persist = 1; 605*12508Samw@Sun.COM sa_group_t grp; 6063034Sdougm 6075331Samw type = sa_get_group_attr((sa_group_t)group, "type"); 608*12508Samw@Sun.COM if (type != NULL) { 609*12508Samw@Sun.COM if (strcmp(type, "transient") == 0) 610*12508Samw@Sun.COM persist = 0; 6114327Sdougm sa_free_attr_string(type); 612*12508Samw@Sun.COM } 613*12508Samw@Sun.COM 614*12508Samw@Sun.COM grp = (sa_is_share(group)) ? sa_get_parent_group(group) : group; 615*12508Samw@Sun.COM if (sa_group_is_zfs(grp)) 616*12508Samw@Sun.COM persist = 1; 617*12508Samw@Sun.COM 6183034Sdougm return (persist); 6193034Sdougm } 6203034Sdougm 6213034Sdougm /* 6223034Sdougm * sa_valid_group_name(name) 6233034Sdougm * 6243034Sdougm * check that the "name" contains only valid characters and otherwise 6253034Sdougm * fits the required naming conventions. Valid names must start with 6263034Sdougm * an alphabetic and the remainder may consist of only alphanumeric 6273034Sdougm * plus the '-' and '_' characters. This name limitation comes from 6283034Sdougm * inherent limitations in SMF. 6293034Sdougm */ 6303034Sdougm 6313034Sdougm int 6323034Sdougm sa_valid_group_name(char *name) 6333034Sdougm { 6343034Sdougm int ret = 1; 6353034Sdougm ssize_t len; 6363034Sdougm 6373034Sdougm if (name != NULL && isalpha(*name)) { 6384327Sdougm char c; 6394327Sdougm len = strlen(name); 6404327Sdougm if (len < (scf_max_name_len - sizeof ("group:"))) { 6414327Sdougm for (c = *name++; c != '\0' && ret != 0; c = *name++) { 6424327Sdougm if (!isalnum(c) && c != '-' && c != '_') 6434327Sdougm ret = 0; 6444327Sdougm } 6454327Sdougm } else { 6463034Sdougm ret = 0; 6473034Sdougm } 6484327Sdougm } else { 6493034Sdougm ret = 0; 6503034Sdougm } 6513034Sdougm return (ret); 6523034Sdougm } 6533034Sdougm 6543034Sdougm 6553034Sdougm /* 6563034Sdougm * is_zfs_group(group) 6573034Sdougm * Determine if the specified group is a ZFS sharenfs group 6583034Sdougm */ 6593034Sdougm static int 6603034Sdougm is_zfs_group(sa_group_t group) 6613034Sdougm { 6623034Sdougm int ret = 0; 6633034Sdougm xmlNodePtr parent; 6643034Sdougm xmlChar *zfs; 6653034Sdougm 6664327Sdougm if (strcmp((char *)((xmlNodePtr)group)->name, "share") == 0) 6674327Sdougm parent = (xmlNodePtr)sa_get_parent_group(group); 6684327Sdougm else 6694327Sdougm parent = (xmlNodePtr)group; 6703034Sdougm zfs = xmlGetProp(parent, (xmlChar *)"zfs"); 6713034Sdougm if (zfs != NULL) { 6724327Sdougm xmlFree(zfs); 6734327Sdougm ret = 1; 6743034Sdougm } 6753034Sdougm return (ret); 6763034Sdougm } 6773034Sdougm 6783034Sdougm /* 6795331Samw * sa_get_object_type(object) 6805331Samw * 6815331Samw * This function returns a numeric value representing the object 6825331Samw * type. This allows using simpler checks when doing type specific 6835331Samw * operations. 6845331Samw */ 6855331Samw 6865331Samw static int 6875331Samw sa_get_object_type(void *object) 6885331Samw { 6895331Samw xmlNodePtr node = (xmlNodePtr)object; 6905331Samw int type; 6915331Samw 6925331Samw if (xmlStrcmp(node->name, (xmlChar *)"group") == 0) 6935331Samw type = SA_TYPE_GROUP; 6945331Samw else if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) 6955331Samw type = SA_TYPE_SHARE; 6965331Samw else if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0) 6975331Samw type = SA_TYPE_RESOURCE; 6985331Samw else if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) 6995331Samw type = SA_TYPE_OPTIONSET; 7005331Samw else if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) 7015331Samw type = SA_TYPE_ALTSPACE; 7025331Samw else 7035331Samw assert(0); 7045331Samw return (type); 7055331Samw } 7065331Samw 7075331Samw /* 7083034Sdougm * sa_optionset_name(optionset, oname, len, id) 7093034Sdougm * return the SMF name for the optionset. If id is not NULL, it 7103034Sdougm * will have the GUID value for a share and should be used 7113034Sdougm * instead of the keyword "optionset" which is used for 7123034Sdougm * groups. If the optionset doesn't have a protocol type 7133034Sdougm * associated with it, "default" is used. This shouldn't happen 7143034Sdougm * at this point but may be desirable in the future if there are 7153034Sdougm * protocol independent properties added. The name is returned in 7163034Sdougm * oname. 7173034Sdougm */ 7183034Sdougm 7193034Sdougm static int 7203034Sdougm sa_optionset_name(sa_optionset_t optionset, char *oname, size_t len, char *id) 7213034Sdougm { 7223034Sdougm char *proto; 7235331Samw void *parent; 7245331Samw int ptype; 7253034Sdougm 7263034Sdougm if (id == NULL) 7274327Sdougm id = "optionset"; 7283034Sdougm 7295331Samw parent = sa_get_optionset_parent(optionset); 7305331Samw if (parent != NULL) { 7315331Samw ptype = sa_get_object_type(parent); 7325331Samw proto = sa_get_optionset_attr(optionset, "type"); 7335331Samw if (ptype != SA_TYPE_RESOURCE) { 7345331Samw len = snprintf(oname, len, "%s_%s", id, 7355331Samw proto ? proto : "default"); 7365331Samw } else { 7375331Samw char *index; 7385331Samw index = get_node_attr((void *)parent, "id"); 73911337SWilliam.Krier@Sun.COM if (index != NULL) { 7405331Samw len = snprintf(oname, len, "%s_%s_%s", id, 7415331Samw proto ? proto : "default", index); 74211337SWilliam.Krier@Sun.COM sa_free_attr_string(index); 74311337SWilliam.Krier@Sun.COM } else { 7445331Samw len = 0; 74511337SWilliam.Krier@Sun.COM } 7465331Samw } 7475331Samw 7485331Samw if (proto != NULL) 7495331Samw sa_free_attr_string(proto); 7505331Samw } else { 7515331Samw len = 0; 7525331Samw } 7533034Sdougm return (len); 7543034Sdougm } 7553034Sdougm 7563034Sdougm /* 7573034Sdougm * sa_security_name(optionset, oname, len, id) 7583034Sdougm * 7593034Sdougm * return the SMF name for the security. If id is not NULL, it will 7603034Sdougm * have the GUID value for a share and should be used instead of the 7613034Sdougm * keyword "optionset" which is used for groups. If the optionset 7623034Sdougm * doesn't have a protocol type associated with it, "default" is 7633034Sdougm * used. This shouldn't happen at this point but may be desirable in 7643034Sdougm * the future if there are protocol independent properties added. The 7653034Sdougm * name is returned in oname. The security type is also encoded into 7663034Sdougm * the name. In the future, this wil *be handled a bit differently. 7673034Sdougm */ 7683034Sdougm 7693034Sdougm static int 7703034Sdougm sa_security_name(sa_security_t security, char *oname, size_t len, char *id) 7713034Sdougm { 7723034Sdougm char *proto; 7733034Sdougm char *sectype; 7743034Sdougm 7753034Sdougm if (id == NULL) 7764327Sdougm id = "optionset"; 7773034Sdougm 7783034Sdougm proto = sa_get_security_attr(security, "type"); 7793034Sdougm sectype = sa_get_security_attr(security, "sectype"); 7804327Sdougm len = snprintf(oname, len, "%s_%s_%s", id, proto ? proto : "default", 7814327Sdougm sectype ? sectype : "default"); 7823034Sdougm if (proto != NULL) 7834327Sdougm sa_free_attr_string(proto); 7843034Sdougm if (sectype != NULL) 7854327Sdougm sa_free_attr_string(sectype); 7863034Sdougm return (len); 7873034Sdougm } 7883034Sdougm 7893034Sdougm /* 7904327Sdougm * verifydefgroupopts(handle) 7914327Sdougm * 7924327Sdougm * Make sure a "default" group exists and has default protocols enabled. 7934327Sdougm */ 7944327Sdougm static void 7954327Sdougm verifydefgroupopts(sa_handle_t handle) 7964327Sdougm { 7974327Sdougm sa_group_t defgrp; 7984327Sdougm sa_optionset_t opt; 7995331Samw 8004327Sdougm defgrp = sa_get_group(handle, "default"); 8014327Sdougm if (defgrp != NULL) { 8024327Sdougm opt = sa_get_optionset(defgrp, NULL); 8034327Sdougm /* 8044327Sdougm * NFS is the default for default group 8054327Sdougm */ 8064327Sdougm if (opt == NULL) 8074327Sdougm opt = sa_create_optionset(defgrp, "nfs"); 8084327Sdougm } 8094327Sdougm } 8104327Sdougm 8114327Sdougm /* 8123348Sdougm * sa_init(init_service) 8133034Sdougm * Initialize the API 8143034Sdougm * find all the shared objects 8153034Sdougm * init the tables with all objects 8163034Sdougm * read in the current configuration 8173034Sdougm */ 8183034Sdougm 8194327Sdougm #define GETPROP(prop) scf_simple_prop_next_astring(prop) 8204327Sdougm #define CHECKTSTAMP(st, tval) stat(SA_LEGACY_DFSTAB, &st) >= 0 && \ 8214327Sdougm tval != TSTAMP(st.st_ctim) 8224327Sdougm 8233910Sdougm sa_handle_t 8243034Sdougm sa_init(int init_service) 8253034Sdougm { 8263034Sdougm struct stat st; 8273034Sdougm int legacy = 0; 8283034Sdougm uint64_t tval = 0; 8293663Sdougm int lockfd; 8303663Sdougm sigset_t old; 8313663Sdougm int updatelegacy = B_FALSE; 8323663Sdougm scf_simple_prop_t *prop; 8333910Sdougm sa_handle_impl_t handle; 8343910Sdougm int err; 8353034Sdougm 8363910Sdougm handle = calloc(sizeof (struct sa_handle_impl), 1); 8373910Sdougm 8383910Sdougm if (handle != NULL) { 8396304Sdougm /* 8406304Sdougm * Get protocol specific structures, but only if this 8416304Sdougm * is the only handle. 8426304Sdougm */ 8436304Sdougm (void) mutex_lock(&sa_global_lock); 8446304Sdougm if (sa_global_handles == NULL) 8456304Sdougm (void) proto_plugin_init(); 8466304Sdougm (void) mutex_unlock(&sa_global_lock); 8474327Sdougm if (init_service & SA_INIT_SHARE_API) { 8483663Sdougm /* 8494327Sdougm * initialize access into libzfs. We use this 8504327Sdougm * when collecting info about ZFS datasets and 8514327Sdougm * shares. 8523663Sdougm */ 8534327Sdougm if (sa_zfs_init(handle) == B_FALSE) { 8544327Sdougm free(handle); 8558474SJose.Borrego@Sun.COM (void) mutex_lock(&sa_global_lock); 8564327Sdougm (void) proto_plugin_fini(); 8578474SJose.Borrego@Sun.COM (void) mutex_unlock(&sa_global_lock); 8584327Sdougm return (NULL); 8594327Sdougm } 8603663Sdougm /* 8614327Sdougm * since we want to use SMF, initialize an svc handle 8624327Sdougm * and find out what is there. 8633663Sdougm */ 8644327Sdougm handle->scfhandle = sa_scf_init(handle); 8654327Sdougm if (handle->scfhandle != NULL) { 8664327Sdougm /* 8674327Sdougm * Need to lock the extraction of the 8684327Sdougm * configuration if the dfstab file has 8694327Sdougm * changed. Lock everything now and release if 8704327Sdougm * not needed. Use a file that isn't being 8714327Sdougm * manipulated by other parts of the system in 8724327Sdougm * order to not interfere with locking. Using 8734327Sdougm * dfstab doesn't work. 8744327Sdougm */ 8754327Sdougm sablocksigs(&old); 8764327Sdougm lockfd = open(DFS_LOCK_FILE, O_RDWR); 8774327Sdougm if (lockfd >= 0) { 8784327Sdougm extern int errno; 8794327Sdougm errno = 0; 8804327Sdougm (void) lockf(lockfd, F_LOCK, 0); 881*12508Samw@Sun.COM (void) mutex_lock(&sa_dfstab_lock); 8824327Sdougm /* 8834327Sdougm * Check whether we are going to need 8844327Sdougm * to merge any dfstab changes. This 8854327Sdougm * is done by comparing the value of 8864327Sdougm * legacy-timestamp with the current 8874327Sdougm * st_ctim of the file. If they are 8884327Sdougm * different, an update is needed and 8894327Sdougm * the file must remain locked until 8904327Sdougm * the merge is done in order to 8914327Sdougm * prevent multiple startups from 8924327Sdougm * changing the SMF repository at the 8934327Sdougm * same time. The first to get the 8944327Sdougm * lock will make any changes before 8954327Sdougm * the others can read the repository. 8964327Sdougm */ 8974327Sdougm prop = scf_simple_prop_get 8984327Sdougm (handle->scfhandle->handle, 8994327Sdougm (const char *)SA_SVC_FMRI_BASE 9004327Sdougm ":default", "operation", 9014327Sdougm "legacy-timestamp"); 9024327Sdougm if (prop != NULL) { 9034327Sdougm char *i64; 9044327Sdougm i64 = GETPROP(prop); 9054327Sdougm if (i64 != NULL) 9064327Sdougm tval = strtoull(i64, 9074327Sdougm NULL, 0); 9084327Sdougm if (CHECKTSTAMP(st, tval)) 9094327Sdougm updatelegacy = B_TRUE; 9104327Sdougm scf_simple_prop_free(prop); 9114327Sdougm } else { 9124327Sdougm /* 9134327Sdougm * We haven't set the 9144327Sdougm * timestamp before so do it. 9154327Sdougm */ 9164327Sdougm updatelegacy = B_TRUE; 9174327Sdougm } 918*12508Samw@Sun.COM if (updatelegacy == B_FALSE) { 919*12508Samw@Sun.COM (void) mutex_unlock( 920*12508Samw@Sun.COM &sa_dfstab_lock); 921*12508Samw@Sun.COM (void) lockf(lockfd, F_ULOCK, 922*12508Samw@Sun.COM 0); 923*12508Samw@Sun.COM (void) close(lockfd); 924*12508Samw@Sun.COM } 925*12508Samw@Sun.COM 9264327Sdougm } 9274327Sdougm /* 9284327Sdougm * It is essential that the document tree and 9294327Sdougm * the internal list of roots to handles be 9304327Sdougm * setup before anything that might try to 9314327Sdougm * create a new object is called. The document 9324327Sdougm * tree is the combination of handle->doc and 9334327Sdougm * handle->tree. This allows searches, 9344327Sdougm * etc. when all you have is an object in the 9354327Sdougm * tree. 9364327Sdougm */ 9374327Sdougm handle->doc = xmlNewDoc((xmlChar *)"1.0"); 9384327Sdougm handle->tree = xmlNewNode(NULL, 9394327Sdougm (xmlChar *)"sharecfg"); 9404327Sdougm if (handle->doc != NULL && 9414327Sdougm handle->tree != NULL) { 9426007Sthurlow (void) xmlDocSetRootElement(handle->doc, 9434327Sdougm handle->tree); 9444327Sdougm err = add_handle_for_root(handle->tree, 9454327Sdougm handle); 9464327Sdougm if (err == SA_OK) 9474327Sdougm err = sa_get_config( 9484327Sdougm handle->scfhandle, 9493973Sdougm handle->tree, handle); 9504327Sdougm } else { 9514327Sdougm if (handle->doc != NULL) 9524327Sdougm xmlFreeDoc(handle->doc); 9534327Sdougm if (handle->tree != NULL) 9544327Sdougm xmlFreeNode(handle->tree); 9554327Sdougm err = SA_NO_MEMORY; 9564327Sdougm } 9573973Sdougm 9584327Sdougm saunblocksigs(&old); 9593910Sdougm 9604327Sdougm if (err != SA_OK) { 9614327Sdougm /* 9624327Sdougm * If we couldn't add the tree handle 9634327Sdougm * to the list, then things are going 9644327Sdougm * to fail badly. Might as well undo 9654327Sdougm * everything now and fail the 9664327Sdougm * sa_init(). 9674327Sdougm */ 9684327Sdougm sa_fini(handle); 969*12508Samw@Sun.COM if (updatelegacy == B_TRUE) { 970*12508Samw@Sun.COM (void) mutex_unlock( 971*12508Samw@Sun.COM &sa_dfstab_lock); 972*12508Samw@Sun.COM (void) lockf(lockfd, 973*12508Samw@Sun.COM F_ULOCK, 0); 974*12508Samw@Sun.COM (void) close(lockfd); 975*12508Samw@Sun.COM } 9764327Sdougm return (NULL); 9774327Sdougm } 9783910Sdougm 9794327Sdougm if (tval == 0) { 9804327Sdougm /* 9814327Sdougm * first time so make sure 9824327Sdougm * default is setup 9834327Sdougm */ 9844327Sdougm verifydefgroupopts(handle); 9854327Sdougm } 9863973Sdougm 9874524Sdougm if (updatelegacy == B_TRUE) { 9884524Sdougm sablocksigs(&old); 9894524Sdougm getlegacyconfig((sa_handle_t)handle, 9904524Sdougm SA_LEGACY_DFSTAB, &handle->tree); 9914524Sdougm if (stat(SA_LEGACY_DFSTAB, &st) >= 0) 9924524Sdougm set_legacy_timestamp( 9934524Sdougm handle->tree, 9944524Sdougm SA_LEGACY_DFSTAB, 9954524Sdougm TSTAMP(st.st_ctim)); 9964524Sdougm saunblocksigs(&old); 9974524Sdougm /* 9984524Sdougm * Safe to unlock now to allow 9994524Sdougm * others to run 10004524Sdougm */ 1001*12508Samw@Sun.COM (void) mutex_unlock(&sa_dfstab_lock); 10024524Sdougm (void) lockf(lockfd, F_ULOCK, 0); 10034524Sdougm (void) close(lockfd); 10044524Sdougm } 10055951Sdougm /* Get sharetab timestamp */ 10065951Sdougm sa_update_sharetab_ts((sa_handle_t)handle); 10075951Sdougm 10085951Sdougm /* Get lastupdate (transaction) timestamp */ 10095951Sdougm prop = scf_simple_prop_get( 10105951Sdougm handle->scfhandle->handle, 10115951Sdougm (const char *)SA_SVC_FMRI_BASE ":default", 10125951Sdougm "state", "lastupdate"); 10135951Sdougm if (prop != NULL) { 10145951Sdougm char *str; 10155951Sdougm str = 10165951Sdougm scf_simple_prop_next_astring(prop); 10175951Sdougm if (str != NULL) 10185951Sdougm handle->tstrans = 10195951Sdougm strtoull(str, NULL, 0); 10205951Sdougm else 10215951Sdougm handle->tstrans = 0; 10225951Sdougm scf_simple_prop_free(prop); 10235951Sdougm } 10244524Sdougm legacy |= sa_get_zfs_shares(handle, "zfs"); 10254524Sdougm legacy |= gettransients(handle, &handle->tree); 10264327Sdougm } 10274327Sdougm } 10283034Sdougm } 10293910Sdougm return ((sa_handle_t)handle); 10303034Sdougm } 10313034Sdougm 10323034Sdougm /* 10333910Sdougm * sa_fini(handle) 10343034Sdougm * Uninitialize the API structures including the configuration 10353218Sdougm * data structures and ZFS related data. 10363034Sdougm */ 10373034Sdougm 10383034Sdougm void 10393910Sdougm sa_fini(sa_handle_t handle) 10403034Sdougm { 10413910Sdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle; 10423910Sdougm 10433910Sdougm if (impl_handle != NULL) { 10443910Sdougm /* 10453910Sdougm * Free the config trees and any other data structures 10463910Sdougm * used in the handle. 10473910Sdougm */ 10483910Sdougm if (impl_handle->doc != NULL) 10493910Sdougm xmlFreeDoc(impl_handle->doc); 10503910Sdougm 10513910Sdougm /* Remove and free the entry in the global list. */ 10523910Sdougm remove_handle_for_root(impl_handle->tree); 10533910Sdougm 10543910Sdougm /* 10553910Sdougm * If this was the last handle to release, unload the 10566304Sdougm * plugins that were loaded. Use a mutex in case 10576304Sdougm * another thread is reinitializing. 10583910Sdougm */ 10596304Sdougm (void) mutex_lock(&sa_global_lock); 10603910Sdougm if (sa_global_handles == NULL) 10614327Sdougm (void) proto_plugin_fini(); 10626304Sdougm (void) mutex_unlock(&sa_global_lock); 10633910Sdougm 10647010Sgwr sa_scf_fini(impl_handle->scfhandle); 10657010Sgwr sa_zfs_fini(impl_handle); 10667010Sgwr 10677010Sgwr /* Make sure we free the handle */ 10687010Sgwr free(impl_handle); 10697010Sgwr 10703034Sdougm } 10713034Sdougm } 10723034Sdougm 10733034Sdougm /* 10743034Sdougm * sa_get_protocols(char **protocol) 10753034Sdougm * Get array of protocols that are supported 10763034Sdougm * Returns pointer to an allocated and NULL terminated 10773034Sdougm * array of strings. Caller must free. 10783034Sdougm * This really should be determined dynamically. 10793034Sdougm * If there aren't any defined, return -1. 10803034Sdougm * Use free() to return memory. 10813034Sdougm */ 10823034Sdougm 10833034Sdougm int 10843034Sdougm sa_get_protocols(char ***protocols) 10853034Sdougm { 10863034Sdougm int numproto = -1; 10873034Sdougm 10883034Sdougm if (protocols != NULL) { 10894327Sdougm struct sa_proto_plugin *plug; 10904327Sdougm for (numproto = 0, plug = sap_proto_list; plug != NULL; 10914327Sdougm plug = plug->plugin_next) { 10924327Sdougm numproto++; 10934327Sdougm } 10943034Sdougm 10954327Sdougm *protocols = calloc(numproto + 1, sizeof (char *)); 10964327Sdougm if (*protocols != NULL) { 10974327Sdougm int ret = 0; 10984327Sdougm for (plug = sap_proto_list; plug != NULL; 10994327Sdougm plug = plug->plugin_next) { 11004327Sdougm /* faking for now */ 11014327Sdougm (*protocols)[ret++] = 11024327Sdougm plug->plugin_ops->sa_protocol; 11034327Sdougm } 11044327Sdougm } else { 11054327Sdougm numproto = -1; 11063034Sdougm } 11073034Sdougm } 11083034Sdougm return (numproto); 11093034Sdougm } 11103034Sdougm 11113034Sdougm /* 11123034Sdougm * find_group_by_name(node, group) 11133034Sdougm * 11143034Sdougm * search the XML document subtree specified by node to find the group 11153034Sdougm * specified by group. Searching subtree allows subgroups to be 11163034Sdougm * searched for. 11173034Sdougm */ 11183034Sdougm 11193034Sdougm static xmlNodePtr 11203034Sdougm find_group_by_name(xmlNodePtr node, xmlChar *group) 11213034Sdougm { 11223034Sdougm xmlChar *name = NULL; 11233034Sdougm 11243034Sdougm for (node = node->xmlChildrenNode; node != NULL; 11253034Sdougm node = node->next) { 11264327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"group") == 0) { 11274327Sdougm /* if no groupname, return the first found */ 11284327Sdougm if (group == NULL) 11294327Sdougm break; 11304327Sdougm name = xmlGetProp(node, (xmlChar *)"name"); 11314327Sdougm if (name != NULL && xmlStrcmp(name, group) == 0) 11324327Sdougm break; 11334327Sdougm if (name != NULL) { 11344327Sdougm xmlFree(name); 11354327Sdougm name = NULL; 11364327Sdougm } 11373034Sdougm } 11383034Sdougm } 11393034Sdougm if (name != NULL) 11404327Sdougm xmlFree(name); 11413034Sdougm return (node); 11423034Sdougm } 11433034Sdougm 11443034Sdougm /* 11453034Sdougm * sa_get_group(groupname) 11463034Sdougm * Return the "group" specified. If groupname is NULL, 11473034Sdougm * return the first group of the list of groups. 11483034Sdougm */ 11493034Sdougm sa_group_t 11503910Sdougm sa_get_group(sa_handle_t handle, char *groupname) 11513034Sdougm { 11523034Sdougm xmlNodePtr node = NULL; 11533034Sdougm char *subgroup = NULL; 11543034Sdougm char *group = NULL; 11553910Sdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle; 11563034Sdougm 11573910Sdougm if (impl_handle != NULL && impl_handle->tree != NULL) { 11584327Sdougm if (groupname != NULL) { 11594327Sdougm group = strdup(groupname); 11604345Sdougm if (group != NULL) { 11614345Sdougm subgroup = strchr(group, '/'); 11624345Sdougm if (subgroup != NULL) 11634345Sdougm *subgroup++ = '\0'; 11644345Sdougm } 11654327Sdougm } 11664345Sdougm /* 11674345Sdougm * We want to find the, possibly, named group. If 11684345Sdougm * group is not NULL, then lookup the name. If it is 11694345Sdougm * NULL, we only do the find if groupname is also 11704345Sdougm * NULL. This allows lookup of the "first" group in 11714345Sdougm * the internal list. 11724345Sdougm */ 11734345Sdougm if (group != NULL || groupname == NULL) 11744345Sdougm node = find_group_by_name(impl_handle->tree, 11754345Sdougm (xmlChar *)group); 11764345Sdougm 11774327Sdougm /* if a subgroup, find it before returning */ 11784327Sdougm if (subgroup != NULL && node != NULL) 11794327Sdougm node = find_group_by_name(node, (xmlChar *)subgroup); 11803034Sdougm } 11813034Sdougm if (node != NULL && (char *)group != NULL) 11824327Sdougm (void) sa_get_instance(impl_handle->scfhandle, (char *)group); 11833034Sdougm if (group != NULL) 11844327Sdougm free(group); 11853034Sdougm return ((sa_group_t)(node)); 11863034Sdougm } 11873034Sdougm 11883034Sdougm /* 11893034Sdougm * sa_get_next_group(group) 11903034Sdougm * Return the "next" group after the specified group from 11913034Sdougm * the internal group list. NULL if there are no more. 11923034Sdougm */ 11933034Sdougm sa_group_t 11943034Sdougm sa_get_next_group(sa_group_t group) 11953034Sdougm { 11963034Sdougm xmlNodePtr ngroup = NULL; 11973034Sdougm if (group != NULL) { 11984327Sdougm for (ngroup = ((xmlNodePtr)group)->next; ngroup != NULL; 11993034Sdougm ngroup = ngroup->next) { 12004327Sdougm if (xmlStrcmp(ngroup->name, (xmlChar *)"group") == 0) 12014327Sdougm break; 12024327Sdougm } 12033034Sdougm } 12043034Sdougm return ((sa_group_t)ngroup); 12053034Sdougm } 12063034Sdougm 12073034Sdougm /* 12083034Sdougm * sa_get_share(group, sharepath) 12093034Sdougm * Return the share object for the share specified. The share 12103034Sdougm * must be in the specified group. Return NULL if not found. 12113034Sdougm */ 12123034Sdougm sa_share_t 12133034Sdougm sa_get_share(sa_group_t group, char *sharepath) 12143034Sdougm { 12153034Sdougm xmlNodePtr node = NULL; 12163034Sdougm xmlChar *path; 12173034Sdougm 12183034Sdougm /* 12193034Sdougm * For future scalability, this should end up building a cache 12203034Sdougm * since it will get called regularly by the mountd and info 12213034Sdougm * services. 12223034Sdougm */ 12233034Sdougm if (group != NULL) { 12244327Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 12253034Sdougm node = node->next) { 12264327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) { 12274327Sdougm if (sharepath == NULL) { 12284327Sdougm break; 12294327Sdougm } else { 12304327Sdougm /* is it the correct share? */ 12314327Sdougm path = xmlGetProp(node, 12324327Sdougm (xmlChar *)"path"); 12334327Sdougm if (path != NULL && 12344327Sdougm xmlStrcmp(path, 12354327Sdougm (xmlChar *)sharepath) == 0) { 12364327Sdougm xmlFree(path); 12374327Sdougm break; 12384327Sdougm } 12394327Sdougm xmlFree(path); 12404327Sdougm } 12413034Sdougm } 12423034Sdougm } 12433034Sdougm } 12443034Sdougm return ((sa_share_t)node); 12453034Sdougm } 12463034Sdougm 12473034Sdougm /* 12483034Sdougm * sa_get_next_share(share) 12493034Sdougm * Return the next share following the specified share 12503034Sdougm * from the internal list of shares. Returns NULL if there 12513034Sdougm * are no more shares. The list is relative to the same 12523034Sdougm * group. 12533034Sdougm */ 12543034Sdougm sa_share_t 12553034Sdougm sa_get_next_share(sa_share_t share) 12563034Sdougm { 12573034Sdougm xmlNodePtr node = NULL; 12583034Sdougm 12593034Sdougm if (share != NULL) { 12604327Sdougm for (node = ((xmlNodePtr)share)->next; node != NULL; 12613034Sdougm node = node->next) { 12624327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) { 12634327Sdougm break; 12644327Sdougm } 12653034Sdougm } 12663034Sdougm } 12673034Sdougm return ((sa_share_t)node); 12683034Sdougm } 12693034Sdougm 12703034Sdougm /* 12713034Sdougm * _sa_get_child_node(node, type) 12723034Sdougm * 12733034Sdougm * find the child node of the specified node that has "type". This is 12743034Sdougm * used to implement several internal functions. 12753034Sdougm */ 12763034Sdougm 12773034Sdougm static xmlNodePtr 12783034Sdougm _sa_get_child_node(xmlNodePtr node, xmlChar *type) 12793034Sdougm { 12803034Sdougm xmlNodePtr child; 12813034Sdougm for (child = node->xmlChildrenNode; child != NULL; 12823034Sdougm child = child->next) 12834327Sdougm if (xmlStrcmp(child->name, type) == 0) 12844327Sdougm return (child); 12853034Sdougm return ((xmlNodePtr)NULL); 12863034Sdougm } 12873034Sdougm 12883034Sdougm /* 12893034Sdougm * find_share(group, path) 12903034Sdougm * 12913034Sdougm * Search all the shares in the specified group for one that has the 12923034Sdougm * specified path. 12933034Sdougm */ 12943034Sdougm 12953034Sdougm static sa_share_t 12963034Sdougm find_share(sa_group_t group, char *sharepath) 12973034Sdougm { 12983034Sdougm sa_share_t share; 12993034Sdougm char *path; 13003034Sdougm 13013034Sdougm for (share = sa_get_share(group, NULL); share != NULL; 13023034Sdougm share = sa_get_next_share(share)) { 13034327Sdougm path = sa_get_share_attr(share, "path"); 13044327Sdougm if (path != NULL && strcmp(path, sharepath) == 0) { 13054327Sdougm sa_free_attr_string(path); 13064327Sdougm break; 13074327Sdougm } 13084327Sdougm if (path != NULL) 13094327Sdougm sa_free_attr_string(path); 13103034Sdougm } 13113034Sdougm return (share); 13123034Sdougm } 13133034Sdougm 13143034Sdougm /* 13153034Sdougm * sa_get_sub_group(group) 13163034Sdougm * 13173034Sdougm * Get the first sub-group of group. The sa_get_next_group() function 13183034Sdougm * can be used to get the rest. This is currently only used for ZFS 13193034Sdougm * sub-groups but could be used to implement a more general mechanism. 13203034Sdougm */ 13213034Sdougm 13223034Sdougm sa_group_t 13233034Sdougm sa_get_sub_group(sa_group_t group) 13243034Sdougm { 13253034Sdougm return ((sa_group_t)_sa_get_child_node((xmlNodePtr)group, 13264327Sdougm (xmlChar *)"group")); 13273034Sdougm } 13283034Sdougm 13293034Sdougm /* 13303034Sdougm * sa_find_share(sharepath) 13313034Sdougm * Finds a share regardless of group. In the future, this 13323034Sdougm * function should utilize a cache and hash table of some kind. 13333034Sdougm * The current assumption is that a path will only be shared 13343034Sdougm * once. In the future, this may change as implementation of 13353034Sdougm * resource names comes into being. 13363034Sdougm */ 13373034Sdougm sa_share_t 13383910Sdougm sa_find_share(sa_handle_t handle, char *sharepath) 13393034Sdougm { 13403034Sdougm sa_group_t group; 13413034Sdougm sa_group_t zgroup; 13423034Sdougm sa_share_t share = NULL; 13433034Sdougm int done = 0; 13443034Sdougm 13453910Sdougm for (group = sa_get_group(handle, NULL); group != NULL && !done; 13464327Sdougm group = sa_get_next_group(group)) { 13474327Sdougm if (is_zfs_group(group)) { 13484327Sdougm for (zgroup = 13494327Sdougm (sa_group_t)_sa_get_child_node((xmlNodePtr)group, 13504327Sdougm (xmlChar *)"group"); 13514327Sdougm zgroup != NULL; 13524327Sdougm zgroup = sa_get_next_group(zgroup)) { 13534327Sdougm share = find_share(zgroup, sharepath); 13544327Sdougm if (share != NULL) 13554327Sdougm break; 13564327Sdougm } 13574327Sdougm } else { 13584327Sdougm share = find_share(group, sharepath); 13594327Sdougm } 13604327Sdougm if (share != NULL) 13613034Sdougm break; 13623034Sdougm } 13633034Sdougm return (share); 13643034Sdougm } 13653034Sdougm 13663034Sdougm /* 13673348Sdougm * sa_check_path(group, path, strictness) 13683034Sdougm * 13695331Samw * Check that path is a valid path relative to the group. Currently, 13703034Sdougm * we are ignoring the group and checking only the NFS rules. Later, 13713034Sdougm * we may want to use the group to then check against the protocols 13723348Sdougm * enabled on the group. The strictness values mean: 13733348Sdougm * SA_CHECK_NORMAL == only check newpath against shares that are active 13743348Sdougm * SA_CHECK_STRICT == check newpath against both active shares and those 13753348Sdougm * stored in the repository 13763034Sdougm */ 13773034Sdougm 13783034Sdougm int 13793348Sdougm sa_check_path(sa_group_t group, char *path, int strictness) 13803034Sdougm { 13813910Sdougm sa_handle_t handle; 13823910Sdougm 13833910Sdougm handle = sa_find_group_handle(group); 138411963SAfshin.Ardakani@Sun.COM if (handle == NULL) 138511963SAfshin.Ardakani@Sun.COM return (SA_BAD_PATH); 138611963SAfshin.Ardakani@Sun.COM 13873910Sdougm return (validpath(handle, path, strictness)); 13883034Sdougm } 13893034Sdougm 13903034Sdougm /* 13915331Samw * mark_excluded_protos(group, share, flags) 13923034Sdougm * 13935331Samw * Walk through all the protocols enabled for the group and check to 13945331Samw * see if the share has any of them should be in the exclude list 13955331Samw * based on the featureset of the protocol. If there are any, add the 13965331Samw * "exclude" property to the share. 13975331Samw */ 13985331Samw static void 13995331Samw mark_excluded_protos(sa_group_t group, xmlNodePtr share, uint64_t flags) 14005331Samw { 14015331Samw sa_optionset_t optionset; 14025331Samw char exclude_list[SA_STRSIZE]; 14035331Samw char *sep = ""; 14045331Samw 14055331Samw exclude_list[0] = '\0'; 14065331Samw for (optionset = sa_get_optionset(group, NULL); 14075331Samw optionset != NULL; 14085331Samw optionset = sa_get_next_optionset(optionset)) { 14095331Samw char *value; 14105331Samw uint64_t features; 14115331Samw value = sa_get_optionset_attr(optionset, "type"); 14125331Samw if (value == NULL) 14135331Samw continue; 14145331Samw features = sa_proto_get_featureset(value); 14155331Samw if (!(features & flags)) { 14165331Samw (void) strlcat(exclude_list, sep, 14175331Samw sizeof (exclude_list)); 14185331Samw (void) strlcat(exclude_list, value, 14195331Samw sizeof (exclude_list)); 14205331Samw sep = ","; 14215331Samw } 142211337SWilliam.Krier@Sun.COM sa_free_attr_string(value); 14235331Samw } 14245331Samw if (exclude_list[0] != '\0') 14256007Sthurlow (void) xmlSetProp(share, (xmlChar *)"exclude", 14265331Samw (xmlChar *)exclude_list); 14275331Samw } 14285331Samw 14295331Samw /* 14305331Samw * get_all_features(group) 14315331Samw * 14325331Samw * Walk through all the protocols on the group and collect all 14335331Samw * possible enabled features. This is the OR of all the featuresets. 14345331Samw */ 14355331Samw static uint64_t 14365331Samw get_all_features(sa_group_t group) 14375331Samw { 14385331Samw sa_optionset_t optionset; 14395331Samw uint64_t features = 0; 14405331Samw 14415331Samw for (optionset = sa_get_optionset(group, NULL); 14425331Samw optionset != NULL; 14435331Samw optionset = sa_get_next_optionset(optionset)) { 14445331Samw char *value; 14455331Samw value = sa_get_optionset_attr(optionset, "type"); 14465331Samw if (value == NULL) 14475331Samw continue; 14485331Samw features |= sa_proto_get_featureset(value); 14495331Samw sa_free_attr_string(value); 14505331Samw } 14515331Samw return (features); 14525331Samw } 14535331Samw 14545331Samw 14555331Samw /* 14565331Samw * _sa_add_share(group, sharepath, persist, *error, flags) 14575331Samw * 14585331Samw * Common code for all types of add_share. sa_add_share() is the 14593034Sdougm * public API, we also need to be able to do this when parsing legacy 14603034Sdougm * files and construction of the internal configuration while 14615331Samw * extracting config info from SMF. "flags" indicates if some 14625331Samw * protocols need relaxed rules while other don't. These values are 14635331Samw * the featureset values defined in libshare.h. 14643034Sdougm */ 14653034Sdougm 14663034Sdougm sa_share_t 14675331Samw _sa_add_share(sa_group_t group, char *sharepath, int persist, int *error, 14685331Samw uint64_t flags) 14693034Sdougm { 14703034Sdougm xmlNodePtr node = NULL; 14713034Sdougm int err; 14723034Sdougm 14733034Sdougm err = SA_OK; /* assume success */ 14743034Sdougm 14754327Sdougm node = xmlNewChild((xmlNodePtr)group, NULL, (xmlChar *)"share", NULL); 14765331Samw if (node == NULL) { 14775331Samw if (error != NULL) 14785331Samw *error = SA_NO_MEMORY; 14795331Samw return (node); 14805331Samw } 14815331Samw 14826007Sthurlow (void) xmlSetProp(node, (xmlChar *)"path", (xmlChar *)sharepath); 14836007Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", 14845331Samw persist ? (xmlChar *)"persist" : (xmlChar *)"transient"); 14855331Samw if (flags != 0) 14865331Samw mark_excluded_protos(group, node, flags); 14875331Samw if (persist != SA_SHARE_TRANSIENT) { 14885331Samw /* 14895331Samw * persistent shares come in two flavors: SMF and 14905331Samw * ZFS. Sort this one out based on target group and 14915331Samw * path type. Both NFS and SMB are supported. First, 14925331Samw * check to see if the protocol is enabled on the 14935331Samw * subgroup and then setup the share appropriately. 14945331Samw */ 14955331Samw if (sa_group_is_zfs(group) && 14965331Samw sa_path_is_zfs(sharepath)) { 14975331Samw if (sa_get_optionset(group, "nfs") != NULL) 14984327Sdougm err = sa_zfs_set_sharenfs(group, sharepath, 1); 14995331Samw else if (sa_get_optionset(group, "smb") != NULL) 15005331Samw err = sa_zfs_set_sharesmb(group, sharepath, 1); 15015331Samw } else { 15025331Samw sa_handle_impl_t impl_handle; 15035331Samw impl_handle = 15045331Samw (sa_handle_impl_t)sa_find_group_handle(group); 15055331Samw if (impl_handle != NULL) { 15065331Samw err = sa_commit_share(impl_handle->scfhandle, 15075331Samw group, (sa_share_t)node); 15084327Sdougm } else { 15095331Samw err = SA_SYSTEM_ERR; 15104327Sdougm } 15113034Sdougm } 15123034Sdougm } 15135331Samw if (err == SA_NO_PERMISSION && persist & SA_SHARE_PARSER) 15145331Samw /* called by the dfstab parser so could be a show */ 15155331Samw err = SA_OK; 15165331Samw 15175331Samw if (err != SA_OK) { 15185331Samw /* 15195331Samw * we couldn't commit to the repository so undo 15205331Samw * our internal state to reflect reality. 15215331Samw */ 15225331Samw xmlUnlinkNode(node); 15235331Samw xmlFreeNode(node); 15245331Samw node = NULL; 15255331Samw } 15265331Samw 15273034Sdougm if (error != NULL) 15284327Sdougm *error = err; 15295331Samw 15303034Sdougm return (node); 15313034Sdougm } 15323034Sdougm 15333034Sdougm /* 15343034Sdougm * sa_add_share(group, sharepath, persist, *error) 15353034Sdougm * 15363034Sdougm * Add a new share object to the specified group. The share will 15373034Sdougm * have the specified sharepath and will only be constructed if 15383034Sdougm * it is a valid path to be shared. NULL is returned on error 15393034Sdougm * and a detailed error value will be returned via the error 15403034Sdougm * pointer. 15413034Sdougm */ 15423034Sdougm sa_share_t 15433034Sdougm sa_add_share(sa_group_t group, char *sharepath, int persist, int *error) 15443034Sdougm { 15453034Sdougm xmlNodePtr node = NULL; 15463348Sdougm int strictness = SA_CHECK_NORMAL; 15473910Sdougm sa_handle_t handle; 15485331Samw uint64_t special = 0; 15495331Samw uint64_t features; 15503348Sdougm 15513348Sdougm /* 15523348Sdougm * If the share is to be permanent, use strict checking so a 15533348Sdougm * bad config doesn't get created. Transient shares only need 15543348Sdougm * to check against the currently active 15553348Sdougm * shares. SA_SHARE_PARSER is a modifier used internally to 15563348Sdougm * indicate that we are being called by the dfstab parser and 15573348Sdougm * that we need strict checking in all cases. Normally persist 15583348Sdougm * is in integer value but SA_SHARE_PARSER may be or'd into 15593348Sdougm * it as an override. 15603348Sdougm */ 15613348Sdougm if (persist & SA_SHARE_PARSER || persist == SA_SHARE_PERMANENT) 15624327Sdougm strictness = SA_CHECK_STRICT; 15633034Sdougm 15643910Sdougm handle = sa_find_group_handle(group); 15653910Sdougm 15665331Samw /* 15675331Samw * need to determine if the share is valid. The rules are: 15685331Samw * - The path must not already exist 15695331Samw * - The path must not be a subdir or parent dir of an 15705331Samw * existing path unless at least one protocol allows it. 15715331Samw * The sub/parent check is done in sa_check_path(). 15725331Samw */ 15735331Samw 15745331Samw if (sa_find_share(handle, sharepath) == NULL) { 15755331Samw *error = sa_check_path(group, sharepath, strictness); 15765331Samw features = get_all_features(group); 15775331Samw switch (*error) { 15785331Samw case SA_PATH_IS_SUBDIR: 15795331Samw if (features & SA_FEATURE_ALLOWSUBDIRS) 15805331Samw special |= SA_FEATURE_ALLOWSUBDIRS; 15815331Samw break; 15825331Samw case SA_PATH_IS_PARENTDIR: 15835331Samw if (features & SA_FEATURE_ALLOWPARDIRS) 15845331Samw special |= SA_FEATURE_ALLOWPARDIRS; 15855331Samw break; 15865331Samw } 15875331Samw if (*error == SA_OK || special != SA_FEATURE_NONE) 15885331Samw node = _sa_add_share(group, sharepath, persist, 15895331Samw error, special); 15905331Samw } else { 15915331Samw *error = SA_DUPLICATE_NAME; 15923034Sdougm } 15933034Sdougm 15943034Sdougm return ((sa_share_t)node); 15953034Sdougm } 15963034Sdougm 15973034Sdougm /* 15983034Sdougm * sa_enable_share(share, protocol) 15993034Sdougm * Enable the specified share to the specified protocol. 16003034Sdougm * If protocol is NULL, then all protocols. 16013034Sdougm */ 16023034Sdougm int 16033034Sdougm sa_enable_share(sa_share_t share, char *protocol) 16043034Sdougm { 16053034Sdougm char *sharepath; 16063034Sdougm struct stat st; 16075331Samw int err = SA_OK; 16085331Samw int ret; 16093034Sdougm 16103034Sdougm sharepath = sa_get_share_attr(share, "path"); 16115331Samw if (sharepath == NULL) 16125331Samw return (SA_NO_MEMORY); 16133034Sdougm if (stat(sharepath, &st) < 0) { 16144327Sdougm err = SA_NO_SUCH_PATH; 16153034Sdougm } else { 16164327Sdougm /* tell the server about the share */ 16174327Sdougm if (protocol != NULL) { 16185331Samw if (excluded_protocol(share, protocol)) 16195331Samw goto done; 16205331Samw 16214327Sdougm /* lookup protocol specific handler */ 16224327Sdougm err = sa_proto_share(protocol, share); 16234327Sdougm if (err == SA_OK) 16245331Samw (void) sa_set_share_attr(share, 16255331Samw "shared", "true"); 16264327Sdougm } else { 16275331Samw /* Tell all protocols about the share */ 16285331Samw sa_group_t group; 16295331Samw sa_optionset_t optionset; 16305331Samw 16315331Samw group = sa_get_parent_group(share); 16325331Samw 16335331Samw for (optionset = sa_get_optionset(group, NULL); 16345331Samw optionset != NULL; 16355331Samw optionset = sa_get_next_optionset(optionset)) { 16365331Samw char *proto; 16375331Samw proto = sa_get_optionset_attr(optionset, 16385331Samw "type"); 16395331Samw if (proto != NULL) { 16405331Samw if (!excluded_protocol(share, proto)) { 16415331Samw ret = sa_proto_share(proto, 16425331Samw share); 16435331Samw if (ret != SA_OK) 16445331Samw err = ret; 16455331Samw } 16465331Samw sa_free_attr_string(proto); 16475331Samw } 16485331Samw } 16494327Sdougm (void) sa_set_share_attr(share, "shared", "true"); 16504327Sdougm } 16513034Sdougm } 16525331Samw done: 16533034Sdougm if (sharepath != NULL) 16544327Sdougm sa_free_attr_string(sharepath); 16553034Sdougm return (err); 16563034Sdougm } 16573034Sdougm 16583034Sdougm /* 16593034Sdougm * sa_disable_share(share, protocol) 16605331Samw * Disable the specified share to the specified protocol. If 16615331Samw * protocol is NULL, then all protocols that are enabled for the 16625331Samw * share should be disabled. 16633034Sdougm */ 16643034Sdougm int 16653034Sdougm sa_disable_share(sa_share_t share, char *protocol) 16663034Sdougm { 16673034Sdougm char *path; 16685331Samw int err = SA_OK; 16693034Sdougm int ret = SA_OK; 16703034Sdougm 16713034Sdougm path = sa_get_share_attr(share, "path"); 16723034Sdougm 16733034Sdougm if (protocol != NULL) { 16744543Smarks ret = sa_proto_unshare(share, protocol, path); 16753034Sdougm } else { 16764327Sdougm /* need to do all protocols */ 16775331Samw sa_group_t group; 16785331Samw sa_optionset_t optionset; 16795331Samw 16805331Samw group = sa_get_parent_group(share); 16815331Samw 16825331Samw /* Tell all protocols about the share */ 16835331Samw for (optionset = sa_get_optionset(group, NULL); 16845331Samw optionset != NULL; 16855331Samw optionset = sa_get_next_optionset(optionset)) { 16865331Samw char *proto; 16875331Samw 16885331Samw proto = sa_get_optionset_attr(optionset, "type"); 16895331Samw if (proto != NULL) { 16905331Samw err = sa_proto_unshare(share, proto, path); 16915331Samw if (err != SA_OK) 16925331Samw ret = err; 16935331Samw sa_free_attr_string(proto); 16945331Samw } 16955331Samw } 16963034Sdougm } 16973034Sdougm if (ret == SA_OK) 16983034Sdougm (void) sa_set_share_attr(share, "shared", NULL); 16993034Sdougm if (path != NULL) 17004327Sdougm sa_free_attr_string(path); 17013034Sdougm return (ret); 17023034Sdougm } 17033034Sdougm 17043034Sdougm /* 17053034Sdougm * sa_remove_share(share) 17063034Sdougm * 17073034Sdougm * remove the specified share from its containing group. 17083034Sdougm * Remove from the SMF or ZFS configuration space. 17093034Sdougm */ 17103034Sdougm 17113034Sdougm int 17123034Sdougm sa_remove_share(sa_share_t share) 17133034Sdougm { 17143034Sdougm sa_group_t group; 17153034Sdougm int ret = SA_OK; 17163034Sdougm char *type; 17173034Sdougm int transient = 0; 17183034Sdougm char *groupname; 17193034Sdougm char *zfs; 17203034Sdougm 17213034Sdougm type = sa_get_share_attr(share, "type"); 17223034Sdougm group = sa_get_parent_group(share); 17233034Sdougm zfs = sa_get_group_attr(group, "zfs"); 17243034Sdougm groupname = sa_get_group_attr(group, "name"); 17253034Sdougm if (type != NULL && strcmp(type, "persist") != 0) 17264327Sdougm transient = 1; 17273034Sdougm if (type != NULL) 17284327Sdougm sa_free_attr_string(type); 17293034Sdougm 17303034Sdougm /* remove the node from its group then free the memory */ 17313034Sdougm 17323034Sdougm /* 17333034Sdougm * need to test if "busy" 17343034Sdougm */ 17353034Sdougm /* only do SMF action if permanent */ 17363034Sdougm if (!transient || zfs != NULL) { 17374327Sdougm /* remove from legacy dfstab as well as possible SMF */ 17385331Samw ret = sa_delete_legacy(share, NULL); 17394327Sdougm if (ret == SA_OK) { 17404327Sdougm if (!sa_group_is_zfs(group)) { 17414327Sdougm sa_handle_impl_t impl_handle; 17424327Sdougm impl_handle = (sa_handle_impl_t) 17434327Sdougm sa_find_group_handle(group); 17444327Sdougm if (impl_handle != NULL) { 17454327Sdougm ret = sa_delete_share( 17464327Sdougm impl_handle->scfhandle, group, 17474327Sdougm share); 17484327Sdougm } else { 17494327Sdougm ret = SA_SYSTEM_ERR; 17504327Sdougm } 17514327Sdougm } else { 17524327Sdougm char *sharepath = sa_get_share_attr(share, 17534327Sdougm "path"); 17544327Sdougm if (sharepath != NULL) { 17554327Sdougm ret = sa_zfs_set_sharenfs(group, 17564327Sdougm sharepath, 0); 17574327Sdougm sa_free_attr_string(sharepath); 17584327Sdougm } 17594327Sdougm } 17603034Sdougm } 17613034Sdougm } 17623034Sdougm if (groupname != NULL) 17634327Sdougm sa_free_attr_string(groupname); 17643034Sdougm if (zfs != NULL) 17654327Sdougm sa_free_attr_string(zfs); 17663034Sdougm 17673034Sdougm xmlUnlinkNode((xmlNodePtr)share); 17683034Sdougm xmlFreeNode((xmlNodePtr)share); 17693034Sdougm return (ret); 17703034Sdougm } 17713034Sdougm 17723034Sdougm /* 17733034Sdougm * sa_move_share(group, share) 17743034Sdougm * 17753034Sdougm * move the specified share to the specified group. Update SMF 17763034Sdougm * appropriately. 17773034Sdougm */ 17783034Sdougm 17793034Sdougm int 17803034Sdougm sa_move_share(sa_group_t group, sa_share_t share) 17813034Sdougm { 17823034Sdougm sa_group_t oldgroup; 17833034Sdougm int ret = SA_OK; 17843034Sdougm 17853034Sdougm /* remove the node from its group then free the memory */ 17863034Sdougm 17873034Sdougm oldgroup = sa_get_parent_group(share); 17883034Sdougm if (oldgroup != group) { 17894327Sdougm sa_handle_impl_t impl_handle; 17904327Sdougm xmlUnlinkNode((xmlNodePtr)share); 17913034Sdougm /* 17924327Sdougm * now that the share isn't in its old group, add to 17934327Sdougm * the new one 17943034Sdougm */ 17956007Sthurlow (void) xmlAddChild((xmlNodePtr)group, (xmlNodePtr)share); 17964327Sdougm /* need to deal with SMF */ 17974327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 17984327Sdougm if (impl_handle != NULL) { 17994327Sdougm /* 18004327Sdougm * need to remove from old group first and then add to 18014327Sdougm * new group. Ideally, we would do the other order but 18024327Sdougm * need to avoid having the share in two groups at the 18034327Sdougm * same time. 18044327Sdougm */ 18054327Sdougm ret = sa_delete_share(impl_handle->scfhandle, oldgroup, 18064327Sdougm share); 18074327Sdougm if (ret == SA_OK) 18084327Sdougm ret = sa_commit_share(impl_handle->scfhandle, 18094327Sdougm group, share); 18104327Sdougm } else { 18114327Sdougm ret = SA_SYSTEM_ERR; 18124327Sdougm } 18133034Sdougm } 18143034Sdougm return (ret); 18153034Sdougm } 18163034Sdougm 18173034Sdougm /* 18183034Sdougm * sa_get_parent_group(share) 18193034Sdougm * 18205331Samw * Return the containing group for the share. If a group was actually 18213034Sdougm * passed in, we don't want a parent so return NULL. 18223034Sdougm */ 18233034Sdougm 18243034Sdougm sa_group_t 18253034Sdougm sa_get_parent_group(sa_share_t share) 18263034Sdougm { 18273034Sdougm xmlNodePtr node = NULL; 18283034Sdougm if (share != NULL) { 18294327Sdougm node = ((xmlNodePtr)share)->parent; 18303034Sdougm /* 18313034Sdougm * make sure parent is a group and not sharecfg since 18323034Sdougm * we may be cheating and passing in a group. 18333034Sdougm * Eventually, groups of groups might come into being. 18343034Sdougm */ 18354327Sdougm if (node == NULL || 18364327Sdougm xmlStrcmp(node->name, (xmlChar *)"sharecfg") == 0) 18374327Sdougm node = NULL; 18383034Sdougm } 18393034Sdougm return ((sa_group_t)node); 18403034Sdougm } 18413034Sdougm 18423034Sdougm /* 18433910Sdougm * _sa_create_group(impl_handle, groupname) 18443034Sdougm * 18453034Sdougm * Create a group in the document. The caller will need to deal with 18463034Sdougm * configuration store and activation. 18473034Sdougm */ 18483034Sdougm 18493034Sdougm sa_group_t 18503910Sdougm _sa_create_group(sa_handle_impl_t impl_handle, char *groupname) 18513034Sdougm { 18523034Sdougm xmlNodePtr node = NULL; 18533034Sdougm 18543034Sdougm if (sa_valid_group_name(groupname)) { 18554327Sdougm node = xmlNewChild(impl_handle->tree, NULL, (xmlChar *)"group", 18564327Sdougm NULL); 18574327Sdougm if (node != NULL) { 18586007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 18594327Sdougm (xmlChar *)groupname); 18606007Sthurlow (void) xmlSetProp(node, (xmlChar *)"state", 18614327Sdougm (xmlChar *)"enabled"); 18624327Sdougm } 18633034Sdougm } 18643034Sdougm return ((sa_group_t)node); 18653034Sdougm } 18663034Sdougm 18673034Sdougm /* 18683034Sdougm * _sa_create_zfs_group(group, groupname) 18693034Sdougm * 18703034Sdougm * Create a ZFS subgroup under the specified group. This may 18713034Sdougm * eventually form the basis of general sub-groups, but is currently 18723034Sdougm * restricted to ZFS. 18733034Sdougm */ 18743034Sdougm sa_group_t 18753034Sdougm _sa_create_zfs_group(sa_group_t group, char *groupname) 18763034Sdougm { 18773034Sdougm xmlNodePtr node = NULL; 18783034Sdougm 18794327Sdougm node = xmlNewChild((xmlNodePtr)group, NULL, (xmlChar *)"group", NULL); 18803034Sdougm if (node != NULL) { 18816007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 18826007Sthurlow (xmlChar *)groupname); 18836007Sthurlow (void) xmlSetProp(node, (xmlChar *)"state", 18846007Sthurlow (xmlChar *)"enabled"); 18853034Sdougm } 18863034Sdougm 18873034Sdougm return ((sa_group_t)node); 18883034Sdougm } 18893034Sdougm 18903034Sdougm /* 18913034Sdougm * sa_create_group(groupname, *error) 18923034Sdougm * 18933034Sdougm * Create a new group with groupname. Need to validate that it is a 18943034Sdougm * legal name for SMF and the construct the SMF service instance of 18953034Sdougm * svc:/network/shares/group to implement the group. All necessary 18963034Sdougm * operational properties must be added to the group at this point 18973034Sdougm * (via the SMF transaction model). 18983034Sdougm */ 18993034Sdougm sa_group_t 19003910Sdougm sa_create_group(sa_handle_t handle, char *groupname, int *error) 19013034Sdougm { 19023034Sdougm xmlNodePtr node = NULL; 19033034Sdougm sa_group_t group; 19043034Sdougm int ret; 19054327Sdougm char rbacstr[SA_STRSIZE]; 19063910Sdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle; 19073034Sdougm 19083034Sdougm ret = SA_OK; 19093034Sdougm 19103910Sdougm if (impl_handle == NULL || impl_handle->scfhandle == NULL) { 19114327Sdougm ret = SA_SYSTEM_ERR; 19124327Sdougm goto err; 19133034Sdougm } 19143034Sdougm 19153910Sdougm group = sa_get_group(handle, groupname); 19163034Sdougm if (group != NULL) { 19174327Sdougm ret = SA_DUPLICATE_NAME; 19183034Sdougm } else { 19194327Sdougm if (sa_valid_group_name(groupname)) { 19204327Sdougm node = xmlNewChild(impl_handle->tree, NULL, 19214327Sdougm (xmlChar *)"group", NULL); 19224327Sdougm if (node != NULL) { 19236007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 19244327Sdougm (xmlChar *)groupname); 19254327Sdougm /* default to the group being enabled */ 19266007Sthurlow (void) xmlSetProp(node, (xmlChar *)"state", 19274327Sdougm (xmlChar *)"enabled"); 19284327Sdougm ret = sa_create_instance(impl_handle->scfhandle, 19294327Sdougm groupname); 19304327Sdougm if (ret == SA_OK) { 19314327Sdougm ret = sa_start_transaction( 19324327Sdougm impl_handle->scfhandle, 19334327Sdougm "operation"); 19344327Sdougm } 19354327Sdougm if (ret == SA_OK) { 19364327Sdougm ret = sa_set_property( 19374327Sdougm impl_handle->scfhandle, 19384327Sdougm "state", "enabled"); 19394327Sdougm if (ret == SA_OK) { 19404327Sdougm ret = sa_end_transaction( 19415951Sdougm impl_handle->scfhandle, 19425951Sdougm impl_handle); 19434327Sdougm } else { 19444327Sdougm sa_abort_transaction( 19454327Sdougm impl_handle->scfhandle); 19464327Sdougm } 19474327Sdougm } 19484327Sdougm if (ret == SA_OK) { 19494327Sdougm /* initialize the RBAC strings */ 19504327Sdougm ret = sa_start_transaction( 19514327Sdougm impl_handle->scfhandle, 19524327Sdougm "general"); 19534327Sdougm if (ret == SA_OK) { 19544327Sdougm (void) snprintf(rbacstr, 19554327Sdougm sizeof (rbacstr), "%s.%s", 19564327Sdougm SA_RBAC_MANAGE, groupname); 19574327Sdougm ret = sa_set_property( 19584327Sdougm impl_handle->scfhandle, 19593034Sdougm "action_authorization", 19603034Sdougm rbacstr); 19614327Sdougm } 19624327Sdougm if (ret == SA_OK) { 19634327Sdougm (void) snprintf(rbacstr, 19644327Sdougm sizeof (rbacstr), "%s.%s", 19654327Sdougm SA_RBAC_VALUE, groupname); 19664327Sdougm ret = sa_set_property( 19674327Sdougm impl_handle->scfhandle, 19683034Sdougm "value_authorization", 19693034Sdougm rbacstr); 19704327Sdougm } 19714327Sdougm if (ret == SA_OK) { 19724327Sdougm ret = sa_end_transaction( 19735951Sdougm impl_handle->scfhandle, 19745951Sdougm impl_handle); 19754327Sdougm } else { 19764327Sdougm sa_abort_transaction( 19774327Sdougm impl_handle->scfhandle); 19784327Sdougm } 19794327Sdougm } 19804327Sdougm if (ret != SA_OK) { 19814327Sdougm /* 19824327Sdougm * Couldn't commit the group 19834327Sdougm * so we need to undo 19844327Sdougm * internally. 19854327Sdougm */ 19864327Sdougm xmlUnlinkNode(node); 19874327Sdougm xmlFreeNode(node); 19884327Sdougm node = NULL; 19894327Sdougm } 19903034Sdougm } else { 19914327Sdougm ret = SA_NO_MEMORY; 19923034Sdougm } 19933034Sdougm } else { 19944327Sdougm ret = SA_INVALID_NAME; 19953034Sdougm } 19963034Sdougm } 19973034Sdougm err: 19983034Sdougm if (error != NULL) 19994327Sdougm *error = ret; 20003034Sdougm return ((sa_group_t)node); 20013034Sdougm } 20023034Sdougm 20033034Sdougm /* 20043034Sdougm * sa_remove_group(group) 20053034Sdougm * 20063034Sdougm * Remove the specified group. This deletes from the SMF repository. 20073034Sdougm * All property groups and properties are removed. 20083034Sdougm */ 20093034Sdougm 20103034Sdougm int 20113034Sdougm sa_remove_group(sa_group_t group) 20123034Sdougm { 20133034Sdougm char *name; 20143034Sdougm int ret = SA_OK; 20153910Sdougm sa_handle_impl_t impl_handle; 20163034Sdougm 20173910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 20183910Sdougm if (impl_handle != NULL) { 20194327Sdougm name = sa_get_group_attr(group, "name"); 20204327Sdougm if (name != NULL) { 20214327Sdougm ret = sa_delete_instance(impl_handle->scfhandle, name); 20224327Sdougm sa_free_attr_string(name); 20234327Sdougm } 20244327Sdougm xmlUnlinkNode((xmlNodePtr)group); /* make sure unlinked */ 20254327Sdougm xmlFreeNode((xmlNodePtr)group); /* now it is gone */ 20263910Sdougm } else { 20274327Sdougm ret = SA_SYSTEM_ERR; 20283034Sdougm } 20293034Sdougm return (ret); 20303034Sdougm } 20313034Sdougm 20323034Sdougm /* 20333034Sdougm * sa_update_config() 20343034Sdougm * 20353034Sdougm * Used to update legacy files that need to be updated in bulk 20363034Sdougm * Currently, this is a placeholder and will go away in a future 20373034Sdougm * release. 20383034Sdougm */ 20393034Sdougm 20403034Sdougm int 20413910Sdougm sa_update_config(sa_handle_t handle) 20423034Sdougm { 20433034Sdougm /* 20443034Sdougm * do legacy files first so we can tell when they change. 20453034Sdougm * This will go away when we start updating individual records 20463034Sdougm * rather than the whole file. 20473034Sdougm */ 20483910Sdougm update_legacy_config(handle); 20493034Sdougm return (SA_OK); 20503034Sdougm } 20513034Sdougm 20523034Sdougm /* 20533034Sdougm * get_node_attr(node, tag) 20543034Sdougm * 20555331Samw * Get the specified tag(attribute) if it exists on the node. This is 20563034Sdougm * used internally by a number of attribute oriented functions. 20573034Sdougm */ 20583034Sdougm 20593034Sdougm static char * 20603034Sdougm get_node_attr(void *nodehdl, char *tag) 20613034Sdougm { 20623034Sdougm xmlNodePtr node = (xmlNodePtr)nodehdl; 20633034Sdougm xmlChar *name = NULL; 20643034Sdougm 20654327Sdougm if (node != NULL) 20663034Sdougm name = xmlGetProp(node, (xmlChar *)tag); 20673034Sdougm return ((char *)name); 20683034Sdougm } 20693034Sdougm 20703034Sdougm /* 207111337SWilliam.Krier@Sun.COM * set_node_attr(node, tag) 20723034Sdougm * 20735331Samw * Set the specified tag(attribute) to the specified value This is 20743034Sdougm * used internally by a number of attribute oriented functions. It 20753034Sdougm * doesn't update the repository, only the internal document state. 20763034Sdougm */ 20773034Sdougm 20783034Sdougm void 20793034Sdougm set_node_attr(void *nodehdl, char *tag, char *value) 20803034Sdougm { 20813034Sdougm xmlNodePtr node = (xmlNodePtr)nodehdl; 20823034Sdougm if (node != NULL && tag != NULL) { 20834327Sdougm if (value != NULL) 20846007Sthurlow (void) xmlSetProp(node, (xmlChar *)tag, 20856007Sthurlow (xmlChar *)value); 20864327Sdougm else 20876007Sthurlow (void) xmlUnsetProp(node, (xmlChar *)tag); 20883034Sdougm } 20893034Sdougm } 20903034Sdougm 20913034Sdougm /* 20923034Sdougm * sa_get_group_attr(group, tag) 20933034Sdougm * 20943034Sdougm * Get the specied attribute, if defined, for the group. 20953034Sdougm */ 20963034Sdougm 20973034Sdougm char * 20983034Sdougm sa_get_group_attr(sa_group_t group, char *tag) 20993034Sdougm { 21003034Sdougm return (get_node_attr((void *)group, tag)); 21013034Sdougm } 21023034Sdougm 21033034Sdougm /* 21043034Sdougm * sa_set_group_attr(group, tag, value) 21053034Sdougm * 21063034Sdougm * set the specified tag/attribute on the group using value as its 21073034Sdougm * value. 21083034Sdougm * 21093034Sdougm * This will result in setting the property in the SMF repository as 21103034Sdougm * well as in the internal document. 21113034Sdougm */ 21123034Sdougm 21133034Sdougm int 21143034Sdougm sa_set_group_attr(sa_group_t group, char *tag, char *value) 21153034Sdougm { 21163034Sdougm int ret; 21173034Sdougm char *groupname; 21183910Sdougm sa_handle_impl_t impl_handle; 21193034Sdougm 21205331Samw /* 21215331Samw * ZFS group/subgroup doesn't need the handle so shortcut. 21225331Samw */ 21235331Samw if (sa_group_is_zfs(group)) { 21245331Samw set_node_attr((void *)group, tag, value); 21255331Samw return (SA_OK); 21265331Samw } 21275331Samw 21283910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 21293910Sdougm if (impl_handle != NULL) { 21304327Sdougm groupname = sa_get_group_attr(group, "name"); 21314327Sdougm ret = sa_get_instance(impl_handle->scfhandle, groupname); 21323910Sdougm if (ret == SA_OK) { 21334327Sdougm set_node_attr((void *)group, tag, value); 21344327Sdougm ret = sa_start_transaction(impl_handle->scfhandle, 21354327Sdougm "operation"); 21364327Sdougm if (ret == SA_OK) { 21374327Sdougm ret = sa_set_property(impl_handle->scfhandle, 21384327Sdougm tag, value); 21394327Sdougm if (ret == SA_OK) 21405885Sdougm ret = sa_end_transaction( 21415951Sdougm impl_handle->scfhandle, 21425951Sdougm impl_handle); 21434327Sdougm else 21444327Sdougm sa_abort_transaction( 21454327Sdougm impl_handle->scfhandle); 21464327Sdougm } 21475885Sdougm if (ret == SA_SYSTEM_ERR) 21485885Sdougm ret = SA_NO_PERMISSION; 21493034Sdougm } 21504327Sdougm if (groupname != NULL) 21514327Sdougm sa_free_attr_string(groupname); 21523910Sdougm } else { 21534327Sdougm ret = SA_SYSTEM_ERR; 21543034Sdougm } 21553034Sdougm return (ret); 21563034Sdougm } 21573034Sdougm 21583034Sdougm /* 21593034Sdougm * sa_get_share_attr(share, tag) 21603034Sdougm * 21613034Sdougm * Return the value of the tag/attribute set on the specified 21623034Sdougm * share. Returns NULL if the tag doesn't exist. 21633034Sdougm */ 21643034Sdougm 21653034Sdougm char * 21663034Sdougm sa_get_share_attr(sa_share_t share, char *tag) 21673034Sdougm { 21683034Sdougm return (get_node_attr((void *)share, tag)); 21693034Sdougm } 21703034Sdougm 21713034Sdougm /* 21723034Sdougm * _sa_set_share_description(share, description) 21733034Sdougm * 21745331Samw * Add a description tag with text contents to the specified share. A 21755331Samw * separate XML tag is used rather than a property. This can also be 21765331Samw * used with resources. 21773034Sdougm */ 21783034Sdougm 21793034Sdougm xmlNodePtr 21805331Samw _sa_set_share_description(void *share, char *content) 21813034Sdougm { 21823034Sdougm xmlNodePtr node; 21834327Sdougm node = xmlNewChild((xmlNodePtr)share, NULL, (xmlChar *)"description", 21844327Sdougm NULL); 21853034Sdougm xmlNodeSetContent(node, (xmlChar *)content); 21863034Sdougm return (node); 21873034Sdougm } 21883034Sdougm 21893034Sdougm /* 21903034Sdougm * sa_set_share_attr(share, tag, value) 21913034Sdougm * 21923034Sdougm * Set the share attribute specified by tag to the specified value. In 21933034Sdougm * the case of "resource", enforce a no duplicates in a group rule. If 21943034Sdougm * the share is not transient, commit the changes to the repository 21953034Sdougm * else just update the share internally. 21963034Sdougm */ 21973034Sdougm 21983034Sdougm int 21993034Sdougm sa_set_share_attr(sa_share_t share, char *tag, char *value) 22003034Sdougm { 22013034Sdougm sa_group_t group; 22023034Sdougm sa_share_t resource; 22033034Sdougm int ret = SA_OK; 22043034Sdougm 22053034Sdougm group = sa_get_parent_group(share); 22063034Sdougm 22073034Sdougm /* 22083034Sdougm * There are some attributes that may have specific 22093034Sdougm * restrictions on them. Initially, only "resource" has 22103034Sdougm * special meaning that needs to be checked. Only one instance 22113034Sdougm * of a resource name may exist within a group. 22123034Sdougm */ 22133034Sdougm 22143034Sdougm if (strcmp(tag, "resource") == 0) { 22154327Sdougm resource = sa_get_resource(group, value); 22164327Sdougm if (resource != share && resource != NULL) 22174327Sdougm ret = SA_DUPLICATE_NAME; 22183034Sdougm } 22193034Sdougm if (ret == SA_OK) { 22204327Sdougm set_node_attr((void *)share, tag, value); 22214327Sdougm if (group != NULL) { 22224327Sdougm char *type; 22234327Sdougm /* we can probably optimize this some */ 22244327Sdougm type = sa_get_share_attr(share, "type"); 22254327Sdougm if (type == NULL || strcmp(type, "transient") != 0) { 22264327Sdougm sa_handle_impl_t impl_handle; 22274327Sdougm impl_handle = 22284327Sdougm (sa_handle_impl_t)sa_find_group_handle( 22294327Sdougm group); 22304327Sdougm if (impl_handle != NULL) { 22314327Sdougm ret = sa_commit_share( 22324327Sdougm impl_handle->scfhandle, group, 22334327Sdougm share); 22344327Sdougm } else { 22354327Sdougm ret = SA_SYSTEM_ERR; 22364327Sdougm } 22374327Sdougm } 22384327Sdougm if (type != NULL) 22394327Sdougm sa_free_attr_string(type); 22403910Sdougm } 22413034Sdougm } 22423034Sdougm return (ret); 22433034Sdougm } 22443034Sdougm 22453034Sdougm /* 22463034Sdougm * sa_get_property_attr(prop, tag) 22473034Sdougm * 22483034Sdougm * Get the value of the specified property attribute. Standard 22493034Sdougm * attributes are "type" and "value". 22503034Sdougm */ 22513034Sdougm 22523034Sdougm char * 22533034Sdougm sa_get_property_attr(sa_property_t prop, char *tag) 22543034Sdougm { 22553034Sdougm return (get_node_attr((void *)prop, tag)); 22563034Sdougm } 22573034Sdougm 22583034Sdougm /* 22593034Sdougm * sa_get_optionset_attr(prop, tag) 22603034Sdougm * 22613034Sdougm * Get the value of the specified property attribute. Standard 22623034Sdougm * attribute is "type". 22633034Sdougm */ 22643034Sdougm 22653034Sdougm char * 22663034Sdougm sa_get_optionset_attr(sa_property_t optionset, char *tag) 22673034Sdougm { 22683034Sdougm return (get_node_attr((void *)optionset, tag)); 22693034Sdougm 22703034Sdougm } 22713034Sdougm 22723034Sdougm /* 22733034Sdougm * sa_set_optionset_attr(optionset, tag, value) 22743034Sdougm * 22753034Sdougm * Set the specified attribute(tag) to the specified value on the 22763034Sdougm * optionset. 22773034Sdougm */ 22783034Sdougm 22793034Sdougm void 22803034Sdougm sa_set_optionset_attr(sa_group_t optionset, char *tag, char *value) 22813034Sdougm { 22823034Sdougm set_node_attr((void *)optionset, tag, value); 22833034Sdougm } 22843034Sdougm 22853034Sdougm /* 22863034Sdougm * sa_free_attr_string(string) 22873034Sdougm * 22883034Sdougm * Free the string that was returned in one of the sa_get_*_attr() 22893034Sdougm * functions. 22903034Sdougm */ 22913034Sdougm 22923034Sdougm void 22933034Sdougm sa_free_attr_string(char *string) 22943034Sdougm { 22953034Sdougm xmlFree((xmlChar *)string); 22963034Sdougm } 22973034Sdougm 22983034Sdougm /* 22993034Sdougm * sa_get_optionset(group, proto) 23003034Sdougm * 23013034Sdougm * Return the optionset, if it exists, that is associated with the 23023034Sdougm * specified protocol. 23033034Sdougm */ 23043034Sdougm 23053034Sdougm sa_optionset_t 23063034Sdougm sa_get_optionset(void *group, char *proto) 23073034Sdougm { 23083034Sdougm xmlNodePtr node; 23093034Sdougm xmlChar *value = NULL; 23103034Sdougm 23113034Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 23124327Sdougm node = node->next) { 23133034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) { 23144327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 23154327Sdougm if (proto != NULL) { 23164327Sdougm if (value != NULL && 23174327Sdougm xmlStrcmp(value, (xmlChar *)proto) == 0) { 23184327Sdougm break; 23194327Sdougm } 23204327Sdougm if (value != NULL) { 23214327Sdougm xmlFree(value); 23224327Sdougm value = NULL; 23234327Sdougm } 23244327Sdougm } else { 23254327Sdougm break; 23263034Sdougm } 23273034Sdougm } 23283034Sdougm } 23293034Sdougm if (value != NULL) 23304327Sdougm xmlFree(value); 23313034Sdougm return ((sa_optionset_t)node); 23323034Sdougm } 23333034Sdougm 23343034Sdougm /* 23353034Sdougm * sa_get_next_optionset(optionset) 23363034Sdougm * 23373034Sdougm * Return the next optionset in the group. NULL if this was the last. 23383034Sdougm */ 23393034Sdougm 23403034Sdougm sa_optionset_t 23413034Sdougm sa_get_next_optionset(sa_optionset_t optionset) 23423034Sdougm { 23433034Sdougm xmlNodePtr node; 23443034Sdougm 23453034Sdougm for (node = ((xmlNodePtr)optionset)->next; node != NULL; 23464327Sdougm node = node->next) { 23473034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) { 23483034Sdougm break; 23493034Sdougm } 23503034Sdougm } 23513034Sdougm return ((sa_optionset_t)node); 23523034Sdougm } 23533034Sdougm 23543034Sdougm /* 23553034Sdougm * sa_get_security(group, sectype, proto) 23563034Sdougm * 23573034Sdougm * Return the security optionset. The internal name is a hold over 23583034Sdougm * from the implementation and will be changed before the API is 23593034Sdougm * finalized. This is really a named optionset that can be negotiated 23603034Sdougm * as a group of properties (like NFS security options). 23613034Sdougm */ 23623034Sdougm 23633034Sdougm sa_security_t 23643034Sdougm sa_get_security(sa_group_t group, char *sectype, char *proto) 23653034Sdougm { 23663034Sdougm xmlNodePtr node; 23673034Sdougm xmlChar *value = NULL; 23683034Sdougm 23693034Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 23704327Sdougm node = node->next) { 23714327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) { 23724327Sdougm if (proto != NULL) { 23734327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 23744327Sdougm if (value == NULL || 23754327Sdougm (value != NULL && 23764327Sdougm xmlStrcmp(value, (xmlChar *)proto) != 0)) { 23774327Sdougm /* it doesn't match so continue */ 23784327Sdougm xmlFree(value); 23794327Sdougm value = NULL; 23804327Sdougm continue; 23814327Sdougm } 23824327Sdougm } 23834327Sdougm if (value != NULL) { 23844327Sdougm xmlFree(value); 23854327Sdougm value = NULL; 23864327Sdougm } 23874327Sdougm /* potential match */ 23884327Sdougm if (sectype != NULL) { 23894327Sdougm value = xmlGetProp(node, (xmlChar *)"sectype"); 23904327Sdougm if (value != NULL && 23914327Sdougm xmlStrcmp(value, (xmlChar *)sectype) == 0) { 23924327Sdougm break; 23934327Sdougm } 23944327Sdougm } else { 23954327Sdougm break; 23964327Sdougm } 23973034Sdougm } 23983034Sdougm if (value != NULL) { 23994327Sdougm xmlFree(value); 24004327Sdougm value = NULL; 24013034Sdougm } 24023034Sdougm } 24033034Sdougm if (value != NULL) 24044327Sdougm xmlFree(value); 24053034Sdougm return ((sa_security_t)node); 24063034Sdougm } 24073034Sdougm 24083034Sdougm /* 24093034Sdougm * sa_get_next_security(security) 24103034Sdougm * 24113034Sdougm * Get the next security optionset if one exists. 24123034Sdougm */ 24133034Sdougm 24143034Sdougm sa_security_t 24153034Sdougm sa_get_next_security(sa_security_t security) 24163034Sdougm { 24173034Sdougm xmlNodePtr node; 24183034Sdougm 24193034Sdougm for (node = ((xmlNodePtr)security)->next; node != NULL; 24204327Sdougm node = node->next) { 24213034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) { 24223034Sdougm break; 24233034Sdougm } 24243034Sdougm } 24253034Sdougm return ((sa_security_t)node); 24263034Sdougm } 24273034Sdougm 24283034Sdougm /* 24293034Sdougm * sa_get_property(optionset, prop) 24303034Sdougm * 24313034Sdougm * Get the property object with the name specified in prop from the 24323034Sdougm * optionset. 24333034Sdougm */ 24343034Sdougm 24353034Sdougm sa_property_t 24363034Sdougm sa_get_property(sa_optionset_t optionset, char *prop) 24373034Sdougm { 24383034Sdougm xmlNodePtr node = (xmlNodePtr)optionset; 24393034Sdougm xmlChar *value = NULL; 24403034Sdougm 24413034Sdougm if (optionset == NULL) 24424327Sdougm return (NULL); 24433034Sdougm 24443034Sdougm for (node = node->children; node != NULL; 24454327Sdougm node = node->next) { 24464327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 24474327Sdougm if (prop == NULL) 24484327Sdougm break; 24494327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 24504327Sdougm if (value != NULL && 24514327Sdougm xmlStrcmp(value, (xmlChar *)prop) == 0) { 24524327Sdougm break; 24534327Sdougm } 24544327Sdougm if (value != NULL) { 24554327Sdougm xmlFree(value); 24564327Sdougm value = NULL; 24574327Sdougm } 24583034Sdougm } 24593034Sdougm } 24603034Sdougm if (value != NULL) 24613034Sdougm xmlFree(value); 24623034Sdougm if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"option") != 0) { 24634327Sdougm /* 24644327Sdougm * avoid a non option node -- it is possible to be a 24654327Sdougm * text node 24664327Sdougm */ 24674327Sdougm node = NULL; 24683034Sdougm } 24693034Sdougm return ((sa_property_t)node); 24703034Sdougm } 24713034Sdougm 24723034Sdougm /* 24733034Sdougm * sa_get_next_property(property) 24743034Sdougm * 24753034Sdougm * Get the next property following the specified property. NULL if 24763034Sdougm * this was the last. 24773034Sdougm */ 24783034Sdougm 24793034Sdougm sa_property_t 24803034Sdougm sa_get_next_property(sa_property_t property) 24813034Sdougm { 24823034Sdougm xmlNodePtr node; 24833034Sdougm 24843034Sdougm for (node = ((xmlNodePtr)property)->next; node != NULL; 24854327Sdougm node = node->next) { 24863034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 24873034Sdougm break; 24883034Sdougm } 24893034Sdougm } 24903034Sdougm return ((sa_property_t)node); 24913034Sdougm } 24923034Sdougm 24933034Sdougm /* 24943034Sdougm * sa_set_share_description(share, content) 24953034Sdougm * 24963034Sdougm * Set the description of share to content. 24973034Sdougm */ 24983034Sdougm 24993034Sdougm int 25003034Sdougm sa_set_share_description(sa_share_t share, char *content) 25013034Sdougm { 25023034Sdougm xmlNodePtr node; 25033034Sdougm sa_group_t group; 25043034Sdougm int ret = SA_OK; 25053034Sdougm 25063034Sdougm for (node = ((xmlNodePtr)share)->children; node != NULL; 25074327Sdougm node = node->next) { 25083034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 25093034Sdougm break; 25103034Sdougm } 25113034Sdougm } 25123034Sdougm /* no existing description but want to add */ 25133034Sdougm if (node == NULL && content != NULL) { 25143034Sdougm /* add a description */ 25154327Sdougm node = _sa_set_share_description(share, content); 25163034Sdougm } else if (node != NULL && content != NULL) { 25173034Sdougm /* update a description */ 25183034Sdougm xmlNodeSetContent(node, (xmlChar *)content); 25193034Sdougm } else if (node != NULL && content == NULL) { 25203034Sdougm /* remove an existing description */ 25213034Sdougm xmlUnlinkNode(node); 25223034Sdougm xmlFreeNode(node); 25233034Sdougm } 25245331Samw group = sa_get_parent_group(share); 2525*12508Samw@Sun.COM if (group != NULL && 2526*12508Samw@Sun.COM sa_is_persistent(share) && (!sa_group_is_zfs(group))) { 25274327Sdougm sa_handle_impl_t impl_handle; 25284327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 25294327Sdougm if (impl_handle != NULL) { 25304327Sdougm ret = sa_commit_share(impl_handle->scfhandle, group, 25314327Sdougm share); 25324327Sdougm } else { 25334327Sdougm ret = SA_SYSTEM_ERR; 25344327Sdougm } 25353910Sdougm } 25363034Sdougm return (ret); 25373034Sdougm } 25383034Sdougm 25393034Sdougm /* 25403034Sdougm * fixproblemchars(string) 25413034Sdougm * 25423034Sdougm * don't want any newline or tab characters in the text since these 25433034Sdougm * could break display of data and legacy file formats. 25443034Sdougm */ 25453034Sdougm static void 25463034Sdougm fixproblemchars(char *str) 25473034Sdougm { 25483034Sdougm int c; 25493034Sdougm for (c = *str; c != '\0'; c = *++str) { 25504327Sdougm if (c == '\t' || c == '\n') 25514327Sdougm *str = ' '; 25524327Sdougm else if (c == '"') 25534327Sdougm *str = '\''; 25543034Sdougm } 25553034Sdougm } 25563034Sdougm 25573034Sdougm /* 25583034Sdougm * sa_get_share_description(share) 25593034Sdougm * 25603034Sdougm * Return the description text for the specified share if it 25613034Sdougm * exists. NULL if no description exists. 25623034Sdougm */ 25633034Sdougm 25643034Sdougm char * 25653034Sdougm sa_get_share_description(sa_share_t share) 25663034Sdougm { 25673034Sdougm xmlChar *description = NULL; 25683034Sdougm xmlNodePtr node; 25693034Sdougm 25703034Sdougm for (node = ((xmlNodePtr)share)->children; node != NULL; 25714327Sdougm node = node->next) { 25724327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 25734327Sdougm break; 25744327Sdougm } 25753034Sdougm } 25763034Sdougm if (node != NULL) { 25775331Samw description = xmlNodeGetContent(node); 25784327Sdougm fixproblemchars((char *)description); 25793034Sdougm } 25803034Sdougm return ((char *)description); 25813034Sdougm } 25823034Sdougm 25833034Sdougm /* 25843034Sdougm * sa_free(share_description(description) 25853034Sdougm * 25863034Sdougm * Free the description string. 25873034Sdougm */ 25883034Sdougm 25893034Sdougm void 25903034Sdougm sa_free_share_description(char *description) 25913034Sdougm { 25923034Sdougm xmlFree((xmlChar *)description); 25933034Sdougm } 25943034Sdougm 25953034Sdougm /* 25963034Sdougm * sa_create_optionset(group, proto) 25973034Sdougm * 25983034Sdougm * Create an optionset for the specified protocol in the specied 25993034Sdougm * group. This is manifested as a property group within SMF. 26003034Sdougm */ 26013034Sdougm 26023034Sdougm sa_optionset_t 26033034Sdougm sa_create_optionset(sa_group_t group, char *proto) 26043034Sdougm { 26053034Sdougm sa_optionset_t optionset; 26063034Sdougm sa_group_t parent = group; 26075331Samw sa_share_t share = NULL; 26085331Samw int err = SA_OK; 26095331Samw char *id = NULL; 26103034Sdougm 26113034Sdougm optionset = sa_get_optionset(group, proto); 26123034Sdougm if (optionset != NULL) { 26133034Sdougm /* can't have a duplicate protocol */ 26144327Sdougm optionset = NULL; 26153034Sdougm } else { 26165331Samw /* 26175331Samw * Account for resource names being slightly 26185331Samw * different. 26195331Samw */ 26205331Samw if (sa_is_share(group)) { 26215331Samw /* 26225331Samw * Transient shares do not have an "id" so not an 26235331Samw * error to not find one. 26245331Samw */ 26255331Samw id = sa_get_share_attr((sa_share_t)group, "id"); 26265331Samw } else if (sa_is_resource(group)) { 26275331Samw share = sa_get_resource_parent( 26285331Samw (sa_resource_t)group); 26295331Samw id = sa_get_resource_attr(share, "id"); 26305331Samw 26315331Samw /* id can be NULL if the group is transient (ZFS) */ 26325331Samw if (id == NULL && sa_is_persistent(group)) 26335331Samw err = SA_NO_MEMORY; 26345331Samw } 26355331Samw if (err == SA_NO_MEMORY) { 26365331Samw /* 26375331Samw * Couldn't get the id for the share or 26385331Samw * resource. While this could be a 26395331Samw * configuration issue, it is most likely an 26405331Samw * out of memory. In any case, fail the create. 26415331Samw */ 26425331Samw return (NULL); 26435331Samw } 26445331Samw 26454327Sdougm optionset = (sa_optionset_t)xmlNewChild((xmlNodePtr)group, 26464327Sdougm NULL, (xmlChar *)"optionset", NULL); 26473034Sdougm /* 26483034Sdougm * only put to repository if on a group and we were 26493034Sdougm * able to create an optionset. 26503034Sdougm */ 26514327Sdougm if (optionset != NULL) { 26524327Sdougm char oname[SA_STRSIZE]; 26534327Sdougm char *groupname; 26545331Samw 26555331Samw /* 26565331Samw * Need to get parent group in all cases, but also get 26575331Samw * the share if this is a resource. 26585331Samw */ 26595331Samw if (sa_is_share(group)) { 26604327Sdougm parent = sa_get_parent_group((sa_share_t)group); 26615331Samw } else if (sa_is_resource(group)) { 26625331Samw share = sa_get_resource_parent( 26635331Samw (sa_resource_t)group); 26645331Samw parent = sa_get_parent_group(share); 26655331Samw } 26664327Sdougm 26674327Sdougm sa_set_optionset_attr(optionset, "type", proto); 26683034Sdougm 26694327Sdougm (void) sa_optionset_name(optionset, oname, 26704327Sdougm sizeof (oname), id); 26714327Sdougm groupname = sa_get_group_attr(parent, "name"); 26725331Samw if (groupname != NULL && sa_is_persistent(group)) { 26734327Sdougm sa_handle_impl_t impl_handle; 26745331Samw impl_handle = 26755331Samw (sa_handle_impl_t)sa_find_group_handle( 26765331Samw group); 26774327Sdougm assert(impl_handle != NULL); 26784327Sdougm if (impl_handle != NULL) { 26794327Sdougm (void) sa_get_instance( 26805331Samw impl_handle->scfhandle, groupname); 26814327Sdougm (void) sa_create_pgroup( 26824327Sdougm impl_handle->scfhandle, oname); 26834327Sdougm } 26844327Sdougm } 26854327Sdougm if (groupname != NULL) 26864327Sdougm sa_free_attr_string(groupname); 26873034Sdougm } 26883034Sdougm } 26895331Samw 26905331Samw if (id != NULL) 26915331Samw sa_free_attr_string(id); 26923034Sdougm return (optionset); 26933034Sdougm } 26943034Sdougm 26953034Sdougm /* 26963034Sdougm * sa_get_property_parent(property) 26973034Sdougm * 26983034Sdougm * Given a property, return the object it is a property of. This will 26993034Sdougm * be an optionset of some type. 27003034Sdougm */ 27013034Sdougm 27023034Sdougm static sa_optionset_t 27033034Sdougm sa_get_property_parent(sa_property_t property) 27043034Sdougm { 27053034Sdougm xmlNodePtr node = NULL; 27063034Sdougm 27074327Sdougm if (property != NULL) 27084327Sdougm node = ((xmlNodePtr)property)->parent; 27093034Sdougm return ((sa_optionset_t)node); 27103034Sdougm } 27113034Sdougm 27123034Sdougm /* 27133034Sdougm * sa_get_optionset_parent(optionset) 27143034Sdougm * 27153034Sdougm * Return the parent of the specified optionset. This could be a group 27163034Sdougm * or a share. 27173034Sdougm */ 27183034Sdougm 27193034Sdougm static sa_group_t 27203034Sdougm sa_get_optionset_parent(sa_optionset_t optionset) 27213034Sdougm { 27223034Sdougm xmlNodePtr node = NULL; 27233034Sdougm 27244327Sdougm if (optionset != NULL) 27254327Sdougm node = ((xmlNodePtr)optionset)->parent; 27263034Sdougm return ((sa_group_t)node); 27273034Sdougm } 27283034Sdougm 27293034Sdougm /* 27303034Sdougm * zfs_needs_update(share) 27313034Sdougm * 27323034Sdougm * In order to avoid making multiple updates to a ZFS share when 27333034Sdougm * setting properties, the share attribute "changed" will be set to 27345331Samw * true when a property is added or modified. When done adding 27353034Sdougm * properties, we can then detect that an update is needed. We then 27363034Sdougm * clear the state here to detect additional changes. 27373034Sdougm */ 27383034Sdougm 27393034Sdougm static int 27403034Sdougm zfs_needs_update(sa_share_t share) 27413034Sdougm { 27423034Sdougm char *attr; 27433034Sdougm int result = 0; 27443034Sdougm 27453034Sdougm attr = sa_get_share_attr(share, "changed"); 27463034Sdougm if (attr != NULL) { 27474327Sdougm sa_free_attr_string(attr); 27483034Sdougm result = 1; 27493034Sdougm } 27503034Sdougm set_node_attr((void *)share, "changed", NULL); 27513034Sdougm return (result); 27523034Sdougm } 27533034Sdougm 27543034Sdougm /* 27553034Sdougm * zfs_set_update(share) 27563034Sdougm * 27573034Sdougm * Set the changed attribute of the share to true. 27583034Sdougm */ 27593034Sdougm 27603034Sdougm static void 27613034Sdougm zfs_set_update(sa_share_t share) 27623034Sdougm { 27633034Sdougm set_node_attr((void *)share, "changed", "true"); 27643034Sdougm } 27653034Sdougm 27663034Sdougm /* 27673034Sdougm * sa_commit_properties(optionset, clear) 27683034Sdougm * 27693034Sdougm * Check if SMF or ZFS config and either update or abort the pending 27703034Sdougm * changes. 27713034Sdougm */ 27723034Sdougm 27733034Sdougm int 27743034Sdougm sa_commit_properties(sa_optionset_t optionset, int clear) 27753034Sdougm { 27763034Sdougm sa_group_t group; 27773034Sdougm sa_group_t parent; 27783034Sdougm int zfs = 0; 27793034Sdougm int needsupdate = 0; 27803034Sdougm int ret = SA_OK; 27813910Sdougm sa_handle_impl_t impl_handle; 27823034Sdougm 27833034Sdougm group = sa_get_optionset_parent(optionset); 27843034Sdougm if (group != NULL && (sa_is_share(group) || is_zfs_group(group))) { 27854327Sdougm /* only update ZFS if on a share */ 27864327Sdougm parent = sa_get_parent_group(group); 27874327Sdougm zfs++; 27884327Sdougm if (parent != NULL && is_zfs_group(parent)) 27894327Sdougm needsupdate = zfs_needs_update(group); 27904327Sdougm else 27914327Sdougm zfs = 0; 27923034Sdougm } 27933034Sdougm if (zfs) { 27944327Sdougm if (!clear && needsupdate) 27954327Sdougm ret = sa_zfs_update((sa_share_t)group); 27963034Sdougm } else { 27974327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 27984327Sdougm if (impl_handle != NULL) { 27994327Sdougm if (clear) { 28004327Sdougm (void) sa_abort_transaction( 28014327Sdougm impl_handle->scfhandle); 28024327Sdougm } else { 28034327Sdougm ret = sa_end_transaction( 28045951Sdougm impl_handle->scfhandle, impl_handle); 28054327Sdougm } 28064327Sdougm } else { 28074327Sdougm ret = SA_SYSTEM_ERR; 28084327Sdougm } 28093034Sdougm } 28103034Sdougm return (ret); 28113034Sdougm } 28123034Sdougm 28133034Sdougm /* 28143034Sdougm * sa_destroy_optionset(optionset) 28153034Sdougm * 28165331Samw * Remove the optionset from its group. Update the repository to 28173034Sdougm * reflect this change. 28183034Sdougm */ 28193034Sdougm 28203034Sdougm int 28213034Sdougm sa_destroy_optionset(sa_optionset_t optionset) 28223034Sdougm { 28234327Sdougm char name[SA_STRSIZE]; 28243034Sdougm int len; 28253034Sdougm int ret; 28263034Sdougm char *id = NULL; 28273034Sdougm sa_group_t group; 28283034Sdougm int ispersist = 1; 28293034Sdougm 28303034Sdougm /* now delete the prop group */ 28313034Sdougm group = sa_get_optionset_parent(optionset); 28325331Samw if (group != NULL) { 28335331Samw if (sa_is_resource(group)) { 28345331Samw sa_resource_t resource = group; 28355331Samw sa_share_t share = sa_get_resource_parent(resource); 28365331Samw group = sa_get_parent_group(share); 28375331Samw id = sa_get_share_attr(share, "id"); 28385331Samw } else if (sa_is_share(group)) { 28395331Samw id = sa_get_share_attr((sa_share_t)group, "id"); 28405331Samw } 28415331Samw ispersist = sa_is_persistent(group); 28423034Sdougm } 28433034Sdougm if (ispersist) { 28444327Sdougm sa_handle_impl_t impl_handle; 28454327Sdougm len = sa_optionset_name(optionset, name, sizeof (name), id); 28464327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 28474327Sdougm if (impl_handle != NULL) { 28484327Sdougm if (len > 0) { 28494327Sdougm ret = sa_delete_pgroup(impl_handle->scfhandle, 28504327Sdougm name); 28514327Sdougm } 28524327Sdougm } else { 28534327Sdougm ret = SA_SYSTEM_ERR; 28543910Sdougm } 28553034Sdougm } 28563034Sdougm xmlUnlinkNode((xmlNodePtr)optionset); 28573034Sdougm xmlFreeNode((xmlNodePtr)optionset); 28583034Sdougm if (id != NULL) 28594327Sdougm sa_free_attr_string(id); 28603034Sdougm return (ret); 28613034Sdougm } 28623034Sdougm 28633034Sdougm /* private to the implementation */ 28643034Sdougm int 28653034Sdougm _sa_remove_optionset(sa_optionset_t optionset) 28663034Sdougm { 28673034Sdougm int ret = SA_OK; 28683034Sdougm 28693034Sdougm xmlUnlinkNode((xmlNodePtr)optionset); 28703034Sdougm xmlFreeNode((xmlNodePtr)optionset); 28713034Sdougm return (ret); 28723034Sdougm } 28733034Sdougm 28743034Sdougm /* 28753034Sdougm * sa_create_security(group, sectype, proto) 28763034Sdougm * 28773034Sdougm * Create a security optionset (one that has a type name and a 28783034Sdougm * proto). Security is left over from a pure NFS implementation. The 28793034Sdougm * naming will change in the future when the API is released. 28803034Sdougm */ 28813034Sdougm sa_security_t 28823034Sdougm sa_create_security(sa_group_t group, char *sectype, char *proto) 28833034Sdougm { 28843034Sdougm sa_security_t security; 28853034Sdougm char *id = NULL; 28863034Sdougm sa_group_t parent; 28873034Sdougm char *groupname = NULL; 28883034Sdougm 28893034Sdougm if (group != NULL && sa_is_share(group)) { 28904327Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 28914327Sdougm parent = sa_get_parent_group(group); 28924327Sdougm if (parent != NULL) 28934327Sdougm groupname = sa_get_group_attr(parent, "name"); 28943034Sdougm } else if (group != NULL) { 28954327Sdougm groupname = sa_get_group_attr(group, "name"); 28963034Sdougm } 28973034Sdougm 28983034Sdougm security = sa_get_security(group, sectype, proto); 28993034Sdougm if (security != NULL) { 29003034Sdougm /* can't have a duplicate security option */ 29013034Sdougm security = NULL; 29023034Sdougm } else { 29033034Sdougm security = (sa_security_t)xmlNewChild((xmlNodePtr)group, 29044327Sdougm NULL, (xmlChar *)"security", NULL); 29053034Sdougm if (security != NULL) { 29064327Sdougm char oname[SA_STRSIZE]; 29073034Sdougm sa_set_security_attr(security, "type", proto); 29083034Sdougm 29093034Sdougm sa_set_security_attr(security, "sectype", sectype); 29103034Sdougm (void) sa_security_name(security, oname, 29114327Sdougm sizeof (oname), id); 29125331Samw if (groupname != NULL && sa_is_persistent(group)) { 29134327Sdougm sa_handle_impl_t impl_handle; 29144327Sdougm impl_handle = 29154327Sdougm (sa_handle_impl_t)sa_find_group_handle( 29164327Sdougm group); 29174327Sdougm if (impl_handle != NULL) { 29184327Sdougm (void) sa_get_instance( 29194327Sdougm impl_handle->scfhandle, groupname); 29204327Sdougm (void) sa_create_pgroup( 29214327Sdougm impl_handle->scfhandle, oname); 29224327Sdougm } 29233034Sdougm } 29243034Sdougm } 29253034Sdougm } 292611337SWilliam.Krier@Sun.COM if (id != NULL) 292711337SWilliam.Krier@Sun.COM sa_free_attr_string(id); 29283034Sdougm if (groupname != NULL) 29294327Sdougm sa_free_attr_string(groupname); 29303034Sdougm return (security); 29313034Sdougm } 29323034Sdougm 29333034Sdougm /* 29343034Sdougm * sa_destroy_security(security) 29353034Sdougm * 29363034Sdougm * Remove the specified optionset from the document and the 29373034Sdougm * configuration. 29383034Sdougm */ 29393034Sdougm 29403034Sdougm int 29413034Sdougm sa_destroy_security(sa_security_t security) 29423034Sdougm { 29434327Sdougm char name[SA_STRSIZE]; 29443034Sdougm int len; 29453034Sdougm int ret = SA_OK; 29463034Sdougm char *id = NULL; 29473034Sdougm sa_group_t group; 29483034Sdougm int iszfs = 0; 29493034Sdougm int ispersist = 1; 29503034Sdougm 29513034Sdougm group = sa_get_optionset_parent(security); 29523034Sdougm 29533034Sdougm if (group != NULL) 29544327Sdougm iszfs = sa_group_is_zfs(group); 29553034Sdougm 29563034Sdougm if (group != NULL && !iszfs) { 29574327Sdougm if (sa_is_share(group)) 29585331Samw ispersist = sa_is_persistent(group); 29594327Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 29603034Sdougm } 29613034Sdougm if (ispersist) { 29624327Sdougm len = sa_security_name(security, name, sizeof (name), id); 29634327Sdougm if (!iszfs && len > 0) { 29644327Sdougm sa_handle_impl_t impl_handle; 29654327Sdougm impl_handle = 29664327Sdougm (sa_handle_impl_t)sa_find_group_handle(group); 29674327Sdougm if (impl_handle != NULL) { 29684327Sdougm ret = sa_delete_pgroup(impl_handle->scfhandle, 29694327Sdougm name); 29704327Sdougm } else { 29714327Sdougm ret = SA_SYSTEM_ERR; 29724327Sdougm } 29733910Sdougm } 29743034Sdougm } 29753034Sdougm xmlUnlinkNode((xmlNodePtr)security); 29763034Sdougm xmlFreeNode((xmlNodePtr)security); 29774327Sdougm if (iszfs) 29784327Sdougm ret = sa_zfs_update(group); 29793034Sdougm if (id != NULL) 29804327Sdougm sa_free_attr_string(id); 29813034Sdougm return (ret); 29823034Sdougm } 29833034Sdougm 29843034Sdougm /* 29853034Sdougm * sa_get_security_attr(optionset, tag) 29863034Sdougm * 29873034Sdougm * Return the specified attribute value from the optionset. 29883034Sdougm */ 29893034Sdougm 29903034Sdougm char * 29913034Sdougm sa_get_security_attr(sa_property_t optionset, char *tag) 29923034Sdougm { 29933034Sdougm return (get_node_attr((void *)optionset, tag)); 29943034Sdougm 29953034Sdougm } 29963034Sdougm 29973034Sdougm /* 29983034Sdougm * sa_set_security_attr(optionset, tag, value) 29993034Sdougm * 30003034Sdougm * Set the optioset attribute specied by tag to the specified value. 30013034Sdougm */ 30023034Sdougm 30033034Sdougm void 30043034Sdougm sa_set_security_attr(sa_group_t optionset, char *tag, char *value) 30053034Sdougm { 30063034Sdougm set_node_attr((void *)optionset, tag, value); 30073034Sdougm } 30083034Sdougm 30093034Sdougm /* 30103034Sdougm * is_nodetype(node, type) 30113034Sdougm * 30123034Sdougm * Check to see if node is of the type specified. 30133034Sdougm */ 30143034Sdougm 30153034Sdougm static int 30163034Sdougm is_nodetype(void *node, char *type) 30173034Sdougm { 30183034Sdougm return (strcmp((char *)((xmlNodePtr)node)->name, type) == 0); 30193034Sdougm } 30203034Sdougm 30214327Sdougm /* 30224327Sdougm * add_or_update() 30234327Sdougm * 30244327Sdougm * Add or update a property. Pulled out of sa_set_prop_by_prop for 30254327Sdougm * readability. 30264327Sdougm */ 30274327Sdougm static int 30284327Sdougm add_or_update(scfutilhandle_t *scf_handle, int type, scf_value_t *value, 30294327Sdougm scf_transaction_entry_t *entry, char *name, char *valstr) 30304327Sdougm { 30314327Sdougm int ret = SA_SYSTEM_ERR; 30324327Sdougm 30334327Sdougm if (value != NULL) { 30344327Sdougm if (type == SA_PROP_OP_ADD) 30354327Sdougm ret = scf_transaction_property_new(scf_handle->trans, 30364327Sdougm entry, name, SCF_TYPE_ASTRING); 30374327Sdougm else 30384327Sdougm ret = scf_transaction_property_change(scf_handle->trans, 30394327Sdougm entry, name, SCF_TYPE_ASTRING); 30404327Sdougm if (ret == 0) { 30414327Sdougm ret = scf_value_set_astring(value, valstr); 30424327Sdougm if (ret == 0) 30434327Sdougm ret = scf_entry_add_value(entry, value); 30444327Sdougm if (ret == 0) 30454327Sdougm return (ret); 30464327Sdougm scf_value_destroy(value); 30474327Sdougm } else { 30484327Sdougm scf_entry_destroy(entry); 30494327Sdougm } 30504327Sdougm } 30514327Sdougm return (SA_SYSTEM_ERR); 30524327Sdougm } 30534327Sdougm 30543034Sdougm /* 30553034Sdougm * sa_set_prop_by_prop(optionset, group, prop, type) 30563034Sdougm * 30573034Sdougm * Add/remove/update the specified property prop into the optionset or 30583034Sdougm * share. If a share, sort out which property group based on GUID. In 30593034Sdougm * all cases, the appropriate transaction is set (or ZFS share is 30603034Sdougm * marked as needing an update) 30613034Sdougm */ 30623034Sdougm 30633034Sdougm static int 30643034Sdougm sa_set_prop_by_prop(sa_optionset_t optionset, sa_group_t group, 30653034Sdougm sa_property_t prop, int type) 30663034Sdougm { 30673034Sdougm char *name; 30683034Sdougm char *valstr; 30693034Sdougm int ret = SA_OK; 30703034Sdougm scf_transaction_entry_t *entry; 30713034Sdougm scf_value_t *value; 30723034Sdougm int opttype; /* 1 == optionset, 0 == security */ 30733034Sdougm char *id = NULL; 30743034Sdougm int iszfs = 0; 30753034Sdougm sa_group_t parent = NULL; 30765331Samw sa_share_t share = NULL; 30773910Sdougm sa_handle_impl_t impl_handle; 30783910Sdougm scfutilhandle_t *scf_handle; 30793034Sdougm 30805331Samw if (!sa_is_persistent(group)) { 30813034Sdougm /* 30823034Sdougm * if the group/share is not persistent we don't need 30833034Sdougm * to do anything here 30843034Sdougm */ 30854327Sdougm return (SA_OK); 30863034Sdougm } 30873910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 30884327Sdougm if (impl_handle == NULL || impl_handle->scfhandle == NULL) 30894327Sdougm return (SA_SYSTEM_ERR); 30903910Sdougm scf_handle = impl_handle->scfhandle; 30913034Sdougm name = sa_get_property_attr(prop, "type"); 30923034Sdougm valstr = sa_get_property_attr(prop, "value"); 30933034Sdougm entry = scf_entry_create(scf_handle->handle); 30943034Sdougm opttype = is_nodetype((void *)optionset, "optionset"); 30953034Sdougm 30965331Samw /* 30975331Samw * Check for share vs. resource since they need slightly 30985331Samw * different treatment given the hierarchy. 30995331Samw */ 31003034Sdougm if (valstr != NULL && entry != NULL) { 31014327Sdougm if (sa_is_share(group)) { 31024327Sdougm parent = sa_get_parent_group(group); 31035331Samw share = (sa_share_t)group; 31044327Sdougm if (parent != NULL) 31054327Sdougm iszfs = is_zfs_group(parent); 31065331Samw } else if (sa_is_resource(group)) { 31075331Samw share = sa_get_parent_group(group); 31085331Samw if (share != NULL) 31095331Samw parent = sa_get_parent_group(share); 31104327Sdougm } else { 31114327Sdougm iszfs = is_zfs_group(group); 31123034Sdougm } 31134327Sdougm if (!iszfs) { 31144327Sdougm if (scf_handle->trans == NULL) { 31154327Sdougm char oname[SA_STRSIZE]; 31164327Sdougm char *groupname = NULL; 31175331Samw if (share != NULL) { 31185331Samw if (parent != NULL) 31194327Sdougm groupname = 31204327Sdougm sa_get_group_attr(parent, 31214327Sdougm "name"); 31225331Samw id = sa_get_share_attr( 31235331Samw (sa_share_t)share, "id"); 31244327Sdougm } else { 31254327Sdougm groupname = sa_get_group_attr(group, 31264327Sdougm "name"); 31274327Sdougm } 31284327Sdougm if (groupname != NULL) { 31294327Sdougm ret = sa_get_instance(scf_handle, 31304327Sdougm groupname); 31314327Sdougm sa_free_attr_string(groupname); 31324327Sdougm } 31334327Sdougm if (opttype) 31344327Sdougm (void) sa_optionset_name(optionset, 31354327Sdougm oname, sizeof (oname), id); 31364327Sdougm else 31374327Sdougm (void) sa_security_name(optionset, 31384327Sdougm oname, sizeof (oname), id); 31394327Sdougm ret = sa_start_transaction(scf_handle, oname); 314011337SWilliam.Krier@Sun.COM if (id != NULL) 314111337SWilliam.Krier@Sun.COM sa_free_attr_string(id); 31423910Sdougm } 31434327Sdougm if (ret == SA_OK) { 31444327Sdougm switch (type) { 31454327Sdougm case SA_PROP_OP_REMOVE: 31464327Sdougm ret = scf_transaction_property_delete( 31474327Sdougm scf_handle->trans, entry, name); 31484327Sdougm break; 31494327Sdougm case SA_PROP_OP_ADD: 31504327Sdougm case SA_PROP_OP_UPDATE: 31514327Sdougm value = scf_value_create( 31524327Sdougm scf_handle->handle); 31534327Sdougm ret = add_or_update(scf_handle, type, 31544327Sdougm value, entry, name, valstr); 31554327Sdougm break; 31563034Sdougm } 31573034Sdougm } 31584327Sdougm } else { 31594327Sdougm /* 31604327Sdougm * ZFS update. The calling function would have updated 31614327Sdougm * the internal XML structure. Just need to flag it as 31624327Sdougm * changed for ZFS. 31634327Sdougm */ 31644327Sdougm zfs_set_update((sa_share_t)group); 31654327Sdougm } 31663034Sdougm } 31673034Sdougm 31683034Sdougm if (name != NULL) 31694327Sdougm sa_free_attr_string(name); 31703034Sdougm if (valstr != NULL) 31714327Sdougm sa_free_attr_string(valstr); 31723034Sdougm else if (entry != NULL) 31734327Sdougm scf_entry_destroy(entry); 31743034Sdougm 31753034Sdougm if (ret == -1) 31764327Sdougm ret = SA_SYSTEM_ERR; 31773034Sdougm 31783034Sdougm return (ret); 31793034Sdougm } 31803034Sdougm 31813034Sdougm /* 31826007Sthurlow * sa_create_section(name, value) 31836007Sthurlow * 31846007Sthurlow * Create a new section with the specified name and extra data. 31856007Sthurlow */ 31866007Sthurlow 31876007Sthurlow sa_property_t 31886007Sthurlow sa_create_section(char *name, char *extra) 31896007Sthurlow { 31906007Sthurlow xmlNodePtr node; 31916007Sthurlow 31926007Sthurlow node = xmlNewNode(NULL, (xmlChar *)"section"); 31936007Sthurlow if (node != NULL) { 31946007Sthurlow if (name != NULL) 31956007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 31966007Sthurlow (xmlChar *)name); 31976007Sthurlow if (extra != NULL) 31986007Sthurlow (void) xmlSetProp(node, (xmlChar *)"extra", 31996007Sthurlow (xmlChar *)extra); 32006007Sthurlow } 32016007Sthurlow return ((sa_property_t)node); 32026007Sthurlow } 32036007Sthurlow 32046007Sthurlow void 32056007Sthurlow sa_set_section_attr(sa_property_t sect, char *name, char *value) 32066007Sthurlow { 32076007Sthurlow (void) xmlSetProp(sect, (xmlChar *)name, (xmlChar *)value); 32086007Sthurlow } 32096007Sthurlow 32106007Sthurlow /* 32116007Sthurlow * sa_create_property(section, name, value) 32123034Sdougm * 32133034Sdougm * Create a new property with the specified name and value. 32143034Sdougm */ 32153034Sdougm 32163034Sdougm sa_property_t 32173034Sdougm sa_create_property(char *name, char *value) 32183034Sdougm { 32193034Sdougm xmlNodePtr node; 32203034Sdougm 32213034Sdougm node = xmlNewNode(NULL, (xmlChar *)"option"); 32223034Sdougm if (node != NULL) { 32236007Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", (xmlChar *)name); 32246007Sthurlow (void) xmlSetProp(node, (xmlChar *)"value", (xmlChar *)value); 32253034Sdougm } 32263034Sdougm return ((sa_property_t)node); 32273034Sdougm } 32283034Sdougm 32293034Sdougm /* 32303034Sdougm * sa_add_property(object, property) 32313034Sdougm * 32323034Sdougm * Add the specified property to the object. Issue the appropriate 32333034Sdougm * transaction or mark a ZFS object as needing an update. 32343034Sdougm */ 32353034Sdougm 32363034Sdougm int 32373034Sdougm sa_add_property(void *object, sa_property_t property) 32383034Sdougm { 32393034Sdougm int ret = SA_OK; 32403034Sdougm sa_group_t parent; 32413034Sdougm sa_group_t group; 32423034Sdougm char *proto; 32436214Sdougm 32443034Sdougm if (property != NULL) { 32456271Sdougm sa_handle_t handle; 32466214Sdougm handle = sa_find_group_handle((sa_group_t)object); 32476271Sdougm /* It is legitimate to not find a handle */ 32486214Sdougm proto = sa_get_optionset_attr(object, "type"); 32496214Sdougm if ((ret = sa_valid_property(handle, object, proto, 32506214Sdougm property)) == SA_OK) { 32514327Sdougm property = (sa_property_t)xmlAddChild( 32524327Sdougm (xmlNodePtr)object, (xmlNodePtr)property); 32534327Sdougm } else { 32544327Sdougm if (proto != NULL) 32554327Sdougm sa_free_attr_string(proto); 32564327Sdougm return (ret); 32574327Sdougm } 32586214Sdougm if (proto != NULL) 32596214Sdougm sa_free_attr_string(proto); 32603034Sdougm } 32613034Sdougm 32623034Sdougm 32633034Sdougm parent = sa_get_parent_group(object); 32645331Samw if (!sa_is_persistent(parent)) 32654327Sdougm return (ret); 32665331Samw 32675331Samw if (sa_is_resource(parent)) { 32685331Samw /* 32695331Samw * Resources are children of share. Need to go up two 32705331Samw * levels to find the group but the parent needs to be 32715331Samw * the share at this point in order to get the "id". 32725331Samw */ 32735331Samw parent = sa_get_parent_group(parent); 32745331Samw group = sa_get_parent_group(parent); 32755331Samw } else if (sa_is_share(parent)) { 32765331Samw group = sa_get_parent_group(parent); 32775331Samw } else { 32785331Samw group = parent; 32793034Sdougm } 32803034Sdougm 32814327Sdougm if (property == NULL) { 32824327Sdougm ret = SA_NO_MEMORY; 32834327Sdougm } else { 32844327Sdougm char oname[SA_STRSIZE]; 32853034Sdougm 32864327Sdougm if (!is_zfs_group(group)) { 32874327Sdougm char *id = NULL; 32884327Sdougm sa_handle_impl_t impl_handle; 32894327Sdougm scfutilhandle_t *scf_handle; 32903910Sdougm 32914327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle( 32924327Sdougm group); 32934327Sdougm if (impl_handle == NULL || 32944327Sdougm impl_handle->scfhandle == NULL) 32954327Sdougm ret = SA_SYSTEM_ERR; 32964327Sdougm if (ret == SA_OK) { 32974327Sdougm scf_handle = impl_handle->scfhandle; 32984327Sdougm if (sa_is_share((sa_group_t)parent)) { 32994327Sdougm id = sa_get_share_attr( 33004327Sdougm (sa_share_t)parent, "id"); 33014327Sdougm } 33024327Sdougm if (scf_handle->trans == NULL) { 33034327Sdougm if (is_nodetype(object, "optionset")) { 33044327Sdougm (void) sa_optionset_name( 33054327Sdougm (sa_optionset_t)object, 33064327Sdougm oname, sizeof (oname), id); 33074327Sdougm } else { 33084327Sdougm (void) sa_security_name( 33094327Sdougm (sa_optionset_t)object, 33104327Sdougm oname, sizeof (oname), id); 33114327Sdougm } 33124327Sdougm ret = sa_start_transaction(scf_handle, 33134327Sdougm oname); 33144327Sdougm } 33154327Sdougm if (ret == SA_OK) { 33164327Sdougm char *name; 33174327Sdougm char *value; 33184327Sdougm name = sa_get_property_attr(property, 33194327Sdougm "type"); 33204327Sdougm value = sa_get_property_attr(property, 33214327Sdougm "value"); 33224327Sdougm if (name != NULL && value != NULL) { 33234327Sdougm if (scf_handle->scf_state == 33244327Sdougm SCH_STATE_INIT) { 33254327Sdougm ret = sa_set_property( 33264327Sdougm scf_handle, name, 33274327Sdougm value); 33284327Sdougm } 33294327Sdougm } else { 33304327Sdougm ret = SA_CONFIG_ERR; 33314327Sdougm } 33324327Sdougm if (name != NULL) 33334327Sdougm sa_free_attr_string( 33344327Sdougm name); 33354327Sdougm if (value != NULL) 33364327Sdougm sa_free_attr_string(value); 33374327Sdougm } 33384327Sdougm if (id != NULL) 33394327Sdougm sa_free_attr_string(id); 33404327Sdougm } 33414327Sdougm } else { 33424327Sdougm /* 33434327Sdougm * ZFS is a special case. We do want 33444327Sdougm * to allow editing property/security 33454327Sdougm * lists since we can have a better 33464327Sdougm * syntax and we also want to keep 33474327Sdougm * things consistent when possible. 33484327Sdougm * 33494327Sdougm * Right now, we defer until the 33504327Sdougm * sa_commit_properties so we can get 33514327Sdougm * them all at once. We do need to 33524327Sdougm * mark the share as "changed" 33534327Sdougm */ 33544327Sdougm zfs_set_update((sa_share_t)parent); 33553034Sdougm } 33563034Sdougm } 33573034Sdougm return (ret); 33583034Sdougm } 33593034Sdougm 33603034Sdougm /* 33613034Sdougm * sa_remove_property(property) 33623034Sdougm * 33633034Sdougm * Remove the specied property from its containing object. Update the 33643034Sdougm * repository as appropriate. 33653034Sdougm */ 33663034Sdougm 33673034Sdougm int 33683034Sdougm sa_remove_property(sa_property_t property) 33693034Sdougm { 33703034Sdougm int ret = SA_OK; 33713034Sdougm 33723034Sdougm if (property != NULL) { 33733034Sdougm sa_optionset_t optionset; 33743034Sdougm sa_group_t group; 33753034Sdougm optionset = sa_get_property_parent(property); 33763034Sdougm if (optionset != NULL) { 33774327Sdougm group = sa_get_optionset_parent(optionset); 33784327Sdougm if (group != NULL) { 33794327Sdougm ret = sa_set_prop_by_prop(optionset, group, 33804327Sdougm property, SA_PROP_OP_REMOVE); 33814327Sdougm } 33823034Sdougm } 33833034Sdougm xmlUnlinkNode((xmlNodePtr)property); 33843034Sdougm xmlFreeNode((xmlNodePtr)property); 33853034Sdougm } else { 33864327Sdougm ret = SA_NO_SUCH_PROP; 33873034Sdougm } 33883034Sdougm return (ret); 33893034Sdougm } 33903034Sdougm 33913034Sdougm /* 33923034Sdougm * sa_update_property(property, value) 33933034Sdougm * 33943034Sdougm * Update the specified property to the new value. If value is NULL, 33953034Sdougm * we currently treat this as a remove. 33963034Sdougm */ 33973034Sdougm 33983034Sdougm int 33993034Sdougm sa_update_property(sa_property_t property, char *value) 34003034Sdougm { 34013034Sdougm int ret = SA_OK; 34023034Sdougm if (value == NULL) { 34033034Sdougm return (sa_remove_property(property)); 34043034Sdougm } else { 34053034Sdougm sa_optionset_t optionset; 34063034Sdougm sa_group_t group; 34073034Sdougm set_node_attr((void *)property, "value", value); 34083034Sdougm optionset = sa_get_property_parent(property); 34093034Sdougm if (optionset != NULL) { 34104327Sdougm group = sa_get_optionset_parent(optionset); 34114327Sdougm if (group != NULL) { 34124327Sdougm ret = sa_set_prop_by_prop(optionset, group, 34134327Sdougm property, SA_PROP_OP_UPDATE); 34144327Sdougm } 34153034Sdougm } else { 34164327Sdougm ret = SA_NO_SUCH_PROP; 34173034Sdougm } 34183034Sdougm } 34193034Sdougm return (ret); 34203034Sdougm } 34213034Sdougm 34223034Sdougm /* 34236007Sthurlow * sa_get_protocol_section(propset, prop) 34246007Sthurlow * 34256007Sthurlow * Get the specified protocol specific section. These are global to 34266007Sthurlow * the protocol and not specific to a group or share. 34276007Sthurlow */ 34286007Sthurlow 34296007Sthurlow sa_protocol_properties_t 34306007Sthurlow sa_get_protocol_section(sa_protocol_properties_t propset, char *section) 34316007Sthurlow { 34326007Sthurlow xmlNodePtr node = (xmlNodePtr)propset; 34336007Sthurlow xmlChar *value = NULL; 34346007Sthurlow char *proto; 34356007Sthurlow 34366007Sthurlow proto = sa_get_optionset_attr(propset, "type"); 34378271SGordon.Ross@Sun.COM if ((sa_proto_get_featureset(proto) & SA_FEATURE_HAS_SECTIONS) == 0) { 34388271SGordon.Ross@Sun.COM if (proto != NULL) 34398271SGordon.Ross@Sun.COM sa_free_attr_string(proto); 34406007Sthurlow return (propset); 34418271SGordon.Ross@Sun.COM } 34426007Sthurlow 34436007Sthurlow for (node = node->children; node != NULL; 34446007Sthurlow node = node->next) { 34456007Sthurlow if (xmlStrcmp(node->name, (xmlChar *)"section") == 0) { 34466007Sthurlow if (section == NULL) 34476007Sthurlow break; 34486007Sthurlow value = xmlGetProp(node, (xmlChar *)"name"); 34496007Sthurlow if (value != NULL && 34506007Sthurlow xmlStrcasecmp(value, (xmlChar *)section) == 0) { 34516007Sthurlow break; 34526007Sthurlow } 34536007Sthurlow if (value != NULL) { 34546007Sthurlow xmlFree(value); 34556007Sthurlow value = NULL; 34566007Sthurlow } 34576007Sthurlow } 34586007Sthurlow } 34596007Sthurlow if (value != NULL) 34606007Sthurlow xmlFree(value); 34618271SGordon.Ross@Sun.COM if (proto != NULL) 34628271SGordon.Ross@Sun.COM sa_free_attr_string(proto); 34636007Sthurlow if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"section") != 0) { 34646007Sthurlow /* 34656007Sthurlow * avoid a non option node -- it is possible to be a 34666007Sthurlow * text node 34676007Sthurlow */ 34686007Sthurlow node = NULL; 34696007Sthurlow } 34706007Sthurlow return ((sa_protocol_properties_t)node); 34716007Sthurlow } 34726007Sthurlow 34736007Sthurlow /* 34746007Sthurlow * sa_get_next_protocol_section(prop, find) 34756007Sthurlow * 34766007Sthurlow * Get the next protocol specific section in the list. 34776007Sthurlow */ 34786007Sthurlow 34796007Sthurlow sa_property_t 34806007Sthurlow sa_get_next_protocol_section(sa_property_t prop, char *find) 34816007Sthurlow { 34826007Sthurlow xmlNodePtr node; 34836007Sthurlow xmlChar *value = NULL; 34846007Sthurlow char *proto; 34856007Sthurlow 34866007Sthurlow proto = sa_get_optionset_attr(prop, "type"); 34878271SGordon.Ross@Sun.COM if ((sa_proto_get_featureset(proto) & SA_FEATURE_HAS_SECTIONS) == 0) { 34888271SGordon.Ross@Sun.COM if (proto != NULL) 34898271SGordon.Ross@Sun.COM sa_free_attr_string(proto); 34906007Sthurlow return ((sa_property_t)NULL); 34918271SGordon.Ross@Sun.COM } 34926007Sthurlow 34936007Sthurlow for (node = ((xmlNodePtr)prop)->next; node != NULL; 34946007Sthurlow node = node->next) { 34956007Sthurlow if (xmlStrcmp(node->name, (xmlChar *)"section") == 0) { 34966007Sthurlow if (find == NULL) 34976007Sthurlow break; 34986007Sthurlow value = xmlGetProp(node, (xmlChar *)"name"); 34996007Sthurlow if (value != NULL && 35006007Sthurlow xmlStrcasecmp(value, (xmlChar *)find) == 0) { 35016007Sthurlow break; 35026007Sthurlow } 35036007Sthurlow if (value != NULL) { 35046007Sthurlow xmlFree(value); 35056007Sthurlow value = NULL; 35066007Sthurlow } 35076007Sthurlow 35086007Sthurlow } 35096007Sthurlow } 35106007Sthurlow if (value != NULL) 35116007Sthurlow xmlFree(value); 35128271SGordon.Ross@Sun.COM if (proto != NULL) 35138271SGordon.Ross@Sun.COM sa_free_attr_string(proto); 35146007Sthurlow return ((sa_property_t)node); 35156007Sthurlow } 35166007Sthurlow 35176007Sthurlow /* 35183034Sdougm * sa_get_protocol_property(propset, prop) 35193034Sdougm * 35203034Sdougm * Get the specified protocol specific property. These are global to 35213034Sdougm * the protocol and not specific to a group or share. 35223034Sdougm */ 35233034Sdougm 35243034Sdougm sa_property_t 35253034Sdougm sa_get_protocol_property(sa_protocol_properties_t propset, char *prop) 35263034Sdougm { 35273034Sdougm xmlNodePtr node = (xmlNodePtr)propset; 35283034Sdougm xmlChar *value = NULL; 35293034Sdougm 35306007Sthurlow if (propset == NULL) 35316007Sthurlow return (NULL); 35326007Sthurlow 35333034Sdougm for (node = node->children; node != NULL; 35344327Sdougm node = node->next) { 35354327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 35364327Sdougm if (prop == NULL) 35374327Sdougm break; 35384327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 35394327Sdougm if (value != NULL && 35404327Sdougm xmlStrcasecmp(value, (xmlChar *)prop) == 0) { 35414327Sdougm break; 35424327Sdougm } 35434327Sdougm if (value != NULL) { 35444327Sdougm xmlFree(value); 35454327Sdougm value = NULL; 35464327Sdougm } 35473034Sdougm } 35483034Sdougm } 35493034Sdougm if (value != NULL) 35503034Sdougm xmlFree(value); 35513034Sdougm if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"option") != 0) { 35524327Sdougm /* 35534327Sdougm * avoid a non option node -- it is possible to be a 35544327Sdougm * text node 35554327Sdougm */ 35564327Sdougm node = NULL; 35573034Sdougm } 35583034Sdougm return ((sa_property_t)node); 35593034Sdougm } 35603034Sdougm 35613034Sdougm /* 35623034Sdougm * sa_get_next_protocol_property(prop) 35633034Sdougm * 35643034Sdougm * Get the next protocol specific property in the list. 35653034Sdougm */ 35663034Sdougm 35673034Sdougm sa_property_t 35686007Sthurlow sa_get_next_protocol_property(sa_property_t prop, char *find) 35693034Sdougm { 35703034Sdougm xmlNodePtr node; 35716007Sthurlow xmlChar *value = NULL; 35723034Sdougm 35733034Sdougm for (node = ((xmlNodePtr)prop)->next; node != NULL; 35744327Sdougm node = node->next) { 35753034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 35766007Sthurlow if (find == NULL) 35776007Sthurlow break; 35786007Sthurlow value = xmlGetProp(node, (xmlChar *)"type"); 35796007Sthurlow if (value != NULL && 35806007Sthurlow xmlStrcasecmp(value, (xmlChar *)find) == 0) { 35816007Sthurlow break; 35826007Sthurlow } 35836007Sthurlow if (value != NULL) { 35846007Sthurlow xmlFree(value); 35856007Sthurlow value = NULL; 35866007Sthurlow } 35876007Sthurlow 35883034Sdougm } 35893034Sdougm } 35906007Sthurlow if (value != NULL) 35916007Sthurlow xmlFree(value); 35923034Sdougm return ((sa_property_t)node); 35933034Sdougm } 35943034Sdougm 35953034Sdougm /* 35963034Sdougm * sa_set_protocol_property(prop, value) 35973034Sdougm * 35983034Sdougm * Set the specified property to have the new value. The protocol 35993034Sdougm * specific plugin will then be called to update the property. 36003034Sdougm */ 36013034Sdougm 36023034Sdougm int 36036007Sthurlow sa_set_protocol_property(sa_property_t prop, char *section, char *value) 36043034Sdougm { 36053034Sdougm sa_protocol_properties_t propset; 36063034Sdougm char *proto; 36073034Sdougm int ret = SA_INVALID_PROTOCOL; 36083034Sdougm 36093034Sdougm propset = ((xmlNodePtr)prop)->parent; 36103034Sdougm if (propset != NULL) { 36114327Sdougm proto = sa_get_optionset_attr(propset, "type"); 36124327Sdougm if (proto != NULL) { 36136007Sthurlow if (section != NULL) 36146007Sthurlow set_node_attr((xmlNodePtr)prop, "section", 36156007Sthurlow section); 36164327Sdougm set_node_attr((xmlNodePtr)prop, "value", value); 36174327Sdougm ret = sa_proto_set_property(proto, prop); 36184327Sdougm sa_free_attr_string(proto); 36194327Sdougm } 36203034Sdougm } 36213034Sdougm return (ret); 36223034Sdougm } 36233034Sdougm 36243034Sdougm /* 36253034Sdougm * sa_add_protocol_property(propset, prop) 36263034Sdougm * 36275331Samw * Add a new property to the protocol specific property set. 36283034Sdougm */ 36293034Sdougm 36303034Sdougm int 36313034Sdougm sa_add_protocol_property(sa_protocol_properties_t propset, sa_property_t prop) 36323034Sdougm { 36333034Sdougm xmlNodePtr node; 36343034Sdougm 36353034Sdougm /* should check for legitimacy */ 36363034Sdougm node = xmlAddChild((xmlNodePtr)propset, (xmlNodePtr)prop); 36373034Sdougm if (node != NULL) 36384327Sdougm return (SA_OK); 36393034Sdougm return (SA_NO_MEMORY); 36403034Sdougm } 36413034Sdougm 36423034Sdougm /* 36433034Sdougm * sa_create_protocol_properties(proto) 36443034Sdougm * 36455331Samw * Create a protocol specific property set. 36463034Sdougm */ 36473034Sdougm 36483034Sdougm sa_protocol_properties_t 36493034Sdougm sa_create_protocol_properties(char *proto) 36503034Sdougm { 36513034Sdougm xmlNodePtr node; 36524327Sdougm 36533034Sdougm node = xmlNewNode(NULL, (xmlChar *)"propertyset"); 36544327Sdougm if (node != NULL) 36556007Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto); 36563034Sdougm return (node); 36573034Sdougm } 36585331Samw 36595331Samw /* 36605331Samw * sa_get_share_resource(share, resource) 36615331Samw * 36625331Samw * Get the named resource from the share, if it exists. If resource is 36635331Samw * NULL, get the first resource. 36645331Samw */ 36655331Samw 36665331Samw sa_resource_t 36675331Samw sa_get_share_resource(sa_share_t share, char *resource) 36685331Samw { 36695331Samw xmlNodePtr node = NULL; 36705331Samw xmlChar *name; 36715331Samw 36725331Samw if (share != NULL) { 36735331Samw for (node = ((xmlNodePtr)share)->children; node != NULL; 36745331Samw node = node->next) { 36755331Samw if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0) { 36765331Samw if (resource == NULL) { 36775331Samw /* 36785331Samw * We are looking for the first 36795331Samw * resource node and not a names 36805331Samw * resource. 36815331Samw */ 36825331Samw break; 36835331Samw } else { 36845331Samw /* is it the correct share? */ 36855331Samw name = xmlGetProp(node, 36865331Samw (xmlChar *)"name"); 36875331Samw if (name != NULL && 36885331Samw xmlStrcasecmp(name, 36895331Samw (xmlChar *)resource) == 0) { 36905331Samw xmlFree(name); 36915331Samw break; 36925331Samw } 36935331Samw xmlFree(name); 36945331Samw } 36955331Samw } 36965331Samw } 36975331Samw } 36985331Samw return ((sa_resource_t)node); 36995331Samw } 37005331Samw 37015331Samw /* 37025331Samw * sa_get_next_resource(resource) 37035331Samw * Return the next share following the specified share 37045331Samw * from the internal list of shares. Returns NULL if there 37055331Samw * are no more shares. The list is relative to the same 37065331Samw * group. 37075331Samw */ 37085331Samw sa_share_t 37095331Samw sa_get_next_resource(sa_resource_t resource) 37105331Samw { 37115331Samw xmlNodePtr node = NULL; 37125331Samw 37135331Samw if (resource != NULL) { 37145331Samw for (node = ((xmlNodePtr)resource)->next; node != NULL; 37155331Samw node = node->next) { 37165331Samw if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0) 37175331Samw break; 37185331Samw } 37195331Samw } 37205331Samw return ((sa_share_t)node); 37215331Samw } 37225331Samw 37235331Samw /* 37245331Samw * _sa_get_next_resource_index(share) 37255331Samw * 37265331Samw * get the next resource index number (one greater then current largest) 37275331Samw */ 37285331Samw 37295331Samw static int 37305331Samw _sa_get_next_resource_index(sa_share_t share) 37315331Samw { 37325331Samw sa_resource_t resource; 37335331Samw int index = 0; 37345331Samw char *id; 37355331Samw 37365331Samw for (resource = sa_get_share_resource(share, NULL); 37375331Samw resource != NULL; 37385331Samw resource = sa_get_next_resource(resource)) { 37395331Samw id = get_node_attr((void *)resource, "id"); 37405331Samw if (id != NULL) { 37415331Samw int val; 37425331Samw val = atoi(id); 37435331Samw if (val > index) 37445331Samw index = val; 37455331Samw sa_free_attr_string(id); 37465331Samw } 37475331Samw } 37485331Samw return (index + 1); 37495331Samw } 37505331Samw 37515331Samw 37525331Samw /* 37535331Samw * sa_add_resource(share, resource, persist, &err) 37545331Samw * 37555331Samw * Adds a new resource name associated with share. The resource name 37565331Samw * must be unique in the system and will be case insensitive (eventually). 37575331Samw */ 37585331Samw 37595331Samw sa_resource_t 37605331Samw sa_add_resource(sa_share_t share, char *resource, int persist, int *error) 37615331Samw { 37625331Samw xmlNodePtr node; 37635331Samw int err = SA_OK; 37645331Samw sa_resource_t res; 37655331Samw sa_group_t group; 37665331Samw sa_handle_t handle; 37675331Samw char istring[8]; /* just big enough for an integer value */ 37685331Samw int index; 37695331Samw 37705331Samw group = sa_get_parent_group(share); 37715331Samw handle = sa_find_group_handle(group); 37725331Samw res = sa_find_resource(handle, resource); 37735331Samw if (res != NULL) { 37745331Samw err = SA_DUPLICATE_NAME; 37755331Samw res = NULL; 37765331Samw } else { 37775331Samw node = xmlNewChild((xmlNodePtr)share, NULL, 37785331Samw (xmlChar *)"resource", NULL); 37795331Samw if (node != NULL) { 37806007Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 37815331Samw (xmlChar *)resource); 37826007Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", persist ? 37835331Samw (xmlChar *)"persist" : (xmlChar *)"transient"); 37845331Samw if (persist != SA_SHARE_TRANSIENT) { 37855331Samw index = _sa_get_next_resource_index(share); 37865331Samw (void) snprintf(istring, sizeof (istring), "%d", 37875331Samw index); 37886007Sthurlow (void) xmlSetProp(node, (xmlChar *)"id", 37895331Samw (xmlChar *)istring); 37907483SDoug.McCallum@Sun.COM 37917483SDoug.McCallum@Sun.COM if (!sa_is_persistent((sa_group_t)share)) 37927483SDoug.McCallum@Sun.COM goto done; 37937483SDoug.McCallum@Sun.COM 37947483SDoug.McCallum@Sun.COM if (!sa_group_is_zfs(group)) { 37955331Samw /* ZFS doesn't use resource names */ 37965331Samw sa_handle_impl_t ihandle; 37977483SDoug.McCallum@Sun.COM 37985331Samw ihandle = (sa_handle_impl_t) 37995331Samw sa_find_group_handle( 38005331Samw group); 38015331Samw if (ihandle != NULL) 38025331Samw err = sa_commit_share( 38035331Samw ihandle->scfhandle, group, 38045331Samw share); 38055331Samw else 38065331Samw err = SA_SYSTEM_ERR; 38077483SDoug.McCallum@Sun.COM } else { 38087483SDoug.McCallum@Sun.COM err = sa_zfs_update((sa_share_t)group); 38095331Samw } 38105331Samw } 38115331Samw } 38125331Samw } 38137483SDoug.McCallum@Sun.COM done: 38145331Samw if (error != NULL) 38155331Samw *error = err; 38165331Samw return ((sa_resource_t)node); 38175331Samw } 38185331Samw 38195331Samw /* 38205331Samw * sa_remove_resource(resource) 38215331Samw * 38225331Samw * Remove the resource name from the share (and the system) 38235331Samw */ 38245331Samw 38255331Samw int 38265331Samw sa_remove_resource(sa_resource_t resource) 38275331Samw { 38285331Samw sa_share_t share; 38295331Samw sa_group_t group; 38305331Samw char *type; 38315331Samw int ret = SA_OK; 38327483SDoug.McCallum@Sun.COM boolean_t transient = B_FALSE; 38335521Sas200622 sa_optionset_t opt; 38345331Samw 38355331Samw share = sa_get_resource_parent(resource); 38365331Samw type = sa_get_share_attr(share, "type"); 38375331Samw group = sa_get_parent_group(share); 38385331Samw 38395331Samw 38405331Samw if (type != NULL) { 38415331Samw if (strcmp(type, "persist") != 0) 38427483SDoug.McCallum@Sun.COM transient = B_TRUE; 38435331Samw sa_free_attr_string(type); 38445331Samw } 38455331Samw 38465521Sas200622 /* Disable the resource for all protocols. */ 38475521Sas200622 (void) sa_disable_resource(resource, NULL); 38485521Sas200622 38495521Sas200622 /* Remove any optionsets from the resource. */ 38505521Sas200622 for (opt = sa_get_optionset(resource, NULL); 38515521Sas200622 opt != NULL; 38525521Sas200622 opt = sa_get_next_optionset(opt)) 38535521Sas200622 (void) sa_destroy_optionset(opt); 38545521Sas200622 38555331Samw /* Remove from the share */ 38565331Samw xmlUnlinkNode((xmlNode *)resource); 38575331Samw xmlFreeNode((xmlNode *)resource); 38585331Samw 38595331Samw /* only do SMF action if permanent and not ZFS */ 38607483SDoug.McCallum@Sun.COM if (transient) 38617483SDoug.McCallum@Sun.COM return (ret); 38627483SDoug.McCallum@Sun.COM 38637483SDoug.McCallum@Sun.COM if (!sa_group_is_zfs(group)) { 38645331Samw sa_handle_impl_t ihandle; 38655331Samw ihandle = (sa_handle_impl_t)sa_find_group_handle(group); 38665331Samw if (ihandle != NULL) 38675331Samw ret = sa_commit_share(ihandle->scfhandle, group, share); 38685331Samw else 38695331Samw ret = SA_SYSTEM_ERR; 38707483SDoug.McCallum@Sun.COM } else { 38717483SDoug.McCallum@Sun.COM ret = sa_zfs_update((sa_share_t)group); 38725331Samw } 38738845Samw@Sun.COM 38745331Samw return (ret); 38755331Samw } 38765331Samw 38775331Samw /* 38788845Samw@Sun.COM * proto_rename_resource(handle, group, resource, newname) 38795331Samw * 38805331Samw * Helper function for sa_rename_resource that notifies the protocol 38815331Samw * of a resource name change prior to a config repository update. 38825331Samw */ 38835331Samw static int 38845331Samw proto_rename_resource(sa_handle_t handle, sa_group_t group, 38855331Samw sa_resource_t resource, char *newname) 38865331Samw { 38875331Samw sa_optionset_t optionset; 38885331Samw int ret = SA_OK; 38895331Samw int err; 38905331Samw 38915331Samw for (optionset = sa_get_optionset(group, NULL); 38925331Samw optionset != NULL; 38935331Samw optionset = sa_get_next_optionset(optionset)) { 38945331Samw char *type; 38955331Samw type = sa_get_optionset_attr(optionset, "type"); 38965331Samw if (type != NULL) { 38975331Samw err = sa_proto_rename_resource(handle, type, resource, 38985331Samw newname); 38995331Samw if (err != SA_OK) 39005331Samw ret = err; 39015331Samw sa_free_attr_string(type); 39025331Samw } 39035331Samw } 39045331Samw return (ret); 39055331Samw } 39065331Samw 39075331Samw /* 39085331Samw * sa_rename_resource(resource, newname) 39095331Samw * 39105331Samw * Rename the resource to the new name, if it is unique. 39115331Samw */ 39125331Samw 39135331Samw int 39145331Samw sa_rename_resource(sa_resource_t resource, char *newname) 39155331Samw { 39165331Samw sa_share_t share; 39175331Samw sa_group_t group = NULL; 39185331Samw sa_resource_t target; 39195331Samw int ret = SA_CONFIG_ERR; 39205331Samw sa_handle_t handle = NULL; 39215331Samw 39225331Samw share = sa_get_resource_parent(resource); 39235331Samw if (share == NULL) 39245331Samw return (ret); 39255331Samw 39265331Samw group = sa_get_parent_group(share); 39275331Samw if (group == NULL) 39285331Samw return (ret); 39295331Samw 39305331Samw handle = (sa_handle_impl_t)sa_find_group_handle(group); 39315331Samw if (handle == NULL) 39325331Samw return (ret); 39335331Samw 39345331Samw target = sa_find_resource(handle, newname); 39355331Samw if (target != NULL) { 39365331Samw ret = SA_DUPLICATE_NAME; 39375331Samw } else { 39385331Samw /* 39395331Samw * Everything appears to be valid at this 39405331Samw * point. Change the name of the active share and then 39415331Samw * update the share in the appropriate repository. 39425331Samw */ 39435331Samw ret = proto_rename_resource(handle, group, resource, newname); 39445331Samw set_node_attr(resource, "name", newname); 39457483SDoug.McCallum@Sun.COM 39467483SDoug.McCallum@Sun.COM if (!sa_is_persistent((sa_group_t)share)) 39477483SDoug.McCallum@Sun.COM return (ret); 39487483SDoug.McCallum@Sun.COM 39497483SDoug.McCallum@Sun.COM if (!sa_group_is_zfs(group)) { 39505331Samw sa_handle_impl_t ihandle = (sa_handle_impl_t)handle; 39515331Samw ret = sa_commit_share(ihandle->scfhandle, group, 39525331Samw share); 39537483SDoug.McCallum@Sun.COM } else { 39547483SDoug.McCallum@Sun.COM ret = sa_zfs_update((sa_share_t)group); 39555331Samw } 39565331Samw } 39575331Samw return (ret); 39585331Samw } 39595331Samw 39605331Samw /* 39615331Samw * sa_get_resource_attr(resource, tag) 39625331Samw * 39635331Samw * Get the named attribute of the resource. "name" and "id" are 39645331Samw * currently defined. NULL if tag not defined. 39655331Samw */ 39665331Samw 39675331Samw char * 39685331Samw sa_get_resource_attr(sa_resource_t resource, char *tag) 39695331Samw { 39705331Samw return (get_node_attr((void *)resource, tag)); 39715331Samw } 39725331Samw 39735331Samw /* 39745331Samw * sa_set_resource_attr(resource, tag, value) 39755331Samw * 39765331Samw * Get the named attribute of the resource. "name" and "id" are 39775331Samw * currently defined. NULL if tag not defined. Currently we don't do 39785331Samw * much, but additional checking may be needed in the future. 39795331Samw */ 39805331Samw 39815331Samw int 39825331Samw sa_set_resource_attr(sa_resource_t resource, char *tag, char *value) 39835331Samw { 39845331Samw set_node_attr((void *)resource, tag, value); 39855331Samw return (SA_OK); 39865331Samw } 39875331Samw 39885331Samw /* 39895331Samw * sa_get_resource_parent(resource_t) 39905331Samw * 39915331Samw * Returns the share associated with the resource. 39925331Samw */ 39935331Samw 39945331Samw sa_share_t 39955331Samw sa_get_resource_parent(sa_resource_t resource) 39965331Samw { 39975331Samw sa_share_t share = NULL; 39985331Samw 39995331Samw if (resource != NULL) 40005331Samw share = (sa_share_t)((xmlNodePtr)resource)->parent; 40015331Samw return (share); 40025331Samw } 40035331Samw 40045331Samw /* 40055331Samw * find_resource(group, name) 40065331Samw * 40075331Samw * Find the resource within the group. 40085331Samw */ 40095331Samw 40105331Samw static sa_resource_t 40115331Samw find_resource(sa_group_t group, char *resname) 40125331Samw { 40135331Samw sa_share_t share; 40145331Samw sa_resource_t resource = NULL; 40155331Samw char *name; 40165331Samw 40175331Samw /* Iterate over all the shares and resources in the group. */ 40185331Samw for (share = sa_get_share(group, NULL); 40195331Samw share != NULL && resource == NULL; 40205331Samw share = sa_get_next_share(share)) { 40215331Samw for (resource = sa_get_share_resource(share, NULL); 40225331Samw resource != NULL; 40235331Samw resource = sa_get_next_resource(resource)) { 40245331Samw name = sa_get_resource_attr(resource, "name"); 40255331Samw if (name != NULL && xmlStrcasecmp((xmlChar*)name, 40265331Samw (xmlChar*)resname) == 0) { 40275331Samw sa_free_attr_string(name); 40285331Samw break; 40295331Samw } 40305331Samw if (name != NULL) { 40315331Samw sa_free_attr_string(name); 40325331Samw } 40335331Samw } 40345331Samw } 40355331Samw return (resource); 40365331Samw } 40375331Samw 40385331Samw /* 40395331Samw * sa_find_resource(name) 40405331Samw * 40415331Samw * Find the named resource in the system. 40425331Samw */ 40435331Samw 40445331Samw sa_resource_t 40455331Samw sa_find_resource(sa_handle_t handle, char *name) 40465331Samw { 40475331Samw sa_group_t group; 40485331Samw sa_group_t zgroup; 40495331Samw sa_resource_t resource = NULL; 40505331Samw 40515331Samw /* 40525331Samw * Iterate over all groups and zfs subgroups and check for 40535331Samw * resource name in them. 40545331Samw */ 40555331Samw for (group = sa_get_group(handle, NULL); group != NULL; 40565331Samw group = sa_get_next_group(group)) { 40575331Samw 40585331Samw if (is_zfs_group(group)) { 40595331Samw for (zgroup = 40605331Samw (sa_group_t)_sa_get_child_node((xmlNodePtr)group, 40615331Samw (xmlChar *)"group"); 40625331Samw zgroup != NULL && resource == NULL; 40635331Samw zgroup = sa_get_next_group(zgroup)) { 40645331Samw resource = find_resource(zgroup, name); 40655331Samw } 40665331Samw } else { 40675331Samw resource = find_resource(group, name); 40685331Samw } 40695331Samw if (resource != NULL) 40705331Samw break; 40715331Samw } 40725331Samw return (resource); 40735331Samw } 40745331Samw 40755331Samw /* 40765331Samw * sa_get_resource(group, resource) 40775331Samw * 40785331Samw * Search all the shares in the specified group for a share with a 40795331Samw * resource name matching the one specified. 40805331Samw * 40815331Samw * In the future, it may be advantageous to allow group to be NULL and 40825331Samw * search all groups but that isn't needed at present. 40835331Samw */ 40845331Samw 40855331Samw sa_resource_t 40865331Samw sa_get_resource(sa_group_t group, char *resource) 40875331Samw { 40885331Samw sa_share_t share = NULL; 40895331Samw sa_resource_t res = NULL; 40905331Samw 40915331Samw if (resource != NULL) { 40925331Samw for (share = sa_get_share(group, NULL); 40935331Samw share != NULL && res == NULL; 40945331Samw share = sa_get_next_share(share)) { 40955331Samw res = sa_get_share_resource(share, resource); 40965331Samw } 40975331Samw } 40985331Samw return (res); 40995331Samw } 41005331Samw 41015331Samw /* 41026270Sdougm * get_protocol_list(optionset, object) 41036270Sdougm * 41046270Sdougm * Get the protocol optionset list for the object and add them as 41056270Sdougm * properties to optionset. 41066270Sdougm */ 41076270Sdougm static int 41086270Sdougm get_protocol_list(sa_optionset_t optionset, void *object) 41096270Sdougm { 41106270Sdougm sa_property_t prop; 41116270Sdougm sa_optionset_t opts; 41126270Sdougm int ret = SA_OK; 41136270Sdougm 41146270Sdougm for (opts = sa_get_optionset(object, NULL); 41156270Sdougm opts != NULL; 41166270Sdougm opts = sa_get_next_optionset(opts)) { 41176270Sdougm char *type; 41186270Sdougm type = sa_get_optionset_attr(opts, "type"); 41196270Sdougm /* 41206270Sdougm * It is possible to have a non-protocol optionset. We 41216270Sdougm * skip any of those found. 41226270Sdougm */ 41236270Sdougm if (type == NULL) 41246270Sdougm continue; 41256270Sdougm prop = sa_create_property(type, "true"); 41266270Sdougm sa_free_attr_string(type); 41276270Sdougm if (prop != NULL) 41286270Sdougm prop = (sa_property_t)xmlAddChild((xmlNodePtr)optionset, 41296270Sdougm (xmlNodePtr)prop); 41306270Sdougm /* If prop is NULL, don't bother continuing */ 41316270Sdougm if (prop == NULL) { 41326270Sdougm ret = SA_NO_MEMORY; 41336270Sdougm break; 41346270Sdougm } 41356270Sdougm } 41366270Sdougm return (ret); 41376270Sdougm } 41386270Sdougm 41396270Sdougm /* 41406270Sdougm * sa_free_protoset(optionset) 41416270Sdougm * 41426270Sdougm * Free the protocol property optionset. 41436270Sdougm */ 41446270Sdougm static void 41456270Sdougm sa_free_protoset(sa_optionset_t optionset) 41466270Sdougm { 41476270Sdougm if (optionset != NULL) { 41486270Sdougm xmlUnlinkNode((xmlNodePtr) optionset); 41496270Sdougm xmlFreeNode((xmlNodePtr) optionset); 41506270Sdougm } 41516270Sdougm } 41526270Sdougm 41536270Sdougm /* 41546270Sdougm * sa_optionset_t sa_get_active_protocols(object) 41556270Sdougm * 41566270Sdougm * Return a list of the protocols that are active for the object. 41576270Sdougm * This is currently an internal helper function, but could be 41586270Sdougm * made visible if there is enough demand for it. 41596270Sdougm * 41606270Sdougm * The function finds the parent group and extracts the protocol 41616270Sdougm * optionsets creating a new optionset with the protocols as properties. 41626270Sdougm * 41636270Sdougm * The caller must free the returned optionset. 41646270Sdougm */ 41656270Sdougm 41666270Sdougm static sa_optionset_t 41676270Sdougm sa_get_active_protocols(void *object) 41686270Sdougm { 41696270Sdougm sa_optionset_t options; 41706270Sdougm sa_share_t share = NULL; 41716270Sdougm sa_group_t group = NULL; 41726270Sdougm sa_resource_t resource = NULL; 41736270Sdougm int ret = SA_OK; 41746270Sdougm 41756270Sdougm if (object == NULL) 41766270Sdougm return (NULL); 41776270Sdougm options = (sa_optionset_t)xmlNewNode(NULL, (xmlChar *)"optionset"); 41786270Sdougm if (options == NULL) 41796270Sdougm return (NULL); 41806270Sdougm 41816270Sdougm /* 41826270Sdougm * Find the objects up the tree that might have protocols 41836270Sdougm * enabled on them. 41846270Sdougm */ 41856270Sdougm if (sa_is_resource(object)) { 41866270Sdougm resource = (sa_resource_t)object; 41876270Sdougm share = sa_get_resource_parent(resource); 41886270Sdougm group = sa_get_parent_group(share); 41896270Sdougm } else if (sa_is_share(object)) { 41906270Sdougm share = (sa_share_t)object; 41916270Sdougm group = sa_get_parent_group(share); 41926270Sdougm } else { 41936270Sdougm group = (sa_group_t)group; 41946270Sdougm } 41956270Sdougm if (resource != NULL) 41966270Sdougm ret = get_protocol_list(options, resource); 41976270Sdougm if (ret == SA_OK && share != NULL) 41986270Sdougm ret = get_protocol_list(options, share); 41996270Sdougm if (ret == SA_OK && group != NULL) 42006270Sdougm ret = get_protocol_list(options, group); 42016270Sdougm 42026270Sdougm /* 42036270Sdougm * If there was an error, we won't have a complete list so 42046270Sdougm * abandon everything. The caller will have to deal with the 42056270Sdougm * issue. 42066270Sdougm */ 42076270Sdougm if (ret != SA_OK) { 42086270Sdougm sa_free_protoset(options); 42096270Sdougm options = NULL; 42106270Sdougm } 42116270Sdougm return (options); 42126270Sdougm } 42136270Sdougm 42146270Sdougm /* 42155331Samw * sa_enable_resource, protocol) 42165331Samw * Disable the specified share to the specified protocol. 42175331Samw * If protocol is NULL, then all protocols. 42185331Samw */ 42195331Samw int 42205331Samw sa_enable_resource(sa_resource_t resource, char *protocol) 42215331Samw { 42225331Samw int ret = SA_OK; 42235331Samw 42245331Samw if (protocol != NULL) { 42255331Samw ret = sa_proto_share_resource(protocol, resource); 42265331Samw } else { 42276270Sdougm sa_optionset_t protoset; 42286270Sdougm sa_property_t prop; 42296270Sdougm char *proto; 42306270Sdougm int err; 42316270Sdougm 42325331Samw /* need to do all protocols */ 42336270Sdougm protoset = sa_get_active_protocols(resource); 42346270Sdougm if (protoset == NULL) 42356270Sdougm return (SA_NO_MEMORY); 42366270Sdougm for (prop = sa_get_property(protoset, NULL); 42376270Sdougm prop != NULL; 42386270Sdougm prop = sa_get_next_property(prop)) { 42396270Sdougm proto = sa_get_property_attr(prop, "type"); 42406270Sdougm if (proto == NULL) { 42416270Sdougm ret = SA_NO_MEMORY; 42426270Sdougm continue; 42435331Samw } 42446270Sdougm err = sa_proto_share_resource(proto, resource); 42456270Sdougm if (err != SA_OK) 42466270Sdougm ret = err; 42476270Sdougm sa_free_attr_string(proto); 42485331Samw } 42496270Sdougm sa_free_protoset(protoset); 42505331Samw } 42515331Samw if (ret == SA_OK) 42525331Samw (void) sa_set_resource_attr(resource, "shared", NULL); 42535331Samw 42545331Samw return (ret); 42555331Samw } 42565331Samw 42575331Samw /* 42585331Samw * sa_disable_resource(resource, protocol) 42595331Samw * 42605331Samw * Disable the specified share for the specified protocol. If 42615331Samw * protocol is NULL, then all protocols. If the underlying 42625331Samw * protocol doesn't implement disable at the resource level, we 42635331Samw * disable at the share level. 42645331Samw */ 42655331Samw int 42665331Samw sa_disable_resource(sa_resource_t resource, char *protocol) 42675331Samw { 42685331Samw int ret = SA_OK; 42695331Samw 42705331Samw if (protocol != NULL) { 42715331Samw ret = sa_proto_unshare_resource(protocol, resource); 42725331Samw if (ret == SA_NOT_IMPLEMENTED) { 42735331Samw sa_share_t parent; 42745331Samw /* 42755331Samw * The protocol doesn't implement unshare 42765331Samw * resource. That implies that resource names are 42775331Samw * simple aliases for this protocol so we need to 42785331Samw * unshare the share. 42795331Samw */ 42805331Samw parent = sa_get_resource_parent(resource); 42815331Samw if (parent != NULL) 42825331Samw ret = sa_disable_share(parent, protocol); 42835331Samw else 42845331Samw ret = SA_CONFIG_ERR; 42855331Samw } 42865331Samw } else { 42876270Sdougm sa_optionset_t protoset; 42886270Sdougm sa_property_t prop; 42896270Sdougm char *proto; 42906270Sdougm int err; 42916270Sdougm 42925331Samw /* need to do all protocols */ 42936270Sdougm protoset = sa_get_active_protocols(resource); 42946270Sdougm if (protoset == NULL) 42956270Sdougm return (SA_NO_MEMORY); 42966270Sdougm for (prop = sa_get_property(protoset, NULL); 42976270Sdougm prop != NULL; 42986270Sdougm prop = sa_get_next_property(prop)) { 42996270Sdougm proto = sa_get_property_attr(prop, "type"); 43006270Sdougm if (proto == NULL) { 43016270Sdougm ret = SA_NO_MEMORY; 43026270Sdougm continue; 43035331Samw } 43046270Sdougm err = sa_proto_unshare_resource(proto, resource); 43056270Sdougm if (err == SA_NOT_SUPPORTED) { 43066270Sdougm sa_share_t parent; 43076270Sdougm parent = sa_get_resource_parent(resource); 43086270Sdougm if (parent != NULL) 43096270Sdougm err = sa_disable_share(parent, proto); 43106270Sdougm else 43116270Sdougm err = SA_CONFIG_ERR; 43126270Sdougm } 43136270Sdougm if (err != SA_OK) 43146270Sdougm ret = err; 43156270Sdougm sa_free_attr_string(proto); 43165331Samw } 43176270Sdougm sa_free_protoset(protoset); 43185331Samw } 43195331Samw if (ret == SA_OK) 43205331Samw (void) sa_set_resource_attr(resource, "shared", NULL); 43215331Samw 43225331Samw return (ret); 43235331Samw } 43245331Samw 43255331Samw /* 43265331Samw * sa_set_resource_description(resource, content) 43275331Samw * 43285331Samw * Set the description of share to content. 43295331Samw */ 43305331Samw 43315331Samw int 43325331Samw sa_set_resource_description(sa_resource_t resource, char *content) 43335331Samw { 43345331Samw xmlNodePtr node; 43355331Samw sa_group_t group; 43365331Samw sa_share_t share; 43375331Samw int ret = SA_OK; 43385331Samw 43395331Samw for (node = ((xmlNodePtr)resource)->children; 43405331Samw node != NULL; 43415331Samw node = node->next) { 43425331Samw if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 43435331Samw break; 43445331Samw } 43455331Samw } 43465331Samw 43475331Samw /* no existing description but want to add */ 43485331Samw if (node == NULL && content != NULL) { 43495331Samw /* add a description */ 43505331Samw node = _sa_set_share_description(resource, content); 43515331Samw } else if (node != NULL && content != NULL) { 43525331Samw /* update a description */ 43535331Samw xmlNodeSetContent(node, (xmlChar *)content); 43545331Samw } else if (node != NULL && content == NULL) { 43555331Samw /* remove an existing description */ 43565331Samw xmlUnlinkNode(node); 43575331Samw xmlFreeNode(node); 43585331Samw } 4359*12508Samw@Sun.COM 43605331Samw share = sa_get_resource_parent(resource); 43615331Samw group = sa_get_parent_group(share); 4362*12508Samw@Sun.COM if (group != NULL && 4363*12508Samw@Sun.COM sa_is_persistent(share) && (!sa_group_is_zfs(group))) { 43645331Samw sa_handle_impl_t impl_handle; 43655331Samw impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 43665331Samw if (impl_handle != NULL) 43675331Samw ret = sa_commit_share(impl_handle->scfhandle, 43685331Samw group, share); 43695331Samw else 43705331Samw ret = SA_SYSTEM_ERR; 43715331Samw } 43725331Samw return (ret); 43735331Samw } 43745331Samw 43755331Samw /* 43765331Samw * sa_get_resource_description(share) 43775331Samw * 43785331Samw * Return the description text for the specified share if it 43795331Samw * exists. NULL if no description exists. 43805331Samw */ 43815331Samw 43825331Samw char * 43835331Samw sa_get_resource_description(sa_resource_t resource) 43845331Samw { 43855331Samw xmlChar *description = NULL; 43865331Samw xmlNodePtr node; 43875331Samw 43885331Samw for (node = ((xmlNodePtr)resource)->children; node != NULL; 43895331Samw node = node->next) { 43905331Samw if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) 43915331Samw break; 43925331Samw } 43935331Samw if (node != NULL) { 43945331Samw description = xmlNodeGetContent(node); 43955331Samw fixproblemchars((char *)description); 43965331Samw } 43975331Samw return ((char *)description); 43985331Samw } 4399