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" 584327Sdougm #define SA_STRSIZE 256 /* max string size for names */ 593663Sdougm 603034Sdougm /* 613034Sdougm * internal data structures 623034Sdougm */ 633034Sdougm 643034Sdougm extern struct sa_proto_plugin *sap_proto_list; 653034Sdougm 663034Sdougm /* current SMF/SVC repository handle */ 673910Sdougm extern void getlegacyconfig(sa_handle_t, char *, xmlNodePtr *); 683910Sdougm extern int gettransients(sa_handle_impl_t, xmlNodePtr *); 693034Sdougm extern int sa_valid_property(void *, char *, sa_property_t); 703034Sdougm extern char *sa_fstype(char *); 713034Sdougm extern int sa_is_share(void *); 723034Sdougm extern ssize_t scf_max_name_len; /* defined in scfutil during initialization */ 733034Sdougm extern int sa_group_is_zfs(sa_group_t); 743034Sdougm extern int sa_path_is_zfs(char *); 753034Sdougm extern int sa_zfs_set_sharenfs(sa_group_t, char *, int); 763910Sdougm extern void update_legacy_config(sa_handle_t); 773034Sdougm extern int issubdir(char *, char *); 784327Sdougm extern int sa_zfs_init(sa_handle_impl_t); 793910Sdougm extern void sa_zfs_fini(sa_handle_impl_t); 803663Sdougm extern void sablocksigs(sigset_t *); 813663Sdougm extern void saunblocksigs(sigset_t *); 823034Sdougm 833910Sdougm /* 843910Sdougm * Data structures for finding/managing the document root to access 853910Sdougm * handle mapping. The list isn't expected to grow very large so a 863910Sdougm * simple list is acceptable. The purpose is to provide a way to start 873910Sdougm * with a group or share and find the library handle needed for 883910Sdougm * various operations. 893910Sdougm */ 903910Sdougm mutex_t sa_global_lock; 913910Sdougm struct doc2handle { 923910Sdougm struct doc2handle *next; 933910Sdougm xmlNodePtr root; 943910Sdougm sa_handle_impl_t handle; 953910Sdougm }; 963910Sdougm 974327Sdougm /* definitions used in a couple of property functions */ 984327Sdougm #define SA_PROP_OP_REMOVE 1 994327Sdougm #define SA_PROP_OP_ADD 2 1004327Sdougm #define SA_PROP_OP_UPDATE 3 1014327Sdougm 1023910Sdougm static struct doc2handle *sa_global_handles = NULL; 1033034Sdougm 1043034Sdougm /* helper functions */ 1053034Sdougm 1063910Sdougm /* 1073910Sdougm * sa_errorstr(err) 1083910Sdougm * 1093910Sdougm * convert an error value to an error string 1103910Sdougm */ 1113910Sdougm 1123034Sdougm char * 1133034Sdougm sa_errorstr(int err) 1143034Sdougm { 1153034Sdougm static char errstr[32]; 1163034Sdougm char *ret = NULL; 1173034Sdougm 1183034Sdougm switch (err) { 1193034Sdougm case SA_OK: 1204327Sdougm ret = dgettext(TEXT_DOMAIN, "ok"); 1214327Sdougm break; 1223034Sdougm case SA_NO_SUCH_PATH: 1234327Sdougm ret = dgettext(TEXT_DOMAIN, "path doesn't exist"); 1244327Sdougm break; 1253034Sdougm case SA_NO_MEMORY: 1264327Sdougm ret = dgettext(TEXT_DOMAIN, "no memory"); 1274327Sdougm break; 1283034Sdougm case SA_DUPLICATE_NAME: 1294327Sdougm ret = dgettext(TEXT_DOMAIN, "name in use"); 1304327Sdougm break; 1313034Sdougm case SA_BAD_PATH: 1324327Sdougm ret = dgettext(TEXT_DOMAIN, "bad path"); 1334327Sdougm break; 1343034Sdougm case SA_NO_SUCH_GROUP: 1354327Sdougm ret = dgettext(TEXT_DOMAIN, "no such group"); 1364327Sdougm break; 1373034Sdougm case SA_CONFIG_ERR: 1384327Sdougm ret = dgettext(TEXT_DOMAIN, "configuration error"); 1394327Sdougm break; 1403034Sdougm case SA_SYSTEM_ERR: 1414327Sdougm ret = dgettext(TEXT_DOMAIN, "system error"); 1424327Sdougm break; 1433034Sdougm case SA_SYNTAX_ERR: 1444327Sdougm ret = dgettext(TEXT_DOMAIN, "syntax error"); 1454327Sdougm break; 1463034Sdougm case SA_NO_PERMISSION: 1474327Sdougm ret = dgettext(TEXT_DOMAIN, "no permission"); 1484327Sdougm break; 1493034Sdougm case SA_BUSY: 1504327Sdougm ret = dgettext(TEXT_DOMAIN, "busy"); 1514327Sdougm break; 1523034Sdougm case SA_NO_SUCH_PROP: 1534327Sdougm ret = dgettext(TEXT_DOMAIN, "no such property"); 1544327Sdougm break; 1553034Sdougm case SA_INVALID_NAME: 1564327Sdougm ret = dgettext(TEXT_DOMAIN, "invalid name"); 1574327Sdougm break; 1583034Sdougm case SA_INVALID_PROTOCOL: 1594327Sdougm ret = dgettext(TEXT_DOMAIN, "invalid protocol"); 1604327Sdougm break; 1613034Sdougm case SA_NOT_ALLOWED: 1624327Sdougm ret = dgettext(TEXT_DOMAIN, "operation not allowed"); 1634327Sdougm break; 1643034Sdougm case SA_BAD_VALUE: 1654327Sdougm ret = dgettext(TEXT_DOMAIN, "bad property value"); 1664327Sdougm break; 1673034Sdougm case SA_INVALID_SECURITY: 1684327Sdougm ret = dgettext(TEXT_DOMAIN, "invalid security type"); 1694327Sdougm break; 1703034Sdougm case SA_NO_SUCH_SECURITY: 1714327Sdougm ret = dgettext(TEXT_DOMAIN, "security type not found"); 1724327Sdougm break; 1733034Sdougm case SA_VALUE_CONFLICT: 1744327Sdougm ret = dgettext(TEXT_DOMAIN, "property value conflict"); 1754327Sdougm break; 1763034Sdougm case SA_NOT_IMPLEMENTED: 1774327Sdougm ret = dgettext(TEXT_DOMAIN, "not implemented"); 1784327Sdougm break; 1793034Sdougm case SA_INVALID_PATH: 1804327Sdougm ret = dgettext(TEXT_DOMAIN, "invalid path"); 1814327Sdougm break; 1823034Sdougm case SA_NOT_SUPPORTED: 1834327Sdougm ret = dgettext(TEXT_DOMAIN, "operation not supported"); 1844327Sdougm break; 1853034Sdougm case SA_PROP_SHARE_ONLY: 1864327Sdougm ret = dgettext(TEXT_DOMAIN, "property not valid for group"); 1874327Sdougm break; 1883034Sdougm case SA_NOT_SHARED: 1894327Sdougm ret = dgettext(TEXT_DOMAIN, "not shared"); 1904327Sdougm break; 1913034Sdougm default: 1924327Sdougm (void) snprintf(errstr, sizeof (errstr), 1934327Sdougm dgettext(TEXT_DOMAIN, "unknown %d"), err); 1944327Sdougm ret = errstr; 1953034Sdougm } 1963034Sdougm return (ret); 1973034Sdougm } 1983034Sdougm 1993034Sdougm /* 2003910Sdougm * Document root to active handle mapping functions. These are only 2013910Sdougm * used internally. A mutex is used to prevent access while the list 2023910Sdougm * is changing. In general, the list will be relatively short - one 2033910Sdougm * item per thread that has called sa_init(). 2043910Sdougm */ 2053910Sdougm 2063910Sdougm sa_handle_impl_t 2073910Sdougm get_handle_for_root(xmlNodePtr root) 2083910Sdougm { 2093910Sdougm struct doc2handle *item; 2103910Sdougm 2113910Sdougm (void) mutex_lock(&sa_global_lock); 2123910Sdougm for (item = sa_global_handles; item != NULL; item = item->next) { 2134327Sdougm if (item->root == root) 2144327Sdougm break; 2153910Sdougm } 2163910Sdougm (void) mutex_unlock(&sa_global_lock); 2173910Sdougm if (item != NULL) 2184327Sdougm return (item->handle); 2193910Sdougm return (NULL); 2203910Sdougm } 2213910Sdougm 2223910Sdougm static int 2233910Sdougm add_handle_for_root(xmlNodePtr root, sa_handle_impl_t handle) 2243910Sdougm { 2253910Sdougm struct doc2handle *item; 2263910Sdougm int ret = SA_NO_MEMORY; 2273910Sdougm 2283910Sdougm item = (struct doc2handle *)calloc(sizeof (struct doc2handle), 1); 2293910Sdougm if (item != NULL) { 2304327Sdougm item->root = root; 2314327Sdougm item->handle = handle; 2324327Sdougm (void) mutex_lock(&sa_global_lock); 2334327Sdougm item->next = sa_global_handles; 2344327Sdougm sa_global_handles = item; 2354327Sdougm (void) mutex_unlock(&sa_global_lock); 2364327Sdougm ret = SA_OK; 2373910Sdougm } 2383910Sdougm return (ret); 2393910Sdougm } 2403910Sdougm 2413910Sdougm /* 2423910Sdougm * remove_handle_for_root(root) 2433910Sdougm * 2443910Sdougm * Walks the list of handles and removes the one for this "root" from 2453910Sdougm * the list. It is up to the caller to free the data. 2463910Sdougm */ 2473910Sdougm 2483910Sdougm static void 2493910Sdougm remove_handle_for_root(xmlNodePtr root) 2503910Sdougm { 2513910Sdougm struct doc2handle *item, *prev; 2523910Sdougm 2533910Sdougm (void) mutex_lock(&sa_global_lock); 2543910Sdougm for (prev = NULL, item = sa_global_handles; item != NULL; 2554327Sdougm item = item->next) { 2564327Sdougm if (item->root == root) { 2574327Sdougm /* first in the list */ 2584327Sdougm if (prev == NULL) 2594327Sdougm sa_global_handles = sa_global_handles->next; 2604327Sdougm else 2614327Sdougm prev->next = item->next; 2624327Sdougm /* Item is out of the list so free the list structure */ 2634327Sdougm free(item); 2644327Sdougm break; 2653910Sdougm } 2664327Sdougm prev = item; 2673910Sdougm } 2683910Sdougm (void) mutex_unlock(&sa_global_lock); 2693910Sdougm } 2703910Sdougm 2713910Sdougm /* 2723910Sdougm * sa_find_group_handle(sa_group_t group) 2733910Sdougm * 2743910Sdougm * Find the sa_handle_t for the configuration associated with this 2753910Sdougm * group. 2763910Sdougm */ 2773910Sdougm sa_handle_t 2783910Sdougm sa_find_group_handle(sa_group_t group) 2793910Sdougm { 2803910Sdougm xmlNodePtr node = (xmlNodePtr)group; 2813910Sdougm sa_handle_t handle; 2823910Sdougm 2833910Sdougm while (node != NULL) { 2844327Sdougm if (strcmp((char *)(node->name), "sharecfg") == 0) { 2854327Sdougm /* have the root so get the handle */ 2864327Sdougm handle = (sa_handle_t)get_handle_for_root(node); 2874327Sdougm return (handle); 2884327Sdougm } 2894327Sdougm node = node->parent; 2903910Sdougm } 2913910Sdougm return (NULL); 2923910Sdougm } 2933910Sdougm 2943910Sdougm /* 2953034Sdougm * set_legacy_timestamp(root, path, timevalue) 2963034Sdougm * 2973034Sdougm * add the current timestamp value to the configuration for use in 2983034Sdougm * determining when to update the legacy files. For SMF, this 2993034Sdougm * property is kept in default/operation/legacy_timestamp 3003034Sdougm */ 3013034Sdougm 3023034Sdougm static void 3033034Sdougm set_legacy_timestamp(xmlNodePtr root, char *path, uint64_t tval) 3043034Sdougm { 3053034Sdougm xmlNodePtr node; 3063034Sdougm xmlChar *lpath = NULL; 3073910Sdougm sa_handle_impl_t handle; 3083910Sdougm 3093910Sdougm /* Have to have a handle or else we weren't initialized. */ 3103910Sdougm handle = get_handle_for_root(root); 3113910Sdougm if (handle == NULL) 3124327Sdougm return; 3133034Sdougm 3143034Sdougm for (node = root->xmlChildrenNode; node != NULL; 3154327Sdougm node = node->next) { 3164327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"legacy") == 0) { 3174327Sdougm /* a possible legacy node for this path */ 3184327Sdougm lpath = xmlGetProp(node, (xmlChar *)"path"); 3194327Sdougm if (lpath != NULL && 3204327Sdougm xmlStrcmp(lpath, (xmlChar *)path) == 0) { 3214327Sdougm xmlFree(lpath); 3224327Sdougm break; 3234327Sdougm } 3244327Sdougm if (lpath != NULL) 3254327Sdougm xmlFree(lpath); 3263034Sdougm } 3273034Sdougm } 3283034Sdougm if (node == NULL) { 3294327Sdougm /* need to create the first legacy timestamp node */ 3304327Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"legacy", NULL); 3313034Sdougm } 3323034Sdougm if (node != NULL) { 3334327Sdougm char tstring[32]; 3344327Sdougm int ret; 3353034Sdougm 3364327Sdougm (void) snprintf(tstring, sizeof (tstring), "%lld", tval); 3374327Sdougm xmlSetProp(node, (xmlChar *)"timestamp", (xmlChar *)tstring); 3384327Sdougm xmlSetProp(node, (xmlChar *)"path", (xmlChar *)path); 3394327Sdougm /* now commit to SMF */ 3404327Sdougm ret = sa_get_instance(handle->scfhandle, "default"); 3413034Sdougm if (ret == SA_OK) { 3424327Sdougm ret = sa_start_transaction(handle->scfhandle, 3434327Sdougm "operation"); 3444327Sdougm if (ret == SA_OK) { 3454327Sdougm ret = sa_set_property(handle->scfhandle, 3464327Sdougm "legacy-timestamp", tstring); 3474327Sdougm if (ret == SA_OK) { 3484327Sdougm (void) sa_end_transaction( 3494327Sdougm handle->scfhandle); 3504327Sdougm } else { 3514327Sdougm sa_abort_transaction(handle->scfhandle); 3524327Sdougm } 3534327Sdougm } 3543034Sdougm } 3553034Sdougm } 3563034Sdougm } 3573034Sdougm 3583034Sdougm /* 3593034Sdougm * is_shared(share) 3603034Sdougm * 3613034Sdougm * determine if the specified share is currently shared or not. 3623034Sdougm */ 3633034Sdougm static int 3643034Sdougm is_shared(sa_share_t share) 3653034Sdougm { 3663034Sdougm char *shared; 3673034Sdougm int result = 0; /* assume not */ 3683034Sdougm 3693034Sdougm shared = sa_get_share_attr(share, "shared"); 3703034Sdougm if (shared != NULL) { 3714327Sdougm if (strcmp(shared, "true") == 0) 3724327Sdougm result = 1; 3734327Sdougm sa_free_attr_string(shared); 3743034Sdougm } 3753034Sdougm return (result); 3763034Sdougm } 3773034Sdougm 3783034Sdougm /* 3793663Sdougm * checksubdirgroup(group, newpath, strictness) 3803348Sdougm * 3813663Sdougm * check all the specified newpath against all the paths in the 3823663Sdougm * group. This is a helper function for checksubdir to make it easier 3833663Sdougm * to also check ZFS subgroups. 3843663Sdougm * The strictness values mean: 3853348Sdougm * SA_CHECK_NORMAL == only check newpath against shares that are active 3863348Sdougm * SA_CHECK_STRICT == check newpath against both active shares and those 3873348Sdougm * stored in the repository 3883034Sdougm */ 3893034Sdougm static int 3903663Sdougm checksubdirgroup(sa_group_t group, char *newpath, int strictness) 3913034Sdougm { 3923034Sdougm sa_share_t share; 3933663Sdougm char *path; 3943663Sdougm int issub = SA_OK; 3953034Sdougm 3963663Sdougm for (share = sa_get_share(group, NULL); share != NULL; 3973663Sdougm share = sa_get_next_share(share)) { 3983034Sdougm /* 3993034Sdougm * The original behavior of share never checked 4003034Sdougm * against the permanent configuration 4013034Sdougm * (/etc/dfs/dfstab). PIT has a number of cases where 4023034Sdougm * it depends on this older behavior even though it 4033034Sdougm * could be considered incorrect. We may tighten this 4043034Sdougm * up in the future. 4053034Sdougm */ 4064327Sdougm if (strictness == SA_CHECK_NORMAL && !is_shared(share)) 4074327Sdougm continue; 4083034Sdougm 4094327Sdougm path = sa_get_share_attr(share, "path"); 4103348Sdougm /* 4113348Sdougm * If path is NULL, then a share is in the process of 4123348Sdougm * construction or someone has modified the property 4133663Sdougm * group inappropriately. It should be 4143663Sdougm * ignored. issubdir() comes from the original share 4153663Sdougm * implementation and does the difficult part of 4163663Sdougm * checking subdirectories. 4173348Sdougm */ 4184327Sdougm if (path == NULL) 4194327Sdougm continue; 4204327Sdougm if (newpath != NULL && 4214327Sdougm (strcmp(path, newpath) == 0 || issubdir(newpath, path) || 4224327Sdougm issubdir(path, newpath))) { 4234327Sdougm sa_free_attr_string(path); 4244327Sdougm path = NULL; 4254327Sdougm issub = SA_INVALID_PATH; 4264327Sdougm break; 4274327Sdougm } 4283034Sdougm sa_free_attr_string(path); 4293034Sdougm path = NULL; 4303663Sdougm } 4313663Sdougm return (issub); 4323663Sdougm } 4333663Sdougm 4343663Sdougm /* 4353663Sdougm * checksubdir(newpath, strictness) 4363663Sdougm * 4373663Sdougm * checksubdir determines if the specified path (newpath) is a 4383663Sdougm * subdirectory of another share. It calls checksubdirgroup() to do 4393663Sdougm * the complicated work. The strictness parameter determines how 4403663Sdougm * strict a check to make against the path. The strictness values 4413663Sdougm * mean: SA_CHECK_NORMAL == only check newpath against shares that are 4423663Sdougm * active SA_CHECK_STRICT == check newpath against both active shares 4433663Sdougm * and those * stored in the repository 4443663Sdougm */ 4453663Sdougm static int 4463910Sdougm checksubdir(sa_handle_t handle, char *newpath, int strictness) 4473663Sdougm { 4483663Sdougm sa_group_t group; 4493663Sdougm int issub; 4503663Sdougm char *path = NULL; 4513663Sdougm 4523910Sdougm for (issub = 0, group = sa_get_group(handle, NULL); 4534327Sdougm group != NULL && !issub; group = sa_get_next_group(group)) { 4544327Sdougm if (sa_group_is_zfs(group)) { 4554327Sdougm sa_group_t subgroup; 4564327Sdougm for (subgroup = sa_get_sub_group(group); 4574327Sdougm subgroup != NULL && !issub; 4584327Sdougm subgroup = sa_get_next_group(subgroup)) 4594327Sdougm issub = checksubdirgroup(subgroup, newpath, 4604327Sdougm strictness); 4614327Sdougm } else { 4624327Sdougm issub = checksubdirgroup(group, newpath, strictness); 4634327Sdougm } 4643034Sdougm } 4653034Sdougm if (path != NULL) 4664327Sdougm sa_free_attr_string(path); 4673034Sdougm return (issub); 4683034Sdougm } 4693034Sdougm 4703034Sdougm /* 4713348Sdougm * validpath(path, strictness) 4723034Sdougm * determine if the provided path is valid for a share. It shouldn't 4733034Sdougm * be a sub-dir of an already shared path or the parent directory of a 4743034Sdougm * share path. 4753034Sdougm */ 4763034Sdougm static int 4773910Sdougm validpath(sa_handle_t handle, char *path, int strictness) 4783034Sdougm { 4793034Sdougm int error = SA_OK; 4803034Sdougm struct stat st; 4813034Sdougm sa_share_t share; 4823034Sdougm char *fstype; 4833034Sdougm 4844327Sdougm if (*path != '/') 4854327Sdougm return (SA_BAD_PATH); 4864327Sdougm 4873034Sdougm if (stat(path, &st) < 0) { 4884327Sdougm error = SA_NO_SUCH_PATH; 4893034Sdougm } else { 4904327Sdougm share = sa_find_share(handle, path); 4914327Sdougm if (share != NULL) 4924327Sdougm error = SA_DUPLICATE_NAME; 4934327Sdougm 4944327Sdougm if (error == SA_OK) { 4954327Sdougm /* 4964327Sdougm * check for special case with file system 4974327Sdougm * that might have restrictions. For now, ZFS 4984327Sdougm * is the only case since it has its own idea 4994327Sdougm * of how to configure shares. We do this 5004327Sdougm * before subdir checking since things like 5014327Sdougm * ZFS will do that for us. This should also 5024327Sdougm * be done via plugin interface. 5034327Sdougm */ 5044327Sdougm fstype = sa_fstype(path); 5054327Sdougm if (fstype != NULL && strcmp(fstype, "zfs") == 0) { 5064327Sdougm if (sa_zfs_is_shared(handle, path)) 5074327Sdougm error = SA_INVALID_NAME; 5084327Sdougm } 5094327Sdougm if (fstype != NULL) 5104327Sdougm sa_free_fstype(fstype); 5113034Sdougm } 5124327Sdougm if (error == SA_OK) 5134327Sdougm error = checksubdir(handle, path, strictness); 5143034Sdougm } 5153034Sdougm return (error); 5163034Sdougm } 5173034Sdougm 5183034Sdougm /* 5193034Sdougm * check to see if group/share is persistent. 5203034Sdougm */ 5213034Sdougm static int 5223034Sdougm is_persistent(sa_group_t group) 5233034Sdougm { 5243034Sdougm char *type; 5253034Sdougm int persist = 1; 5263034Sdougm 5273034Sdougm type = sa_get_group_attr(group, "type"); 5283034Sdougm if (type != NULL && strcmp(type, "transient") == 0) 5294327Sdougm persist = 0; 5303034Sdougm if (type != NULL) 5314327Sdougm sa_free_attr_string(type); 5323034Sdougm return (persist); 5333034Sdougm } 5343034Sdougm 5353034Sdougm /* 5363034Sdougm * sa_valid_group_name(name) 5373034Sdougm * 5383034Sdougm * check that the "name" contains only valid characters and otherwise 5393034Sdougm * fits the required naming conventions. Valid names must start with 5403034Sdougm * an alphabetic and the remainder may consist of only alphanumeric 5413034Sdougm * plus the '-' and '_' characters. This name limitation comes from 5423034Sdougm * inherent limitations in SMF. 5433034Sdougm */ 5443034Sdougm 5453034Sdougm int 5463034Sdougm sa_valid_group_name(char *name) 5473034Sdougm { 5483034Sdougm int ret = 1; 5493034Sdougm ssize_t len; 5503034Sdougm 5513034Sdougm if (name != NULL && isalpha(*name)) { 5524327Sdougm char c; 5534327Sdougm len = strlen(name); 5544327Sdougm if (len < (scf_max_name_len - sizeof ("group:"))) { 5554327Sdougm for (c = *name++; c != '\0' && ret != 0; c = *name++) { 5564327Sdougm if (!isalnum(c) && c != '-' && c != '_') 5574327Sdougm ret = 0; 5584327Sdougm } 5594327Sdougm } else { 5603034Sdougm ret = 0; 5613034Sdougm } 5624327Sdougm } else { 5633034Sdougm ret = 0; 5643034Sdougm } 5653034Sdougm return (ret); 5663034Sdougm } 5673034Sdougm 5683034Sdougm 5693034Sdougm /* 5703034Sdougm * is_zfs_group(group) 5713034Sdougm * Determine if the specified group is a ZFS sharenfs group 5723034Sdougm */ 5733034Sdougm static int 5743034Sdougm is_zfs_group(sa_group_t group) 5753034Sdougm { 5763034Sdougm int ret = 0; 5773034Sdougm xmlNodePtr parent; 5783034Sdougm xmlChar *zfs; 5793034Sdougm 5804327Sdougm if (strcmp((char *)((xmlNodePtr)group)->name, "share") == 0) 5814327Sdougm parent = (xmlNodePtr)sa_get_parent_group(group); 5824327Sdougm else 5834327Sdougm parent = (xmlNodePtr)group; 5843034Sdougm zfs = xmlGetProp(parent, (xmlChar *)"zfs"); 5853034Sdougm if (zfs != NULL) { 5864327Sdougm xmlFree(zfs); 5874327Sdougm ret = 1; 5883034Sdougm } 5893034Sdougm return (ret); 5903034Sdougm } 5913034Sdougm 5923034Sdougm /* 5933034Sdougm * sa_optionset_name(optionset, oname, len, id) 5943034Sdougm * return the SMF name for the optionset. If id is not NULL, it 5953034Sdougm * will have the GUID value for a share and should be used 5963034Sdougm * instead of the keyword "optionset" which is used for 5973034Sdougm * groups. If the optionset doesn't have a protocol type 5983034Sdougm * associated with it, "default" is used. This shouldn't happen 5993034Sdougm * at this point but may be desirable in the future if there are 6003034Sdougm * protocol independent properties added. The name is returned in 6013034Sdougm * oname. 6023034Sdougm */ 6033034Sdougm 6043034Sdougm static int 6053034Sdougm sa_optionset_name(sa_optionset_t optionset, char *oname, size_t len, char *id) 6063034Sdougm { 6073034Sdougm char *proto; 6083034Sdougm 6093034Sdougm if (id == NULL) 6104327Sdougm id = "optionset"; 6113034Sdougm 6123034Sdougm proto = sa_get_optionset_attr(optionset, "type"); 6133034Sdougm len = snprintf(oname, len, "%s_%s", id, proto ? proto : "default"); 6143034Sdougm 6153034Sdougm if (proto != NULL) 6164327Sdougm sa_free_attr_string(proto); 6173034Sdougm return (len); 6183034Sdougm } 6193034Sdougm 6203034Sdougm /* 6213034Sdougm * sa_security_name(optionset, oname, len, id) 6223034Sdougm * 6233034Sdougm * return the SMF name for the security. If id is not NULL, it will 6243034Sdougm * have the GUID value for a share and should be used instead of the 6253034Sdougm * keyword "optionset" which is used for groups. If the optionset 6263034Sdougm * doesn't have a protocol type associated with it, "default" is 6273034Sdougm * used. This shouldn't happen at this point but may be desirable in 6283034Sdougm * the future if there are protocol independent properties added. The 6293034Sdougm * name is returned in oname. The security type is also encoded into 6303034Sdougm * the name. In the future, this wil *be handled a bit differently. 6313034Sdougm */ 6323034Sdougm 6333034Sdougm static int 6343034Sdougm sa_security_name(sa_security_t security, char *oname, size_t len, char *id) 6353034Sdougm { 6363034Sdougm char *proto; 6373034Sdougm char *sectype; 6383034Sdougm 6393034Sdougm if (id == NULL) 6404327Sdougm id = "optionset"; 6413034Sdougm 6423034Sdougm proto = sa_get_security_attr(security, "type"); 6433034Sdougm sectype = sa_get_security_attr(security, "sectype"); 6444327Sdougm len = snprintf(oname, len, "%s_%s_%s", id, proto ? proto : "default", 6454327Sdougm sectype ? sectype : "default"); 6463034Sdougm if (proto != NULL) 6474327Sdougm sa_free_attr_string(proto); 6483034Sdougm if (sectype != NULL) 6494327Sdougm sa_free_attr_string(sectype); 6503034Sdougm return (len); 6513034Sdougm } 6523034Sdougm 6533034Sdougm /* 6544327Sdougm * verifydefgroupopts(handle) 6554327Sdougm * 6564327Sdougm * Make sure a "default" group exists and has default protocols enabled. 6574327Sdougm */ 6584327Sdougm static void 6594327Sdougm verifydefgroupopts(sa_handle_t handle) 6604327Sdougm { 6614327Sdougm sa_group_t defgrp; 6624327Sdougm sa_optionset_t opt; 6634327Sdougm defgrp = sa_get_group(handle, "default"); 6644327Sdougm if (defgrp != NULL) { 6654327Sdougm opt = sa_get_optionset(defgrp, NULL); 6664327Sdougm /* 6674327Sdougm * NFS is the default for default group 6684327Sdougm */ 6694327Sdougm if (opt == NULL) 6704327Sdougm opt = sa_create_optionset(defgrp, "nfs"); 6714327Sdougm } 6724327Sdougm } 6734327Sdougm 6744327Sdougm /* 6753348Sdougm * sa_init(init_service) 6763034Sdougm * Initialize the API 6773034Sdougm * find all the shared objects 6783034Sdougm * init the tables with all objects 6793034Sdougm * read in the current configuration 6803034Sdougm */ 6813034Sdougm 6824327Sdougm #define GETPROP(prop) scf_simple_prop_next_astring(prop) 6834327Sdougm #define CHECKTSTAMP(st, tval) stat(SA_LEGACY_DFSTAB, &st) >= 0 && \ 6844327Sdougm tval != TSTAMP(st.st_ctim) 6854327Sdougm 6863910Sdougm sa_handle_t 6873034Sdougm sa_init(int init_service) 6883034Sdougm { 6893034Sdougm struct stat st; 6903034Sdougm int legacy = 0; 6913034Sdougm uint64_t tval = 0; 6923663Sdougm int lockfd; 6933663Sdougm sigset_t old; 6943663Sdougm int updatelegacy = B_FALSE; 6953663Sdougm scf_simple_prop_t *prop; 6963910Sdougm sa_handle_impl_t handle; 6973910Sdougm int err; 6983034Sdougm 6993910Sdougm handle = calloc(sizeof (struct sa_handle_impl), 1); 7003910Sdougm 7013910Sdougm if (handle != NULL) { 7024327Sdougm /* get protocol specific structures */ 7034327Sdougm (void) proto_plugin_init(); 7044327Sdougm if (init_service & SA_INIT_SHARE_API) { 7053663Sdougm /* 7064327Sdougm * initialize access into libzfs. We use this 7074327Sdougm * when collecting info about ZFS datasets and 7084327Sdougm * shares. 7093663Sdougm */ 7104327Sdougm if (sa_zfs_init(handle) == B_FALSE) { 7114327Sdougm free(handle); 7124327Sdougm (void) proto_plugin_fini(); 7134327Sdougm return (NULL); 7144327Sdougm } 7153663Sdougm /* 7164327Sdougm * since we want to use SMF, initialize an svc handle 7174327Sdougm * and find out what is there. 7183663Sdougm */ 7194327Sdougm handle->scfhandle = sa_scf_init(handle); 7204327Sdougm if (handle->scfhandle != NULL) { 7214327Sdougm /* 7224327Sdougm * Need to lock the extraction of the 7234327Sdougm * configuration if the dfstab file has 7244327Sdougm * changed. Lock everything now and release if 7254327Sdougm * not needed. Use a file that isn't being 7264327Sdougm * manipulated by other parts of the system in 7274327Sdougm * order to not interfere with locking. Using 7284327Sdougm * dfstab doesn't work. 7294327Sdougm */ 7304327Sdougm sablocksigs(&old); 7314327Sdougm lockfd = open(DFS_LOCK_FILE, O_RDWR); 7324327Sdougm if (lockfd >= 0) { 7334327Sdougm extern int errno; 7344327Sdougm errno = 0; 7354327Sdougm (void) lockf(lockfd, F_LOCK, 0); 7364327Sdougm /* 7374327Sdougm * Check whether we are going to need 7384327Sdougm * to merge any dfstab changes. This 7394327Sdougm * is done by comparing the value of 7404327Sdougm * legacy-timestamp with the current 7414327Sdougm * st_ctim of the file. If they are 7424327Sdougm * different, an update is needed and 7434327Sdougm * the file must remain locked until 7444327Sdougm * the merge is done in order to 7454327Sdougm * prevent multiple startups from 7464327Sdougm * changing the SMF repository at the 7474327Sdougm * same time. The first to get the 7484327Sdougm * lock will make any changes before 7494327Sdougm * the others can read the repository. 7504327Sdougm */ 7514327Sdougm prop = scf_simple_prop_get 7524327Sdougm (handle->scfhandle->handle, 7534327Sdougm (const char *)SA_SVC_FMRI_BASE 7544327Sdougm ":default", "operation", 7554327Sdougm "legacy-timestamp"); 7564327Sdougm if (prop != NULL) { 7574327Sdougm char *i64; 7584327Sdougm i64 = GETPROP(prop); 7594327Sdougm if (i64 != NULL) 7604327Sdougm tval = strtoull(i64, 7614327Sdougm NULL, 0); 7624327Sdougm if (CHECKTSTAMP(st, tval)) 7634327Sdougm updatelegacy = B_TRUE; 7644327Sdougm scf_simple_prop_free(prop); 7654327Sdougm } else { 7664327Sdougm /* 7674327Sdougm * We haven't set the 7684327Sdougm * timestamp before so do it. 7694327Sdougm */ 7704327Sdougm updatelegacy = B_TRUE; 7714327Sdougm } 7724327Sdougm } 7734327Sdougm if (updatelegacy == B_FALSE) { 7744327Sdougm /* Don't need the lock anymore */ 7754327Sdougm (void) lockf(lockfd, F_ULOCK, 0); 7764327Sdougm (void) close(lockfd); 7774327Sdougm } 7783973Sdougm 7794327Sdougm /* 7804327Sdougm * It is essential that the document tree and 7814327Sdougm * the internal list of roots to handles be 7824327Sdougm * setup before anything that might try to 7834327Sdougm * create a new object is called. The document 7844327Sdougm * tree is the combination of handle->doc and 7854327Sdougm * handle->tree. This allows searches, 7864327Sdougm * etc. when all you have is an object in the 7874327Sdougm * tree. 7884327Sdougm */ 7894327Sdougm handle->doc = xmlNewDoc((xmlChar *)"1.0"); 7904327Sdougm handle->tree = xmlNewNode(NULL, 7914327Sdougm (xmlChar *)"sharecfg"); 7924327Sdougm if (handle->doc != NULL && 7934327Sdougm handle->tree != NULL) { 7944327Sdougm xmlDocSetRootElement(handle->doc, 7954327Sdougm handle->tree); 7964327Sdougm err = add_handle_for_root(handle->tree, 7974327Sdougm handle); 7984327Sdougm if (err == SA_OK) 7994327Sdougm err = sa_get_config( 8004327Sdougm handle->scfhandle, 8013973Sdougm handle->tree, handle); 8024327Sdougm } else { 8034327Sdougm if (handle->doc != NULL) 8044327Sdougm xmlFreeDoc(handle->doc); 8054327Sdougm if (handle->tree != NULL) 8064327Sdougm xmlFreeNode(handle->tree); 8074327Sdougm err = SA_NO_MEMORY; 8084327Sdougm } 8093973Sdougm 8104327Sdougm saunblocksigs(&old); 8113910Sdougm 8124327Sdougm if (err != SA_OK) { 8134327Sdougm /* 8144327Sdougm * If we couldn't add the tree handle 8154327Sdougm * to the list, then things are going 8164327Sdougm * to fail badly. Might as well undo 8174327Sdougm * everything now and fail the 8184327Sdougm * sa_init(). 8194327Sdougm */ 8204327Sdougm sa_fini(handle); 8214327Sdougm return (NULL); 8224327Sdougm } 8233910Sdougm 8244327Sdougm if (tval == 0) { 8254327Sdougm /* 8264327Sdougm * first time so make sure 8274327Sdougm * default is setup 8284327Sdougm */ 8294327Sdougm verifydefgroupopts(handle); 8304327Sdougm } 8313973Sdougm 832*4524Sdougm if (updatelegacy == B_TRUE) { 833*4524Sdougm sablocksigs(&old); 834*4524Sdougm getlegacyconfig((sa_handle_t)handle, 835*4524Sdougm SA_LEGACY_DFSTAB, &handle->tree); 836*4524Sdougm if (stat(SA_LEGACY_DFSTAB, &st) >= 0) 837*4524Sdougm set_legacy_timestamp( 838*4524Sdougm handle->tree, 839*4524Sdougm SA_LEGACY_DFSTAB, 840*4524Sdougm TSTAMP(st.st_ctim)); 841*4524Sdougm saunblocksigs(&old); 842*4524Sdougm /* 843*4524Sdougm * Safe to unlock now to allow 844*4524Sdougm * others to run 845*4524Sdougm */ 846*4524Sdougm (void) lockf(lockfd, F_ULOCK, 0); 847*4524Sdougm (void) close(lockfd); 848*4524Sdougm } 849*4524Sdougm legacy |= sa_get_zfs_shares(handle, "zfs"); 850*4524Sdougm legacy |= gettransients(handle, &handle->tree); 8514327Sdougm } 8524327Sdougm } 8533034Sdougm } 8543910Sdougm return ((sa_handle_t)handle); 8553034Sdougm } 8563034Sdougm 8573034Sdougm /* 8583910Sdougm * sa_fini(handle) 8593034Sdougm * Uninitialize the API structures including the configuration 8603218Sdougm * data structures and ZFS related data. 8613034Sdougm */ 8623034Sdougm 8633034Sdougm void 8643910Sdougm sa_fini(sa_handle_t handle) 8653034Sdougm { 8663910Sdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle; 8673910Sdougm 8683910Sdougm if (impl_handle != NULL) { 8693910Sdougm /* 8703910Sdougm * Free the config trees and any other data structures 8713910Sdougm * used in the handle. 8723910Sdougm */ 8733910Sdougm if (impl_handle->doc != NULL) 8743910Sdougm xmlFreeDoc(impl_handle->doc); 8753910Sdougm sa_scf_fini(impl_handle->scfhandle); 8763910Sdougm sa_zfs_fini(impl_handle); 8773910Sdougm 8783910Sdougm /* Remove and free the entry in the global list. */ 8793910Sdougm remove_handle_for_root(impl_handle->tree); 8803910Sdougm 8813910Sdougm /* Make sure we free the handle */ 8823910Sdougm free(impl_handle); 8833910Sdougm 8843910Sdougm /* 8853910Sdougm * If this was the last handle to release, unload the 8863910Sdougm * plugins that were loaded. 8873910Sdougm */ 8883910Sdougm if (sa_global_handles == NULL) 8894327Sdougm (void) proto_plugin_fini(); 8903910Sdougm 8913034Sdougm } 8923034Sdougm } 8933034Sdougm 8943034Sdougm /* 8953034Sdougm * sa_get_protocols(char **protocol) 8963034Sdougm * Get array of protocols that are supported 8973034Sdougm * Returns pointer to an allocated and NULL terminated 8983034Sdougm * array of strings. Caller must free. 8993034Sdougm * This really should be determined dynamically. 9003034Sdougm * If there aren't any defined, return -1. 9013034Sdougm * Use free() to return memory. 9023034Sdougm */ 9033034Sdougm 9043034Sdougm int 9053034Sdougm sa_get_protocols(char ***protocols) 9063034Sdougm { 9073034Sdougm int numproto = -1; 9083034Sdougm 9093034Sdougm if (protocols != NULL) { 9104327Sdougm struct sa_proto_plugin *plug; 9114327Sdougm for (numproto = 0, plug = sap_proto_list; plug != NULL; 9124327Sdougm plug = plug->plugin_next) { 9134327Sdougm numproto++; 9144327Sdougm } 9153034Sdougm 9164327Sdougm *protocols = calloc(numproto + 1, sizeof (char *)); 9174327Sdougm if (*protocols != NULL) { 9184327Sdougm int ret = 0; 9194327Sdougm for (plug = sap_proto_list; plug != NULL; 9204327Sdougm plug = plug->plugin_next) { 9214327Sdougm /* faking for now */ 9224327Sdougm (*protocols)[ret++] = 9234327Sdougm plug->plugin_ops->sa_protocol; 9244327Sdougm } 9254327Sdougm } else { 9264327Sdougm numproto = -1; 9273034Sdougm } 9283034Sdougm } 9293034Sdougm return (numproto); 9303034Sdougm } 9313034Sdougm 9323034Sdougm /* 9333034Sdougm * find_group_by_name(node, group) 9343034Sdougm * 9353034Sdougm * search the XML document subtree specified by node to find the group 9363034Sdougm * specified by group. Searching subtree allows subgroups to be 9373034Sdougm * searched for. 9383034Sdougm */ 9393034Sdougm 9403034Sdougm static xmlNodePtr 9413034Sdougm find_group_by_name(xmlNodePtr node, xmlChar *group) 9423034Sdougm { 9433034Sdougm xmlChar *name = NULL; 9443034Sdougm 9453034Sdougm for (node = node->xmlChildrenNode; node != NULL; 9463034Sdougm node = node->next) { 9474327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"group") == 0) { 9484327Sdougm /* if no groupname, return the first found */ 9494327Sdougm if (group == NULL) 9504327Sdougm break; 9514327Sdougm name = xmlGetProp(node, (xmlChar *)"name"); 9524327Sdougm if (name != NULL && xmlStrcmp(name, group) == 0) 9534327Sdougm break; 9544327Sdougm if (name != NULL) { 9554327Sdougm xmlFree(name); 9564327Sdougm name = NULL; 9574327Sdougm } 9583034Sdougm } 9593034Sdougm } 9603034Sdougm if (name != NULL) 9614327Sdougm xmlFree(name); 9623034Sdougm return (node); 9633034Sdougm } 9643034Sdougm 9653034Sdougm /* 9663034Sdougm * sa_get_group(groupname) 9673034Sdougm * Return the "group" specified. If groupname is NULL, 9683034Sdougm * return the first group of the list of groups. 9693034Sdougm */ 9703034Sdougm sa_group_t 9713910Sdougm sa_get_group(sa_handle_t handle, char *groupname) 9723034Sdougm { 9733034Sdougm xmlNodePtr node = NULL; 9743034Sdougm char *subgroup = NULL; 9753034Sdougm char *group = NULL; 9763910Sdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle; 9773034Sdougm 9783910Sdougm if (impl_handle != NULL && impl_handle->tree != NULL) { 9794327Sdougm if (groupname != NULL) { 9804327Sdougm group = strdup(groupname); 9814345Sdougm if (group != NULL) { 9824345Sdougm subgroup = strchr(group, '/'); 9834345Sdougm if (subgroup != NULL) 9844345Sdougm *subgroup++ = '\0'; 9854345Sdougm } 9864327Sdougm } 9874345Sdougm /* 9884345Sdougm * We want to find the, possibly, named group. If 9894345Sdougm * group is not NULL, then lookup the name. If it is 9904345Sdougm * NULL, we only do the find if groupname is also 9914345Sdougm * NULL. This allows lookup of the "first" group in 9924345Sdougm * the internal list. 9934345Sdougm */ 9944345Sdougm if (group != NULL || groupname == NULL) 9954345Sdougm node = find_group_by_name(impl_handle->tree, 9964345Sdougm (xmlChar *)group); 9974345Sdougm 9984327Sdougm /* if a subgroup, find it before returning */ 9994327Sdougm if (subgroup != NULL && node != NULL) 10004327Sdougm node = find_group_by_name(node, (xmlChar *)subgroup); 10013034Sdougm } 10023034Sdougm if (node != NULL && (char *)group != NULL) 10034327Sdougm (void) sa_get_instance(impl_handle->scfhandle, (char *)group); 10043034Sdougm if (group != NULL) 10054327Sdougm free(group); 10063034Sdougm return ((sa_group_t)(node)); 10073034Sdougm } 10083034Sdougm 10093034Sdougm /* 10103034Sdougm * sa_get_next_group(group) 10113034Sdougm * Return the "next" group after the specified group from 10123034Sdougm * the internal group list. NULL if there are no more. 10133034Sdougm */ 10143034Sdougm sa_group_t 10153034Sdougm sa_get_next_group(sa_group_t group) 10163034Sdougm { 10173034Sdougm xmlNodePtr ngroup = NULL; 10183034Sdougm if (group != NULL) { 10194327Sdougm for (ngroup = ((xmlNodePtr)group)->next; ngroup != NULL; 10203034Sdougm ngroup = ngroup->next) { 10214327Sdougm if (xmlStrcmp(ngroup->name, (xmlChar *)"group") == 0) 10224327Sdougm break; 10234327Sdougm } 10243034Sdougm } 10253034Sdougm return ((sa_group_t)ngroup); 10263034Sdougm } 10273034Sdougm 10283034Sdougm /* 10293034Sdougm * sa_get_share(group, sharepath) 10303034Sdougm * Return the share object for the share specified. The share 10313034Sdougm * must be in the specified group. Return NULL if not found. 10323034Sdougm */ 10333034Sdougm sa_share_t 10343034Sdougm sa_get_share(sa_group_t group, char *sharepath) 10353034Sdougm { 10363034Sdougm xmlNodePtr node = NULL; 10373034Sdougm xmlChar *path; 10383034Sdougm 10393034Sdougm /* 10403034Sdougm * For future scalability, this should end up building a cache 10413034Sdougm * since it will get called regularly by the mountd and info 10423034Sdougm * services. 10433034Sdougm */ 10443034Sdougm if (group != NULL) { 10454327Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 10463034Sdougm node = node->next) { 10474327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) { 10484327Sdougm if (sharepath == NULL) { 10494327Sdougm break; 10504327Sdougm } else { 10514327Sdougm /* is it the correct share? */ 10524327Sdougm path = xmlGetProp(node, 10534327Sdougm (xmlChar *)"path"); 10544327Sdougm if (path != NULL && 10554327Sdougm xmlStrcmp(path, 10564327Sdougm (xmlChar *)sharepath) == 0) { 10574327Sdougm xmlFree(path); 10584327Sdougm break; 10594327Sdougm } 10604327Sdougm xmlFree(path); 10614327Sdougm } 10623034Sdougm } 10633034Sdougm } 10643034Sdougm } 10653034Sdougm return ((sa_share_t)node); 10663034Sdougm } 10673034Sdougm 10683034Sdougm /* 10693034Sdougm * sa_get_next_share(share) 10703034Sdougm * Return the next share following the specified share 10713034Sdougm * from the internal list of shares. Returns NULL if there 10723034Sdougm * are no more shares. The list is relative to the same 10733034Sdougm * group. 10743034Sdougm */ 10753034Sdougm sa_share_t 10763034Sdougm sa_get_next_share(sa_share_t share) 10773034Sdougm { 10783034Sdougm xmlNodePtr node = NULL; 10793034Sdougm 10803034Sdougm if (share != NULL) { 10814327Sdougm for (node = ((xmlNodePtr)share)->next; node != NULL; 10823034Sdougm node = node->next) { 10834327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) { 10844327Sdougm break; 10854327Sdougm } 10863034Sdougm } 10873034Sdougm } 10883034Sdougm return ((sa_share_t)node); 10893034Sdougm } 10903034Sdougm 10913034Sdougm /* 10923034Sdougm * _sa_get_child_node(node, type) 10933034Sdougm * 10943034Sdougm * find the child node of the specified node that has "type". This is 10953034Sdougm * used to implement several internal functions. 10963034Sdougm */ 10973034Sdougm 10983034Sdougm static xmlNodePtr 10993034Sdougm _sa_get_child_node(xmlNodePtr node, xmlChar *type) 11003034Sdougm { 11013034Sdougm xmlNodePtr child; 11023034Sdougm for (child = node->xmlChildrenNode; child != NULL; 11033034Sdougm child = child->next) 11044327Sdougm if (xmlStrcmp(child->name, type) == 0) 11054327Sdougm return (child); 11063034Sdougm return ((xmlNodePtr)NULL); 11073034Sdougm } 11083034Sdougm 11093034Sdougm /* 11103034Sdougm * find_share(group, path) 11113034Sdougm * 11123034Sdougm * Search all the shares in the specified group for one that has the 11133034Sdougm * specified path. 11143034Sdougm */ 11153034Sdougm 11163034Sdougm static sa_share_t 11173034Sdougm find_share(sa_group_t group, char *sharepath) 11183034Sdougm { 11193034Sdougm sa_share_t share; 11203034Sdougm char *path; 11213034Sdougm 11223034Sdougm for (share = sa_get_share(group, NULL); share != NULL; 11233034Sdougm share = sa_get_next_share(share)) { 11244327Sdougm path = sa_get_share_attr(share, "path"); 11254327Sdougm if (path != NULL && strcmp(path, sharepath) == 0) { 11264327Sdougm sa_free_attr_string(path); 11274327Sdougm break; 11284327Sdougm } 11294327Sdougm if (path != NULL) 11304327Sdougm sa_free_attr_string(path); 11313034Sdougm } 11323034Sdougm return (share); 11333034Sdougm } 11343034Sdougm 11353034Sdougm /* 11363034Sdougm * sa_get_sub_group(group) 11373034Sdougm * 11383034Sdougm * Get the first sub-group of group. The sa_get_next_group() function 11393034Sdougm * can be used to get the rest. This is currently only used for ZFS 11403034Sdougm * sub-groups but could be used to implement a more general mechanism. 11413034Sdougm */ 11423034Sdougm 11433034Sdougm sa_group_t 11443034Sdougm sa_get_sub_group(sa_group_t group) 11453034Sdougm { 11463034Sdougm return ((sa_group_t)_sa_get_child_node((xmlNodePtr)group, 11474327Sdougm (xmlChar *)"group")); 11483034Sdougm } 11493034Sdougm 11503034Sdougm /* 11513034Sdougm * sa_find_share(sharepath) 11523034Sdougm * Finds a share regardless of group. In the future, this 11533034Sdougm * function should utilize a cache and hash table of some kind. 11543034Sdougm * The current assumption is that a path will only be shared 11553034Sdougm * once. In the future, this may change as implementation of 11563034Sdougm * resource names comes into being. 11573034Sdougm */ 11583034Sdougm sa_share_t 11593910Sdougm sa_find_share(sa_handle_t handle, char *sharepath) 11603034Sdougm { 11613034Sdougm sa_group_t group; 11623034Sdougm sa_group_t zgroup; 11633034Sdougm sa_share_t share = NULL; 11643034Sdougm int done = 0; 11653034Sdougm 11663910Sdougm for (group = sa_get_group(handle, NULL); group != NULL && !done; 11674327Sdougm group = sa_get_next_group(group)) { 11684327Sdougm if (is_zfs_group(group)) { 11694327Sdougm for (zgroup = 11704327Sdougm (sa_group_t)_sa_get_child_node((xmlNodePtr)group, 11714327Sdougm (xmlChar *)"group"); 11724327Sdougm zgroup != NULL; 11734327Sdougm zgroup = sa_get_next_group(zgroup)) { 11744327Sdougm share = find_share(zgroup, sharepath); 11754327Sdougm if (share != NULL) 11764327Sdougm break; 11774327Sdougm } 11784327Sdougm } else { 11794327Sdougm share = find_share(group, sharepath); 11804327Sdougm } 11814327Sdougm if (share != NULL) 11823034Sdougm break; 11833034Sdougm } 11843034Sdougm return (share); 11853034Sdougm } 11863034Sdougm 11873034Sdougm /* 11883348Sdougm * sa_check_path(group, path, strictness) 11893034Sdougm * 11903034Sdougm * check that path is a valid path relative to the group. Currently, 11913034Sdougm * we are ignoring the group and checking only the NFS rules. Later, 11923034Sdougm * we may want to use the group to then check against the protocols 11933348Sdougm * enabled on the group. The strictness values mean: 11943348Sdougm * SA_CHECK_NORMAL == only check newpath against shares that are active 11953348Sdougm * SA_CHECK_STRICT == check newpath against both active shares and those 11963348Sdougm * stored in the repository 11973034Sdougm */ 11983034Sdougm 11993034Sdougm int 12003348Sdougm sa_check_path(sa_group_t group, char *path, int strictness) 12013034Sdougm { 12023910Sdougm sa_handle_t handle; 12033910Sdougm 12043910Sdougm handle = sa_find_group_handle(group); 12053910Sdougm return (validpath(handle, path, strictness)); 12063034Sdougm } 12073034Sdougm 12083034Sdougm /* 12093034Sdougm * _sa_add_share(group, sharepath, persist, *error) 12103034Sdougm * 12113034Sdougm * common code for all types of add_share. sa_add_share() is the 12123034Sdougm * public API, we also need to be able to do this when parsing legacy 12133034Sdougm * files and construction of the internal configuration while 12143034Sdougm * extracting config info from SMF. 12153034Sdougm */ 12163034Sdougm 12173034Sdougm sa_share_t 12183034Sdougm _sa_add_share(sa_group_t group, char *sharepath, int persist, int *error) 12193034Sdougm { 12203034Sdougm xmlNodePtr node = NULL; 12213034Sdougm int err; 12223034Sdougm 12233034Sdougm err = SA_OK; /* assume success */ 12243034Sdougm 12254327Sdougm node = xmlNewChild((xmlNodePtr)group, NULL, (xmlChar *)"share", NULL); 12263034Sdougm if (node != NULL) { 12274327Sdougm xmlSetProp(node, (xmlChar *)"path", (xmlChar *)sharepath); 12284327Sdougm xmlSetProp(node, (xmlChar *)"type", 12294327Sdougm persist ? (xmlChar *)"persist" : (xmlChar *)"transient"); 12304327Sdougm if (persist != SA_SHARE_TRANSIENT) { 12314327Sdougm /* 12324327Sdougm * persistent shares come in two flavors: SMF and 12334327Sdougm * ZFS. Sort this one out based on target group and 12344327Sdougm * path type. Currently, only NFS is supported in the 12354327Sdougm * ZFS group and it is always on. 12364327Sdougm */ 12374327Sdougm if (sa_group_is_zfs(group) && 12384327Sdougm sa_path_is_zfs(sharepath)) { 12394327Sdougm err = sa_zfs_set_sharenfs(group, sharepath, 1); 12404327Sdougm } else { 12414327Sdougm sa_handle_impl_t impl_handle; 12424327Sdougm impl_handle = 12434327Sdougm (sa_handle_impl_t)sa_find_group_handle( 12444327Sdougm group); 12454327Sdougm if (impl_handle != NULL) { 12464327Sdougm err = sa_commit_share( 12474327Sdougm impl_handle->scfhandle, group, 12484327Sdougm (sa_share_t)node); 12494327Sdougm } else { 12504327Sdougm err = SA_SYSTEM_ERR; 12514327Sdougm } 12524327Sdougm } 12533034Sdougm } 12544327Sdougm if (err == SA_NO_PERMISSION && persist & SA_SHARE_PARSER) { 12554327Sdougm /* called by the dfstab parser so could be a show */ 12564327Sdougm err = SA_OK; 12574327Sdougm } 12584327Sdougm if (err != SA_OK) { 12594327Sdougm /* 12604327Sdougm * we couldn't commit to the repository so undo 12614327Sdougm * our internal state to reflect reality. 12624327Sdougm */ 12634327Sdougm xmlUnlinkNode(node); 12644327Sdougm xmlFreeNode(node); 12654327Sdougm node = NULL; 12664327Sdougm } 12673034Sdougm } else { 12684327Sdougm err = SA_NO_MEMORY; 12693034Sdougm } 12703034Sdougm if (error != NULL) 12714327Sdougm *error = err; 12723034Sdougm return (node); 12733034Sdougm } 12743034Sdougm 12753034Sdougm /* 12763034Sdougm * sa_add_share(group, sharepath, persist, *error) 12773034Sdougm * 12783034Sdougm * Add a new share object to the specified group. The share will 12793034Sdougm * have the specified sharepath and will only be constructed if 12803034Sdougm * it is a valid path to be shared. NULL is returned on error 12813034Sdougm * and a detailed error value will be returned via the error 12823034Sdougm * pointer. 12833034Sdougm */ 12843034Sdougm sa_share_t 12853034Sdougm sa_add_share(sa_group_t group, char *sharepath, int persist, int *error) 12863034Sdougm { 12873034Sdougm xmlNodePtr node = NULL; 12883034Sdougm sa_share_t dup; 12893348Sdougm int strictness = SA_CHECK_NORMAL; 12903910Sdougm sa_handle_t handle; 12913348Sdougm 12923348Sdougm /* 12933348Sdougm * If the share is to be permanent, use strict checking so a 12943348Sdougm * bad config doesn't get created. Transient shares only need 12953348Sdougm * to check against the currently active 12963348Sdougm * shares. SA_SHARE_PARSER is a modifier used internally to 12973348Sdougm * indicate that we are being called by the dfstab parser and 12983348Sdougm * that we need strict checking in all cases. Normally persist 12993348Sdougm * is in integer value but SA_SHARE_PARSER may be or'd into 13003348Sdougm * it as an override. 13013348Sdougm */ 13023348Sdougm if (persist & SA_SHARE_PARSER || persist == SA_SHARE_PERMANENT) 13034327Sdougm strictness = SA_CHECK_STRICT; 13043034Sdougm 13053910Sdougm handle = sa_find_group_handle(group); 13063910Sdougm 13073910Sdougm if ((dup = sa_find_share(handle, sharepath)) == NULL && 13084327Sdougm (*error = sa_check_path(group, sharepath, strictness)) == SA_OK) { 13094327Sdougm node = _sa_add_share(group, sharepath, persist, error); 13103034Sdougm } 13113034Sdougm if (dup != NULL) 13124327Sdougm *error = SA_DUPLICATE_NAME; 13133034Sdougm 13143034Sdougm return ((sa_share_t)node); 13153034Sdougm } 13163034Sdougm 13173034Sdougm /* 13183034Sdougm * sa_enable_share(share, protocol) 13193034Sdougm * Enable the specified share to the specified protocol. 13203034Sdougm * If protocol is NULL, then all protocols. 13213034Sdougm */ 13223034Sdougm int 13233034Sdougm sa_enable_share(sa_share_t share, char *protocol) 13243034Sdougm { 13253034Sdougm char *sharepath; 13263034Sdougm struct stat st; 13273034Sdougm int err = 0; 13283034Sdougm 13293034Sdougm sharepath = sa_get_share_attr(share, "path"); 13303034Sdougm if (stat(sharepath, &st) < 0) { 13314327Sdougm err = SA_NO_SUCH_PATH; 13323034Sdougm } else { 13334327Sdougm /* tell the server about the share */ 13344327Sdougm if (protocol != NULL) { 13354327Sdougm /* lookup protocol specific handler */ 13364327Sdougm err = sa_proto_share(protocol, share); 13374327Sdougm if (err == SA_OK) 13384327Sdougm (void) sa_set_share_attr(share, "shared", 13394327Sdougm "true"); 13404327Sdougm } else { 13414327Sdougm /* 13424327Sdougm * Tell all protocols. Only NFS for now but 13434327Sdougm * SMB is coming. 13444327Sdougm */ 13454327Sdougm err = sa_proto_share("nfs", share); 13464327Sdougm (void) sa_set_share_attr(share, "shared", "true"); 13474327Sdougm } 13483034Sdougm } 13493034Sdougm if (sharepath != NULL) 13504327Sdougm sa_free_attr_string(sharepath); 13513034Sdougm return (err); 13523034Sdougm } 13533034Sdougm 13543034Sdougm /* 13553034Sdougm * sa_disable_share(share, protocol) 13563034Sdougm * Disable the specified share to the specified protocol. 13573034Sdougm * If protocol is NULL, then all protocols. 13583034Sdougm */ 13593034Sdougm int 13603034Sdougm sa_disable_share(sa_share_t share, char *protocol) 13613034Sdougm { 13623034Sdougm char *path; 13633034Sdougm char *shared; 13643034Sdougm int ret = SA_OK; 13653034Sdougm 13663034Sdougm path = sa_get_share_attr(share, "path"); 13673034Sdougm shared = sa_get_share_attr(share, "shared"); 13683034Sdougm 13693034Sdougm if (protocol != NULL) { 13704327Sdougm ret = sa_proto_unshare(protocol, path); 13713034Sdougm } else { 13724327Sdougm /* need to do all protocols */ 13734327Sdougm ret = sa_proto_unshare("nfs", path); 13743034Sdougm } 13753034Sdougm if (ret == SA_OK) 13763034Sdougm (void) sa_set_share_attr(share, "shared", NULL); 13773034Sdougm if (path != NULL) 13784327Sdougm sa_free_attr_string(path); 13793034Sdougm if (shared != NULL) 13804327Sdougm sa_free_attr_string(shared); 13813034Sdougm return (ret); 13823034Sdougm } 13833034Sdougm 13843034Sdougm /* 13853034Sdougm * sa_remove_share(share) 13863034Sdougm * 13873034Sdougm * remove the specified share from its containing group. 13883034Sdougm * Remove from the SMF or ZFS configuration space. 13893034Sdougm */ 13903034Sdougm 13913034Sdougm int 13923034Sdougm sa_remove_share(sa_share_t share) 13933034Sdougm { 13943034Sdougm sa_group_t group; 13953034Sdougm int ret = SA_OK; 13963034Sdougm char *type; 13973034Sdougm int transient = 0; 13983034Sdougm char *groupname; 13993034Sdougm char *zfs; 14003034Sdougm 14013034Sdougm type = sa_get_share_attr(share, "type"); 14023034Sdougm group = sa_get_parent_group(share); 14033034Sdougm zfs = sa_get_group_attr(group, "zfs"); 14043034Sdougm groupname = sa_get_group_attr(group, "name"); 14053034Sdougm if (type != NULL && strcmp(type, "persist") != 0) 14064327Sdougm transient = 1; 14073034Sdougm if (type != NULL) 14084327Sdougm sa_free_attr_string(type); 14093034Sdougm 14103034Sdougm /* remove the node from its group then free the memory */ 14113034Sdougm 14123034Sdougm /* 14133034Sdougm * need to test if "busy" 14143034Sdougm */ 14153034Sdougm /* only do SMF action if permanent */ 14163034Sdougm if (!transient || zfs != NULL) { 14174327Sdougm /* remove from legacy dfstab as well as possible SMF */ 14184327Sdougm ret = sa_delete_legacy(share); 14194327Sdougm if (ret == SA_OK) { 14204327Sdougm if (!sa_group_is_zfs(group)) { 14214327Sdougm sa_handle_impl_t impl_handle; 14224327Sdougm impl_handle = (sa_handle_impl_t) 14234327Sdougm sa_find_group_handle(group); 14244327Sdougm if (impl_handle != NULL) { 14254327Sdougm ret = sa_delete_share( 14264327Sdougm impl_handle->scfhandle, group, 14274327Sdougm share); 14284327Sdougm } else { 14294327Sdougm ret = SA_SYSTEM_ERR; 14304327Sdougm } 14314327Sdougm } else { 14324327Sdougm char *sharepath = sa_get_share_attr(share, 14334327Sdougm "path"); 14344327Sdougm if (sharepath != NULL) { 14354327Sdougm ret = sa_zfs_set_sharenfs(group, 14364327Sdougm sharepath, 0); 14374327Sdougm sa_free_attr_string(sharepath); 14384327Sdougm } 14394327Sdougm } 14403034Sdougm } 14413034Sdougm } 14423034Sdougm if (groupname != NULL) 14434327Sdougm sa_free_attr_string(groupname); 14443034Sdougm if (zfs != NULL) 14454327Sdougm sa_free_attr_string(zfs); 14463034Sdougm 14473034Sdougm xmlUnlinkNode((xmlNodePtr)share); 14483034Sdougm xmlFreeNode((xmlNodePtr)share); 14493034Sdougm return (ret); 14503034Sdougm } 14513034Sdougm 14523034Sdougm /* 14533034Sdougm * sa_move_share(group, share) 14543034Sdougm * 14553034Sdougm * move the specified share to the specified group. Update SMF 14563034Sdougm * appropriately. 14573034Sdougm */ 14583034Sdougm 14593034Sdougm int 14603034Sdougm sa_move_share(sa_group_t group, sa_share_t share) 14613034Sdougm { 14623034Sdougm sa_group_t oldgroup; 14633034Sdougm int ret = SA_OK; 14643034Sdougm 14653034Sdougm /* remove the node from its group then free the memory */ 14663034Sdougm 14673034Sdougm oldgroup = sa_get_parent_group(share); 14683034Sdougm if (oldgroup != group) { 14694327Sdougm sa_handle_impl_t impl_handle; 14704327Sdougm xmlUnlinkNode((xmlNodePtr)share); 14713034Sdougm /* 14724327Sdougm * now that the share isn't in its old group, add to 14734327Sdougm * the new one 14743034Sdougm */ 14754327Sdougm xmlAddChild((xmlNodePtr)group, (xmlNodePtr)share); 14764327Sdougm /* need to deal with SMF */ 14774327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 14784327Sdougm if (impl_handle != NULL) { 14794327Sdougm /* 14804327Sdougm * need to remove from old group first and then add to 14814327Sdougm * new group. Ideally, we would do the other order but 14824327Sdougm * need to avoid having the share in two groups at the 14834327Sdougm * same time. 14844327Sdougm */ 14854327Sdougm ret = sa_delete_share(impl_handle->scfhandle, oldgroup, 14864327Sdougm share); 14874327Sdougm if (ret == SA_OK) 14884327Sdougm ret = sa_commit_share(impl_handle->scfhandle, 14894327Sdougm group, share); 14904327Sdougm } else { 14914327Sdougm ret = SA_SYSTEM_ERR; 14924327Sdougm } 14933034Sdougm } 14943034Sdougm return (ret); 14953034Sdougm } 14963034Sdougm 14973034Sdougm /* 14983034Sdougm * sa_get_parent_group(share) 14993034Sdougm * 15003034Sdougm * Return the containg group for the share. If a group was actually 15013034Sdougm * passed in, we don't want a parent so return NULL. 15023034Sdougm */ 15033034Sdougm 15043034Sdougm sa_group_t 15053034Sdougm sa_get_parent_group(sa_share_t share) 15063034Sdougm { 15073034Sdougm xmlNodePtr node = NULL; 15083034Sdougm if (share != NULL) { 15094327Sdougm node = ((xmlNodePtr)share)->parent; 15103034Sdougm /* 15113034Sdougm * make sure parent is a group and not sharecfg since 15123034Sdougm * we may be cheating and passing in a group. 15133034Sdougm * Eventually, groups of groups might come into being. 15143034Sdougm */ 15154327Sdougm if (node == NULL || 15164327Sdougm xmlStrcmp(node->name, (xmlChar *)"sharecfg") == 0) 15174327Sdougm node = NULL; 15183034Sdougm } 15193034Sdougm return ((sa_group_t)node); 15203034Sdougm } 15213034Sdougm 15223034Sdougm /* 15233910Sdougm * _sa_create_group(impl_handle, groupname) 15243034Sdougm * 15253034Sdougm * Create a group in the document. The caller will need to deal with 15263034Sdougm * configuration store and activation. 15273034Sdougm */ 15283034Sdougm 15293034Sdougm sa_group_t 15303910Sdougm _sa_create_group(sa_handle_impl_t impl_handle, char *groupname) 15313034Sdougm { 15323034Sdougm xmlNodePtr node = NULL; 15333034Sdougm 15343034Sdougm if (sa_valid_group_name(groupname)) { 15354327Sdougm node = xmlNewChild(impl_handle->tree, NULL, (xmlChar *)"group", 15364327Sdougm NULL); 15374327Sdougm if (node != NULL) { 15384327Sdougm xmlSetProp(node, (xmlChar *)"name", 15394327Sdougm (xmlChar *)groupname); 15404327Sdougm xmlSetProp(node, (xmlChar *)"state", 15414327Sdougm (xmlChar *)"enabled"); 15424327Sdougm } 15433034Sdougm } 15443034Sdougm return ((sa_group_t)node); 15453034Sdougm } 15463034Sdougm 15473034Sdougm /* 15483034Sdougm * _sa_create_zfs_group(group, groupname) 15493034Sdougm * 15503034Sdougm * Create a ZFS subgroup under the specified group. This may 15513034Sdougm * eventually form the basis of general sub-groups, but is currently 15523034Sdougm * restricted to ZFS. 15533034Sdougm */ 15543034Sdougm sa_group_t 15553034Sdougm _sa_create_zfs_group(sa_group_t group, char *groupname) 15563034Sdougm { 15573034Sdougm xmlNodePtr node = NULL; 15583034Sdougm 15594327Sdougm node = xmlNewChild((xmlNodePtr)group, NULL, (xmlChar *)"group", NULL); 15603034Sdougm if (node != NULL) { 15613034Sdougm xmlSetProp(node, (xmlChar *)"name", (xmlChar *)groupname); 15623034Sdougm xmlSetProp(node, (xmlChar *)"state", (xmlChar *)"enabled"); 15633034Sdougm } 15643034Sdougm 15653034Sdougm return ((sa_group_t)node); 15663034Sdougm } 15673034Sdougm 15683034Sdougm /* 15693034Sdougm * sa_create_group(groupname, *error) 15703034Sdougm * 15713034Sdougm * Create a new group with groupname. Need to validate that it is a 15723034Sdougm * legal name for SMF and the construct the SMF service instance of 15733034Sdougm * svc:/network/shares/group to implement the group. All necessary 15743034Sdougm * operational properties must be added to the group at this point 15753034Sdougm * (via the SMF transaction model). 15763034Sdougm */ 15773034Sdougm sa_group_t 15783910Sdougm sa_create_group(sa_handle_t handle, char *groupname, int *error) 15793034Sdougm { 15803034Sdougm xmlNodePtr node = NULL; 15813034Sdougm sa_group_t group; 15823034Sdougm int ret; 15834327Sdougm char rbacstr[SA_STRSIZE]; 15843910Sdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle; 15853034Sdougm 15863034Sdougm ret = SA_OK; 15873034Sdougm 15883910Sdougm if (impl_handle == NULL || impl_handle->scfhandle == NULL) { 15894327Sdougm ret = SA_SYSTEM_ERR; 15904327Sdougm goto err; 15913034Sdougm } 15923034Sdougm 15933910Sdougm group = sa_get_group(handle, groupname); 15943034Sdougm if (group != NULL) { 15954327Sdougm ret = SA_DUPLICATE_NAME; 15963034Sdougm } else { 15974327Sdougm if (sa_valid_group_name(groupname)) { 15984327Sdougm node = xmlNewChild(impl_handle->tree, NULL, 15994327Sdougm (xmlChar *)"group", NULL); 16004327Sdougm if (node != NULL) { 16014327Sdougm xmlSetProp(node, (xmlChar *)"name", 16024327Sdougm (xmlChar *)groupname); 16034327Sdougm /* default to the group being enabled */ 16044327Sdougm xmlSetProp(node, (xmlChar *)"state", 16054327Sdougm (xmlChar *)"enabled"); 16064327Sdougm ret = sa_create_instance(impl_handle->scfhandle, 16074327Sdougm groupname); 16084327Sdougm if (ret == SA_OK) { 16094327Sdougm ret = sa_start_transaction( 16104327Sdougm impl_handle->scfhandle, 16114327Sdougm "operation"); 16124327Sdougm } 16134327Sdougm if (ret == SA_OK) { 16144327Sdougm ret = sa_set_property( 16154327Sdougm impl_handle->scfhandle, 16164327Sdougm "state", "enabled"); 16174327Sdougm if (ret == SA_OK) { 16184327Sdougm ret = sa_end_transaction( 16194327Sdougm impl_handle->scfhandle); 16204327Sdougm } else { 16214327Sdougm sa_abort_transaction( 16224327Sdougm impl_handle->scfhandle); 16234327Sdougm } 16244327Sdougm } 16254327Sdougm if (ret == SA_OK) { 16264327Sdougm /* initialize the RBAC strings */ 16274327Sdougm ret = sa_start_transaction( 16284327Sdougm impl_handle->scfhandle, 16294327Sdougm "general"); 16304327Sdougm if (ret == SA_OK) { 16314327Sdougm (void) snprintf(rbacstr, 16324327Sdougm sizeof (rbacstr), "%s.%s", 16334327Sdougm SA_RBAC_MANAGE, groupname); 16344327Sdougm ret = sa_set_property( 16354327Sdougm impl_handle->scfhandle, 16363034Sdougm "action_authorization", 16373034Sdougm rbacstr); 16384327Sdougm } 16394327Sdougm if (ret == SA_OK) { 16404327Sdougm (void) snprintf(rbacstr, 16414327Sdougm sizeof (rbacstr), "%s.%s", 16424327Sdougm SA_RBAC_VALUE, groupname); 16434327Sdougm ret = sa_set_property( 16444327Sdougm impl_handle->scfhandle, 16453034Sdougm "value_authorization", 16463034Sdougm rbacstr); 16474327Sdougm } 16484327Sdougm if (ret == SA_OK) { 16494327Sdougm ret = sa_end_transaction( 16504327Sdougm impl_handle->scfhandle); 16514327Sdougm } else { 16524327Sdougm sa_abort_transaction( 16534327Sdougm impl_handle->scfhandle); 16544327Sdougm } 16554327Sdougm } 16564327Sdougm if (ret != SA_OK) { 16574327Sdougm /* 16584327Sdougm * Couldn't commit the group 16594327Sdougm * so we need to undo 16604327Sdougm * internally. 16614327Sdougm */ 16624327Sdougm xmlUnlinkNode(node); 16634327Sdougm xmlFreeNode(node); 16644327Sdougm node = NULL; 16654327Sdougm } 16663034Sdougm } else { 16674327Sdougm ret = SA_NO_MEMORY; 16683034Sdougm } 16693034Sdougm } else { 16704327Sdougm ret = SA_INVALID_NAME; 16713034Sdougm } 16723034Sdougm } 16733034Sdougm err: 16743034Sdougm if (error != NULL) 16754327Sdougm *error = ret; 16763034Sdougm return ((sa_group_t)node); 16773034Sdougm } 16783034Sdougm 16793034Sdougm /* 16803034Sdougm * sa_remove_group(group) 16813034Sdougm * 16823034Sdougm * Remove the specified group. This deletes from the SMF repository. 16833034Sdougm * All property groups and properties are removed. 16843034Sdougm */ 16853034Sdougm 16863034Sdougm int 16873034Sdougm sa_remove_group(sa_group_t group) 16883034Sdougm { 16893034Sdougm char *name; 16903034Sdougm int ret = SA_OK; 16913910Sdougm sa_handle_impl_t impl_handle; 16923034Sdougm 16933910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 16943910Sdougm if (impl_handle != NULL) { 16954327Sdougm name = sa_get_group_attr(group, "name"); 16964327Sdougm if (name != NULL) { 16974327Sdougm ret = sa_delete_instance(impl_handle->scfhandle, name); 16984327Sdougm sa_free_attr_string(name); 16994327Sdougm } 17004327Sdougm xmlUnlinkNode((xmlNodePtr)group); /* make sure unlinked */ 17014327Sdougm xmlFreeNode((xmlNodePtr)group); /* now it is gone */ 17023910Sdougm } else { 17034327Sdougm ret = SA_SYSTEM_ERR; 17043034Sdougm } 17053034Sdougm return (ret); 17063034Sdougm } 17073034Sdougm 17083034Sdougm /* 17093034Sdougm * sa_update_config() 17103034Sdougm * 17113034Sdougm * Used to update legacy files that need to be updated in bulk 17123034Sdougm * Currently, this is a placeholder and will go away in a future 17133034Sdougm * release. 17143034Sdougm */ 17153034Sdougm 17163034Sdougm int 17173910Sdougm sa_update_config(sa_handle_t handle) 17183034Sdougm { 17193034Sdougm /* 17203034Sdougm * do legacy files first so we can tell when they change. 17213034Sdougm * This will go away when we start updating individual records 17223034Sdougm * rather than the whole file. 17233034Sdougm */ 17243910Sdougm update_legacy_config(handle); 17253034Sdougm return (SA_OK); 17263034Sdougm } 17273034Sdougm 17283034Sdougm /* 17293034Sdougm * get_node_attr(node, tag) 17303034Sdougm * 17313034Sdougm * Get the speficied tag(attribute) if it exists on the node. This is 17323034Sdougm * used internally by a number of attribute oriented functions. 17333034Sdougm */ 17343034Sdougm 17353034Sdougm static char * 17363034Sdougm get_node_attr(void *nodehdl, char *tag) 17373034Sdougm { 17383034Sdougm xmlNodePtr node = (xmlNodePtr)nodehdl; 17393034Sdougm xmlChar *name = NULL; 17403034Sdougm 17414327Sdougm if (node != NULL) 17423034Sdougm name = xmlGetProp(node, (xmlChar *)tag); 17433034Sdougm return ((char *)name); 17443034Sdougm } 17453034Sdougm 17463034Sdougm /* 17473034Sdougm * get_node_attr(node, tag) 17483034Sdougm * 17493034Sdougm * Set the speficied tag(attribute) to the specified value This is 17503034Sdougm * used internally by a number of attribute oriented functions. It 17513034Sdougm * doesn't update the repository, only the internal document state. 17523034Sdougm */ 17533034Sdougm 17543034Sdougm void 17553034Sdougm set_node_attr(void *nodehdl, char *tag, char *value) 17563034Sdougm { 17573034Sdougm xmlNodePtr node = (xmlNodePtr)nodehdl; 17583034Sdougm if (node != NULL && tag != NULL) { 17594327Sdougm if (value != NULL) 17603034Sdougm xmlSetProp(node, (xmlChar *)tag, (xmlChar *)value); 17614327Sdougm else 17623034Sdougm xmlUnsetProp(node, (xmlChar *)tag); 17633034Sdougm } 17643034Sdougm } 17653034Sdougm 17663034Sdougm /* 17673034Sdougm * sa_get_group_attr(group, tag) 17683034Sdougm * 17693034Sdougm * Get the specied attribute, if defined, for the group. 17703034Sdougm */ 17713034Sdougm 17723034Sdougm char * 17733034Sdougm sa_get_group_attr(sa_group_t group, char *tag) 17743034Sdougm { 17753034Sdougm return (get_node_attr((void *)group, tag)); 17763034Sdougm } 17773034Sdougm 17783034Sdougm /* 17793034Sdougm * sa_set_group_attr(group, tag, value) 17803034Sdougm * 17813034Sdougm * set the specified tag/attribute on the group using value as its 17823034Sdougm * value. 17833034Sdougm * 17843034Sdougm * This will result in setting the property in the SMF repository as 17853034Sdougm * well as in the internal document. 17863034Sdougm */ 17873034Sdougm 17883034Sdougm int 17893034Sdougm sa_set_group_attr(sa_group_t group, char *tag, char *value) 17903034Sdougm { 17913034Sdougm int ret; 17923034Sdougm char *groupname; 17933910Sdougm sa_handle_impl_t impl_handle; 17943034Sdougm 17953910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 17963910Sdougm if (impl_handle != NULL) { 17974327Sdougm groupname = sa_get_group_attr(group, "name"); 17984327Sdougm ret = sa_get_instance(impl_handle->scfhandle, groupname); 17993910Sdougm if (ret == SA_OK) { 18004327Sdougm set_node_attr((void *)group, tag, value); 18014327Sdougm ret = sa_start_transaction(impl_handle->scfhandle, 18024327Sdougm "operation"); 18034327Sdougm if (ret == SA_OK) { 18044327Sdougm ret = sa_set_property(impl_handle->scfhandle, 18054327Sdougm tag, value); 18064327Sdougm if (ret == SA_OK) 18074327Sdougm (void) sa_end_transaction( 18084327Sdougm impl_handle->scfhandle); 18094327Sdougm else 18104327Sdougm sa_abort_transaction( 18114327Sdougm impl_handle->scfhandle); 18124327Sdougm } 18133034Sdougm } 18144327Sdougm if (groupname != NULL) 18154327Sdougm sa_free_attr_string(groupname); 18163910Sdougm } else { 18174327Sdougm ret = SA_SYSTEM_ERR; 18183034Sdougm } 18193034Sdougm return (ret); 18203034Sdougm } 18213034Sdougm 18223034Sdougm /* 18233034Sdougm * sa_get_share_attr(share, tag) 18243034Sdougm * 18253034Sdougm * Return the value of the tag/attribute set on the specified 18263034Sdougm * share. Returns NULL if the tag doesn't exist. 18273034Sdougm */ 18283034Sdougm 18293034Sdougm char * 18303034Sdougm sa_get_share_attr(sa_share_t share, char *tag) 18313034Sdougm { 18323034Sdougm return (get_node_attr((void *)share, tag)); 18333034Sdougm } 18343034Sdougm 18353034Sdougm /* 18363034Sdougm * sa_get_resource(group, resource) 18373034Sdougm * 18383034Sdougm * Search all the shares in the speified group for a share with a 18393034Sdougm * resource name matching the one specified. 18403034Sdougm * 18413034Sdougm * In the future, it may be advantageous to allow group to be NULL and 18423034Sdougm * search all groups but that isn't needed at present. 18433034Sdougm */ 18443034Sdougm 18453034Sdougm sa_share_t 18463034Sdougm sa_get_resource(sa_group_t group, char *resource) 18473034Sdougm { 18483034Sdougm sa_share_t share = NULL; 18493034Sdougm char *name = NULL; 18503034Sdougm 18513034Sdougm if (resource != NULL) { 18524327Sdougm for (share = sa_get_share(group, NULL); share != NULL; 18534327Sdougm share = sa_get_next_share(share)) { 18544327Sdougm name = sa_get_share_attr(share, "resource"); 18554327Sdougm if (name != NULL) { 18564327Sdougm if (strcmp(name, resource) == 0) 18574327Sdougm break; 18584327Sdougm sa_free_attr_string(name); 18594327Sdougm name = NULL; 18604327Sdougm } 18613034Sdougm } 18624327Sdougm if (name != NULL) 18634327Sdougm sa_free_attr_string(name); 18643034Sdougm } 18653034Sdougm return ((sa_share_t)share); 18663034Sdougm } 18673034Sdougm 18683034Sdougm /* 18693034Sdougm * _sa_set_share_description(share, description) 18703034Sdougm * 18713034Sdougm * Add a description tag with text contents to the specified share. 18723034Sdougm * A separate XML tag is used rather than a property. 18733034Sdougm */ 18743034Sdougm 18753034Sdougm xmlNodePtr 18763034Sdougm _sa_set_share_description(sa_share_t share, char *content) 18773034Sdougm { 18783034Sdougm xmlNodePtr node; 18794327Sdougm node = xmlNewChild((xmlNodePtr)share, NULL, (xmlChar *)"description", 18804327Sdougm NULL); 18813034Sdougm xmlNodeSetContent(node, (xmlChar *)content); 18823034Sdougm return (node); 18833034Sdougm } 18843034Sdougm 18853034Sdougm /* 18863034Sdougm * sa_set_share_attr(share, tag, value) 18873034Sdougm * 18883034Sdougm * Set the share attribute specified by tag to the specified value. In 18893034Sdougm * the case of "resource", enforce a no duplicates in a group rule. If 18903034Sdougm * the share is not transient, commit the changes to the repository 18913034Sdougm * else just update the share internally. 18923034Sdougm */ 18933034Sdougm 18943034Sdougm int 18953034Sdougm sa_set_share_attr(sa_share_t share, char *tag, char *value) 18963034Sdougm { 18973034Sdougm sa_group_t group; 18983034Sdougm sa_share_t resource; 18993034Sdougm int ret = SA_OK; 19003034Sdougm 19013034Sdougm group = sa_get_parent_group(share); 19023034Sdougm 19033034Sdougm /* 19043034Sdougm * There are some attributes that may have specific 19053034Sdougm * restrictions on them. Initially, only "resource" has 19063034Sdougm * special meaning that needs to be checked. Only one instance 19073034Sdougm * of a resource name may exist within a group. 19083034Sdougm */ 19093034Sdougm 19103034Sdougm if (strcmp(tag, "resource") == 0) { 19114327Sdougm resource = sa_get_resource(group, value); 19124327Sdougm if (resource != share && resource != NULL) 19134327Sdougm ret = SA_DUPLICATE_NAME; 19143034Sdougm } 19153034Sdougm if (ret == SA_OK) { 19164327Sdougm set_node_attr((void *)share, tag, value); 19174327Sdougm if (group != NULL) { 19184327Sdougm char *type; 19194327Sdougm /* we can probably optimize this some */ 19204327Sdougm type = sa_get_share_attr(share, "type"); 19214327Sdougm if (type == NULL || strcmp(type, "transient") != 0) { 19224327Sdougm sa_handle_impl_t impl_handle; 19234327Sdougm impl_handle = 19244327Sdougm (sa_handle_impl_t)sa_find_group_handle( 19254327Sdougm group); 19264327Sdougm if (impl_handle != NULL) { 19274327Sdougm ret = sa_commit_share( 19284327Sdougm impl_handle->scfhandle, group, 19294327Sdougm share); 19304327Sdougm } else { 19314327Sdougm ret = SA_SYSTEM_ERR; 19324327Sdougm } 19334327Sdougm } 19344327Sdougm if (type != NULL) 19354327Sdougm sa_free_attr_string(type); 19363910Sdougm } 19373034Sdougm } 19383034Sdougm return (ret); 19393034Sdougm } 19403034Sdougm 19413034Sdougm /* 19423034Sdougm * sa_get_property_attr(prop, tag) 19433034Sdougm * 19443034Sdougm * Get the value of the specified property attribute. Standard 19453034Sdougm * attributes are "type" and "value". 19463034Sdougm */ 19473034Sdougm 19483034Sdougm char * 19493034Sdougm sa_get_property_attr(sa_property_t prop, char *tag) 19503034Sdougm { 19513034Sdougm return (get_node_attr((void *)prop, tag)); 19523034Sdougm } 19533034Sdougm 19543034Sdougm /* 19553034Sdougm * sa_get_optionset_attr(prop, tag) 19563034Sdougm * 19573034Sdougm * Get the value of the specified property attribute. Standard 19583034Sdougm * attribute is "type". 19593034Sdougm */ 19603034Sdougm 19613034Sdougm char * 19623034Sdougm sa_get_optionset_attr(sa_property_t optionset, char *tag) 19633034Sdougm { 19643034Sdougm return (get_node_attr((void *)optionset, tag)); 19653034Sdougm 19663034Sdougm } 19673034Sdougm 19683034Sdougm /* 19693034Sdougm * sa_set_optionset_attr(optionset, tag, value) 19703034Sdougm * 19713034Sdougm * Set the specified attribute(tag) to the specified value on the 19723034Sdougm * optionset. 19733034Sdougm */ 19743034Sdougm 19753034Sdougm void 19763034Sdougm sa_set_optionset_attr(sa_group_t optionset, char *tag, char *value) 19773034Sdougm { 19783034Sdougm set_node_attr((void *)optionset, tag, value); 19793034Sdougm } 19803034Sdougm 19813034Sdougm /* 19823034Sdougm * sa_free_attr_string(string) 19833034Sdougm * 19843034Sdougm * Free the string that was returned in one of the sa_get_*_attr() 19853034Sdougm * functions. 19863034Sdougm */ 19873034Sdougm 19883034Sdougm void 19893034Sdougm sa_free_attr_string(char *string) 19903034Sdougm { 19913034Sdougm xmlFree((xmlChar *)string); 19923034Sdougm } 19933034Sdougm 19943034Sdougm /* 19953034Sdougm * sa_get_optionset(group, proto) 19963034Sdougm * 19973034Sdougm * Return the optionset, if it exists, that is associated with the 19983034Sdougm * specified protocol. 19993034Sdougm */ 20003034Sdougm 20013034Sdougm sa_optionset_t 20023034Sdougm sa_get_optionset(void *group, char *proto) 20033034Sdougm { 20043034Sdougm xmlNodePtr node; 20053034Sdougm xmlChar *value = NULL; 20063034Sdougm 20073034Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 20084327Sdougm node = node->next) { 20093034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) { 20104327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 20114327Sdougm if (proto != NULL) { 20124327Sdougm if (value != NULL && 20134327Sdougm xmlStrcmp(value, (xmlChar *)proto) == 0) { 20144327Sdougm break; 20154327Sdougm } 20164327Sdougm if (value != NULL) { 20174327Sdougm xmlFree(value); 20184327Sdougm value = NULL; 20194327Sdougm } 20204327Sdougm } else { 20214327Sdougm break; 20223034Sdougm } 20233034Sdougm } 20243034Sdougm } 20253034Sdougm if (value != NULL) 20264327Sdougm xmlFree(value); 20273034Sdougm return ((sa_optionset_t)node); 20283034Sdougm } 20293034Sdougm 20303034Sdougm /* 20313034Sdougm * sa_get_next_optionset(optionset) 20323034Sdougm * 20333034Sdougm * Return the next optionset in the group. NULL if this was the last. 20343034Sdougm */ 20353034Sdougm 20363034Sdougm sa_optionset_t 20373034Sdougm sa_get_next_optionset(sa_optionset_t optionset) 20383034Sdougm { 20393034Sdougm xmlNodePtr node; 20403034Sdougm 20413034Sdougm for (node = ((xmlNodePtr)optionset)->next; node != NULL; 20424327Sdougm node = node->next) { 20433034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) { 20443034Sdougm break; 20453034Sdougm } 20463034Sdougm } 20473034Sdougm return ((sa_optionset_t)node); 20483034Sdougm } 20493034Sdougm 20503034Sdougm /* 20513034Sdougm * sa_get_security(group, sectype, proto) 20523034Sdougm * 20533034Sdougm * Return the security optionset. The internal name is a hold over 20543034Sdougm * from the implementation and will be changed before the API is 20553034Sdougm * finalized. This is really a named optionset that can be negotiated 20563034Sdougm * as a group of properties (like NFS security options). 20573034Sdougm */ 20583034Sdougm 20593034Sdougm sa_security_t 20603034Sdougm sa_get_security(sa_group_t group, char *sectype, char *proto) 20613034Sdougm { 20623034Sdougm xmlNodePtr node; 20633034Sdougm xmlChar *value = NULL; 20643034Sdougm 20653034Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 20664327Sdougm node = node->next) { 20674327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) { 20684327Sdougm if (proto != NULL) { 20694327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 20704327Sdougm if (value == NULL || 20714327Sdougm (value != NULL && 20724327Sdougm xmlStrcmp(value, (xmlChar *)proto) != 0)) { 20734327Sdougm /* it doesn't match so continue */ 20744327Sdougm xmlFree(value); 20754327Sdougm value = NULL; 20764327Sdougm continue; 20774327Sdougm } 20784327Sdougm } 20794327Sdougm if (value != NULL) { 20804327Sdougm xmlFree(value); 20814327Sdougm value = NULL; 20824327Sdougm } 20834327Sdougm /* potential match */ 20844327Sdougm if (sectype != NULL) { 20854327Sdougm value = xmlGetProp(node, (xmlChar *)"sectype"); 20864327Sdougm if (value != NULL && 20874327Sdougm xmlStrcmp(value, (xmlChar *)sectype) == 0) { 20884327Sdougm break; 20894327Sdougm } 20904327Sdougm } else { 20914327Sdougm break; 20924327Sdougm } 20933034Sdougm } 20943034Sdougm if (value != NULL) { 20954327Sdougm xmlFree(value); 20964327Sdougm value = NULL; 20973034Sdougm } 20983034Sdougm } 20993034Sdougm if (value != NULL) 21004327Sdougm xmlFree(value); 21013034Sdougm return ((sa_security_t)node); 21023034Sdougm } 21033034Sdougm 21043034Sdougm /* 21053034Sdougm * sa_get_next_security(security) 21063034Sdougm * 21073034Sdougm * Get the next security optionset if one exists. 21083034Sdougm */ 21093034Sdougm 21103034Sdougm sa_security_t 21113034Sdougm sa_get_next_security(sa_security_t security) 21123034Sdougm { 21133034Sdougm xmlNodePtr node; 21143034Sdougm 21153034Sdougm for (node = ((xmlNodePtr)security)->next; node != NULL; 21164327Sdougm node = node->next) { 21173034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) { 21183034Sdougm break; 21193034Sdougm } 21203034Sdougm } 21213034Sdougm return ((sa_security_t)node); 21223034Sdougm } 21233034Sdougm 21243034Sdougm /* 21253034Sdougm * sa_get_property(optionset, prop) 21263034Sdougm * 21273034Sdougm * Get the property object with the name specified in prop from the 21283034Sdougm * optionset. 21293034Sdougm */ 21303034Sdougm 21313034Sdougm sa_property_t 21323034Sdougm sa_get_property(sa_optionset_t optionset, char *prop) 21333034Sdougm { 21343034Sdougm xmlNodePtr node = (xmlNodePtr)optionset; 21353034Sdougm xmlChar *value = NULL; 21363034Sdougm 21373034Sdougm if (optionset == NULL) 21384327Sdougm return (NULL); 21393034Sdougm 21403034Sdougm for (node = node->children; node != NULL; 21414327Sdougm node = node->next) { 21424327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 21434327Sdougm if (prop == NULL) 21444327Sdougm break; 21454327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 21464327Sdougm if (value != NULL && 21474327Sdougm xmlStrcmp(value, (xmlChar *)prop) == 0) { 21484327Sdougm break; 21494327Sdougm } 21504327Sdougm if (value != NULL) { 21514327Sdougm xmlFree(value); 21524327Sdougm value = NULL; 21534327Sdougm } 21543034Sdougm } 21553034Sdougm } 21563034Sdougm if (value != NULL) 21573034Sdougm xmlFree(value); 21583034Sdougm if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"option") != 0) { 21594327Sdougm /* 21604327Sdougm * avoid a non option node -- it is possible to be a 21614327Sdougm * text node 21624327Sdougm */ 21634327Sdougm node = NULL; 21643034Sdougm } 21653034Sdougm return ((sa_property_t)node); 21663034Sdougm } 21673034Sdougm 21683034Sdougm /* 21693034Sdougm * sa_get_next_property(property) 21703034Sdougm * 21713034Sdougm * Get the next property following the specified property. NULL if 21723034Sdougm * this was the last. 21733034Sdougm */ 21743034Sdougm 21753034Sdougm sa_property_t 21763034Sdougm sa_get_next_property(sa_property_t property) 21773034Sdougm { 21783034Sdougm xmlNodePtr node; 21793034Sdougm 21803034Sdougm for (node = ((xmlNodePtr)property)->next; node != NULL; 21814327Sdougm node = node->next) { 21823034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 21833034Sdougm break; 21843034Sdougm } 21853034Sdougm } 21863034Sdougm return ((sa_property_t)node); 21873034Sdougm } 21883034Sdougm 21893034Sdougm /* 21903034Sdougm * sa_set_share_description(share, content) 21913034Sdougm * 21923034Sdougm * Set the description of share to content. 21933034Sdougm */ 21943034Sdougm 21953034Sdougm int 21963034Sdougm sa_set_share_description(sa_share_t share, char *content) 21973034Sdougm { 21983034Sdougm xmlNodePtr node; 21993034Sdougm sa_group_t group; 22003034Sdougm int ret = SA_OK; 22013034Sdougm 22023034Sdougm for (node = ((xmlNodePtr)share)->children; node != NULL; 22034327Sdougm node = node->next) { 22043034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 22053034Sdougm break; 22063034Sdougm } 22073034Sdougm } 22083034Sdougm group = sa_get_parent_group(share); 22093034Sdougm /* no existing description but want to add */ 22103034Sdougm if (node == NULL && content != NULL) { 22113034Sdougm /* add a description */ 22124327Sdougm node = _sa_set_share_description(share, content); 22133034Sdougm } else if (node != NULL && content != NULL) { 22143034Sdougm /* update a description */ 22153034Sdougm xmlNodeSetContent(node, (xmlChar *)content); 22163034Sdougm } else if (node != NULL && content == NULL) { 22173034Sdougm /* remove an existing description */ 22183034Sdougm xmlUnlinkNode(node); 22193034Sdougm xmlFreeNode(node); 22203034Sdougm } 22213910Sdougm if (group != NULL && is_persistent((sa_group_t)share)) { 22224327Sdougm sa_handle_impl_t impl_handle; 22234327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 22244327Sdougm if (impl_handle != NULL) { 22254327Sdougm ret = sa_commit_share(impl_handle->scfhandle, group, 22264327Sdougm share); 22274327Sdougm } else { 22284327Sdougm ret = SA_SYSTEM_ERR; 22294327Sdougm } 22303910Sdougm } 22313034Sdougm return (ret); 22323034Sdougm } 22333034Sdougm 22343034Sdougm /* 22353034Sdougm * fixproblemchars(string) 22363034Sdougm * 22373034Sdougm * don't want any newline or tab characters in the text since these 22383034Sdougm * could break display of data and legacy file formats. 22393034Sdougm */ 22403034Sdougm static void 22413034Sdougm fixproblemchars(char *str) 22423034Sdougm { 22433034Sdougm int c; 22443034Sdougm for (c = *str; c != '\0'; c = *++str) { 22454327Sdougm if (c == '\t' || c == '\n') 22464327Sdougm *str = ' '; 22474327Sdougm else if (c == '"') 22484327Sdougm *str = '\''; 22493034Sdougm } 22503034Sdougm } 22513034Sdougm 22523034Sdougm /* 22533034Sdougm * sa_get_share_description(share) 22543034Sdougm * 22553034Sdougm * Return the description text for the specified share if it 22563034Sdougm * exists. NULL if no description exists. 22573034Sdougm */ 22583034Sdougm 22593034Sdougm char * 22603034Sdougm sa_get_share_description(sa_share_t share) 22613034Sdougm { 22623034Sdougm xmlChar *description = NULL; 22633034Sdougm xmlNodePtr node; 22643034Sdougm 22653034Sdougm for (node = ((xmlNodePtr)share)->children; node != NULL; 22664327Sdougm node = node->next) { 22674327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 22684327Sdougm break; 22694327Sdougm } 22703034Sdougm } 22713034Sdougm if (node != NULL) { 22724327Sdougm description = xmlNodeGetContent((xmlNodePtr)share); 22734327Sdougm fixproblemchars((char *)description); 22743034Sdougm } 22753034Sdougm return ((char *)description); 22763034Sdougm } 22773034Sdougm 22783034Sdougm /* 22793034Sdougm * sa_free(share_description(description) 22803034Sdougm * 22813034Sdougm * Free the description string. 22823034Sdougm */ 22833034Sdougm 22843034Sdougm void 22853034Sdougm sa_free_share_description(char *description) 22863034Sdougm { 22873034Sdougm xmlFree((xmlChar *)description); 22883034Sdougm } 22893034Sdougm 22903034Sdougm /* 22913034Sdougm * sa_create_optionset(group, proto) 22923034Sdougm * 22933034Sdougm * Create an optionset for the specified protocol in the specied 22943034Sdougm * group. This is manifested as a property group within SMF. 22953034Sdougm */ 22963034Sdougm 22973034Sdougm sa_optionset_t 22983034Sdougm sa_create_optionset(sa_group_t group, char *proto) 22993034Sdougm { 23003034Sdougm sa_optionset_t optionset; 23013034Sdougm sa_group_t parent = group; 23023034Sdougm 23033034Sdougm optionset = sa_get_optionset(group, proto); 23043034Sdougm if (optionset != NULL) { 23053034Sdougm /* can't have a duplicate protocol */ 23064327Sdougm optionset = NULL; 23073034Sdougm } else { 23084327Sdougm optionset = (sa_optionset_t)xmlNewChild((xmlNodePtr)group, 23094327Sdougm NULL, (xmlChar *)"optionset", NULL); 23103034Sdougm /* 23113034Sdougm * only put to repository if on a group and we were 23123034Sdougm * able to create an optionset. 23133034Sdougm */ 23144327Sdougm if (optionset != NULL) { 23154327Sdougm char oname[SA_STRSIZE]; 23164327Sdougm char *groupname; 23174327Sdougm char *id = NULL; 23184327Sdougm 23194327Sdougm if (sa_is_share(group)) 23204327Sdougm parent = sa_get_parent_group((sa_share_t)group); 23214327Sdougm 23224327Sdougm sa_set_optionset_attr(optionset, "type", proto); 23233034Sdougm 23244327Sdougm if (sa_is_share(group)) { 23254327Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 23264327Sdougm } 23274327Sdougm (void) sa_optionset_name(optionset, oname, 23284327Sdougm sizeof (oname), id); 23294327Sdougm groupname = sa_get_group_attr(parent, "name"); 23304327Sdougm if (groupname != NULL && is_persistent(group)) { 23314327Sdougm sa_handle_impl_t impl_handle; 23324327Sdougm impl_handle = (sa_handle_impl_t) 23334327Sdougm sa_find_group_handle(group); 23344327Sdougm assert(impl_handle != NULL); 23354327Sdougm if (impl_handle != NULL) { 23364327Sdougm (void) sa_get_instance( 23374327Sdougm impl_handle->scfhandle, 23384327Sdougm groupname); 23394327Sdougm (void) sa_create_pgroup( 23404327Sdougm impl_handle->scfhandle, oname); 23414327Sdougm } 23424327Sdougm } 23434327Sdougm if (groupname != NULL) 23444327Sdougm sa_free_attr_string(groupname); 23454327Sdougm if (id != NULL) 23464327Sdougm sa_free_attr_string(id); 23473034Sdougm } 23483034Sdougm } 23493034Sdougm return (optionset); 23503034Sdougm } 23513034Sdougm 23523034Sdougm /* 23533034Sdougm * sa_get_property_parent(property) 23543034Sdougm * 23553034Sdougm * Given a property, return the object it is a property of. This will 23563034Sdougm * be an optionset of some type. 23573034Sdougm */ 23583034Sdougm 23593034Sdougm static sa_optionset_t 23603034Sdougm sa_get_property_parent(sa_property_t property) 23613034Sdougm { 23623034Sdougm xmlNodePtr node = NULL; 23633034Sdougm 23644327Sdougm if (property != NULL) 23654327Sdougm node = ((xmlNodePtr)property)->parent; 23663034Sdougm return ((sa_optionset_t)node); 23673034Sdougm } 23683034Sdougm 23693034Sdougm /* 23703034Sdougm * sa_get_optionset_parent(optionset) 23713034Sdougm * 23723034Sdougm * Return the parent of the specified optionset. This could be a group 23733034Sdougm * or a share. 23743034Sdougm */ 23753034Sdougm 23763034Sdougm static sa_group_t 23773034Sdougm sa_get_optionset_parent(sa_optionset_t optionset) 23783034Sdougm { 23793034Sdougm xmlNodePtr node = NULL; 23803034Sdougm 23814327Sdougm if (optionset != NULL) 23824327Sdougm node = ((xmlNodePtr)optionset)->parent; 23833034Sdougm return ((sa_group_t)node); 23843034Sdougm } 23853034Sdougm 23863034Sdougm /* 23873034Sdougm * zfs_needs_update(share) 23883034Sdougm * 23893034Sdougm * In order to avoid making multiple updates to a ZFS share when 23903034Sdougm * setting properties, the share attribute "changed" will be set to 23913034Sdougm * true when a property is added or modifed. When done adding 23923034Sdougm * properties, we can then detect that an update is needed. We then 23933034Sdougm * clear the state here to detect additional changes. 23943034Sdougm */ 23953034Sdougm 23963034Sdougm static int 23973034Sdougm zfs_needs_update(sa_share_t share) 23983034Sdougm { 23993034Sdougm char *attr; 24003034Sdougm int result = 0; 24013034Sdougm 24023034Sdougm attr = sa_get_share_attr(share, "changed"); 24033034Sdougm if (attr != NULL) { 24044327Sdougm sa_free_attr_string(attr); 24053034Sdougm result = 1; 24063034Sdougm } 24073034Sdougm set_node_attr((void *)share, "changed", NULL); 24083034Sdougm return (result); 24093034Sdougm } 24103034Sdougm 24113034Sdougm /* 24123034Sdougm * zfs_set_update(share) 24133034Sdougm * 24143034Sdougm * Set the changed attribute of the share to true. 24153034Sdougm */ 24163034Sdougm 24173034Sdougm static void 24183034Sdougm zfs_set_update(sa_share_t share) 24193034Sdougm { 24203034Sdougm set_node_attr((void *)share, "changed", "true"); 24213034Sdougm } 24223034Sdougm 24233034Sdougm /* 24243034Sdougm * sa_commit_properties(optionset, clear) 24253034Sdougm * 24263034Sdougm * Check if SMF or ZFS config and either update or abort the pending 24273034Sdougm * changes. 24283034Sdougm */ 24293034Sdougm 24303034Sdougm int 24313034Sdougm sa_commit_properties(sa_optionset_t optionset, int clear) 24323034Sdougm { 24333034Sdougm sa_group_t group; 24343034Sdougm sa_group_t parent; 24353034Sdougm int zfs = 0; 24363034Sdougm int needsupdate = 0; 24373034Sdougm int ret = SA_OK; 24383910Sdougm sa_handle_impl_t impl_handle; 24393034Sdougm 24403034Sdougm group = sa_get_optionset_parent(optionset); 24413034Sdougm if (group != NULL && (sa_is_share(group) || is_zfs_group(group))) { 24424327Sdougm /* only update ZFS if on a share */ 24434327Sdougm parent = sa_get_parent_group(group); 24444327Sdougm zfs++; 24454327Sdougm if (parent != NULL && is_zfs_group(parent)) 24464327Sdougm needsupdate = zfs_needs_update(group); 24474327Sdougm else 24484327Sdougm zfs = 0; 24493034Sdougm } 24503034Sdougm if (zfs) { 24514327Sdougm if (!clear && needsupdate) 24524327Sdougm ret = sa_zfs_update((sa_share_t)group); 24533034Sdougm } else { 24544327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 24554327Sdougm if (impl_handle != NULL) { 24564327Sdougm if (clear) { 24574327Sdougm (void) sa_abort_transaction( 24584327Sdougm impl_handle->scfhandle); 24594327Sdougm } else { 24604327Sdougm ret = sa_end_transaction( 24614327Sdougm impl_handle->scfhandle); 24624327Sdougm } 24634327Sdougm } else { 24644327Sdougm ret = SA_SYSTEM_ERR; 24654327Sdougm } 24663034Sdougm } 24673034Sdougm return (ret); 24683034Sdougm } 24693034Sdougm 24703034Sdougm /* 24713034Sdougm * sa_destroy_optionset(optionset) 24723034Sdougm * 24733034Sdougm * Remove the optionset from its group. Update the repostory to 24743034Sdougm * reflect this change. 24753034Sdougm */ 24763034Sdougm 24773034Sdougm int 24783034Sdougm sa_destroy_optionset(sa_optionset_t optionset) 24793034Sdougm { 24804327Sdougm char name[SA_STRSIZE]; 24813034Sdougm int len; 24823034Sdougm int ret; 24833034Sdougm char *id = NULL; 24843034Sdougm sa_group_t group; 24853034Sdougm int ispersist = 1; 24863034Sdougm 24873034Sdougm /* now delete the prop group */ 24883034Sdougm group = sa_get_optionset_parent(optionset); 24893034Sdougm if (group != NULL && sa_is_share(group)) { 24904327Sdougm ispersist = is_persistent(group); 24914327Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 24923034Sdougm } 24933034Sdougm if (ispersist) { 24944327Sdougm sa_handle_impl_t impl_handle; 24954327Sdougm len = sa_optionset_name(optionset, name, sizeof (name), id); 24964327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 24974327Sdougm if (impl_handle != NULL) { 24984327Sdougm if (len > 0) { 24994327Sdougm ret = sa_delete_pgroup(impl_handle->scfhandle, 25004327Sdougm name); 25014327Sdougm } 25024327Sdougm } else { 25034327Sdougm ret = SA_SYSTEM_ERR; 25043910Sdougm } 25053034Sdougm } 25063034Sdougm xmlUnlinkNode((xmlNodePtr)optionset); 25073034Sdougm xmlFreeNode((xmlNodePtr)optionset); 25083034Sdougm if (id != NULL) 25094327Sdougm sa_free_attr_string(id); 25103034Sdougm return (ret); 25113034Sdougm } 25123034Sdougm 25133034Sdougm /* private to the implementation */ 25143034Sdougm int 25153034Sdougm _sa_remove_optionset(sa_optionset_t optionset) 25163034Sdougm { 25173034Sdougm int ret = SA_OK; 25183034Sdougm 25193034Sdougm xmlUnlinkNode((xmlNodePtr)optionset); 25203034Sdougm xmlFreeNode((xmlNodePtr)optionset); 25213034Sdougm return (ret); 25223034Sdougm } 25233034Sdougm 25243034Sdougm /* 25253034Sdougm * sa_create_security(group, sectype, proto) 25263034Sdougm * 25273034Sdougm * Create a security optionset (one that has a type name and a 25283034Sdougm * proto). Security is left over from a pure NFS implementation. The 25293034Sdougm * naming will change in the future when the API is released. 25303034Sdougm */ 25313034Sdougm sa_security_t 25323034Sdougm sa_create_security(sa_group_t group, char *sectype, char *proto) 25333034Sdougm { 25343034Sdougm sa_security_t security; 25353034Sdougm char *id = NULL; 25363034Sdougm sa_group_t parent; 25373034Sdougm char *groupname = NULL; 25383034Sdougm 25393034Sdougm if (group != NULL && sa_is_share(group)) { 25404327Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 25414327Sdougm parent = sa_get_parent_group(group); 25424327Sdougm if (parent != NULL) 25434327Sdougm groupname = sa_get_group_attr(parent, "name"); 25443034Sdougm } else if (group != NULL) { 25454327Sdougm groupname = sa_get_group_attr(group, "name"); 25463034Sdougm } 25473034Sdougm 25483034Sdougm security = sa_get_security(group, sectype, proto); 25493034Sdougm if (security != NULL) { 25503034Sdougm /* can't have a duplicate security option */ 25513034Sdougm security = NULL; 25523034Sdougm } else { 25533034Sdougm security = (sa_security_t)xmlNewChild((xmlNodePtr)group, 25544327Sdougm NULL, (xmlChar *)"security", NULL); 25553034Sdougm if (security != NULL) { 25564327Sdougm char oname[SA_STRSIZE]; 25573034Sdougm sa_set_security_attr(security, "type", proto); 25583034Sdougm 25593034Sdougm sa_set_security_attr(security, "sectype", sectype); 25603034Sdougm (void) sa_security_name(security, oname, 25614327Sdougm sizeof (oname), id); 25623034Sdougm if (groupname != NULL && is_persistent(group)) { 25634327Sdougm sa_handle_impl_t impl_handle; 25644327Sdougm impl_handle = 25654327Sdougm (sa_handle_impl_t)sa_find_group_handle( 25664327Sdougm group); 25674327Sdougm if (impl_handle != NULL) { 25684327Sdougm (void) sa_get_instance( 25694327Sdougm impl_handle->scfhandle, groupname); 25704327Sdougm (void) sa_create_pgroup( 25714327Sdougm impl_handle->scfhandle, oname); 25724327Sdougm } 25733034Sdougm } 25743034Sdougm } 25753034Sdougm } 25763034Sdougm if (groupname != NULL) 25774327Sdougm sa_free_attr_string(groupname); 25783034Sdougm return (security); 25793034Sdougm } 25803034Sdougm 25813034Sdougm /* 25823034Sdougm * sa_destroy_security(security) 25833034Sdougm * 25843034Sdougm * Remove the specified optionset from the document and the 25853034Sdougm * configuration. 25863034Sdougm */ 25873034Sdougm 25883034Sdougm int 25893034Sdougm sa_destroy_security(sa_security_t security) 25903034Sdougm { 25914327Sdougm char name[SA_STRSIZE]; 25923034Sdougm int len; 25933034Sdougm int ret = SA_OK; 25943034Sdougm char *id = NULL; 25953034Sdougm sa_group_t group; 25963034Sdougm int iszfs = 0; 25973034Sdougm int ispersist = 1; 25983034Sdougm 25993034Sdougm group = sa_get_optionset_parent(security); 26003034Sdougm 26013034Sdougm if (group != NULL) 26024327Sdougm iszfs = sa_group_is_zfs(group); 26033034Sdougm 26043034Sdougm if (group != NULL && !iszfs) { 26054327Sdougm if (sa_is_share(group)) 26064327Sdougm ispersist = is_persistent(group); 26074327Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 26083034Sdougm } 26093034Sdougm if (ispersist) { 26104327Sdougm len = sa_security_name(security, name, sizeof (name), id); 26114327Sdougm if (!iszfs && len > 0) { 26124327Sdougm sa_handle_impl_t impl_handle; 26134327Sdougm impl_handle = 26144327Sdougm (sa_handle_impl_t)sa_find_group_handle(group); 26154327Sdougm if (impl_handle != NULL) { 26164327Sdougm ret = sa_delete_pgroup(impl_handle->scfhandle, 26174327Sdougm name); 26184327Sdougm } else { 26194327Sdougm ret = SA_SYSTEM_ERR; 26204327Sdougm } 26213910Sdougm } 26223034Sdougm } 26233034Sdougm xmlUnlinkNode((xmlNodePtr)security); 26243034Sdougm xmlFreeNode((xmlNodePtr)security); 26254327Sdougm if (iszfs) 26264327Sdougm ret = sa_zfs_update(group); 26273034Sdougm if (id != NULL) 26284327Sdougm sa_free_attr_string(id); 26293034Sdougm return (ret); 26303034Sdougm } 26313034Sdougm 26323034Sdougm /* 26333034Sdougm * sa_get_security_attr(optionset, tag) 26343034Sdougm * 26353034Sdougm * Return the specified attribute value from the optionset. 26363034Sdougm */ 26373034Sdougm 26383034Sdougm char * 26393034Sdougm sa_get_security_attr(sa_property_t optionset, char *tag) 26403034Sdougm { 26413034Sdougm return (get_node_attr((void *)optionset, tag)); 26423034Sdougm 26433034Sdougm } 26443034Sdougm 26453034Sdougm /* 26463034Sdougm * sa_set_security_attr(optionset, tag, value) 26473034Sdougm * 26483034Sdougm * Set the optioset attribute specied by tag to the specified value. 26493034Sdougm */ 26503034Sdougm 26513034Sdougm void 26523034Sdougm sa_set_security_attr(sa_group_t optionset, char *tag, char *value) 26533034Sdougm { 26543034Sdougm set_node_attr((void *)optionset, tag, value); 26553034Sdougm } 26563034Sdougm 26573034Sdougm /* 26583034Sdougm * is_nodetype(node, type) 26593034Sdougm * 26603034Sdougm * Check to see if node is of the type specified. 26613034Sdougm */ 26623034Sdougm 26633034Sdougm static int 26643034Sdougm is_nodetype(void *node, char *type) 26653034Sdougm { 26663034Sdougm return (strcmp((char *)((xmlNodePtr)node)->name, type) == 0); 26673034Sdougm } 26683034Sdougm 26694327Sdougm 26704327Sdougm /* 26714327Sdougm * add_or_update() 26724327Sdougm * 26734327Sdougm * Add or update a property. Pulled out of sa_set_prop_by_prop for 26744327Sdougm * readability. 26754327Sdougm */ 26764327Sdougm static int 26774327Sdougm add_or_update(scfutilhandle_t *scf_handle, int type, scf_value_t *value, 26784327Sdougm scf_transaction_entry_t *entry, char *name, char *valstr) 26794327Sdougm { 26804327Sdougm int ret = SA_SYSTEM_ERR; 26814327Sdougm 26824327Sdougm if (value != NULL) { 26834327Sdougm if (type == SA_PROP_OP_ADD) 26844327Sdougm ret = scf_transaction_property_new(scf_handle->trans, 26854327Sdougm entry, name, SCF_TYPE_ASTRING); 26864327Sdougm else 26874327Sdougm ret = scf_transaction_property_change(scf_handle->trans, 26884327Sdougm entry, name, SCF_TYPE_ASTRING); 26894327Sdougm if (ret == 0) { 26904327Sdougm ret = scf_value_set_astring(value, valstr); 26914327Sdougm if (ret == 0) 26924327Sdougm ret = scf_entry_add_value(entry, value); 26934327Sdougm if (ret == 0) 26944327Sdougm return (ret); 26954327Sdougm scf_value_destroy(value); 26964327Sdougm } else { 26974327Sdougm scf_entry_destroy(entry); 26984327Sdougm } 26994327Sdougm } 27004327Sdougm return (SA_SYSTEM_ERR); 27014327Sdougm } 27024327Sdougm 27033034Sdougm /* 27043034Sdougm * sa_set_prop_by_prop(optionset, group, prop, type) 27053034Sdougm * 27063034Sdougm * Add/remove/update the specified property prop into the optionset or 27073034Sdougm * share. If a share, sort out which property group based on GUID. In 27083034Sdougm * all cases, the appropriate transaction is set (or ZFS share is 27093034Sdougm * marked as needing an update) 27103034Sdougm */ 27113034Sdougm 27123034Sdougm static int 27133034Sdougm sa_set_prop_by_prop(sa_optionset_t optionset, sa_group_t group, 27143034Sdougm sa_property_t prop, int type) 27153034Sdougm { 27163034Sdougm char *name; 27173034Sdougm char *valstr; 27183034Sdougm int ret = SA_OK; 27193034Sdougm scf_transaction_entry_t *entry; 27203034Sdougm scf_value_t *value; 27213034Sdougm int opttype; /* 1 == optionset, 0 == security */ 27223034Sdougm char *id = NULL; 27233034Sdougm int iszfs = 0; 27243034Sdougm int isshare = 0; 27253034Sdougm sa_group_t parent = NULL; 27263910Sdougm sa_handle_impl_t impl_handle; 27273910Sdougm scfutilhandle_t *scf_handle; 27283034Sdougm 27293034Sdougm if (!is_persistent(group)) { 27303034Sdougm /* 27313034Sdougm * if the group/share is not persistent we don't need 27323034Sdougm * to do anything here 27333034Sdougm */ 27344327Sdougm return (SA_OK); 27353034Sdougm } 27363910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 27374327Sdougm if (impl_handle == NULL || impl_handle->scfhandle == NULL) 27384327Sdougm return (SA_SYSTEM_ERR); 27393910Sdougm scf_handle = impl_handle->scfhandle; 27403034Sdougm name = sa_get_property_attr(prop, "type"); 27413034Sdougm valstr = sa_get_property_attr(prop, "value"); 27423034Sdougm entry = scf_entry_create(scf_handle->handle); 27433034Sdougm opttype = is_nodetype((void *)optionset, "optionset"); 27443034Sdougm 27453034Sdougm if (valstr != NULL && entry != NULL) { 27464327Sdougm if (sa_is_share(group)) { 27474327Sdougm isshare = 1; 27484327Sdougm parent = sa_get_parent_group(group); 27494327Sdougm if (parent != NULL) 27504327Sdougm iszfs = is_zfs_group(parent); 27514327Sdougm } else { 27524327Sdougm iszfs = is_zfs_group(group); 27533034Sdougm } 27544327Sdougm if (!iszfs) { 27554327Sdougm if (scf_handle->trans == NULL) { 27564327Sdougm char oname[SA_STRSIZE]; 27574327Sdougm char *groupname = NULL; 27584327Sdougm if (isshare) { 27594327Sdougm if (parent != NULL) { 27604327Sdougm groupname = 27614327Sdougm sa_get_group_attr(parent, 27624327Sdougm "name"); 27634327Sdougm } 27644327Sdougm id = 27654327Sdougm sa_get_share_attr((sa_share_t)group, 27664327Sdougm "id"); 27674327Sdougm } else { 27684327Sdougm groupname = sa_get_group_attr(group, 27694327Sdougm "name"); 27704327Sdougm } 27714327Sdougm if (groupname != NULL) { 27724327Sdougm ret = sa_get_instance(scf_handle, 27734327Sdougm groupname); 27744327Sdougm sa_free_attr_string(groupname); 27754327Sdougm } 27764327Sdougm if (opttype) 27774327Sdougm (void) sa_optionset_name(optionset, 27784327Sdougm oname, sizeof (oname), id); 27794327Sdougm else 27804327Sdougm (void) sa_security_name(optionset, 27814327Sdougm oname, sizeof (oname), id); 27824327Sdougm ret = sa_start_transaction(scf_handle, oname); 27833910Sdougm } 27844327Sdougm if (ret == SA_OK) { 27854327Sdougm switch (type) { 27864327Sdougm case SA_PROP_OP_REMOVE: 27874327Sdougm ret = scf_transaction_property_delete( 27884327Sdougm scf_handle->trans, entry, name); 27894327Sdougm break; 27904327Sdougm case SA_PROP_OP_ADD: 27914327Sdougm case SA_PROP_OP_UPDATE: 27924327Sdougm value = scf_value_create( 27934327Sdougm scf_handle->handle); 27944327Sdougm ret = add_or_update(scf_handle, type, 27954327Sdougm value, entry, name, valstr); 27964327Sdougm break; 27973034Sdougm } 27983034Sdougm } 27994327Sdougm } else { 28004327Sdougm /* 28014327Sdougm * ZFS update. The calling function would have updated 28024327Sdougm * the internal XML structure. Just need to flag it as 28034327Sdougm * changed for ZFS. 28044327Sdougm */ 28054327Sdougm zfs_set_update((sa_share_t)group); 28064327Sdougm } 28073034Sdougm } 28083034Sdougm 28093034Sdougm if (name != NULL) 28104327Sdougm sa_free_attr_string(name); 28113034Sdougm if (valstr != NULL) 28124327Sdougm sa_free_attr_string(valstr); 28133034Sdougm else if (entry != NULL) 28144327Sdougm scf_entry_destroy(entry); 28153034Sdougm 28163034Sdougm if (ret == -1) 28174327Sdougm ret = SA_SYSTEM_ERR; 28183034Sdougm 28193034Sdougm return (ret); 28203034Sdougm } 28213034Sdougm 28223034Sdougm /* 28233034Sdougm * sa_create_property(name, value) 28243034Sdougm * 28253034Sdougm * Create a new property with the specified name and value. 28263034Sdougm */ 28273034Sdougm 28283034Sdougm sa_property_t 28293034Sdougm sa_create_property(char *name, char *value) 28303034Sdougm { 28313034Sdougm xmlNodePtr node; 28323034Sdougm 28333034Sdougm node = xmlNewNode(NULL, (xmlChar *)"option"); 28343034Sdougm if (node != NULL) { 28353034Sdougm xmlSetProp(node, (xmlChar *)"type", (xmlChar *)name); 28363034Sdougm xmlSetProp(node, (xmlChar *)"value", (xmlChar *)value); 28373034Sdougm } 28383034Sdougm return ((sa_property_t)node); 28393034Sdougm } 28403034Sdougm 28413034Sdougm /* 28423034Sdougm * sa_add_property(object, property) 28433034Sdougm * 28443034Sdougm * Add the specified property to the object. Issue the appropriate 28453034Sdougm * transaction or mark a ZFS object as needing an update. 28463034Sdougm */ 28473034Sdougm 28483034Sdougm int 28493034Sdougm sa_add_property(void *object, sa_property_t property) 28503034Sdougm { 28513034Sdougm int ret = SA_OK; 28523034Sdougm sa_group_t parent; 28533034Sdougm sa_group_t group; 28543034Sdougm char *proto; 28553034Sdougm 28563034Sdougm proto = sa_get_optionset_attr(object, "type"); 28573034Sdougm if (property != NULL) { 28584327Sdougm if ((ret = sa_valid_property(object, proto, property)) == 28594327Sdougm SA_OK) { 28604327Sdougm property = (sa_property_t)xmlAddChild( 28614327Sdougm (xmlNodePtr)object, (xmlNodePtr)property); 28624327Sdougm } else { 28634327Sdougm if (proto != NULL) 28644327Sdougm sa_free_attr_string(proto); 28654327Sdougm return (ret); 28664327Sdougm } 28673034Sdougm } 28683034Sdougm 28693034Sdougm if (proto != NULL) 28704327Sdougm sa_free_attr_string(proto); 28713034Sdougm 28723034Sdougm parent = sa_get_parent_group(object); 28733034Sdougm if (!is_persistent(parent)) { 28744327Sdougm return (ret); 28753034Sdougm } 28763034Sdougm 28773034Sdougm if (sa_is_share(parent)) 28784327Sdougm group = sa_get_parent_group(parent); 28793034Sdougm else 28804327Sdougm group = parent; 28813034Sdougm 28824327Sdougm if (property == NULL) { 28834327Sdougm ret = SA_NO_MEMORY; 28844327Sdougm } else { 28854327Sdougm char oname[SA_STRSIZE]; 28863034Sdougm 28874327Sdougm if (!is_zfs_group(group)) { 28884327Sdougm char *id = NULL; 28894327Sdougm sa_handle_impl_t impl_handle; 28904327Sdougm scfutilhandle_t *scf_handle; 28913910Sdougm 28924327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle( 28934327Sdougm group); 28944327Sdougm if (impl_handle == NULL || 28954327Sdougm impl_handle->scfhandle == NULL) 28964327Sdougm ret = SA_SYSTEM_ERR; 28974327Sdougm if (ret == SA_OK) { 28984327Sdougm scf_handle = impl_handle->scfhandle; 28994327Sdougm if (sa_is_share((sa_group_t)parent)) { 29004327Sdougm id = sa_get_share_attr( 29014327Sdougm (sa_share_t)parent, "id"); 29024327Sdougm } 29034327Sdougm if (scf_handle->trans == NULL) { 29044327Sdougm if (is_nodetype(object, "optionset")) { 29054327Sdougm (void) sa_optionset_name( 29064327Sdougm (sa_optionset_t)object, 29074327Sdougm oname, sizeof (oname), id); 29084327Sdougm } else { 29094327Sdougm (void) sa_security_name( 29104327Sdougm (sa_optionset_t)object, 29114327Sdougm oname, sizeof (oname), id); 29124327Sdougm } 29134327Sdougm ret = sa_start_transaction(scf_handle, 29144327Sdougm oname); 29154327Sdougm } 29164327Sdougm if (ret == SA_OK) { 29174327Sdougm char *name; 29184327Sdougm char *value; 29194327Sdougm name = sa_get_property_attr(property, 29204327Sdougm "type"); 29214327Sdougm value = sa_get_property_attr(property, 29224327Sdougm "value"); 29234327Sdougm if (name != NULL && value != NULL) { 29244327Sdougm if (scf_handle->scf_state == 29254327Sdougm SCH_STATE_INIT) { 29264327Sdougm ret = sa_set_property( 29274327Sdougm scf_handle, name, 29284327Sdougm value); 29294327Sdougm } 29304327Sdougm } else { 29314327Sdougm ret = SA_CONFIG_ERR; 29324327Sdougm } 29334327Sdougm if (name != NULL) 29344327Sdougm sa_free_attr_string( 29354327Sdougm name); 29364327Sdougm if (value != NULL) 29374327Sdougm sa_free_attr_string(value); 29384327Sdougm } 29394327Sdougm if (id != NULL) 29404327Sdougm sa_free_attr_string(id); 29414327Sdougm } 29424327Sdougm } else { 29434327Sdougm /* 29444327Sdougm * ZFS is a special case. We do want 29454327Sdougm * to allow editing property/security 29464327Sdougm * lists since we can have a better 29474327Sdougm * syntax and we also want to keep 29484327Sdougm * things consistent when possible. 29494327Sdougm * 29504327Sdougm * Right now, we defer until the 29514327Sdougm * sa_commit_properties so we can get 29524327Sdougm * them all at once. We do need to 29534327Sdougm * mark the share as "changed" 29544327Sdougm */ 29554327Sdougm zfs_set_update((sa_share_t)parent); 29563034Sdougm } 29573034Sdougm } 29583034Sdougm return (ret); 29593034Sdougm } 29603034Sdougm 29613034Sdougm /* 29623034Sdougm * sa_remove_property(property) 29633034Sdougm * 29643034Sdougm * Remove the specied property from its containing object. Update the 29653034Sdougm * repository as appropriate. 29663034Sdougm */ 29673034Sdougm 29683034Sdougm int 29693034Sdougm sa_remove_property(sa_property_t property) 29703034Sdougm { 29713034Sdougm int ret = SA_OK; 29723034Sdougm 29733034Sdougm if (property != NULL) { 29743034Sdougm sa_optionset_t optionset; 29753034Sdougm sa_group_t group; 29763034Sdougm optionset = sa_get_property_parent(property); 29773034Sdougm if (optionset != NULL) { 29784327Sdougm group = sa_get_optionset_parent(optionset); 29794327Sdougm if (group != NULL) { 29804327Sdougm ret = sa_set_prop_by_prop(optionset, group, 29814327Sdougm property, SA_PROP_OP_REMOVE); 29824327Sdougm } 29833034Sdougm } 29843034Sdougm xmlUnlinkNode((xmlNodePtr)property); 29853034Sdougm xmlFreeNode((xmlNodePtr)property); 29863034Sdougm } else { 29874327Sdougm ret = SA_NO_SUCH_PROP; 29883034Sdougm } 29893034Sdougm return (ret); 29903034Sdougm } 29913034Sdougm 29923034Sdougm /* 29933034Sdougm * sa_update_property(property, value) 29943034Sdougm * 29953034Sdougm * Update the specified property to the new value. If value is NULL, 29963034Sdougm * we currently treat this as a remove. 29973034Sdougm */ 29983034Sdougm 29993034Sdougm int 30003034Sdougm sa_update_property(sa_property_t property, char *value) 30013034Sdougm { 30023034Sdougm int ret = SA_OK; 30033034Sdougm if (value == NULL) { 30043034Sdougm return (sa_remove_property(property)); 30053034Sdougm } else { 30063034Sdougm sa_optionset_t optionset; 30073034Sdougm sa_group_t group; 30083034Sdougm set_node_attr((void *)property, "value", value); 30093034Sdougm optionset = sa_get_property_parent(property); 30103034Sdougm if (optionset != NULL) { 30114327Sdougm group = sa_get_optionset_parent(optionset); 30124327Sdougm if (group != NULL) { 30134327Sdougm ret = sa_set_prop_by_prop(optionset, group, 30144327Sdougm property, SA_PROP_OP_UPDATE); 30154327Sdougm } 30163034Sdougm } else { 30174327Sdougm ret = SA_NO_SUCH_PROP; 30183034Sdougm } 30193034Sdougm } 30203034Sdougm return (ret); 30213034Sdougm } 30223034Sdougm 30233034Sdougm /* 30243034Sdougm * sa_get_protocol_property(propset, prop) 30253034Sdougm * 30263034Sdougm * Get the specified protocol specific property. These are global to 30273034Sdougm * the protocol and not specific to a group or share. 30283034Sdougm */ 30293034Sdougm 30303034Sdougm sa_property_t 30313034Sdougm sa_get_protocol_property(sa_protocol_properties_t propset, char *prop) 30323034Sdougm { 30333034Sdougm xmlNodePtr node = (xmlNodePtr)propset; 30343034Sdougm xmlChar *value = NULL; 30353034Sdougm 30363034Sdougm for (node = node->children; node != NULL; 30374327Sdougm node = node->next) { 30384327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 30394327Sdougm if (prop == NULL) 30404327Sdougm break; 30414327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 30424327Sdougm if (value != NULL && 30434327Sdougm xmlStrcasecmp(value, (xmlChar *)prop) == 0) { 30444327Sdougm break; 30454327Sdougm } 30464327Sdougm if (value != NULL) { 30474327Sdougm xmlFree(value); 30484327Sdougm value = NULL; 30494327Sdougm } 30503034Sdougm } 30513034Sdougm } 30523034Sdougm if (value != NULL) 30533034Sdougm xmlFree(value); 30543034Sdougm if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"option") != 0) { 30554327Sdougm /* 30564327Sdougm * avoid a non option node -- it is possible to be a 30574327Sdougm * text node 30584327Sdougm */ 30594327Sdougm node = NULL; 30603034Sdougm } 30613034Sdougm return ((sa_property_t)node); 30623034Sdougm } 30633034Sdougm 30643034Sdougm /* 30653034Sdougm * sa_get_next_protocol_property(prop) 30663034Sdougm * 30673034Sdougm * Get the next protocol specific property in the list. 30683034Sdougm */ 30693034Sdougm 30703034Sdougm sa_property_t 30713034Sdougm sa_get_next_protocol_property(sa_property_t prop) 30723034Sdougm { 30733034Sdougm xmlNodePtr node; 30743034Sdougm 30753034Sdougm for (node = ((xmlNodePtr)prop)->next; node != NULL; 30764327Sdougm node = node->next) { 30773034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 30783034Sdougm break; 30793034Sdougm } 30803034Sdougm } 30813034Sdougm return ((sa_property_t)node); 30823034Sdougm } 30833034Sdougm 30843034Sdougm /* 30853034Sdougm * sa_set_protocol_property(prop, value) 30863034Sdougm * 30873034Sdougm * Set the specified property to have the new value. The protocol 30883034Sdougm * specific plugin will then be called to update the property. 30893034Sdougm */ 30903034Sdougm 30913034Sdougm int 30923034Sdougm sa_set_protocol_property(sa_property_t prop, char *value) 30933034Sdougm { 30943034Sdougm sa_protocol_properties_t propset; 30953034Sdougm char *proto; 30963034Sdougm int ret = SA_INVALID_PROTOCOL; 30973034Sdougm 30983034Sdougm propset = ((xmlNodePtr)prop)->parent; 30993034Sdougm if (propset != NULL) { 31004327Sdougm proto = sa_get_optionset_attr(propset, "type"); 31014327Sdougm if (proto != NULL) { 31024327Sdougm set_node_attr((xmlNodePtr)prop, "value", value); 31034327Sdougm ret = sa_proto_set_property(proto, prop); 31044327Sdougm sa_free_attr_string(proto); 31054327Sdougm } 31063034Sdougm } 31073034Sdougm return (ret); 31083034Sdougm } 31093034Sdougm 31103034Sdougm /* 31113034Sdougm * sa_add_protocol_property(propset, prop) 31123034Sdougm * 31133034Sdougm * Add a new property to the protocol sepcific property set. 31143034Sdougm */ 31153034Sdougm 31163034Sdougm int 31173034Sdougm sa_add_protocol_property(sa_protocol_properties_t propset, sa_property_t prop) 31183034Sdougm { 31193034Sdougm xmlNodePtr node; 31203034Sdougm 31213034Sdougm /* should check for legitimacy */ 31223034Sdougm node = xmlAddChild((xmlNodePtr)propset, (xmlNodePtr)prop); 31233034Sdougm if (node != NULL) 31244327Sdougm return (SA_OK); 31253034Sdougm return (SA_NO_MEMORY); 31263034Sdougm } 31273034Sdougm 31283034Sdougm /* 31293034Sdougm * sa_create_protocol_properties(proto) 31303034Sdougm * 31313034Sdougm * Create a protocol specifity property set. 31323034Sdougm */ 31333034Sdougm 31343034Sdougm sa_protocol_properties_t 31353034Sdougm sa_create_protocol_properties(char *proto) 31363034Sdougm { 31373034Sdougm xmlNodePtr node; 31384327Sdougm 31393034Sdougm node = xmlNewNode(NULL, (xmlChar *)"propertyset"); 31404327Sdougm if (node != NULL) 31414327Sdougm xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto); 31423034Sdougm return (node); 31433034Sdougm } 3144