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 8324327Sdougm if (updatelegacy == B_TRUE) { 8334327Sdougm sablocksigs(&old); 8344327Sdougm getlegacyconfig((sa_handle_t)handle, 8354327Sdougm SA_LEGACY_DFSTAB, &handle->tree); 8364327Sdougm if (stat(SA_LEGACY_DFSTAB, &st) >= 0) 8374327Sdougm set_legacy_timestamp(handle->tree, 8384327Sdougm SA_LEGACY_DFSTAB, 8394327Sdougm TSTAMP(st.st_ctim)); 8404327Sdougm saunblocksigs(&old); 8414327Sdougm /* Safe to unlock now to allow others to run */ 8424327Sdougm (void) lockf(lockfd, F_ULOCK, 0); 8434327Sdougm (void) close(lockfd); 8444327Sdougm } 8454327Sdougm legacy |= sa_get_zfs_shares(handle, "zfs"); 8464327Sdougm legacy |= gettransients(handle, &handle->tree); 8473034Sdougm } 8484327Sdougm } 8493034Sdougm } 8503910Sdougm return ((sa_handle_t)handle); 8513034Sdougm } 8523034Sdougm 8533034Sdougm /* 8543910Sdougm * sa_fini(handle) 8553034Sdougm * Uninitialize the API structures including the configuration 8563218Sdougm * data structures and ZFS related data. 8573034Sdougm */ 8583034Sdougm 8593034Sdougm void 8603910Sdougm sa_fini(sa_handle_t handle) 8613034Sdougm { 8623910Sdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle; 8633910Sdougm 8643910Sdougm if (impl_handle != NULL) { 8653910Sdougm /* 8663910Sdougm * Free the config trees and any other data structures 8673910Sdougm * used in the handle. 8683910Sdougm */ 8693910Sdougm if (impl_handle->doc != NULL) 8703910Sdougm xmlFreeDoc(impl_handle->doc); 8713910Sdougm sa_scf_fini(impl_handle->scfhandle); 8723910Sdougm sa_zfs_fini(impl_handle); 8733910Sdougm 8743910Sdougm /* Remove and free the entry in the global list. */ 8753910Sdougm remove_handle_for_root(impl_handle->tree); 8763910Sdougm 8773910Sdougm /* Make sure we free the handle */ 8783910Sdougm free(impl_handle); 8793910Sdougm 8803910Sdougm /* 8813910Sdougm * If this was the last handle to release, unload the 8823910Sdougm * plugins that were loaded. 8833910Sdougm */ 8843910Sdougm if (sa_global_handles == NULL) 8854327Sdougm (void) proto_plugin_fini(); 8863910Sdougm 8873034Sdougm } 8883034Sdougm } 8893034Sdougm 8903034Sdougm /* 8913034Sdougm * sa_get_protocols(char **protocol) 8923034Sdougm * Get array of protocols that are supported 8933034Sdougm * Returns pointer to an allocated and NULL terminated 8943034Sdougm * array of strings. Caller must free. 8953034Sdougm * This really should be determined dynamically. 8963034Sdougm * If there aren't any defined, return -1. 8973034Sdougm * Use free() to return memory. 8983034Sdougm */ 8993034Sdougm 9003034Sdougm int 9013034Sdougm sa_get_protocols(char ***protocols) 9023034Sdougm { 9033034Sdougm int numproto = -1; 9043034Sdougm 9053034Sdougm if (protocols != NULL) { 9064327Sdougm struct sa_proto_plugin *plug; 9074327Sdougm for (numproto = 0, plug = sap_proto_list; plug != NULL; 9084327Sdougm plug = plug->plugin_next) { 9094327Sdougm numproto++; 9104327Sdougm } 9113034Sdougm 9124327Sdougm *protocols = calloc(numproto + 1, sizeof (char *)); 9134327Sdougm if (*protocols != NULL) { 9144327Sdougm int ret = 0; 9154327Sdougm for (plug = sap_proto_list; plug != NULL; 9164327Sdougm plug = plug->plugin_next) { 9174327Sdougm /* faking for now */ 9184327Sdougm (*protocols)[ret++] = 9194327Sdougm plug->plugin_ops->sa_protocol; 9204327Sdougm } 9214327Sdougm } else { 9224327Sdougm numproto = -1; 9233034Sdougm } 9243034Sdougm } 9253034Sdougm return (numproto); 9263034Sdougm } 9273034Sdougm 9283034Sdougm /* 9293034Sdougm * find_group_by_name(node, group) 9303034Sdougm * 9313034Sdougm * search the XML document subtree specified by node to find the group 9323034Sdougm * specified by group. Searching subtree allows subgroups to be 9333034Sdougm * searched for. 9343034Sdougm */ 9353034Sdougm 9363034Sdougm static xmlNodePtr 9373034Sdougm find_group_by_name(xmlNodePtr node, xmlChar *group) 9383034Sdougm { 9393034Sdougm xmlChar *name = NULL; 9403034Sdougm 9413034Sdougm for (node = node->xmlChildrenNode; node != NULL; 9423034Sdougm node = node->next) { 9434327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"group") == 0) { 9444327Sdougm /* if no groupname, return the first found */ 9454327Sdougm if (group == NULL) 9464327Sdougm break; 9474327Sdougm name = xmlGetProp(node, (xmlChar *)"name"); 9484327Sdougm if (name != NULL && xmlStrcmp(name, group) == 0) 9494327Sdougm break; 9504327Sdougm if (name != NULL) { 9514327Sdougm xmlFree(name); 9524327Sdougm name = NULL; 9534327Sdougm } 9543034Sdougm } 9553034Sdougm } 9563034Sdougm if (name != NULL) 9574327Sdougm xmlFree(name); 9583034Sdougm return (node); 9593034Sdougm } 9603034Sdougm 9613034Sdougm /* 9623034Sdougm * sa_get_group(groupname) 9633034Sdougm * Return the "group" specified. If groupname is NULL, 9643034Sdougm * return the first group of the list of groups. 9653034Sdougm */ 9663034Sdougm sa_group_t 9673910Sdougm sa_get_group(sa_handle_t handle, char *groupname) 9683034Sdougm { 9693034Sdougm xmlNodePtr node = NULL; 9703034Sdougm char *subgroup = NULL; 9713034Sdougm char *group = NULL; 9723910Sdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle; 9733034Sdougm 9743910Sdougm if (impl_handle != NULL && impl_handle->tree != NULL) { 9754327Sdougm if (groupname != NULL) { 9764327Sdougm group = strdup(groupname); 977*4345Sdougm if (group != NULL) { 978*4345Sdougm subgroup = strchr(group, '/'); 979*4345Sdougm if (subgroup != NULL) 980*4345Sdougm *subgroup++ = '\0'; 981*4345Sdougm } 9824327Sdougm } 983*4345Sdougm /* 984*4345Sdougm * We want to find the, possibly, named group. If 985*4345Sdougm * group is not NULL, then lookup the name. If it is 986*4345Sdougm * NULL, we only do the find if groupname is also 987*4345Sdougm * NULL. This allows lookup of the "first" group in 988*4345Sdougm * the internal list. 989*4345Sdougm */ 990*4345Sdougm if (group != NULL || groupname == NULL) 991*4345Sdougm node = find_group_by_name(impl_handle->tree, 992*4345Sdougm (xmlChar *)group); 993*4345Sdougm 9944327Sdougm /* if a subgroup, find it before returning */ 9954327Sdougm if (subgroup != NULL && node != NULL) 9964327Sdougm node = find_group_by_name(node, (xmlChar *)subgroup); 9973034Sdougm } 9983034Sdougm if (node != NULL && (char *)group != NULL) 9994327Sdougm (void) sa_get_instance(impl_handle->scfhandle, (char *)group); 10003034Sdougm if (group != NULL) 10014327Sdougm free(group); 10023034Sdougm return ((sa_group_t)(node)); 10033034Sdougm } 10043034Sdougm 10053034Sdougm /* 10063034Sdougm * sa_get_next_group(group) 10073034Sdougm * Return the "next" group after the specified group from 10083034Sdougm * the internal group list. NULL if there are no more. 10093034Sdougm */ 10103034Sdougm sa_group_t 10113034Sdougm sa_get_next_group(sa_group_t group) 10123034Sdougm { 10133034Sdougm xmlNodePtr ngroup = NULL; 10143034Sdougm if (group != NULL) { 10154327Sdougm for (ngroup = ((xmlNodePtr)group)->next; ngroup != NULL; 10163034Sdougm ngroup = ngroup->next) { 10174327Sdougm if (xmlStrcmp(ngroup->name, (xmlChar *)"group") == 0) 10184327Sdougm break; 10194327Sdougm } 10203034Sdougm } 10213034Sdougm return ((sa_group_t)ngroup); 10223034Sdougm } 10233034Sdougm 10243034Sdougm /* 10253034Sdougm * sa_get_share(group, sharepath) 10263034Sdougm * Return the share object for the share specified. The share 10273034Sdougm * must be in the specified group. Return NULL if not found. 10283034Sdougm */ 10293034Sdougm sa_share_t 10303034Sdougm sa_get_share(sa_group_t group, char *sharepath) 10313034Sdougm { 10323034Sdougm xmlNodePtr node = NULL; 10333034Sdougm xmlChar *path; 10343034Sdougm 10353034Sdougm /* 10363034Sdougm * For future scalability, this should end up building a cache 10373034Sdougm * since it will get called regularly by the mountd and info 10383034Sdougm * services. 10393034Sdougm */ 10403034Sdougm if (group != NULL) { 10414327Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 10423034Sdougm node = node->next) { 10434327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) { 10444327Sdougm if (sharepath == NULL) { 10454327Sdougm break; 10464327Sdougm } else { 10474327Sdougm /* is it the correct share? */ 10484327Sdougm path = xmlGetProp(node, 10494327Sdougm (xmlChar *)"path"); 10504327Sdougm if (path != NULL && 10514327Sdougm xmlStrcmp(path, 10524327Sdougm (xmlChar *)sharepath) == 0) { 10534327Sdougm xmlFree(path); 10544327Sdougm break; 10554327Sdougm } 10564327Sdougm xmlFree(path); 10574327Sdougm } 10583034Sdougm } 10593034Sdougm } 10603034Sdougm } 10613034Sdougm return ((sa_share_t)node); 10623034Sdougm } 10633034Sdougm 10643034Sdougm /* 10653034Sdougm * sa_get_next_share(share) 10663034Sdougm * Return the next share following the specified share 10673034Sdougm * from the internal list of shares. Returns NULL if there 10683034Sdougm * are no more shares. The list is relative to the same 10693034Sdougm * group. 10703034Sdougm */ 10713034Sdougm sa_share_t 10723034Sdougm sa_get_next_share(sa_share_t share) 10733034Sdougm { 10743034Sdougm xmlNodePtr node = NULL; 10753034Sdougm 10763034Sdougm if (share != NULL) { 10774327Sdougm for (node = ((xmlNodePtr)share)->next; node != NULL; 10783034Sdougm node = node->next) { 10794327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) { 10804327Sdougm break; 10814327Sdougm } 10823034Sdougm } 10833034Sdougm } 10843034Sdougm return ((sa_share_t)node); 10853034Sdougm } 10863034Sdougm 10873034Sdougm /* 10883034Sdougm * _sa_get_child_node(node, type) 10893034Sdougm * 10903034Sdougm * find the child node of the specified node that has "type". This is 10913034Sdougm * used to implement several internal functions. 10923034Sdougm */ 10933034Sdougm 10943034Sdougm static xmlNodePtr 10953034Sdougm _sa_get_child_node(xmlNodePtr node, xmlChar *type) 10963034Sdougm { 10973034Sdougm xmlNodePtr child; 10983034Sdougm for (child = node->xmlChildrenNode; child != NULL; 10993034Sdougm child = child->next) 11004327Sdougm if (xmlStrcmp(child->name, type) == 0) 11014327Sdougm return (child); 11023034Sdougm return ((xmlNodePtr)NULL); 11033034Sdougm } 11043034Sdougm 11053034Sdougm /* 11063034Sdougm * find_share(group, path) 11073034Sdougm * 11083034Sdougm * Search all the shares in the specified group for one that has the 11093034Sdougm * specified path. 11103034Sdougm */ 11113034Sdougm 11123034Sdougm static sa_share_t 11133034Sdougm find_share(sa_group_t group, char *sharepath) 11143034Sdougm { 11153034Sdougm sa_share_t share; 11163034Sdougm char *path; 11173034Sdougm 11183034Sdougm for (share = sa_get_share(group, NULL); share != NULL; 11193034Sdougm share = sa_get_next_share(share)) { 11204327Sdougm path = sa_get_share_attr(share, "path"); 11214327Sdougm if (path != NULL && strcmp(path, sharepath) == 0) { 11224327Sdougm sa_free_attr_string(path); 11234327Sdougm break; 11244327Sdougm } 11254327Sdougm if (path != NULL) 11264327Sdougm sa_free_attr_string(path); 11273034Sdougm } 11283034Sdougm return (share); 11293034Sdougm } 11303034Sdougm 11313034Sdougm /* 11323034Sdougm * sa_get_sub_group(group) 11333034Sdougm * 11343034Sdougm * Get the first sub-group of group. The sa_get_next_group() function 11353034Sdougm * can be used to get the rest. This is currently only used for ZFS 11363034Sdougm * sub-groups but could be used to implement a more general mechanism. 11373034Sdougm */ 11383034Sdougm 11393034Sdougm sa_group_t 11403034Sdougm sa_get_sub_group(sa_group_t group) 11413034Sdougm { 11423034Sdougm return ((sa_group_t)_sa_get_child_node((xmlNodePtr)group, 11434327Sdougm (xmlChar *)"group")); 11443034Sdougm } 11453034Sdougm 11463034Sdougm /* 11473034Sdougm * sa_find_share(sharepath) 11483034Sdougm * Finds a share regardless of group. In the future, this 11493034Sdougm * function should utilize a cache and hash table of some kind. 11503034Sdougm * The current assumption is that a path will only be shared 11513034Sdougm * once. In the future, this may change as implementation of 11523034Sdougm * resource names comes into being. 11533034Sdougm */ 11543034Sdougm sa_share_t 11553910Sdougm sa_find_share(sa_handle_t handle, char *sharepath) 11563034Sdougm { 11573034Sdougm sa_group_t group; 11583034Sdougm sa_group_t zgroup; 11593034Sdougm sa_share_t share = NULL; 11603034Sdougm int done = 0; 11613034Sdougm 11623910Sdougm for (group = sa_get_group(handle, NULL); group != NULL && !done; 11634327Sdougm group = sa_get_next_group(group)) { 11644327Sdougm if (is_zfs_group(group)) { 11654327Sdougm for (zgroup = 11664327Sdougm (sa_group_t)_sa_get_child_node((xmlNodePtr)group, 11674327Sdougm (xmlChar *)"group"); 11684327Sdougm zgroup != NULL; 11694327Sdougm zgroup = sa_get_next_group(zgroup)) { 11704327Sdougm share = find_share(zgroup, sharepath); 11714327Sdougm if (share != NULL) 11724327Sdougm break; 11734327Sdougm } 11744327Sdougm } else { 11754327Sdougm share = find_share(group, sharepath); 11764327Sdougm } 11774327Sdougm if (share != NULL) 11783034Sdougm break; 11793034Sdougm } 11803034Sdougm return (share); 11813034Sdougm } 11823034Sdougm 11833034Sdougm /* 11843348Sdougm * sa_check_path(group, path, strictness) 11853034Sdougm * 11863034Sdougm * check that path is a valid path relative to the group. Currently, 11873034Sdougm * we are ignoring the group and checking only the NFS rules. Later, 11883034Sdougm * we may want to use the group to then check against the protocols 11893348Sdougm * enabled on the group. The strictness values mean: 11903348Sdougm * SA_CHECK_NORMAL == only check newpath against shares that are active 11913348Sdougm * SA_CHECK_STRICT == check newpath against both active shares and those 11923348Sdougm * stored in the repository 11933034Sdougm */ 11943034Sdougm 11953034Sdougm int 11963348Sdougm sa_check_path(sa_group_t group, char *path, int strictness) 11973034Sdougm { 11983910Sdougm sa_handle_t handle; 11993910Sdougm 12003910Sdougm handle = sa_find_group_handle(group); 12013910Sdougm return (validpath(handle, path, strictness)); 12023034Sdougm } 12033034Sdougm 12043034Sdougm /* 12053034Sdougm * _sa_add_share(group, sharepath, persist, *error) 12063034Sdougm * 12073034Sdougm * common code for all types of add_share. sa_add_share() is the 12083034Sdougm * public API, we also need to be able to do this when parsing legacy 12093034Sdougm * files and construction of the internal configuration while 12103034Sdougm * extracting config info from SMF. 12113034Sdougm */ 12123034Sdougm 12133034Sdougm sa_share_t 12143034Sdougm _sa_add_share(sa_group_t group, char *sharepath, int persist, int *error) 12153034Sdougm { 12163034Sdougm xmlNodePtr node = NULL; 12173034Sdougm int err; 12183034Sdougm 12193034Sdougm err = SA_OK; /* assume success */ 12203034Sdougm 12214327Sdougm node = xmlNewChild((xmlNodePtr)group, NULL, (xmlChar *)"share", NULL); 12223034Sdougm if (node != NULL) { 12234327Sdougm xmlSetProp(node, (xmlChar *)"path", (xmlChar *)sharepath); 12244327Sdougm xmlSetProp(node, (xmlChar *)"type", 12254327Sdougm persist ? (xmlChar *)"persist" : (xmlChar *)"transient"); 12264327Sdougm if (persist != SA_SHARE_TRANSIENT) { 12274327Sdougm /* 12284327Sdougm * persistent shares come in two flavors: SMF and 12294327Sdougm * ZFS. Sort this one out based on target group and 12304327Sdougm * path type. Currently, only NFS is supported in the 12314327Sdougm * ZFS group and it is always on. 12324327Sdougm */ 12334327Sdougm if (sa_group_is_zfs(group) && 12344327Sdougm sa_path_is_zfs(sharepath)) { 12354327Sdougm err = sa_zfs_set_sharenfs(group, sharepath, 1); 12364327Sdougm } else { 12374327Sdougm sa_handle_impl_t impl_handle; 12384327Sdougm impl_handle = 12394327Sdougm (sa_handle_impl_t)sa_find_group_handle( 12404327Sdougm group); 12414327Sdougm if (impl_handle != NULL) { 12424327Sdougm err = sa_commit_share( 12434327Sdougm impl_handle->scfhandle, group, 12444327Sdougm (sa_share_t)node); 12454327Sdougm } else { 12464327Sdougm err = SA_SYSTEM_ERR; 12474327Sdougm } 12484327Sdougm } 12493034Sdougm } 12504327Sdougm if (err == SA_NO_PERMISSION && persist & SA_SHARE_PARSER) { 12514327Sdougm /* called by the dfstab parser so could be a show */ 12524327Sdougm err = SA_OK; 12534327Sdougm } 12544327Sdougm if (err != SA_OK) { 12554327Sdougm /* 12564327Sdougm * we couldn't commit to the repository so undo 12574327Sdougm * our internal state to reflect reality. 12584327Sdougm */ 12594327Sdougm xmlUnlinkNode(node); 12604327Sdougm xmlFreeNode(node); 12614327Sdougm node = NULL; 12624327Sdougm } 12633034Sdougm } else { 12644327Sdougm err = SA_NO_MEMORY; 12653034Sdougm } 12663034Sdougm if (error != NULL) 12674327Sdougm *error = err; 12683034Sdougm return (node); 12693034Sdougm } 12703034Sdougm 12713034Sdougm /* 12723034Sdougm * sa_add_share(group, sharepath, persist, *error) 12733034Sdougm * 12743034Sdougm * Add a new share object to the specified group. The share will 12753034Sdougm * have the specified sharepath and will only be constructed if 12763034Sdougm * it is a valid path to be shared. NULL is returned on error 12773034Sdougm * and a detailed error value will be returned via the error 12783034Sdougm * pointer. 12793034Sdougm */ 12803034Sdougm sa_share_t 12813034Sdougm sa_add_share(sa_group_t group, char *sharepath, int persist, int *error) 12823034Sdougm { 12833034Sdougm xmlNodePtr node = NULL; 12843034Sdougm sa_share_t dup; 12853348Sdougm int strictness = SA_CHECK_NORMAL; 12863910Sdougm sa_handle_t handle; 12873348Sdougm 12883348Sdougm /* 12893348Sdougm * If the share is to be permanent, use strict checking so a 12903348Sdougm * bad config doesn't get created. Transient shares only need 12913348Sdougm * to check against the currently active 12923348Sdougm * shares. SA_SHARE_PARSER is a modifier used internally to 12933348Sdougm * indicate that we are being called by the dfstab parser and 12943348Sdougm * that we need strict checking in all cases. Normally persist 12953348Sdougm * is in integer value but SA_SHARE_PARSER may be or'd into 12963348Sdougm * it as an override. 12973348Sdougm */ 12983348Sdougm if (persist & SA_SHARE_PARSER || persist == SA_SHARE_PERMANENT) 12994327Sdougm strictness = SA_CHECK_STRICT; 13003034Sdougm 13013910Sdougm handle = sa_find_group_handle(group); 13023910Sdougm 13033910Sdougm if ((dup = sa_find_share(handle, sharepath)) == NULL && 13044327Sdougm (*error = sa_check_path(group, sharepath, strictness)) == SA_OK) { 13054327Sdougm node = _sa_add_share(group, sharepath, persist, error); 13063034Sdougm } 13073034Sdougm if (dup != NULL) 13084327Sdougm *error = SA_DUPLICATE_NAME; 13093034Sdougm 13103034Sdougm return ((sa_share_t)node); 13113034Sdougm } 13123034Sdougm 13133034Sdougm /* 13143034Sdougm * sa_enable_share(share, protocol) 13153034Sdougm * Enable the specified share to the specified protocol. 13163034Sdougm * If protocol is NULL, then all protocols. 13173034Sdougm */ 13183034Sdougm int 13193034Sdougm sa_enable_share(sa_share_t share, char *protocol) 13203034Sdougm { 13213034Sdougm char *sharepath; 13223034Sdougm struct stat st; 13233034Sdougm int err = 0; 13243034Sdougm 13253034Sdougm sharepath = sa_get_share_attr(share, "path"); 13263034Sdougm if (stat(sharepath, &st) < 0) { 13274327Sdougm err = SA_NO_SUCH_PATH; 13283034Sdougm } else { 13294327Sdougm /* tell the server about the share */ 13304327Sdougm if (protocol != NULL) { 13314327Sdougm /* lookup protocol specific handler */ 13324327Sdougm err = sa_proto_share(protocol, share); 13334327Sdougm if (err == SA_OK) 13344327Sdougm (void) sa_set_share_attr(share, "shared", 13354327Sdougm "true"); 13364327Sdougm } else { 13374327Sdougm /* 13384327Sdougm * Tell all protocols. Only NFS for now but 13394327Sdougm * SMB is coming. 13404327Sdougm */ 13414327Sdougm err = sa_proto_share("nfs", share); 13424327Sdougm (void) sa_set_share_attr(share, "shared", "true"); 13434327Sdougm } 13443034Sdougm } 13453034Sdougm if (sharepath != NULL) 13464327Sdougm sa_free_attr_string(sharepath); 13473034Sdougm return (err); 13483034Sdougm } 13493034Sdougm 13503034Sdougm /* 13513034Sdougm * sa_disable_share(share, protocol) 13523034Sdougm * Disable the specified share to the specified protocol. 13533034Sdougm * If protocol is NULL, then all protocols. 13543034Sdougm */ 13553034Sdougm int 13563034Sdougm sa_disable_share(sa_share_t share, char *protocol) 13573034Sdougm { 13583034Sdougm char *path; 13593034Sdougm char *shared; 13603034Sdougm int ret = SA_OK; 13613034Sdougm 13623034Sdougm path = sa_get_share_attr(share, "path"); 13633034Sdougm shared = sa_get_share_attr(share, "shared"); 13643034Sdougm 13653034Sdougm if (protocol != NULL) { 13664327Sdougm ret = sa_proto_unshare(protocol, path); 13673034Sdougm } else { 13684327Sdougm /* need to do all protocols */ 13694327Sdougm ret = sa_proto_unshare("nfs", path); 13703034Sdougm } 13713034Sdougm if (ret == SA_OK) 13723034Sdougm (void) sa_set_share_attr(share, "shared", NULL); 13733034Sdougm if (path != NULL) 13744327Sdougm sa_free_attr_string(path); 13753034Sdougm if (shared != NULL) 13764327Sdougm sa_free_attr_string(shared); 13773034Sdougm return (ret); 13783034Sdougm } 13793034Sdougm 13803034Sdougm /* 13813034Sdougm * sa_remove_share(share) 13823034Sdougm * 13833034Sdougm * remove the specified share from its containing group. 13843034Sdougm * Remove from the SMF or ZFS configuration space. 13853034Sdougm */ 13863034Sdougm 13873034Sdougm int 13883034Sdougm sa_remove_share(sa_share_t share) 13893034Sdougm { 13903034Sdougm sa_group_t group; 13913034Sdougm int ret = SA_OK; 13923034Sdougm char *type; 13933034Sdougm int transient = 0; 13943034Sdougm char *groupname; 13953034Sdougm char *zfs; 13963034Sdougm 13973034Sdougm type = sa_get_share_attr(share, "type"); 13983034Sdougm group = sa_get_parent_group(share); 13993034Sdougm zfs = sa_get_group_attr(group, "zfs"); 14003034Sdougm groupname = sa_get_group_attr(group, "name"); 14013034Sdougm if (type != NULL && strcmp(type, "persist") != 0) 14024327Sdougm transient = 1; 14033034Sdougm if (type != NULL) 14044327Sdougm sa_free_attr_string(type); 14053034Sdougm 14063034Sdougm /* remove the node from its group then free the memory */ 14073034Sdougm 14083034Sdougm /* 14093034Sdougm * need to test if "busy" 14103034Sdougm */ 14113034Sdougm /* only do SMF action if permanent */ 14123034Sdougm if (!transient || zfs != NULL) { 14134327Sdougm /* remove from legacy dfstab as well as possible SMF */ 14144327Sdougm ret = sa_delete_legacy(share); 14154327Sdougm if (ret == SA_OK) { 14164327Sdougm if (!sa_group_is_zfs(group)) { 14174327Sdougm sa_handle_impl_t impl_handle; 14184327Sdougm impl_handle = (sa_handle_impl_t) 14194327Sdougm sa_find_group_handle(group); 14204327Sdougm if (impl_handle != NULL) { 14214327Sdougm ret = sa_delete_share( 14224327Sdougm impl_handle->scfhandle, group, 14234327Sdougm share); 14244327Sdougm } else { 14254327Sdougm ret = SA_SYSTEM_ERR; 14264327Sdougm } 14274327Sdougm } else { 14284327Sdougm char *sharepath = sa_get_share_attr(share, 14294327Sdougm "path"); 14304327Sdougm if (sharepath != NULL) { 14314327Sdougm ret = sa_zfs_set_sharenfs(group, 14324327Sdougm sharepath, 0); 14334327Sdougm sa_free_attr_string(sharepath); 14344327Sdougm } 14354327Sdougm } 14363034Sdougm } 14373034Sdougm } 14383034Sdougm if (groupname != NULL) 14394327Sdougm sa_free_attr_string(groupname); 14403034Sdougm if (zfs != NULL) 14414327Sdougm sa_free_attr_string(zfs); 14423034Sdougm 14433034Sdougm xmlUnlinkNode((xmlNodePtr)share); 14443034Sdougm xmlFreeNode((xmlNodePtr)share); 14453034Sdougm return (ret); 14463034Sdougm } 14473034Sdougm 14483034Sdougm /* 14493034Sdougm * sa_move_share(group, share) 14503034Sdougm * 14513034Sdougm * move the specified share to the specified group. Update SMF 14523034Sdougm * appropriately. 14533034Sdougm */ 14543034Sdougm 14553034Sdougm int 14563034Sdougm sa_move_share(sa_group_t group, sa_share_t share) 14573034Sdougm { 14583034Sdougm sa_group_t oldgroup; 14593034Sdougm int ret = SA_OK; 14603034Sdougm 14613034Sdougm /* remove the node from its group then free the memory */ 14623034Sdougm 14633034Sdougm oldgroup = sa_get_parent_group(share); 14643034Sdougm if (oldgroup != group) { 14654327Sdougm sa_handle_impl_t impl_handle; 14664327Sdougm xmlUnlinkNode((xmlNodePtr)share); 14673034Sdougm /* 14684327Sdougm * now that the share isn't in its old group, add to 14694327Sdougm * the new one 14703034Sdougm */ 14714327Sdougm xmlAddChild((xmlNodePtr)group, (xmlNodePtr)share); 14724327Sdougm /* need to deal with SMF */ 14734327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 14744327Sdougm if (impl_handle != NULL) { 14754327Sdougm /* 14764327Sdougm * need to remove from old group first and then add to 14774327Sdougm * new group. Ideally, we would do the other order but 14784327Sdougm * need to avoid having the share in two groups at the 14794327Sdougm * same time. 14804327Sdougm */ 14814327Sdougm ret = sa_delete_share(impl_handle->scfhandle, oldgroup, 14824327Sdougm share); 14834327Sdougm if (ret == SA_OK) 14844327Sdougm ret = sa_commit_share(impl_handle->scfhandle, 14854327Sdougm group, share); 14864327Sdougm } else { 14874327Sdougm ret = SA_SYSTEM_ERR; 14884327Sdougm } 14893034Sdougm } 14903034Sdougm return (ret); 14913034Sdougm } 14923034Sdougm 14933034Sdougm /* 14943034Sdougm * sa_get_parent_group(share) 14953034Sdougm * 14963034Sdougm * Return the containg group for the share. If a group was actually 14973034Sdougm * passed in, we don't want a parent so return NULL. 14983034Sdougm */ 14993034Sdougm 15003034Sdougm sa_group_t 15013034Sdougm sa_get_parent_group(sa_share_t share) 15023034Sdougm { 15033034Sdougm xmlNodePtr node = NULL; 15043034Sdougm if (share != NULL) { 15054327Sdougm node = ((xmlNodePtr)share)->parent; 15063034Sdougm /* 15073034Sdougm * make sure parent is a group and not sharecfg since 15083034Sdougm * we may be cheating and passing in a group. 15093034Sdougm * Eventually, groups of groups might come into being. 15103034Sdougm */ 15114327Sdougm if (node == NULL || 15124327Sdougm xmlStrcmp(node->name, (xmlChar *)"sharecfg") == 0) 15134327Sdougm node = NULL; 15143034Sdougm } 15153034Sdougm return ((sa_group_t)node); 15163034Sdougm } 15173034Sdougm 15183034Sdougm /* 15193910Sdougm * _sa_create_group(impl_handle, groupname) 15203034Sdougm * 15213034Sdougm * Create a group in the document. The caller will need to deal with 15223034Sdougm * configuration store and activation. 15233034Sdougm */ 15243034Sdougm 15253034Sdougm sa_group_t 15263910Sdougm _sa_create_group(sa_handle_impl_t impl_handle, char *groupname) 15273034Sdougm { 15283034Sdougm xmlNodePtr node = NULL; 15293034Sdougm 15303034Sdougm if (sa_valid_group_name(groupname)) { 15314327Sdougm node = xmlNewChild(impl_handle->tree, NULL, (xmlChar *)"group", 15324327Sdougm NULL); 15334327Sdougm if (node != NULL) { 15344327Sdougm xmlSetProp(node, (xmlChar *)"name", 15354327Sdougm (xmlChar *)groupname); 15364327Sdougm xmlSetProp(node, (xmlChar *)"state", 15374327Sdougm (xmlChar *)"enabled"); 15384327Sdougm } 15393034Sdougm } 15403034Sdougm return ((sa_group_t)node); 15413034Sdougm } 15423034Sdougm 15433034Sdougm /* 15443034Sdougm * _sa_create_zfs_group(group, groupname) 15453034Sdougm * 15463034Sdougm * Create a ZFS subgroup under the specified group. This may 15473034Sdougm * eventually form the basis of general sub-groups, but is currently 15483034Sdougm * restricted to ZFS. 15493034Sdougm */ 15503034Sdougm sa_group_t 15513034Sdougm _sa_create_zfs_group(sa_group_t group, char *groupname) 15523034Sdougm { 15533034Sdougm xmlNodePtr node = NULL; 15543034Sdougm 15554327Sdougm node = xmlNewChild((xmlNodePtr)group, NULL, (xmlChar *)"group", NULL); 15563034Sdougm if (node != NULL) { 15573034Sdougm xmlSetProp(node, (xmlChar *)"name", (xmlChar *)groupname); 15583034Sdougm xmlSetProp(node, (xmlChar *)"state", (xmlChar *)"enabled"); 15593034Sdougm } 15603034Sdougm 15613034Sdougm return ((sa_group_t)node); 15623034Sdougm } 15633034Sdougm 15643034Sdougm /* 15653034Sdougm * sa_create_group(groupname, *error) 15663034Sdougm * 15673034Sdougm * Create a new group with groupname. Need to validate that it is a 15683034Sdougm * legal name for SMF and the construct the SMF service instance of 15693034Sdougm * svc:/network/shares/group to implement the group. All necessary 15703034Sdougm * operational properties must be added to the group at this point 15713034Sdougm * (via the SMF transaction model). 15723034Sdougm */ 15733034Sdougm sa_group_t 15743910Sdougm sa_create_group(sa_handle_t handle, char *groupname, int *error) 15753034Sdougm { 15763034Sdougm xmlNodePtr node = NULL; 15773034Sdougm sa_group_t group; 15783034Sdougm int ret; 15794327Sdougm char rbacstr[SA_STRSIZE]; 15803910Sdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle; 15813034Sdougm 15823034Sdougm ret = SA_OK; 15833034Sdougm 15843910Sdougm if (impl_handle == NULL || impl_handle->scfhandle == NULL) { 15854327Sdougm ret = SA_SYSTEM_ERR; 15864327Sdougm goto err; 15873034Sdougm } 15883034Sdougm 15893910Sdougm group = sa_get_group(handle, groupname); 15903034Sdougm if (group != NULL) { 15914327Sdougm ret = SA_DUPLICATE_NAME; 15923034Sdougm } else { 15934327Sdougm if (sa_valid_group_name(groupname)) { 15944327Sdougm node = xmlNewChild(impl_handle->tree, NULL, 15954327Sdougm (xmlChar *)"group", NULL); 15964327Sdougm if (node != NULL) { 15974327Sdougm xmlSetProp(node, (xmlChar *)"name", 15984327Sdougm (xmlChar *)groupname); 15994327Sdougm /* default to the group being enabled */ 16004327Sdougm xmlSetProp(node, (xmlChar *)"state", 16014327Sdougm (xmlChar *)"enabled"); 16024327Sdougm ret = sa_create_instance(impl_handle->scfhandle, 16034327Sdougm groupname); 16044327Sdougm if (ret == SA_OK) { 16054327Sdougm ret = sa_start_transaction( 16064327Sdougm impl_handle->scfhandle, 16074327Sdougm "operation"); 16084327Sdougm } 16094327Sdougm if (ret == SA_OK) { 16104327Sdougm ret = sa_set_property( 16114327Sdougm impl_handle->scfhandle, 16124327Sdougm "state", "enabled"); 16134327Sdougm if (ret == SA_OK) { 16144327Sdougm ret = sa_end_transaction( 16154327Sdougm impl_handle->scfhandle); 16164327Sdougm } else { 16174327Sdougm sa_abort_transaction( 16184327Sdougm impl_handle->scfhandle); 16194327Sdougm } 16204327Sdougm } 16214327Sdougm if (ret == SA_OK) { 16224327Sdougm /* initialize the RBAC strings */ 16234327Sdougm ret = sa_start_transaction( 16244327Sdougm impl_handle->scfhandle, 16254327Sdougm "general"); 16264327Sdougm if (ret == SA_OK) { 16274327Sdougm (void) snprintf(rbacstr, 16284327Sdougm sizeof (rbacstr), "%s.%s", 16294327Sdougm SA_RBAC_MANAGE, groupname); 16304327Sdougm ret = sa_set_property( 16314327Sdougm impl_handle->scfhandle, 16323034Sdougm "action_authorization", 16333034Sdougm rbacstr); 16344327Sdougm } 16354327Sdougm if (ret == SA_OK) { 16364327Sdougm (void) snprintf(rbacstr, 16374327Sdougm sizeof (rbacstr), "%s.%s", 16384327Sdougm SA_RBAC_VALUE, groupname); 16394327Sdougm ret = sa_set_property( 16404327Sdougm impl_handle->scfhandle, 16413034Sdougm "value_authorization", 16423034Sdougm rbacstr); 16434327Sdougm } 16444327Sdougm if (ret == SA_OK) { 16454327Sdougm ret = sa_end_transaction( 16464327Sdougm impl_handle->scfhandle); 16474327Sdougm } else { 16484327Sdougm sa_abort_transaction( 16494327Sdougm impl_handle->scfhandle); 16504327Sdougm } 16514327Sdougm } 16524327Sdougm if (ret != SA_OK) { 16534327Sdougm /* 16544327Sdougm * Couldn't commit the group 16554327Sdougm * so we need to undo 16564327Sdougm * internally. 16574327Sdougm */ 16584327Sdougm xmlUnlinkNode(node); 16594327Sdougm xmlFreeNode(node); 16604327Sdougm node = NULL; 16614327Sdougm } 16623034Sdougm } else { 16634327Sdougm ret = SA_NO_MEMORY; 16643034Sdougm } 16653034Sdougm } else { 16664327Sdougm ret = SA_INVALID_NAME; 16673034Sdougm } 16683034Sdougm } 16693034Sdougm err: 16703034Sdougm if (error != NULL) 16714327Sdougm *error = ret; 16723034Sdougm return ((sa_group_t)node); 16733034Sdougm } 16743034Sdougm 16753034Sdougm /* 16763034Sdougm * sa_remove_group(group) 16773034Sdougm * 16783034Sdougm * Remove the specified group. This deletes from the SMF repository. 16793034Sdougm * All property groups and properties are removed. 16803034Sdougm */ 16813034Sdougm 16823034Sdougm int 16833034Sdougm sa_remove_group(sa_group_t group) 16843034Sdougm { 16853034Sdougm char *name; 16863034Sdougm int ret = SA_OK; 16873910Sdougm sa_handle_impl_t impl_handle; 16883034Sdougm 16893910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 16903910Sdougm if (impl_handle != NULL) { 16914327Sdougm name = sa_get_group_attr(group, "name"); 16924327Sdougm if (name != NULL) { 16934327Sdougm ret = sa_delete_instance(impl_handle->scfhandle, name); 16944327Sdougm sa_free_attr_string(name); 16954327Sdougm } 16964327Sdougm xmlUnlinkNode((xmlNodePtr)group); /* make sure unlinked */ 16974327Sdougm xmlFreeNode((xmlNodePtr)group); /* now it is gone */ 16983910Sdougm } else { 16994327Sdougm ret = SA_SYSTEM_ERR; 17003034Sdougm } 17013034Sdougm return (ret); 17023034Sdougm } 17033034Sdougm 17043034Sdougm /* 17053034Sdougm * sa_update_config() 17063034Sdougm * 17073034Sdougm * Used to update legacy files that need to be updated in bulk 17083034Sdougm * Currently, this is a placeholder and will go away in a future 17093034Sdougm * release. 17103034Sdougm */ 17113034Sdougm 17123034Sdougm int 17133910Sdougm sa_update_config(sa_handle_t handle) 17143034Sdougm { 17153034Sdougm /* 17163034Sdougm * do legacy files first so we can tell when they change. 17173034Sdougm * This will go away when we start updating individual records 17183034Sdougm * rather than the whole file. 17193034Sdougm */ 17203910Sdougm update_legacy_config(handle); 17213034Sdougm return (SA_OK); 17223034Sdougm } 17233034Sdougm 17243034Sdougm /* 17253034Sdougm * get_node_attr(node, tag) 17263034Sdougm * 17273034Sdougm * Get the speficied tag(attribute) if it exists on the node. This is 17283034Sdougm * used internally by a number of attribute oriented functions. 17293034Sdougm */ 17303034Sdougm 17313034Sdougm static char * 17323034Sdougm get_node_attr(void *nodehdl, char *tag) 17333034Sdougm { 17343034Sdougm xmlNodePtr node = (xmlNodePtr)nodehdl; 17353034Sdougm xmlChar *name = NULL; 17363034Sdougm 17374327Sdougm if (node != NULL) 17383034Sdougm name = xmlGetProp(node, (xmlChar *)tag); 17393034Sdougm return ((char *)name); 17403034Sdougm } 17413034Sdougm 17423034Sdougm /* 17433034Sdougm * get_node_attr(node, tag) 17443034Sdougm * 17453034Sdougm * Set the speficied tag(attribute) to the specified value This is 17463034Sdougm * used internally by a number of attribute oriented functions. It 17473034Sdougm * doesn't update the repository, only the internal document state. 17483034Sdougm */ 17493034Sdougm 17503034Sdougm void 17513034Sdougm set_node_attr(void *nodehdl, char *tag, char *value) 17523034Sdougm { 17533034Sdougm xmlNodePtr node = (xmlNodePtr)nodehdl; 17543034Sdougm if (node != NULL && tag != NULL) { 17554327Sdougm if (value != NULL) 17563034Sdougm xmlSetProp(node, (xmlChar *)tag, (xmlChar *)value); 17574327Sdougm else 17583034Sdougm xmlUnsetProp(node, (xmlChar *)tag); 17593034Sdougm } 17603034Sdougm } 17613034Sdougm 17623034Sdougm /* 17633034Sdougm * sa_get_group_attr(group, tag) 17643034Sdougm * 17653034Sdougm * Get the specied attribute, if defined, for the group. 17663034Sdougm */ 17673034Sdougm 17683034Sdougm char * 17693034Sdougm sa_get_group_attr(sa_group_t group, char *tag) 17703034Sdougm { 17713034Sdougm return (get_node_attr((void *)group, tag)); 17723034Sdougm } 17733034Sdougm 17743034Sdougm /* 17753034Sdougm * sa_set_group_attr(group, tag, value) 17763034Sdougm * 17773034Sdougm * set the specified tag/attribute on the group using value as its 17783034Sdougm * value. 17793034Sdougm * 17803034Sdougm * This will result in setting the property in the SMF repository as 17813034Sdougm * well as in the internal document. 17823034Sdougm */ 17833034Sdougm 17843034Sdougm int 17853034Sdougm sa_set_group_attr(sa_group_t group, char *tag, char *value) 17863034Sdougm { 17873034Sdougm int ret; 17883034Sdougm char *groupname; 17893910Sdougm sa_handle_impl_t impl_handle; 17903034Sdougm 17913910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 17923910Sdougm if (impl_handle != NULL) { 17934327Sdougm groupname = sa_get_group_attr(group, "name"); 17944327Sdougm ret = sa_get_instance(impl_handle->scfhandle, groupname); 17953910Sdougm if (ret == SA_OK) { 17964327Sdougm set_node_attr((void *)group, tag, value); 17974327Sdougm ret = sa_start_transaction(impl_handle->scfhandle, 17984327Sdougm "operation"); 17994327Sdougm if (ret == SA_OK) { 18004327Sdougm ret = sa_set_property(impl_handle->scfhandle, 18014327Sdougm tag, value); 18024327Sdougm if (ret == SA_OK) 18034327Sdougm (void) sa_end_transaction( 18044327Sdougm impl_handle->scfhandle); 18054327Sdougm else 18064327Sdougm sa_abort_transaction( 18074327Sdougm impl_handle->scfhandle); 18084327Sdougm } 18093034Sdougm } 18104327Sdougm if (groupname != NULL) 18114327Sdougm sa_free_attr_string(groupname); 18123910Sdougm } else { 18134327Sdougm ret = SA_SYSTEM_ERR; 18143034Sdougm } 18153034Sdougm return (ret); 18163034Sdougm } 18173034Sdougm 18183034Sdougm /* 18193034Sdougm * sa_get_share_attr(share, tag) 18203034Sdougm * 18213034Sdougm * Return the value of the tag/attribute set on the specified 18223034Sdougm * share. Returns NULL if the tag doesn't exist. 18233034Sdougm */ 18243034Sdougm 18253034Sdougm char * 18263034Sdougm sa_get_share_attr(sa_share_t share, char *tag) 18273034Sdougm { 18283034Sdougm return (get_node_attr((void *)share, tag)); 18293034Sdougm } 18303034Sdougm 18313034Sdougm /* 18323034Sdougm * sa_get_resource(group, resource) 18333034Sdougm * 18343034Sdougm * Search all the shares in the speified group for a share with a 18353034Sdougm * resource name matching the one specified. 18363034Sdougm * 18373034Sdougm * In the future, it may be advantageous to allow group to be NULL and 18383034Sdougm * search all groups but that isn't needed at present. 18393034Sdougm */ 18403034Sdougm 18413034Sdougm sa_share_t 18423034Sdougm sa_get_resource(sa_group_t group, char *resource) 18433034Sdougm { 18443034Sdougm sa_share_t share = NULL; 18453034Sdougm char *name = NULL; 18463034Sdougm 18473034Sdougm if (resource != NULL) { 18484327Sdougm for (share = sa_get_share(group, NULL); share != NULL; 18494327Sdougm share = sa_get_next_share(share)) { 18504327Sdougm name = sa_get_share_attr(share, "resource"); 18514327Sdougm if (name != NULL) { 18524327Sdougm if (strcmp(name, resource) == 0) 18534327Sdougm break; 18544327Sdougm sa_free_attr_string(name); 18554327Sdougm name = NULL; 18564327Sdougm } 18573034Sdougm } 18584327Sdougm if (name != NULL) 18594327Sdougm sa_free_attr_string(name); 18603034Sdougm } 18613034Sdougm return ((sa_share_t)share); 18623034Sdougm } 18633034Sdougm 18643034Sdougm /* 18653034Sdougm * _sa_set_share_description(share, description) 18663034Sdougm * 18673034Sdougm * Add a description tag with text contents to the specified share. 18683034Sdougm * A separate XML tag is used rather than a property. 18693034Sdougm */ 18703034Sdougm 18713034Sdougm xmlNodePtr 18723034Sdougm _sa_set_share_description(sa_share_t share, char *content) 18733034Sdougm { 18743034Sdougm xmlNodePtr node; 18754327Sdougm node = xmlNewChild((xmlNodePtr)share, NULL, (xmlChar *)"description", 18764327Sdougm NULL); 18773034Sdougm xmlNodeSetContent(node, (xmlChar *)content); 18783034Sdougm return (node); 18793034Sdougm } 18803034Sdougm 18813034Sdougm /* 18823034Sdougm * sa_set_share_attr(share, tag, value) 18833034Sdougm * 18843034Sdougm * Set the share attribute specified by tag to the specified value. In 18853034Sdougm * the case of "resource", enforce a no duplicates in a group rule. If 18863034Sdougm * the share is not transient, commit the changes to the repository 18873034Sdougm * else just update the share internally. 18883034Sdougm */ 18893034Sdougm 18903034Sdougm int 18913034Sdougm sa_set_share_attr(sa_share_t share, char *tag, char *value) 18923034Sdougm { 18933034Sdougm sa_group_t group; 18943034Sdougm sa_share_t resource; 18953034Sdougm int ret = SA_OK; 18963034Sdougm 18973034Sdougm group = sa_get_parent_group(share); 18983034Sdougm 18993034Sdougm /* 19003034Sdougm * There are some attributes that may have specific 19013034Sdougm * restrictions on them. Initially, only "resource" has 19023034Sdougm * special meaning that needs to be checked. Only one instance 19033034Sdougm * of a resource name may exist within a group. 19043034Sdougm */ 19053034Sdougm 19063034Sdougm if (strcmp(tag, "resource") == 0) { 19074327Sdougm resource = sa_get_resource(group, value); 19084327Sdougm if (resource != share && resource != NULL) 19094327Sdougm ret = SA_DUPLICATE_NAME; 19103034Sdougm } 19113034Sdougm if (ret == SA_OK) { 19124327Sdougm set_node_attr((void *)share, tag, value); 19134327Sdougm if (group != NULL) { 19144327Sdougm char *type; 19154327Sdougm /* we can probably optimize this some */ 19164327Sdougm type = sa_get_share_attr(share, "type"); 19174327Sdougm if (type == NULL || strcmp(type, "transient") != 0) { 19184327Sdougm sa_handle_impl_t impl_handle; 19194327Sdougm impl_handle = 19204327Sdougm (sa_handle_impl_t)sa_find_group_handle( 19214327Sdougm group); 19224327Sdougm if (impl_handle != NULL) { 19234327Sdougm ret = sa_commit_share( 19244327Sdougm impl_handle->scfhandle, group, 19254327Sdougm share); 19264327Sdougm } else { 19274327Sdougm ret = SA_SYSTEM_ERR; 19284327Sdougm } 19294327Sdougm } 19304327Sdougm if (type != NULL) 19314327Sdougm sa_free_attr_string(type); 19323910Sdougm } 19333034Sdougm } 19343034Sdougm return (ret); 19353034Sdougm } 19363034Sdougm 19373034Sdougm /* 19383034Sdougm * sa_get_property_attr(prop, tag) 19393034Sdougm * 19403034Sdougm * Get the value of the specified property attribute. Standard 19413034Sdougm * attributes are "type" and "value". 19423034Sdougm */ 19433034Sdougm 19443034Sdougm char * 19453034Sdougm sa_get_property_attr(sa_property_t prop, char *tag) 19463034Sdougm { 19473034Sdougm return (get_node_attr((void *)prop, tag)); 19483034Sdougm } 19493034Sdougm 19503034Sdougm /* 19513034Sdougm * sa_get_optionset_attr(prop, tag) 19523034Sdougm * 19533034Sdougm * Get the value of the specified property attribute. Standard 19543034Sdougm * attribute is "type". 19553034Sdougm */ 19563034Sdougm 19573034Sdougm char * 19583034Sdougm sa_get_optionset_attr(sa_property_t optionset, char *tag) 19593034Sdougm { 19603034Sdougm return (get_node_attr((void *)optionset, tag)); 19613034Sdougm 19623034Sdougm } 19633034Sdougm 19643034Sdougm /* 19653034Sdougm * sa_set_optionset_attr(optionset, tag, value) 19663034Sdougm * 19673034Sdougm * Set the specified attribute(tag) to the specified value on the 19683034Sdougm * optionset. 19693034Sdougm */ 19703034Sdougm 19713034Sdougm void 19723034Sdougm sa_set_optionset_attr(sa_group_t optionset, char *tag, char *value) 19733034Sdougm { 19743034Sdougm set_node_attr((void *)optionset, tag, value); 19753034Sdougm } 19763034Sdougm 19773034Sdougm /* 19783034Sdougm * sa_free_attr_string(string) 19793034Sdougm * 19803034Sdougm * Free the string that was returned in one of the sa_get_*_attr() 19813034Sdougm * functions. 19823034Sdougm */ 19833034Sdougm 19843034Sdougm void 19853034Sdougm sa_free_attr_string(char *string) 19863034Sdougm { 19873034Sdougm xmlFree((xmlChar *)string); 19883034Sdougm } 19893034Sdougm 19903034Sdougm /* 19913034Sdougm * sa_get_optionset(group, proto) 19923034Sdougm * 19933034Sdougm * Return the optionset, if it exists, that is associated with the 19943034Sdougm * specified protocol. 19953034Sdougm */ 19963034Sdougm 19973034Sdougm sa_optionset_t 19983034Sdougm sa_get_optionset(void *group, char *proto) 19993034Sdougm { 20003034Sdougm xmlNodePtr node; 20013034Sdougm xmlChar *value = NULL; 20023034Sdougm 20033034Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 20044327Sdougm node = node->next) { 20053034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) { 20064327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 20074327Sdougm if (proto != NULL) { 20084327Sdougm if (value != NULL && 20094327Sdougm xmlStrcmp(value, (xmlChar *)proto) == 0) { 20104327Sdougm break; 20114327Sdougm } 20124327Sdougm if (value != NULL) { 20134327Sdougm xmlFree(value); 20144327Sdougm value = NULL; 20154327Sdougm } 20164327Sdougm } else { 20174327Sdougm break; 20183034Sdougm } 20193034Sdougm } 20203034Sdougm } 20213034Sdougm if (value != NULL) 20224327Sdougm xmlFree(value); 20233034Sdougm return ((sa_optionset_t)node); 20243034Sdougm } 20253034Sdougm 20263034Sdougm /* 20273034Sdougm * sa_get_next_optionset(optionset) 20283034Sdougm * 20293034Sdougm * Return the next optionset in the group. NULL if this was the last. 20303034Sdougm */ 20313034Sdougm 20323034Sdougm sa_optionset_t 20333034Sdougm sa_get_next_optionset(sa_optionset_t optionset) 20343034Sdougm { 20353034Sdougm xmlNodePtr node; 20363034Sdougm 20373034Sdougm for (node = ((xmlNodePtr)optionset)->next; node != NULL; 20384327Sdougm node = node->next) { 20393034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) { 20403034Sdougm break; 20413034Sdougm } 20423034Sdougm } 20433034Sdougm return ((sa_optionset_t)node); 20443034Sdougm } 20453034Sdougm 20463034Sdougm /* 20473034Sdougm * sa_get_security(group, sectype, proto) 20483034Sdougm * 20493034Sdougm * Return the security optionset. The internal name is a hold over 20503034Sdougm * from the implementation and will be changed before the API is 20513034Sdougm * finalized. This is really a named optionset that can be negotiated 20523034Sdougm * as a group of properties (like NFS security options). 20533034Sdougm */ 20543034Sdougm 20553034Sdougm sa_security_t 20563034Sdougm sa_get_security(sa_group_t group, char *sectype, char *proto) 20573034Sdougm { 20583034Sdougm xmlNodePtr node; 20593034Sdougm xmlChar *value = NULL; 20603034Sdougm 20613034Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 20624327Sdougm node = node->next) { 20634327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) { 20644327Sdougm if (proto != NULL) { 20654327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 20664327Sdougm if (value == NULL || 20674327Sdougm (value != NULL && 20684327Sdougm xmlStrcmp(value, (xmlChar *)proto) != 0)) { 20694327Sdougm /* it doesn't match so continue */ 20704327Sdougm xmlFree(value); 20714327Sdougm value = NULL; 20724327Sdougm continue; 20734327Sdougm } 20744327Sdougm } 20754327Sdougm if (value != NULL) { 20764327Sdougm xmlFree(value); 20774327Sdougm value = NULL; 20784327Sdougm } 20794327Sdougm /* potential match */ 20804327Sdougm if (sectype != NULL) { 20814327Sdougm value = xmlGetProp(node, (xmlChar *)"sectype"); 20824327Sdougm if (value != NULL && 20834327Sdougm xmlStrcmp(value, (xmlChar *)sectype) == 0) { 20844327Sdougm break; 20854327Sdougm } 20864327Sdougm } else { 20874327Sdougm break; 20884327Sdougm } 20893034Sdougm } 20903034Sdougm if (value != NULL) { 20914327Sdougm xmlFree(value); 20924327Sdougm value = NULL; 20933034Sdougm } 20943034Sdougm } 20953034Sdougm if (value != NULL) 20964327Sdougm xmlFree(value); 20973034Sdougm return ((sa_security_t)node); 20983034Sdougm } 20993034Sdougm 21003034Sdougm /* 21013034Sdougm * sa_get_next_security(security) 21023034Sdougm * 21033034Sdougm * Get the next security optionset if one exists. 21043034Sdougm */ 21053034Sdougm 21063034Sdougm sa_security_t 21073034Sdougm sa_get_next_security(sa_security_t security) 21083034Sdougm { 21093034Sdougm xmlNodePtr node; 21103034Sdougm 21113034Sdougm for (node = ((xmlNodePtr)security)->next; node != NULL; 21124327Sdougm node = node->next) { 21133034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) { 21143034Sdougm break; 21153034Sdougm } 21163034Sdougm } 21173034Sdougm return ((sa_security_t)node); 21183034Sdougm } 21193034Sdougm 21203034Sdougm /* 21213034Sdougm * sa_get_property(optionset, prop) 21223034Sdougm * 21233034Sdougm * Get the property object with the name specified in prop from the 21243034Sdougm * optionset. 21253034Sdougm */ 21263034Sdougm 21273034Sdougm sa_property_t 21283034Sdougm sa_get_property(sa_optionset_t optionset, char *prop) 21293034Sdougm { 21303034Sdougm xmlNodePtr node = (xmlNodePtr)optionset; 21313034Sdougm xmlChar *value = NULL; 21323034Sdougm 21333034Sdougm if (optionset == NULL) 21344327Sdougm return (NULL); 21353034Sdougm 21363034Sdougm for (node = node->children; node != NULL; 21374327Sdougm node = node->next) { 21384327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 21394327Sdougm if (prop == NULL) 21404327Sdougm break; 21414327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 21424327Sdougm if (value != NULL && 21434327Sdougm xmlStrcmp(value, (xmlChar *)prop) == 0) { 21444327Sdougm break; 21454327Sdougm } 21464327Sdougm if (value != NULL) { 21474327Sdougm xmlFree(value); 21484327Sdougm value = NULL; 21494327Sdougm } 21503034Sdougm } 21513034Sdougm } 21523034Sdougm if (value != NULL) 21533034Sdougm xmlFree(value); 21543034Sdougm if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"option") != 0) { 21554327Sdougm /* 21564327Sdougm * avoid a non option node -- it is possible to be a 21574327Sdougm * text node 21584327Sdougm */ 21594327Sdougm node = NULL; 21603034Sdougm } 21613034Sdougm return ((sa_property_t)node); 21623034Sdougm } 21633034Sdougm 21643034Sdougm /* 21653034Sdougm * sa_get_next_property(property) 21663034Sdougm * 21673034Sdougm * Get the next property following the specified property. NULL if 21683034Sdougm * this was the last. 21693034Sdougm */ 21703034Sdougm 21713034Sdougm sa_property_t 21723034Sdougm sa_get_next_property(sa_property_t property) 21733034Sdougm { 21743034Sdougm xmlNodePtr node; 21753034Sdougm 21763034Sdougm for (node = ((xmlNodePtr)property)->next; node != NULL; 21774327Sdougm node = node->next) { 21783034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 21793034Sdougm break; 21803034Sdougm } 21813034Sdougm } 21823034Sdougm return ((sa_property_t)node); 21833034Sdougm } 21843034Sdougm 21853034Sdougm /* 21863034Sdougm * sa_set_share_description(share, content) 21873034Sdougm * 21883034Sdougm * Set the description of share to content. 21893034Sdougm */ 21903034Sdougm 21913034Sdougm int 21923034Sdougm sa_set_share_description(sa_share_t share, char *content) 21933034Sdougm { 21943034Sdougm xmlNodePtr node; 21953034Sdougm sa_group_t group; 21963034Sdougm int ret = SA_OK; 21973034Sdougm 21983034Sdougm for (node = ((xmlNodePtr)share)->children; node != NULL; 21994327Sdougm node = node->next) { 22003034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 22013034Sdougm break; 22023034Sdougm } 22033034Sdougm } 22043034Sdougm group = sa_get_parent_group(share); 22053034Sdougm /* no existing description but want to add */ 22063034Sdougm if (node == NULL && content != NULL) { 22073034Sdougm /* add a description */ 22084327Sdougm node = _sa_set_share_description(share, content); 22093034Sdougm } else if (node != NULL && content != NULL) { 22103034Sdougm /* update a description */ 22113034Sdougm xmlNodeSetContent(node, (xmlChar *)content); 22123034Sdougm } else if (node != NULL && content == NULL) { 22133034Sdougm /* remove an existing description */ 22143034Sdougm xmlUnlinkNode(node); 22153034Sdougm xmlFreeNode(node); 22163034Sdougm } 22173910Sdougm if (group != NULL && is_persistent((sa_group_t)share)) { 22184327Sdougm sa_handle_impl_t impl_handle; 22194327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 22204327Sdougm if (impl_handle != NULL) { 22214327Sdougm ret = sa_commit_share(impl_handle->scfhandle, group, 22224327Sdougm share); 22234327Sdougm } else { 22244327Sdougm ret = SA_SYSTEM_ERR; 22254327Sdougm } 22263910Sdougm } 22273034Sdougm return (ret); 22283034Sdougm } 22293034Sdougm 22303034Sdougm /* 22313034Sdougm * fixproblemchars(string) 22323034Sdougm * 22333034Sdougm * don't want any newline or tab characters in the text since these 22343034Sdougm * could break display of data and legacy file formats. 22353034Sdougm */ 22363034Sdougm static void 22373034Sdougm fixproblemchars(char *str) 22383034Sdougm { 22393034Sdougm int c; 22403034Sdougm for (c = *str; c != '\0'; c = *++str) { 22414327Sdougm if (c == '\t' || c == '\n') 22424327Sdougm *str = ' '; 22434327Sdougm else if (c == '"') 22444327Sdougm *str = '\''; 22453034Sdougm } 22463034Sdougm } 22473034Sdougm 22483034Sdougm /* 22493034Sdougm * sa_get_share_description(share) 22503034Sdougm * 22513034Sdougm * Return the description text for the specified share if it 22523034Sdougm * exists. NULL if no description exists. 22533034Sdougm */ 22543034Sdougm 22553034Sdougm char * 22563034Sdougm sa_get_share_description(sa_share_t share) 22573034Sdougm { 22583034Sdougm xmlChar *description = NULL; 22593034Sdougm xmlNodePtr node; 22603034Sdougm 22613034Sdougm for (node = ((xmlNodePtr)share)->children; node != NULL; 22624327Sdougm node = node->next) { 22634327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 22644327Sdougm break; 22654327Sdougm } 22663034Sdougm } 22673034Sdougm if (node != NULL) { 22684327Sdougm description = xmlNodeGetContent((xmlNodePtr)share); 22694327Sdougm fixproblemchars((char *)description); 22703034Sdougm } 22713034Sdougm return ((char *)description); 22723034Sdougm } 22733034Sdougm 22743034Sdougm /* 22753034Sdougm * sa_free(share_description(description) 22763034Sdougm * 22773034Sdougm * Free the description string. 22783034Sdougm */ 22793034Sdougm 22803034Sdougm void 22813034Sdougm sa_free_share_description(char *description) 22823034Sdougm { 22833034Sdougm xmlFree((xmlChar *)description); 22843034Sdougm } 22853034Sdougm 22863034Sdougm /* 22873034Sdougm * sa_create_optionset(group, proto) 22883034Sdougm * 22893034Sdougm * Create an optionset for the specified protocol in the specied 22903034Sdougm * group. This is manifested as a property group within SMF. 22913034Sdougm */ 22923034Sdougm 22933034Sdougm sa_optionset_t 22943034Sdougm sa_create_optionset(sa_group_t group, char *proto) 22953034Sdougm { 22963034Sdougm sa_optionset_t optionset; 22973034Sdougm sa_group_t parent = group; 22983034Sdougm 22993034Sdougm optionset = sa_get_optionset(group, proto); 23003034Sdougm if (optionset != NULL) { 23013034Sdougm /* can't have a duplicate protocol */ 23024327Sdougm optionset = NULL; 23033034Sdougm } else { 23044327Sdougm optionset = (sa_optionset_t)xmlNewChild((xmlNodePtr)group, 23054327Sdougm NULL, (xmlChar *)"optionset", NULL); 23063034Sdougm /* 23073034Sdougm * only put to repository if on a group and we were 23083034Sdougm * able to create an optionset. 23093034Sdougm */ 23104327Sdougm if (optionset != NULL) { 23114327Sdougm char oname[SA_STRSIZE]; 23124327Sdougm char *groupname; 23134327Sdougm char *id = NULL; 23144327Sdougm 23154327Sdougm if (sa_is_share(group)) 23164327Sdougm parent = sa_get_parent_group((sa_share_t)group); 23174327Sdougm 23184327Sdougm sa_set_optionset_attr(optionset, "type", proto); 23193034Sdougm 23204327Sdougm if (sa_is_share(group)) { 23214327Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 23224327Sdougm } 23234327Sdougm (void) sa_optionset_name(optionset, oname, 23244327Sdougm sizeof (oname), id); 23254327Sdougm groupname = sa_get_group_attr(parent, "name"); 23264327Sdougm if (groupname != NULL && is_persistent(group)) { 23274327Sdougm sa_handle_impl_t impl_handle; 23284327Sdougm impl_handle = (sa_handle_impl_t) 23294327Sdougm sa_find_group_handle(group); 23304327Sdougm assert(impl_handle != NULL); 23314327Sdougm if (impl_handle != NULL) { 23324327Sdougm (void) sa_get_instance( 23334327Sdougm impl_handle->scfhandle, 23344327Sdougm groupname); 23354327Sdougm (void) sa_create_pgroup( 23364327Sdougm impl_handle->scfhandle, oname); 23374327Sdougm } 23384327Sdougm } 23394327Sdougm if (groupname != NULL) 23404327Sdougm sa_free_attr_string(groupname); 23414327Sdougm if (id != NULL) 23424327Sdougm sa_free_attr_string(id); 23433034Sdougm } 23443034Sdougm } 23453034Sdougm return (optionset); 23463034Sdougm } 23473034Sdougm 23483034Sdougm /* 23493034Sdougm * sa_get_property_parent(property) 23503034Sdougm * 23513034Sdougm * Given a property, return the object it is a property of. This will 23523034Sdougm * be an optionset of some type. 23533034Sdougm */ 23543034Sdougm 23553034Sdougm static sa_optionset_t 23563034Sdougm sa_get_property_parent(sa_property_t property) 23573034Sdougm { 23583034Sdougm xmlNodePtr node = NULL; 23593034Sdougm 23604327Sdougm if (property != NULL) 23614327Sdougm node = ((xmlNodePtr)property)->parent; 23623034Sdougm return ((sa_optionset_t)node); 23633034Sdougm } 23643034Sdougm 23653034Sdougm /* 23663034Sdougm * sa_get_optionset_parent(optionset) 23673034Sdougm * 23683034Sdougm * Return the parent of the specified optionset. This could be a group 23693034Sdougm * or a share. 23703034Sdougm */ 23713034Sdougm 23723034Sdougm static sa_group_t 23733034Sdougm sa_get_optionset_parent(sa_optionset_t optionset) 23743034Sdougm { 23753034Sdougm xmlNodePtr node = NULL; 23763034Sdougm 23774327Sdougm if (optionset != NULL) 23784327Sdougm node = ((xmlNodePtr)optionset)->parent; 23793034Sdougm return ((sa_group_t)node); 23803034Sdougm } 23813034Sdougm 23823034Sdougm /* 23833034Sdougm * zfs_needs_update(share) 23843034Sdougm * 23853034Sdougm * In order to avoid making multiple updates to a ZFS share when 23863034Sdougm * setting properties, the share attribute "changed" will be set to 23873034Sdougm * true when a property is added or modifed. When done adding 23883034Sdougm * properties, we can then detect that an update is needed. We then 23893034Sdougm * clear the state here to detect additional changes. 23903034Sdougm */ 23913034Sdougm 23923034Sdougm static int 23933034Sdougm zfs_needs_update(sa_share_t share) 23943034Sdougm { 23953034Sdougm char *attr; 23963034Sdougm int result = 0; 23973034Sdougm 23983034Sdougm attr = sa_get_share_attr(share, "changed"); 23993034Sdougm if (attr != NULL) { 24004327Sdougm sa_free_attr_string(attr); 24013034Sdougm result = 1; 24023034Sdougm } 24033034Sdougm set_node_attr((void *)share, "changed", NULL); 24043034Sdougm return (result); 24053034Sdougm } 24063034Sdougm 24073034Sdougm /* 24083034Sdougm * zfs_set_update(share) 24093034Sdougm * 24103034Sdougm * Set the changed attribute of the share to true. 24113034Sdougm */ 24123034Sdougm 24133034Sdougm static void 24143034Sdougm zfs_set_update(sa_share_t share) 24153034Sdougm { 24163034Sdougm set_node_attr((void *)share, "changed", "true"); 24173034Sdougm } 24183034Sdougm 24193034Sdougm /* 24203034Sdougm * sa_commit_properties(optionset, clear) 24213034Sdougm * 24223034Sdougm * Check if SMF or ZFS config and either update or abort the pending 24233034Sdougm * changes. 24243034Sdougm */ 24253034Sdougm 24263034Sdougm int 24273034Sdougm sa_commit_properties(sa_optionset_t optionset, int clear) 24283034Sdougm { 24293034Sdougm sa_group_t group; 24303034Sdougm sa_group_t parent; 24313034Sdougm int zfs = 0; 24323034Sdougm int needsupdate = 0; 24333034Sdougm int ret = SA_OK; 24343910Sdougm sa_handle_impl_t impl_handle; 24353034Sdougm 24363034Sdougm group = sa_get_optionset_parent(optionset); 24373034Sdougm if (group != NULL && (sa_is_share(group) || is_zfs_group(group))) { 24384327Sdougm /* only update ZFS if on a share */ 24394327Sdougm parent = sa_get_parent_group(group); 24404327Sdougm zfs++; 24414327Sdougm if (parent != NULL && is_zfs_group(parent)) 24424327Sdougm needsupdate = zfs_needs_update(group); 24434327Sdougm else 24444327Sdougm zfs = 0; 24453034Sdougm } 24463034Sdougm if (zfs) { 24474327Sdougm if (!clear && needsupdate) 24484327Sdougm ret = sa_zfs_update((sa_share_t)group); 24493034Sdougm } else { 24504327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 24514327Sdougm if (impl_handle != NULL) { 24524327Sdougm if (clear) { 24534327Sdougm (void) sa_abort_transaction( 24544327Sdougm impl_handle->scfhandle); 24554327Sdougm } else { 24564327Sdougm ret = sa_end_transaction( 24574327Sdougm impl_handle->scfhandle); 24584327Sdougm } 24594327Sdougm } else { 24604327Sdougm ret = SA_SYSTEM_ERR; 24614327Sdougm } 24623034Sdougm } 24633034Sdougm return (ret); 24643034Sdougm } 24653034Sdougm 24663034Sdougm /* 24673034Sdougm * sa_destroy_optionset(optionset) 24683034Sdougm * 24693034Sdougm * Remove the optionset from its group. Update the repostory to 24703034Sdougm * reflect this change. 24713034Sdougm */ 24723034Sdougm 24733034Sdougm int 24743034Sdougm sa_destroy_optionset(sa_optionset_t optionset) 24753034Sdougm { 24764327Sdougm char name[SA_STRSIZE]; 24773034Sdougm int len; 24783034Sdougm int ret; 24793034Sdougm char *id = NULL; 24803034Sdougm sa_group_t group; 24813034Sdougm int ispersist = 1; 24823034Sdougm 24833034Sdougm /* now delete the prop group */ 24843034Sdougm group = sa_get_optionset_parent(optionset); 24853034Sdougm if (group != NULL && sa_is_share(group)) { 24864327Sdougm ispersist = is_persistent(group); 24874327Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 24883034Sdougm } 24893034Sdougm if (ispersist) { 24904327Sdougm sa_handle_impl_t impl_handle; 24914327Sdougm len = sa_optionset_name(optionset, name, sizeof (name), id); 24924327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 24934327Sdougm if (impl_handle != NULL) { 24944327Sdougm if (len > 0) { 24954327Sdougm ret = sa_delete_pgroup(impl_handle->scfhandle, 24964327Sdougm name); 24974327Sdougm } 24984327Sdougm } else { 24994327Sdougm ret = SA_SYSTEM_ERR; 25003910Sdougm } 25013034Sdougm } 25023034Sdougm xmlUnlinkNode((xmlNodePtr)optionset); 25033034Sdougm xmlFreeNode((xmlNodePtr)optionset); 25043034Sdougm if (id != NULL) 25054327Sdougm sa_free_attr_string(id); 25063034Sdougm return (ret); 25073034Sdougm } 25083034Sdougm 25093034Sdougm /* private to the implementation */ 25103034Sdougm int 25113034Sdougm _sa_remove_optionset(sa_optionset_t optionset) 25123034Sdougm { 25133034Sdougm int ret = SA_OK; 25143034Sdougm 25153034Sdougm xmlUnlinkNode((xmlNodePtr)optionset); 25163034Sdougm xmlFreeNode((xmlNodePtr)optionset); 25173034Sdougm return (ret); 25183034Sdougm } 25193034Sdougm 25203034Sdougm /* 25213034Sdougm * sa_create_security(group, sectype, proto) 25223034Sdougm * 25233034Sdougm * Create a security optionset (one that has a type name and a 25243034Sdougm * proto). Security is left over from a pure NFS implementation. The 25253034Sdougm * naming will change in the future when the API is released. 25263034Sdougm */ 25273034Sdougm sa_security_t 25283034Sdougm sa_create_security(sa_group_t group, char *sectype, char *proto) 25293034Sdougm { 25303034Sdougm sa_security_t security; 25313034Sdougm char *id = NULL; 25323034Sdougm sa_group_t parent; 25333034Sdougm char *groupname = NULL; 25343034Sdougm 25353034Sdougm if (group != NULL && sa_is_share(group)) { 25364327Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 25374327Sdougm parent = sa_get_parent_group(group); 25384327Sdougm if (parent != NULL) 25394327Sdougm groupname = sa_get_group_attr(parent, "name"); 25403034Sdougm } else if (group != NULL) { 25414327Sdougm groupname = sa_get_group_attr(group, "name"); 25423034Sdougm } 25433034Sdougm 25443034Sdougm security = sa_get_security(group, sectype, proto); 25453034Sdougm if (security != NULL) { 25463034Sdougm /* can't have a duplicate security option */ 25473034Sdougm security = NULL; 25483034Sdougm } else { 25493034Sdougm security = (sa_security_t)xmlNewChild((xmlNodePtr)group, 25504327Sdougm NULL, (xmlChar *)"security", NULL); 25513034Sdougm if (security != NULL) { 25524327Sdougm char oname[SA_STRSIZE]; 25533034Sdougm sa_set_security_attr(security, "type", proto); 25543034Sdougm 25553034Sdougm sa_set_security_attr(security, "sectype", sectype); 25563034Sdougm (void) sa_security_name(security, oname, 25574327Sdougm sizeof (oname), id); 25583034Sdougm if (groupname != NULL && is_persistent(group)) { 25594327Sdougm sa_handle_impl_t impl_handle; 25604327Sdougm impl_handle = 25614327Sdougm (sa_handle_impl_t)sa_find_group_handle( 25624327Sdougm group); 25634327Sdougm if (impl_handle != NULL) { 25644327Sdougm (void) sa_get_instance( 25654327Sdougm impl_handle->scfhandle, groupname); 25664327Sdougm (void) sa_create_pgroup( 25674327Sdougm impl_handle->scfhandle, oname); 25684327Sdougm } 25693034Sdougm } 25703034Sdougm } 25713034Sdougm } 25723034Sdougm if (groupname != NULL) 25734327Sdougm sa_free_attr_string(groupname); 25743034Sdougm return (security); 25753034Sdougm } 25763034Sdougm 25773034Sdougm /* 25783034Sdougm * sa_destroy_security(security) 25793034Sdougm * 25803034Sdougm * Remove the specified optionset from the document and the 25813034Sdougm * configuration. 25823034Sdougm */ 25833034Sdougm 25843034Sdougm int 25853034Sdougm sa_destroy_security(sa_security_t security) 25863034Sdougm { 25874327Sdougm char name[SA_STRSIZE]; 25883034Sdougm int len; 25893034Sdougm int ret = SA_OK; 25903034Sdougm char *id = NULL; 25913034Sdougm sa_group_t group; 25923034Sdougm int iszfs = 0; 25933034Sdougm int ispersist = 1; 25943034Sdougm 25953034Sdougm group = sa_get_optionset_parent(security); 25963034Sdougm 25973034Sdougm if (group != NULL) 25984327Sdougm iszfs = sa_group_is_zfs(group); 25993034Sdougm 26003034Sdougm if (group != NULL && !iszfs) { 26014327Sdougm if (sa_is_share(group)) 26024327Sdougm ispersist = is_persistent(group); 26034327Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 26043034Sdougm } 26053034Sdougm if (ispersist) { 26064327Sdougm len = sa_security_name(security, name, sizeof (name), id); 26074327Sdougm if (!iszfs && len > 0) { 26084327Sdougm sa_handle_impl_t impl_handle; 26094327Sdougm impl_handle = 26104327Sdougm (sa_handle_impl_t)sa_find_group_handle(group); 26114327Sdougm if (impl_handle != NULL) { 26124327Sdougm ret = sa_delete_pgroup(impl_handle->scfhandle, 26134327Sdougm name); 26144327Sdougm } else { 26154327Sdougm ret = SA_SYSTEM_ERR; 26164327Sdougm } 26173910Sdougm } 26183034Sdougm } 26193034Sdougm xmlUnlinkNode((xmlNodePtr)security); 26203034Sdougm xmlFreeNode((xmlNodePtr)security); 26214327Sdougm if (iszfs) 26224327Sdougm ret = sa_zfs_update(group); 26233034Sdougm if (id != NULL) 26244327Sdougm sa_free_attr_string(id); 26253034Sdougm return (ret); 26263034Sdougm } 26273034Sdougm 26283034Sdougm /* 26293034Sdougm * sa_get_security_attr(optionset, tag) 26303034Sdougm * 26313034Sdougm * Return the specified attribute value from the optionset. 26323034Sdougm */ 26333034Sdougm 26343034Sdougm char * 26353034Sdougm sa_get_security_attr(sa_property_t optionset, char *tag) 26363034Sdougm { 26373034Sdougm return (get_node_attr((void *)optionset, tag)); 26383034Sdougm 26393034Sdougm } 26403034Sdougm 26413034Sdougm /* 26423034Sdougm * sa_set_security_attr(optionset, tag, value) 26433034Sdougm * 26443034Sdougm * Set the optioset attribute specied by tag to the specified value. 26453034Sdougm */ 26463034Sdougm 26473034Sdougm void 26483034Sdougm sa_set_security_attr(sa_group_t optionset, char *tag, char *value) 26493034Sdougm { 26503034Sdougm set_node_attr((void *)optionset, tag, value); 26513034Sdougm } 26523034Sdougm 26533034Sdougm /* 26543034Sdougm * is_nodetype(node, type) 26553034Sdougm * 26563034Sdougm * Check to see if node is of the type specified. 26573034Sdougm */ 26583034Sdougm 26593034Sdougm static int 26603034Sdougm is_nodetype(void *node, char *type) 26613034Sdougm { 26623034Sdougm return (strcmp((char *)((xmlNodePtr)node)->name, type) == 0); 26633034Sdougm } 26643034Sdougm 26654327Sdougm 26664327Sdougm /* 26674327Sdougm * add_or_update() 26684327Sdougm * 26694327Sdougm * Add or update a property. Pulled out of sa_set_prop_by_prop for 26704327Sdougm * readability. 26714327Sdougm */ 26724327Sdougm static int 26734327Sdougm add_or_update(scfutilhandle_t *scf_handle, int type, scf_value_t *value, 26744327Sdougm scf_transaction_entry_t *entry, char *name, char *valstr) 26754327Sdougm { 26764327Sdougm int ret = SA_SYSTEM_ERR; 26774327Sdougm 26784327Sdougm if (value != NULL) { 26794327Sdougm if (type == SA_PROP_OP_ADD) 26804327Sdougm ret = scf_transaction_property_new(scf_handle->trans, 26814327Sdougm entry, name, SCF_TYPE_ASTRING); 26824327Sdougm else 26834327Sdougm ret = scf_transaction_property_change(scf_handle->trans, 26844327Sdougm entry, name, SCF_TYPE_ASTRING); 26854327Sdougm if (ret == 0) { 26864327Sdougm ret = scf_value_set_astring(value, valstr); 26874327Sdougm if (ret == 0) 26884327Sdougm ret = scf_entry_add_value(entry, value); 26894327Sdougm if (ret == 0) 26904327Sdougm return (ret); 26914327Sdougm scf_value_destroy(value); 26924327Sdougm } else { 26934327Sdougm scf_entry_destroy(entry); 26944327Sdougm } 26954327Sdougm } 26964327Sdougm return (SA_SYSTEM_ERR); 26974327Sdougm } 26984327Sdougm 26993034Sdougm /* 27003034Sdougm * sa_set_prop_by_prop(optionset, group, prop, type) 27013034Sdougm * 27023034Sdougm * Add/remove/update the specified property prop into the optionset or 27033034Sdougm * share. If a share, sort out which property group based on GUID. In 27043034Sdougm * all cases, the appropriate transaction is set (or ZFS share is 27053034Sdougm * marked as needing an update) 27063034Sdougm */ 27073034Sdougm 27083034Sdougm static int 27093034Sdougm sa_set_prop_by_prop(sa_optionset_t optionset, sa_group_t group, 27103034Sdougm sa_property_t prop, int type) 27113034Sdougm { 27123034Sdougm char *name; 27133034Sdougm char *valstr; 27143034Sdougm int ret = SA_OK; 27153034Sdougm scf_transaction_entry_t *entry; 27163034Sdougm scf_value_t *value; 27173034Sdougm int opttype; /* 1 == optionset, 0 == security */ 27183034Sdougm char *id = NULL; 27193034Sdougm int iszfs = 0; 27203034Sdougm int isshare = 0; 27213034Sdougm sa_group_t parent = NULL; 27223910Sdougm sa_handle_impl_t impl_handle; 27233910Sdougm scfutilhandle_t *scf_handle; 27243034Sdougm 27253034Sdougm if (!is_persistent(group)) { 27263034Sdougm /* 27273034Sdougm * if the group/share is not persistent we don't need 27283034Sdougm * to do anything here 27293034Sdougm */ 27304327Sdougm return (SA_OK); 27313034Sdougm } 27323910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 27334327Sdougm if (impl_handle == NULL || impl_handle->scfhandle == NULL) 27344327Sdougm return (SA_SYSTEM_ERR); 27353910Sdougm scf_handle = impl_handle->scfhandle; 27363034Sdougm name = sa_get_property_attr(prop, "type"); 27373034Sdougm valstr = sa_get_property_attr(prop, "value"); 27383034Sdougm entry = scf_entry_create(scf_handle->handle); 27393034Sdougm opttype = is_nodetype((void *)optionset, "optionset"); 27403034Sdougm 27413034Sdougm if (valstr != NULL && entry != NULL) { 27424327Sdougm if (sa_is_share(group)) { 27434327Sdougm isshare = 1; 27444327Sdougm parent = sa_get_parent_group(group); 27454327Sdougm if (parent != NULL) 27464327Sdougm iszfs = is_zfs_group(parent); 27474327Sdougm } else { 27484327Sdougm iszfs = is_zfs_group(group); 27493034Sdougm } 27504327Sdougm if (!iszfs) { 27514327Sdougm if (scf_handle->trans == NULL) { 27524327Sdougm char oname[SA_STRSIZE]; 27534327Sdougm char *groupname = NULL; 27544327Sdougm if (isshare) { 27554327Sdougm if (parent != NULL) { 27564327Sdougm groupname = 27574327Sdougm sa_get_group_attr(parent, 27584327Sdougm "name"); 27594327Sdougm } 27604327Sdougm id = 27614327Sdougm sa_get_share_attr((sa_share_t)group, 27624327Sdougm "id"); 27634327Sdougm } else { 27644327Sdougm groupname = sa_get_group_attr(group, 27654327Sdougm "name"); 27664327Sdougm } 27674327Sdougm if (groupname != NULL) { 27684327Sdougm ret = sa_get_instance(scf_handle, 27694327Sdougm groupname); 27704327Sdougm sa_free_attr_string(groupname); 27714327Sdougm } 27724327Sdougm if (opttype) 27734327Sdougm (void) sa_optionset_name(optionset, 27744327Sdougm oname, sizeof (oname), id); 27754327Sdougm else 27764327Sdougm (void) sa_security_name(optionset, 27774327Sdougm oname, sizeof (oname), id); 27784327Sdougm ret = sa_start_transaction(scf_handle, oname); 27793910Sdougm } 27804327Sdougm if (ret == SA_OK) { 27814327Sdougm switch (type) { 27824327Sdougm case SA_PROP_OP_REMOVE: 27834327Sdougm ret = scf_transaction_property_delete( 27844327Sdougm scf_handle->trans, entry, name); 27854327Sdougm break; 27864327Sdougm case SA_PROP_OP_ADD: 27874327Sdougm case SA_PROP_OP_UPDATE: 27884327Sdougm value = scf_value_create( 27894327Sdougm scf_handle->handle); 27904327Sdougm ret = add_or_update(scf_handle, type, 27914327Sdougm value, entry, name, valstr); 27924327Sdougm break; 27933034Sdougm } 27943034Sdougm } 27954327Sdougm } else { 27964327Sdougm /* 27974327Sdougm * ZFS update. The calling function would have updated 27984327Sdougm * the internal XML structure. Just need to flag it as 27994327Sdougm * changed for ZFS. 28004327Sdougm */ 28014327Sdougm zfs_set_update((sa_share_t)group); 28024327Sdougm } 28033034Sdougm } 28043034Sdougm 28053034Sdougm if (name != NULL) 28064327Sdougm sa_free_attr_string(name); 28073034Sdougm if (valstr != NULL) 28084327Sdougm sa_free_attr_string(valstr); 28093034Sdougm else if (entry != NULL) 28104327Sdougm scf_entry_destroy(entry); 28113034Sdougm 28123034Sdougm if (ret == -1) 28134327Sdougm ret = SA_SYSTEM_ERR; 28143034Sdougm 28153034Sdougm return (ret); 28163034Sdougm } 28173034Sdougm 28183034Sdougm /* 28193034Sdougm * sa_create_property(name, value) 28203034Sdougm * 28213034Sdougm * Create a new property with the specified name and value. 28223034Sdougm */ 28233034Sdougm 28243034Sdougm sa_property_t 28253034Sdougm sa_create_property(char *name, char *value) 28263034Sdougm { 28273034Sdougm xmlNodePtr node; 28283034Sdougm 28293034Sdougm node = xmlNewNode(NULL, (xmlChar *)"option"); 28303034Sdougm if (node != NULL) { 28313034Sdougm xmlSetProp(node, (xmlChar *)"type", (xmlChar *)name); 28323034Sdougm xmlSetProp(node, (xmlChar *)"value", (xmlChar *)value); 28333034Sdougm } 28343034Sdougm return ((sa_property_t)node); 28353034Sdougm } 28363034Sdougm 28373034Sdougm /* 28383034Sdougm * sa_add_property(object, property) 28393034Sdougm * 28403034Sdougm * Add the specified property to the object. Issue the appropriate 28413034Sdougm * transaction or mark a ZFS object as needing an update. 28423034Sdougm */ 28433034Sdougm 28443034Sdougm int 28453034Sdougm sa_add_property(void *object, sa_property_t property) 28463034Sdougm { 28473034Sdougm int ret = SA_OK; 28483034Sdougm sa_group_t parent; 28493034Sdougm sa_group_t group; 28503034Sdougm char *proto; 28513034Sdougm 28523034Sdougm proto = sa_get_optionset_attr(object, "type"); 28533034Sdougm if (property != NULL) { 28544327Sdougm if ((ret = sa_valid_property(object, proto, property)) == 28554327Sdougm SA_OK) { 28564327Sdougm property = (sa_property_t)xmlAddChild( 28574327Sdougm (xmlNodePtr)object, (xmlNodePtr)property); 28584327Sdougm } else { 28594327Sdougm if (proto != NULL) 28604327Sdougm sa_free_attr_string(proto); 28614327Sdougm return (ret); 28624327Sdougm } 28633034Sdougm } 28643034Sdougm 28653034Sdougm if (proto != NULL) 28664327Sdougm sa_free_attr_string(proto); 28673034Sdougm 28683034Sdougm parent = sa_get_parent_group(object); 28693034Sdougm if (!is_persistent(parent)) { 28704327Sdougm return (ret); 28713034Sdougm } 28723034Sdougm 28733034Sdougm if (sa_is_share(parent)) 28744327Sdougm group = sa_get_parent_group(parent); 28753034Sdougm else 28764327Sdougm group = parent; 28773034Sdougm 28784327Sdougm if (property == NULL) { 28794327Sdougm ret = SA_NO_MEMORY; 28804327Sdougm } else { 28814327Sdougm char oname[SA_STRSIZE]; 28823034Sdougm 28834327Sdougm if (!is_zfs_group(group)) { 28844327Sdougm char *id = NULL; 28854327Sdougm sa_handle_impl_t impl_handle; 28864327Sdougm scfutilhandle_t *scf_handle; 28873910Sdougm 28884327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle( 28894327Sdougm group); 28904327Sdougm if (impl_handle == NULL || 28914327Sdougm impl_handle->scfhandle == NULL) 28924327Sdougm ret = SA_SYSTEM_ERR; 28934327Sdougm if (ret == SA_OK) { 28944327Sdougm scf_handle = impl_handle->scfhandle; 28954327Sdougm if (sa_is_share((sa_group_t)parent)) { 28964327Sdougm id = sa_get_share_attr( 28974327Sdougm (sa_share_t)parent, "id"); 28984327Sdougm } 28994327Sdougm if (scf_handle->trans == NULL) { 29004327Sdougm if (is_nodetype(object, "optionset")) { 29014327Sdougm (void) sa_optionset_name( 29024327Sdougm (sa_optionset_t)object, 29034327Sdougm oname, sizeof (oname), id); 29044327Sdougm } else { 29054327Sdougm (void) sa_security_name( 29064327Sdougm (sa_optionset_t)object, 29074327Sdougm oname, sizeof (oname), id); 29084327Sdougm } 29094327Sdougm ret = sa_start_transaction(scf_handle, 29104327Sdougm oname); 29114327Sdougm } 29124327Sdougm if (ret == SA_OK) { 29134327Sdougm char *name; 29144327Sdougm char *value; 29154327Sdougm name = sa_get_property_attr(property, 29164327Sdougm "type"); 29174327Sdougm value = sa_get_property_attr(property, 29184327Sdougm "value"); 29194327Sdougm if (name != NULL && value != NULL) { 29204327Sdougm if (scf_handle->scf_state == 29214327Sdougm SCH_STATE_INIT) { 29224327Sdougm ret = sa_set_property( 29234327Sdougm scf_handle, name, 29244327Sdougm value); 29254327Sdougm } 29264327Sdougm } else { 29274327Sdougm ret = SA_CONFIG_ERR; 29284327Sdougm } 29294327Sdougm if (name != NULL) 29304327Sdougm sa_free_attr_string( 29314327Sdougm name); 29324327Sdougm if (value != NULL) 29334327Sdougm sa_free_attr_string(value); 29344327Sdougm } 29354327Sdougm if (id != NULL) 29364327Sdougm sa_free_attr_string(id); 29374327Sdougm } 29384327Sdougm } else { 29394327Sdougm /* 29404327Sdougm * ZFS is a special case. We do want 29414327Sdougm * to allow editing property/security 29424327Sdougm * lists since we can have a better 29434327Sdougm * syntax and we also want to keep 29444327Sdougm * things consistent when possible. 29454327Sdougm * 29464327Sdougm * Right now, we defer until the 29474327Sdougm * sa_commit_properties so we can get 29484327Sdougm * them all at once. We do need to 29494327Sdougm * mark the share as "changed" 29504327Sdougm */ 29514327Sdougm zfs_set_update((sa_share_t)parent); 29523034Sdougm } 29533034Sdougm } 29543034Sdougm return (ret); 29553034Sdougm } 29563034Sdougm 29573034Sdougm /* 29583034Sdougm * sa_remove_property(property) 29593034Sdougm * 29603034Sdougm * Remove the specied property from its containing object. Update the 29613034Sdougm * repository as appropriate. 29623034Sdougm */ 29633034Sdougm 29643034Sdougm int 29653034Sdougm sa_remove_property(sa_property_t property) 29663034Sdougm { 29673034Sdougm int ret = SA_OK; 29683034Sdougm 29693034Sdougm if (property != NULL) { 29703034Sdougm sa_optionset_t optionset; 29713034Sdougm sa_group_t group; 29723034Sdougm optionset = sa_get_property_parent(property); 29733034Sdougm if (optionset != NULL) { 29744327Sdougm group = sa_get_optionset_parent(optionset); 29754327Sdougm if (group != NULL) { 29764327Sdougm ret = sa_set_prop_by_prop(optionset, group, 29774327Sdougm property, SA_PROP_OP_REMOVE); 29784327Sdougm } 29793034Sdougm } 29803034Sdougm xmlUnlinkNode((xmlNodePtr)property); 29813034Sdougm xmlFreeNode((xmlNodePtr)property); 29823034Sdougm } else { 29834327Sdougm ret = SA_NO_SUCH_PROP; 29843034Sdougm } 29853034Sdougm return (ret); 29863034Sdougm } 29873034Sdougm 29883034Sdougm /* 29893034Sdougm * sa_update_property(property, value) 29903034Sdougm * 29913034Sdougm * Update the specified property to the new value. If value is NULL, 29923034Sdougm * we currently treat this as a remove. 29933034Sdougm */ 29943034Sdougm 29953034Sdougm int 29963034Sdougm sa_update_property(sa_property_t property, char *value) 29973034Sdougm { 29983034Sdougm int ret = SA_OK; 29993034Sdougm if (value == NULL) { 30003034Sdougm return (sa_remove_property(property)); 30013034Sdougm } else { 30023034Sdougm sa_optionset_t optionset; 30033034Sdougm sa_group_t group; 30043034Sdougm set_node_attr((void *)property, "value", value); 30053034Sdougm optionset = sa_get_property_parent(property); 30063034Sdougm if (optionset != NULL) { 30074327Sdougm group = sa_get_optionset_parent(optionset); 30084327Sdougm if (group != NULL) { 30094327Sdougm ret = sa_set_prop_by_prop(optionset, group, 30104327Sdougm property, SA_PROP_OP_UPDATE); 30114327Sdougm } 30123034Sdougm } else { 30134327Sdougm ret = SA_NO_SUCH_PROP; 30143034Sdougm } 30153034Sdougm } 30163034Sdougm return (ret); 30173034Sdougm } 30183034Sdougm 30193034Sdougm /* 30203034Sdougm * sa_get_protocol_property(propset, prop) 30213034Sdougm * 30223034Sdougm * Get the specified protocol specific property. These are global to 30233034Sdougm * the protocol and not specific to a group or share. 30243034Sdougm */ 30253034Sdougm 30263034Sdougm sa_property_t 30273034Sdougm sa_get_protocol_property(sa_protocol_properties_t propset, char *prop) 30283034Sdougm { 30293034Sdougm xmlNodePtr node = (xmlNodePtr)propset; 30303034Sdougm xmlChar *value = NULL; 30313034Sdougm 30323034Sdougm for (node = node->children; node != NULL; 30334327Sdougm node = node->next) { 30344327Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 30354327Sdougm if (prop == NULL) 30364327Sdougm break; 30374327Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 30384327Sdougm if (value != NULL && 30394327Sdougm xmlStrcasecmp(value, (xmlChar *)prop) == 0) { 30404327Sdougm break; 30414327Sdougm } 30424327Sdougm if (value != NULL) { 30434327Sdougm xmlFree(value); 30444327Sdougm value = NULL; 30454327Sdougm } 30463034Sdougm } 30473034Sdougm } 30483034Sdougm if (value != NULL) 30493034Sdougm xmlFree(value); 30503034Sdougm if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"option") != 0) { 30514327Sdougm /* 30524327Sdougm * avoid a non option node -- it is possible to be a 30534327Sdougm * text node 30544327Sdougm */ 30554327Sdougm node = NULL; 30563034Sdougm } 30573034Sdougm return ((sa_property_t)node); 30583034Sdougm } 30593034Sdougm 30603034Sdougm /* 30613034Sdougm * sa_get_next_protocol_property(prop) 30623034Sdougm * 30633034Sdougm * Get the next protocol specific property in the list. 30643034Sdougm */ 30653034Sdougm 30663034Sdougm sa_property_t 30673034Sdougm sa_get_next_protocol_property(sa_property_t prop) 30683034Sdougm { 30693034Sdougm xmlNodePtr node; 30703034Sdougm 30713034Sdougm for (node = ((xmlNodePtr)prop)->next; node != NULL; 30724327Sdougm node = node->next) { 30733034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 30743034Sdougm break; 30753034Sdougm } 30763034Sdougm } 30773034Sdougm return ((sa_property_t)node); 30783034Sdougm } 30793034Sdougm 30803034Sdougm /* 30813034Sdougm * sa_set_protocol_property(prop, value) 30823034Sdougm * 30833034Sdougm * Set the specified property to have the new value. The protocol 30843034Sdougm * specific plugin will then be called to update the property. 30853034Sdougm */ 30863034Sdougm 30873034Sdougm int 30883034Sdougm sa_set_protocol_property(sa_property_t prop, char *value) 30893034Sdougm { 30903034Sdougm sa_protocol_properties_t propset; 30913034Sdougm char *proto; 30923034Sdougm int ret = SA_INVALID_PROTOCOL; 30933034Sdougm 30943034Sdougm propset = ((xmlNodePtr)prop)->parent; 30953034Sdougm if (propset != NULL) { 30964327Sdougm proto = sa_get_optionset_attr(propset, "type"); 30974327Sdougm if (proto != NULL) { 30984327Sdougm set_node_attr((xmlNodePtr)prop, "value", value); 30994327Sdougm ret = sa_proto_set_property(proto, prop); 31004327Sdougm sa_free_attr_string(proto); 31014327Sdougm } 31023034Sdougm } 31033034Sdougm return (ret); 31043034Sdougm } 31053034Sdougm 31063034Sdougm /* 31073034Sdougm * sa_add_protocol_property(propset, prop) 31083034Sdougm * 31093034Sdougm * Add a new property to the protocol sepcific property set. 31103034Sdougm */ 31113034Sdougm 31123034Sdougm int 31133034Sdougm sa_add_protocol_property(sa_protocol_properties_t propset, sa_property_t prop) 31143034Sdougm { 31153034Sdougm xmlNodePtr node; 31163034Sdougm 31173034Sdougm /* should check for legitimacy */ 31183034Sdougm node = xmlAddChild((xmlNodePtr)propset, (xmlNodePtr)prop); 31193034Sdougm if (node != NULL) 31204327Sdougm return (SA_OK); 31213034Sdougm return (SA_NO_MEMORY); 31223034Sdougm } 31233034Sdougm 31243034Sdougm /* 31253034Sdougm * sa_create_protocol_properties(proto) 31263034Sdougm * 31273034Sdougm * Create a protocol specifity property set. 31283034Sdougm */ 31293034Sdougm 31303034Sdougm sa_protocol_properties_t 31313034Sdougm sa_create_protocol_properties(char *proto) 31323034Sdougm { 31333034Sdougm xmlNodePtr node; 31344327Sdougm 31353034Sdougm node = xmlNewNode(NULL, (xmlChar *)"propertyset"); 31364327Sdougm if (node != NULL) 31374327Sdougm xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto); 31383034Sdougm return (node); 31393034Sdougm } 3140