16185db85Sdougm /* 26185db85Sdougm * CDDL HEADER START 36185db85Sdougm * 46185db85Sdougm * The contents of this file are subject to the terms of the 56185db85Sdougm * Common Development and Distribution License (the "License"). 66185db85Sdougm * You may not use this file except in compliance with the License. 76185db85Sdougm * 86185db85Sdougm * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 96185db85Sdougm * or http://www.opensolaris.org/os/licensing. 106185db85Sdougm * See the License for the specific language governing permissions 116185db85Sdougm * and limitations under the License. 126185db85Sdougm * 136185db85Sdougm * When distributing Covered Code, include this CDDL HEADER in each 146185db85Sdougm * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 156185db85Sdougm * If applicable, add the following below this CDDL HEADER, with the 166185db85Sdougm * fields enclosed by brackets "[]" replaced with your own identifying 176185db85Sdougm * information: Portions Copyright [yyyy] [name of copyright owner] 186185db85Sdougm * 196185db85Sdougm * CDDL HEADER END 206185db85Sdougm */ 216185db85Sdougm 226185db85Sdougm /* 23*f345c0beSdougm * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 246185db85Sdougm * Use is subject to license terms. 256185db85Sdougm */ 266185db85Sdougm 276185db85Sdougm #pragma ident "%Z%%M% %I% %E% SMI" 286185db85Sdougm 296185db85Sdougm /* helper functions for using libscf with sharemgr */ 306185db85Sdougm 316185db85Sdougm #include <libscf.h> 326185db85Sdougm #include <libxml/parser.h> 336185db85Sdougm #include <libxml/tree.h> 346185db85Sdougm #include "libshare.h" 356185db85Sdougm #include "libshare_impl.h" 366185db85Sdougm #include "scfutil.h" 376185db85Sdougm #include <string.h> 386185db85Sdougm #include <errno.h> 396185db85Sdougm #include <uuid/uuid.h> 406185db85Sdougm #include <sys/param.h> 41*f345c0beSdougm #include <signal.h> 426185db85Sdougm 436185db85Sdougm ssize_t scf_max_name_len; 446185db85Sdougm extern struct sa_proto_plugin *sap_proto_list; 456185db85Sdougm 466185db85Sdougm /* 476185db85Sdougm * The SMF facility uses some properties that must exist. We want to 486185db85Sdougm * skip over these when processing protocol options. 496185db85Sdougm */ 506185db85Sdougm static char *skip_props[] = { 516185db85Sdougm "modify_authorization", 526185db85Sdougm "action_authorization", 536185db85Sdougm "value_authorization", 546185db85Sdougm NULL 556185db85Sdougm }; 566185db85Sdougm 576185db85Sdougm /* 586185db85Sdougm * sa_scf_fini(handle) 596185db85Sdougm * 606185db85Sdougm * must be called when done. Called with the handle allocated in 616185db85Sdougm * sa_scf_init(), it cleans up the state and frees any SCF resources 626185db85Sdougm * still in use. Called by sa_fini(). 636185db85Sdougm */ 646185db85Sdougm 656185db85Sdougm void 666185db85Sdougm sa_scf_fini(scfutilhandle_t *handle) 676185db85Sdougm { 686185db85Sdougm if (handle != NULL) { 696185db85Sdougm int unbind = 0; 706185db85Sdougm if (handle->scope != NULL) { 716185db85Sdougm unbind = 1; 726185db85Sdougm scf_scope_destroy(handle->scope); 736185db85Sdougm } 746185db85Sdougm if (handle->service != NULL) 756185db85Sdougm scf_service_destroy(handle->service); 766185db85Sdougm if (handle->pg != NULL) 776185db85Sdougm scf_pg_destroy(handle->pg); 786185db85Sdougm if (handle->handle != NULL) { 796185db85Sdougm handle->scf_state = SCH_STATE_UNINIT; 806185db85Sdougm if (unbind) 816185db85Sdougm (void) scf_handle_unbind(handle->handle); 826185db85Sdougm scf_handle_destroy(handle->handle); 836185db85Sdougm } 846185db85Sdougm free(handle); 856185db85Sdougm } 866185db85Sdougm } 876185db85Sdougm 886185db85Sdougm /* 896185db85Sdougm * sa_scf_init() 906185db85Sdougm * 916185db85Sdougm * must be called before using any of the SCF functions. Called by 926185db85Sdougm * sa_init() during the API setup. 936185db85Sdougm */ 946185db85Sdougm 956185db85Sdougm scfutilhandle_t * 966185db85Sdougm sa_scf_init() 976185db85Sdougm { 986185db85Sdougm scfutilhandle_t *handle; 996185db85Sdougm 1006185db85Sdougm scf_max_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH); 1016185db85Sdougm if (scf_max_name_len <= 0) 1026185db85Sdougm scf_max_name_len = SA_MAX_NAME_LEN + 1; 1036185db85Sdougm 1046185db85Sdougm handle = calloc(1, sizeof (scfutilhandle_t)); 1056185db85Sdougm if (handle != NULL) { 1066185db85Sdougm handle->scf_state = SCH_STATE_INITIALIZING; 1076185db85Sdougm handle->handle = scf_handle_create(SCF_VERSION); 1086185db85Sdougm if (handle->handle != NULL) { 1096185db85Sdougm if (scf_handle_bind(handle->handle) == 0) { 1106185db85Sdougm handle->scope = scf_scope_create(handle->handle); 1116185db85Sdougm handle->service = scf_service_create(handle->handle); 1126185db85Sdougm handle->pg = scf_pg_create(handle->handle); 1136185db85Sdougm handle->instance = scf_instance_create(handle->handle); 1146185db85Sdougm if (scf_handle_get_scope(handle->handle, 1156185db85Sdougm SCF_SCOPE_LOCAL, handle->scope) == 0) { 1166185db85Sdougm if (scf_scope_get_service(handle->scope, 1176185db85Sdougm SA_GROUP_SVC_NAME, 1186185db85Sdougm handle->service) != 0) { 1196185db85Sdougm goto err; 1206185db85Sdougm } 1216185db85Sdougm handle->scf_state = SCH_STATE_INIT; 1226185db85Sdougm if (sa_get_instance(handle, "default") != SA_OK) { 1236185db85Sdougm char **protolist; 1246185db85Sdougm int numprotos, i; 1256185db85Sdougm sa_group_t defgrp; 1266185db85Sdougm defgrp = sa_create_group("default", NULL); 1276185db85Sdougm if (defgrp != NULL) { 1286185db85Sdougm numprotos = sa_get_protocols(&protolist); 1296185db85Sdougm for (i = 0; i < numprotos; i++) { 1306185db85Sdougm (void) sa_create_optionset(defgrp, 1316185db85Sdougm protolist[i]); 1326185db85Sdougm } 1336185db85Sdougm if (protolist != NULL) 1346185db85Sdougm free(protolist); 1356185db85Sdougm } 1366185db85Sdougm } 1376185db85Sdougm } else { 1386185db85Sdougm goto err; 1396185db85Sdougm } 1406185db85Sdougm } else { 1416185db85Sdougm goto err; 1426185db85Sdougm } 1436185db85Sdougm } else { 1446185db85Sdougm free(handle); 1456185db85Sdougm handle = NULL; 1466185db85Sdougm (void) printf("libshare could not access SMF repository: %s\n", 1476185db85Sdougm scf_strerror(scf_error())); 1486185db85Sdougm } 1496185db85Sdougm } 1506185db85Sdougm return (handle); 1516185db85Sdougm 1526185db85Sdougm /* error handling/unwinding */ 1536185db85Sdougm err: 1546185db85Sdougm (void) sa_scf_fini(handle); 1556185db85Sdougm (void) printf("libshare SMF initialization problem: %s\n", 1566185db85Sdougm scf_strerror(scf_error())); 1576185db85Sdougm return (NULL); 1586185db85Sdougm } 1596185db85Sdougm 1606185db85Sdougm /* 1616185db85Sdougm * get_scf_limit(name) 1626185db85Sdougm * 1636185db85Sdougm * Since we use scf_limit a lot and do the same check and return the 1646185db85Sdougm * same value if it fails, implement as a function for code 1656185db85Sdougm * simplification. Basically, if name isn't found, return MAXPATHLEN 1666185db85Sdougm * (1024) so we have a reasonable default buffer size. 1676185db85Sdougm */ 1686185db85Sdougm static ssize_t 1696185db85Sdougm get_scf_limit(uint32_t name) 1706185db85Sdougm { 1716185db85Sdougm ssize_t vallen; 1726185db85Sdougm 1736185db85Sdougm vallen = scf_limit(name); 1746185db85Sdougm if (vallen == (ssize_t)-1) 1756185db85Sdougm vallen = MAXPATHLEN; 1766185db85Sdougm return (vallen); 1776185db85Sdougm } 1786185db85Sdougm 1796185db85Sdougm /* 1806185db85Sdougm * skip_property(name) 1816185db85Sdougm * 1826185db85Sdougm * internal function to check to see if a property is an SMF magic 1836185db85Sdougm * property that needs to be skipped. 1846185db85Sdougm */ 1856185db85Sdougm static int 1866185db85Sdougm skip_property(char *name) 1876185db85Sdougm { 1886185db85Sdougm int i; 1896185db85Sdougm 1906185db85Sdougm for (i = 0; skip_props[i] != NULL; i++) 1916185db85Sdougm if (strcmp(name, skip_props[i]) == 0) 1926185db85Sdougm return (1); 1936185db85Sdougm return (0); 1946185db85Sdougm } 1956185db85Sdougm 1966185db85Sdougm /* 1976185db85Sdougm * generate_unique_sharename(sharename) 1986185db85Sdougm * 1996185db85Sdougm * Shares are represented in SMF as property groups. Due to share 2006185db85Sdougm * paths containing characters that are not allowed in SMF names and 2016185db85Sdougm * the need to be unique, we use UUIDs to construct a unique name. 2026185db85Sdougm */ 2036185db85Sdougm 2046185db85Sdougm static void 2056185db85Sdougm generate_unique_sharename(char *sharename) 2066185db85Sdougm { 2076185db85Sdougm uuid_t uuid; 2086185db85Sdougm 2096185db85Sdougm uuid_generate(uuid); 2106185db85Sdougm (void) strcpy(sharename, "S-"); 2116185db85Sdougm uuid_unparse(uuid, sharename + 2); 2126185db85Sdougm } 2136185db85Sdougm 2146185db85Sdougm /* 2156185db85Sdougm * valid_protocol(proto) 2166185db85Sdougm * 2176185db85Sdougm * check to see if the specified protocol is a valid one for the 2186185db85Sdougm * general sharemgr facility. We determine this by checking which 2196185db85Sdougm * plugin protocols were found. 2206185db85Sdougm */ 2216185db85Sdougm 2226185db85Sdougm static int 2236185db85Sdougm valid_protocol(char *proto) 2246185db85Sdougm { 2256185db85Sdougm struct sa_proto_plugin *plugin; 2266185db85Sdougm for (plugin = sap_proto_list; plugin != NULL; 2276185db85Sdougm plugin = plugin->plugin_next) 2286185db85Sdougm if (strcmp(proto, plugin->plugin_ops->sa_protocol) == 0) 2296185db85Sdougm return (1); 2306185db85Sdougm return (0); 2316185db85Sdougm } 2326185db85Sdougm 2336185db85Sdougm /* 2346185db85Sdougm * sa_extract_pgroup(root, handle, pg, nodetype, proto, sectype) 2356185db85Sdougm * 2366185db85Sdougm * extract the name property group and create the specified type of 2376185db85Sdougm * node on the provided group. type will be optionset or security. 2386185db85Sdougm */ 2396185db85Sdougm 2406185db85Sdougm static int 2416185db85Sdougm sa_extract_pgroup(xmlNodePtr root, scfutilhandle_t *handle, 2426185db85Sdougm scf_propertygroup_t *pg, 2436185db85Sdougm char *nodetype, char *proto, char *sectype) 2446185db85Sdougm { 2456185db85Sdougm xmlNodePtr node; 2466185db85Sdougm scf_iter_t *iter; 2476185db85Sdougm scf_property_t *prop; 2486185db85Sdougm scf_value_t *value; 2496185db85Sdougm char *name; 2506185db85Sdougm char *valuestr; 2516185db85Sdougm ssize_t vallen; 2526185db85Sdougm int ret = SA_OK; 2536185db85Sdougm 2546185db85Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 2556185db85Sdougm 2566185db85Sdougm node = xmlNewChild(root, NULL, (xmlChar *)nodetype, NULL); 2576185db85Sdougm if (node != NULL) { 2586185db85Sdougm if (proto != NULL) 2596185db85Sdougm xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto); 2606185db85Sdougm if (sectype != NULL) 2616185db85Sdougm xmlSetProp(node, (xmlChar *)"sectype", (xmlChar *)sectype); 2626185db85Sdougm /* 2636185db85Sdougm * have node to work with so iterate over the properties 2646185db85Sdougm * in the pg and create option sub nodes. 2656185db85Sdougm */ 2666185db85Sdougm iter = scf_iter_create(handle->handle); 2676185db85Sdougm value = scf_value_create(handle->handle); 2686185db85Sdougm prop = scf_property_create(handle->handle); 2696185db85Sdougm name = malloc(scf_max_name_len); 2706185db85Sdougm valuestr = malloc(vallen); 2716185db85Sdougm /* 2726185db85Sdougm * want to iterate through the properties and add them 2736185db85Sdougm * to the base optionset. 2746185db85Sdougm */ 2756185db85Sdougm if (iter != NULL && value != NULL && prop != NULL && 2766185db85Sdougm valuestr != NULL && name != NULL) { 2776185db85Sdougm if (scf_iter_pg_properties(iter, pg) == 0) { 2786185db85Sdougm /* now iterate the properties in the group */ 2796185db85Sdougm while (scf_iter_next_property(iter, prop) > 0) { 2806185db85Sdougm /* have a property */ 2816185db85Sdougm if (scf_property_get_name(prop, name, 2826185db85Sdougm scf_max_name_len) > 0) { 2836185db85Sdougm /* some properties are part of the framework */ 2846185db85Sdougm if (skip_property(name)) 2856185db85Sdougm continue; 2866185db85Sdougm if (scf_property_get_value(prop, value) == 0) { 2876185db85Sdougm if (scf_value_get_astring(value, valuestr, 2886185db85Sdougm vallen) >= 0) { 2896185db85Sdougm sa_property_t saprop; 2906185db85Sdougm saprop = sa_create_property(name, 2916185db85Sdougm valuestr); 2926185db85Sdougm if (saprop != NULL) { 2936185db85Sdougm /* 2946185db85Sdougm * since in SMF, don't 2956185db85Sdougm * recurse. Use xmlAddChild 2966185db85Sdougm * directly, instead. 2976185db85Sdougm */ 2986185db85Sdougm xmlAddChild(node, 2996185db85Sdougm (xmlNodePtr) saprop); 3006185db85Sdougm } 3016185db85Sdougm } 3026185db85Sdougm } 3036185db85Sdougm } 3046185db85Sdougm } 3056185db85Sdougm } 3066185db85Sdougm } else { 3076185db85Sdougm ret = SA_NO_MEMORY; 3086185db85Sdougm } 3096185db85Sdougm /* cleanup to avoid memory leaks */ 3106185db85Sdougm if (value != NULL) 3116185db85Sdougm scf_value_destroy(value); 3126185db85Sdougm if (iter != NULL) 3136185db85Sdougm scf_iter_destroy(iter); 3146185db85Sdougm if (prop != NULL) 3156185db85Sdougm scf_property_destroy(prop); 3166185db85Sdougm if (name != NULL) 3176185db85Sdougm free(name); 3186185db85Sdougm if (valuestr != NULL) 3196185db85Sdougm free(valuestr); 3206185db85Sdougm } 3216185db85Sdougm return (ret); 3226185db85Sdougm } 3236185db85Sdougm 3246185db85Sdougm /* 3256185db85Sdougm * sa_extract_attrs(root, handle, instance) 3266185db85Sdougm * 3276185db85Sdougm * local function to extract the actual attributes/properties from the 3286185db85Sdougm * property group of the service instance. These are the well known 3296185db85Sdougm * attributes of "state" and "zfs". If additional attributes are 3306185db85Sdougm * added, they should be added here. 3316185db85Sdougm */ 3326185db85Sdougm 3336185db85Sdougm static void 3346185db85Sdougm sa_extract_attrs(xmlNodePtr root, scfutilhandle_t *handle, 3356185db85Sdougm scf_instance_t *instance) 3366185db85Sdougm { 3376185db85Sdougm scf_property_t *prop; 3386185db85Sdougm scf_value_t *value; 3396185db85Sdougm char *valuestr; 3406185db85Sdougm ssize_t vallen; 3416185db85Sdougm 3426185db85Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 3436185db85Sdougm prop = scf_property_create(handle->handle); 3446185db85Sdougm value = scf_value_create(handle->handle); 3456185db85Sdougm valuestr = malloc(vallen); 3466185db85Sdougm if (prop != NULL && value != NULL && valuestr != NULL && 3476185db85Sdougm scf_instance_get_pg(instance, "operation", 3486185db85Sdougm handle->pg) == 0) { 3496185db85Sdougm /* 3506185db85Sdougm * have a property group with desired name so now get 3516185db85Sdougm * the known attributes. 3526185db85Sdougm */ 3536185db85Sdougm if (scf_pg_get_property(handle->pg, "state", prop) == 0) { 3546185db85Sdougm /* found the property so get the value */ 3556185db85Sdougm if (scf_property_get_value(prop, value) == 0) { 3566185db85Sdougm if (scf_value_get_astring(value, valuestr, vallen) >= 0) { 3576185db85Sdougm xmlSetProp(root, (xmlChar *)"state", 3586185db85Sdougm (xmlChar *)valuestr); 3596185db85Sdougm } 3606185db85Sdougm } 3616185db85Sdougm } 3626185db85Sdougm if (scf_pg_get_property(handle->pg, "zfs", prop) == 0) { 3636185db85Sdougm /* found the property so get the value */ 3646185db85Sdougm if (scf_property_get_value(prop, value) == 0) { 3656185db85Sdougm if (scf_value_get_astring(value, valuestr, vallen) > 0) { 3666185db85Sdougm xmlSetProp(root, (xmlChar *)"zfs", 3676185db85Sdougm (xmlChar *)valuestr); 3686185db85Sdougm } 3696185db85Sdougm } 3706185db85Sdougm } 3716185db85Sdougm } 3726185db85Sdougm if (valuestr != NULL) 3736185db85Sdougm free(valuestr); 3746185db85Sdougm if (value != NULL) 3756185db85Sdougm scf_value_destroy(value); 3766185db85Sdougm if (prop != NULL) 3776185db85Sdougm scf_property_destroy(prop); 3786185db85Sdougm } 3796185db85Sdougm 3806185db85Sdougm /* 3816185db85Sdougm * list of known share attributes. 3826185db85Sdougm */ 3836185db85Sdougm 3846185db85Sdougm static char *share_attr[] = { 3856185db85Sdougm "path", 3866185db85Sdougm "id", 3876185db85Sdougm "resource", 3886185db85Sdougm NULL, 3896185db85Sdougm }; 3906185db85Sdougm 3916185db85Sdougm static int 3926185db85Sdougm is_share_attr(char *name) 3936185db85Sdougm { 3946185db85Sdougm int i; 3956185db85Sdougm for (i = 0; share_attr[i] != NULL; i++) 3966185db85Sdougm if (strcmp(name, share_attr[i]) == 0) 3976185db85Sdougm return (1); 3986185db85Sdougm return (0); 3996185db85Sdougm } 4006185db85Sdougm 4016185db85Sdougm /* 4026185db85Sdougm * sa_share_from_pgroup 4036185db85Sdougm * 4046185db85Sdougm * extract the share definition from the share property group. We do 4056185db85Sdougm * some sanity checking to avoid bad data. 4066185db85Sdougm * 4076185db85Sdougm * Since this is only constructing the internal data structures, we 4086185db85Sdougm * don't use the sa_* functions most of the time. 4096185db85Sdougm */ 4106185db85Sdougm void 4116185db85Sdougm sa_share_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle, 4126185db85Sdougm scf_propertygroup_t *pg, char *id) 4136185db85Sdougm { 4146185db85Sdougm xmlNodePtr node; 4156185db85Sdougm char *name; 4166185db85Sdougm scf_iter_t *iter; 4176185db85Sdougm scf_property_t *prop; 4186185db85Sdougm scf_value_t *value; 4196185db85Sdougm ssize_t vallen; 4206185db85Sdougm char *valuestr; 4216185db85Sdougm int ret = SA_OK; 422*f345c0beSdougm int have_path = 0; 4236185db85Sdougm 4246185db85Sdougm /* 4256185db85Sdougm * While preliminary check (starts with 'S') passed before 4266185db85Sdougm * getting here. Need to make sure it is in ID syntax 4276185db85Sdougm * (Snnnnnn). Note that shares with properties have similar 4286185db85Sdougm * pgroups. 4296185db85Sdougm */ 4306185db85Sdougm vallen = strlen(id); 4316185db85Sdougm if (*id == SA_SHARE_PG_PREFIX[0] && vallen == SA_SHARE_PG_LEN) { 4326185db85Sdougm uuid_t uuid; 4336185db85Sdougm if (strncmp(id, SA_SHARE_PG_PREFIX, SA_SHARE_PG_PREFIXLEN) != 0 || 4346185db85Sdougm uuid_parse(id + 2, uuid) < 0) 4356185db85Sdougm return; 4366185db85Sdougm } else { 4376185db85Sdougm return; 4386185db85Sdougm } 4396185db85Sdougm 4406185db85Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 4416185db85Sdougm 4426185db85Sdougm iter = scf_iter_create(handle->handle); 4436185db85Sdougm value = scf_value_create(handle->handle); 4446185db85Sdougm prop = scf_property_create(handle->handle); 4456185db85Sdougm name = malloc(scf_max_name_len); 4466185db85Sdougm valuestr = malloc(vallen); 4476185db85Sdougm 4486185db85Sdougm /* 4496185db85Sdougm * construct the share XML node. It is similar to sa_add_share 4506185db85Sdougm * but never changes the repository. Also, there won't be any 4516185db85Sdougm * ZFS or transient shares. Root will be the group it is 4526185db85Sdougm * associated with. 4536185db85Sdougm */ 4546185db85Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"share", NULL); 4556185db85Sdougm if (node != NULL) { 4566185db85Sdougm /* 4576185db85Sdougm * make sure the UUID part of the property group is 4586185db85Sdougm * stored in the share "id" property. We use this 4596185db85Sdougm * later. 4606185db85Sdougm */ 4616185db85Sdougm xmlSetProp(node, (xmlChar *)"id", (xmlChar *)id); 4626185db85Sdougm xmlSetProp(node, (xmlChar *)"type", (xmlChar *)"persist"); 4636185db85Sdougm } 4646185db85Sdougm 4656185db85Sdougm if (iter != NULL && value != NULL && prop != NULL && name != NULL) { 4666185db85Sdougm /* iterate over the share pg properties */ 4676185db85Sdougm if (scf_iter_pg_properties(iter, pg) == 0) { 4686185db85Sdougm while (scf_iter_next_property(iter, prop) > 0) { 4696185db85Sdougm ret = SA_SYSTEM_ERR; /* assume the worst */ 4706185db85Sdougm if (scf_property_get_name(prop, name, 4716185db85Sdougm scf_max_name_len) > 0) { 4726185db85Sdougm if (scf_property_get_value(prop, value) == 0) { 4736185db85Sdougm if (scf_value_get_astring(value, valuestr, 4746185db85Sdougm vallen) >= 0) { 4756185db85Sdougm ret = SA_OK; 4766185db85Sdougm } 4776185db85Sdougm } 4786185db85Sdougm } 4796185db85Sdougm if (ret == SA_OK) { 480*f345c0beSdougm /* 481*f345c0beSdougm * check that we have the "path" property in 482*f345c0beSdougm * name. The string in name will always be nul 483*f345c0beSdougm * terminated if scf_property_get_name() 484*f345c0beSdougm * succeeded. 485*f345c0beSdougm */ 486*f345c0beSdougm if (strcmp(name, "path") == 0) 487*f345c0beSdougm have_path = 1; 4886185db85Sdougm if (is_share_attr(name)) { 4896185db85Sdougm /* 4906185db85Sdougm * if a share attr, then simple - 4916185db85Sdougm * usually path and resource name 4926185db85Sdougm */ 4936185db85Sdougm xmlSetProp(node, (xmlChar *)name, 4946185db85Sdougm (xmlChar *)valuestr); 4956185db85Sdougm } else { 4966185db85Sdougm if (strcmp(name, "description") == 0) { 4976185db85Sdougm /* we have a description node */ 4986185db85Sdougm xmlNodePtr desc; 4996185db85Sdougm desc = xmlNewChild(node, NULL, 5006185db85Sdougm (xmlChar *)"description", 5016185db85Sdougm NULL); 5026185db85Sdougm if (desc != NULL) 5036185db85Sdougm xmlNodeSetContent(desc, 5046185db85Sdougm (xmlChar *)valuestr); 5056185db85Sdougm } 5066185db85Sdougm } 5076185db85Sdougm } 5086185db85Sdougm } 5096185db85Sdougm } 5106185db85Sdougm } 511*f345c0beSdougm /* 512*f345c0beSdougm * a share without a path is broken so we want to not include 513*f345c0beSdougm * these. They shouldn't happen but if you kill a sharemgr in 514*f345c0beSdougm * the process of creating a share, it could happen. They 515*f345c0beSdougm * should be harmless. It is also possible that another 516*f345c0beSdougm * sharemgr is running and in the process of creating a share. 517*f345c0beSdougm */ 518*f345c0beSdougm if (have_path == 0 && node != NULL) { 519*f345c0beSdougm xmlUnlinkNode(node); 520*f345c0beSdougm xmlFreeNode(node); 521*f345c0beSdougm } 5226185db85Sdougm if (name != NULL) 5236185db85Sdougm free(name); 5246185db85Sdougm if (valuestr != NULL) 5256185db85Sdougm free(valuestr); 5266185db85Sdougm if (value != NULL) 5276185db85Sdougm scf_value_destroy(value); 5286185db85Sdougm if (iter != NULL) 5296185db85Sdougm scf_iter_destroy(iter); 5306185db85Sdougm if (prop != NULL) 5316185db85Sdougm scf_property_destroy(prop); 5326185db85Sdougm } 5336185db85Sdougm 5346185db85Sdougm /* 5356185db85Sdougm * find_share_by_id(shareid) 5366185db85Sdougm * 5376185db85Sdougm * Search all shares in all groups until we find the share represented 5386185db85Sdougm * by "id". 5396185db85Sdougm */ 5406185db85Sdougm 5416185db85Sdougm static sa_share_t 5426185db85Sdougm find_share_by_id(char *shareid) 5436185db85Sdougm { 5446185db85Sdougm sa_group_t group; 5456185db85Sdougm sa_share_t share = NULL; 5466185db85Sdougm char *id = NULL; 5476185db85Sdougm int done = 0; 5486185db85Sdougm 5496185db85Sdougm for (group = sa_get_group(NULL); group != NULL && !done; 5506185db85Sdougm group = sa_get_next_group(group)) { 5516185db85Sdougm for (share = sa_get_share(group, NULL); share != NULL; 5526185db85Sdougm share = sa_get_next_share(share)) { 5536185db85Sdougm id = sa_get_share_attr(share, "id"); 5546185db85Sdougm if (id != NULL && strcmp(id, shareid) == 0) { 5556185db85Sdougm sa_free_attr_string(id); 5566185db85Sdougm id = NULL; 5576185db85Sdougm done++; 5586185db85Sdougm break; 5596185db85Sdougm } 5606185db85Sdougm if (id != NULL) { 5616185db85Sdougm sa_free_attr_string(id); 5626185db85Sdougm id = NULL; 5636185db85Sdougm } 5646185db85Sdougm } 5656185db85Sdougm } 5666185db85Sdougm return (share); 5676185db85Sdougm } 5686185db85Sdougm 5696185db85Sdougm /* 5706185db85Sdougm * sa_share_props_from_pgroup(root, handle, pg, id) 5716185db85Sdougm * 5726185db85Sdougm * extract share properties from the SMF property group. More sanity 5736185db85Sdougm * checks are done and the share object is created. We ignore some 5746185db85Sdougm * errors that could exist in the repository and only worry about 5756185db85Sdougm * property groups that validate in naming. 5766185db85Sdougm */ 5776185db85Sdougm 5786185db85Sdougm static int 5796185db85Sdougm sa_share_props_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle, 5806185db85Sdougm scf_propertygroup_t *pg, char *id) 5816185db85Sdougm { 5826185db85Sdougm xmlNodePtr node; 5836185db85Sdougm char *name; 5846185db85Sdougm scf_iter_t *iter; 5856185db85Sdougm scf_property_t *prop; 5866185db85Sdougm scf_value_t *value; 5876185db85Sdougm ssize_t vallen; 5886185db85Sdougm char *valuestr; 5896185db85Sdougm int ret = SA_OK; 5906185db85Sdougm char *sectype = NULL; 5916185db85Sdougm char *proto; 5926185db85Sdougm sa_share_t share; 5936185db85Sdougm 5946185db85Sdougm /* 5956185db85Sdougm * While preliminary check (starts with 'S') passed before 5966185db85Sdougm * getting here. Need to make sure it is in ID syntax 5976185db85Sdougm * (Snnnnnn). Note that shares with properties have similar 5986185db85Sdougm * pgroups. If the pg name is more than SA_SHARE_PG_LEN 5996185db85Sdougm * characters, it is likely one of the protocol/security 6006185db85Sdougm * versions. 6016185db85Sdougm */ 6026185db85Sdougm vallen = strlen(id); 6036185db85Sdougm if (*id == SA_SHARE_PG_PREFIX[0] && vallen > SA_SHARE_PG_LEN) { 6046185db85Sdougm uuid_t uuid; 6056185db85Sdougm if (strncmp(id, SA_SHARE_PG_PREFIX, SA_SHARE_PG_PREFIXLEN) == 0) { 6066185db85Sdougm proto = strchr(id, '_'); 6076185db85Sdougm if (proto == NULL) 6086185db85Sdougm return (ret); 6096185db85Sdougm *proto++ = '\0'; 6106185db85Sdougm if (uuid_parse(id + SA_SHARE_PG_PREFIXLEN, uuid) < 0) 6116185db85Sdougm return (ret); 6126185db85Sdougm /* 6136185db85Sdougm * probably a legal optionset so check a few more 6146185db85Sdougm * syntax points below. 6156185db85Sdougm */ 6166185db85Sdougm if (*proto == '\0') { 6176185db85Sdougm /* not a valid proto (null) */ 6186185db85Sdougm return (ret); 6196185db85Sdougm } 6206185db85Sdougm sectype = strchr(proto, '_'); 6216185db85Sdougm if (sectype != NULL) 6226185db85Sdougm *sectype++ = '\0'; 6236185db85Sdougm if (!valid_protocol(proto)) 6246185db85Sdougm return (ret); 6256185db85Sdougm } 6266185db85Sdougm } else { 6276185db85Sdougm /* 6286185db85Sdougm * it is ok to not have what we thought since someone might 6296185db85Sdougm * have added a name via SMF. 6306185db85Sdougm */ 6316185db85Sdougm return (ret); 6326185db85Sdougm } 6336185db85Sdougm 6346185db85Sdougm /* 6356185db85Sdougm * to get here, we have a valid protocol and possibly a 6366185db85Sdougm * security. We now have to find the share that it is really 6376185db85Sdougm * associated with. The "id" portion of the pgroup name will 6386185db85Sdougm * match. 6396185db85Sdougm */ 6406185db85Sdougm 6416185db85Sdougm share = find_share_by_id(id); 6426185db85Sdougm if (share == NULL) 6436185db85Sdougm return (SA_BAD_PATH); 6446185db85Sdougm 6456185db85Sdougm root = (xmlNodePtr)share; 6466185db85Sdougm 6476185db85Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 6486185db85Sdougm 6496185db85Sdougm iter = scf_iter_create(handle->handle); 6506185db85Sdougm value = scf_value_create(handle->handle); 6516185db85Sdougm prop = scf_property_create(handle->handle); 6526185db85Sdougm name = malloc(scf_max_name_len); 6536185db85Sdougm valuestr = malloc(vallen); 6546185db85Sdougm 6556185db85Sdougm if (sectype == NULL) 6566185db85Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"optionset", NULL); 6576185db85Sdougm else { 6586185db85Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"security", NULL); 6596185db85Sdougm if (node != NULL) 6606185db85Sdougm xmlSetProp(node, (xmlChar *)"sectype", (xmlChar *)sectype); 6616185db85Sdougm } 6626185db85Sdougm if (node != NULL) { 6636185db85Sdougm xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto); 6646185db85Sdougm /* now find the properties */ 6656185db85Sdougm if (iter != NULL && value != NULL && prop != NULL && name != NULL) { 6666185db85Sdougm /* iterate over the share pg properties */ 6676185db85Sdougm if (scf_iter_pg_properties(iter, pg) == 0) { 6686185db85Sdougm while (scf_iter_next_property(iter, prop) > 0) { 6696185db85Sdougm ret = SA_SYSTEM_ERR; /* assume the worst */ 6706185db85Sdougm if (scf_property_get_name(prop, name, 6716185db85Sdougm scf_max_name_len) > 0) { 6726185db85Sdougm if (scf_property_get_value(prop, value) == 0) { 6736185db85Sdougm if (scf_value_get_astring(value, valuestr, 6746185db85Sdougm vallen) >= 0) { 6756185db85Sdougm ret = SA_OK; 6766185db85Sdougm } 6776185db85Sdougm } 6786185db85Sdougm } else { 6796185db85Sdougm ret = SA_SYSTEM_ERR; 6806185db85Sdougm } 6816185db85Sdougm if (ret == SA_OK) { 6826185db85Sdougm sa_property_t prop; 6836185db85Sdougm prop = sa_create_property(name, valuestr); 6846185db85Sdougm if (prop != NULL) 6856185db85Sdougm prop = (sa_property_t)xmlAddChild(node, 6866185db85Sdougm (xmlNodePtr)prop); 6876185db85Sdougm else 6886185db85Sdougm ret = SA_NO_MEMORY; 6896185db85Sdougm } 6906185db85Sdougm } 6916185db85Sdougm } else { 6926185db85Sdougm ret = SA_SYSTEM_ERR; 6936185db85Sdougm } 6946185db85Sdougm } 6956185db85Sdougm } else { 6966185db85Sdougm ret = SA_NO_MEMORY; 6976185db85Sdougm } 6986185db85Sdougm if (iter != NULL) 6996185db85Sdougm scf_iter_destroy(iter); 7006185db85Sdougm if (value != NULL) 7016185db85Sdougm scf_value_destroy(value); 7026185db85Sdougm if (prop != NULL) 7036185db85Sdougm scf_property_destroy(prop); 7046185db85Sdougm if (name != NULL) 7056185db85Sdougm free(name); 7066185db85Sdougm if (valuestr != NULL) 7076185db85Sdougm free(valuestr); 7086185db85Sdougm return (ret); 7096185db85Sdougm } 7106185db85Sdougm 7116185db85Sdougm /* 7126185db85Sdougm * sa_extract_group(root, handle, instance) 7136185db85Sdougm * 7146185db85Sdougm * get the config info for this instance of a group and create the XML 7156185db85Sdougm * subtree from it. 7166185db85Sdougm */ 7176185db85Sdougm 7186185db85Sdougm static int 7196185db85Sdougm sa_extract_group(xmlNodePtr root, scfutilhandle_t *handle, 7206185db85Sdougm scf_instance_t *instance) 7216185db85Sdougm { 7226185db85Sdougm char *buff; 7236185db85Sdougm xmlNodePtr node; 7246185db85Sdougm scf_iter_t *iter; 7256185db85Sdougm char *proto; 7266185db85Sdougm char *sectype; 7276185db85Sdougm int have_shares = 0; 7286185db85Sdougm int has_proto = 0; 7296185db85Sdougm int is_default = 0; 7306185db85Sdougm int ret = SA_OK; 7316185db85Sdougm int err; 7326185db85Sdougm 7336185db85Sdougm buff = malloc(scf_max_name_len); 7346185db85Sdougm iter = scf_iter_create(handle->handle); 7356185db85Sdougm if (buff != NULL) { 7366185db85Sdougm if (scf_instance_get_name(instance, buff, 7376185db85Sdougm scf_max_name_len) > 0) { 7386185db85Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"group", NULL); 7396185db85Sdougm if (node != NULL) { 7406185db85Sdougm xmlSetProp(node, (xmlChar *)"name", (xmlChar *)buff); 7416185db85Sdougm if (strcmp(buff, "default") == 0) 7426185db85Sdougm is_default++; 7436185db85Sdougm sa_extract_attrs(node, handle, instance); 7446185db85Sdougm /* 7456185db85Sdougm * Iterate through all the property groups 7466185db85Sdougm * looking for those with security or 7476185db85Sdougm * optionset prefixes. The names of the 7486185db85Sdougm * matching pgroups are parsed to get the 7496185db85Sdougm * protocol, and for security, the sectype. 7506185db85Sdougm * Syntax is as follows: 7516185db85Sdougm * optionset | optionset_<proto> 7526185db85Sdougm * security_default | security_<proto>_<sectype> 7536185db85Sdougm * "operation" is handled by 7546185db85Sdougm * sa_extract_attrs(). 7556185db85Sdougm */ 7566185db85Sdougm if (iter != NULL) { 7576185db85Sdougm if (scf_iter_instance_pgs(iter, instance) == 0) { 7586185db85Sdougm while (scf_iter_next_pg(iter, handle->pg) > 0) { 7596185db85Sdougm /* have a pgroup so sort it out */ 7606185db85Sdougm ret = scf_pg_get_name(handle->pg, buff, 7616185db85Sdougm scf_max_name_len); 7626185db85Sdougm if (ret > 0) { 7636185db85Sdougm if (buff[0] == SA_SHARE_PG_PREFIX[0]) { 7646185db85Sdougm sa_share_from_pgroup(node, handle, 7656185db85Sdougm handle->pg, 7666185db85Sdougm buff); 7676185db85Sdougm have_shares++; 7686185db85Sdougm } else if (strncmp(buff, "optionset", 9) == 7696185db85Sdougm 0) { 7706185db85Sdougm char *nodetype = "optionset"; 7716185db85Sdougm /* have an optionset */ 7726185db85Sdougm sectype = NULL; 7736185db85Sdougm proto = strchr(buff, '_'); 7746185db85Sdougm if (proto != NULL) { 7756185db85Sdougm *proto++ = '\0'; 7766185db85Sdougm sectype = strchr(proto, '_'); 7776185db85Sdougm if (sectype != NULL) { 7786185db85Sdougm *sectype++ = '\0'; 7796185db85Sdougm nodetype = "security"; 7806185db85Sdougm } 7816185db85Sdougm } 7826185db85Sdougm ret = sa_extract_pgroup(node, handle, 7836185db85Sdougm handle->pg, 7846185db85Sdougm nodetype, 7856185db85Sdougm proto, sectype); 7866185db85Sdougm has_proto++; 7876185db85Sdougm } else if (strncmp(buff, 7886185db85Sdougm "security", 8) == 0) { 7896185db85Sdougm /* 7906185db85Sdougm * have a security (note that 7916185db85Sdougm * this should change in the 7926185db85Sdougm * future) 7936185db85Sdougm */ 7946185db85Sdougm proto = strchr(buff, '_'); 7956185db85Sdougm sectype = NULL; 7966185db85Sdougm if (proto != NULL) { 7976185db85Sdougm *proto++ = '\0'; 7986185db85Sdougm sectype = strchr(proto, '_'); 7996185db85Sdougm if (sectype != NULL) 8006185db85Sdougm *sectype++ = '\0'; 8016185db85Sdougm if (strcmp(proto, "default") == 0) 8026185db85Sdougm proto = NULL; 8036185db85Sdougm } 8046185db85Sdougm ret = sa_extract_pgroup(node, handle, 8056185db85Sdougm handle->pg, 8066185db85Sdougm "security", proto, 8076185db85Sdougm sectype); 8086185db85Sdougm has_proto++; 8096185db85Sdougm } 8106185db85Sdougm /* ignore everything else */ 8116185db85Sdougm } 8126185db85Sdougm } 8136185db85Sdougm } else { 8146185db85Sdougm ret = SA_NO_MEMORY; 8156185db85Sdougm } 8166185db85Sdougm /* 8176185db85Sdougm * Make sure we have a valid default group. 8186185db85Sdougm * On first boot, default won't have any 8196185db85Sdougm * protocols defined and won't be enabled (but 8206185db85Sdougm * should be). 8216185db85Sdougm */ 8226185db85Sdougm if (is_default) { 8236185db85Sdougm char *state = sa_get_group_attr((sa_group_t)node, 8246185db85Sdougm "state"); 8256185db85Sdougm char **protos; 8266185db85Sdougm int numprotos; 8276185db85Sdougm int i; 8286185db85Sdougm 8296185db85Sdougm if (state == NULL) { 8306185db85Sdougm /* set attribute to enabled */ 8316185db85Sdougm (void) sa_set_group_attr((sa_group_t)node, 8326185db85Sdougm "state", 8336185db85Sdougm "enabled"); 8346185db85Sdougm /* we can assume no protocols */ 8356185db85Sdougm numprotos = sa_get_protocols(&protos); 8366185db85Sdougm for (i = 0; i < numprotos; i++) 8376185db85Sdougm (void) sa_create_optionset((sa_group_t)node, 8386185db85Sdougm protos[i]); 8396185db85Sdougm if (numprotos > 0) 8406185db85Sdougm free(protos); 8416185db85Sdougm } else { 8426185db85Sdougm sa_free_attr_string(state); 8436185db85Sdougm } 8446185db85Sdougm } 8456185db85Sdougm /* do a second pass if shares were found */ 8466185db85Sdougm if (have_shares && 8476185db85Sdougm scf_iter_instance_pgs(iter, instance) == 0) { 8486185db85Sdougm while (scf_iter_next_pg(iter, handle->pg) > 0) { 8496185db85Sdougm /* 8506185db85Sdougm * have a pgroup so see if it is a 8516185db85Sdougm * share optionset 8526185db85Sdougm */ 8536185db85Sdougm err = scf_pg_get_name(handle->pg, buff, 8546185db85Sdougm scf_max_name_len); 8556185db85Sdougm if (err > 0) { 8566185db85Sdougm if (buff[0] == SA_SHARE_PG_PREFIX[0]) { 8576185db85Sdougm ret = sa_share_props_from_pgroup(node, 8586185db85Sdougm handle, 8596185db85Sdougm handle->pg, 8606185db85Sdougm buff); 8616185db85Sdougm } 8626185db85Sdougm } 8636185db85Sdougm } 8646185db85Sdougm } 8656185db85Sdougm } 8666185db85Sdougm } 8676185db85Sdougm } 8686185db85Sdougm } 8696185db85Sdougm if (iter != NULL) 8706185db85Sdougm scf_iter_destroy(iter); 8716185db85Sdougm if (buff != NULL) 8726185db85Sdougm free(buff); 8736185db85Sdougm return (ret); 8746185db85Sdougm } 8756185db85Sdougm 8766185db85Sdougm /* 8776185db85Sdougm * sa_extract_defaults(root, handle, instance) 8786185db85Sdougm * 8796185db85Sdougm * local function to find the default properties that live in the 8806185db85Sdougm * default instance's "operation" proprerty group. 8816185db85Sdougm */ 8826185db85Sdougm 8836185db85Sdougm static void 8846185db85Sdougm sa_extract_defaults(xmlNodePtr root, scfutilhandle_t *handle, 8856185db85Sdougm scf_instance_t *instance) 8866185db85Sdougm { 8876185db85Sdougm xmlNodePtr node; 8886185db85Sdougm scf_property_t *prop; 8896185db85Sdougm scf_value_t *value; 8906185db85Sdougm char *valuestr; 8916185db85Sdougm ssize_t vallen; 8926185db85Sdougm 8936185db85Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 8946185db85Sdougm prop = scf_property_create(handle->handle); 8956185db85Sdougm value = scf_value_create(handle->handle); 8966185db85Sdougm valuestr = malloc(vallen); 8976185db85Sdougm if (prop != NULL && value != NULL && vallen != NULL && 8986185db85Sdougm scf_instance_get_pg(instance, "operation", 8996185db85Sdougm handle->pg) == 0) { 9006185db85Sdougm if (scf_pg_get_property(handle->pg, 9016185db85Sdougm "legacy-timestamp", prop) == 0) { 9026185db85Sdougm /* found the property so get the value */ 9036185db85Sdougm if (scf_property_get_value(prop, value) == 0) { 9046185db85Sdougm if (scf_value_get_astring(value, valuestr, vallen) > 0) { 9056185db85Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"legacy", 9066185db85Sdougm NULL); 9076185db85Sdougm if (node != NULL) { 9086185db85Sdougm xmlSetProp(node, (xmlChar *)"timestamp", 9096185db85Sdougm (xmlChar *)valuestr); 9106185db85Sdougm xmlSetProp(node, (xmlChar *)"path", 9116185db85Sdougm (xmlChar *)SA_LEGACY_DFSTAB); 9126185db85Sdougm } 9136185db85Sdougm } 9146185db85Sdougm } 9156185db85Sdougm } 9166185db85Sdougm } 9176185db85Sdougm if (valuestr != NULL) 9186185db85Sdougm free(valuestr); 9196185db85Sdougm if (value != NULL) 9206185db85Sdougm scf_value_destroy(value); 9216185db85Sdougm if (prop != NULL) 9226185db85Sdougm scf_property_destroy(prop); 9236185db85Sdougm } 9246185db85Sdougm 9256185db85Sdougm 9266185db85Sdougm /* 9276185db85Sdougm * sa_get_config(handle, root, doc) 9286185db85Sdougm * 9296185db85Sdougm * walk the SMF repository for /network/shares/group and find all the 9306185db85Sdougm * instances. These become group names. Then add the XML structure 9316185db85Sdougm * below the groups based on property groups and properties. 9326185db85Sdougm */ 9336185db85Sdougm int 9346185db85Sdougm sa_get_config(scfutilhandle_t *handle, xmlNodePtr *root, xmlDocPtr *doc) 9356185db85Sdougm { 9366185db85Sdougm int ret = SA_OK; 9376185db85Sdougm scf_instance_t *instance; 9386185db85Sdougm scf_iter_t *iter; 9396185db85Sdougm char buff[BUFSIZ * 2]; 9406185db85Sdougm 9416185db85Sdougm *doc = xmlNewDoc((xmlChar *)"1.0"); 9426185db85Sdougm *root = xmlNewNode(NULL, (xmlChar *)"sharecfg"); 9436185db85Sdougm instance = scf_instance_create(handle->handle); 9446185db85Sdougm iter = scf_iter_create(handle->handle); 9456185db85Sdougm if (*doc != NULL && *root != NULL && instance != NULL && iter != NULL) { 9466185db85Sdougm xmlDocSetRootElement(*doc, *root); 9476185db85Sdougm if ((ret = scf_iter_service_instances(iter, 9486185db85Sdougm handle->service)) == 0) { 9496185db85Sdougm while ((ret = scf_iter_next_instance(iter, 9506185db85Sdougm instance)) > 0) { 9516185db85Sdougm if (scf_instance_get_name(instance, buff, 9526185db85Sdougm sizeof (buff)) > 0) { 9536185db85Sdougm if (strcmp(buff, "default") == 0) 9546185db85Sdougm sa_extract_defaults(*root, handle, instance); 9556185db85Sdougm ret = sa_extract_group(*root, handle, instance); 9566185db85Sdougm } 9576185db85Sdougm } 9586185db85Sdougm } 9596185db85Sdougm } else { 9606185db85Sdougm /* if we can't create the document, cleanup */ 9616185db85Sdougm if (*doc != NULL) 9626185db85Sdougm xmlFreeDoc(*doc); 9636185db85Sdougm if (*root != NULL) 9646185db85Sdougm xmlFreeNode(*root); 9656185db85Sdougm *doc = NULL; 9666185db85Sdougm *root = NULL; 9676185db85Sdougm } 9686185db85Sdougm /* always cleanup these */ 9696185db85Sdougm if (instance != NULL) 9706185db85Sdougm scf_instance_destroy(instance); 9716185db85Sdougm if (iter != NULL) 9726185db85Sdougm scf_iter_destroy(iter); 9736185db85Sdougm return (ret); 9746185db85Sdougm } 9756185db85Sdougm 9766185db85Sdougm /* 9776185db85Sdougm * sa_get_instance(handle, instance) 9786185db85Sdougm * 9796185db85Sdougm * get the instance of the group service. This is actually the 9806185db85Sdougm * specific group name. The instance is needed for all property and 9816185db85Sdougm * control operations. 9826185db85Sdougm */ 9836185db85Sdougm 9846185db85Sdougm int 9856185db85Sdougm sa_get_instance(scfutilhandle_t *handle, char *instname) 9866185db85Sdougm { 9876185db85Sdougm if (scf_service_get_instance(handle->service, instname, 9886185db85Sdougm handle->instance) != 0) { 9896185db85Sdougm return (SA_NO_SUCH_GROUP); 9906185db85Sdougm } 9916185db85Sdougm return (SA_OK); 9926185db85Sdougm } 9936185db85Sdougm 9946185db85Sdougm /* 9956185db85Sdougm * sa_create_instance(handle, instname) 9966185db85Sdougm * 9976185db85Sdougm * Create a new SMF service instance. There can only be one with a 9986185db85Sdougm * given name. 9996185db85Sdougm */ 10006185db85Sdougm 10016185db85Sdougm int 10026185db85Sdougm sa_create_instance(scfutilhandle_t *handle, char *instname) 10036185db85Sdougm { 10046185db85Sdougm int ret = SA_OK; 10056185db85Sdougm char instance[SA_GROUP_INST_LEN]; 10066185db85Sdougm if (scf_service_add_instance(handle->service, instname, 10076185db85Sdougm handle->instance) != 0) { 10086185db85Sdougm /* better error returns need to be added based on real error */ 10096185db85Sdougm if (scf_error() == SCF_ERROR_PERMISSION_DENIED) 10106185db85Sdougm ret = SA_NO_PERMISSION; 10116185db85Sdougm else 10126185db85Sdougm ret = SA_DUPLICATE_NAME; 10136185db85Sdougm } else { 10146185db85Sdougm /* have the service created, so enable it */ 10156185db85Sdougm (void) snprintf(instance, sizeof (instance), "%s:%s", 10166185db85Sdougm SA_SVC_FMRI_BASE, instname); 10176185db85Sdougm (void) smf_enable_instance(instance, 0); 10186185db85Sdougm } 10196185db85Sdougm return (ret); 10206185db85Sdougm } 10216185db85Sdougm 10226185db85Sdougm /* 10236185db85Sdougm * sa_delete_instance(handle, instname) 10246185db85Sdougm * 10256185db85Sdougm * When a group goes away, we also remove the service instance. 10266185db85Sdougm */ 10276185db85Sdougm 10286185db85Sdougm int 10296185db85Sdougm sa_delete_instance(scfutilhandle_t *handle, char *instname) 10306185db85Sdougm { 10316185db85Sdougm int ret; 10326185db85Sdougm 10336185db85Sdougm if (strcmp(instname, "default") == 0) { 10346185db85Sdougm ret = SA_NO_PERMISSION; 10356185db85Sdougm } else { 10366185db85Sdougm if ((ret = sa_get_instance(handle, instname)) == SA_OK) { 10376185db85Sdougm if (scf_instance_delete(handle->instance) != 0) 10386185db85Sdougm /* need better analysis */ 10396185db85Sdougm ret = SA_NO_PERMISSION; 10406185db85Sdougm } 10416185db85Sdougm } 10426185db85Sdougm return (ret); 10436185db85Sdougm } 10446185db85Sdougm 10456185db85Sdougm /* 10466185db85Sdougm * sa_create_pgroup(handle, pgroup) 10476185db85Sdougm * 10486185db85Sdougm * create a new property group 10496185db85Sdougm */ 10506185db85Sdougm 10516185db85Sdougm int 10526185db85Sdougm sa_create_pgroup(scfutilhandle_t *handle, char *pgroup) 10536185db85Sdougm { 10546185db85Sdougm int ret = SA_OK; 10556185db85Sdougm /* 10566185db85Sdougm * only create a handle if it doesn't exist. It is ok to exist 10576185db85Sdougm * since the pg handle will be set as a side effect. 10586185db85Sdougm */ 10596185db85Sdougm if (handle->pg == NULL) { 10606185db85Sdougm handle->pg = scf_pg_create(handle->handle); 10616185db85Sdougm } 10626185db85Sdougm /* 10636185db85Sdougm * if the pgroup exists, we are done. If it doesn't, then we 10646185db85Sdougm * need to actually add one to the service instance. 10656185db85Sdougm */ 10666185db85Sdougm if (scf_instance_get_pg(handle->instance, 10676185db85Sdougm pgroup, handle->pg) != 0) { 10686185db85Sdougm /* doesn't exist so create one */ 10696185db85Sdougm if (scf_instance_add_pg(handle->instance, pgroup, 10706185db85Sdougm SCF_GROUP_APPLICATION, 0, 10716185db85Sdougm handle->pg) != 0) { 10726185db85Sdougm switch (scf_error()) { 10736185db85Sdougm case SCF_ERROR_PERMISSION_DENIED: 10746185db85Sdougm ret = SA_NO_PERMISSION; 10756185db85Sdougm break; 10766185db85Sdougm default: 10776185db85Sdougm ret = SA_SYSTEM_ERR; 10786185db85Sdougm break; 10796185db85Sdougm } 10806185db85Sdougm } 10816185db85Sdougm } 10826185db85Sdougm return (ret); 10836185db85Sdougm } 10846185db85Sdougm 10856185db85Sdougm /* 10866185db85Sdougm * sa_delete_pgroup(handle, pgroup) 10876185db85Sdougm * 10886185db85Sdougm * remove the property group from the current instance of the service, 10896185db85Sdougm * but only if it actually exists. 10906185db85Sdougm */ 10916185db85Sdougm 10926185db85Sdougm int 10936185db85Sdougm sa_delete_pgroup(scfutilhandle_t *handle, char *pgroup) 10946185db85Sdougm { 10956185db85Sdougm int ret = SA_OK; 10966185db85Sdougm /* 10976185db85Sdougm * only delete if it does exist. 10986185db85Sdougm */ 10996185db85Sdougm if (scf_instance_get_pg(handle->instance, 11006185db85Sdougm pgroup, handle->pg) == 0) { 11016185db85Sdougm /* does exist so delete it */ 11026185db85Sdougm if (scf_pg_delete(handle->pg) != 0) { 11036185db85Sdougm ret = SA_SYSTEM_ERR; 11046185db85Sdougm } 11056185db85Sdougm } else { 11066185db85Sdougm ret = SA_SYSTEM_ERR; 11076185db85Sdougm } 11086185db85Sdougm if (ret == SA_SYSTEM_ERR && 11096185db85Sdougm scf_error() == SCF_ERROR_PERMISSION_DENIED) { 11106185db85Sdougm ret = SA_NO_PERMISSION; 11116185db85Sdougm } 11126185db85Sdougm return (ret); 11136185db85Sdougm } 11146185db85Sdougm 11156185db85Sdougm /* 11166185db85Sdougm * sa_start_transaction(handle, pgroup) 11176185db85Sdougm * 11186185db85Sdougm * Start an SMF transaction so we can deal with properties. it would 11196185db85Sdougm * be nice to not have to expose this, but we have to in order to 11206185db85Sdougm * optimize. 11216185db85Sdougm * 11226185db85Sdougm * Basic model is to hold the transaction in the handle and allow 11236185db85Sdougm * property adds/deletes/updates to be added then close the 11246185db85Sdougm * transaction (or abort). There may eventually be a need to handle 11256185db85Sdougm * other types of transaction mechanisms but we don't do that now. 11266185db85Sdougm * 11276185db85Sdougm * An sa_start_transaction must be followed by either an 11286185db85Sdougm * sa_end_transaction or sa_abort_transaction before another 11296185db85Sdougm * sa_start_transaction can be done. 11306185db85Sdougm */ 11316185db85Sdougm 11326185db85Sdougm int 11336185db85Sdougm sa_start_transaction(scfutilhandle_t *handle, char *propgroup) 11346185db85Sdougm { 11356185db85Sdougm int ret = SA_OK; 11366185db85Sdougm /* 11376185db85Sdougm * lookup the property group and create it if it doesn't already 11386185db85Sdougm * exist. 11396185db85Sdougm */ 11406185db85Sdougm if (handle->scf_state == SCH_STATE_INIT) { 11416185db85Sdougm ret = sa_create_pgroup(handle, propgroup); 11426185db85Sdougm if (ret == SA_OK) { 11436185db85Sdougm handle->trans = scf_transaction_create(handle->handle); 11446185db85Sdougm if (handle->trans != NULL) { 11456185db85Sdougm if (scf_transaction_start(handle->trans, handle->pg) != 0) { 11466185db85Sdougm ret = SA_SYSTEM_ERR; 11476185db85Sdougm } 11486185db85Sdougm if (ret != SA_OK) { 11496185db85Sdougm scf_transaction_destroy(handle->trans); 11506185db85Sdougm handle->trans = NULL; 11516185db85Sdougm } 11526185db85Sdougm } else { 11536185db85Sdougm ret = SA_SYSTEM_ERR; 11546185db85Sdougm } 11556185db85Sdougm } 11566185db85Sdougm } 11576185db85Sdougm if (ret == SA_SYSTEM_ERR && 11586185db85Sdougm scf_error() == SCF_ERROR_PERMISSION_DENIED) { 11596185db85Sdougm ret = SA_NO_PERMISSION; 11606185db85Sdougm } 11616185db85Sdougm return (ret); 11626185db85Sdougm } 11636185db85Sdougm 11646185db85Sdougm /* 11656185db85Sdougm * sa_end_transaction(handle) 11666185db85Sdougm * 11676185db85Sdougm * Commit the changes that were added to the transaction in the 11686185db85Sdougm * handle. Do all necessary cleanup. 11696185db85Sdougm */ 11706185db85Sdougm 11716185db85Sdougm int 11726185db85Sdougm sa_end_transaction(scfutilhandle_t *handle) 11736185db85Sdougm { 11746185db85Sdougm int ret = SA_OK; 11756185db85Sdougm 11766185db85Sdougm if (handle->trans == NULL) { 11776185db85Sdougm ret = SA_SYSTEM_ERR; 11786185db85Sdougm } else { 11796185db85Sdougm if (scf_transaction_commit(handle->trans) < 0) 11806185db85Sdougm ret = SA_SYSTEM_ERR; 11816185db85Sdougm scf_transaction_destroy_children(handle->trans); 11826185db85Sdougm scf_transaction_destroy(handle->trans); 11836185db85Sdougm handle->trans = NULL; 11846185db85Sdougm } 11856185db85Sdougm return (ret); 11866185db85Sdougm } 11876185db85Sdougm 11886185db85Sdougm /* 11896185db85Sdougm * sa_abort_transaction(handle) 11906185db85Sdougm * 11916185db85Sdougm * Abort the changes that were added to the transaction in the 11926185db85Sdougm * handle. Do all necessary cleanup. 11936185db85Sdougm */ 11946185db85Sdougm 11956185db85Sdougm void 11966185db85Sdougm sa_abort_transaction(scfutilhandle_t *handle) 11976185db85Sdougm { 11986185db85Sdougm if (handle->trans != NULL) { 11996185db85Sdougm scf_transaction_reset_all(handle->trans); 12006185db85Sdougm scf_transaction_destroy_children(handle->trans); 12016185db85Sdougm scf_transaction_destroy(handle->trans); 12026185db85Sdougm handle->trans = NULL; 12036185db85Sdougm } 12046185db85Sdougm } 12056185db85Sdougm 12066185db85Sdougm /* 12076185db85Sdougm * sa_set_property(handle, prop, value) 12086185db85Sdougm * 12096185db85Sdougm * set a property transaction entry into the pending SMF transaction. 12106185db85Sdougm */ 12116185db85Sdougm 12126185db85Sdougm int 12136185db85Sdougm sa_set_property(scfutilhandle_t *handle, char *propname, char *valstr) 12146185db85Sdougm { 12156185db85Sdougm int ret = SA_OK; 12166185db85Sdougm scf_value_t *value; 12176185db85Sdougm scf_transaction_entry_t *entry; 12186185db85Sdougm /* 12196185db85Sdougm * properties must be set in transactions and don't take 12206185db85Sdougm * effect until the transaction has been ended/committed. 12216185db85Sdougm */ 12226185db85Sdougm value = scf_value_create(handle->handle); 12236185db85Sdougm entry = scf_entry_create(handle->handle); 12246185db85Sdougm if (value != NULL && entry != NULL) { 12256185db85Sdougm if (scf_transaction_property_change(handle->trans, entry, 12266185db85Sdougm propname, 12276185db85Sdougm SCF_TYPE_ASTRING) == 0 || 12286185db85Sdougm scf_transaction_property_new(handle->trans, entry, 12296185db85Sdougm propname, 12306185db85Sdougm SCF_TYPE_ASTRING) == 0) { 12316185db85Sdougm if (scf_value_set_astring(value, valstr) == 0) { 12326185db85Sdougm if (scf_entry_add_value(entry, value) != 0) { 12336185db85Sdougm ret = SA_SYSTEM_ERR; 12346185db85Sdougm scf_value_destroy(value); 12356185db85Sdougm } 12366185db85Sdougm /* the value is in the transaction */ 12376185db85Sdougm value = NULL; 12386185db85Sdougm } else { 12396185db85Sdougm /* value couldn't be constructed */ 12406185db85Sdougm ret = SA_SYSTEM_ERR; 12416185db85Sdougm } 12426185db85Sdougm /* the entry is in the transaction */ 12436185db85Sdougm entry = NULL; 12446185db85Sdougm } else { 12456185db85Sdougm ret = SA_SYSTEM_ERR; 12466185db85Sdougm } 12476185db85Sdougm } else { 12486185db85Sdougm ret = SA_SYSTEM_ERR; 12496185db85Sdougm } 12506185db85Sdougm if (ret == SA_SYSTEM_ERR) { 12516185db85Sdougm switch (scf_error()) { 12526185db85Sdougm case SCF_ERROR_PERMISSION_DENIED: 12536185db85Sdougm ret = SA_NO_PERMISSION; 12546185db85Sdougm break; 12556185db85Sdougm } 12566185db85Sdougm } 12576185db85Sdougm /* 12586185db85Sdougm * cleanup if there were any errors that didn't leave these 12596185db85Sdougm * values where they would be cleaned up later. 12606185db85Sdougm */ 12616185db85Sdougm if (value != NULL) 12626185db85Sdougm scf_value_destroy(value); 12636185db85Sdougm if (entry != NULL) 12646185db85Sdougm scf_entry_destroy(entry); 12656185db85Sdougm return (ret); 12666185db85Sdougm } 12676185db85Sdougm 12686185db85Sdougm /* 12696185db85Sdougm * sa_commit_share(handle, group, share) 12706185db85Sdougm * 12716185db85Sdougm * commit this share to the repository. 12726185db85Sdougm * properties are added if they exist but can be added later. 12736185db85Sdougm * Need to add to dfstab and sharetab, if appropriate. 12746185db85Sdougm */ 12756185db85Sdougm int 12766185db85Sdougm sa_commit_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share) 12776185db85Sdougm { 12786185db85Sdougm int ret = SA_OK; 12796185db85Sdougm char *groupname; 12806185db85Sdougm char *name; 12816185db85Sdougm char *resource; 12826185db85Sdougm char *description; 12836185db85Sdougm char *sharename; 12846185db85Sdougm ssize_t proplen; 12856185db85Sdougm char *propstring; 12866185db85Sdougm 12876185db85Sdougm /* 12886185db85Sdougm * don't commit in the zfs group. We do commit legacy 12896185db85Sdougm * (default) and all other groups/shares. ZFS is handled 12906185db85Sdougm * through the ZFS configuration rather than SMF. 12916185db85Sdougm */ 12926185db85Sdougm 12936185db85Sdougm groupname = sa_get_group_attr(group, "name"); 12946185db85Sdougm if (groupname != NULL) { 12956185db85Sdougm if (strcmp(groupname, "zfs") == 0) { 12966185db85Sdougm /* 12976185db85Sdougm * adding to the ZFS group will result in the sharenfs 12986185db85Sdougm * property being set but we don't want to do anything 12996185db85Sdougm * SMF related at this point. 13006185db85Sdougm */ 13016185db85Sdougm sa_free_attr_string(groupname); 13026185db85Sdougm return (ret); 13036185db85Sdougm } 13046185db85Sdougm } 13056185db85Sdougm 13066185db85Sdougm proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 13076185db85Sdougm propstring = malloc(proplen); 13086185db85Sdougm if (propstring == NULL) 13096185db85Sdougm ret = SA_NO_MEMORY; 13106185db85Sdougm 13116185db85Sdougm if (groupname != NULL && ret == SA_OK) { 13126185db85Sdougm ret = sa_get_instance(handle, groupname); 13136185db85Sdougm sa_free_attr_string(groupname); 13146185db85Sdougm groupname = NULL; 13156185db85Sdougm sharename = sa_get_share_attr(share, "id"); 13166185db85Sdougm if (sharename == NULL) { 13176185db85Sdougm /* slipped by */ 13186185db85Sdougm char shname[SA_SHARE_UUID_BUFLEN]; 13196185db85Sdougm generate_unique_sharename(shname); 13206185db85Sdougm xmlSetProp((xmlNodePtr)share, (xmlChar *)"id", 13216185db85Sdougm (xmlChar *)shname); 13226185db85Sdougm sharename = strdup(shname); 13236185db85Sdougm } 13246185db85Sdougm if (sharename != NULL) { 1325*f345c0beSdougm sigset_t old, new; 13266185db85Sdougm /* 1327*f345c0beSdougm * have a share name allocated so create a pgroup for 1328*f345c0beSdougm * it. It may already exist, but that is OK. In order 1329*f345c0beSdougm * to avoid creating a share pgroup that doesn't have 1330*f345c0beSdougm * a path property, block signals around the critical 1331*f345c0beSdougm * region of creating the share pgroup and props. 13326185db85Sdougm */ 1333*f345c0beSdougm (void) sigprocmask(SIG_BLOCK, NULL, &new); 1334*f345c0beSdougm (void) sigaddset(&new, SIGHUP); 1335*f345c0beSdougm (void) sigaddset(&new, SIGINT); 1336*f345c0beSdougm (void) sigaddset(&new, SIGQUIT); 1337*f345c0beSdougm (void) sigaddset(&new, SIGTSTP); 1338*f345c0beSdougm (void) sigprocmask(SIG_SETMASK, &new, &old); 1339*f345c0beSdougm 13406185db85Sdougm ret = sa_create_pgroup(handle, sharename); 13416185db85Sdougm if (ret == SA_OK) { 13426185db85Sdougm /* 13436185db85Sdougm * now start the transaction for the 13446185db85Sdougm * properties that define this share. They may 13456185db85Sdougm * exist so attempt to update before create. 13466185db85Sdougm */ 13476185db85Sdougm ret = sa_start_transaction(handle, sharename); 13486185db85Sdougm } 13496185db85Sdougm if (ret == SA_OK) { 13506185db85Sdougm name = sa_get_share_attr(share, "path"); 13516185db85Sdougm if (name != NULL) { 13526185db85Sdougm /* there needs to be a path for a share to exist */ 13536185db85Sdougm ret = sa_set_property(handle, "path", name); 13546185db85Sdougm sa_free_attr_string(name); 13556185db85Sdougm } else { 13566185db85Sdougm ret = SA_NO_MEMORY; 13576185db85Sdougm } 13586185db85Sdougm } 13596185db85Sdougm if (ret == SA_OK) { 13606185db85Sdougm resource = sa_get_share_attr(share, "resource"); 13616185db85Sdougm if (resource != NULL) { 13626185db85Sdougm ret = sa_set_property(handle, "resource", resource); 13636185db85Sdougm sa_free_attr_string(resource); 13646185db85Sdougm } 13656185db85Sdougm } 13666185db85Sdougm if (ret == SA_OK) { 13676185db85Sdougm description = sa_get_share_description(share); 13686185db85Sdougm if (description != NULL) { 13696185db85Sdougm ret = sa_set_property(handle, "description", 13706185db85Sdougm description); 13716185db85Sdougm sa_free_share_description(description); 13726185db85Sdougm } 13736185db85Sdougm } 13746185db85Sdougm /* make sure we cleanup the transaction */ 13756185db85Sdougm if (ret == SA_OK) { 13766185db85Sdougm ret = sa_end_transaction(handle); 13776185db85Sdougm } else { 13786185db85Sdougm sa_abort_transaction(handle); 13796185db85Sdougm } 1380*f345c0beSdougm 1381*f345c0beSdougm (void) sigprocmask(SIG_SETMASK, &old, NULL); 1382*f345c0beSdougm 13836185db85Sdougm free(sharename); 13846185db85Sdougm } 13856185db85Sdougm } 13866185db85Sdougm if (ret == SA_SYSTEM_ERR) { 13876185db85Sdougm int err = scf_error(); 13886185db85Sdougm if (err == SCF_ERROR_PERMISSION_DENIED) 13896185db85Sdougm ret = SA_NO_PERMISSION; 13906185db85Sdougm } 13916185db85Sdougm if (propstring != NULL) 13926185db85Sdougm free(propstring); 13936185db85Sdougm if (groupname != NULL) 13946185db85Sdougm sa_free_attr_string(groupname); 13956185db85Sdougm 13966185db85Sdougm return (ret); 13976185db85Sdougm } 13986185db85Sdougm 13996185db85Sdougm /* 14006185db85Sdougm * sa_delete_share(handle, group, share) 14016185db85Sdougm * 14026185db85Sdougm * remove the specified share from the group (and service instance). 14036185db85Sdougm */ 14046185db85Sdougm 14056185db85Sdougm int 14066185db85Sdougm sa_delete_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share) 14076185db85Sdougm { 14086185db85Sdougm int ret = SA_OK; 14096185db85Sdougm char *groupname = NULL; 14106185db85Sdougm char *shareid = NULL; 14116185db85Sdougm sa_optionset_t opt; 14126185db85Sdougm sa_security_t sec; 14136185db85Sdougm ssize_t proplen; 14146185db85Sdougm char *propstring; 14156185db85Sdougm 14166185db85Sdougm proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 14176185db85Sdougm propstring = malloc(proplen); 14186185db85Sdougm if (propstring == NULL) 14196185db85Sdougm ret = SA_NO_MEMORY; 14206185db85Sdougm 14216185db85Sdougm if (ret == SA_OK) { 14226185db85Sdougm groupname = sa_get_group_attr(group, "name"); 14236185db85Sdougm shareid = sa_get_share_attr(share, "id"); 14246185db85Sdougm if (groupname != NULL && shareid != NULL) { 14256185db85Sdougm ret = sa_get_instance(handle, groupname); 14266185db85Sdougm if (ret == SA_OK) { 14276185db85Sdougm /* if a share has properties, remove them */ 14286185db85Sdougm ret = sa_delete_pgroup(handle, shareid); 14296185db85Sdougm for (opt = sa_get_optionset(share, NULL); opt != NULL; 14306185db85Sdougm opt = sa_get_next_optionset(opt)) { 14316185db85Sdougm char *proto; 14326185db85Sdougm proto = sa_get_optionset_attr(opt, "type"); 14336185db85Sdougm if (proto != NULL) { 14346185db85Sdougm (void) snprintf(propstring, proplen, "%s_%s", 14356185db85Sdougm shareid, proto); 14366185db85Sdougm ret = sa_delete_pgroup(handle, propstring); 14376185db85Sdougm sa_free_attr_string(proto); 14386185db85Sdougm } else { 14396185db85Sdougm ret = SA_NO_MEMORY; 14406185db85Sdougm } 14416185db85Sdougm } 14426185db85Sdougm /* 14436185db85Sdougm * if a share has security/negotiable 14446185db85Sdougm * properties, remove them. 14456185db85Sdougm */ 14466185db85Sdougm for (sec = sa_get_security(share, NULL, NULL); sec != NULL; 14476185db85Sdougm sec = sa_get_next_security(sec)) { 14486185db85Sdougm char *proto; 14496185db85Sdougm char *sectype; 14506185db85Sdougm proto = sa_get_security_attr(sec, "type"); 14516185db85Sdougm sectype = sa_get_security_attr(sec, "sectype"); 14526185db85Sdougm if (proto != NULL && sectype != NULL) { 14536185db85Sdougm (void) snprintf(propstring, proplen, "%s_%s_%s", 14546185db85Sdougm shareid, 14556185db85Sdougm proto, sectype); 14566185db85Sdougm ret = sa_delete_pgroup(handle, propstring); 14576185db85Sdougm } else { 14586185db85Sdougm ret = SA_NO_MEMORY; 14596185db85Sdougm } 14606185db85Sdougm if (proto != NULL) 14616185db85Sdougm sa_free_attr_string(proto); 14626185db85Sdougm if (sectype != NULL) 14636185db85Sdougm sa_free_attr_string(sectype); 14646185db85Sdougm } 14656185db85Sdougm } 14666185db85Sdougm } else { 14676185db85Sdougm ret = SA_CONFIG_ERR; 14686185db85Sdougm } 14696185db85Sdougm } 14706185db85Sdougm if (groupname != NULL) 14716185db85Sdougm sa_free_attr_string(groupname); 14726185db85Sdougm if (shareid != NULL) 14736185db85Sdougm sa_free_attr_string(shareid); 14746185db85Sdougm if (propstring != NULL) 14756185db85Sdougm free(propstring); 14766185db85Sdougm 14776185db85Sdougm return (ret); 14786185db85Sdougm } 1479