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 /* 233348Sdougm * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 243034Sdougm * Use is subject to license terms. 253034Sdougm */ 263034Sdougm 273034Sdougm #pragma ident "%Z%%M% %I% %E% SMI" 283034Sdougm 293034Sdougm /* 303034Sdougm * Share control API 313034Sdougm */ 323034Sdougm #include <stdio.h> 333034Sdougm #include <string.h> 343034Sdougm #include <ctype.h> 353034Sdougm #include <sys/types.h> 363034Sdougm #include <sys/stat.h> 373663Sdougm #include <fcntl.h> 383034Sdougm #include <unistd.h> 393034Sdougm #include <libxml/parser.h> 403034Sdougm #include <libxml/tree.h> 413034Sdougm #include "libshare.h" 423034Sdougm #include "libshare_impl.h" 433034Sdougm #include <libscf.h> 443034Sdougm #include "scfutil.h" 453034Sdougm #include <ctype.h> 463034Sdougm #include <libintl.h> 473910Sdougm #include <thread.h> 483910Sdougm #include <synch.h> 493034Sdougm 503034Sdougm #if _NOT_SMF 513034Sdougm #define CONFIG_FILE "/var/tmp/share.cfg" 523034Sdougm #define CONFIG_FILE_TMP "/var/tmp/share.cfg.tmp" 533034Sdougm #endif 543034Sdougm #define TSTAMP(tm) (uint64_t)(((uint64_t)tm.tv_sec << 32) | \ 553034Sdougm (tm.tv_nsec & 0xffffffff)) 563034Sdougm 573663Sdougm #define DFS_LOCK_FILE "/etc/dfs/fstypes" 583663Sdougm 593034Sdougm /* 603034Sdougm * internal data structures 613034Sdougm */ 623034Sdougm 633034Sdougm extern struct sa_proto_plugin *sap_proto_list; 643034Sdougm 653034Sdougm /* current SMF/SVC repository handle */ 663910Sdougm extern void getlegacyconfig(sa_handle_t, char *, xmlNodePtr *); 673910Sdougm extern int gettransients(sa_handle_impl_t, xmlNodePtr *); 683034Sdougm extern int sa_valid_property(void *, char *, sa_property_t); 693034Sdougm extern char *sa_fstype(char *); 703034Sdougm extern int sa_is_share(void *); 713034Sdougm extern ssize_t scf_max_name_len; /* defined in scfutil during initialization */ 723034Sdougm extern int sa_group_is_zfs(sa_group_t); 733034Sdougm extern int sa_path_is_zfs(char *); 743034Sdougm extern int sa_zfs_set_sharenfs(sa_group_t, char *, int); 753910Sdougm extern void update_legacy_config(sa_handle_t); 763034Sdougm extern int issubdir(char *, char *); 773910Sdougm extern void sa_zfs_init(sa_handle_impl_t); 783910Sdougm extern void sa_zfs_fini(sa_handle_impl_t); 793663Sdougm extern void sablocksigs(sigset_t *); 803663Sdougm extern void saunblocksigs(sigset_t *); 813034Sdougm 823910Sdougm /* 833910Sdougm * Data structures for finding/managing the document root to access 843910Sdougm * handle mapping. The list isn't expected to grow very large so a 853910Sdougm * simple list is acceptable. The purpose is to provide a way to start 863910Sdougm * with a group or share and find the library handle needed for 873910Sdougm * various operations. 883910Sdougm */ 893910Sdougm mutex_t sa_global_lock; 903910Sdougm struct doc2handle { 913910Sdougm struct doc2handle *next; 923910Sdougm xmlNodePtr root; 933910Sdougm sa_handle_impl_t handle; 943910Sdougm }; 953910Sdougm 963910Sdougm static struct doc2handle *sa_global_handles = NULL; 973034Sdougm 983034Sdougm /* helper functions */ 993034Sdougm 1003910Sdougm /* 1013910Sdougm * sa_errorstr(err) 1023910Sdougm * 1033910Sdougm * convert an error value to an error string 1043910Sdougm */ 1053910Sdougm 1063034Sdougm char * 1073034Sdougm sa_errorstr(int err) 1083034Sdougm { 1093034Sdougm static char errstr[32]; 1103034Sdougm char *ret = NULL; 1113034Sdougm 1123034Sdougm switch (err) { 1133034Sdougm case SA_OK: 1143407Sdougm ret = dgettext(TEXT_DOMAIN, "ok"); 1153034Sdougm break; 1163034Sdougm case SA_NO_SUCH_PATH: 1173407Sdougm ret = dgettext(TEXT_DOMAIN, "path doesn't exist"); 1183034Sdougm break; 1193034Sdougm case SA_NO_MEMORY: 1203407Sdougm ret = dgettext(TEXT_DOMAIN, "no memory"); 1213034Sdougm break; 1223034Sdougm case SA_DUPLICATE_NAME: 1233407Sdougm ret = dgettext(TEXT_DOMAIN, "name in use"); 1243034Sdougm break; 1253034Sdougm case SA_BAD_PATH: 1263407Sdougm ret = dgettext(TEXT_DOMAIN, "bad path"); 1273034Sdougm break; 1283034Sdougm case SA_NO_SUCH_GROUP: 1293407Sdougm ret = dgettext(TEXT_DOMAIN, "no such group"); 1303034Sdougm break; 1313034Sdougm case SA_CONFIG_ERR: 1323407Sdougm ret = dgettext(TEXT_DOMAIN, "configuration error"); 1333034Sdougm break; 1343034Sdougm case SA_SYSTEM_ERR: 1353407Sdougm ret = dgettext(TEXT_DOMAIN, "system error"); 1363034Sdougm break; 1373034Sdougm case SA_SYNTAX_ERR: 1383407Sdougm ret = dgettext(TEXT_DOMAIN, "syntax error"); 1393034Sdougm break; 1403034Sdougm case SA_NO_PERMISSION: 1413407Sdougm ret = dgettext(TEXT_DOMAIN, "no permission"); 1423034Sdougm break; 1433034Sdougm case SA_BUSY: 1443407Sdougm ret = dgettext(TEXT_DOMAIN, "busy"); 1453034Sdougm break; 1463034Sdougm case SA_NO_SUCH_PROP: 1473407Sdougm ret = dgettext(TEXT_DOMAIN, "no such property"); 1483034Sdougm break; 1493034Sdougm case SA_INVALID_NAME: 1503407Sdougm ret = dgettext(TEXT_DOMAIN, "invalid name"); 1513034Sdougm break; 1523034Sdougm case SA_INVALID_PROTOCOL: 1533407Sdougm ret = dgettext(TEXT_DOMAIN, "invalid protocol"); 1543034Sdougm break; 1553034Sdougm case SA_NOT_ALLOWED: 1563407Sdougm ret = dgettext(TEXT_DOMAIN, "operation not allowed"); 1573034Sdougm break; 1583034Sdougm case SA_BAD_VALUE: 1593407Sdougm ret = dgettext(TEXT_DOMAIN, "bad property value"); 1603034Sdougm break; 1613034Sdougm case SA_INVALID_SECURITY: 1623407Sdougm ret = dgettext(TEXT_DOMAIN, "invalid security type"); 1633034Sdougm break; 1643034Sdougm case SA_NO_SUCH_SECURITY: 1653407Sdougm ret = dgettext(TEXT_DOMAIN, "security type not found"); 1663034Sdougm break; 1673034Sdougm case SA_VALUE_CONFLICT: 1683407Sdougm ret = dgettext(TEXT_DOMAIN, "property value conflict"); 1693034Sdougm break; 1703034Sdougm case SA_NOT_IMPLEMENTED: 1713407Sdougm ret = dgettext(TEXT_DOMAIN, "not implemented"); 1723034Sdougm break; 1733034Sdougm case SA_INVALID_PATH: 1743407Sdougm ret = dgettext(TEXT_DOMAIN, "invalid path"); 1753034Sdougm break; 1763034Sdougm case SA_NOT_SUPPORTED: 1773407Sdougm ret = dgettext(TEXT_DOMAIN, "operation not supported"); 1783034Sdougm break; 1793034Sdougm case SA_PROP_SHARE_ONLY: 1803407Sdougm ret = dgettext(TEXT_DOMAIN, "property not valid for group"); 1813034Sdougm break; 1823034Sdougm case SA_NOT_SHARED: 1833407Sdougm ret = dgettext(TEXT_DOMAIN, "not shared"); 1843034Sdougm break; 1853034Sdougm default: 1863034Sdougm (void) snprintf(errstr, sizeof (errstr), 1873407Sdougm dgettext(TEXT_DOMAIN, "unknown %d"), err); 1883034Sdougm ret = errstr; 1893034Sdougm } 1903034Sdougm return (ret); 1913034Sdougm } 1923034Sdougm 1933034Sdougm /* 1943910Sdougm * Document root to active handle mapping functions. These are only 1953910Sdougm * used internally. A mutex is used to prevent access while the list 1963910Sdougm * is changing. In general, the list will be relatively short - one 1973910Sdougm * item per thread that has called sa_init(). 1983910Sdougm */ 1993910Sdougm 2003910Sdougm sa_handle_impl_t 2013910Sdougm get_handle_for_root(xmlNodePtr root) 2023910Sdougm { 2033910Sdougm struct doc2handle *item; 2043910Sdougm 2053910Sdougm (void) mutex_lock(&sa_global_lock); 2063910Sdougm for (item = sa_global_handles; item != NULL; item = item->next) { 2073910Sdougm if (item->root == root) 2083910Sdougm break; 2093910Sdougm } 2103910Sdougm (void) mutex_unlock(&sa_global_lock); 2113910Sdougm if (item != NULL) 2123910Sdougm return (item->handle); 2133910Sdougm return (NULL); 2143910Sdougm } 2153910Sdougm 2163910Sdougm static int 2173910Sdougm add_handle_for_root(xmlNodePtr root, sa_handle_impl_t handle) 2183910Sdougm { 2193910Sdougm struct doc2handle *item; 2203910Sdougm int ret = SA_NO_MEMORY; 2213910Sdougm 2223910Sdougm item = (struct doc2handle *)calloc(sizeof (struct doc2handle), 1); 2233910Sdougm if (item != NULL) { 2243910Sdougm item->root = root; 2253910Sdougm item->handle = handle; 2263910Sdougm (void) mutex_lock(&sa_global_lock); 2273910Sdougm item->next = sa_global_handles; 2283910Sdougm sa_global_handles = item; 2293910Sdougm (void) mutex_unlock(&sa_global_lock); 2303910Sdougm ret = SA_OK; 2313910Sdougm } 2323910Sdougm return (ret); 2333910Sdougm } 2343910Sdougm 2353910Sdougm /* 2363910Sdougm * remove_handle_for_root(root) 2373910Sdougm * 2383910Sdougm * Walks the list of handles and removes the one for this "root" from 2393910Sdougm * the list. It is up to the caller to free the data. 2403910Sdougm */ 2413910Sdougm 2423910Sdougm static void 2433910Sdougm remove_handle_for_root(xmlNodePtr root) 2443910Sdougm { 2453910Sdougm struct doc2handle *item, *prev; 2463910Sdougm 2473910Sdougm (void) mutex_lock(&sa_global_lock); 2483910Sdougm for (prev = NULL, item = sa_global_handles; item != NULL; 2493910Sdougm item = item->next) { 2503910Sdougm if (item->root == root) { 2513910Sdougm if (prev == NULL) { 2523910Sdougm /* first in the list */ 2533910Sdougm sa_global_handles = sa_global_handles->next; 2543910Sdougm } else { 2553910Sdougm prev->next = item->next; 2563910Sdougm } 2573910Sdougm /* Item is out of the list so free the list structure */ 2583910Sdougm free(item); 2593910Sdougm break; 2603910Sdougm } 2613910Sdougm prev = item; 2623910Sdougm } 2633910Sdougm (void) mutex_unlock(&sa_global_lock); 2643910Sdougm } 2653910Sdougm 2663910Sdougm /* 2673910Sdougm * sa_find_group_handle(sa_group_t group) 2683910Sdougm * 2693910Sdougm * Find the sa_handle_t for the configuration associated with this 2703910Sdougm * group. 2713910Sdougm */ 2723910Sdougm sa_handle_t 2733910Sdougm sa_find_group_handle(sa_group_t group) 2743910Sdougm { 2753910Sdougm xmlNodePtr node = (xmlNodePtr)group; 2763910Sdougm sa_handle_t handle; 2773910Sdougm 2783910Sdougm while (node != NULL) { 2793910Sdougm if (strcmp((char *)(node->name), "sharecfg") == 0) { 2803910Sdougm /* have the root so get the handle */ 2813910Sdougm handle = (sa_handle_t)get_handle_for_root(node); 2823910Sdougm return (handle); 2833910Sdougm } 2843910Sdougm node = node->parent; 2853910Sdougm } 2863910Sdougm return (NULL); 2873910Sdougm } 2883910Sdougm 2893910Sdougm /* 2903034Sdougm * set_legacy_timestamp(root, path, timevalue) 2913034Sdougm * 2923034Sdougm * add the current timestamp value to the configuration for use in 2933034Sdougm * determining when to update the legacy files. For SMF, this 2943034Sdougm * property is kept in default/operation/legacy_timestamp 2953034Sdougm */ 2963034Sdougm 2973034Sdougm static void 2983034Sdougm set_legacy_timestamp(xmlNodePtr root, char *path, uint64_t tval) 2993034Sdougm { 3003034Sdougm xmlNodePtr node; 3013034Sdougm xmlChar *lpath = NULL; 3023910Sdougm sa_handle_impl_t handle; 3033910Sdougm 3043910Sdougm /* Have to have a handle or else we weren't initialized. */ 3053910Sdougm handle = get_handle_for_root(root); 3063910Sdougm if (handle == NULL) 3073910Sdougm return; 3083034Sdougm 3093034Sdougm for (node = root->xmlChildrenNode; node != NULL; 3103034Sdougm node = node->next) { 3113034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"legacy") == 0) { 3123034Sdougm /* a possible legacy node for this path */ 3133034Sdougm lpath = xmlGetProp(node, (xmlChar *)"path"); 3143034Sdougm if (lpath != NULL && xmlStrcmp(lpath, (xmlChar *)path) == 0) { 3153034Sdougm xmlFree(lpath); 3163034Sdougm break; 3173034Sdougm } 3183034Sdougm if (lpath != NULL) 3193034Sdougm xmlFree(lpath); 3203034Sdougm } 3213034Sdougm } 3223034Sdougm if (node == NULL) { 3233034Sdougm /* need to create the first legacy timestamp node */ 3243034Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"legacy", NULL); 3253034Sdougm } 3263034Sdougm if (node != NULL) { 3273034Sdougm char tstring[32]; 3283034Sdougm int ret; 3293034Sdougm 3303034Sdougm (void) snprintf(tstring, sizeof (tstring), "%lld", tval); 3313034Sdougm xmlSetProp(node, (xmlChar *)"timestamp", (xmlChar *)tstring); 3323034Sdougm xmlSetProp(node, (xmlChar *)"path", (xmlChar *)path); 3333034Sdougm /* now commit to SMF */ 3343910Sdougm ret = sa_get_instance(handle->scfhandle, "default"); 3353034Sdougm if (ret == SA_OK) { 3363910Sdougm ret = sa_start_transaction(handle->scfhandle, "operation"); 3373034Sdougm if (ret == SA_OK) { 3383910Sdougm ret = sa_set_property(handle->scfhandle, "legacy-timestamp", 3393034Sdougm tstring); 3403034Sdougm if (ret == SA_OK) { 3413910Sdougm (void) sa_end_transaction(handle->scfhandle); 3423034Sdougm } else { 3433910Sdougm sa_abort_transaction(handle->scfhandle); 3443034Sdougm } 3453034Sdougm } 3463034Sdougm } 3473034Sdougm } 3483034Sdougm } 3493034Sdougm 3503034Sdougm /* 3513034Sdougm * is_shared(share) 3523034Sdougm * 3533034Sdougm * determine if the specified share is currently shared or not. 3543034Sdougm */ 3553034Sdougm static int 3563034Sdougm is_shared(sa_share_t share) 3573034Sdougm { 3583034Sdougm char *shared; 3593034Sdougm int result = 0; /* assume not */ 3603034Sdougm 3613034Sdougm shared = sa_get_share_attr(share, "shared"); 3623034Sdougm if (shared != NULL) { 3633034Sdougm if (strcmp(shared, "true") == 0) 3643034Sdougm result = 1; 3653034Sdougm sa_free_attr_string(shared); 3663034Sdougm } 3673034Sdougm return (result); 3683034Sdougm } 3693034Sdougm 3703034Sdougm /* 3713663Sdougm * checksubdirgroup(group, newpath, strictness) 3723348Sdougm * 3733663Sdougm * check all the specified newpath against all the paths in the 3743663Sdougm * group. This is a helper function for checksubdir to make it easier 3753663Sdougm * to also check ZFS subgroups. 3763663Sdougm * The strictness values mean: 3773348Sdougm * SA_CHECK_NORMAL == only check newpath against shares that are active 3783348Sdougm * SA_CHECK_STRICT == check newpath against both active shares and those 3793348Sdougm * stored in the repository 3803034Sdougm */ 3813034Sdougm static int 3823663Sdougm checksubdirgroup(sa_group_t group, char *newpath, int strictness) 3833034Sdougm { 3843034Sdougm sa_share_t share; 3853663Sdougm char *path; 3863663Sdougm int issub = SA_OK; 3873034Sdougm 3883663Sdougm for (share = sa_get_share(group, NULL); share != NULL; 3893663Sdougm share = sa_get_next_share(share)) { 3903034Sdougm /* 3913034Sdougm * The original behavior of share never checked 3923034Sdougm * against the permanent configuration 3933034Sdougm * (/etc/dfs/dfstab). PIT has a number of cases where 3943034Sdougm * it depends on this older behavior even though it 3953034Sdougm * could be considered incorrect. We may tighten this 3963034Sdougm * up in the future. 3973034Sdougm */ 3983663Sdougm if (strictness == SA_CHECK_NORMAL && !is_shared(share)) 3993663Sdougm continue; 4003034Sdougm 4013663Sdougm path = sa_get_share_attr(share, "path"); 4023348Sdougm /* 4033348Sdougm * If path is NULL, then a share is in the process of 4043348Sdougm * construction or someone has modified the property 4053663Sdougm * group inappropriately. It should be 4063663Sdougm * ignored. issubdir() comes from the original share 4073663Sdougm * implementation and does the difficult part of 4083663Sdougm * checking subdirectories. 4093348Sdougm */ 4103663Sdougm if (path == NULL) 4113663Sdougm continue; 4123663Sdougm if (newpath != NULL && 4133663Sdougm (strcmp(path, newpath) == 0 || issubdir(newpath, path) || 4143663Sdougm issubdir(path, newpath))) { 4153034Sdougm sa_free_attr_string(path); 4163034Sdougm path = NULL; 4173663Sdougm issub = SA_INVALID_PATH; 4183663Sdougm break; 4193663Sdougm } 4203663Sdougm sa_free_attr_string(path); 4213663Sdougm path = NULL; 4223663Sdougm } 4233663Sdougm return (issub); 4243663Sdougm } 4253663Sdougm 4263663Sdougm /* 4273663Sdougm * checksubdir(newpath, strictness) 4283663Sdougm * 4293663Sdougm * checksubdir determines if the specified path (newpath) is a 4303663Sdougm * subdirectory of another share. It calls checksubdirgroup() to do 4313663Sdougm * the complicated work. The strictness parameter determines how 4323663Sdougm * strict a check to make against the path. The strictness values 4333663Sdougm * mean: SA_CHECK_NORMAL == only check newpath against shares that are 4343663Sdougm * active SA_CHECK_STRICT == check newpath against both active shares 4353663Sdougm * and those * stored in the repository 4363663Sdougm */ 4373663Sdougm static int 4383910Sdougm checksubdir(sa_handle_t handle, char *newpath, int strictness) 4393663Sdougm { 4403663Sdougm sa_group_t group; 4413663Sdougm int issub; 4423663Sdougm char *path = NULL; 4433663Sdougm 4443910Sdougm for (issub = 0, group = sa_get_group(handle, NULL); 4453663Sdougm group != NULL && !issub; 4463663Sdougm group = sa_get_next_group(group)) { 4473663Sdougm if (sa_group_is_zfs(group)) { 4483663Sdougm sa_group_t subgroup; 4493663Sdougm for (subgroup = sa_get_sub_group(group); 4503663Sdougm subgroup != NULL && !issub; 4513663Sdougm subgroup = sa_get_next_group(subgroup)) 4523663Sdougm issub = checksubdirgroup(subgroup, newpath, strictness); 4533663Sdougm } else { 4543663Sdougm issub = checksubdirgroup(group, newpath, strictness); 4553034Sdougm } 4563034Sdougm } 4573034Sdougm if (path != NULL) 4583034Sdougm sa_free_attr_string(path); 4593034Sdougm return (issub); 4603034Sdougm } 4613034Sdougm 4623034Sdougm /* 4633348Sdougm * validpath(path, strictness) 4643034Sdougm * determine if the provided path is valid for a share. It shouldn't 4653034Sdougm * be a sub-dir of an already shared path or the parent directory of a 4663034Sdougm * share path. 4673034Sdougm */ 4683034Sdougm static int 4693910Sdougm validpath(sa_handle_t handle, char *path, int strictness) 4703034Sdougm { 4713034Sdougm int error = SA_OK; 4723034Sdougm struct stat st; 4733034Sdougm sa_share_t share; 4743034Sdougm char *fstype; 4753034Sdougm 4763034Sdougm if (*path != '/') { 4773034Sdougm return (SA_BAD_PATH); 4783034Sdougm } 4793034Sdougm if (stat(path, &st) < 0) { 4803034Sdougm error = SA_NO_SUCH_PATH; 4813034Sdougm } else { 4823910Sdougm share = sa_find_share(handle, path); 4833034Sdougm if (share != NULL) { 4843034Sdougm error = SA_DUPLICATE_NAME; 4853034Sdougm } 4863034Sdougm if (error == SA_OK) { 4873034Sdougm /* 4883034Sdougm * check for special case with file system that might 4893034Sdougm * have restrictions. For now, ZFS is the only case 4903034Sdougm * since it has its own idea of how to configure 4913034Sdougm * shares. We do this before subdir checking since 4923034Sdougm * things like ZFS will do that for us. This should 4933034Sdougm * also be done via plugin interface. 4943034Sdougm */ 4953034Sdougm fstype = sa_fstype(path); 4963034Sdougm if (fstype != NULL && strcmp(fstype, "zfs") == 0) { 4973910Sdougm if (sa_zfs_is_shared(handle, path)) 4983663Sdougm error = SA_INVALID_NAME; 4993034Sdougm } 5003034Sdougm if (fstype != NULL) 5013034Sdougm sa_free_fstype(fstype); 5023034Sdougm } 5033034Sdougm if (error == SA_OK) { 5043910Sdougm error = checksubdir(handle, path, strictness); 5053034Sdougm } 5063034Sdougm } 5073034Sdougm return (error); 5083034Sdougm } 5093034Sdougm 5103034Sdougm /* 5113034Sdougm * check to see if group/share is persistent. 5123034Sdougm */ 5133034Sdougm static int 5143034Sdougm is_persistent(sa_group_t group) 5153034Sdougm { 5163034Sdougm char *type; 5173034Sdougm int persist = 1; 5183034Sdougm 5193034Sdougm type = sa_get_group_attr(group, "type"); 5203034Sdougm if (type != NULL && strcmp(type, "transient") == 0) 5213034Sdougm persist = 0; 5223034Sdougm if (type != NULL) 5233034Sdougm sa_free_attr_string(type); 5243034Sdougm return (persist); 5253034Sdougm } 5263034Sdougm 5273034Sdougm /* 5283034Sdougm * sa_valid_group_name(name) 5293034Sdougm * 5303034Sdougm * check that the "name" contains only valid characters and otherwise 5313034Sdougm * fits the required naming conventions. Valid names must start with 5323034Sdougm * an alphabetic and the remainder may consist of only alphanumeric 5333034Sdougm * plus the '-' and '_' characters. This name limitation comes from 5343034Sdougm * inherent limitations in SMF. 5353034Sdougm */ 5363034Sdougm 5373034Sdougm int 5383034Sdougm sa_valid_group_name(char *name) 5393034Sdougm { 5403034Sdougm int ret = 1; 5413034Sdougm ssize_t len; 5423034Sdougm 5433034Sdougm if (name != NULL && isalpha(*name)) { 5443034Sdougm char c; 5453034Sdougm len = strlen(name); 5463034Sdougm if (len < (scf_max_name_len - sizeof ("group:"))) { 5473034Sdougm for (c = *name++; c != '\0' && ret != 0; c = *name++) { 5483034Sdougm if (!isalnum(c) && c != '-' && c != '_') 5493034Sdougm ret = 0; 5503034Sdougm } 5513034Sdougm } else { 5523034Sdougm ret = 0; 5533034Sdougm } 5543034Sdougm } else { 5553034Sdougm ret = 0; 5563034Sdougm } 5573034Sdougm return (ret); 5583034Sdougm } 5593034Sdougm 5603034Sdougm 5613034Sdougm /* 5623034Sdougm * is_zfs_group(group) 5633034Sdougm * Determine if the specified group is a ZFS sharenfs group 5643034Sdougm */ 5653034Sdougm static int 5663034Sdougm is_zfs_group(sa_group_t group) 5673034Sdougm { 5683034Sdougm int ret = 0; 5693034Sdougm xmlNodePtr parent; 5703034Sdougm xmlChar *zfs; 5713034Sdougm 5723034Sdougm if (strcmp((char *)((xmlNodePtr)group)->name, "share") == 0) { 5733034Sdougm parent = (xmlNodePtr)sa_get_parent_group(group); 5743034Sdougm } else { 5753034Sdougm parent = (xmlNodePtr)group; 5763034Sdougm } 5773034Sdougm zfs = xmlGetProp(parent, (xmlChar *)"zfs"); 5783034Sdougm if (zfs != NULL) { 5793034Sdougm xmlFree(zfs); 5803034Sdougm ret = 1; 5813034Sdougm } 5823034Sdougm return (ret); 5833034Sdougm } 5843034Sdougm 5853034Sdougm /* 5863034Sdougm * sa_optionset_name(optionset, oname, len, id) 5873034Sdougm * return the SMF name for the optionset. If id is not NULL, it 5883034Sdougm * will have the GUID value for a share and should be used 5893034Sdougm * instead of the keyword "optionset" which is used for 5903034Sdougm * groups. If the optionset doesn't have a protocol type 5913034Sdougm * associated with it, "default" is used. This shouldn't happen 5923034Sdougm * at this point but may be desirable in the future if there are 5933034Sdougm * protocol independent properties added. The name is returned in 5943034Sdougm * oname. 5953034Sdougm */ 5963034Sdougm 5973034Sdougm static int 5983034Sdougm sa_optionset_name(sa_optionset_t optionset, char *oname, size_t len, char *id) 5993034Sdougm { 6003034Sdougm char *proto; 6013034Sdougm 6023034Sdougm if (id == NULL) 6033034Sdougm id = "optionset"; 6043034Sdougm 6053034Sdougm proto = sa_get_optionset_attr(optionset, "type"); 6063034Sdougm len = snprintf(oname, len, "%s_%s", id, proto ? proto : "default"); 6073034Sdougm 6083034Sdougm if (proto != NULL) 6093034Sdougm sa_free_attr_string(proto); 6103034Sdougm return (len); 6113034Sdougm } 6123034Sdougm 6133034Sdougm /* 6143034Sdougm * sa_security_name(optionset, oname, len, id) 6153034Sdougm * 6163034Sdougm * return the SMF name for the security. If id is not NULL, it will 6173034Sdougm * have the GUID value for a share and should be used instead of the 6183034Sdougm * keyword "optionset" which is used for groups. If the optionset 6193034Sdougm * doesn't have a protocol type associated with it, "default" is 6203034Sdougm * used. This shouldn't happen at this point but may be desirable in 6213034Sdougm * the future if there are protocol independent properties added. The 6223034Sdougm * name is returned in oname. The security type is also encoded into 6233034Sdougm * the name. In the future, this wil *be handled a bit differently. 6243034Sdougm */ 6253034Sdougm 6263034Sdougm static int 6273034Sdougm sa_security_name(sa_security_t security, char *oname, size_t len, char *id) 6283034Sdougm { 6293034Sdougm char *proto; 6303034Sdougm char *sectype; 6313034Sdougm 6323034Sdougm if (id == NULL) 6333034Sdougm id = "optionset"; 6343034Sdougm 6353034Sdougm proto = sa_get_security_attr(security, "type"); 6363034Sdougm sectype = sa_get_security_attr(security, "sectype"); 6373034Sdougm len = snprintf(oname, len, "%s_%s_%s", id, 6383034Sdougm proto ? proto : "default", 6393034Sdougm sectype ? sectype : "default"); 6403034Sdougm if (proto != NULL) 6413034Sdougm sa_free_attr_string(proto); 6423034Sdougm if (sectype != NULL) 6433034Sdougm sa_free_attr_string(sectype); 6443034Sdougm return (len); 6453034Sdougm } 6463034Sdougm 6473034Sdougm /* 6483348Sdougm * sa_init(init_service) 6493034Sdougm * Initialize the API 6503034Sdougm * find all the shared objects 6513034Sdougm * init the tables with all objects 6523034Sdougm * read in the current configuration 6533034Sdougm */ 6543034Sdougm 6553910Sdougm sa_handle_t 6563034Sdougm sa_init(int init_service) 6573034Sdougm { 6583034Sdougm struct stat st; 6593034Sdougm int legacy = 0; 6603034Sdougm uint64_t tval = 0; 6613663Sdougm int lockfd; 6623663Sdougm sigset_t old; 6633663Sdougm int updatelegacy = B_FALSE; 6643663Sdougm scf_simple_prop_t *prop; 6653910Sdougm sa_handle_impl_t handle; 6663910Sdougm int err; 6673034Sdougm 6683910Sdougm handle = calloc(sizeof (struct sa_handle_impl), 1); 6693910Sdougm 6703910Sdougm if (handle != NULL) { 6713034Sdougm /* get protocol specific structures */ 6723034Sdougm (void) proto_plugin_init(); 6733034Sdougm if (init_service & SA_INIT_SHARE_API) { 6743034Sdougm /* 6753218Sdougm * initialize access into libzfs. We use this when 6763218Sdougm * collecting info about ZFS datasets and shares. 6773218Sdougm */ 6783910Sdougm sa_zfs_init(handle); 6793218Sdougm /* 6803034Sdougm * since we want to use SMF, initialize an svc handle 6813034Sdougm * and find out what is there. 6823034Sdougm */ 6833910Sdougm handle->scfhandle = sa_scf_init(handle); 6843910Sdougm if (handle->scfhandle != NULL) { 6853663Sdougm /* 6863663Sdougm * Need to lock the extraction of the 6873663Sdougm * configuration if the dfstab file has 6883663Sdougm * changed. Lock everything now and release if 6893663Sdougm * not needed. Use a file that isn't being 6903663Sdougm * manipulated by other parts of the system in 6913663Sdougm * order to not interfere with locking. Using 6923663Sdougm * dfstab doesn't work. 6933663Sdougm */ 6943663Sdougm sablocksigs(&old); 6953663Sdougm lockfd = open(DFS_LOCK_FILE, O_RDWR); 6963663Sdougm if (lockfd >= 0) { 6973663Sdougm extern int errno; 6983663Sdougm errno = 0; 6993663Sdougm (void) lockf(lockfd, F_LOCK, 0); 7003663Sdougm /* 7013663Sdougm * Check whether we are going to need to merge 7023663Sdougm * any dfstab changes. This is done by 7033663Sdougm * comparing the value of legacy-timestamp 7043663Sdougm * with the current st_ctim of the file. If 7053663Sdougm * they are different, an update is needed and 7063663Sdougm * the file must remain locked until the merge 7073663Sdougm * is done in order to prevent multiple 7083663Sdougm * startups from changing the SMF repository 7093663Sdougm * at the same time. The first to get the 7103663Sdougm * lock will make any changes before the 7113663Sdougm * others can read the repository. 7123663Sdougm */ 7133910Sdougm prop = scf_simple_prop_get(handle->scfhandle->handle, 7143663Sdougm (const char *) 7153663Sdougm SA_SVC_FMRI_BASE ":default", 7163663Sdougm "operation", 7173663Sdougm "legacy-timestamp"); 7183663Sdougm if (prop != NULL) { 7193663Sdougm char *i64; 7203663Sdougm i64 = scf_simple_prop_next_astring(prop); 7213663Sdougm if (i64 != NULL) { 7223663Sdougm tval = strtoull(i64, NULL, 0); 7233663Sdougm } 7243663Sdougm if (stat(SA_LEGACY_DFSTAB, &st) >= 0 && 7253663Sdougm tval != TSTAMP(st.st_ctim)) { 7263663Sdougm updatelegacy = B_TRUE; 7273663Sdougm } 7283663Sdougm } else { 7293663Sdougm /* We haven't set the timestamp before so do it. */ 7303663Sdougm updatelegacy = B_TRUE; 7313663Sdougm } 7323663Sdougm } 7333663Sdougm if (updatelegacy == B_FALSE) { 7343663Sdougm /* Don't need the lock anymore */ 7353663Sdougm (void) lockf(lockfd, F_ULOCK, 0); 7363663Sdougm (void) close(lockfd); 7373663Sdougm } 738*3973Sdougm 739*3973Sdougm /* 740*3973Sdougm * It is essential that the document tree and 741*3973Sdougm * the internal list of roots to handles be 742*3973Sdougm * setup before anything that might try to 743*3973Sdougm * create a new object is called. The document 744*3973Sdougm * tree is the combination of handle->doc and 745*3973Sdougm * handle->tree. This allows searches, 746*3973Sdougm * etc. when all you have is an object in the 747*3973Sdougm * tree. 748*3973Sdougm */ 749*3973Sdougm handle->doc = xmlNewDoc((xmlChar *)"1.0"); 750*3973Sdougm handle->tree = xmlNewNode(NULL, (xmlChar *)"sharecfg"); 751*3973Sdougm if (handle->doc != NULL && handle->tree != NULL) { 752*3973Sdougm xmlDocSetRootElement(handle->doc, handle->tree); 753*3973Sdougm err = add_handle_for_root(handle->tree, handle); 754*3973Sdougm if (err == SA_OK) 755*3973Sdougm err = sa_get_config(handle->scfhandle, 756*3973Sdougm handle->tree, handle); 757*3973Sdougm } else { 758*3973Sdougm if (handle->doc != NULL) 759*3973Sdougm xmlFreeDoc(handle->doc); 760*3973Sdougm if (handle->tree != NULL) 761*3973Sdougm xmlFreeNode(handle->tree); 762*3973Sdougm err = SA_NO_MEMORY; 763*3973Sdougm } 764*3973Sdougm 7653663Sdougm saunblocksigs(&old); 7663910Sdougm 7673910Sdougm if (err != SA_OK) { 7683910Sdougm /* 769*3973Sdougm * If we couldn't add the tree handle 770*3973Sdougm * to the list, then things are going 771*3973Sdougm * to fail badly. Might as well undo 772*3973Sdougm * everything now and fail the 773*3973Sdougm * sa_init(). 7743910Sdougm */ 7753910Sdougm sa_fini(handle); 7763910Sdougm return (NULL); 7773910Sdougm } 7783910Sdougm 7793034Sdougm if (tval == 0) { 7803034Sdougm /* first time so make sure default is setup */ 7813034Sdougm sa_group_t defgrp; 7823034Sdougm sa_optionset_t opt; 7833910Sdougm defgrp = sa_get_group(handle, "default"); 7843034Sdougm if (defgrp != NULL) { 7853034Sdougm opt = sa_get_optionset(defgrp, NULL); 7863034Sdougm if (opt == NULL) 7873034Sdougm /* NFS is the default for default */ 7883034Sdougm opt = sa_create_optionset(defgrp, "nfs"); 7893034Sdougm } 7903034Sdougm } 791*3973Sdougm 7923663Sdougm if (updatelegacy == B_TRUE) { 7933663Sdougm sablocksigs(&old); 7943910Sdougm getlegacyconfig((sa_handle_t)handle, 7953910Sdougm SA_LEGACY_DFSTAB, &handle->tree); 7963034Sdougm if (stat(SA_LEGACY_DFSTAB, &st) >= 0) 7973910Sdougm set_legacy_timestamp(handle->tree, 7983034Sdougm SA_LEGACY_DFSTAB, 7993034Sdougm TSTAMP(st.st_ctim)); 8003663Sdougm saunblocksigs(&old); 8013663Sdougm /* Safe to unlock now to allow others to run */ 8023663Sdougm (void) lockf(lockfd, F_ULOCK, 0); 8033663Sdougm (void) close(lockfd); 8043034Sdougm } 8053910Sdougm legacy |= sa_get_zfs_shares(handle, "zfs"); 8063910Sdougm legacy |= gettransients(handle, &handle->tree); 8073034Sdougm } 8083034Sdougm } 8093034Sdougm } 8103910Sdougm return ((sa_handle_t)handle); 8113034Sdougm } 8123034Sdougm 8133034Sdougm /* 8143910Sdougm * sa_fini(handle) 8153034Sdougm * Uninitialize the API structures including the configuration 8163218Sdougm * data structures and ZFS related data. 8173034Sdougm */ 8183034Sdougm 8193034Sdougm void 8203910Sdougm sa_fini(sa_handle_t handle) 8213034Sdougm { 8223910Sdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle; 8233910Sdougm 8243910Sdougm if (impl_handle != NULL) { 8253910Sdougm /* 8263910Sdougm * Free the config trees and any other data structures 8273910Sdougm * used in the handle. 8283910Sdougm */ 8293910Sdougm if (impl_handle->doc != NULL) 8303910Sdougm xmlFreeDoc(impl_handle->doc); 8313910Sdougm sa_scf_fini(impl_handle->scfhandle); 8323910Sdougm sa_zfs_fini(impl_handle); 8333910Sdougm 8343910Sdougm /* Remove and free the entry in the global list. */ 8353910Sdougm remove_handle_for_root(impl_handle->tree); 8363910Sdougm 8373910Sdougm /* Make sure we free the handle */ 8383910Sdougm free(impl_handle); 8393910Sdougm 8403910Sdougm /* 8413910Sdougm * If this was the last handle to release, unload the 8423910Sdougm * plugins that were loaded. 8433910Sdougm */ 8443910Sdougm if (sa_global_handles == NULL) 8453910Sdougm (void) proto_plugin_fini(); 8463910Sdougm 8473034Sdougm } 8483034Sdougm } 8493034Sdougm 8503034Sdougm /* 8513034Sdougm * sa_get_protocols(char **protocol) 8523034Sdougm * Get array of protocols that are supported 8533034Sdougm * Returns pointer to an allocated and NULL terminated 8543034Sdougm * array of strings. Caller must free. 8553034Sdougm * This really should be determined dynamically. 8563034Sdougm * If there aren't any defined, return -1. 8573034Sdougm * Use free() to return memory. 8583034Sdougm */ 8593034Sdougm 8603034Sdougm int 8613034Sdougm sa_get_protocols(char ***protocols) 8623034Sdougm { 8633034Sdougm int numproto = -1; 8643034Sdougm 8653034Sdougm if (protocols != NULL) { 8663034Sdougm struct sa_proto_plugin *plug; 8673034Sdougm for (numproto = 0, plug = sap_proto_list; plug != NULL; 8683034Sdougm plug = plug->plugin_next) { 8693034Sdougm numproto++; 8703034Sdougm } 8713034Sdougm 8723034Sdougm *protocols = calloc(numproto + 1, sizeof (char *)); 8733034Sdougm if (*protocols != NULL) { 8743034Sdougm int ret = 0; 8753034Sdougm for (plug = sap_proto_list; plug != NULL; 8763034Sdougm plug = plug->plugin_next) { 8773034Sdougm /* faking for now */ 8783034Sdougm (*protocols)[ret++] = plug->plugin_ops->sa_protocol; 8793034Sdougm } 8803034Sdougm } else { 8813034Sdougm numproto = -1; 8823034Sdougm } 8833034Sdougm } 8843034Sdougm return (numproto); 8853034Sdougm } 8863034Sdougm 8873034Sdougm /* 8883034Sdougm * find_group_by_name(node, group) 8893034Sdougm * 8903034Sdougm * search the XML document subtree specified by node to find the group 8913034Sdougm * specified by group. Searching subtree allows subgroups to be 8923034Sdougm * searched for. 8933034Sdougm */ 8943034Sdougm 8953034Sdougm static xmlNodePtr 8963034Sdougm find_group_by_name(xmlNodePtr node, xmlChar *group) 8973034Sdougm { 8983034Sdougm xmlChar *name = NULL; 8993034Sdougm 9003034Sdougm for (node = node->xmlChildrenNode; node != NULL; 9013034Sdougm node = node->next) { 9023034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"group") == 0) { 9033034Sdougm /* if no groupname, return the first found */ 9043034Sdougm if (group == NULL) 9053034Sdougm break; 9063034Sdougm name = xmlGetProp(node, (xmlChar *)"name"); 9073034Sdougm if (name != NULL && 9083034Sdougm xmlStrcmp(name, group) == 0) { 9093034Sdougm break; 9103034Sdougm } 9113034Sdougm if (name != NULL) { 9123034Sdougm xmlFree(name); 9133034Sdougm name = NULL; 9143034Sdougm } 9153034Sdougm } 9163034Sdougm } 9173034Sdougm if (name != NULL) 9183034Sdougm xmlFree(name); 9193034Sdougm return (node); 9203034Sdougm } 9213034Sdougm 9223034Sdougm /* 9233034Sdougm * sa_get_group(groupname) 9243034Sdougm * Return the "group" specified. If groupname is NULL, 9253034Sdougm * return the first group of the list of groups. 9263034Sdougm */ 9273034Sdougm sa_group_t 9283910Sdougm sa_get_group(sa_handle_t handle, char *groupname) 9293034Sdougm { 9303034Sdougm xmlNodePtr node = NULL; 9313034Sdougm char *subgroup = NULL; 9323034Sdougm char *group = NULL; 9333910Sdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle; 9343034Sdougm 9353910Sdougm if (impl_handle != NULL && impl_handle->tree != NULL) { 9363034Sdougm if (groupname != NULL) { 9373034Sdougm group = strdup(groupname); 9383034Sdougm subgroup = strchr(group, '/'); 9393034Sdougm if (subgroup != NULL) 9403034Sdougm *subgroup++ = '\0'; 9413034Sdougm } 9423910Sdougm node = find_group_by_name(impl_handle->tree, (xmlChar *)group); 9433034Sdougm /* if a subgroup, find it before returning */ 9443034Sdougm if (subgroup != NULL && node != NULL) { 9453034Sdougm node = find_group_by_name(node, (xmlChar *)subgroup); 9463034Sdougm } 9473034Sdougm } 9483034Sdougm if (node != NULL && (char *)group != NULL) 9493910Sdougm (void) sa_get_instance(impl_handle->scfhandle, (char *)group); 9503034Sdougm if (group != NULL) 9513034Sdougm free(group); 9523034Sdougm return ((sa_group_t)(node)); 9533034Sdougm } 9543034Sdougm 9553034Sdougm /* 9563034Sdougm * sa_get_next_group(group) 9573034Sdougm * Return the "next" group after the specified group from 9583034Sdougm * the internal group list. NULL if there are no more. 9593034Sdougm */ 9603034Sdougm sa_group_t 9613034Sdougm sa_get_next_group(sa_group_t group) 9623034Sdougm { 9633034Sdougm xmlNodePtr ngroup = NULL; 9643034Sdougm if (group != NULL) { 9653034Sdougm for (ngroup = ((xmlNodePtr)group)->next; ngroup != NULL; 9663034Sdougm ngroup = ngroup->next) { 9673034Sdougm if (xmlStrcmp(ngroup->name, (xmlChar *)"group") == 0) 9683034Sdougm break; 9693034Sdougm } 9703034Sdougm } 9713034Sdougm return ((sa_group_t)ngroup); 9723034Sdougm } 9733034Sdougm 9743034Sdougm /* 9753034Sdougm * sa_get_share(group, sharepath) 9763034Sdougm * Return the share object for the share specified. The share 9773034Sdougm * must be in the specified group. Return NULL if not found. 9783034Sdougm */ 9793034Sdougm sa_share_t 9803034Sdougm sa_get_share(sa_group_t group, char *sharepath) 9813034Sdougm { 9823034Sdougm xmlNodePtr node = NULL; 9833034Sdougm xmlChar *path; 9843034Sdougm 9853034Sdougm /* 9863034Sdougm * For future scalability, this should end up building a cache 9873034Sdougm * since it will get called regularly by the mountd and info 9883034Sdougm * services. 9893034Sdougm */ 9903034Sdougm if (group != NULL) { 9913034Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 9923034Sdougm node = node->next) { 9933034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) { 9943034Sdougm if (sharepath == NULL) { 9953034Sdougm break; 9963034Sdougm } else { 9973034Sdougm /* is it the correct share? */ 9983034Sdougm path = xmlGetProp(node, (xmlChar *)"path"); 9993034Sdougm if (path != NULL && 10003034Sdougm xmlStrcmp(path, (xmlChar *)sharepath) == 0) { 10013034Sdougm xmlFree(path); 10023034Sdougm break; 10033034Sdougm } 10043034Sdougm xmlFree(path); 10053034Sdougm } 10063034Sdougm } 10073034Sdougm } 10083034Sdougm } 10093034Sdougm return ((sa_share_t)node); 10103034Sdougm } 10113034Sdougm 10123034Sdougm /* 10133034Sdougm * sa_get_next_share(share) 10143034Sdougm * Return the next share following the specified share 10153034Sdougm * from the internal list of shares. Returns NULL if there 10163034Sdougm * are no more shares. The list is relative to the same 10173034Sdougm * group. 10183034Sdougm */ 10193034Sdougm sa_share_t 10203034Sdougm sa_get_next_share(sa_share_t share) 10213034Sdougm { 10223034Sdougm xmlNodePtr node = NULL; 10233034Sdougm 10243034Sdougm if (share != NULL) { 10253034Sdougm for (node = ((xmlNodePtr)share)->next; node != NULL; 10263034Sdougm node = node->next) { 10273034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) { 10283034Sdougm break; 10293034Sdougm } 10303034Sdougm } 10313034Sdougm } 10323034Sdougm return ((sa_share_t)node); 10333034Sdougm } 10343034Sdougm 10353034Sdougm /* 10363034Sdougm * _sa_get_child_node(node, type) 10373034Sdougm * 10383034Sdougm * find the child node of the specified node that has "type". This is 10393034Sdougm * used to implement several internal functions. 10403034Sdougm */ 10413034Sdougm 10423034Sdougm static xmlNodePtr 10433034Sdougm _sa_get_child_node(xmlNodePtr node, xmlChar *type) 10443034Sdougm { 10453034Sdougm xmlNodePtr child; 10463034Sdougm for (child = node->xmlChildrenNode; child != NULL; 10473034Sdougm child = child->next) 10483034Sdougm if (xmlStrcmp(child->name, type) == 0) 10493034Sdougm return (child); 10503034Sdougm return ((xmlNodePtr)NULL); 10513034Sdougm } 10523034Sdougm 10533034Sdougm /* 10543034Sdougm * find_share(group, path) 10553034Sdougm * 10563034Sdougm * Search all the shares in the specified group for one that has the 10573034Sdougm * specified path. 10583034Sdougm */ 10593034Sdougm 10603034Sdougm static sa_share_t 10613034Sdougm find_share(sa_group_t group, char *sharepath) 10623034Sdougm { 10633034Sdougm sa_share_t share; 10643034Sdougm char *path; 10653034Sdougm 10663034Sdougm for (share = sa_get_share(group, NULL); share != NULL; 10673034Sdougm share = sa_get_next_share(share)) { 10683034Sdougm path = sa_get_share_attr(share, "path"); 10693034Sdougm if (path != NULL && strcmp(path, sharepath) == 0) { 10703034Sdougm sa_free_attr_string(path); 10713034Sdougm break; 10723034Sdougm } 10733034Sdougm if (path != NULL) 10743034Sdougm sa_free_attr_string(path); 10753034Sdougm } 10763034Sdougm return (share); 10773034Sdougm } 10783034Sdougm 10793034Sdougm /* 10803034Sdougm * sa_get_sub_group(group) 10813034Sdougm * 10823034Sdougm * Get the first sub-group of group. The sa_get_next_group() function 10833034Sdougm * can be used to get the rest. This is currently only used for ZFS 10843034Sdougm * sub-groups but could be used to implement a more general mechanism. 10853034Sdougm */ 10863034Sdougm 10873034Sdougm sa_group_t 10883034Sdougm sa_get_sub_group(sa_group_t group) 10893034Sdougm { 10903034Sdougm return ((sa_group_t)_sa_get_child_node((xmlNodePtr)group, 10913034Sdougm (xmlChar *)"group")); 10923034Sdougm } 10933034Sdougm 10943034Sdougm /* 10953034Sdougm * sa_find_share(sharepath) 10963034Sdougm * Finds a share regardless of group. In the future, this 10973034Sdougm * function should utilize a cache and hash table of some kind. 10983034Sdougm * The current assumption is that a path will only be shared 10993034Sdougm * once. In the future, this may change as implementation of 11003034Sdougm * resource names comes into being. 11013034Sdougm */ 11023034Sdougm sa_share_t 11033910Sdougm sa_find_share(sa_handle_t handle, char *sharepath) 11043034Sdougm { 11053034Sdougm sa_group_t group; 11063034Sdougm sa_group_t zgroup; 11073034Sdougm sa_share_t share = NULL; 11083034Sdougm int done = 0; 11093034Sdougm 11103910Sdougm for (group = sa_get_group(handle, NULL); group != NULL && !done; 11113034Sdougm group = sa_get_next_group(group)) { 11123034Sdougm if (is_zfs_group(group)) { 11133034Sdougm for (zgroup = (sa_group_t)_sa_get_child_node((xmlNodePtr)group, 11143034Sdougm (xmlChar *)"group"); 11153034Sdougm zgroup != NULL; zgroup = sa_get_next_group(zgroup)) { 11163034Sdougm share = find_share(zgroup, sharepath); 11173034Sdougm if (share != NULL) 11183034Sdougm break; 11193034Sdougm } 11203034Sdougm } else { 11213034Sdougm share = find_share(group, sharepath); 11223034Sdougm } 11233034Sdougm if (share != NULL) 11243034Sdougm break; 11253034Sdougm } 11263034Sdougm return (share); 11273034Sdougm } 11283034Sdougm 11293034Sdougm /* 11303348Sdougm * sa_check_path(group, path, strictness) 11313034Sdougm * 11323034Sdougm * check that path is a valid path relative to the group. Currently, 11333034Sdougm * we are ignoring the group and checking only the NFS rules. Later, 11343034Sdougm * we may want to use the group to then check against the protocols 11353348Sdougm * enabled on the group. The strictness values mean: 11363348Sdougm * SA_CHECK_NORMAL == only check newpath against shares that are active 11373348Sdougm * SA_CHECK_STRICT == check newpath against both active shares and those 11383348Sdougm * stored in the repository 11393034Sdougm */ 11403034Sdougm 11413034Sdougm int 11423348Sdougm sa_check_path(sa_group_t group, char *path, int strictness) 11433034Sdougm { 11443910Sdougm sa_handle_t handle; 11453910Sdougm 11463910Sdougm handle = sa_find_group_handle(group); 11473910Sdougm return (validpath(handle, path, strictness)); 11483034Sdougm } 11493034Sdougm 11503034Sdougm /* 11513034Sdougm * _sa_add_share(group, sharepath, persist, *error) 11523034Sdougm * 11533034Sdougm * common code for all types of add_share. sa_add_share() is the 11543034Sdougm * public API, we also need to be able to do this when parsing legacy 11553034Sdougm * files and construction of the internal configuration while 11563034Sdougm * extracting config info from SMF. 11573034Sdougm */ 11583034Sdougm 11593034Sdougm sa_share_t 11603034Sdougm _sa_add_share(sa_group_t group, char *sharepath, int persist, int *error) 11613034Sdougm { 11623034Sdougm xmlNodePtr node = NULL; 11633034Sdougm int err; 11643034Sdougm 11653034Sdougm err = SA_OK; /* assume success */ 11663034Sdougm 11673034Sdougm node = xmlNewChild((xmlNodePtr)group, NULL, 11683034Sdougm (xmlChar *)"share", NULL); 11693034Sdougm if (node != NULL) { 11703034Sdougm xmlSetProp(node, (xmlChar *)"path", (xmlChar *)sharepath); 11713034Sdougm xmlSetProp(node, (xmlChar *)"type", persist ? 11723034Sdougm (xmlChar *)"persist" : (xmlChar *)"transient"); 11733034Sdougm if (persist != SA_SHARE_TRANSIENT) { 11743034Sdougm /* 11753034Sdougm * persistent shares come in two flavors: SMF and 11763034Sdougm * ZFS. Sort this one out based on target group and 11773034Sdougm * path type. Currently, only NFS is supported in the 11783034Sdougm * ZFS group and it is always on. 11793034Sdougm */ 11803034Sdougm if (sa_group_is_zfs(group) && sa_path_is_zfs(sharepath)) { 11813034Sdougm err = sa_zfs_set_sharenfs(group, sharepath, 1); 11823034Sdougm } else { 11833910Sdougm sa_handle_impl_t impl_handle; 11843910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 11853910Sdougm if (impl_handle != NULL) 11863910Sdougm err = sa_commit_share(impl_handle->scfhandle, group, 11873034Sdougm (sa_share_t)node); 11883910Sdougm else 11893910Sdougm err = SA_SYSTEM_ERR; 11903034Sdougm } 11913034Sdougm } 11923034Sdougm if (err == SA_NO_PERMISSION && persist & SA_SHARE_PARSER) { 11933034Sdougm /* called by the dfstab parser so could be a show */ 11943034Sdougm err = SA_OK; 11953034Sdougm } 11963034Sdougm if (err != SA_OK) { 11973034Sdougm /* 11983034Sdougm * we couldn't commit to the repository so undo 11993034Sdougm * our internal state to reflect reality. 12003034Sdougm */ 12013034Sdougm xmlUnlinkNode(node); 12023034Sdougm xmlFreeNode(node); 12033034Sdougm node = NULL; 12043034Sdougm } 12053034Sdougm } else { 12063034Sdougm err = SA_NO_MEMORY; 12073034Sdougm } 12083034Sdougm if (error != NULL) 12093034Sdougm *error = err; 12103034Sdougm return (node); 12113034Sdougm } 12123034Sdougm 12133034Sdougm /* 12143034Sdougm * sa_add_share(group, sharepath, persist, *error) 12153034Sdougm * 12163034Sdougm * Add a new share object to the specified group. The share will 12173034Sdougm * have the specified sharepath and will only be constructed if 12183034Sdougm * it is a valid path to be shared. NULL is returned on error 12193034Sdougm * and a detailed error value will be returned via the error 12203034Sdougm * pointer. 12213034Sdougm */ 12223034Sdougm sa_share_t 12233034Sdougm sa_add_share(sa_group_t group, char *sharepath, int persist, int *error) 12243034Sdougm { 12253034Sdougm xmlNodePtr node = NULL; 12263034Sdougm sa_share_t dup; 12273348Sdougm int strictness = SA_CHECK_NORMAL; 12283910Sdougm sa_handle_t handle; 12293348Sdougm 12303348Sdougm /* 12313348Sdougm * If the share is to be permanent, use strict checking so a 12323348Sdougm * bad config doesn't get created. Transient shares only need 12333348Sdougm * to check against the currently active 12343348Sdougm * shares. SA_SHARE_PARSER is a modifier used internally to 12353348Sdougm * indicate that we are being called by the dfstab parser and 12363348Sdougm * that we need strict checking in all cases. Normally persist 12373348Sdougm * is in integer value but SA_SHARE_PARSER may be or'd into 12383348Sdougm * it as an override. 12393348Sdougm */ 12403348Sdougm if (persist & SA_SHARE_PARSER || persist == SA_SHARE_PERMANENT) 12413348Sdougm strictness = SA_CHECK_STRICT; 12423034Sdougm 12433910Sdougm handle = sa_find_group_handle(group); 12443910Sdougm 12453910Sdougm if ((dup = sa_find_share(handle, sharepath)) == NULL && 12463348Sdougm (*error = sa_check_path(group, sharepath, strictness)) == 12473348Sdougm SA_OK) { 12483034Sdougm node = _sa_add_share(group, sharepath, persist, error); 12493034Sdougm } 12503034Sdougm if (dup != NULL) 12513034Sdougm *error = SA_DUPLICATE_NAME; 12523034Sdougm 12533034Sdougm return ((sa_share_t)node); 12543034Sdougm } 12553034Sdougm 12563034Sdougm /* 12573034Sdougm * sa_enable_share(share, protocol) 12583034Sdougm * Enable the specified share to the specified protocol. 12593034Sdougm * If protocol is NULL, then all protocols. 12603034Sdougm */ 12613034Sdougm int 12623034Sdougm sa_enable_share(sa_share_t share, char *protocol) 12633034Sdougm { 12643034Sdougm char *sharepath; 12653034Sdougm struct stat st; 12663034Sdougm int err = 0; 12673034Sdougm 12683034Sdougm sharepath = sa_get_share_attr(share, "path"); 12693034Sdougm if (stat(sharepath, &st) < 0) { 12703034Sdougm err = SA_NO_SUCH_PATH; 12713034Sdougm } else { 12723034Sdougm /* tell the server about the share */ 12733034Sdougm if (protocol != NULL) { 12743034Sdougm /* lookup protocol specific handler */ 12753034Sdougm err = sa_proto_share(protocol, share); 12763034Sdougm if (err == SA_OK) 12773034Sdougm (void) sa_set_share_attr(share, "shared", "true"); 12783034Sdougm } else { 12793034Sdougm /* tell all protocols */ 12803034Sdougm err = sa_proto_share("nfs", share); /* only NFS for now */ 12813034Sdougm (void) sa_set_share_attr(share, "shared", "true"); 12823034Sdougm } 12833034Sdougm } 12843034Sdougm if (sharepath != NULL) 12853034Sdougm sa_free_attr_string(sharepath); 12863034Sdougm return (err); 12873034Sdougm } 12883034Sdougm 12893034Sdougm /* 12903034Sdougm * sa_disable_share(share, protocol) 12913034Sdougm * Disable the specified share to the specified protocol. 12923034Sdougm * If protocol is NULL, then all protocols. 12933034Sdougm */ 12943034Sdougm int 12953034Sdougm sa_disable_share(sa_share_t share, char *protocol) 12963034Sdougm { 12973034Sdougm char *path; 12983034Sdougm char *shared; 12993034Sdougm int ret = SA_OK; 13003034Sdougm 13013034Sdougm path = sa_get_share_attr(share, "path"); 13023034Sdougm shared = sa_get_share_attr(share, "shared"); 13033034Sdougm 13043034Sdougm if (protocol != NULL) { 13053034Sdougm ret = sa_proto_unshare(protocol, path); 13063034Sdougm } else { 13073034Sdougm /* need to do all protocols */ 13083034Sdougm ret = sa_proto_unshare("nfs", path); 13093034Sdougm } 13103034Sdougm if (ret == SA_OK) 13113034Sdougm (void) sa_set_share_attr(share, "shared", NULL); 13123034Sdougm if (path != NULL) 13133034Sdougm sa_free_attr_string(path); 13143034Sdougm if (shared != NULL) 13153034Sdougm sa_free_attr_string(shared); 13163034Sdougm return (ret); 13173034Sdougm } 13183034Sdougm 13193034Sdougm /* 13203034Sdougm * sa_remove_share(share) 13213034Sdougm * 13223034Sdougm * remove the specified share from its containing group. 13233034Sdougm * Remove from the SMF or ZFS configuration space. 13243034Sdougm */ 13253034Sdougm 13263034Sdougm int 13273034Sdougm sa_remove_share(sa_share_t share) 13283034Sdougm { 13293034Sdougm sa_group_t group; 13303034Sdougm int ret = SA_OK; 13313034Sdougm char *type; 13323034Sdougm int transient = 0; 13333034Sdougm char *groupname; 13343034Sdougm char *zfs; 13353034Sdougm 13363034Sdougm type = sa_get_share_attr(share, "type"); 13373034Sdougm group = sa_get_parent_group(share); 13383034Sdougm zfs = sa_get_group_attr(group, "zfs"); 13393034Sdougm groupname = sa_get_group_attr(group, "name"); 13403034Sdougm if (type != NULL && strcmp(type, "persist") != 0) 13413034Sdougm transient = 1; 13423034Sdougm if (type != NULL) 13433034Sdougm sa_free_attr_string(type); 13443034Sdougm 13453034Sdougm /* remove the node from its group then free the memory */ 13463034Sdougm 13473034Sdougm /* 13483034Sdougm * need to test if "busy" 13493034Sdougm */ 13503034Sdougm /* only do SMF action if permanent */ 13513034Sdougm if (!transient || zfs != NULL) { 13523034Sdougm /* remove from legacy dfstab as well as possible SMF */ 13533034Sdougm ret = sa_delete_legacy(share); 13543034Sdougm if (ret == SA_OK) { 13553034Sdougm if (!sa_group_is_zfs(group)) { 13563910Sdougm sa_handle_impl_t impl_handle; 13573910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 13583910Sdougm if (impl_handle != NULL) 13593910Sdougm ret = sa_delete_share(impl_handle->scfhandle, 13603910Sdougm group, share); 13613910Sdougm else 13623910Sdougm ret = SA_SYSTEM_ERR; 13633034Sdougm } else { 13643034Sdougm char *sharepath = sa_get_share_attr(share, "path"); 13653034Sdougm if (sharepath != NULL) { 13663034Sdougm ret = sa_zfs_set_sharenfs(group, sharepath, 0); 13673034Sdougm sa_free_attr_string(sharepath); 13683034Sdougm } 13693034Sdougm } 13703034Sdougm } 13713034Sdougm } 13723034Sdougm if (groupname != NULL) 13733034Sdougm sa_free_attr_string(groupname); 13743034Sdougm if (zfs != NULL) 13753034Sdougm sa_free_attr_string(zfs); 13763034Sdougm 13773034Sdougm xmlUnlinkNode((xmlNodePtr)share); 13783034Sdougm xmlFreeNode((xmlNodePtr)share); 13793034Sdougm return (ret); 13803034Sdougm } 13813034Sdougm 13823034Sdougm /* 13833034Sdougm * sa_move_share(group, share) 13843034Sdougm * 13853034Sdougm * move the specified share to the specified group. Update SMF 13863034Sdougm * appropriately. 13873034Sdougm */ 13883034Sdougm 13893034Sdougm int 13903034Sdougm sa_move_share(sa_group_t group, sa_share_t share) 13913034Sdougm { 13923034Sdougm sa_group_t oldgroup; 13933034Sdougm int ret = SA_OK; 13943034Sdougm 13953034Sdougm /* remove the node from its group then free the memory */ 13963034Sdougm 13973034Sdougm oldgroup = sa_get_parent_group(share); 13983034Sdougm if (oldgroup != group) { 13993910Sdougm sa_handle_impl_t impl_handle; 14003034Sdougm xmlUnlinkNode((xmlNodePtr)share); 14013034Sdougm /* now that the share isn't in its old group, add to the new one */ 14023034Sdougm xmlAddChild((xmlNodePtr)group, (xmlNodePtr)share); 14033034Sdougm /* need to deal with SMF */ 14043910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 14053910Sdougm if (impl_handle != NULL) { 14063034Sdougm /* 14073034Sdougm * need to remove from old group first and then add to 14083034Sdougm * new group. Ideally, we would do the other order but 14093034Sdougm * need to avoid having the share in two groups at the 14103034Sdougm * same time. 14113034Sdougm */ 14123910Sdougm ret = sa_delete_share(impl_handle->scfhandle, oldgroup, share); 14133910Sdougm if (ret == SA_OK) 14143910Sdougm ret = sa_commit_share(impl_handle->scfhandle, group, share); 14153910Sdougm } else { 14163910Sdougm ret = SA_SYSTEM_ERR; 14173034Sdougm } 14183034Sdougm } 14193034Sdougm return (ret); 14203034Sdougm } 14213034Sdougm 14223034Sdougm /* 14233034Sdougm * sa_get_parent_group(share) 14243034Sdougm * 14253034Sdougm * Return the containg group for the share. If a group was actually 14263034Sdougm * passed in, we don't want a parent so return NULL. 14273034Sdougm */ 14283034Sdougm 14293034Sdougm sa_group_t 14303034Sdougm sa_get_parent_group(sa_share_t share) 14313034Sdougm { 14323034Sdougm xmlNodePtr node = NULL; 14333034Sdougm if (share != NULL) { 14343034Sdougm node = ((xmlNodePtr)share)->parent; 14353034Sdougm /* 14363034Sdougm * make sure parent is a group and not sharecfg since 14373034Sdougm * we may be cheating and passing in a group. 14383034Sdougm * Eventually, groups of groups might come into being. 14393034Sdougm */ 14403034Sdougm if (node == NULL || 14413034Sdougm xmlStrcmp(node->name, (xmlChar *)"sharecfg") == 0) 14423034Sdougm node = NULL; 14433034Sdougm } 14443034Sdougm return ((sa_group_t)node); 14453034Sdougm } 14463034Sdougm 14473034Sdougm /* 14483910Sdougm * _sa_create_group(impl_handle, groupname) 14493034Sdougm * 14503034Sdougm * Create a group in the document. The caller will need to deal with 14513034Sdougm * configuration store and activation. 14523034Sdougm */ 14533034Sdougm 14543034Sdougm sa_group_t 14553910Sdougm _sa_create_group(sa_handle_impl_t impl_handle, char *groupname) 14563034Sdougm { 14573034Sdougm xmlNodePtr node = NULL; 14583034Sdougm 14593034Sdougm if (sa_valid_group_name(groupname)) { 14603910Sdougm node = xmlNewChild(impl_handle->tree, NULL, 14613034Sdougm (xmlChar *)"group", NULL); 14623034Sdougm if (node != NULL) { 14633034Sdougm xmlSetProp(node, (xmlChar *)"name", (xmlChar *)groupname); 14643034Sdougm xmlSetProp(node, (xmlChar *)"state", (xmlChar *)"enabled"); 14653034Sdougm } 14663034Sdougm } 14673034Sdougm return ((sa_group_t)node); 14683034Sdougm } 14693034Sdougm 14703034Sdougm /* 14713034Sdougm * _sa_create_zfs_group(group, groupname) 14723034Sdougm * 14733034Sdougm * Create a ZFS subgroup under the specified group. This may 14743034Sdougm * eventually form the basis of general sub-groups, but is currently 14753034Sdougm * restricted to ZFS. 14763034Sdougm */ 14773034Sdougm sa_group_t 14783034Sdougm _sa_create_zfs_group(sa_group_t group, char *groupname) 14793034Sdougm { 14803034Sdougm xmlNodePtr node = NULL; 14813034Sdougm 14823034Sdougm node = xmlNewChild((xmlNodePtr)group, NULL, 14833034Sdougm (xmlChar *)"group", NULL); 14843034Sdougm if (node != NULL) { 14853034Sdougm xmlSetProp(node, (xmlChar *)"name", (xmlChar *)groupname); 14863034Sdougm xmlSetProp(node, (xmlChar *)"state", (xmlChar *)"enabled"); 14873034Sdougm } 14883034Sdougm 14893034Sdougm return ((sa_group_t)node); 14903034Sdougm } 14913034Sdougm 14923034Sdougm /* 14933034Sdougm * sa_create_group(groupname, *error) 14943034Sdougm * 14953034Sdougm * Create a new group with groupname. Need to validate that it is a 14963034Sdougm * legal name for SMF and the construct the SMF service instance of 14973034Sdougm * svc:/network/shares/group to implement the group. All necessary 14983034Sdougm * operational properties must be added to the group at this point 14993034Sdougm * (via the SMF transaction model). 15003034Sdougm */ 15013034Sdougm sa_group_t 15023910Sdougm sa_create_group(sa_handle_t handle, char *groupname, int *error) 15033034Sdougm { 15043034Sdougm xmlNodePtr node = NULL; 15053034Sdougm sa_group_t group; 15063034Sdougm int ret; 15073034Sdougm char rbacstr[256]; 15083910Sdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle; 15093034Sdougm 15103034Sdougm ret = SA_OK; 15113034Sdougm 15123910Sdougm if (impl_handle == NULL || impl_handle->scfhandle == NULL) { 15133034Sdougm ret = SA_SYSTEM_ERR; 15143034Sdougm goto err; 15153034Sdougm } 15163034Sdougm 15173910Sdougm group = sa_get_group(handle, groupname); 15183034Sdougm if (group != NULL) { 15193034Sdougm ret = SA_DUPLICATE_NAME; 15203034Sdougm } else { 15213034Sdougm if (sa_valid_group_name(groupname)) { 15223910Sdougm node = xmlNewChild(impl_handle->tree, NULL, 15233034Sdougm (xmlChar *)"group", NULL); 15243034Sdougm if (node != NULL) { 15253034Sdougm xmlSetProp(node, (xmlChar *)"name", (xmlChar *)groupname); 15263034Sdougm /* default to the group being enabled */ 15273034Sdougm xmlSetProp(node, (xmlChar *)"state", (xmlChar *)"enabled"); 15283910Sdougm ret = sa_create_instance(impl_handle->scfhandle, groupname); 15293034Sdougm if (ret == SA_OK) { 15303910Sdougm ret = sa_start_transaction(impl_handle->scfhandle, 15313910Sdougm "operation"); 15323034Sdougm } 15333034Sdougm if (ret == SA_OK) { 15343910Sdougm ret = sa_set_property(impl_handle->scfhandle, 15353910Sdougm "state", "enabled"); 15363034Sdougm if (ret == SA_OK) { 15373910Sdougm ret = sa_end_transaction(impl_handle->scfhandle); 15383034Sdougm } else { 15393910Sdougm sa_abort_transaction(impl_handle->scfhandle); 15403034Sdougm } 15413034Sdougm } 15423034Sdougm if (ret == SA_OK) { 15433034Sdougm /* initialize the RBAC strings */ 15443910Sdougm ret = sa_start_transaction(impl_handle->scfhandle, 15453910Sdougm "general"); 15463034Sdougm if (ret == SA_OK) { 15473034Sdougm (void) snprintf(rbacstr, sizeof (rbacstr), "%s.%s", 15483034Sdougm SA_RBAC_MANAGE, groupname); 15493910Sdougm ret = sa_set_property(impl_handle->scfhandle, 15503034Sdougm "action_authorization", 15513034Sdougm rbacstr); 15523034Sdougm } 15533034Sdougm if (ret == SA_OK) { 15543034Sdougm (void) snprintf(rbacstr, sizeof (rbacstr), "%s.%s", 15553034Sdougm SA_RBAC_VALUE, groupname); 15563910Sdougm ret = sa_set_property(impl_handle->scfhandle, 15573034Sdougm "value_authorization", 15583034Sdougm rbacstr); 15593034Sdougm } 15603034Sdougm if (ret == SA_OK) { 15613910Sdougm ret = sa_end_transaction(impl_handle->scfhandle); 15623034Sdougm } else { 15633910Sdougm sa_abort_transaction(impl_handle->scfhandle); 15643034Sdougm } 15653034Sdougm } 15663034Sdougm if (ret != SA_OK) { 15673034Sdougm /* 15683034Sdougm * Couldn't commit the group so we need to 15693034Sdougm * undo internally. 15703034Sdougm */ 15713034Sdougm xmlUnlinkNode(node); 15723034Sdougm xmlFreeNode(node); 15733034Sdougm node = NULL; 15743034Sdougm } 15753034Sdougm } else { 15763034Sdougm ret = SA_NO_MEMORY; 15773034Sdougm } 15783034Sdougm } else { 15793034Sdougm ret = SA_INVALID_NAME; 15803034Sdougm } 15813034Sdougm } 15823034Sdougm err: 15833034Sdougm if (error != NULL) 15843034Sdougm *error = ret; 15853034Sdougm return ((sa_group_t)node); 15863034Sdougm } 15873034Sdougm 15883034Sdougm /* 15893034Sdougm * sa_remove_group(group) 15903034Sdougm * 15913034Sdougm * Remove the specified group. This deletes from the SMF repository. 15923034Sdougm * All property groups and properties are removed. 15933034Sdougm */ 15943034Sdougm 15953034Sdougm int 15963034Sdougm sa_remove_group(sa_group_t group) 15973034Sdougm { 15983034Sdougm char *name; 15993034Sdougm int ret = SA_OK; 16003910Sdougm sa_handle_impl_t impl_handle; 16013034Sdougm 16023910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 16033910Sdougm if (impl_handle != NULL) { 16043910Sdougm name = sa_get_group_attr(group, "name"); 16053910Sdougm if (name != NULL) { 16063910Sdougm ret = sa_delete_instance(impl_handle->scfhandle, name); 16073910Sdougm sa_free_attr_string(name); 16083910Sdougm } 16093910Sdougm xmlUnlinkNode((xmlNodePtr)group); /* make sure unlinked */ 16103910Sdougm xmlFreeNode((xmlNodePtr)group); /* now it is gone */ 16113910Sdougm } else { 16123910Sdougm ret = SA_SYSTEM_ERR; 16133034Sdougm } 16143034Sdougm return (ret); 16153034Sdougm } 16163034Sdougm 16173034Sdougm /* 16183034Sdougm * sa_update_config() 16193034Sdougm * 16203034Sdougm * Used to update legacy files that need to be updated in bulk 16213034Sdougm * Currently, this is a placeholder and will go away in a future 16223034Sdougm * release. 16233034Sdougm */ 16243034Sdougm 16253034Sdougm int 16263910Sdougm sa_update_config(sa_handle_t handle) 16273034Sdougm { 16283034Sdougm /* 16293034Sdougm * do legacy files first so we can tell when they change. 16303034Sdougm * This will go away when we start updating individual records 16313034Sdougm * rather than the whole file. 16323034Sdougm */ 16333910Sdougm update_legacy_config(handle); 16343034Sdougm return (SA_OK); 16353034Sdougm } 16363034Sdougm 16373034Sdougm /* 16383034Sdougm * get_node_attr(node, tag) 16393034Sdougm * 16403034Sdougm * Get the speficied tag(attribute) if it exists on the node. This is 16413034Sdougm * used internally by a number of attribute oriented functions. 16423034Sdougm */ 16433034Sdougm 16443034Sdougm static char * 16453034Sdougm get_node_attr(void *nodehdl, char *tag) 16463034Sdougm { 16473034Sdougm xmlNodePtr node = (xmlNodePtr)nodehdl; 16483034Sdougm xmlChar *name = NULL; 16493034Sdougm 16503034Sdougm if (node != NULL) { 16513034Sdougm name = xmlGetProp(node, (xmlChar *)tag); 16523034Sdougm } 16533034Sdougm return ((char *)name); 16543034Sdougm } 16553034Sdougm 16563034Sdougm /* 16573034Sdougm * get_node_attr(node, tag) 16583034Sdougm * 16593034Sdougm * Set the speficied tag(attribute) to the specified value This is 16603034Sdougm * used internally by a number of attribute oriented functions. It 16613034Sdougm * doesn't update the repository, only the internal document state. 16623034Sdougm */ 16633034Sdougm 16643034Sdougm void 16653034Sdougm set_node_attr(void *nodehdl, char *tag, char *value) 16663034Sdougm { 16673034Sdougm xmlNodePtr node = (xmlNodePtr)nodehdl; 16683034Sdougm if (node != NULL && tag != NULL) { 16693034Sdougm if (value != NULL) { 16703034Sdougm xmlSetProp(node, (xmlChar *)tag, (xmlChar *)value); 16713034Sdougm } else { 16723034Sdougm xmlUnsetProp(node, (xmlChar *)tag); 16733034Sdougm } 16743034Sdougm } 16753034Sdougm } 16763034Sdougm 16773034Sdougm /* 16783034Sdougm * sa_get_group_attr(group, tag) 16793034Sdougm * 16803034Sdougm * Get the specied attribute, if defined, for the group. 16813034Sdougm */ 16823034Sdougm 16833034Sdougm char * 16843034Sdougm sa_get_group_attr(sa_group_t group, char *tag) 16853034Sdougm { 16863034Sdougm return (get_node_attr((void *)group, tag)); 16873034Sdougm } 16883034Sdougm 16893034Sdougm /* 16903034Sdougm * sa_set_group_attr(group, tag, value) 16913034Sdougm * 16923034Sdougm * set the specified tag/attribute on the group using value as its 16933034Sdougm * value. 16943034Sdougm * 16953034Sdougm * This will result in setting the property in the SMF repository as 16963034Sdougm * well as in the internal document. 16973034Sdougm */ 16983034Sdougm 16993034Sdougm int 17003034Sdougm sa_set_group_attr(sa_group_t group, char *tag, char *value) 17013034Sdougm { 17023034Sdougm int ret; 17033034Sdougm char *groupname; 17043910Sdougm sa_handle_impl_t impl_handle; 17053034Sdougm 17063910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 17073910Sdougm if (impl_handle != NULL) { 17083910Sdougm groupname = sa_get_group_attr(group, "name"); 17093910Sdougm ret = sa_get_instance(impl_handle->scfhandle, groupname); 17103034Sdougm if (ret == SA_OK) { 17113910Sdougm set_node_attr((void *)group, tag, value); 17123910Sdougm ret = sa_start_transaction(impl_handle->scfhandle, "operation"); 17133910Sdougm if (ret == SA_OK) { 17143910Sdougm ret = sa_set_property(impl_handle->scfhandle, tag, value); 17153910Sdougm if (ret == SA_OK) 17163910Sdougm (void) sa_end_transaction(impl_handle->scfhandle); 17173910Sdougm else { 17183910Sdougm sa_abort_transaction(impl_handle->scfhandle); 17193910Sdougm } 17203034Sdougm } 17213034Sdougm } 17223910Sdougm if (groupname != NULL) 17233910Sdougm sa_free_attr_string(groupname); 17243910Sdougm } else { 17253910Sdougm ret = SA_SYSTEM_ERR; 17263034Sdougm } 17273034Sdougm return (ret); 17283034Sdougm } 17293034Sdougm 17303034Sdougm /* 17313034Sdougm * sa_get_share_attr(share, tag) 17323034Sdougm * 17333034Sdougm * Return the value of the tag/attribute set on the specified 17343034Sdougm * share. Returns NULL if the tag doesn't exist. 17353034Sdougm */ 17363034Sdougm 17373034Sdougm char * 17383034Sdougm sa_get_share_attr(sa_share_t share, char *tag) 17393034Sdougm { 17403034Sdougm return (get_node_attr((void *)share, tag)); 17413034Sdougm } 17423034Sdougm 17433034Sdougm /* 17443034Sdougm * sa_get_resource(group, resource) 17453034Sdougm * 17463034Sdougm * Search all the shares in the speified group for a share with a 17473034Sdougm * resource name matching the one specified. 17483034Sdougm * 17493034Sdougm * In the future, it may be advantageous to allow group to be NULL and 17503034Sdougm * search all groups but that isn't needed at present. 17513034Sdougm */ 17523034Sdougm 17533034Sdougm sa_share_t 17543034Sdougm sa_get_resource(sa_group_t group, char *resource) 17553034Sdougm { 17563034Sdougm sa_share_t share = NULL; 17573034Sdougm char *name = NULL; 17583034Sdougm 17593034Sdougm if (resource != NULL) { 17603034Sdougm for (share = sa_get_share(group, NULL); share != NULL; 17613034Sdougm share = sa_get_next_share(share)) { 17623034Sdougm name = sa_get_share_attr(share, "resource"); 17633034Sdougm if (name != NULL) { 17643034Sdougm if (strcmp(name, resource) == 0) 17653034Sdougm break; 17663034Sdougm sa_free_attr_string(name); 17673034Sdougm name = NULL; 17683034Sdougm } 17693034Sdougm } 17703034Sdougm if (name != NULL) 17713034Sdougm sa_free_attr_string(name); 17723034Sdougm } 17733034Sdougm return ((sa_share_t)share); 17743034Sdougm } 17753034Sdougm 17763034Sdougm /* 17773034Sdougm * _sa_set_share_description(share, description) 17783034Sdougm * 17793034Sdougm * Add a description tag with text contents to the specified share. 17803034Sdougm * A separate XML tag is used rather than a property. 17813034Sdougm */ 17823034Sdougm 17833034Sdougm xmlNodePtr 17843034Sdougm _sa_set_share_description(sa_share_t share, char *content) 17853034Sdougm { 17863034Sdougm xmlNodePtr node; 17873034Sdougm node = xmlNewChild((xmlNodePtr)share, 17883034Sdougm NULL, (xmlChar *)"description", NULL); 17893034Sdougm xmlNodeSetContent(node, (xmlChar *)content); 17903034Sdougm return (node); 17913034Sdougm } 17923034Sdougm 17933034Sdougm /* 17943034Sdougm * sa_set_share_attr(share, tag, value) 17953034Sdougm * 17963034Sdougm * Set the share attribute specified by tag to the specified value. In 17973034Sdougm * the case of "resource", enforce a no duplicates in a group rule. If 17983034Sdougm * the share is not transient, commit the changes to the repository 17993034Sdougm * else just update the share internally. 18003034Sdougm */ 18013034Sdougm 18023034Sdougm int 18033034Sdougm sa_set_share_attr(sa_share_t share, char *tag, char *value) 18043034Sdougm { 18053034Sdougm sa_group_t group; 18063034Sdougm sa_share_t resource; 18073034Sdougm int ret = SA_OK; 18083034Sdougm 18093034Sdougm group = sa_get_parent_group(share); 18103034Sdougm 18113034Sdougm /* 18123034Sdougm * There are some attributes that may have specific 18133034Sdougm * restrictions on them. Initially, only "resource" has 18143034Sdougm * special meaning that needs to be checked. Only one instance 18153034Sdougm * of a resource name may exist within a group. 18163034Sdougm */ 18173034Sdougm 18183034Sdougm if (strcmp(tag, "resource") == 0) { 18193034Sdougm resource = sa_get_resource(group, value); 18203034Sdougm if (resource != share && resource != NULL) 18213034Sdougm ret = SA_DUPLICATE_NAME; 18223034Sdougm } 18233034Sdougm if (ret == SA_OK) { 18243034Sdougm set_node_attr((void *)share, tag, value); 18253034Sdougm if (group != NULL) { 18263034Sdougm char *type; 18273034Sdougm /* we can probably optimize this some */ 18283034Sdougm type = sa_get_share_attr(share, "type"); 18293910Sdougm if (type == NULL || strcmp(type, "transient") != 0) { 18303910Sdougm sa_handle_impl_t impl_handle; 18313910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 18323910Sdougm if (impl_handle != NULL) 18333910Sdougm ret = sa_commit_share(impl_handle->scfhandle, 18343910Sdougm group, share); 18353910Sdougm else 18363910Sdougm ret = SA_SYSTEM_ERR; 18373910Sdougm } 18383034Sdougm if (type != NULL) 18393034Sdougm sa_free_attr_string(type); 18403034Sdougm } 18413034Sdougm } 18423034Sdougm return (ret); 18433034Sdougm } 18443034Sdougm 18453034Sdougm /* 18463034Sdougm * sa_get_property_attr(prop, tag) 18473034Sdougm * 18483034Sdougm * Get the value of the specified property attribute. Standard 18493034Sdougm * attributes are "type" and "value". 18503034Sdougm */ 18513034Sdougm 18523034Sdougm char * 18533034Sdougm sa_get_property_attr(sa_property_t prop, char *tag) 18543034Sdougm { 18553034Sdougm return (get_node_attr((void *)prop, tag)); 18563034Sdougm } 18573034Sdougm 18583034Sdougm /* 18593034Sdougm * sa_get_optionset_attr(prop, tag) 18603034Sdougm * 18613034Sdougm * Get the value of the specified property attribute. Standard 18623034Sdougm * attribute is "type". 18633034Sdougm */ 18643034Sdougm 18653034Sdougm char * 18663034Sdougm sa_get_optionset_attr(sa_property_t optionset, char *tag) 18673034Sdougm { 18683034Sdougm return (get_node_attr((void *)optionset, tag)); 18693034Sdougm 18703034Sdougm } 18713034Sdougm 18723034Sdougm /* 18733034Sdougm * sa_set_optionset_attr(optionset, tag, value) 18743034Sdougm * 18753034Sdougm * Set the specified attribute(tag) to the specified value on the 18763034Sdougm * optionset. 18773034Sdougm */ 18783034Sdougm 18793034Sdougm void 18803034Sdougm sa_set_optionset_attr(sa_group_t optionset, char *tag, char *value) 18813034Sdougm { 18823034Sdougm set_node_attr((void *)optionset, tag, value); 18833034Sdougm } 18843034Sdougm 18853034Sdougm /* 18863034Sdougm * sa_free_attr_string(string) 18873034Sdougm * 18883034Sdougm * Free the string that was returned in one of the sa_get_*_attr() 18893034Sdougm * functions. 18903034Sdougm */ 18913034Sdougm 18923034Sdougm void 18933034Sdougm sa_free_attr_string(char *string) 18943034Sdougm { 18953034Sdougm xmlFree((xmlChar *)string); 18963034Sdougm } 18973034Sdougm 18983034Sdougm /* 18993034Sdougm * sa_get_optionset(group, proto) 19003034Sdougm * 19013034Sdougm * Return the optionset, if it exists, that is associated with the 19023034Sdougm * specified protocol. 19033034Sdougm */ 19043034Sdougm 19053034Sdougm sa_optionset_t 19063034Sdougm sa_get_optionset(void *group, char *proto) 19073034Sdougm { 19083034Sdougm xmlNodePtr node; 19093034Sdougm xmlChar *value = NULL; 19103034Sdougm 19113034Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 19123034Sdougm node = node->next) { 19133034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) { 19143034Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 19153034Sdougm if (proto != NULL) { 19163034Sdougm if (value != NULL && 19173034Sdougm xmlStrcmp(value, (xmlChar *)proto) == 0) { 19183034Sdougm break; 19193034Sdougm } 19203034Sdougm if (value != NULL) { 19213034Sdougm xmlFree(value); 19223034Sdougm value = NULL; 19233034Sdougm } 19243034Sdougm } else { 19253034Sdougm break; 19263034Sdougm } 19273034Sdougm } 19283034Sdougm } 19293034Sdougm if (value != NULL) 19303034Sdougm xmlFree(value); 19313034Sdougm return ((sa_optionset_t)node); 19323034Sdougm } 19333034Sdougm 19343034Sdougm /* 19353034Sdougm * sa_get_next_optionset(optionset) 19363034Sdougm * 19373034Sdougm * Return the next optionset in the group. NULL if this was the last. 19383034Sdougm */ 19393034Sdougm 19403034Sdougm sa_optionset_t 19413034Sdougm sa_get_next_optionset(sa_optionset_t optionset) 19423034Sdougm { 19433034Sdougm xmlNodePtr node; 19443034Sdougm 19453034Sdougm for (node = ((xmlNodePtr)optionset)->next; node != NULL; 19463034Sdougm node = node->next) { 19473034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) { 19483034Sdougm break; 19493034Sdougm } 19503034Sdougm } 19513034Sdougm return ((sa_optionset_t)node); 19523034Sdougm } 19533034Sdougm 19543034Sdougm /* 19553034Sdougm * sa_get_security(group, sectype, proto) 19563034Sdougm * 19573034Sdougm * Return the security optionset. The internal name is a hold over 19583034Sdougm * from the implementation and will be changed before the API is 19593034Sdougm * finalized. This is really a named optionset that can be negotiated 19603034Sdougm * as a group of properties (like NFS security options). 19613034Sdougm */ 19623034Sdougm 19633034Sdougm sa_security_t 19643034Sdougm sa_get_security(sa_group_t group, char *sectype, char *proto) 19653034Sdougm { 19663034Sdougm xmlNodePtr node; 19673034Sdougm xmlChar *value = NULL; 19683034Sdougm 19693034Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 19703034Sdougm node = node->next) { 19713034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) { 19723034Sdougm if (proto != NULL) { 19733034Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 19743034Sdougm if (value == NULL || 19753034Sdougm (value != NULL && 19763034Sdougm xmlStrcmp(value, (xmlChar *)proto) != 0)) { 19773034Sdougm /* it doesn't match so continue */ 19783034Sdougm xmlFree(value); 19793034Sdougm value = NULL; 19803034Sdougm continue; 19813034Sdougm } 19823034Sdougm } 19833034Sdougm if (value != NULL) { 19843034Sdougm xmlFree(value); 19853034Sdougm value = NULL; 19863034Sdougm } 19873034Sdougm /* potential match */ 19883034Sdougm if (sectype != NULL) { 19893034Sdougm value = xmlGetProp(node, (xmlChar *)"sectype"); 19903034Sdougm if (value != NULL && 19913034Sdougm xmlStrcmp(value, (xmlChar *)sectype) == 0) { 19923034Sdougm break; 19933034Sdougm } 19943034Sdougm } else { 19953034Sdougm break; 19963034Sdougm } 19973034Sdougm } 19983034Sdougm if (value != NULL) { 19993034Sdougm xmlFree(value); 20003034Sdougm value = NULL; 20013034Sdougm } 20023034Sdougm } 20033034Sdougm if (value != NULL) 20043034Sdougm xmlFree(value); 20053034Sdougm return ((sa_security_t)node); 20063034Sdougm } 20073034Sdougm 20083034Sdougm /* 20093034Sdougm * sa_get_next_security(security) 20103034Sdougm * 20113034Sdougm * Get the next security optionset if one exists. 20123034Sdougm */ 20133034Sdougm 20143034Sdougm sa_security_t 20153034Sdougm sa_get_next_security(sa_security_t security) 20163034Sdougm { 20173034Sdougm xmlNodePtr node; 20183034Sdougm 20193034Sdougm for (node = ((xmlNodePtr)security)->next; node != NULL; 20203034Sdougm node = node->next) { 20213034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) { 20223034Sdougm break; 20233034Sdougm } 20243034Sdougm } 20253034Sdougm return ((sa_security_t)node); 20263034Sdougm } 20273034Sdougm 20283034Sdougm /* 20293034Sdougm * sa_get_property(optionset, prop) 20303034Sdougm * 20313034Sdougm * Get the property object with the name specified in prop from the 20323034Sdougm * optionset. 20333034Sdougm */ 20343034Sdougm 20353034Sdougm sa_property_t 20363034Sdougm sa_get_property(sa_optionset_t optionset, char *prop) 20373034Sdougm { 20383034Sdougm xmlNodePtr node = (xmlNodePtr)optionset; 20393034Sdougm xmlChar *value = NULL; 20403034Sdougm 20413034Sdougm if (optionset == NULL) 20423034Sdougm return (NULL); 20433034Sdougm 20443034Sdougm for (node = node->children; node != NULL; 20453034Sdougm node = node->next) { 20463034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 20473034Sdougm if (prop == NULL) 20483034Sdougm break; 20493034Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 20503034Sdougm if (value != NULL && xmlStrcmp(value, (xmlChar *)prop) == 0) { 20513034Sdougm break; 20523034Sdougm } 20533034Sdougm if (value != NULL) { 20543034Sdougm xmlFree(value); 20553034Sdougm value = NULL; 20563034Sdougm } 20573034Sdougm } 20583034Sdougm } 20593034Sdougm if (value != NULL) 20603034Sdougm xmlFree(value); 20613034Sdougm if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"option") != 0) { 20623034Sdougm /* avoid a non option node -- it is possible to be a text node */ 20633034Sdougm node = NULL; 20643034Sdougm } 20653034Sdougm return ((sa_property_t)node); 20663034Sdougm } 20673034Sdougm 20683034Sdougm /* 20693034Sdougm * sa_get_next_property(property) 20703034Sdougm * 20713034Sdougm * Get the next property following the specified property. NULL if 20723034Sdougm * this was the last. 20733034Sdougm */ 20743034Sdougm 20753034Sdougm sa_property_t 20763034Sdougm sa_get_next_property(sa_property_t property) 20773034Sdougm { 20783034Sdougm xmlNodePtr node; 20793034Sdougm 20803034Sdougm for (node = ((xmlNodePtr)property)->next; node != NULL; 20813034Sdougm node = node->next) { 20823034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 20833034Sdougm break; 20843034Sdougm } 20853034Sdougm } 20863034Sdougm return ((sa_property_t)node); 20873034Sdougm } 20883034Sdougm 20893034Sdougm /* 20903034Sdougm * sa_set_share_description(share, content) 20913034Sdougm * 20923034Sdougm * Set the description of share to content. 20933034Sdougm */ 20943034Sdougm 20953034Sdougm int 20963034Sdougm sa_set_share_description(sa_share_t share, char *content) 20973034Sdougm { 20983034Sdougm xmlNodePtr node; 20993034Sdougm sa_group_t group; 21003034Sdougm int ret = SA_OK; 21013034Sdougm 21023034Sdougm for (node = ((xmlNodePtr)share)->children; node != NULL; 21033034Sdougm node = node->next) { 21043034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 21053034Sdougm break; 21063034Sdougm } 21073034Sdougm } 21083034Sdougm group = sa_get_parent_group(share); 21093034Sdougm /* no existing description but want to add */ 21103034Sdougm if (node == NULL && content != NULL) { 21113034Sdougm /* add a description */ 21123034Sdougm node = _sa_set_share_description(share, content); 21133034Sdougm } else if (node != NULL && content != NULL) { 21143034Sdougm /* update a description */ 21153034Sdougm xmlNodeSetContent(node, (xmlChar *)content); 21163034Sdougm } else if (node != NULL && content == NULL) { 21173034Sdougm /* remove an existing description */ 21183034Sdougm xmlUnlinkNode(node); 21193034Sdougm xmlFreeNode(node); 21203034Sdougm } 21213910Sdougm if (group != NULL && is_persistent((sa_group_t)share)) { 21223910Sdougm sa_handle_impl_t impl_handle; 21233910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 21243910Sdougm if (impl_handle != NULL) 21253910Sdougm ret = sa_commit_share(impl_handle->scfhandle, group, share); 21263910Sdougm else 21273910Sdougm ret = SA_SYSTEM_ERR; 21283910Sdougm } 21293034Sdougm return (ret); 21303034Sdougm } 21313034Sdougm 21323034Sdougm /* 21333034Sdougm * fixproblemchars(string) 21343034Sdougm * 21353034Sdougm * don't want any newline or tab characters in the text since these 21363034Sdougm * could break display of data and legacy file formats. 21373034Sdougm */ 21383034Sdougm static void 21393034Sdougm fixproblemchars(char *str) 21403034Sdougm { 21413034Sdougm int c; 21423034Sdougm for (c = *str; c != '\0'; c = *++str) { 21433034Sdougm if (c == '\t' || c == '\n') 21443034Sdougm *str = ' '; 21453034Sdougm else if (c == '"') 21463034Sdougm *str = '\''; 21473034Sdougm } 21483034Sdougm } 21493034Sdougm 21503034Sdougm /* 21513034Sdougm * sa_get_share_description(share) 21523034Sdougm * 21533034Sdougm * Return the description text for the specified share if it 21543034Sdougm * exists. NULL if no description exists. 21553034Sdougm */ 21563034Sdougm 21573034Sdougm char * 21583034Sdougm sa_get_share_description(sa_share_t share) 21593034Sdougm { 21603034Sdougm xmlChar *description = NULL; 21613034Sdougm xmlNodePtr node; 21623034Sdougm 21633034Sdougm for (node = ((xmlNodePtr)share)->children; node != NULL; 21643034Sdougm node = node->next) { 21653034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 21663034Sdougm break; 21673034Sdougm } 21683034Sdougm } 21693034Sdougm if (node != NULL) { 21703034Sdougm description = xmlNodeGetContent((xmlNodePtr)share); 21713034Sdougm fixproblemchars((char *)description); 21723034Sdougm } 21733034Sdougm return ((char *)description); 21743034Sdougm } 21753034Sdougm 21763034Sdougm /* 21773034Sdougm * sa_free(share_description(description) 21783034Sdougm * 21793034Sdougm * Free the description string. 21803034Sdougm */ 21813034Sdougm 21823034Sdougm void 21833034Sdougm sa_free_share_description(char *description) 21843034Sdougm { 21853034Sdougm xmlFree((xmlChar *)description); 21863034Sdougm } 21873034Sdougm 21883034Sdougm /* 21893034Sdougm * sa_create_optionset(group, proto) 21903034Sdougm * 21913034Sdougm * Create an optionset for the specified protocol in the specied 21923034Sdougm * group. This is manifested as a property group within SMF. 21933034Sdougm */ 21943034Sdougm 21953034Sdougm sa_optionset_t 21963034Sdougm sa_create_optionset(sa_group_t group, char *proto) 21973034Sdougm { 21983034Sdougm sa_optionset_t optionset; 21993034Sdougm sa_group_t parent = group; 22003034Sdougm 22013034Sdougm optionset = sa_get_optionset(group, proto); 22023034Sdougm if (optionset != NULL) { 22033034Sdougm /* can't have a duplicate protocol */ 22043034Sdougm optionset = NULL; 22053034Sdougm } else { 22063034Sdougm optionset = (sa_optionset_t)xmlNewChild((xmlNodePtr)group, 22073034Sdougm NULL, 22083034Sdougm (xmlChar *)"optionset", 22093034Sdougm NULL); 22103034Sdougm /* 22113034Sdougm * only put to repository if on a group and we were 22123034Sdougm * able to create an optionset. 22133034Sdougm */ 22143034Sdougm if (optionset != NULL) { 22153034Sdougm char oname[256]; 22163034Sdougm char *groupname; 22173034Sdougm char *id = NULL; 22183034Sdougm 22193034Sdougm if (sa_is_share(group)) 22203034Sdougm parent = sa_get_parent_group((sa_share_t)group); 22213034Sdougm 22223034Sdougm sa_set_optionset_attr(optionset, "type", proto); 22233034Sdougm 22243034Sdougm if (sa_is_share(group)) { 22253034Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 22263034Sdougm } 22273034Sdougm (void) sa_optionset_name(optionset, oname, 22283034Sdougm sizeof (oname), id); 22293034Sdougm groupname = sa_get_group_attr(parent, "name"); 22303034Sdougm if (groupname != NULL && is_persistent(group)) { 22313910Sdougm sa_handle_impl_t impl_handle; 22323910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 22333910Sdougm assert(impl_handle != NULL); 22343910Sdougm if (impl_handle != NULL) { 22353910Sdougm (void) sa_get_instance(impl_handle->scfhandle, 22363910Sdougm groupname); 22373910Sdougm (void) sa_create_pgroup(impl_handle->scfhandle, oname); 22383910Sdougm } 22393034Sdougm } 22403910Sdougm if (groupname != NULL) 22413910Sdougm sa_free_attr_string(groupname); 22423034Sdougm if (id != NULL) 22433034Sdougm sa_free_attr_string(id); 22443034Sdougm } 22453034Sdougm } 22463034Sdougm return (optionset); 22473034Sdougm } 22483034Sdougm 22493034Sdougm /* 22503034Sdougm * sa_get_property_parent(property) 22513034Sdougm * 22523034Sdougm * Given a property, return the object it is a property of. This will 22533034Sdougm * be an optionset of some type. 22543034Sdougm */ 22553034Sdougm 22563034Sdougm static sa_optionset_t 22573034Sdougm sa_get_property_parent(sa_property_t property) 22583034Sdougm { 22593034Sdougm xmlNodePtr node = NULL; 22603034Sdougm 22613034Sdougm if (property != NULL) { 22623034Sdougm node = ((xmlNodePtr)property)->parent; 22633034Sdougm } 22643034Sdougm return ((sa_optionset_t)node); 22653034Sdougm } 22663034Sdougm 22673034Sdougm /* 22683034Sdougm * sa_get_optionset_parent(optionset) 22693034Sdougm * 22703034Sdougm * Return the parent of the specified optionset. This could be a group 22713034Sdougm * or a share. 22723034Sdougm */ 22733034Sdougm 22743034Sdougm static sa_group_t 22753034Sdougm sa_get_optionset_parent(sa_optionset_t optionset) 22763034Sdougm { 22773034Sdougm xmlNodePtr node = NULL; 22783034Sdougm 22793034Sdougm if (optionset != NULL) { 22803034Sdougm node = ((xmlNodePtr)optionset)->parent; 22813034Sdougm } 22823034Sdougm return ((sa_group_t)node); 22833034Sdougm } 22843034Sdougm 22853034Sdougm /* 22863034Sdougm * zfs_needs_update(share) 22873034Sdougm * 22883034Sdougm * In order to avoid making multiple updates to a ZFS share when 22893034Sdougm * setting properties, the share attribute "changed" will be set to 22903034Sdougm * true when a property is added or modifed. When done adding 22913034Sdougm * properties, we can then detect that an update is needed. We then 22923034Sdougm * clear the state here to detect additional changes. 22933034Sdougm */ 22943034Sdougm 22953034Sdougm static int 22963034Sdougm zfs_needs_update(sa_share_t share) 22973034Sdougm { 22983034Sdougm char *attr; 22993034Sdougm int result = 0; 23003034Sdougm 23013034Sdougm attr = sa_get_share_attr(share, "changed"); 23023034Sdougm if (attr != NULL) { 23033034Sdougm sa_free_attr_string(attr); 23043034Sdougm result = 1; 23053034Sdougm } 23063034Sdougm set_node_attr((void *)share, "changed", NULL); 23073034Sdougm return (result); 23083034Sdougm } 23093034Sdougm 23103034Sdougm /* 23113034Sdougm * zfs_set_update(share) 23123034Sdougm * 23133034Sdougm * Set the changed attribute of the share to true. 23143034Sdougm */ 23153034Sdougm 23163034Sdougm static void 23173034Sdougm zfs_set_update(sa_share_t share) 23183034Sdougm { 23193034Sdougm set_node_attr((void *)share, "changed", "true"); 23203034Sdougm } 23213034Sdougm 23223034Sdougm /* 23233034Sdougm * sa_commit_properties(optionset, clear) 23243034Sdougm * 23253034Sdougm * Check if SMF or ZFS config and either update or abort the pending 23263034Sdougm * changes. 23273034Sdougm */ 23283034Sdougm 23293034Sdougm int 23303034Sdougm sa_commit_properties(sa_optionset_t optionset, int clear) 23313034Sdougm { 23323034Sdougm sa_group_t group; 23333034Sdougm sa_group_t parent; 23343034Sdougm int zfs = 0; 23353034Sdougm int needsupdate = 0; 23363034Sdougm int ret = SA_OK; 23373910Sdougm sa_handle_impl_t impl_handle; 23383034Sdougm 23393034Sdougm group = sa_get_optionset_parent(optionset); 23403034Sdougm if (group != NULL && (sa_is_share(group) || is_zfs_group(group))) { 23413034Sdougm /* only update ZFS if on a share */ 23423034Sdougm parent = sa_get_parent_group(group); 23433034Sdougm zfs++; 23443034Sdougm if (parent != NULL && is_zfs_group(parent)) { 23453034Sdougm needsupdate = zfs_needs_update(group); 23463034Sdougm } else { 23473034Sdougm zfs = 0; 23483034Sdougm } 23493034Sdougm } 23503034Sdougm if (zfs) { 23513034Sdougm if (!clear && needsupdate) 23523034Sdougm ret = sa_zfs_update((sa_share_t)group); 23533034Sdougm } else { 23543910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 23553910Sdougm if (impl_handle != NULL) { 23563910Sdougm if (clear) 23573910Sdougm (void) sa_abort_transaction(impl_handle->scfhandle); 23583910Sdougm else 23593910Sdougm ret = sa_end_transaction(impl_handle->scfhandle); 23603910Sdougm } else { 23613910Sdougm ret = SA_SYSTEM_ERR; 23623910Sdougm } 23633034Sdougm } 23643034Sdougm return (ret); 23653034Sdougm } 23663034Sdougm 23673034Sdougm /* 23683034Sdougm * sa_destroy_optionset(optionset) 23693034Sdougm * 23703034Sdougm * Remove the optionset from its group. Update the repostory to 23713034Sdougm * reflect this change. 23723034Sdougm */ 23733034Sdougm 23743034Sdougm int 23753034Sdougm sa_destroy_optionset(sa_optionset_t optionset) 23763034Sdougm { 23773034Sdougm char name[256]; 23783034Sdougm int len; 23793034Sdougm int ret; 23803034Sdougm char *id = NULL; 23813034Sdougm sa_group_t group; 23823034Sdougm int ispersist = 1; 23833034Sdougm 23843034Sdougm /* now delete the prop group */ 23853034Sdougm group = sa_get_optionset_parent(optionset); 23863034Sdougm if (group != NULL && sa_is_share(group)) { 23873034Sdougm ispersist = is_persistent(group); 23883034Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 23893034Sdougm } 23903034Sdougm if (ispersist) { 23913910Sdougm sa_handle_impl_t impl_handle; 23923034Sdougm len = sa_optionset_name(optionset, name, sizeof (name), id); 23933910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 23943910Sdougm if (impl_handle != NULL) { 23953910Sdougm if (len > 0) { 23963910Sdougm ret = sa_delete_pgroup(impl_handle->scfhandle, name); 23973910Sdougm } 23983910Sdougm } else { 23993910Sdougm ret = SA_SYSTEM_ERR; 24003034Sdougm } 24013034Sdougm } 24023034Sdougm xmlUnlinkNode((xmlNodePtr)optionset); 24033034Sdougm xmlFreeNode((xmlNodePtr)optionset); 24043034Sdougm if (id != NULL) 24053034Sdougm sa_free_attr_string(id); 24063034Sdougm return (ret); 24073034Sdougm } 24083034Sdougm 24093034Sdougm /* private to the implementation */ 24103034Sdougm int 24113034Sdougm _sa_remove_optionset(sa_optionset_t optionset) 24123034Sdougm { 24133034Sdougm int ret = SA_OK; 24143034Sdougm 24153034Sdougm xmlUnlinkNode((xmlNodePtr)optionset); 24163034Sdougm xmlFreeNode((xmlNodePtr)optionset); 24173034Sdougm return (ret); 24183034Sdougm } 24193034Sdougm 24203034Sdougm /* 24213034Sdougm * sa_create_security(group, sectype, proto) 24223034Sdougm * 24233034Sdougm * Create a security optionset (one that has a type name and a 24243034Sdougm * proto). Security is left over from a pure NFS implementation. The 24253034Sdougm * naming will change in the future when the API is released. 24263034Sdougm */ 24273034Sdougm sa_security_t 24283034Sdougm sa_create_security(sa_group_t group, char *sectype, char *proto) 24293034Sdougm { 24303034Sdougm sa_security_t security; 24313034Sdougm char *id = NULL; 24323034Sdougm sa_group_t parent; 24333034Sdougm char *groupname = NULL; 24343034Sdougm 24353034Sdougm if (group != NULL && sa_is_share(group)) { 24363034Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 24373034Sdougm parent = sa_get_parent_group(group); 24383034Sdougm if (parent != NULL) 24393034Sdougm groupname = sa_get_group_attr(parent, "name"); 24403034Sdougm } else if (group != NULL) { 24413034Sdougm groupname = sa_get_group_attr(group, "name"); 24423034Sdougm } 24433034Sdougm 24443034Sdougm security = sa_get_security(group, sectype, proto); 24453034Sdougm if (security != NULL) { 24463034Sdougm /* can't have a duplicate security option */ 24473034Sdougm security = NULL; 24483034Sdougm } else { 24493034Sdougm security = (sa_security_t)xmlNewChild((xmlNodePtr)group, 24503034Sdougm NULL, 24513034Sdougm (xmlChar *)"security", 24523034Sdougm NULL); 24533034Sdougm if (security != NULL) { 24543034Sdougm char oname[256]; 24553034Sdougm sa_set_security_attr(security, "type", proto); 24563034Sdougm 24573034Sdougm sa_set_security_attr(security, "sectype", sectype); 24583034Sdougm (void) sa_security_name(security, oname, 24593034Sdougm sizeof (oname), id); 24603034Sdougm if (groupname != NULL && is_persistent(group)) { 24613910Sdougm sa_handle_impl_t impl_handle; 24623910Sdougm impl_handle = 24633910Sdougm (sa_handle_impl_t)sa_find_group_handle(group); 24643910Sdougm if (impl_handle != NULL) { 24653910Sdougm (void) sa_get_instance(impl_handle->scfhandle, 24663910Sdougm groupname); 24673910Sdougm (void) sa_create_pgroup(impl_handle->scfhandle, 24683910Sdougm oname); 24693910Sdougm } 24703034Sdougm } 24713034Sdougm } 24723034Sdougm } 24733034Sdougm if (groupname != NULL) 24743034Sdougm sa_free_attr_string(groupname); 24753034Sdougm return (security); 24763034Sdougm } 24773034Sdougm 24783034Sdougm /* 24793034Sdougm * sa_destroy_security(security) 24803034Sdougm * 24813034Sdougm * Remove the specified optionset from the document and the 24823034Sdougm * configuration. 24833034Sdougm */ 24843034Sdougm 24853034Sdougm int 24863034Sdougm sa_destroy_security(sa_security_t security) 24873034Sdougm { 24883034Sdougm char name[256]; 24893034Sdougm int len; 24903034Sdougm int ret = SA_OK; 24913034Sdougm char *id = NULL; 24923034Sdougm sa_group_t group; 24933034Sdougm int iszfs = 0; 24943034Sdougm int ispersist = 1; 24953034Sdougm 24963034Sdougm group = sa_get_optionset_parent(security); 24973034Sdougm 24983034Sdougm if (group != NULL) 24993034Sdougm iszfs = sa_group_is_zfs(group); 25003034Sdougm 25013034Sdougm if (group != NULL && !iszfs) { 25023034Sdougm if (sa_is_share(group)) 25033034Sdougm ispersist = is_persistent(group); 25043034Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 25053034Sdougm } 25063034Sdougm if (ispersist) { 25073034Sdougm len = sa_security_name(security, name, sizeof (name), id); 25083034Sdougm if (!iszfs && len > 0) { 25093910Sdougm sa_handle_impl_t impl_handle; 25103910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 25113910Sdougm if (impl_handle != NULL) { 25123910Sdougm ret = sa_delete_pgroup(impl_handle->scfhandle, name); 25133910Sdougm } else { 25143910Sdougm ret = SA_SYSTEM_ERR; 25153910Sdougm } 25163034Sdougm } 25173034Sdougm } 25183034Sdougm xmlUnlinkNode((xmlNodePtr)security); 25193034Sdougm xmlFreeNode((xmlNodePtr)security); 25203034Sdougm if (iszfs) { 25213034Sdougm ret = sa_zfs_update(group); 25223034Sdougm } 25233034Sdougm if (id != NULL) 25243034Sdougm sa_free_attr_string(id); 25253034Sdougm return (ret); 25263034Sdougm } 25273034Sdougm 25283034Sdougm /* 25293034Sdougm * sa_get_security_attr(optionset, tag) 25303034Sdougm * 25313034Sdougm * Return the specified attribute value from the optionset. 25323034Sdougm */ 25333034Sdougm 25343034Sdougm char * 25353034Sdougm sa_get_security_attr(sa_property_t optionset, char *tag) 25363034Sdougm { 25373034Sdougm return (get_node_attr((void *)optionset, tag)); 25383034Sdougm 25393034Sdougm } 25403034Sdougm 25413034Sdougm /* 25423034Sdougm * sa_set_security_attr(optionset, tag, value) 25433034Sdougm * 25443034Sdougm * Set the optioset attribute specied by tag to the specified value. 25453034Sdougm */ 25463034Sdougm 25473034Sdougm void 25483034Sdougm sa_set_security_attr(sa_group_t optionset, char *tag, char *value) 25493034Sdougm { 25503034Sdougm set_node_attr((void *)optionset, tag, value); 25513034Sdougm } 25523034Sdougm 25533034Sdougm /* 25543034Sdougm * is_nodetype(node, type) 25553034Sdougm * 25563034Sdougm * Check to see if node is of the type specified. 25573034Sdougm */ 25583034Sdougm 25593034Sdougm static int 25603034Sdougm is_nodetype(void *node, char *type) 25613034Sdougm { 25623034Sdougm return (strcmp((char *)((xmlNodePtr)node)->name, type) == 0); 25633034Sdougm } 25643034Sdougm 25653034Sdougm /* 25663034Sdougm * sa_set_prop_by_prop(optionset, group, prop, type) 25673034Sdougm * 25683034Sdougm * Add/remove/update the specified property prop into the optionset or 25693034Sdougm * share. If a share, sort out which property group based on GUID. In 25703034Sdougm * all cases, the appropriate transaction is set (or ZFS share is 25713034Sdougm * marked as needing an update) 25723034Sdougm */ 25733034Sdougm 25743034Sdougm #define SA_PROP_OP_REMOVE 1 25753034Sdougm #define SA_PROP_OP_ADD 2 25763034Sdougm #define SA_PROP_OP_UPDATE 3 25773034Sdougm static int 25783034Sdougm sa_set_prop_by_prop(sa_optionset_t optionset, sa_group_t group, 25793034Sdougm sa_property_t prop, int type) 25803034Sdougm { 25813034Sdougm char *name; 25823034Sdougm char *valstr; 25833034Sdougm int ret = SA_OK; 25843034Sdougm scf_transaction_entry_t *entry; 25853034Sdougm scf_value_t *value; 25863034Sdougm int opttype; /* 1 == optionset, 0 == security */ 25873034Sdougm char *id = NULL; 25883034Sdougm int iszfs = 0; 25893034Sdougm int isshare = 0; 25903034Sdougm sa_group_t parent = NULL; 25913910Sdougm sa_handle_impl_t impl_handle; 25923910Sdougm scfutilhandle_t *scf_handle; 25933034Sdougm 25943034Sdougm if (!is_persistent(group)) { 25953034Sdougm /* 25963034Sdougm * if the group/share is not persistent we don't need 25973034Sdougm * to do anything here 25983034Sdougm */ 25993034Sdougm return (SA_OK); 26003034Sdougm } 26013910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 26023910Sdougm if (impl_handle == NULL || impl_handle->scfhandle == NULL) { 26033910Sdougm return (SA_SYSTEM_ERR); 26043910Sdougm } 26053910Sdougm scf_handle = impl_handle->scfhandle; 26063034Sdougm name = sa_get_property_attr(prop, "type"); 26073034Sdougm valstr = sa_get_property_attr(prop, "value"); 26083034Sdougm entry = scf_entry_create(scf_handle->handle); 26093034Sdougm opttype = is_nodetype((void *)optionset, "optionset"); 26103034Sdougm 26113034Sdougm if (valstr != NULL && entry != NULL) { 26123034Sdougm if (sa_is_share(group)) { 26133034Sdougm isshare = 1; 26143034Sdougm parent = sa_get_parent_group(group); 26153034Sdougm if (parent != NULL) { 26163034Sdougm iszfs = is_zfs_group(parent); 26173034Sdougm } 26183034Sdougm } else { 26193034Sdougm iszfs = is_zfs_group(group); 26203034Sdougm } 26213034Sdougm if (!iszfs) { 26223910Sdougm if (scf_handle->trans == NULL) { 26233910Sdougm char oname[256]; 26243910Sdougm char *groupname = NULL; 26253910Sdougm if (isshare) { 26263910Sdougm if (parent != NULL) { 26273910Sdougm groupname = sa_get_group_attr(parent, "name"); 26283910Sdougm } 26293910Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 26303910Sdougm } else { 26313910Sdougm groupname = sa_get_group_attr(group, "name"); 26323034Sdougm } 26333910Sdougm if (groupname != NULL) { 26343910Sdougm ret = sa_get_instance(scf_handle, groupname); 26353910Sdougm sa_free_attr_string(groupname); 26363910Sdougm } 26373910Sdougm if (opttype) 26383910Sdougm (void) sa_optionset_name(optionset, oname, 26393034Sdougm sizeof (oname), id); 26403910Sdougm else 26413910Sdougm (void) sa_security_name(optionset, oname, 26423034Sdougm sizeof (oname), id); 26433910Sdougm ret = sa_start_transaction(scf_handle, oname); 26443910Sdougm } 26453910Sdougm if (ret == SA_OK) { 26463910Sdougm switch (type) { 26473910Sdougm case SA_PROP_OP_REMOVE: 26483910Sdougm ret = scf_transaction_property_delete( 26493910Sdougm scf_handle->trans, 26503910Sdougm entry, name); 26513910Sdougm break; 26523910Sdougm case SA_PROP_OP_ADD: 26533910Sdougm case SA_PROP_OP_UPDATE: 26543910Sdougm value = scf_value_create(scf_handle->handle); 26553910Sdougm if (value != NULL) { 26563910Sdougm if (type == SA_PROP_OP_ADD) 26573910Sdougm ret = scf_transaction_property_new( 26583910Sdougm scf_handle->trans, 26593910Sdougm entry, 26603910Sdougm name, 26613910Sdougm SCF_TYPE_ASTRING); 26623910Sdougm else 26633910Sdougm ret = scf_transaction_property_change( 26643910Sdougm scf_handle->trans, 26653910Sdougm entry, 26663910Sdougm name, 26673910Sdougm SCF_TYPE_ASTRING); 26683910Sdougm if (ret == 0) { 26693910Sdougm ret = scf_value_set_astring(value, valstr); 26703910Sdougm if (ret == 0) 26713910Sdougm ret = scf_entry_add_value(entry, value); 26723910Sdougm if (ret != 0) { 26733910Sdougm scf_value_destroy(value); 26743910Sdougm ret = SA_SYSTEM_ERR; 26753910Sdougm } 26763910Sdougm } else { 26773910Sdougm scf_entry_destroy(entry); 26783034Sdougm ret = SA_SYSTEM_ERR; 26793034Sdougm } 26803910Sdougm break; 26813034Sdougm } 26823034Sdougm } 26833034Sdougm } 26843034Sdougm } else { 26853034Sdougm /* 26863034Sdougm * ZFS update. The calling function would have updated 26873034Sdougm * the internal XML structure. Just need to flag it as 26883034Sdougm * changed for ZFS. 26893034Sdougm */ 26903034Sdougm zfs_set_update((sa_share_t)group); 26913034Sdougm } 26923034Sdougm } 26933034Sdougm 26943034Sdougm if (name != NULL) 26953034Sdougm sa_free_attr_string(name); 26963034Sdougm if (valstr != NULL) 26973034Sdougm sa_free_attr_string(valstr); 26983034Sdougm else if (entry != NULL) 26993034Sdougm scf_entry_destroy(entry); 27003034Sdougm 27013034Sdougm if (ret == -1) 27023034Sdougm ret = SA_SYSTEM_ERR; 27033034Sdougm 27043034Sdougm return (ret); 27053034Sdougm } 27063034Sdougm 27073034Sdougm /* 27083034Sdougm * sa_create_property(name, value) 27093034Sdougm * 27103034Sdougm * Create a new property with the specified name and value. 27113034Sdougm */ 27123034Sdougm 27133034Sdougm sa_property_t 27143034Sdougm sa_create_property(char *name, char *value) 27153034Sdougm { 27163034Sdougm xmlNodePtr node; 27173034Sdougm 27183034Sdougm node = xmlNewNode(NULL, (xmlChar *)"option"); 27193034Sdougm if (node != NULL) { 27203034Sdougm xmlSetProp(node, (xmlChar *)"type", (xmlChar *)name); 27213034Sdougm xmlSetProp(node, (xmlChar *)"value", (xmlChar *)value); 27223034Sdougm } 27233034Sdougm return ((sa_property_t)node); 27243034Sdougm } 27253034Sdougm 27263034Sdougm /* 27273034Sdougm * sa_add_property(object, property) 27283034Sdougm * 27293034Sdougm * Add the specified property to the object. Issue the appropriate 27303034Sdougm * transaction or mark a ZFS object as needing an update. 27313034Sdougm */ 27323034Sdougm 27333034Sdougm int 27343034Sdougm sa_add_property(void *object, sa_property_t property) 27353034Sdougm { 27363034Sdougm int ret = SA_OK; 27373034Sdougm sa_group_t parent; 27383034Sdougm sa_group_t group; 27393034Sdougm char *proto; 27403034Sdougm 27413034Sdougm proto = sa_get_optionset_attr(object, "type"); 27423034Sdougm if (property != NULL) { 27433034Sdougm if ((ret = sa_valid_property(object, proto, property)) == SA_OK) { 27443034Sdougm property = (sa_property_t)xmlAddChild((xmlNodePtr)object, 27453034Sdougm (xmlNodePtr)property); 27463034Sdougm } else { 27473034Sdougm if (proto != NULL) 27483034Sdougm sa_free_attr_string(proto); 27493034Sdougm return (ret); 27503034Sdougm } 27513034Sdougm } 27523034Sdougm 27533034Sdougm if (proto != NULL) 27543034Sdougm sa_free_attr_string(proto); 27553034Sdougm 27563034Sdougm parent = sa_get_parent_group(object); 27573034Sdougm if (!is_persistent(parent)) { 27583034Sdougm return (ret); 27593034Sdougm } 27603034Sdougm 27613034Sdougm if (sa_is_share(parent)) 27623034Sdougm group = sa_get_parent_group(parent); 27633034Sdougm else 27643034Sdougm group = parent; 27653034Sdougm 27663034Sdougm if (property == NULL) 27673034Sdougm ret = SA_NO_MEMORY; 27683034Sdougm else { 27693034Sdougm char oname[256]; 27703034Sdougm 27713034Sdougm if (!is_zfs_group(group)) { 27723034Sdougm char *id = NULL; 27733910Sdougm sa_handle_impl_t impl_handle; 27743910Sdougm scfutilhandle_t *scf_handle; 27753910Sdougm 27763910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 27773910Sdougm if (impl_handle == NULL || impl_handle->scfhandle == NULL) 27783910Sdougm ret = SA_SYSTEM_ERR; 27793034Sdougm if (ret == SA_OK) { 27803910Sdougm scf_handle = impl_handle->scfhandle; 27813910Sdougm if (sa_is_share((sa_group_t)parent)) { 27823910Sdougm id = sa_get_share_attr((sa_share_t)parent, "id"); 27833910Sdougm } 27843910Sdougm if (scf_handle->trans == NULL) { 27853910Sdougm if (is_nodetype(object, "optionset")) 27863910Sdougm (void) sa_optionset_name((sa_optionset_t)object, 27873910Sdougm oname, sizeof (oname), id); 27883910Sdougm else 27893910Sdougm (void) sa_security_name((sa_optionset_t)object, 27903910Sdougm oname, sizeof (oname), id); 27913910Sdougm ret = sa_start_transaction(scf_handle, oname); 27923910Sdougm } 27933910Sdougm if (ret == SA_OK) { 27943910Sdougm char *name; 27953910Sdougm char *value; 27963910Sdougm name = sa_get_property_attr(property, "type"); 27973910Sdougm value = sa_get_property_attr(property, "value"); 27983910Sdougm if (name != NULL && value != NULL) { 27993910Sdougm if (scf_handle->scf_state == SCH_STATE_INIT) 28003910Sdougm ret = sa_set_property(scf_handle, name, value); 28013910Sdougm } else 28023910Sdougm ret = SA_CONFIG_ERR; 28033910Sdougm if (name != NULL) 28043910Sdougm sa_free_attr_string(name); 28053910Sdougm if (value != NULL) 28063910Sdougm sa_free_attr_string(value); 28073910Sdougm } 28083910Sdougm if (id != NULL) 28093910Sdougm sa_free_attr_string(id); 28103034Sdougm } 28113034Sdougm } else { 28123034Sdougm /* 28133034Sdougm * ZFS is a special case. We do want to allow editing 28143034Sdougm * property/security lists since we can have a better 28153034Sdougm * syntax and we also want to keep things consistent 28163034Sdougm * when possible. 28173034Sdougm * 28183034Sdougm * Right now, we defer until the sa_commit_properties 28193034Sdougm * so we can get them all at once. We do need to mark 28203034Sdougm * the share as "changed" 28213034Sdougm */ 28223034Sdougm zfs_set_update((sa_share_t)parent); 28233034Sdougm } 28243034Sdougm } 28253034Sdougm return (ret); 28263034Sdougm } 28273034Sdougm 28283034Sdougm /* 28293034Sdougm * sa_remove_property(property) 28303034Sdougm * 28313034Sdougm * Remove the specied property from its containing object. Update the 28323034Sdougm * repository as appropriate. 28333034Sdougm */ 28343034Sdougm 28353034Sdougm int 28363034Sdougm sa_remove_property(sa_property_t property) 28373034Sdougm { 28383034Sdougm int ret = SA_OK; 28393034Sdougm 28403034Sdougm if (property != NULL) { 28413034Sdougm sa_optionset_t optionset; 28423034Sdougm sa_group_t group; 28433034Sdougm optionset = sa_get_property_parent(property); 28443034Sdougm if (optionset != NULL) { 28453034Sdougm group = sa_get_optionset_parent(optionset); 28463034Sdougm if (group != NULL) { 28473034Sdougm ret = sa_set_prop_by_prop(optionset, group, property, 28483034Sdougm SA_PROP_OP_REMOVE); 28493034Sdougm } 28503034Sdougm } 28513034Sdougm xmlUnlinkNode((xmlNodePtr)property); 28523034Sdougm xmlFreeNode((xmlNodePtr)property); 28533034Sdougm } else { 28543034Sdougm ret = SA_NO_SUCH_PROP; 28553034Sdougm } 28563034Sdougm return (ret); 28573034Sdougm } 28583034Sdougm 28593034Sdougm /* 28603034Sdougm * sa_update_property(property, value) 28613034Sdougm * 28623034Sdougm * Update the specified property to the new value. If value is NULL, 28633034Sdougm * we currently treat this as a remove. 28643034Sdougm */ 28653034Sdougm 28663034Sdougm int 28673034Sdougm sa_update_property(sa_property_t property, char *value) 28683034Sdougm { 28693034Sdougm int ret = SA_OK; 28703034Sdougm if (value == NULL) { 28713034Sdougm return (sa_remove_property(property)); 28723034Sdougm } else { 28733034Sdougm sa_optionset_t optionset; 28743034Sdougm sa_group_t group; 28753034Sdougm set_node_attr((void *)property, "value", value); 28763034Sdougm optionset = sa_get_property_parent(property); 28773034Sdougm if (optionset != NULL) { 28783034Sdougm group = sa_get_optionset_parent(optionset); 28793034Sdougm if (group != NULL) { 28803034Sdougm ret = sa_set_prop_by_prop(optionset, group, property, 28813034Sdougm SA_PROP_OP_UPDATE); 28823034Sdougm } 28833034Sdougm } else { 28843034Sdougm ret = SA_NO_SUCH_PROP; 28853034Sdougm } 28863034Sdougm } 28873034Sdougm return (ret); 28883034Sdougm } 28893034Sdougm 28903034Sdougm /* 28913034Sdougm * sa_get_protocol_property(propset, prop) 28923034Sdougm * 28933034Sdougm * Get the specified protocol specific property. These are global to 28943034Sdougm * the protocol and not specific to a group or share. 28953034Sdougm */ 28963034Sdougm 28973034Sdougm sa_property_t 28983034Sdougm sa_get_protocol_property(sa_protocol_properties_t propset, char *prop) 28993034Sdougm { 29003034Sdougm xmlNodePtr node = (xmlNodePtr)propset; 29013034Sdougm xmlChar *value = NULL; 29023034Sdougm 29033034Sdougm for (node = node->children; node != NULL; 29043034Sdougm node = node->next) { 29053034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 29063034Sdougm if (prop == NULL) 29073034Sdougm break; 29083034Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 29093034Sdougm if (value != NULL && 29103034Sdougm xmlStrcasecmp(value, (xmlChar *)prop) == 0) { 29113034Sdougm break; 29123034Sdougm } 29133034Sdougm if (value != NULL) { 29143034Sdougm xmlFree(value); 29153034Sdougm value = NULL; 29163034Sdougm } 29173034Sdougm } 29183034Sdougm } 29193034Sdougm if (value != NULL) 29203034Sdougm xmlFree(value); 29213034Sdougm if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"option") != 0) { 29223034Sdougm /* avoid a non option node -- it is possible to be a text node */ 29233034Sdougm node = NULL; 29243034Sdougm } 29253034Sdougm return ((sa_property_t)node); 29263034Sdougm } 29273034Sdougm 29283034Sdougm /* 29293034Sdougm * sa_get_next_protocol_property(prop) 29303034Sdougm * 29313034Sdougm * Get the next protocol specific property in the list. 29323034Sdougm */ 29333034Sdougm 29343034Sdougm sa_property_t 29353034Sdougm sa_get_next_protocol_property(sa_property_t prop) 29363034Sdougm { 29373034Sdougm xmlNodePtr node; 29383034Sdougm 29393034Sdougm for (node = ((xmlNodePtr)prop)->next; node != NULL; 29403034Sdougm node = node->next) { 29413034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 29423034Sdougm break; 29433034Sdougm } 29443034Sdougm } 29453034Sdougm return ((sa_property_t)node); 29463034Sdougm } 29473034Sdougm 29483034Sdougm /* 29493034Sdougm * sa_set_protocol_property(prop, value) 29503034Sdougm * 29513034Sdougm * Set the specified property to have the new value. The protocol 29523034Sdougm * specific plugin will then be called to update the property. 29533034Sdougm */ 29543034Sdougm 29553034Sdougm int 29563034Sdougm sa_set_protocol_property(sa_property_t prop, char *value) 29573034Sdougm { 29583034Sdougm sa_protocol_properties_t propset; 29593034Sdougm char *proto; 29603034Sdougm int ret = SA_INVALID_PROTOCOL; 29613034Sdougm 29623034Sdougm propset = ((xmlNodePtr)prop)->parent; 29633034Sdougm if (propset != NULL) { 29643034Sdougm proto = sa_get_optionset_attr(propset, "type"); 29653034Sdougm if (proto != NULL) { 29663034Sdougm set_node_attr((xmlNodePtr)prop, "value", value); 29673034Sdougm ret = sa_proto_set_property(proto, prop); 29683393Sdougm sa_free_attr_string(proto); 29693034Sdougm } 29703034Sdougm } 29713034Sdougm return (ret); 29723034Sdougm } 29733034Sdougm 29743034Sdougm /* 29753034Sdougm * sa_add_protocol_property(propset, prop) 29763034Sdougm * 29773034Sdougm * Add a new property to the protocol sepcific property set. 29783034Sdougm */ 29793034Sdougm 29803034Sdougm int 29813034Sdougm sa_add_protocol_property(sa_protocol_properties_t propset, sa_property_t prop) 29823034Sdougm { 29833034Sdougm xmlNodePtr node; 29843034Sdougm 29853034Sdougm /* should check for legitimacy */ 29863034Sdougm node = xmlAddChild((xmlNodePtr)propset, (xmlNodePtr)prop); 29873034Sdougm if (node != NULL) 29883034Sdougm return (SA_OK); 29893034Sdougm return (SA_NO_MEMORY); 29903034Sdougm } 29913034Sdougm 29923034Sdougm /* 29933034Sdougm * sa_create_protocol_properties(proto) 29943034Sdougm * 29953034Sdougm * Create a protocol specifity property set. 29963034Sdougm */ 29973034Sdougm 29983034Sdougm sa_protocol_properties_t 29993034Sdougm sa_create_protocol_properties(char *proto) 30003034Sdougm { 30013034Sdougm xmlNodePtr node; 30023034Sdougm node = xmlNewNode(NULL, (xmlChar *)"propertyset"); 30033034Sdougm if (node != NULL) { 30043034Sdougm xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto); 30053034Sdougm } 30063034Sdougm return (node); 30073034Sdougm } 3008