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 /* 233034Sdougm * Copyright 2006 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> 373034Sdougm #include <unistd.h> 383034Sdougm #include <libxml/parser.h> 393034Sdougm #include <libxml/tree.h> 403034Sdougm #include "libshare.h" 413034Sdougm #include "libshare_impl.h" 423034Sdougm #include <libscf.h> 433034Sdougm #include "scfutil.h" 443034Sdougm #include <ctype.h> 453034Sdougm #include <libintl.h> 463034Sdougm 473034Sdougm #if _NOT_SMF 483034Sdougm #define CONFIG_FILE "/var/tmp/share.cfg" 493034Sdougm #define CONFIG_FILE_TMP "/var/tmp/share.cfg.tmp" 503034Sdougm #endif 513034Sdougm #define TSTAMP(tm) (uint64_t)(((uint64_t)tm.tv_sec << 32) | \ 523034Sdougm (tm.tv_nsec & 0xffffffff)) 533034Sdougm 543034Sdougm /* 553034Sdougm * internal data structures 563034Sdougm */ 573034Sdougm 583034Sdougm static xmlNodePtr sa_config_tree; /* the current config */ 593034Sdougm static xmlDocPtr sa_config_doc = NULL; /* current config document */ 603034Sdougm extern struct sa_proto_plugin *sap_proto_list; 613034Sdougm 623034Sdougm /* current SMF/SVC repository handle */ 633034Sdougm static scfutilhandle_t *scf_handle = NULL; 643034Sdougm extern void getlegacyconfig(char *, xmlNodePtr *); 653034Sdougm extern int gettransients(xmlNodePtr *); 663034Sdougm extern int sa_valid_property(void *, char *, sa_property_t); 673034Sdougm extern char *sa_fstype(char *); 683034Sdougm extern int sa_is_share(void *); 693034Sdougm extern ssize_t scf_max_name_len; /* defined in scfutil during initialization */ 703034Sdougm extern int sa_group_is_zfs(sa_group_t); 713034Sdougm extern int sa_path_is_zfs(char *); 723034Sdougm extern int sa_zfs_set_sharenfs(sa_group_t, char *, int); 733034Sdougm extern void update_legacy_config(void); 743034Sdougm extern int issubdir(char *, char *); 75*3218Sdougm extern void sa_zfs_init(void); 76*3218Sdougm extern void sa_zfs_fini(void); 773034Sdougm 783034Sdougm static int sa_initialized = 0; 793034Sdougm 803034Sdougm /* helper functions */ 813034Sdougm 823034Sdougm char * 833034Sdougm sa_errorstr(int err) 843034Sdougm { 853034Sdougm static char errstr[32]; 863034Sdougm char *ret = NULL; 873034Sdougm 883034Sdougm switch (err) { 893034Sdougm case SA_OK: 903034Sdougm ret = gettext("ok"); 913034Sdougm break; 923034Sdougm case SA_NO_SUCH_PATH: 933034Sdougm ret = gettext("path doesn't exist"); 943034Sdougm break; 953034Sdougm case SA_NO_MEMORY: 963034Sdougm ret = gettext("no memory"); 973034Sdougm break; 983034Sdougm case SA_DUPLICATE_NAME: 993034Sdougm ret = gettext("name in use"); 1003034Sdougm break; 1013034Sdougm case SA_BAD_PATH: 1023034Sdougm ret = gettext("bad path"); 1033034Sdougm break; 1043034Sdougm case SA_NO_SUCH_GROUP: 1053034Sdougm ret = gettext("no such group"); 1063034Sdougm break; 1073034Sdougm case SA_CONFIG_ERR: 1083034Sdougm ret = gettext("configuration error"); 1093034Sdougm break; 1103034Sdougm case SA_SYSTEM_ERR: 1113034Sdougm ret = gettext("system error"); 1123034Sdougm break; 1133034Sdougm case SA_SYNTAX_ERR: 1143034Sdougm ret = gettext("syntax error"); 1153034Sdougm break; 1163034Sdougm case SA_NO_PERMISSION: 1173034Sdougm ret = gettext("no permission"); 1183034Sdougm break; 1193034Sdougm case SA_BUSY: 1203034Sdougm ret = gettext("busy"); 1213034Sdougm break; 1223034Sdougm case SA_NO_SUCH_PROP: 1233034Sdougm ret = gettext("no such property"); 1243034Sdougm break; 1253034Sdougm case SA_INVALID_NAME: 1263034Sdougm ret = gettext("invalid name"); 1273034Sdougm break; 1283034Sdougm case SA_INVALID_PROTOCOL: 1293034Sdougm ret = gettext("invalid protocol"); 1303034Sdougm break; 1313034Sdougm case SA_NOT_ALLOWED: 1323034Sdougm ret = gettext("operation not allowed"); 1333034Sdougm break; 1343034Sdougm case SA_BAD_VALUE: 1353034Sdougm ret = gettext("bad property value"); 1363034Sdougm break; 1373034Sdougm case SA_INVALID_SECURITY: 1383034Sdougm ret = gettext("invalid security type"); 1393034Sdougm break; 1403034Sdougm case SA_NO_SUCH_SECURITY: 1413034Sdougm ret = gettext("security type not found"); 1423034Sdougm break; 1433034Sdougm case SA_VALUE_CONFLICT: 1443034Sdougm ret = gettext("property value conflict"); 1453034Sdougm break; 1463034Sdougm case SA_NOT_IMPLEMENTED: 1473034Sdougm ret = gettext("not implemented"); 1483034Sdougm break; 1493034Sdougm case SA_INVALID_PATH: 1503034Sdougm ret = gettext("invalid path"); 1513034Sdougm break; 1523034Sdougm case SA_NOT_SUPPORTED: 1533034Sdougm ret = gettext("operation not supported"); 1543034Sdougm break; 1553034Sdougm case SA_PROP_SHARE_ONLY: 1563034Sdougm ret = gettext("property not valid for group"); 1573034Sdougm break; 1583034Sdougm case SA_NOT_SHARED: 1593034Sdougm ret = gettext("not shared"); 1603034Sdougm break; 1613034Sdougm default: 1623034Sdougm (void) snprintf(errstr, sizeof (errstr), 1633034Sdougm gettext("unknown %d"), err); 1643034Sdougm ret = errstr; 1653034Sdougm } 1663034Sdougm return (ret); 1673034Sdougm } 1683034Sdougm 1693034Sdougm /* 1703034Sdougm * get_legacy_timestamp(root, path) 1713034Sdougm * gets the timestamp of the last time sharemgr updated the legacy 1723034Sdougm * files. This is used to determine if someone has modified them by 1733034Sdougm * hand. 1743034Sdougm */ 1753034Sdougm static uint64_t 1763034Sdougm get_legacy_timestamp(xmlNodePtr root, char *path) 1773034Sdougm { 1783034Sdougm uint64_t tval = 0; 1793034Sdougm xmlNodePtr node; 1803034Sdougm xmlChar *lpath = NULL; 1813034Sdougm xmlChar *timestamp = NULL; 1823034Sdougm 1833034Sdougm for (node = root->xmlChildrenNode; node != NULL; 1843034Sdougm node = node->next) { 1853034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"legacy") == 0) { 1863034Sdougm /* a possible legacy node for this path */ 1873034Sdougm lpath = xmlGetProp(node, (xmlChar *)"path"); 1883034Sdougm if (lpath != NULL && xmlStrcmp(lpath, (xmlChar *)path) == 0) { 1893034Sdougm /* now have the node, extract the data */ 1903034Sdougm timestamp = xmlGetProp(node, (xmlChar *)"timestamp"); 1913034Sdougm if (timestamp != NULL) { 1923034Sdougm tval = strtoull((char *)timestamp, NULL, 0); 1933034Sdougm break; 1943034Sdougm } 1953034Sdougm } 1963034Sdougm if (lpath != NULL) { 1973034Sdougm xmlFree(lpath); 1983034Sdougm lpath = NULL; 1993034Sdougm } 2003034Sdougm } 2013034Sdougm } 2023034Sdougm if (lpath != NULL) 2033034Sdougm xmlFree(lpath); 2043034Sdougm if (timestamp != NULL) 2053034Sdougm xmlFree(timestamp); 2063034Sdougm return (tval); 2073034Sdougm } 2083034Sdougm 2093034Sdougm /* 2103034Sdougm * set_legacy_timestamp(root, path, timevalue) 2113034Sdougm * 2123034Sdougm * add the current timestamp value to the configuration for use in 2133034Sdougm * determining when to update the legacy files. For SMF, this 2143034Sdougm * property is kept in default/operation/legacy_timestamp 2153034Sdougm */ 2163034Sdougm 2173034Sdougm static void 2183034Sdougm set_legacy_timestamp(xmlNodePtr root, char *path, uint64_t tval) 2193034Sdougm { 2203034Sdougm xmlNodePtr node; 2213034Sdougm xmlChar *lpath = NULL; 2223034Sdougm 2233034Sdougm for (node = root->xmlChildrenNode; node != NULL; 2243034Sdougm node = node->next) { 2253034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"legacy") == 0) { 2263034Sdougm /* a possible legacy node for this path */ 2273034Sdougm lpath = xmlGetProp(node, (xmlChar *)"path"); 2283034Sdougm if (lpath != NULL && xmlStrcmp(lpath, (xmlChar *)path) == 0) { 2293034Sdougm xmlFree(lpath); 2303034Sdougm break; 2313034Sdougm } 2323034Sdougm if (lpath != NULL) 2333034Sdougm xmlFree(lpath); 2343034Sdougm } 2353034Sdougm } 2363034Sdougm if (node == NULL) { 2373034Sdougm /* need to create the first legacy timestamp node */ 2383034Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"legacy", NULL); 2393034Sdougm } 2403034Sdougm if (node != NULL) { 2413034Sdougm char tstring[32]; 2423034Sdougm int ret; 2433034Sdougm 2443034Sdougm (void) snprintf(tstring, sizeof (tstring), "%lld", tval); 2453034Sdougm xmlSetProp(node, (xmlChar *)"timestamp", (xmlChar *)tstring); 2463034Sdougm xmlSetProp(node, (xmlChar *)"path", (xmlChar *)path); 2473034Sdougm /* now commit to SMF */ 2483034Sdougm ret = sa_get_instance(scf_handle, "default"); 2493034Sdougm if (ret == SA_OK) { 2503034Sdougm ret = sa_start_transaction(scf_handle, "operation"); 2513034Sdougm if (ret == SA_OK) { 2523034Sdougm ret = sa_set_property(scf_handle, "legacy-timestamp", 2533034Sdougm tstring); 2543034Sdougm if (ret == SA_OK) { 2553034Sdougm (void) sa_end_transaction(scf_handle); 2563034Sdougm } else { 2573034Sdougm sa_abort_transaction(scf_handle); 2583034Sdougm } 2593034Sdougm } 2603034Sdougm } 2613034Sdougm } 2623034Sdougm } 2633034Sdougm 2643034Sdougm /* 2653034Sdougm * is_shared(share) 2663034Sdougm * 2673034Sdougm * determine if the specified share is currently shared or not. 2683034Sdougm */ 2693034Sdougm static int 2703034Sdougm is_shared(sa_share_t share) 2713034Sdougm { 2723034Sdougm char *shared; 2733034Sdougm int result = 0; /* assume not */ 2743034Sdougm 2753034Sdougm shared = sa_get_share_attr(share, "shared"); 2763034Sdougm if (shared != NULL) { 2773034Sdougm if (strcmp(shared, "true") == 0) 2783034Sdougm result = 1; 2793034Sdougm sa_free_attr_string(shared); 2803034Sdougm } 2813034Sdougm return (result); 2823034Sdougm } 2833034Sdougm 2843034Sdougm /* 2853034Sdougm * checksubdir determines if the specified path is a subdirectory of 2863034Sdougm * another share. It calls issubdir() from the old share 2873034Sdougm * implementation to do the complicated work. 2883034Sdougm */ 2893034Sdougm static int 2903034Sdougm checksubdir(char *newpath) 2913034Sdougm { 2923034Sdougm sa_group_t group; 2933034Sdougm sa_share_t share; 2943034Sdougm int issub; 2953034Sdougm char *path = NULL; 2963034Sdougm 2973034Sdougm for (issub = 0, group = sa_get_group(NULL); 2983034Sdougm group != NULL && !issub; 2993034Sdougm group = sa_get_next_group(group)) { 3003034Sdougm for (share = sa_get_share(group, NULL); share != NULL; 3013034Sdougm share = sa_get_next_share(share)) { 3023034Sdougm /* 3033034Sdougm * The original behavior of share never checked 3043034Sdougm * against the permanent configuration 3053034Sdougm * (/etc/dfs/dfstab). PIT has a number of cases where 3063034Sdougm * it depends on this older behavior even though it 3073034Sdougm * could be considered incorrect. We may tighten this 3083034Sdougm * up in the future. 3093034Sdougm */ 3103034Sdougm if (!is_shared(share)) 3113034Sdougm continue; 3123034Sdougm 3133034Sdougm path = sa_get_share_attr(share, "path"); 3143034Sdougm if (newpath != NULL && 3153034Sdougm (strcmp(path, newpath) == 0 || issubdir(newpath, path) || 3163034Sdougm issubdir(path, newpath))) { 3173034Sdougm sa_free_attr_string(path); 3183034Sdougm path = NULL; 3193034Sdougm issub = SA_INVALID_PATH; 3203034Sdougm break; 3213034Sdougm } 3223034Sdougm sa_free_attr_string(path); 3233034Sdougm path = NULL; 3243034Sdougm } 3253034Sdougm } 3263034Sdougm if (path != NULL) 3273034Sdougm sa_free_attr_string(path); 3283034Sdougm return (issub); 3293034Sdougm } 3303034Sdougm 3313034Sdougm /* 3323034Sdougm * validpath(path) 3333034Sdougm * determine if the provided path is valid for a share. It shouldn't 3343034Sdougm * be a sub-dir of an already shared path or the parent directory of a 3353034Sdougm * share path. 3363034Sdougm */ 3373034Sdougm static int 3383034Sdougm validpath(char *path) 3393034Sdougm { 3403034Sdougm int error = SA_OK; 3413034Sdougm struct stat st; 3423034Sdougm sa_share_t share; 3433034Sdougm char *fstype; 3443034Sdougm 3453034Sdougm if (*path != '/') { 3463034Sdougm return (SA_BAD_PATH); 3473034Sdougm } 3483034Sdougm if (stat(path, &st) < 0) { 3493034Sdougm error = SA_NO_SUCH_PATH; 3503034Sdougm } else { 3513034Sdougm share = sa_find_share(path); 3523034Sdougm if (share != NULL) { 3533034Sdougm error = SA_DUPLICATE_NAME; 3543034Sdougm } 3553034Sdougm if (error == SA_OK) { 3563034Sdougm /* 3573034Sdougm * check for special case with file system that might 3583034Sdougm * have restrictions. For now, ZFS is the only case 3593034Sdougm * since it has its own idea of how to configure 3603034Sdougm * shares. We do this before subdir checking since 3613034Sdougm * things like ZFS will do that for us. This should 3623034Sdougm * also be done via plugin interface. 3633034Sdougm */ 3643034Sdougm fstype = sa_fstype(path); 3653034Sdougm if (fstype != NULL && strcmp(fstype, "zfs") == 0) { 3663034Sdougm if (sa_zfs_is_shared(path)) 3673034Sdougm error = SA_DUPLICATE_NAME; 3683034Sdougm } 3693034Sdougm if (fstype != NULL) 3703034Sdougm sa_free_fstype(fstype); 3713034Sdougm } 3723034Sdougm if (error == SA_OK) { 3733034Sdougm error = checksubdir(path); 3743034Sdougm } 3753034Sdougm } 3763034Sdougm return (error); 3773034Sdougm } 3783034Sdougm 3793034Sdougm /* 3803034Sdougm * check to see if group/share is persistent. 3813034Sdougm */ 3823034Sdougm static int 3833034Sdougm is_persistent(sa_group_t group) 3843034Sdougm { 3853034Sdougm char *type; 3863034Sdougm int persist = 1; 3873034Sdougm 3883034Sdougm type = sa_get_group_attr(group, "type"); 3893034Sdougm if (type != NULL && strcmp(type, "transient") == 0) 3903034Sdougm persist = 0; 3913034Sdougm if (type != NULL) 3923034Sdougm sa_free_attr_string(type); 3933034Sdougm return (persist); 3943034Sdougm } 3953034Sdougm 3963034Sdougm /* 3973034Sdougm * sa_valid_group_name(name) 3983034Sdougm * 3993034Sdougm * check that the "name" contains only valid characters and otherwise 4003034Sdougm * fits the required naming conventions. Valid names must start with 4013034Sdougm * an alphabetic and the remainder may consist of only alphanumeric 4023034Sdougm * plus the '-' and '_' characters. This name limitation comes from 4033034Sdougm * inherent limitations in SMF. 4043034Sdougm */ 4053034Sdougm 4063034Sdougm int 4073034Sdougm sa_valid_group_name(char *name) 4083034Sdougm { 4093034Sdougm int ret = 1; 4103034Sdougm ssize_t len; 4113034Sdougm 4123034Sdougm if (name != NULL && isalpha(*name)) { 4133034Sdougm char c; 4143034Sdougm len = strlen(name); 4153034Sdougm if (len < (scf_max_name_len - sizeof ("group:"))) { 4163034Sdougm for (c = *name++; c != '\0' && ret != 0; c = *name++) { 4173034Sdougm if (!isalnum(c) && c != '-' && c != '_') 4183034Sdougm ret = 0; 4193034Sdougm } 4203034Sdougm } else { 4213034Sdougm ret = 0; 4223034Sdougm } 4233034Sdougm } else { 4243034Sdougm ret = 0; 4253034Sdougm } 4263034Sdougm return (ret); 4273034Sdougm } 4283034Sdougm 4293034Sdougm 4303034Sdougm /* 4313034Sdougm * is_zfs_group(group) 4323034Sdougm * Determine if the specified group is a ZFS sharenfs group 4333034Sdougm */ 4343034Sdougm static int 4353034Sdougm is_zfs_group(sa_group_t group) 4363034Sdougm { 4373034Sdougm int ret = 0; 4383034Sdougm xmlNodePtr parent; 4393034Sdougm xmlChar *zfs; 4403034Sdougm 4413034Sdougm if (strcmp((char *)((xmlNodePtr)group)->name, "share") == 0) { 4423034Sdougm parent = (xmlNodePtr)sa_get_parent_group(group); 4433034Sdougm } else { 4443034Sdougm parent = (xmlNodePtr)group; 4453034Sdougm } 4463034Sdougm zfs = xmlGetProp(parent, (xmlChar *)"zfs"); 4473034Sdougm if (zfs != NULL) { 4483034Sdougm xmlFree(zfs); 4493034Sdougm ret = 1; 4503034Sdougm } 4513034Sdougm return (ret); 4523034Sdougm } 4533034Sdougm 4543034Sdougm /* 4553034Sdougm * sa_optionset_name(optionset, oname, len, id) 4563034Sdougm * return the SMF name for the optionset. If id is not NULL, it 4573034Sdougm * will have the GUID value for a share and should be used 4583034Sdougm * instead of the keyword "optionset" which is used for 4593034Sdougm * groups. If the optionset doesn't have a protocol type 4603034Sdougm * associated with it, "default" is used. This shouldn't happen 4613034Sdougm * at this point but may be desirable in the future if there are 4623034Sdougm * protocol independent properties added. The name is returned in 4633034Sdougm * oname. 4643034Sdougm */ 4653034Sdougm 4663034Sdougm static int 4673034Sdougm sa_optionset_name(sa_optionset_t optionset, char *oname, size_t len, char *id) 4683034Sdougm { 4693034Sdougm char *proto; 4703034Sdougm 4713034Sdougm if (id == NULL) 4723034Sdougm id = "optionset"; 4733034Sdougm 4743034Sdougm proto = sa_get_optionset_attr(optionset, "type"); 4753034Sdougm len = snprintf(oname, len, "%s_%s", id, proto ? proto : "default"); 4763034Sdougm 4773034Sdougm if (proto != NULL) 4783034Sdougm sa_free_attr_string(proto); 4793034Sdougm return (len); 4803034Sdougm } 4813034Sdougm 4823034Sdougm /* 4833034Sdougm * sa_security_name(optionset, oname, len, id) 4843034Sdougm * 4853034Sdougm * return the SMF name for the security. If id is not NULL, it will 4863034Sdougm * have the GUID value for a share and should be used instead of the 4873034Sdougm * keyword "optionset" which is used for groups. If the optionset 4883034Sdougm * doesn't have a protocol type associated with it, "default" is 4893034Sdougm * used. This shouldn't happen at this point but may be desirable in 4903034Sdougm * the future if there are protocol independent properties added. The 4913034Sdougm * name is returned in oname. The security type is also encoded into 4923034Sdougm * the name. In the future, this wil *be handled a bit differently. 4933034Sdougm */ 4943034Sdougm 4953034Sdougm static int 4963034Sdougm sa_security_name(sa_security_t security, char *oname, size_t len, char *id) 4973034Sdougm { 4983034Sdougm char *proto; 4993034Sdougm char *sectype; 5003034Sdougm 5013034Sdougm if (id == NULL) 5023034Sdougm id = "optionset"; 5033034Sdougm 5043034Sdougm proto = sa_get_security_attr(security, "type"); 5053034Sdougm sectype = sa_get_security_attr(security, "sectype"); 5063034Sdougm len = snprintf(oname, len, "%s_%s_%s", id, 5073034Sdougm proto ? proto : "default", 5083034Sdougm sectype ? sectype : "default"); 5093034Sdougm if (proto != NULL) 5103034Sdougm sa_free_attr_string(proto); 5113034Sdougm if (sectype != NULL) 5123034Sdougm sa_free_attr_string(sectype); 5133034Sdougm return (len); 5143034Sdougm } 5153034Sdougm 5163034Sdougm /* 5173034Sdougm * sa_init() 5183034Sdougm * Initialize the API 5193034Sdougm * find all the shared objects 5203034Sdougm * init the tables with all objects 5213034Sdougm * read in the current configuration 5223034Sdougm */ 5233034Sdougm 5243034Sdougm void 5253034Sdougm sa_init(int init_service) 5263034Sdougm { 5273034Sdougm struct stat st; 5283034Sdougm int legacy = 0; 5293034Sdougm uint64_t tval = 0; 5303034Sdougm 5313034Sdougm if (!sa_initialized) { 5323034Sdougm /* get protocol specific structures */ 5333034Sdougm (void) proto_plugin_init(); 5343034Sdougm if (init_service & SA_INIT_SHARE_API) { 5353034Sdougm /* 536*3218Sdougm * initialize access into libzfs. We use this when 537*3218Sdougm * collecting info about ZFS datasets and shares. 538*3218Sdougm */ 539*3218Sdougm sa_zfs_init(); 540*3218Sdougm /* 5413034Sdougm * since we want to use SMF, initialize an svc handle 5423034Sdougm * and find out what is there. 5433034Sdougm */ 5443034Sdougm scf_handle = sa_scf_init(); 5453034Sdougm if (scf_handle != NULL) { 5463034Sdougm (void) sa_get_config(scf_handle, &sa_config_tree, 5473034Sdougm &sa_config_doc); 5483034Sdougm tval = get_legacy_timestamp(sa_config_tree, 5493034Sdougm SA_LEGACY_DFSTAB); 5503034Sdougm if (tval == 0) { 5513034Sdougm /* first time so make sure default is setup */ 5523034Sdougm sa_group_t defgrp; 5533034Sdougm sa_optionset_t opt; 5543034Sdougm defgrp = sa_get_group("default"); 5553034Sdougm if (defgrp != NULL) { 5563034Sdougm opt = sa_get_optionset(defgrp, NULL); 5573034Sdougm if (opt == NULL) 5583034Sdougm /* NFS is the default for default */ 5593034Sdougm opt = sa_create_optionset(defgrp, "nfs"); 5603034Sdougm } 5613034Sdougm } 5623034Sdougm if (stat(SA_LEGACY_DFSTAB, &st) >= 0 && 5633034Sdougm tval != TSTAMP(st.st_ctim)) { 5643034Sdougm getlegacyconfig(SA_LEGACY_DFSTAB, &sa_config_tree); 5653034Sdougm if (stat(SA_LEGACY_DFSTAB, &st) >= 0) 5663034Sdougm set_legacy_timestamp(sa_config_tree, 5673034Sdougm SA_LEGACY_DFSTAB, 5683034Sdougm TSTAMP(st.st_ctim)); 5693034Sdougm } 5703034Sdougm legacy |= sa_get_zfs_shares("zfs"); 5713034Sdougm legacy |= gettransients(&sa_config_tree); 5723034Sdougm } 5733034Sdougm } 5743034Sdougm } 5753034Sdougm } 5763034Sdougm 5773034Sdougm /* 5783034Sdougm * sa_fini() 5793034Sdougm * Uninitialize the API structures including the configuration 580*3218Sdougm * data structures and ZFS related data. 5813034Sdougm */ 5823034Sdougm 5833034Sdougm void 5843034Sdougm sa_fini() 5853034Sdougm { 5863034Sdougm if (sa_initialized) { 5873034Sdougm /* free the config trees */ 5883034Sdougm sa_initialized = 0; 5893034Sdougm if (sa_config_doc != NULL) 5903034Sdougm xmlFreeDoc(sa_config_doc); 5913034Sdougm sa_config_tree = NULL; 5923034Sdougm sa_config_doc = NULL; 5933034Sdougm sa_scf_fini(scf_handle); 594*3218Sdougm sa_zfs_fini(); 5953034Sdougm (void) proto_plugin_init(); 5963034Sdougm } 5973034Sdougm } 5983034Sdougm 5993034Sdougm /* 6003034Sdougm * sa_get_protocols(char **protocol) 6013034Sdougm * Get array of protocols that are supported 6023034Sdougm * Returns pointer to an allocated and NULL terminated 6033034Sdougm * array of strings. Caller must free. 6043034Sdougm * This really should be determined dynamically. 6053034Sdougm * If there aren't any defined, return -1. 6063034Sdougm * Use free() to return memory. 6073034Sdougm */ 6083034Sdougm 6093034Sdougm int 6103034Sdougm sa_get_protocols(char ***protocols) 6113034Sdougm { 6123034Sdougm int numproto = -1; 6133034Sdougm 6143034Sdougm if (protocols != NULL) { 6153034Sdougm struct sa_proto_plugin *plug; 6163034Sdougm for (numproto = 0, plug = sap_proto_list; plug != NULL; 6173034Sdougm plug = plug->plugin_next) { 6183034Sdougm numproto++; 6193034Sdougm } 6203034Sdougm 6213034Sdougm *protocols = calloc(numproto + 1, sizeof (char *)); 6223034Sdougm if (*protocols != NULL) { 6233034Sdougm int ret = 0; 6243034Sdougm for (plug = sap_proto_list; plug != NULL; 6253034Sdougm plug = plug->plugin_next) { 6263034Sdougm /* faking for now */ 6273034Sdougm (*protocols)[ret++] = plug->plugin_ops->sa_protocol; 6283034Sdougm } 6293034Sdougm } else { 6303034Sdougm numproto = -1; 6313034Sdougm } 6323034Sdougm } 6333034Sdougm return (numproto); 6343034Sdougm } 6353034Sdougm 6363034Sdougm /* 6373034Sdougm * find_group_by_name(node, group) 6383034Sdougm * 6393034Sdougm * search the XML document subtree specified by node to find the group 6403034Sdougm * specified by group. Searching subtree allows subgroups to be 6413034Sdougm * searched for. 6423034Sdougm */ 6433034Sdougm 6443034Sdougm static xmlNodePtr 6453034Sdougm find_group_by_name(xmlNodePtr node, xmlChar *group) 6463034Sdougm { 6473034Sdougm xmlChar *name = NULL; 6483034Sdougm 6493034Sdougm for (node = node->xmlChildrenNode; node != NULL; 6503034Sdougm node = node->next) { 6513034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"group") == 0) { 6523034Sdougm /* if no groupname, return the first found */ 6533034Sdougm if (group == NULL) 6543034Sdougm break; 6553034Sdougm name = xmlGetProp(node, (xmlChar *)"name"); 6563034Sdougm if (name != NULL && 6573034Sdougm xmlStrcmp(name, group) == 0) { 6583034Sdougm break; 6593034Sdougm } 6603034Sdougm if (name != NULL) { 6613034Sdougm xmlFree(name); 6623034Sdougm name = NULL; 6633034Sdougm } 6643034Sdougm } 6653034Sdougm } 6663034Sdougm if (name != NULL) 6673034Sdougm xmlFree(name); 6683034Sdougm return (node); 6693034Sdougm } 6703034Sdougm 6713034Sdougm /* 6723034Sdougm * sa_get_group(groupname) 6733034Sdougm * Return the "group" specified. If groupname is NULL, 6743034Sdougm * return the first group of the list of groups. 6753034Sdougm */ 6763034Sdougm sa_group_t 6773034Sdougm sa_get_group(char *groupname) 6783034Sdougm { 6793034Sdougm xmlNodePtr node = NULL; 6803034Sdougm char *subgroup = NULL; 6813034Sdougm char *group = NULL; 6823034Sdougm 6833034Sdougm if (sa_config_tree != NULL) { 6843034Sdougm if (groupname != NULL) { 6853034Sdougm group = strdup(groupname); 6863034Sdougm subgroup = strchr(group, '/'); 6873034Sdougm if (subgroup != NULL) 6883034Sdougm *subgroup++ = '\0'; 6893034Sdougm } 6903034Sdougm node = find_group_by_name(sa_config_tree, (xmlChar *)group); 6913034Sdougm /* if a subgroup, find it before returning */ 6923034Sdougm if (subgroup != NULL && node != NULL) { 6933034Sdougm node = find_group_by_name(node, (xmlChar *)subgroup); 6943034Sdougm } 6953034Sdougm } 6963034Sdougm if (node != NULL && (char *)group != NULL) 6973034Sdougm (void) sa_get_instance(scf_handle, (char *)group); 6983034Sdougm if (group != NULL) 6993034Sdougm free(group); 7003034Sdougm return ((sa_group_t)(node)); 7013034Sdougm } 7023034Sdougm 7033034Sdougm /* 7043034Sdougm * sa_get_next_group(group) 7053034Sdougm * Return the "next" group after the specified group from 7063034Sdougm * the internal group list. NULL if there are no more. 7073034Sdougm */ 7083034Sdougm sa_group_t 7093034Sdougm sa_get_next_group(sa_group_t group) 7103034Sdougm { 7113034Sdougm xmlNodePtr ngroup = NULL; 7123034Sdougm if (group != NULL) { 7133034Sdougm for (ngroup = ((xmlNodePtr)group)->next; ngroup != NULL; 7143034Sdougm ngroup = ngroup->next) { 7153034Sdougm if (xmlStrcmp(ngroup->name, (xmlChar *)"group") == 0) 7163034Sdougm break; 7173034Sdougm } 7183034Sdougm } 7193034Sdougm return ((sa_group_t)ngroup); 7203034Sdougm } 7213034Sdougm 7223034Sdougm /* 7233034Sdougm * sa_get_share(group, sharepath) 7243034Sdougm * Return the share object for the share specified. The share 7253034Sdougm * must be in the specified group. Return NULL if not found. 7263034Sdougm */ 7273034Sdougm sa_share_t 7283034Sdougm sa_get_share(sa_group_t group, char *sharepath) 7293034Sdougm { 7303034Sdougm xmlNodePtr node = NULL; 7313034Sdougm xmlChar *path; 7323034Sdougm 7333034Sdougm /* 7343034Sdougm * For future scalability, this should end up building a cache 7353034Sdougm * since it will get called regularly by the mountd and info 7363034Sdougm * services. 7373034Sdougm */ 7383034Sdougm if (group != NULL) { 7393034Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 7403034Sdougm node = node->next) { 7413034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) { 7423034Sdougm if (sharepath == NULL) { 7433034Sdougm break; 7443034Sdougm } else { 7453034Sdougm /* is it the correct share? */ 7463034Sdougm path = xmlGetProp(node, (xmlChar *)"path"); 7473034Sdougm if (path != NULL && 7483034Sdougm xmlStrcmp(path, (xmlChar *)sharepath) == 0) { 7493034Sdougm xmlFree(path); 7503034Sdougm break; 7513034Sdougm } 7523034Sdougm xmlFree(path); 7533034Sdougm } 7543034Sdougm } 7553034Sdougm } 7563034Sdougm } 7573034Sdougm return ((sa_share_t)node); 7583034Sdougm } 7593034Sdougm 7603034Sdougm /* 7613034Sdougm * sa_get_next_share(share) 7623034Sdougm * Return the next share following the specified share 7633034Sdougm * from the internal list of shares. Returns NULL if there 7643034Sdougm * are no more shares. The list is relative to the same 7653034Sdougm * group. 7663034Sdougm */ 7673034Sdougm sa_share_t 7683034Sdougm sa_get_next_share(sa_share_t share) 7693034Sdougm { 7703034Sdougm xmlNodePtr node = NULL; 7713034Sdougm 7723034Sdougm if (share != NULL) { 7733034Sdougm for (node = ((xmlNodePtr)share)->next; node != NULL; 7743034Sdougm node = node->next) { 7753034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) { 7763034Sdougm break; 7773034Sdougm } 7783034Sdougm } 7793034Sdougm } 7803034Sdougm return ((sa_share_t)node); 7813034Sdougm } 7823034Sdougm 7833034Sdougm /* 7843034Sdougm * _sa_get_child_node(node, type) 7853034Sdougm * 7863034Sdougm * find the child node of the specified node that has "type". This is 7873034Sdougm * used to implement several internal functions. 7883034Sdougm */ 7893034Sdougm 7903034Sdougm static xmlNodePtr 7913034Sdougm _sa_get_child_node(xmlNodePtr node, xmlChar *type) 7923034Sdougm { 7933034Sdougm xmlNodePtr child; 7943034Sdougm for (child = node->xmlChildrenNode; child != NULL; 7953034Sdougm child = child->next) 7963034Sdougm if (xmlStrcmp(child->name, type) == 0) 7973034Sdougm return (child); 7983034Sdougm return ((xmlNodePtr)NULL); 7993034Sdougm } 8003034Sdougm 8013034Sdougm /* 8023034Sdougm * find_share(group, path) 8033034Sdougm * 8043034Sdougm * Search all the shares in the specified group for one that has the 8053034Sdougm * specified path. 8063034Sdougm */ 8073034Sdougm 8083034Sdougm static sa_share_t 8093034Sdougm find_share(sa_group_t group, char *sharepath) 8103034Sdougm { 8113034Sdougm sa_share_t share; 8123034Sdougm char *path; 8133034Sdougm 8143034Sdougm for (share = sa_get_share(group, NULL); share != NULL; 8153034Sdougm share = sa_get_next_share(share)) { 8163034Sdougm path = sa_get_share_attr(share, "path"); 8173034Sdougm if (path != NULL && strcmp(path, sharepath) == 0) { 8183034Sdougm sa_free_attr_string(path); 8193034Sdougm break; 8203034Sdougm } 8213034Sdougm if (path != NULL) 8223034Sdougm sa_free_attr_string(path); 8233034Sdougm } 8243034Sdougm return (share); 8253034Sdougm } 8263034Sdougm 8273034Sdougm /* 8283034Sdougm * sa_get_sub_group(group) 8293034Sdougm * 8303034Sdougm * Get the first sub-group of group. The sa_get_next_group() function 8313034Sdougm * can be used to get the rest. This is currently only used for ZFS 8323034Sdougm * sub-groups but could be used to implement a more general mechanism. 8333034Sdougm */ 8343034Sdougm 8353034Sdougm sa_group_t 8363034Sdougm sa_get_sub_group(sa_group_t group) 8373034Sdougm { 8383034Sdougm return ((sa_group_t)_sa_get_child_node((xmlNodePtr)group, 8393034Sdougm (xmlChar *)"group")); 8403034Sdougm } 8413034Sdougm 8423034Sdougm /* 8433034Sdougm * sa_find_share(sharepath) 8443034Sdougm * Finds a share regardless of group. In the future, this 8453034Sdougm * function should utilize a cache and hash table of some kind. 8463034Sdougm * The current assumption is that a path will only be shared 8473034Sdougm * once. In the future, this may change as implementation of 8483034Sdougm * resource names comes into being. 8493034Sdougm */ 8503034Sdougm sa_share_t 8513034Sdougm sa_find_share(char *sharepath) 8523034Sdougm { 8533034Sdougm sa_group_t group; 8543034Sdougm sa_group_t zgroup; 8553034Sdougm sa_share_t share = NULL; 8563034Sdougm int done = 0; 8573034Sdougm 8583034Sdougm for (group = sa_get_group(NULL); group != NULL && !done; 8593034Sdougm group = sa_get_next_group(group)) { 8603034Sdougm if (is_zfs_group(group)) { 8613034Sdougm for (zgroup = (sa_group_t)_sa_get_child_node((xmlNodePtr)group, 8623034Sdougm (xmlChar *)"group"); 8633034Sdougm zgroup != NULL; zgroup = sa_get_next_group(zgroup)) { 8643034Sdougm share = find_share(zgroup, sharepath); 8653034Sdougm if (share != NULL) 8663034Sdougm break; 8673034Sdougm } 8683034Sdougm } else { 8693034Sdougm share = find_share(group, sharepath); 8703034Sdougm } 8713034Sdougm if (share != NULL) 8723034Sdougm break; 8733034Sdougm } 8743034Sdougm return (share); 8753034Sdougm } 8763034Sdougm 8773034Sdougm /* 8783034Sdougm * sa_check_path(group, path) 8793034Sdougm * 8803034Sdougm * check that path is a valid path relative to the group. Currently, 8813034Sdougm * we are ignoring the group and checking only the NFS rules. Later, 8823034Sdougm * we may want to use the group to then check against the protocols 8833034Sdougm * enabled on the group. 8843034Sdougm */ 8853034Sdougm 8863034Sdougm int 8873034Sdougm sa_check_path(sa_group_t group, char *path) 8883034Sdougm { 8893034Sdougm #ifdef lint 8903034Sdougm group = group; 8913034Sdougm #endif 8923034Sdougm return (validpath(path)); 8933034Sdougm } 8943034Sdougm 8953034Sdougm /* 8963034Sdougm * _sa_add_share(group, sharepath, persist, *error) 8973034Sdougm * 8983034Sdougm * common code for all types of add_share. sa_add_share() is the 8993034Sdougm * public API, we also need to be able to do this when parsing legacy 9003034Sdougm * files and construction of the internal configuration while 9013034Sdougm * extracting config info from SMF. 9023034Sdougm */ 9033034Sdougm 9043034Sdougm sa_share_t 9053034Sdougm _sa_add_share(sa_group_t group, char *sharepath, int persist, int *error) 9063034Sdougm { 9073034Sdougm xmlNodePtr node = NULL; 9083034Sdougm int err; 9093034Sdougm 9103034Sdougm err = SA_OK; /* assume success */ 9113034Sdougm 9123034Sdougm node = xmlNewChild((xmlNodePtr)group, NULL, 9133034Sdougm (xmlChar *)"share", NULL); 9143034Sdougm if (node != NULL) { 9153034Sdougm xmlSetProp(node, (xmlChar *)"path", (xmlChar *)sharepath); 9163034Sdougm xmlSetProp(node, (xmlChar *)"type", persist ? 9173034Sdougm (xmlChar *)"persist" : (xmlChar *)"transient"); 9183034Sdougm if (persist != SA_SHARE_TRANSIENT) { 9193034Sdougm /* 9203034Sdougm * persistent shares come in two flavors: SMF and 9213034Sdougm * ZFS. Sort this one out based on target group and 9223034Sdougm * path type. Currently, only NFS is supported in the 9233034Sdougm * ZFS group and it is always on. 9243034Sdougm */ 9253034Sdougm if (sa_group_is_zfs(group) && sa_path_is_zfs(sharepath)) { 9263034Sdougm err = sa_zfs_set_sharenfs(group, sharepath, 1); 9273034Sdougm } else { 9283034Sdougm err = sa_commit_share(scf_handle, group, 9293034Sdougm (sa_share_t)node); 9303034Sdougm } 9313034Sdougm } 9323034Sdougm if (err == SA_NO_PERMISSION && persist & SA_SHARE_PARSER) { 9333034Sdougm /* called by the dfstab parser so could be a show */ 9343034Sdougm err = SA_OK; 9353034Sdougm } 9363034Sdougm if (err != SA_OK) { 9373034Sdougm /* 9383034Sdougm * we couldn't commit to the repository so undo 9393034Sdougm * our internal state to reflect reality. 9403034Sdougm */ 9413034Sdougm xmlUnlinkNode(node); 9423034Sdougm xmlFreeNode(node); 9433034Sdougm node = NULL; 9443034Sdougm } 9453034Sdougm } else { 9463034Sdougm err = SA_NO_MEMORY; 9473034Sdougm } 9483034Sdougm if (error != NULL) 9493034Sdougm *error = err; 9503034Sdougm return (node); 9513034Sdougm } 9523034Sdougm 9533034Sdougm /* 9543034Sdougm * sa_add_share(group, sharepath, persist, *error) 9553034Sdougm * 9563034Sdougm * Add a new share object to the specified group. The share will 9573034Sdougm * have the specified sharepath and will only be constructed if 9583034Sdougm * it is a valid path to be shared. NULL is returned on error 9593034Sdougm * and a detailed error value will be returned via the error 9603034Sdougm * pointer. 9613034Sdougm */ 9623034Sdougm sa_share_t 9633034Sdougm sa_add_share(sa_group_t group, char *sharepath, int persist, int *error) 9643034Sdougm { 9653034Sdougm xmlNodePtr node = NULL; 9663034Sdougm sa_share_t dup; 9673034Sdougm 9683034Sdougm if ((dup = sa_find_share(sharepath)) == NULL && 9693034Sdougm (*error = sa_check_path(group, sharepath)) == SA_OK) { 9703034Sdougm node = _sa_add_share(group, sharepath, persist, error); 9713034Sdougm } 9723034Sdougm if (dup != NULL) 9733034Sdougm *error = SA_DUPLICATE_NAME; 9743034Sdougm 9753034Sdougm return ((sa_share_t)node); 9763034Sdougm } 9773034Sdougm 9783034Sdougm /* 9793034Sdougm * sa_enable_share(share, protocol) 9803034Sdougm * Enable the specified share to the specified protocol. 9813034Sdougm * If protocol is NULL, then all protocols. 9823034Sdougm */ 9833034Sdougm int 9843034Sdougm sa_enable_share(sa_share_t share, char *protocol) 9853034Sdougm { 9863034Sdougm char *sharepath; 9873034Sdougm struct stat st; 9883034Sdougm int err = 0; 9893034Sdougm 9903034Sdougm sharepath = sa_get_share_attr(share, "path"); 9913034Sdougm if (stat(sharepath, &st) < 0) { 9923034Sdougm err = SA_NO_SUCH_PATH; 9933034Sdougm } else { 9943034Sdougm /* tell the server about the share */ 9953034Sdougm if (protocol != NULL) { 9963034Sdougm /* lookup protocol specific handler */ 9973034Sdougm err = sa_proto_share(protocol, share); 9983034Sdougm if (err == SA_OK) 9993034Sdougm (void) sa_set_share_attr(share, "shared", "true"); 10003034Sdougm } else { 10013034Sdougm /* tell all protocols */ 10023034Sdougm err = sa_proto_share("nfs", share); /* only NFS for now */ 10033034Sdougm (void) sa_set_share_attr(share, "shared", "true"); 10043034Sdougm } 10053034Sdougm } 10063034Sdougm if (sharepath != NULL) 10073034Sdougm sa_free_attr_string(sharepath); 10083034Sdougm return (err); 10093034Sdougm } 10103034Sdougm 10113034Sdougm /* 10123034Sdougm * sa_disable_share(share, protocol) 10133034Sdougm * Disable the specified share to the specified protocol. 10143034Sdougm * If protocol is NULL, then all protocols. 10153034Sdougm */ 10163034Sdougm int 10173034Sdougm sa_disable_share(sa_share_t share, char *protocol) 10183034Sdougm { 10193034Sdougm char *path; 10203034Sdougm char *shared; 10213034Sdougm int ret = SA_OK; 10223034Sdougm 10233034Sdougm path = sa_get_share_attr(share, "path"); 10243034Sdougm shared = sa_get_share_attr(share, "shared"); 10253034Sdougm 10263034Sdougm if (protocol != NULL) { 10273034Sdougm ret = sa_proto_unshare(protocol, path); 10283034Sdougm } else { 10293034Sdougm /* need to do all protocols */ 10303034Sdougm ret = sa_proto_unshare("nfs", path); 10313034Sdougm } 10323034Sdougm if (ret == SA_OK) 10333034Sdougm (void) sa_set_share_attr(share, "shared", NULL); 10343034Sdougm if (path != NULL) 10353034Sdougm sa_free_attr_string(path); 10363034Sdougm if (shared != NULL) 10373034Sdougm sa_free_attr_string(shared); 10383034Sdougm return (ret); 10393034Sdougm } 10403034Sdougm 10413034Sdougm /* 10423034Sdougm * sa_remove_share(share) 10433034Sdougm * 10443034Sdougm * remove the specified share from its containing group. 10453034Sdougm * Remove from the SMF or ZFS configuration space. 10463034Sdougm */ 10473034Sdougm 10483034Sdougm int 10493034Sdougm sa_remove_share(sa_share_t share) 10503034Sdougm { 10513034Sdougm sa_group_t group; 10523034Sdougm int ret = SA_OK; 10533034Sdougm char *type; 10543034Sdougm int transient = 0; 10553034Sdougm char *groupname; 10563034Sdougm char *zfs; 10573034Sdougm 10583034Sdougm type = sa_get_share_attr(share, "type"); 10593034Sdougm group = sa_get_parent_group(share); 10603034Sdougm zfs = sa_get_group_attr(group, "zfs"); 10613034Sdougm groupname = sa_get_group_attr(group, "name"); 10623034Sdougm if (type != NULL && strcmp(type, "persist") != 0) 10633034Sdougm transient = 1; 10643034Sdougm if (type != NULL) 10653034Sdougm sa_free_attr_string(type); 10663034Sdougm 10673034Sdougm /* remove the node from its group then free the memory */ 10683034Sdougm 10693034Sdougm /* 10703034Sdougm * need to test if "busy" 10713034Sdougm */ 10723034Sdougm /* only do SMF action if permanent */ 10733034Sdougm if (!transient || zfs != NULL) { 10743034Sdougm /* remove from legacy dfstab as well as possible SMF */ 10753034Sdougm ret = sa_delete_legacy(share); 10763034Sdougm if (ret == SA_OK) { 10773034Sdougm if (!sa_group_is_zfs(group)) { 10783034Sdougm ret = sa_delete_share(scf_handle, group, share); 10793034Sdougm } else { 10803034Sdougm char *sharepath = sa_get_share_attr(share, "path"); 10813034Sdougm if (sharepath != NULL) { 10823034Sdougm ret = sa_zfs_set_sharenfs(group, sharepath, 0); 10833034Sdougm sa_free_attr_string(sharepath); 10843034Sdougm } 10853034Sdougm } 10863034Sdougm } 10873034Sdougm } 10883034Sdougm if (groupname != NULL) 10893034Sdougm sa_free_attr_string(groupname); 10903034Sdougm if (zfs != NULL) 10913034Sdougm sa_free_attr_string(zfs); 10923034Sdougm 10933034Sdougm xmlUnlinkNode((xmlNodePtr)share); 10943034Sdougm xmlFreeNode((xmlNodePtr)share); 10953034Sdougm return (ret); 10963034Sdougm } 10973034Sdougm 10983034Sdougm /* 10993034Sdougm * sa_move_share(group, share) 11003034Sdougm * 11013034Sdougm * move the specified share to the specified group. Update SMF 11023034Sdougm * appropriately. 11033034Sdougm */ 11043034Sdougm 11053034Sdougm int 11063034Sdougm sa_move_share(sa_group_t group, sa_share_t share) 11073034Sdougm { 11083034Sdougm sa_group_t oldgroup; 11093034Sdougm int ret = SA_OK; 11103034Sdougm 11113034Sdougm /* remove the node from its group then free the memory */ 11123034Sdougm 11133034Sdougm oldgroup = sa_get_parent_group(share); 11143034Sdougm if (oldgroup != group) { 11153034Sdougm xmlUnlinkNode((xmlNodePtr)share); 11163034Sdougm /* now that the share isn't in its old group, add to the new one */ 11173034Sdougm xmlAddChild((xmlNodePtr)group, (xmlNodePtr)share); 11183034Sdougm /* need to deal with SMF */ 11193034Sdougm if (ret == SA_OK) { 11203034Sdougm /* 11213034Sdougm * need to remove from old group first and then add to 11223034Sdougm * new group. Ideally, we would do the other order but 11233034Sdougm * need to avoid having the share in two groups at the 11243034Sdougm * same time. 11253034Sdougm */ 11263034Sdougm ret = sa_delete_share(scf_handle, oldgroup, share); 11273034Sdougm } 11283034Sdougm ret = sa_commit_share(scf_handle, group, share); 11293034Sdougm } 11303034Sdougm return (ret); 11313034Sdougm } 11323034Sdougm 11333034Sdougm /* 11343034Sdougm * sa_get_parent_group(share) 11353034Sdougm * 11363034Sdougm * Return the containg group for the share. If a group was actually 11373034Sdougm * passed in, we don't want a parent so return NULL. 11383034Sdougm */ 11393034Sdougm 11403034Sdougm sa_group_t 11413034Sdougm sa_get_parent_group(sa_share_t share) 11423034Sdougm { 11433034Sdougm xmlNodePtr node = NULL; 11443034Sdougm if (share != NULL) { 11453034Sdougm node = ((xmlNodePtr)share)->parent; 11463034Sdougm /* 11473034Sdougm * make sure parent is a group and not sharecfg since 11483034Sdougm * we may be cheating and passing in a group. 11493034Sdougm * Eventually, groups of groups might come into being. 11503034Sdougm */ 11513034Sdougm if (node == NULL || 11523034Sdougm xmlStrcmp(node->name, (xmlChar *)"sharecfg") == 0) 11533034Sdougm node = NULL; 11543034Sdougm } 11553034Sdougm return ((sa_group_t)node); 11563034Sdougm } 11573034Sdougm 11583034Sdougm /* 11593034Sdougm * _sa_create_group(groupname) 11603034Sdougm * 11613034Sdougm * Create a group in the document. The caller will need to deal with 11623034Sdougm * configuration store and activation. 11633034Sdougm */ 11643034Sdougm 11653034Sdougm sa_group_t 11663034Sdougm _sa_create_group(char *groupname) 11673034Sdougm { 11683034Sdougm xmlNodePtr node = NULL; 11693034Sdougm 11703034Sdougm if (sa_valid_group_name(groupname)) { 11713034Sdougm node = xmlNewChild(sa_config_tree, NULL, 11723034Sdougm (xmlChar *)"group", NULL); 11733034Sdougm if (node != NULL) { 11743034Sdougm xmlSetProp(node, (xmlChar *)"name", (xmlChar *)groupname); 11753034Sdougm xmlSetProp(node, (xmlChar *)"state", (xmlChar *)"enabled"); 11763034Sdougm } 11773034Sdougm } 11783034Sdougm return ((sa_group_t)node); 11793034Sdougm } 11803034Sdougm 11813034Sdougm /* 11823034Sdougm * _sa_create_zfs_group(group, groupname) 11833034Sdougm * 11843034Sdougm * Create a ZFS subgroup under the specified group. This may 11853034Sdougm * eventually form the basis of general sub-groups, but is currently 11863034Sdougm * restricted to ZFS. 11873034Sdougm */ 11883034Sdougm sa_group_t 11893034Sdougm _sa_create_zfs_group(sa_group_t group, char *groupname) 11903034Sdougm { 11913034Sdougm xmlNodePtr node = NULL; 11923034Sdougm 11933034Sdougm node = xmlNewChild((xmlNodePtr)group, NULL, 11943034Sdougm (xmlChar *)"group", NULL); 11953034Sdougm if (node != NULL) { 11963034Sdougm xmlSetProp(node, (xmlChar *)"name", (xmlChar *)groupname); 11973034Sdougm xmlSetProp(node, (xmlChar *)"state", (xmlChar *)"enabled"); 11983034Sdougm } 11993034Sdougm 12003034Sdougm return ((sa_group_t)node); 12013034Sdougm } 12023034Sdougm 12033034Sdougm /* 12043034Sdougm * sa_create_group(groupname, *error) 12053034Sdougm * 12063034Sdougm * Create a new group with groupname. Need to validate that it is a 12073034Sdougm * legal name for SMF and the construct the SMF service instance of 12083034Sdougm * svc:/network/shares/group to implement the group. All necessary 12093034Sdougm * operational properties must be added to the group at this point 12103034Sdougm * (via the SMF transaction model). 12113034Sdougm */ 12123034Sdougm sa_group_t 12133034Sdougm sa_create_group(char *groupname, int *error) 12143034Sdougm { 12153034Sdougm xmlNodePtr node = NULL; 12163034Sdougm sa_group_t group; 12173034Sdougm int ret; 12183034Sdougm char rbacstr[256]; 12193034Sdougm 12203034Sdougm ret = SA_OK; 12213034Sdougm 12223034Sdougm if (scf_handle == NULL) { 12233034Sdougm ret = SA_SYSTEM_ERR; 12243034Sdougm goto err; 12253034Sdougm } 12263034Sdougm 12273034Sdougm group = sa_get_group(groupname); 12283034Sdougm if (group != NULL) { 12293034Sdougm ret = SA_DUPLICATE_NAME; 12303034Sdougm } else { 12313034Sdougm if (sa_valid_group_name(groupname)) { 12323034Sdougm node = xmlNewChild(sa_config_tree, NULL, 12333034Sdougm (xmlChar *)"group", NULL); 12343034Sdougm if (node != NULL) { 12353034Sdougm xmlSetProp(node, (xmlChar *)"name", (xmlChar *)groupname); 12363034Sdougm /* default to the group being enabled */ 12373034Sdougm xmlSetProp(node, (xmlChar *)"state", (xmlChar *)"enabled"); 12383034Sdougm ret = sa_create_instance(scf_handle, groupname); 12393034Sdougm if (ret == SA_OK) { 12403034Sdougm ret = sa_start_transaction(scf_handle, "operation"); 12413034Sdougm } 12423034Sdougm if (ret == SA_OK) { 12433034Sdougm ret = sa_set_property(scf_handle, "state", "enabled"); 12443034Sdougm if (ret == SA_OK) { 12453034Sdougm ret = sa_end_transaction(scf_handle); 12463034Sdougm } else { 12473034Sdougm sa_abort_transaction(scf_handle); 12483034Sdougm } 12493034Sdougm } 12503034Sdougm if (ret == SA_OK) { 12513034Sdougm /* initialize the RBAC strings */ 12523034Sdougm ret = sa_start_transaction(scf_handle, "general"); 12533034Sdougm if (ret == SA_OK) { 12543034Sdougm (void) snprintf(rbacstr, sizeof (rbacstr), "%s.%s", 12553034Sdougm SA_RBAC_MANAGE, groupname); 12563034Sdougm ret = sa_set_property(scf_handle, 12573034Sdougm "action_authorization", 12583034Sdougm rbacstr); 12593034Sdougm } 12603034Sdougm if (ret == SA_OK) { 12613034Sdougm (void) snprintf(rbacstr, sizeof (rbacstr), "%s.%s", 12623034Sdougm SA_RBAC_VALUE, groupname); 12633034Sdougm ret = sa_set_property(scf_handle, 12643034Sdougm "value_authorization", 12653034Sdougm rbacstr); 12663034Sdougm } 12673034Sdougm if (ret == SA_OK) { 12683034Sdougm ret = sa_end_transaction(scf_handle); 12693034Sdougm } else { 12703034Sdougm sa_abort_transaction(scf_handle); 12713034Sdougm } 12723034Sdougm } 12733034Sdougm if (ret != SA_OK) { 12743034Sdougm /* 12753034Sdougm * Couldn't commit the group so we need to 12763034Sdougm * undo internally. 12773034Sdougm */ 12783034Sdougm xmlUnlinkNode(node); 12793034Sdougm xmlFreeNode(node); 12803034Sdougm node = NULL; 12813034Sdougm } 12823034Sdougm } else { 12833034Sdougm ret = SA_NO_MEMORY; 12843034Sdougm } 12853034Sdougm } else { 12863034Sdougm ret = SA_INVALID_NAME; 12873034Sdougm } 12883034Sdougm } 12893034Sdougm err: 12903034Sdougm if (error != NULL) 12913034Sdougm *error = ret; 12923034Sdougm return ((sa_group_t)node); 12933034Sdougm } 12943034Sdougm 12953034Sdougm /* 12963034Sdougm * sa_remove_group(group) 12973034Sdougm * 12983034Sdougm * Remove the specified group. This deletes from the SMF repository. 12993034Sdougm * All property groups and properties are removed. 13003034Sdougm */ 13013034Sdougm 13023034Sdougm int 13033034Sdougm sa_remove_group(sa_group_t group) 13043034Sdougm { 13053034Sdougm char *name; 13063034Sdougm int ret = SA_OK; 13073034Sdougm 13083034Sdougm name = sa_get_group_attr(group, "name"); 13093034Sdougm if (name != NULL) { 13103034Sdougm ret = sa_delete_instance(scf_handle, name); 13113034Sdougm sa_free_attr_string(name); 13123034Sdougm } 13133034Sdougm xmlUnlinkNode((xmlNodePtr)group); /* make sure unlinked */ 13143034Sdougm xmlFreeNode((xmlNodePtr)group); /* now it is gone */ 13153034Sdougm return (ret); 13163034Sdougm } 13173034Sdougm 13183034Sdougm /* 13193034Sdougm * sa_update_config() 13203034Sdougm * 13213034Sdougm * Used to update legacy files that need to be updated in bulk 13223034Sdougm * Currently, this is a placeholder and will go away in a future 13233034Sdougm * release. 13243034Sdougm */ 13253034Sdougm 13263034Sdougm int 13273034Sdougm sa_update_config() 13283034Sdougm { 13293034Sdougm struct stat st; 13303034Sdougm 13313034Sdougm /* 13323034Sdougm * do legacy files first so we can tell when they change. 13333034Sdougm * This will go away when we start updating individual records 13343034Sdougm * rather than the whole file. 13353034Sdougm */ 13363034Sdougm update_legacy_config(); 13373034Sdougm /* update legacy timestamp */ 13383034Sdougm if (stat(SA_LEGACY_DFSTAB, &st) >= 0) { 13393034Sdougm set_legacy_timestamp(sa_config_tree, SA_LEGACY_DFSTAB, 13403034Sdougm TSTAMP(st.st_ctim)); 13413034Sdougm } 13423034Sdougm return (SA_OK); 13433034Sdougm } 13443034Sdougm 13453034Sdougm /* 13463034Sdougm * get_node_attr(node, tag) 13473034Sdougm * 13483034Sdougm * Get the speficied tag(attribute) if it exists on the node. This is 13493034Sdougm * used internally by a number of attribute oriented functions. 13503034Sdougm */ 13513034Sdougm 13523034Sdougm static char * 13533034Sdougm get_node_attr(void *nodehdl, char *tag) 13543034Sdougm { 13553034Sdougm xmlNodePtr node = (xmlNodePtr)nodehdl; 13563034Sdougm xmlChar *name = NULL; 13573034Sdougm 13583034Sdougm if (node != NULL) { 13593034Sdougm name = xmlGetProp(node, (xmlChar *)tag); 13603034Sdougm } 13613034Sdougm return ((char *)name); 13623034Sdougm } 13633034Sdougm 13643034Sdougm /* 13653034Sdougm * get_node_attr(node, tag) 13663034Sdougm * 13673034Sdougm * Set the speficied tag(attribute) to the specified value This is 13683034Sdougm * used internally by a number of attribute oriented functions. It 13693034Sdougm * doesn't update the repository, only the internal document state. 13703034Sdougm */ 13713034Sdougm 13723034Sdougm void 13733034Sdougm set_node_attr(void *nodehdl, char *tag, char *value) 13743034Sdougm { 13753034Sdougm xmlNodePtr node = (xmlNodePtr)nodehdl; 13763034Sdougm if (node != NULL && tag != NULL) { 13773034Sdougm if (value != NULL) { 13783034Sdougm xmlSetProp(node, (xmlChar *)tag, (xmlChar *)value); 13793034Sdougm } else { 13803034Sdougm xmlUnsetProp(node, (xmlChar *)tag); 13813034Sdougm } 13823034Sdougm } 13833034Sdougm } 13843034Sdougm 13853034Sdougm /* 13863034Sdougm * sa_get_group_attr(group, tag) 13873034Sdougm * 13883034Sdougm * Get the specied attribute, if defined, for the group. 13893034Sdougm */ 13903034Sdougm 13913034Sdougm char * 13923034Sdougm sa_get_group_attr(sa_group_t group, char *tag) 13933034Sdougm { 13943034Sdougm return (get_node_attr((void *)group, tag)); 13953034Sdougm } 13963034Sdougm 13973034Sdougm /* 13983034Sdougm * sa_set_group_attr(group, tag, value) 13993034Sdougm * 14003034Sdougm * set the specified tag/attribute on the group using value as its 14013034Sdougm * value. 14023034Sdougm * 14033034Sdougm * This will result in setting the property in the SMF repository as 14043034Sdougm * well as in the internal document. 14053034Sdougm */ 14063034Sdougm 14073034Sdougm int 14083034Sdougm sa_set_group_attr(sa_group_t group, char *tag, char *value) 14093034Sdougm { 14103034Sdougm int ret; 14113034Sdougm char *groupname; 14123034Sdougm 14133034Sdougm groupname = sa_get_group_attr(group, "name"); 14143034Sdougm ret = sa_get_instance(scf_handle, groupname); 14153034Sdougm if (ret == SA_OK) { 14163034Sdougm set_node_attr((void *)group, tag, value); 14173034Sdougm ret = sa_start_transaction(scf_handle, "operation"); 14183034Sdougm if (ret == SA_OK) { 14193034Sdougm ret = sa_set_property(scf_handle, tag, value); 14203034Sdougm if (ret == SA_OK) 14213034Sdougm (void) sa_end_transaction(scf_handle); 14223034Sdougm else { 14233034Sdougm sa_abort_transaction(scf_handle); 14243034Sdougm } 14253034Sdougm } 14263034Sdougm } 14273034Sdougm if (groupname != NULL) 14283034Sdougm sa_free_attr_string(groupname); 14293034Sdougm return (ret); 14303034Sdougm } 14313034Sdougm 14323034Sdougm /* 14333034Sdougm * sa_get_share_attr(share, tag) 14343034Sdougm * 14353034Sdougm * Return the value of the tag/attribute set on the specified 14363034Sdougm * share. Returns NULL if the tag doesn't exist. 14373034Sdougm */ 14383034Sdougm 14393034Sdougm char * 14403034Sdougm sa_get_share_attr(sa_share_t share, char *tag) 14413034Sdougm { 14423034Sdougm return (get_node_attr((void *)share, tag)); 14433034Sdougm } 14443034Sdougm 14453034Sdougm /* 14463034Sdougm * sa_get_resource(group, resource) 14473034Sdougm * 14483034Sdougm * Search all the shares in the speified group for a share with a 14493034Sdougm * resource name matching the one specified. 14503034Sdougm * 14513034Sdougm * In the future, it may be advantageous to allow group to be NULL and 14523034Sdougm * search all groups but that isn't needed at present. 14533034Sdougm */ 14543034Sdougm 14553034Sdougm sa_share_t 14563034Sdougm sa_get_resource(sa_group_t group, char *resource) 14573034Sdougm { 14583034Sdougm sa_share_t share = NULL; 14593034Sdougm char *name = NULL; 14603034Sdougm 14613034Sdougm if (resource != NULL) { 14623034Sdougm for (share = sa_get_share(group, NULL); share != NULL; 14633034Sdougm share = sa_get_next_share(share)) { 14643034Sdougm name = sa_get_share_attr(share, "resource"); 14653034Sdougm if (name != NULL) { 14663034Sdougm if (strcmp(name, resource) == 0) 14673034Sdougm break; 14683034Sdougm sa_free_attr_string(name); 14693034Sdougm name = NULL; 14703034Sdougm } 14713034Sdougm } 14723034Sdougm if (name != NULL) 14733034Sdougm sa_free_attr_string(name); 14743034Sdougm } 14753034Sdougm return ((sa_share_t)share); 14763034Sdougm } 14773034Sdougm 14783034Sdougm /* 14793034Sdougm * _sa_set_share_description(share, description) 14803034Sdougm * 14813034Sdougm * Add a description tag with text contents to the specified share. 14823034Sdougm * A separate XML tag is used rather than a property. 14833034Sdougm */ 14843034Sdougm 14853034Sdougm xmlNodePtr 14863034Sdougm _sa_set_share_description(sa_share_t share, char *content) 14873034Sdougm { 14883034Sdougm xmlNodePtr node; 14893034Sdougm node = xmlNewChild((xmlNodePtr)share, 14903034Sdougm NULL, (xmlChar *)"description", NULL); 14913034Sdougm xmlNodeSetContent(node, (xmlChar *)content); 14923034Sdougm return (node); 14933034Sdougm } 14943034Sdougm 14953034Sdougm /* 14963034Sdougm * sa_set_share_attr(share, tag, value) 14973034Sdougm * 14983034Sdougm * Set the share attribute specified by tag to the specified value. In 14993034Sdougm * the case of "resource", enforce a no duplicates in a group rule. If 15003034Sdougm * the share is not transient, commit the changes to the repository 15013034Sdougm * else just update the share internally. 15023034Sdougm */ 15033034Sdougm 15043034Sdougm int 15053034Sdougm sa_set_share_attr(sa_share_t share, char *tag, char *value) 15063034Sdougm { 15073034Sdougm sa_group_t group; 15083034Sdougm sa_share_t resource; 15093034Sdougm int ret = SA_OK; 15103034Sdougm 15113034Sdougm group = sa_get_parent_group(share); 15123034Sdougm 15133034Sdougm /* 15143034Sdougm * There are some attributes that may have specific 15153034Sdougm * restrictions on them. Initially, only "resource" has 15163034Sdougm * special meaning that needs to be checked. Only one instance 15173034Sdougm * of a resource name may exist within a group. 15183034Sdougm */ 15193034Sdougm 15203034Sdougm if (strcmp(tag, "resource") == 0) { 15213034Sdougm resource = sa_get_resource(group, value); 15223034Sdougm if (resource != share && resource != NULL) 15233034Sdougm ret = SA_DUPLICATE_NAME; 15243034Sdougm } 15253034Sdougm if (ret == SA_OK) { 15263034Sdougm set_node_attr((void *)share, tag, value); 15273034Sdougm if (group != NULL) { 15283034Sdougm char *type; 15293034Sdougm /* we can probably optimize this some */ 15303034Sdougm type = sa_get_share_attr(share, "type"); 15313034Sdougm if (type == NULL || strcmp(type, "transient") != 0) 15323034Sdougm ret = sa_commit_share(scf_handle, group, share); 15333034Sdougm if (type != NULL) 15343034Sdougm sa_free_attr_string(type); 15353034Sdougm } 15363034Sdougm } 15373034Sdougm return (ret); 15383034Sdougm } 15393034Sdougm 15403034Sdougm /* 15413034Sdougm * sa_get_property_attr(prop, tag) 15423034Sdougm * 15433034Sdougm * Get the value of the specified property attribute. Standard 15443034Sdougm * attributes are "type" and "value". 15453034Sdougm */ 15463034Sdougm 15473034Sdougm char * 15483034Sdougm sa_get_property_attr(sa_property_t prop, char *tag) 15493034Sdougm { 15503034Sdougm return (get_node_attr((void *)prop, tag)); 15513034Sdougm } 15523034Sdougm 15533034Sdougm /* 15543034Sdougm * sa_get_optionset_attr(prop, tag) 15553034Sdougm * 15563034Sdougm * Get the value of the specified property attribute. Standard 15573034Sdougm * attribute is "type". 15583034Sdougm */ 15593034Sdougm 15603034Sdougm char * 15613034Sdougm sa_get_optionset_attr(sa_property_t optionset, char *tag) 15623034Sdougm { 15633034Sdougm return (get_node_attr((void *)optionset, tag)); 15643034Sdougm 15653034Sdougm } 15663034Sdougm 15673034Sdougm /* 15683034Sdougm * sa_set_optionset_attr(optionset, tag, value) 15693034Sdougm * 15703034Sdougm * Set the specified attribute(tag) to the specified value on the 15713034Sdougm * optionset. 15723034Sdougm */ 15733034Sdougm 15743034Sdougm void 15753034Sdougm sa_set_optionset_attr(sa_group_t optionset, char *tag, char *value) 15763034Sdougm { 15773034Sdougm set_node_attr((void *)optionset, tag, value); 15783034Sdougm } 15793034Sdougm 15803034Sdougm /* 15813034Sdougm * sa_free_attr_string(string) 15823034Sdougm * 15833034Sdougm * Free the string that was returned in one of the sa_get_*_attr() 15843034Sdougm * functions. 15853034Sdougm */ 15863034Sdougm 15873034Sdougm void 15883034Sdougm sa_free_attr_string(char *string) 15893034Sdougm { 15903034Sdougm xmlFree((xmlChar *)string); 15913034Sdougm } 15923034Sdougm 15933034Sdougm /* 15943034Sdougm * sa_get_optionset(group, proto) 15953034Sdougm * 15963034Sdougm * Return the optionset, if it exists, that is associated with the 15973034Sdougm * specified protocol. 15983034Sdougm */ 15993034Sdougm 16003034Sdougm sa_optionset_t 16013034Sdougm sa_get_optionset(void *group, char *proto) 16023034Sdougm { 16033034Sdougm xmlNodePtr node; 16043034Sdougm xmlChar *value = NULL; 16053034Sdougm 16063034Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 16073034Sdougm node = node->next) { 16083034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) { 16093034Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 16103034Sdougm if (proto != NULL) { 16113034Sdougm if (value != NULL && 16123034Sdougm xmlStrcmp(value, (xmlChar *)proto) == 0) { 16133034Sdougm break; 16143034Sdougm } 16153034Sdougm if (value != NULL) { 16163034Sdougm xmlFree(value); 16173034Sdougm value = NULL; 16183034Sdougm } 16193034Sdougm } else { 16203034Sdougm break; 16213034Sdougm } 16223034Sdougm } 16233034Sdougm } 16243034Sdougm if (value != NULL) 16253034Sdougm xmlFree(value); 16263034Sdougm return ((sa_optionset_t)node); 16273034Sdougm } 16283034Sdougm 16293034Sdougm /* 16303034Sdougm * sa_get_next_optionset(optionset) 16313034Sdougm * 16323034Sdougm * Return the next optionset in the group. NULL if this was the last. 16333034Sdougm */ 16343034Sdougm 16353034Sdougm sa_optionset_t 16363034Sdougm sa_get_next_optionset(sa_optionset_t optionset) 16373034Sdougm { 16383034Sdougm xmlNodePtr node; 16393034Sdougm 16403034Sdougm for (node = ((xmlNodePtr)optionset)->next; node != NULL; 16413034Sdougm node = node->next) { 16423034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) { 16433034Sdougm break; 16443034Sdougm } 16453034Sdougm } 16463034Sdougm return ((sa_optionset_t)node); 16473034Sdougm } 16483034Sdougm 16493034Sdougm /* 16503034Sdougm * sa_get_security(group, sectype, proto) 16513034Sdougm * 16523034Sdougm * Return the security optionset. The internal name is a hold over 16533034Sdougm * from the implementation and will be changed before the API is 16543034Sdougm * finalized. This is really a named optionset that can be negotiated 16553034Sdougm * as a group of properties (like NFS security options). 16563034Sdougm */ 16573034Sdougm 16583034Sdougm sa_security_t 16593034Sdougm sa_get_security(sa_group_t group, char *sectype, char *proto) 16603034Sdougm { 16613034Sdougm xmlNodePtr node; 16623034Sdougm xmlChar *value = NULL; 16633034Sdougm 16643034Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 16653034Sdougm node = node->next) { 16663034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) { 16673034Sdougm if (proto != NULL) { 16683034Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 16693034Sdougm if (value == NULL || 16703034Sdougm (value != NULL && 16713034Sdougm xmlStrcmp(value, (xmlChar *)proto) != 0)) { 16723034Sdougm /* it doesn't match so continue */ 16733034Sdougm xmlFree(value); 16743034Sdougm value = NULL; 16753034Sdougm continue; 16763034Sdougm } 16773034Sdougm } 16783034Sdougm if (value != NULL) { 16793034Sdougm xmlFree(value); 16803034Sdougm value = NULL; 16813034Sdougm } 16823034Sdougm /* potential match */ 16833034Sdougm if (sectype != NULL) { 16843034Sdougm value = xmlGetProp(node, (xmlChar *)"sectype"); 16853034Sdougm if (value != NULL && 16863034Sdougm xmlStrcmp(value, (xmlChar *)sectype) == 0) { 16873034Sdougm break; 16883034Sdougm } 16893034Sdougm } else { 16903034Sdougm break; 16913034Sdougm } 16923034Sdougm } 16933034Sdougm if (value != NULL) { 16943034Sdougm xmlFree(value); 16953034Sdougm value = NULL; 16963034Sdougm } 16973034Sdougm } 16983034Sdougm if (value != NULL) 16993034Sdougm xmlFree(value); 17003034Sdougm return ((sa_security_t)node); 17013034Sdougm } 17023034Sdougm 17033034Sdougm /* 17043034Sdougm * sa_get_next_security(security) 17053034Sdougm * 17063034Sdougm * Get the next security optionset if one exists. 17073034Sdougm */ 17083034Sdougm 17093034Sdougm sa_security_t 17103034Sdougm sa_get_next_security(sa_security_t security) 17113034Sdougm { 17123034Sdougm xmlNodePtr node; 17133034Sdougm 17143034Sdougm for (node = ((xmlNodePtr)security)->next; node != NULL; 17153034Sdougm node = node->next) { 17163034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) { 17173034Sdougm break; 17183034Sdougm } 17193034Sdougm } 17203034Sdougm return ((sa_security_t)node); 17213034Sdougm } 17223034Sdougm 17233034Sdougm /* 17243034Sdougm * sa_get_property(optionset, prop) 17253034Sdougm * 17263034Sdougm * Get the property object with the name specified in prop from the 17273034Sdougm * optionset. 17283034Sdougm */ 17293034Sdougm 17303034Sdougm sa_property_t 17313034Sdougm sa_get_property(sa_optionset_t optionset, char *prop) 17323034Sdougm { 17333034Sdougm xmlNodePtr node = (xmlNodePtr)optionset; 17343034Sdougm xmlChar *value = NULL; 17353034Sdougm 17363034Sdougm if (optionset == NULL) 17373034Sdougm return (NULL); 17383034Sdougm 17393034Sdougm for (node = node->children; node != NULL; 17403034Sdougm node = node->next) { 17413034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 17423034Sdougm if (prop == NULL) 17433034Sdougm break; 17443034Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 17453034Sdougm if (value != NULL && xmlStrcmp(value, (xmlChar *)prop) == 0) { 17463034Sdougm break; 17473034Sdougm } 17483034Sdougm if (value != NULL) { 17493034Sdougm xmlFree(value); 17503034Sdougm value = NULL; 17513034Sdougm } 17523034Sdougm } 17533034Sdougm } 17543034Sdougm if (value != NULL) 17553034Sdougm xmlFree(value); 17563034Sdougm if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"option") != 0) { 17573034Sdougm /* avoid a non option node -- it is possible to be a text node */ 17583034Sdougm node = NULL; 17593034Sdougm } 17603034Sdougm return ((sa_property_t)node); 17613034Sdougm } 17623034Sdougm 17633034Sdougm /* 17643034Sdougm * sa_get_next_property(property) 17653034Sdougm * 17663034Sdougm * Get the next property following the specified property. NULL if 17673034Sdougm * this was the last. 17683034Sdougm */ 17693034Sdougm 17703034Sdougm sa_property_t 17713034Sdougm sa_get_next_property(sa_property_t property) 17723034Sdougm { 17733034Sdougm xmlNodePtr node; 17743034Sdougm 17753034Sdougm for (node = ((xmlNodePtr)property)->next; node != NULL; 17763034Sdougm node = node->next) { 17773034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 17783034Sdougm break; 17793034Sdougm } 17803034Sdougm } 17813034Sdougm return ((sa_property_t)node); 17823034Sdougm } 17833034Sdougm 17843034Sdougm /* 17853034Sdougm * sa_set_share_description(share, content) 17863034Sdougm * 17873034Sdougm * Set the description of share to content. 17883034Sdougm */ 17893034Sdougm 17903034Sdougm int 17913034Sdougm sa_set_share_description(sa_share_t share, char *content) 17923034Sdougm { 17933034Sdougm xmlNodePtr node; 17943034Sdougm sa_group_t group; 17953034Sdougm int ret = SA_OK; 17963034Sdougm 17973034Sdougm for (node = ((xmlNodePtr)share)->children; node != NULL; 17983034Sdougm node = node->next) { 17993034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 18003034Sdougm break; 18013034Sdougm } 18023034Sdougm } 18033034Sdougm group = sa_get_parent_group(share); 18043034Sdougm /* no existing description but want to add */ 18053034Sdougm if (node == NULL && content != NULL) { 18063034Sdougm /* add a description */ 18073034Sdougm node = _sa_set_share_description(share, content); 18083034Sdougm } else if (node != NULL && content != NULL) { 18093034Sdougm /* update a description */ 18103034Sdougm xmlNodeSetContent(node, (xmlChar *)content); 18113034Sdougm } else if (node != NULL && content == NULL) { 18123034Sdougm /* remove an existing description */ 18133034Sdougm xmlUnlinkNode(node); 18143034Sdougm xmlFreeNode(node); 18153034Sdougm } 18163034Sdougm if (group != NULL && is_persistent((sa_group_t)share)) 18173034Sdougm ret = sa_commit_share(scf_handle, group, share); 18183034Sdougm return (ret); 18193034Sdougm } 18203034Sdougm 18213034Sdougm /* 18223034Sdougm * fixproblemchars(string) 18233034Sdougm * 18243034Sdougm * don't want any newline or tab characters in the text since these 18253034Sdougm * could break display of data and legacy file formats. 18263034Sdougm */ 18273034Sdougm static void 18283034Sdougm fixproblemchars(char *str) 18293034Sdougm { 18303034Sdougm int c; 18313034Sdougm for (c = *str; c != '\0'; c = *++str) { 18323034Sdougm if (c == '\t' || c == '\n') 18333034Sdougm *str = ' '; 18343034Sdougm else if (c == '"') 18353034Sdougm *str = '\''; 18363034Sdougm } 18373034Sdougm } 18383034Sdougm 18393034Sdougm /* 18403034Sdougm * sa_get_share_description(share) 18413034Sdougm * 18423034Sdougm * Return the description text for the specified share if it 18433034Sdougm * exists. NULL if no description exists. 18443034Sdougm */ 18453034Sdougm 18463034Sdougm char * 18473034Sdougm sa_get_share_description(sa_share_t share) 18483034Sdougm { 18493034Sdougm xmlChar *description = NULL; 18503034Sdougm xmlNodePtr node; 18513034Sdougm 18523034Sdougm for (node = ((xmlNodePtr)share)->children; node != NULL; 18533034Sdougm node = node->next) { 18543034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 18553034Sdougm break; 18563034Sdougm } 18573034Sdougm } 18583034Sdougm if (node != NULL) { 18593034Sdougm description = xmlNodeGetContent((xmlNodePtr)share); 18603034Sdougm fixproblemchars((char *)description); 18613034Sdougm } 18623034Sdougm return ((char *)description); 18633034Sdougm } 18643034Sdougm 18653034Sdougm /* 18663034Sdougm * sa_free(share_description(description) 18673034Sdougm * 18683034Sdougm * Free the description string. 18693034Sdougm */ 18703034Sdougm 18713034Sdougm void 18723034Sdougm sa_free_share_description(char *description) 18733034Sdougm { 18743034Sdougm xmlFree((xmlChar *)description); 18753034Sdougm } 18763034Sdougm 18773034Sdougm /* 18783034Sdougm * sa_create_optionset(group, proto) 18793034Sdougm * 18803034Sdougm * Create an optionset for the specified protocol in the specied 18813034Sdougm * group. This is manifested as a property group within SMF. 18823034Sdougm */ 18833034Sdougm 18843034Sdougm sa_optionset_t 18853034Sdougm sa_create_optionset(sa_group_t group, char *proto) 18863034Sdougm { 18873034Sdougm sa_optionset_t optionset; 18883034Sdougm sa_group_t parent = group; 18893034Sdougm 18903034Sdougm optionset = sa_get_optionset(group, proto); 18913034Sdougm if (optionset != NULL) { 18923034Sdougm /* can't have a duplicate protocol */ 18933034Sdougm optionset = NULL; 18943034Sdougm } else { 18953034Sdougm optionset = (sa_optionset_t)xmlNewChild((xmlNodePtr)group, 18963034Sdougm NULL, 18973034Sdougm (xmlChar *)"optionset", 18983034Sdougm NULL); 18993034Sdougm /* 19003034Sdougm * only put to repository if on a group and we were 19013034Sdougm * able to create an optionset. 19023034Sdougm */ 19033034Sdougm if (optionset != NULL) { 19043034Sdougm char oname[256]; 19053034Sdougm char *groupname; 19063034Sdougm char *id = NULL; 19073034Sdougm 19083034Sdougm if (sa_is_share(group)) 19093034Sdougm parent = sa_get_parent_group((sa_share_t)group); 19103034Sdougm 19113034Sdougm sa_set_optionset_attr(optionset, "type", proto); 19123034Sdougm 19133034Sdougm if (sa_is_share(group)) { 19143034Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 19153034Sdougm } 19163034Sdougm (void) sa_optionset_name(optionset, oname, 19173034Sdougm sizeof (oname), id); 19183034Sdougm groupname = sa_get_group_attr(parent, "name"); 19193034Sdougm if (groupname != NULL && is_persistent(group)) { 19203034Sdougm (void) sa_get_instance(scf_handle, groupname); 19213034Sdougm sa_free_attr_string(groupname); 19223034Sdougm (void) sa_create_pgroup(scf_handle, oname); 19233034Sdougm } 19243034Sdougm if (id != NULL) 19253034Sdougm sa_free_attr_string(id); 19263034Sdougm } 19273034Sdougm } 19283034Sdougm return (optionset); 19293034Sdougm } 19303034Sdougm 19313034Sdougm /* 19323034Sdougm * sa_get_property_parent(property) 19333034Sdougm * 19343034Sdougm * Given a property, return the object it is a property of. This will 19353034Sdougm * be an optionset of some type. 19363034Sdougm */ 19373034Sdougm 19383034Sdougm static sa_optionset_t 19393034Sdougm sa_get_property_parent(sa_property_t property) 19403034Sdougm { 19413034Sdougm xmlNodePtr node = NULL; 19423034Sdougm 19433034Sdougm if (property != NULL) { 19443034Sdougm node = ((xmlNodePtr)property)->parent; 19453034Sdougm } 19463034Sdougm return ((sa_optionset_t)node); 19473034Sdougm } 19483034Sdougm 19493034Sdougm /* 19503034Sdougm * sa_get_optionset_parent(optionset) 19513034Sdougm * 19523034Sdougm * Return the parent of the specified optionset. This could be a group 19533034Sdougm * or a share. 19543034Sdougm */ 19553034Sdougm 19563034Sdougm static sa_group_t 19573034Sdougm sa_get_optionset_parent(sa_optionset_t optionset) 19583034Sdougm { 19593034Sdougm xmlNodePtr node = NULL; 19603034Sdougm 19613034Sdougm if (optionset != NULL) { 19623034Sdougm node = ((xmlNodePtr)optionset)->parent; 19633034Sdougm } 19643034Sdougm return ((sa_group_t)node); 19653034Sdougm } 19663034Sdougm 19673034Sdougm /* 19683034Sdougm * zfs_needs_update(share) 19693034Sdougm * 19703034Sdougm * In order to avoid making multiple updates to a ZFS share when 19713034Sdougm * setting properties, the share attribute "changed" will be set to 19723034Sdougm * true when a property is added or modifed. When done adding 19733034Sdougm * properties, we can then detect that an update is needed. We then 19743034Sdougm * clear the state here to detect additional changes. 19753034Sdougm */ 19763034Sdougm 19773034Sdougm static int 19783034Sdougm zfs_needs_update(sa_share_t share) 19793034Sdougm { 19803034Sdougm char *attr; 19813034Sdougm int result = 0; 19823034Sdougm 19833034Sdougm attr = sa_get_share_attr(share, "changed"); 19843034Sdougm if (attr != NULL) { 19853034Sdougm sa_free_attr_string(attr); 19863034Sdougm result = 1; 19873034Sdougm } 19883034Sdougm set_node_attr((void *)share, "changed", NULL); 19893034Sdougm return (result); 19903034Sdougm } 19913034Sdougm 19923034Sdougm /* 19933034Sdougm * zfs_set_update(share) 19943034Sdougm * 19953034Sdougm * Set the changed attribute of the share to true. 19963034Sdougm */ 19973034Sdougm 19983034Sdougm static void 19993034Sdougm zfs_set_update(sa_share_t share) 20003034Sdougm { 20013034Sdougm set_node_attr((void *)share, "changed", "true"); 20023034Sdougm } 20033034Sdougm 20043034Sdougm /* 20053034Sdougm * sa_commit_properties(optionset, clear) 20063034Sdougm * 20073034Sdougm * Check if SMF or ZFS config and either update or abort the pending 20083034Sdougm * changes. 20093034Sdougm */ 20103034Sdougm 20113034Sdougm int 20123034Sdougm sa_commit_properties(sa_optionset_t optionset, int clear) 20133034Sdougm { 20143034Sdougm sa_group_t group; 20153034Sdougm sa_group_t parent; 20163034Sdougm int zfs = 0; 20173034Sdougm int needsupdate = 0; 20183034Sdougm int ret = SA_OK; 20193034Sdougm 20203034Sdougm group = sa_get_optionset_parent(optionset); 20213034Sdougm if (group != NULL && (sa_is_share(group) || is_zfs_group(group))) { 20223034Sdougm /* only update ZFS if on a share */ 20233034Sdougm parent = sa_get_parent_group(group); 20243034Sdougm zfs++; 20253034Sdougm if (parent != NULL && is_zfs_group(parent)) { 20263034Sdougm needsupdate = zfs_needs_update(group); 20273034Sdougm } else { 20283034Sdougm zfs = 0; 20293034Sdougm } 20303034Sdougm } 20313034Sdougm if (zfs) { 20323034Sdougm if (!clear && needsupdate) 20333034Sdougm ret = sa_zfs_update((sa_share_t)group); 20343034Sdougm } else { 20353034Sdougm if (clear) 20363034Sdougm (void) sa_abort_transaction(scf_handle); 20373034Sdougm else 20383034Sdougm ret = sa_end_transaction(scf_handle); 20393034Sdougm } 20403034Sdougm return (ret); 20413034Sdougm } 20423034Sdougm 20433034Sdougm /* 20443034Sdougm * sa_destroy_optionset(optionset) 20453034Sdougm * 20463034Sdougm * Remove the optionset from its group. Update the repostory to 20473034Sdougm * reflect this change. 20483034Sdougm */ 20493034Sdougm 20503034Sdougm int 20513034Sdougm sa_destroy_optionset(sa_optionset_t optionset) 20523034Sdougm { 20533034Sdougm char name[256]; 20543034Sdougm int len; 20553034Sdougm int ret; 20563034Sdougm char *id = NULL; 20573034Sdougm sa_group_t group; 20583034Sdougm int ispersist = 1; 20593034Sdougm 20603034Sdougm /* now delete the prop group */ 20613034Sdougm group = sa_get_optionset_parent(optionset); 20623034Sdougm if (group != NULL && sa_is_share(group)) { 20633034Sdougm ispersist = is_persistent(group); 20643034Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 20653034Sdougm } 20663034Sdougm if (ispersist) { 20673034Sdougm len = sa_optionset_name(optionset, name, sizeof (name), id); 20683034Sdougm if (len > 0) { 20693034Sdougm ret = sa_delete_pgroup(scf_handle, name); 20703034Sdougm } 20713034Sdougm } 20723034Sdougm xmlUnlinkNode((xmlNodePtr)optionset); 20733034Sdougm xmlFreeNode((xmlNodePtr)optionset); 20743034Sdougm if (id != NULL) 20753034Sdougm sa_free_attr_string(id); 20763034Sdougm return (ret); 20773034Sdougm } 20783034Sdougm 20793034Sdougm /* private to the implementation */ 20803034Sdougm int 20813034Sdougm _sa_remove_optionset(sa_optionset_t optionset) 20823034Sdougm { 20833034Sdougm int ret = SA_OK; 20843034Sdougm 20853034Sdougm xmlUnlinkNode((xmlNodePtr)optionset); 20863034Sdougm xmlFreeNode((xmlNodePtr)optionset); 20873034Sdougm return (ret); 20883034Sdougm } 20893034Sdougm 20903034Sdougm /* 20913034Sdougm * sa_create_security(group, sectype, proto) 20923034Sdougm * 20933034Sdougm * Create a security optionset (one that has a type name and a 20943034Sdougm * proto). Security is left over from a pure NFS implementation. The 20953034Sdougm * naming will change in the future when the API is released. 20963034Sdougm */ 20973034Sdougm sa_security_t 20983034Sdougm sa_create_security(sa_group_t group, char *sectype, char *proto) 20993034Sdougm { 21003034Sdougm sa_security_t security; 21013034Sdougm char *id = NULL; 21023034Sdougm sa_group_t parent; 21033034Sdougm char *groupname = NULL; 21043034Sdougm 21053034Sdougm if (group != NULL && sa_is_share(group)) { 21063034Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 21073034Sdougm parent = sa_get_parent_group(group); 21083034Sdougm if (parent != NULL) 21093034Sdougm groupname = sa_get_group_attr(parent, "name"); 21103034Sdougm } else if (group != NULL) { 21113034Sdougm groupname = sa_get_group_attr(group, "name"); 21123034Sdougm } 21133034Sdougm 21143034Sdougm security = sa_get_security(group, sectype, proto); 21153034Sdougm if (security != NULL) { 21163034Sdougm /* can't have a duplicate security option */ 21173034Sdougm security = NULL; 21183034Sdougm } else { 21193034Sdougm security = (sa_security_t)xmlNewChild((xmlNodePtr)group, 21203034Sdougm NULL, 21213034Sdougm (xmlChar *)"security", 21223034Sdougm NULL); 21233034Sdougm if (security != NULL) { 21243034Sdougm char oname[256]; 21253034Sdougm sa_set_security_attr(security, "type", proto); 21263034Sdougm 21273034Sdougm sa_set_security_attr(security, "sectype", sectype); 21283034Sdougm (void) sa_security_name(security, oname, 21293034Sdougm sizeof (oname), id); 21303034Sdougm if (groupname != NULL && is_persistent(group)) { 21313034Sdougm (void) sa_get_instance(scf_handle, groupname); 21323034Sdougm (void) sa_create_pgroup(scf_handle, oname); 21333034Sdougm } 21343034Sdougm } 21353034Sdougm } 21363034Sdougm if (groupname != NULL) 21373034Sdougm sa_free_attr_string(groupname); 21383034Sdougm return (security); 21393034Sdougm } 21403034Sdougm 21413034Sdougm /* 21423034Sdougm * sa_destroy_security(security) 21433034Sdougm * 21443034Sdougm * Remove the specified optionset from the document and the 21453034Sdougm * configuration. 21463034Sdougm */ 21473034Sdougm 21483034Sdougm int 21493034Sdougm sa_destroy_security(sa_security_t security) 21503034Sdougm { 21513034Sdougm char name[256]; 21523034Sdougm int len; 21533034Sdougm int ret = SA_OK; 21543034Sdougm char *id = NULL; 21553034Sdougm sa_group_t group; 21563034Sdougm int iszfs = 0; 21573034Sdougm int ispersist = 1; 21583034Sdougm 21593034Sdougm group = sa_get_optionset_parent(security); 21603034Sdougm 21613034Sdougm if (group != NULL) 21623034Sdougm iszfs = sa_group_is_zfs(group); 21633034Sdougm 21643034Sdougm if (group != NULL && !iszfs) { 21653034Sdougm if (sa_is_share(group)) 21663034Sdougm ispersist = is_persistent(group); 21673034Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 21683034Sdougm } 21693034Sdougm if (ispersist) { 21703034Sdougm len = sa_security_name(security, name, sizeof (name), id); 21713034Sdougm if (!iszfs && len > 0) { 21723034Sdougm ret = sa_delete_pgroup(scf_handle, name); 21733034Sdougm } 21743034Sdougm } 21753034Sdougm xmlUnlinkNode((xmlNodePtr)security); 21763034Sdougm xmlFreeNode((xmlNodePtr)security); 21773034Sdougm if (iszfs) { 21783034Sdougm ret = sa_zfs_update(group); 21793034Sdougm } 21803034Sdougm if (id != NULL) 21813034Sdougm sa_free_attr_string(id); 21823034Sdougm return (ret); 21833034Sdougm } 21843034Sdougm 21853034Sdougm /* 21863034Sdougm * sa_get_security_attr(optionset, tag) 21873034Sdougm * 21883034Sdougm * Return the specified attribute value from the optionset. 21893034Sdougm */ 21903034Sdougm 21913034Sdougm char * 21923034Sdougm sa_get_security_attr(sa_property_t optionset, char *tag) 21933034Sdougm { 21943034Sdougm return (get_node_attr((void *)optionset, tag)); 21953034Sdougm 21963034Sdougm } 21973034Sdougm 21983034Sdougm /* 21993034Sdougm * sa_set_security_attr(optionset, tag, value) 22003034Sdougm * 22013034Sdougm * Set the optioset attribute specied by tag to the specified value. 22023034Sdougm */ 22033034Sdougm 22043034Sdougm void 22053034Sdougm sa_set_security_attr(sa_group_t optionset, char *tag, char *value) 22063034Sdougm { 22073034Sdougm set_node_attr((void *)optionset, tag, value); 22083034Sdougm } 22093034Sdougm 22103034Sdougm /* 22113034Sdougm * is_nodetype(node, type) 22123034Sdougm * 22133034Sdougm * Check to see if node is of the type specified. 22143034Sdougm */ 22153034Sdougm 22163034Sdougm static int 22173034Sdougm is_nodetype(void *node, char *type) 22183034Sdougm { 22193034Sdougm return (strcmp((char *)((xmlNodePtr)node)->name, type) == 0); 22203034Sdougm } 22213034Sdougm 22223034Sdougm /* 22233034Sdougm * sa_set_prop_by_prop(optionset, group, prop, type) 22243034Sdougm * 22253034Sdougm * Add/remove/update the specified property prop into the optionset or 22263034Sdougm * share. If a share, sort out which property group based on GUID. In 22273034Sdougm * all cases, the appropriate transaction is set (or ZFS share is 22283034Sdougm * marked as needing an update) 22293034Sdougm */ 22303034Sdougm 22313034Sdougm #define SA_PROP_OP_REMOVE 1 22323034Sdougm #define SA_PROP_OP_ADD 2 22333034Sdougm #define SA_PROP_OP_UPDATE 3 22343034Sdougm static int 22353034Sdougm sa_set_prop_by_prop(sa_optionset_t optionset, sa_group_t group, 22363034Sdougm sa_property_t prop, int type) 22373034Sdougm { 22383034Sdougm char *name; 22393034Sdougm char *valstr; 22403034Sdougm int ret = SA_OK; 22413034Sdougm scf_transaction_entry_t *entry; 22423034Sdougm scf_value_t *value; 22433034Sdougm int opttype; /* 1 == optionset, 0 == security */ 22443034Sdougm char *id = NULL; 22453034Sdougm int iszfs = 0; 22463034Sdougm int isshare = 0; 22473034Sdougm sa_group_t parent = NULL; 22483034Sdougm 22493034Sdougm if (!is_persistent(group)) { 22503034Sdougm /* 22513034Sdougm * if the group/share is not persistent we don't need 22523034Sdougm * to do anything here 22533034Sdougm */ 22543034Sdougm return (SA_OK); 22553034Sdougm } 22563034Sdougm name = sa_get_property_attr(prop, "type"); 22573034Sdougm valstr = sa_get_property_attr(prop, "value"); 22583034Sdougm entry = scf_entry_create(scf_handle->handle); 22593034Sdougm opttype = is_nodetype((void *)optionset, "optionset"); 22603034Sdougm 22613034Sdougm if (valstr != NULL && entry != NULL) { 22623034Sdougm if (sa_is_share(group)) { 22633034Sdougm isshare = 1; 22643034Sdougm parent = sa_get_parent_group(group); 22653034Sdougm if (parent != NULL) { 22663034Sdougm iszfs = is_zfs_group(parent); 22673034Sdougm } 22683034Sdougm } else { 22693034Sdougm iszfs = is_zfs_group(group); 22703034Sdougm } 22713034Sdougm if (!iszfs) { 22723034Sdougm if (scf_handle->trans == NULL) { 22733034Sdougm char oname[256]; 22743034Sdougm char *groupname = NULL; 22753034Sdougm if (isshare) { 22763034Sdougm if (parent != NULL) { 22773034Sdougm groupname = sa_get_group_attr(parent, "name"); 22783034Sdougm } 22793034Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 22803034Sdougm } else { 22813034Sdougm groupname = sa_get_group_attr(group, "name"); 22823034Sdougm } 22833034Sdougm if (groupname != NULL) { 22843034Sdougm ret = sa_get_instance(scf_handle, groupname); 22853034Sdougm sa_free_attr_string(groupname); 22863034Sdougm } 22873034Sdougm if (opttype) 22883034Sdougm (void) sa_optionset_name(optionset, oname, 22893034Sdougm sizeof (oname), id); 22903034Sdougm else 22913034Sdougm (void) sa_security_name(optionset, oname, 22923034Sdougm sizeof (oname), id); 22933034Sdougm ret = sa_start_transaction(scf_handle, oname); 22943034Sdougm } 22953034Sdougm if (ret == SA_OK) { 22963034Sdougm switch (type) { 22973034Sdougm case SA_PROP_OP_REMOVE: 22983034Sdougm ret = scf_transaction_property_delete(scf_handle->trans, 22993034Sdougm entry, 23003034Sdougm name); 23013034Sdougm break; 23023034Sdougm case SA_PROP_OP_ADD: 23033034Sdougm case SA_PROP_OP_UPDATE: 23043034Sdougm value = scf_value_create(scf_handle->handle); 23053034Sdougm if (value != NULL) { 23063034Sdougm if (type == SA_PROP_OP_ADD) 23073034Sdougm ret = scf_transaction_property_new( 23083034Sdougm scf_handle->trans, 23093034Sdougm entry, 23103034Sdougm name, 23113034Sdougm SCF_TYPE_ASTRING); 23123034Sdougm else 23133034Sdougm ret = scf_transaction_property_change( 23143034Sdougm scf_handle->trans, 23153034Sdougm entry, 23163034Sdougm name, 23173034Sdougm SCF_TYPE_ASTRING); 23183034Sdougm if (ret == 0) { 23193034Sdougm ret = scf_value_set_astring(value, valstr); 23203034Sdougm if (ret == 0) 23213034Sdougm ret = scf_entry_add_value(entry, value); 23223034Sdougm if (ret != 0) { 23233034Sdougm scf_value_destroy(value); 23243034Sdougm ret = SA_SYSTEM_ERR; 23253034Sdougm } 23263034Sdougm } else { 23273034Sdougm scf_entry_destroy(entry); 23283034Sdougm ret = SA_SYSTEM_ERR; 23293034Sdougm } 23303034Sdougm break; 23313034Sdougm } 23323034Sdougm } 23333034Sdougm } 23343034Sdougm } else { 23353034Sdougm /* 23363034Sdougm * ZFS update. The calling function would have updated 23373034Sdougm * the internal XML structure. Just need to flag it as 23383034Sdougm * changed for ZFS. 23393034Sdougm */ 23403034Sdougm zfs_set_update((sa_share_t)group); 23413034Sdougm } 23423034Sdougm } 23433034Sdougm 23443034Sdougm if (name != NULL) 23453034Sdougm sa_free_attr_string(name); 23463034Sdougm if (valstr != NULL) 23473034Sdougm sa_free_attr_string(valstr); 23483034Sdougm else if (entry != NULL) 23493034Sdougm scf_entry_destroy(entry); 23503034Sdougm 23513034Sdougm if (ret == -1) 23523034Sdougm ret = SA_SYSTEM_ERR; 23533034Sdougm 23543034Sdougm return (ret); 23553034Sdougm } 23563034Sdougm 23573034Sdougm /* 23583034Sdougm * sa_create_property(name, value) 23593034Sdougm * 23603034Sdougm * Create a new property with the specified name and value. 23613034Sdougm */ 23623034Sdougm 23633034Sdougm sa_property_t 23643034Sdougm sa_create_property(char *name, char *value) 23653034Sdougm { 23663034Sdougm xmlNodePtr node; 23673034Sdougm 23683034Sdougm node = xmlNewNode(NULL, (xmlChar *)"option"); 23693034Sdougm if (node != NULL) { 23703034Sdougm xmlSetProp(node, (xmlChar *)"type", (xmlChar *)name); 23713034Sdougm xmlSetProp(node, (xmlChar *)"value", (xmlChar *)value); 23723034Sdougm } 23733034Sdougm return ((sa_property_t)node); 23743034Sdougm } 23753034Sdougm 23763034Sdougm /* 23773034Sdougm * sa_add_property(object, property) 23783034Sdougm * 23793034Sdougm * Add the specified property to the object. Issue the appropriate 23803034Sdougm * transaction or mark a ZFS object as needing an update. 23813034Sdougm */ 23823034Sdougm 23833034Sdougm int 23843034Sdougm sa_add_property(void *object, sa_property_t property) 23853034Sdougm { 23863034Sdougm int ret = SA_OK; 23873034Sdougm sa_group_t parent; 23883034Sdougm sa_group_t group; 23893034Sdougm char *proto; 23903034Sdougm 23913034Sdougm proto = sa_get_optionset_attr(object, "type"); 23923034Sdougm if (property != NULL) { 23933034Sdougm if ((ret = sa_valid_property(object, proto, property)) == SA_OK) { 23943034Sdougm property = (sa_property_t)xmlAddChild((xmlNodePtr)object, 23953034Sdougm (xmlNodePtr)property); 23963034Sdougm } else { 23973034Sdougm if (proto != NULL) 23983034Sdougm sa_free_attr_string(proto); 23993034Sdougm return (ret); 24003034Sdougm } 24013034Sdougm } 24023034Sdougm 24033034Sdougm if (proto != NULL) 24043034Sdougm sa_free_attr_string(proto); 24053034Sdougm 24063034Sdougm parent = sa_get_parent_group(object); 24073034Sdougm if (!is_persistent(parent)) { 24083034Sdougm return (ret); 24093034Sdougm } 24103034Sdougm 24113034Sdougm if (sa_is_share(parent)) 24123034Sdougm group = sa_get_parent_group(parent); 24133034Sdougm else 24143034Sdougm group = parent; 24153034Sdougm 24163034Sdougm if (property == NULL) 24173034Sdougm ret = SA_NO_MEMORY; 24183034Sdougm else { 24193034Sdougm char oname[256]; 24203034Sdougm 24213034Sdougm if (!is_zfs_group(group)) { 24223034Sdougm char *id = NULL; 24233034Sdougm if (sa_is_share((sa_group_t)parent)) { 24243034Sdougm id = sa_get_share_attr((sa_share_t)parent, "id"); 24253034Sdougm } 24263034Sdougm if (scf_handle->trans == NULL) { 24273034Sdougm if (is_nodetype(object, "optionset")) 24283034Sdougm (void) sa_optionset_name((sa_optionset_t)object, 24293034Sdougm oname, sizeof (oname), id); 24303034Sdougm else 24313034Sdougm (void) sa_security_name((sa_optionset_t)object, 24323034Sdougm oname, sizeof (oname), id); 24333034Sdougm ret = sa_start_transaction(scf_handle, oname); 24343034Sdougm } 24353034Sdougm if (ret == SA_OK) { 24363034Sdougm char *name; 24373034Sdougm char *value; 24383034Sdougm name = sa_get_property_attr(property, "type"); 24393034Sdougm value = sa_get_property_attr(property, "value"); 24403034Sdougm if (name != NULL && value != NULL) { 24413034Sdougm if (scf_handle->scf_state == SCH_STATE_INIT) 24423034Sdougm ret = sa_set_property(scf_handle, name, value); 24433034Sdougm } else 24443034Sdougm ret = SA_CONFIG_ERR; 24453034Sdougm if (name != NULL) 24463034Sdougm sa_free_attr_string(name); 24473034Sdougm if (value != NULL) 24483034Sdougm sa_free_attr_string(value); 24493034Sdougm } 24503034Sdougm if (id != NULL) 24513034Sdougm sa_free_attr_string(id); 24523034Sdougm } else { 24533034Sdougm /* 24543034Sdougm * ZFS is a special case. We do want to allow editing 24553034Sdougm * property/security lists since we can have a better 24563034Sdougm * syntax and we also want to keep things consistent 24573034Sdougm * when possible. 24583034Sdougm * 24593034Sdougm * Right now, we defer until the sa_commit_properties 24603034Sdougm * so we can get them all at once. We do need to mark 24613034Sdougm * the share as "changed" 24623034Sdougm */ 24633034Sdougm zfs_set_update((sa_share_t)parent); 24643034Sdougm } 24653034Sdougm } 24663034Sdougm return (ret); 24673034Sdougm } 24683034Sdougm 24693034Sdougm /* 24703034Sdougm * sa_remove_property(property) 24713034Sdougm * 24723034Sdougm * Remove the specied property from its containing object. Update the 24733034Sdougm * repository as appropriate. 24743034Sdougm */ 24753034Sdougm 24763034Sdougm int 24773034Sdougm sa_remove_property(sa_property_t property) 24783034Sdougm { 24793034Sdougm int ret = SA_OK; 24803034Sdougm 24813034Sdougm if (property != NULL) { 24823034Sdougm sa_optionset_t optionset; 24833034Sdougm sa_group_t group; 24843034Sdougm optionset = sa_get_property_parent(property); 24853034Sdougm if (optionset != NULL) { 24863034Sdougm group = sa_get_optionset_parent(optionset); 24873034Sdougm if (group != NULL) { 24883034Sdougm ret = sa_set_prop_by_prop(optionset, group, property, 24893034Sdougm SA_PROP_OP_REMOVE); 24903034Sdougm } 24913034Sdougm } 24923034Sdougm xmlUnlinkNode((xmlNodePtr)property); 24933034Sdougm xmlFreeNode((xmlNodePtr)property); 24943034Sdougm } else { 24953034Sdougm ret = SA_NO_SUCH_PROP; 24963034Sdougm } 24973034Sdougm return (ret); 24983034Sdougm } 24993034Sdougm 25003034Sdougm /* 25013034Sdougm * sa_update_property(property, value) 25023034Sdougm * 25033034Sdougm * Update the specified property to the new value. If value is NULL, 25043034Sdougm * we currently treat this as a remove. 25053034Sdougm */ 25063034Sdougm 25073034Sdougm int 25083034Sdougm sa_update_property(sa_property_t property, char *value) 25093034Sdougm { 25103034Sdougm int ret = SA_OK; 25113034Sdougm if (value == NULL) { 25123034Sdougm return (sa_remove_property(property)); 25133034Sdougm } else { 25143034Sdougm sa_optionset_t optionset; 25153034Sdougm sa_group_t group; 25163034Sdougm set_node_attr((void *)property, "value", value); 25173034Sdougm optionset = sa_get_property_parent(property); 25183034Sdougm if (optionset != NULL) { 25193034Sdougm group = sa_get_optionset_parent(optionset); 25203034Sdougm if (group != NULL) { 25213034Sdougm ret = sa_set_prop_by_prop(optionset, group, property, 25223034Sdougm SA_PROP_OP_UPDATE); 25233034Sdougm } 25243034Sdougm } else { 25253034Sdougm ret = SA_NO_SUCH_PROP; 25263034Sdougm } 25273034Sdougm } 25283034Sdougm return (ret); 25293034Sdougm } 25303034Sdougm 25313034Sdougm /* 25323034Sdougm * _sa_get_next_error(node) 25333034Sdougm * 25343034Sdougm * Get the next (first if node==NULL) error node in the 25353034Sdougm * document. "error" nodes are added if there were syntax errors 25363034Sdougm * during parsing of the /etc/dfs/dfstab file. They are preserved in 25373034Sdougm * comments and recreated in the doc on the next parse. 25383034Sdougm */ 25393034Sdougm 25403034Sdougm xmlNodePtr 25413034Sdougm _sa_get_next_error(xmlNodePtr node) 25423034Sdougm { 25433034Sdougm if (node == NULL) { 25443034Sdougm for (node = sa_config_tree->xmlChildrenNode; 25453034Sdougm node != NULL; node = node->next) 25463034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"error") == 0) 25473034Sdougm return (node); 25483034Sdougm } else { 25493034Sdougm for (node = node->next; node != NULL; node = node->next) 25503034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"error") == 0) 25513034Sdougm return (node); 25523034Sdougm } 25533034Sdougm return (node); 25543034Sdougm } 25553034Sdougm 25563034Sdougm /* 25573034Sdougm * sa_get_protocol_property(propset, prop) 25583034Sdougm * 25593034Sdougm * Get the specified protocol specific property. These are global to 25603034Sdougm * the protocol and not specific to a group or share. 25613034Sdougm */ 25623034Sdougm 25633034Sdougm sa_property_t 25643034Sdougm sa_get_protocol_property(sa_protocol_properties_t propset, char *prop) 25653034Sdougm { 25663034Sdougm xmlNodePtr node = (xmlNodePtr)propset; 25673034Sdougm xmlChar *value = NULL; 25683034Sdougm 25693034Sdougm for (node = node->children; node != NULL; 25703034Sdougm node = node->next) { 25713034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 25723034Sdougm if (prop == NULL) 25733034Sdougm break; 25743034Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 25753034Sdougm if (value != NULL && 25763034Sdougm xmlStrcasecmp(value, (xmlChar *)prop) == 0) { 25773034Sdougm break; 25783034Sdougm } 25793034Sdougm if (value != NULL) { 25803034Sdougm xmlFree(value); 25813034Sdougm value = NULL; 25823034Sdougm } 25833034Sdougm } 25843034Sdougm } 25853034Sdougm if (value != NULL) 25863034Sdougm xmlFree(value); 25873034Sdougm if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"option") != 0) { 25883034Sdougm /* avoid a non option node -- it is possible to be a text node */ 25893034Sdougm node = NULL; 25903034Sdougm } 25913034Sdougm return ((sa_property_t)node); 25923034Sdougm } 25933034Sdougm 25943034Sdougm /* 25953034Sdougm * sa_get_next_protocol_property(prop) 25963034Sdougm * 25973034Sdougm * Get the next protocol specific property in the list. 25983034Sdougm */ 25993034Sdougm 26003034Sdougm sa_property_t 26013034Sdougm sa_get_next_protocol_property(sa_property_t prop) 26023034Sdougm { 26033034Sdougm xmlNodePtr node; 26043034Sdougm 26053034Sdougm for (node = ((xmlNodePtr)prop)->next; node != NULL; 26063034Sdougm node = node->next) { 26073034Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 26083034Sdougm break; 26093034Sdougm } 26103034Sdougm } 26113034Sdougm return ((sa_property_t)node); 26123034Sdougm } 26133034Sdougm 26143034Sdougm /* 26153034Sdougm * sa_set_protocol_property(prop, value) 26163034Sdougm * 26173034Sdougm * Set the specified property to have the new value. The protocol 26183034Sdougm * specific plugin will then be called to update the property. 26193034Sdougm */ 26203034Sdougm 26213034Sdougm int 26223034Sdougm sa_set_protocol_property(sa_property_t prop, char *value) 26233034Sdougm { 26243034Sdougm sa_protocol_properties_t propset; 26253034Sdougm char *proto; 26263034Sdougm int ret = SA_INVALID_PROTOCOL; 26273034Sdougm 26283034Sdougm propset = ((xmlNodePtr)prop)->parent; 26293034Sdougm if (propset != NULL) { 26303034Sdougm proto = sa_get_optionset_attr(propset, "type"); 26313034Sdougm if (proto != NULL) { 26323034Sdougm set_node_attr((xmlNodePtr)prop, "value", value); 26333034Sdougm ret = sa_proto_set_property(proto, prop); 26343034Sdougm sa_free_attr_string(prop); 26353034Sdougm } 26363034Sdougm } 26373034Sdougm return (ret); 26383034Sdougm } 26393034Sdougm 26403034Sdougm /* 26413034Sdougm * sa_add_protocol_property(propset, prop) 26423034Sdougm * 26433034Sdougm * Add a new property to the protocol sepcific property set. 26443034Sdougm */ 26453034Sdougm 26463034Sdougm int 26473034Sdougm sa_add_protocol_property(sa_protocol_properties_t propset, sa_property_t prop) 26483034Sdougm { 26493034Sdougm xmlNodePtr node; 26503034Sdougm 26513034Sdougm /* should check for legitimacy */ 26523034Sdougm node = xmlAddChild((xmlNodePtr)propset, (xmlNodePtr)prop); 26533034Sdougm if (node != NULL) 26543034Sdougm return (SA_OK); 26553034Sdougm return (SA_NO_MEMORY); 26563034Sdougm } 26573034Sdougm 26583034Sdougm /* 26593034Sdougm * sa_create_protocol_properties(proto) 26603034Sdougm * 26613034Sdougm * Create a protocol specifity property set. 26623034Sdougm */ 26633034Sdougm 26643034Sdougm sa_protocol_properties_t 26653034Sdougm sa_create_protocol_properties(char *proto) 26663034Sdougm { 26673034Sdougm xmlNodePtr node; 26683034Sdougm node = xmlNewNode(NULL, (xmlChar *)"propertyset"); 26693034Sdougm if (node != NULL) { 26703034Sdougm xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto); 26713034Sdougm } 26723034Sdougm return (node); 26733034Sdougm } 2674