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 /* 23f345c0beSdougm * 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> 41f345c0beSdougm #include <signal.h> 426185db85Sdougm 436185db85Sdougm ssize_t scf_max_name_len; 446185db85Sdougm extern struct sa_proto_plugin *sap_proto_list; 45549ec3ffSdougm extern sa_handle_impl_t get_handle_for_root(xmlNodePtr); 466185db85Sdougm 476185db85Sdougm /* 486185db85Sdougm * The SMF facility uses some properties that must exist. We want to 496185db85Sdougm * skip over these when processing protocol options. 506185db85Sdougm */ 516185db85Sdougm static char *skip_props[] = { 526185db85Sdougm "modify_authorization", 536185db85Sdougm "action_authorization", 546185db85Sdougm "value_authorization", 556185db85Sdougm NULL 566185db85Sdougm }; 576185db85Sdougm 586185db85Sdougm /* 596185db85Sdougm * sa_scf_fini(handle) 606185db85Sdougm * 61*25a68471Sdougm * Must be called when done. Called with the handle allocated in 626185db85Sdougm * sa_scf_init(), it cleans up the state and frees any SCF resources 636185db85Sdougm * still in use. Called by sa_fini(). 646185db85Sdougm */ 656185db85Sdougm 666185db85Sdougm void 676185db85Sdougm sa_scf_fini(scfutilhandle_t *handle) 686185db85Sdougm { 696185db85Sdougm if (handle != NULL) { 706185db85Sdougm int unbind = 0; 716185db85Sdougm if (handle->scope != NULL) { 726185db85Sdougm unbind = 1; 736185db85Sdougm scf_scope_destroy(handle->scope); 746185db85Sdougm } 75a3351425Sdougm if (handle->instance != NULL) 76a3351425Sdougm scf_instance_destroy(handle->instance); 776185db85Sdougm if (handle->service != NULL) 786185db85Sdougm scf_service_destroy(handle->service); 796185db85Sdougm if (handle->pg != NULL) 806185db85Sdougm scf_pg_destroy(handle->pg); 816185db85Sdougm if (handle->handle != NULL) { 826185db85Sdougm handle->scf_state = SCH_STATE_UNINIT; 836185db85Sdougm if (unbind) 846185db85Sdougm (void) scf_handle_unbind(handle->handle); 856185db85Sdougm scf_handle_destroy(handle->handle); 866185db85Sdougm } 876185db85Sdougm free(handle); 886185db85Sdougm } 896185db85Sdougm } 906185db85Sdougm 916185db85Sdougm /* 926185db85Sdougm * sa_scf_init() 936185db85Sdougm * 94*25a68471Sdougm * Must be called before using any of the SCF functions. Called by 956185db85Sdougm * sa_init() during the API setup. 966185db85Sdougm */ 976185db85Sdougm 986185db85Sdougm scfutilhandle_t * 99549ec3ffSdougm sa_scf_init(sa_handle_impl_t ihandle) 1006185db85Sdougm { 1016185db85Sdougm scfutilhandle_t *handle; 1026185db85Sdougm 1036185db85Sdougm scf_max_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH); 1046185db85Sdougm if (scf_max_name_len <= 0) 1056185db85Sdougm scf_max_name_len = SA_MAX_NAME_LEN + 1; 1066185db85Sdougm 1076185db85Sdougm handle = calloc(1, sizeof (scfutilhandle_t)); 108*25a68471Sdougm if (handle == NULL) 109*25a68471Sdougm return (handle); 110*25a68471Sdougm 111549ec3ffSdougm ihandle->scfhandle = handle; 1126185db85Sdougm handle->scf_state = SCH_STATE_INITIALIZING; 1136185db85Sdougm handle->handle = scf_handle_create(SCF_VERSION); 114*25a68471Sdougm if (handle->handle == NULL) { 115*25a68471Sdougm free(handle); 116*25a68471Sdougm handle = NULL; 117*25a68471Sdougm (void) printf("libshare could not access SMF repository: %s\n", 118*25a68471Sdougm scf_strerror(scf_error())); 119*25a68471Sdougm return (handle); 120*25a68471Sdougm } 121*25a68471Sdougm if (scf_handle_bind(handle->handle) != 0) 122*25a68471Sdougm goto err; 123*25a68471Sdougm 1246185db85Sdougm handle->scope = scf_scope_create(handle->handle); 1256185db85Sdougm handle->service = scf_service_create(handle->handle); 1266185db85Sdougm handle->pg = scf_pg_create(handle->handle); 127a3351425Sdougm 128*25a68471Sdougm /* Make sure we have sufficient SMF running */ 1296185db85Sdougm handle->instance = scf_instance_create(handle->handle); 130a3351425Sdougm if (handle->scope == NULL || handle->service == NULL || 131a3351425Sdougm handle->pg == NULL || handle->instance == NULL) 132a3351425Sdougm goto err; 1336185db85Sdougm if (scf_handle_get_scope(handle->handle, 134*25a68471Sdougm SCF_SCOPE_LOCAL, handle->scope) != 0) 1356185db85Sdougm goto err; 136*25a68471Sdougm if (scf_scope_get_service(handle->scope, 137*25a68471Sdougm SA_GROUP_SVC_NAME, handle->service) != 0) 138*25a68471Sdougm goto err; 139*25a68471Sdougm 1406185db85Sdougm handle->scf_state = SCH_STATE_INIT; 1416185db85Sdougm if (sa_get_instance(handle, "default") != SA_OK) { 1426185db85Sdougm char **protolist; 1436185db85Sdougm int numprotos, i; 1446185db85Sdougm sa_group_t defgrp; 145*25a68471Sdougm defgrp = sa_create_group((sa_handle_t)ihandle, "default", NULL); 1466185db85Sdougm if (defgrp != NULL) { 147*25a68471Sdougm numprotos = sa_get_protocols( 148*25a68471Sdougm &protolist); 149*25a68471Sdougm for (i = 0; i < numprotos; i++) 1506185db85Sdougm (void) sa_create_optionset(defgrp, 1516185db85Sdougm protolist[i]); 1526185db85Sdougm if (protolist != NULL) 1536185db85Sdougm free(protolist); 1546185db85Sdougm } 1556185db85Sdougm } 156*25a68471Sdougm 1576185db85Sdougm return (handle); 1586185db85Sdougm 159*25a68471Sdougm /* Error handling/unwinding */ 1606185db85Sdougm err: 1616185db85Sdougm (void) sa_scf_fini(handle); 1626185db85Sdougm (void) printf("libshare SMF initialization problem: %s\n", 1636185db85Sdougm scf_strerror(scf_error())); 1646185db85Sdougm return (NULL); 1656185db85Sdougm } 1666185db85Sdougm 1676185db85Sdougm /* 1686185db85Sdougm * get_scf_limit(name) 1696185db85Sdougm * 1706185db85Sdougm * Since we use scf_limit a lot and do the same check and return the 1716185db85Sdougm * same value if it fails, implement as a function for code 1726185db85Sdougm * simplification. Basically, if name isn't found, return MAXPATHLEN 1736185db85Sdougm * (1024) so we have a reasonable default buffer size. 1746185db85Sdougm */ 1756185db85Sdougm static ssize_t 1766185db85Sdougm get_scf_limit(uint32_t name) 1776185db85Sdougm { 1786185db85Sdougm ssize_t vallen; 1796185db85Sdougm 1806185db85Sdougm vallen = scf_limit(name); 1816185db85Sdougm if (vallen == (ssize_t)-1) 1826185db85Sdougm vallen = MAXPATHLEN; 1836185db85Sdougm return (vallen); 1846185db85Sdougm } 1856185db85Sdougm 1866185db85Sdougm /* 1876185db85Sdougm * skip_property(name) 1886185db85Sdougm * 189*25a68471Sdougm * Internal function to check to see if a property is an SMF magic 1906185db85Sdougm * property that needs to be skipped. 1916185db85Sdougm */ 1926185db85Sdougm static int 1936185db85Sdougm skip_property(char *name) 1946185db85Sdougm { 1956185db85Sdougm int i; 1966185db85Sdougm 1976185db85Sdougm for (i = 0; skip_props[i] != NULL; i++) 1986185db85Sdougm if (strcmp(name, skip_props[i]) == 0) 1996185db85Sdougm return (1); 2006185db85Sdougm return (0); 2016185db85Sdougm } 2026185db85Sdougm 2036185db85Sdougm /* 2046185db85Sdougm * generate_unique_sharename(sharename) 2056185db85Sdougm * 2066185db85Sdougm * Shares are represented in SMF as property groups. Due to share 2076185db85Sdougm * paths containing characters that are not allowed in SMF names and 2086185db85Sdougm * the need to be unique, we use UUIDs to construct a unique name. 2096185db85Sdougm */ 2106185db85Sdougm 2116185db85Sdougm static void 2126185db85Sdougm generate_unique_sharename(char *sharename) 2136185db85Sdougm { 2146185db85Sdougm uuid_t uuid; 2156185db85Sdougm 2166185db85Sdougm uuid_generate(uuid); 2176185db85Sdougm (void) strcpy(sharename, "S-"); 2186185db85Sdougm uuid_unparse(uuid, sharename + 2); 2196185db85Sdougm } 2206185db85Sdougm 2216185db85Sdougm /* 2226185db85Sdougm * valid_protocol(proto) 2236185db85Sdougm * 224*25a68471Sdougm * Check to see if the specified protocol is a valid one for the 2256185db85Sdougm * general sharemgr facility. We determine this by checking which 2266185db85Sdougm * plugin protocols were found. 2276185db85Sdougm */ 2286185db85Sdougm 2296185db85Sdougm static int 2306185db85Sdougm valid_protocol(char *proto) 2316185db85Sdougm { 2326185db85Sdougm struct sa_proto_plugin *plugin; 2336185db85Sdougm for (plugin = sap_proto_list; plugin != NULL; 2346185db85Sdougm plugin = plugin->plugin_next) 2356185db85Sdougm if (strcmp(proto, plugin->plugin_ops->sa_protocol) == 0) 2366185db85Sdougm return (1); 2376185db85Sdougm return (0); 2386185db85Sdougm } 2396185db85Sdougm 2406185db85Sdougm /* 2416185db85Sdougm * sa_extract_pgroup(root, handle, pg, nodetype, proto, sectype) 2426185db85Sdougm * 243*25a68471Sdougm * Extract the name property group and create the specified type of 2446185db85Sdougm * node on the provided group. type will be optionset or security. 2456185db85Sdougm */ 2466185db85Sdougm 2476185db85Sdougm static int 2486185db85Sdougm sa_extract_pgroup(xmlNodePtr root, scfutilhandle_t *handle, 2496185db85Sdougm scf_propertygroup_t *pg, 2506185db85Sdougm char *nodetype, char *proto, char *sectype) 2516185db85Sdougm { 2526185db85Sdougm xmlNodePtr node; 2536185db85Sdougm scf_iter_t *iter; 2546185db85Sdougm scf_property_t *prop; 2556185db85Sdougm scf_value_t *value; 2566185db85Sdougm char *name; 2576185db85Sdougm char *valuestr; 2586185db85Sdougm ssize_t vallen; 2596185db85Sdougm int ret = SA_OK; 2606185db85Sdougm 2616185db85Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 2626185db85Sdougm 2636185db85Sdougm node = xmlNewChild(root, NULL, (xmlChar *)nodetype, NULL); 264*25a68471Sdougm if (node == NULL) 265*25a68471Sdougm return (ret); 266*25a68471Sdougm 2676185db85Sdougm if (proto != NULL) 2686185db85Sdougm xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto); 2696185db85Sdougm if (sectype != NULL) 2706185db85Sdougm xmlSetProp(node, (xmlChar *)"sectype", (xmlChar *)sectype); 2716185db85Sdougm /* 272*25a68471Sdougm * Have node to work with so iterate over the properties 2736185db85Sdougm * in the pg and create option sub nodes. 2746185db85Sdougm */ 2756185db85Sdougm iter = scf_iter_create(handle->handle); 2766185db85Sdougm value = scf_value_create(handle->handle); 2776185db85Sdougm prop = scf_property_create(handle->handle); 2786185db85Sdougm name = malloc(scf_max_name_len); 2796185db85Sdougm valuestr = malloc(vallen); 2806185db85Sdougm /* 281*25a68471Sdougm * Want to iterate through the properties and add them 2826185db85Sdougm * to the base optionset. 2836185db85Sdougm */ 284*25a68471Sdougm if (iter == NULL || value == NULL || prop == NULL || 285*25a68471Sdougm valuestr == NULL || name == NULL) { 286*25a68471Sdougm ret = SA_NO_MEMORY; 287*25a68471Sdougm goto out; 288*25a68471Sdougm } 2896185db85Sdougm if (scf_iter_pg_properties(iter, pg) == 0) { 290*25a68471Sdougm /* Now iterate the properties in the group */ 2916185db85Sdougm while (scf_iter_next_property(iter, prop) > 0) { 2926185db85Sdougm /* have a property */ 2936185db85Sdougm if (scf_property_get_name(prop, name, 2946185db85Sdougm scf_max_name_len) > 0) { 295*25a68471Sdougm sa_property_t saprop; 296*25a68471Sdougm /* Some properties are part of the framework */ 2976185db85Sdougm if (skip_property(name)) 2986185db85Sdougm continue; 299*25a68471Sdougm if (scf_property_get_value(prop, value) != 0) 300*25a68471Sdougm continue; 3016185db85Sdougm if (scf_value_get_astring(value, valuestr, 302*25a68471Sdougm vallen) < 0) 303*25a68471Sdougm continue; 304*25a68471Sdougm saprop = sa_create_property(name, valuestr); 3056185db85Sdougm if (saprop != NULL) { 3066185db85Sdougm /* 307*25a68471Sdougm * Since in SMF, don't 3086185db85Sdougm * recurse. Use xmlAddChild 3096185db85Sdougm * directly, instead. 3106185db85Sdougm */ 3116185db85Sdougm xmlAddChild(node, 3126185db85Sdougm (xmlNodePtr) saprop); 3136185db85Sdougm } 3146185db85Sdougm } 3156185db85Sdougm } 3166185db85Sdougm } 317*25a68471Sdougm out: 3186185db85Sdougm /* cleanup to avoid memory leaks */ 3196185db85Sdougm if (value != NULL) 3206185db85Sdougm scf_value_destroy(value); 3216185db85Sdougm if (iter != NULL) 3226185db85Sdougm scf_iter_destroy(iter); 3236185db85Sdougm if (prop != NULL) 3246185db85Sdougm scf_property_destroy(prop); 3256185db85Sdougm if (name != NULL) 3266185db85Sdougm free(name); 3276185db85Sdougm if (valuestr != NULL) 3286185db85Sdougm free(valuestr); 329*25a68471Sdougm 3306185db85Sdougm return (ret); 3316185db85Sdougm } 3326185db85Sdougm 3336185db85Sdougm /* 3346185db85Sdougm * sa_extract_attrs(root, handle, instance) 3356185db85Sdougm * 336*25a68471Sdougm * Local function to extract the actual attributes/properties from the 3376185db85Sdougm * property group of the service instance. These are the well known 3386185db85Sdougm * attributes of "state" and "zfs". If additional attributes are 3396185db85Sdougm * added, they should be added here. 3406185db85Sdougm */ 3416185db85Sdougm 3426185db85Sdougm static void 3436185db85Sdougm sa_extract_attrs(xmlNodePtr root, scfutilhandle_t *handle, 3446185db85Sdougm scf_instance_t *instance) 3456185db85Sdougm { 3466185db85Sdougm scf_property_t *prop; 3476185db85Sdougm scf_value_t *value; 3486185db85Sdougm char *valuestr; 3496185db85Sdougm ssize_t vallen; 3506185db85Sdougm 3516185db85Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 3526185db85Sdougm prop = scf_property_create(handle->handle); 3536185db85Sdougm value = scf_value_create(handle->handle); 3546185db85Sdougm valuestr = malloc(vallen); 355*25a68471Sdougm if (prop == NULL || value == NULL || valuestr == NULL || 356*25a68471Sdougm scf_instance_get_pg(instance, "operation", handle->pg) != 0) { 357*25a68471Sdougm goto out; 358*25a68471Sdougm } 3596185db85Sdougm /* 360*25a68471Sdougm * Have a property group with desired name so now get 3616185db85Sdougm * the known attributes. 3626185db85Sdougm */ 3636185db85Sdougm if (scf_pg_get_property(handle->pg, "state", prop) == 0) { 364*25a68471Sdougm /* Found the property so get the value */ 3656185db85Sdougm if (scf_property_get_value(prop, value) == 0) { 366*25a68471Sdougm if (scf_value_get_astring(value, valuestr, 367*25a68471Sdougm vallen) >= 0) { 3686185db85Sdougm xmlSetProp(root, (xmlChar *)"state", 3696185db85Sdougm (xmlChar *)valuestr); 3706185db85Sdougm } 3716185db85Sdougm } 3726185db85Sdougm } 3736185db85Sdougm if (scf_pg_get_property(handle->pg, "zfs", prop) == 0) { 374*25a68471Sdougm /* Found the property so get the value */ 3756185db85Sdougm if (scf_property_get_value(prop, value) == 0) { 376*25a68471Sdougm if (scf_value_get_astring(value, valuestr, 377*25a68471Sdougm vallen) > 0) { 3786185db85Sdougm xmlSetProp(root, (xmlChar *)"zfs", 3796185db85Sdougm (xmlChar *)valuestr); 3806185db85Sdougm } 3816185db85Sdougm } 3826185db85Sdougm } 383*25a68471Sdougm out: 3846185db85Sdougm if (valuestr != NULL) 3856185db85Sdougm free(valuestr); 3866185db85Sdougm if (value != NULL) 3876185db85Sdougm scf_value_destroy(value); 3886185db85Sdougm if (prop != NULL) 3896185db85Sdougm scf_property_destroy(prop); 3906185db85Sdougm } 3916185db85Sdougm 3926185db85Sdougm /* 393*25a68471Sdougm * List of known share attributes. 3946185db85Sdougm */ 3956185db85Sdougm 3966185db85Sdougm static char *share_attr[] = { 3976185db85Sdougm "path", 3986185db85Sdougm "id", 3996185db85Sdougm "resource", 4006185db85Sdougm NULL, 4016185db85Sdougm }; 4026185db85Sdougm 4036185db85Sdougm static int 4046185db85Sdougm is_share_attr(char *name) 4056185db85Sdougm { 4066185db85Sdougm int i; 4076185db85Sdougm for (i = 0; share_attr[i] != NULL; i++) 4086185db85Sdougm if (strcmp(name, share_attr[i]) == 0) 4096185db85Sdougm return (1); 4106185db85Sdougm return (0); 4116185db85Sdougm } 4126185db85Sdougm 4136185db85Sdougm /* 4146185db85Sdougm * sa_share_from_pgroup 4156185db85Sdougm * 416*25a68471Sdougm * Extract the share definition from the share property group. We do 4176185db85Sdougm * some sanity checking to avoid bad data. 4186185db85Sdougm * 4196185db85Sdougm * Since this is only constructing the internal data structures, we 4206185db85Sdougm * don't use the sa_* functions most of the time. 4216185db85Sdougm */ 4226185db85Sdougm void 4236185db85Sdougm sa_share_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle, 4246185db85Sdougm scf_propertygroup_t *pg, char *id) 4256185db85Sdougm { 4266185db85Sdougm xmlNodePtr node; 4276185db85Sdougm char *name; 4286185db85Sdougm scf_iter_t *iter; 4296185db85Sdougm scf_property_t *prop; 4306185db85Sdougm scf_value_t *value; 4316185db85Sdougm ssize_t vallen; 4326185db85Sdougm char *valuestr; 4336185db85Sdougm int ret = SA_OK; 434f345c0beSdougm int have_path = 0; 4356185db85Sdougm 4366185db85Sdougm /* 4376185db85Sdougm * While preliminary check (starts with 'S') passed before 4386185db85Sdougm * getting here. Need to make sure it is in ID syntax 4396185db85Sdougm * (Snnnnnn). Note that shares with properties have similar 4406185db85Sdougm * pgroups. 4416185db85Sdougm */ 4426185db85Sdougm vallen = strlen(id); 4436185db85Sdougm if (*id == SA_SHARE_PG_PREFIX[0] && vallen == SA_SHARE_PG_LEN) { 4446185db85Sdougm uuid_t uuid; 445*25a68471Sdougm if (strncmp(id, SA_SHARE_PG_PREFIX, 446*25a68471Sdougm SA_SHARE_PG_PREFIXLEN) != 0 || 4476185db85Sdougm uuid_parse(id + 2, uuid) < 0) 4486185db85Sdougm return; 4496185db85Sdougm } else { 4506185db85Sdougm return; 4516185db85Sdougm } 4526185db85Sdougm 4536185db85Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 4546185db85Sdougm 4556185db85Sdougm iter = scf_iter_create(handle->handle); 4566185db85Sdougm value = scf_value_create(handle->handle); 4576185db85Sdougm prop = scf_property_create(handle->handle); 4586185db85Sdougm name = malloc(scf_max_name_len); 4596185db85Sdougm valuestr = malloc(vallen); 4606185db85Sdougm 4616185db85Sdougm /* 462*25a68471Sdougm * Construct the share XML node. It is similar to sa_add_share 4636185db85Sdougm * but never changes the repository. Also, there won't be any 4646185db85Sdougm * ZFS or transient shares. Root will be the group it is 4656185db85Sdougm * associated with. 4666185db85Sdougm */ 4676185db85Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"share", NULL); 4686185db85Sdougm if (node != NULL) { 4696185db85Sdougm /* 470*25a68471Sdougm * Make sure the UUID part of the property group is 4716185db85Sdougm * stored in the share "id" property. We use this 4726185db85Sdougm * later. 4736185db85Sdougm */ 4746185db85Sdougm xmlSetProp(node, (xmlChar *)"id", (xmlChar *)id); 4756185db85Sdougm xmlSetProp(node, (xmlChar *)"type", (xmlChar *)"persist"); 4766185db85Sdougm } 4776185db85Sdougm 478*25a68471Sdougm if (iter == NULL || value == NULL || prop == NULL || name == NULL) 479*25a68471Sdougm goto out; 480*25a68471Sdougm 481*25a68471Sdougm /* Iterate over the share pg properties */ 482*25a68471Sdougm if (scf_iter_pg_properties(iter, pg) != 0) 483*25a68471Sdougm goto out; 484*25a68471Sdougm 4856185db85Sdougm while (scf_iter_next_property(iter, prop) > 0) { 4866185db85Sdougm ret = SA_SYSTEM_ERR; /* assume the worst */ 487*25a68471Sdougm if (scf_property_get_name(prop, name, scf_max_name_len) > 0) { 4886185db85Sdougm if (scf_property_get_value(prop, value) == 0) { 4896185db85Sdougm if (scf_value_get_astring(value, valuestr, 4906185db85Sdougm vallen) >= 0) { 4916185db85Sdougm ret = SA_OK; 4926185db85Sdougm } 4936185db85Sdougm } 4946185db85Sdougm } 4956185db85Sdougm if (ret == SA_OK) { 496f345c0beSdougm /* 497*25a68471Sdougm * Check that we have the "path" property in 498f345c0beSdougm * name. The string in name will always be nul 499f345c0beSdougm * terminated if scf_property_get_name() 500f345c0beSdougm * succeeded. 501f345c0beSdougm */ 502f345c0beSdougm if (strcmp(name, "path") == 0) 503f345c0beSdougm have_path = 1; 5046185db85Sdougm if (is_share_attr(name)) { 5056185db85Sdougm /* 506*25a68471Sdougm * If a share attr, then simple - 5076185db85Sdougm * usually path and resource name 5086185db85Sdougm */ 5096185db85Sdougm xmlSetProp(node, (xmlChar *)name, 5106185db85Sdougm (xmlChar *)valuestr); 5116185db85Sdougm } else { 5126185db85Sdougm if (strcmp(name, "description") == 0) { 513*25a68471Sdougm /* We have a description node */ 5146185db85Sdougm xmlNodePtr desc; 5156185db85Sdougm desc = xmlNewChild(node, NULL, 516*25a68471Sdougm (xmlChar *)"description", NULL); 5176185db85Sdougm if (desc != NULL) 5186185db85Sdougm xmlNodeSetContent(desc, 5196185db85Sdougm (xmlChar *)valuestr); 5206185db85Sdougm } 5216185db85Sdougm } 5226185db85Sdougm } 5236185db85Sdougm } 524*25a68471Sdougm out: 525f345c0beSdougm /* 526*25a68471Sdougm * A share without a path is broken so we want to not include 527f345c0beSdougm * these. They shouldn't happen but if you kill a sharemgr in 528f345c0beSdougm * the process of creating a share, it could happen. They 529f345c0beSdougm * should be harmless. It is also possible that another 530f345c0beSdougm * sharemgr is running and in the process of creating a share. 531f345c0beSdougm */ 532f345c0beSdougm if (have_path == 0 && node != NULL) { 533f345c0beSdougm xmlUnlinkNode(node); 534f345c0beSdougm xmlFreeNode(node); 535f345c0beSdougm } 5366185db85Sdougm if (name != NULL) 5376185db85Sdougm free(name); 5386185db85Sdougm if (valuestr != NULL) 5396185db85Sdougm free(valuestr); 5406185db85Sdougm if (value != NULL) 5416185db85Sdougm scf_value_destroy(value); 5426185db85Sdougm if (iter != NULL) 5436185db85Sdougm scf_iter_destroy(iter); 5446185db85Sdougm if (prop != NULL) 5456185db85Sdougm scf_property_destroy(prop); 5466185db85Sdougm } 5476185db85Sdougm 5486185db85Sdougm /* 5496185db85Sdougm * find_share_by_id(shareid) 5506185db85Sdougm * 5516185db85Sdougm * Search all shares in all groups until we find the share represented 5526185db85Sdougm * by "id". 5536185db85Sdougm */ 5546185db85Sdougm 5556185db85Sdougm static sa_share_t 556549ec3ffSdougm find_share_by_id(sa_handle_t handle, char *shareid) 5576185db85Sdougm { 5586185db85Sdougm sa_group_t group; 5596185db85Sdougm sa_share_t share = NULL; 5606185db85Sdougm char *id = NULL; 5616185db85Sdougm int done = 0; 5626185db85Sdougm 563*25a68471Sdougm for (group = sa_get_group(handle, NULL); 564*25a68471Sdougm group != NULL && !done; 5656185db85Sdougm group = sa_get_next_group(group)) { 566*25a68471Sdougm for (share = sa_get_share(group, NULL); 567*25a68471Sdougm share != NULL; 5686185db85Sdougm share = sa_get_next_share(share)) { 5696185db85Sdougm id = sa_get_share_attr(share, "id"); 5706185db85Sdougm if (id != NULL && strcmp(id, shareid) == 0) { 5716185db85Sdougm sa_free_attr_string(id); 5726185db85Sdougm id = NULL; 5736185db85Sdougm done++; 5746185db85Sdougm break; 5756185db85Sdougm } 5766185db85Sdougm if (id != NULL) { 5776185db85Sdougm sa_free_attr_string(id); 5786185db85Sdougm id = NULL; 5796185db85Sdougm } 5806185db85Sdougm } 5816185db85Sdougm } 5826185db85Sdougm return (share); 5836185db85Sdougm } 5846185db85Sdougm 5856185db85Sdougm /* 5866185db85Sdougm * sa_share_props_from_pgroup(root, handle, pg, id) 5876185db85Sdougm * 588*25a68471Sdougm * Extract share properties from the SMF property group. More sanity 5896185db85Sdougm * checks are done and the share object is created. We ignore some 5906185db85Sdougm * errors that could exist in the repository and only worry about 5916185db85Sdougm * property groups that validate in naming. 5926185db85Sdougm */ 5936185db85Sdougm 5946185db85Sdougm static int 5956185db85Sdougm sa_share_props_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle, 596549ec3ffSdougm scf_propertygroup_t *pg, char *id, sa_handle_t sahandle) 5976185db85Sdougm { 5986185db85Sdougm xmlNodePtr node; 599*25a68471Sdougm char *name = NULL; 600*25a68471Sdougm scf_iter_t *iter = NULL; 601*25a68471Sdougm scf_property_t *prop = NULL; 602*25a68471Sdougm scf_value_t *value = NULL; 6036185db85Sdougm ssize_t vallen; 604*25a68471Sdougm char *valuestr = NULL; 6056185db85Sdougm int ret = SA_OK; 6066185db85Sdougm char *sectype = NULL; 6076185db85Sdougm char *proto; 6086185db85Sdougm sa_share_t share; 609*25a68471Sdougm uuid_t uuid; 6106185db85Sdougm 6116185db85Sdougm /* 6126185db85Sdougm * While preliminary check (starts with 'S') passed before 6136185db85Sdougm * getting here. Need to make sure it is in ID syntax 6146185db85Sdougm * (Snnnnnn). Note that shares with properties have similar 6156185db85Sdougm * pgroups. If the pg name is more than SA_SHARE_PG_LEN 6166185db85Sdougm * characters, it is likely one of the protocol/security 6176185db85Sdougm * versions. 6186185db85Sdougm */ 6196185db85Sdougm vallen = strlen(id); 620*25a68471Sdougm if (*id != SA_SHARE_PG_PREFIX[0] || vallen <= SA_SHARE_PG_LEN) { 621*25a68471Sdougm /* 622*25a68471Sdougm * It is ok to not have what we thought since someone might 623*25a68471Sdougm * have added a name via SMF. 624*25a68471Sdougm */ 625*25a68471Sdougm return (ret); 626*25a68471Sdougm } 6276185db85Sdougm if (strncmp(id, SA_SHARE_PG_PREFIX, SA_SHARE_PG_PREFIXLEN) == 0) { 6286185db85Sdougm proto = strchr(id, '_'); 6296185db85Sdougm if (proto == NULL) 6306185db85Sdougm return (ret); 6316185db85Sdougm *proto++ = '\0'; 6326185db85Sdougm if (uuid_parse(id + SA_SHARE_PG_PREFIXLEN, uuid) < 0) 6336185db85Sdougm return (ret); 6346185db85Sdougm /* 6356185db85Sdougm * probably a legal optionset so check a few more 6366185db85Sdougm * syntax points below. 6376185db85Sdougm */ 6386185db85Sdougm if (*proto == '\0') { 6396185db85Sdougm /* not a valid proto (null) */ 6406185db85Sdougm return (ret); 6416185db85Sdougm } 6426185db85Sdougm sectype = strchr(proto, '_'); 6436185db85Sdougm if (sectype != NULL) 6446185db85Sdougm *sectype++ = '\0'; 6456185db85Sdougm if (!valid_protocol(proto)) 6466185db85Sdougm return (ret); 6476185db85Sdougm } 6486185db85Sdougm 6496185db85Sdougm /* 650*25a68471Sdougm * To get here, we have a valid protocol and possibly a 6516185db85Sdougm * security. We now have to find the share that it is really 6526185db85Sdougm * associated with. The "id" portion of the pgroup name will 6536185db85Sdougm * match. 6546185db85Sdougm */ 6556185db85Sdougm 656549ec3ffSdougm share = find_share_by_id(sahandle, id); 6576185db85Sdougm if (share == NULL) 6586185db85Sdougm return (SA_BAD_PATH); 6596185db85Sdougm 6606185db85Sdougm root = (xmlNodePtr)share; 6616185db85Sdougm 6626185db85Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 6636185db85Sdougm 664*25a68471Sdougm if (sectype == NULL) 665*25a68471Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"optionset", NULL); 666*25a68471Sdougm else { 667*25a68471Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"security", NULL); 668*25a68471Sdougm if (node != NULL) 669*25a68471Sdougm xmlSetProp(node, (xmlChar *)"sectype", 670*25a68471Sdougm (xmlChar *)sectype); 671*25a68471Sdougm } 672*25a68471Sdougm if (node == NULL) { 673*25a68471Sdougm ret = SA_NO_MEMORY; 674*25a68471Sdougm goto out; 675*25a68471Sdougm } 676*25a68471Sdougm 677*25a68471Sdougm xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto); 678*25a68471Sdougm /* now find the properties */ 6796185db85Sdougm iter = scf_iter_create(handle->handle); 6806185db85Sdougm value = scf_value_create(handle->handle); 6816185db85Sdougm prop = scf_property_create(handle->handle); 6826185db85Sdougm name = malloc(scf_max_name_len); 6836185db85Sdougm valuestr = malloc(vallen); 6846185db85Sdougm 685*25a68471Sdougm if (iter == NULL || value == NULL || prop == NULL || name == NULL) 686*25a68471Sdougm goto out; 687*25a68471Sdougm 688*25a68471Sdougm /* Iterate over the share pg properties */ 6896185db85Sdougm if (scf_iter_pg_properties(iter, pg) == 0) { 6906185db85Sdougm while (scf_iter_next_property(iter, prop) > 0) { 6916185db85Sdougm ret = SA_SYSTEM_ERR; /* assume the worst */ 6926185db85Sdougm if (scf_property_get_name(prop, name, 6936185db85Sdougm scf_max_name_len) > 0) { 6946185db85Sdougm if (scf_property_get_value(prop, value) == 0) { 695*25a68471Sdougm if (scf_value_get_astring(value, 696*25a68471Sdougm valuestr, vallen) >= 0) { 6976185db85Sdougm ret = SA_OK; 6986185db85Sdougm } 6996185db85Sdougm } 7006185db85Sdougm } else { 7016185db85Sdougm ret = SA_SYSTEM_ERR; 7026185db85Sdougm } 7036185db85Sdougm if (ret == SA_OK) { 7046185db85Sdougm sa_property_t prop; 7056185db85Sdougm prop = sa_create_property(name, valuestr); 7066185db85Sdougm if (prop != NULL) 7076185db85Sdougm prop = (sa_property_t)xmlAddChild(node, 7086185db85Sdougm (xmlNodePtr)prop); 7096185db85Sdougm else 7106185db85Sdougm ret = SA_NO_MEMORY; 7116185db85Sdougm } 7126185db85Sdougm } 7136185db85Sdougm } else { 7146185db85Sdougm ret = SA_SYSTEM_ERR; 7156185db85Sdougm } 716*25a68471Sdougm out: 7176185db85Sdougm if (iter != NULL) 7186185db85Sdougm scf_iter_destroy(iter); 7196185db85Sdougm if (value != NULL) 7206185db85Sdougm scf_value_destroy(value); 7216185db85Sdougm if (prop != NULL) 7226185db85Sdougm scf_property_destroy(prop); 7236185db85Sdougm if (name != NULL) 7246185db85Sdougm free(name); 7256185db85Sdougm if (valuestr != NULL) 7266185db85Sdougm free(valuestr); 7276185db85Sdougm return (ret); 7286185db85Sdougm } 7296185db85Sdougm 7306185db85Sdougm /* 7316185db85Sdougm * sa_extract_group(root, handle, instance) 7326185db85Sdougm * 733*25a68471Sdougm * Get the config info for this instance of a group and create the XML 7346185db85Sdougm * subtree from it. 7356185db85Sdougm */ 7366185db85Sdougm 7376185db85Sdougm static int 7386185db85Sdougm sa_extract_group(xmlNodePtr root, scfutilhandle_t *handle, 739549ec3ffSdougm scf_instance_t *instance, sa_handle_t sahandle) 7406185db85Sdougm { 7416185db85Sdougm char *buff; 7426185db85Sdougm xmlNodePtr node; 7436185db85Sdougm scf_iter_t *iter; 7446185db85Sdougm char *proto; 7456185db85Sdougm char *sectype; 7466185db85Sdougm int have_shares = 0; 7476185db85Sdougm int has_proto = 0; 7486185db85Sdougm int is_default = 0; 7496185db85Sdougm int ret = SA_OK; 7506185db85Sdougm int err; 7516185db85Sdougm 7526185db85Sdougm buff = malloc(scf_max_name_len); 753*25a68471Sdougm if (buff == NULL) 754*25a68471Sdougm return (SA_NO_MEMORY); 755*25a68471Sdougm 7566185db85Sdougm iter = scf_iter_create(handle->handle); 757*25a68471Sdougm if (iter == NULL) { 758*25a68471Sdougm ret = SA_NO_MEMORY; 759*25a68471Sdougm goto out; 760*25a68471Sdougm } 761*25a68471Sdougm 762*25a68471Sdougm if (scf_instance_get_name(instance, buff, scf_max_name_len) > 0) { 7636185db85Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"group", NULL); 764*25a68471Sdougm if (node == NULL) { 765*25a68471Sdougm ret = SA_NO_MEMORY; 766*25a68471Sdougm goto out; 767*25a68471Sdougm } 7686185db85Sdougm xmlSetProp(node, (xmlChar *)"name", (xmlChar *)buff); 7696185db85Sdougm if (strcmp(buff, "default") == 0) 7706185db85Sdougm is_default++; 771*25a68471Sdougm 7726185db85Sdougm sa_extract_attrs(node, handle, instance); 7736185db85Sdougm /* 7746185db85Sdougm * Iterate through all the property groups 7756185db85Sdougm * looking for those with security or 7766185db85Sdougm * optionset prefixes. The names of the 7776185db85Sdougm * matching pgroups are parsed to get the 7786185db85Sdougm * protocol, and for security, the sectype. 7796185db85Sdougm * Syntax is as follows: 7806185db85Sdougm * optionset | optionset_<proto> 7816185db85Sdougm * security_default | security_<proto>_<sectype> 7826185db85Sdougm * "operation" is handled by 7836185db85Sdougm * sa_extract_attrs(). 7846185db85Sdougm */ 785*25a68471Sdougm if (scf_iter_instance_pgs(iter, instance) != 0) { 786*25a68471Sdougm ret = SA_NO_MEMORY; 787*25a68471Sdougm goto out; 788*25a68471Sdougm } 7896185db85Sdougm while (scf_iter_next_pg(iter, handle->pg) > 0) { 790*25a68471Sdougm /* Have a pgroup so sort it out */ 7916185db85Sdougm ret = scf_pg_get_name(handle->pg, buff, 7926185db85Sdougm scf_max_name_len); 7936185db85Sdougm if (ret > 0) { 7946185db85Sdougm if (buff[0] == SA_SHARE_PG_PREFIX[0]) { 7956185db85Sdougm sa_share_from_pgroup(node, handle, 796*25a68471Sdougm handle->pg, buff); 7976185db85Sdougm have_shares++; 7986185db85Sdougm } else if (strncmp(buff, "optionset", 9) == 7996185db85Sdougm 0) { 8006185db85Sdougm char *nodetype = "optionset"; 801*25a68471Sdougm /* Have an optionset */ 8026185db85Sdougm sectype = NULL; 8036185db85Sdougm proto = strchr(buff, '_'); 8046185db85Sdougm if (proto != NULL) { 8056185db85Sdougm *proto++ = '\0'; 8066185db85Sdougm sectype = strchr(proto, '_'); 8076185db85Sdougm if (sectype != NULL) { 8086185db85Sdougm *sectype++ = '\0'; 8096185db85Sdougm nodetype = "security"; 8106185db85Sdougm } 8116185db85Sdougm } 8126185db85Sdougm ret = sa_extract_pgroup(node, handle, 813*25a68471Sdougm handle->pg, nodetype, proto, 814*25a68471Sdougm sectype); 8156185db85Sdougm has_proto++; 816*25a68471Sdougm } else if (strncmp(buff, "security", 8) == 0) { 8176185db85Sdougm /* 818*25a68471Sdougm * Have a security (note that 8196185db85Sdougm * this should change in the 8206185db85Sdougm * future) 8216185db85Sdougm */ 8226185db85Sdougm proto = strchr(buff, '_'); 8236185db85Sdougm sectype = NULL; 8246185db85Sdougm if (proto != NULL) { 8256185db85Sdougm *proto++ = '\0'; 8266185db85Sdougm sectype = strchr(proto, '_'); 8276185db85Sdougm if (sectype != NULL) 8286185db85Sdougm *sectype++ = '\0'; 829*25a68471Sdougm if (strcmp(proto, "default") == 830*25a68471Sdougm 0) 8316185db85Sdougm proto = NULL; 8326185db85Sdougm } 8336185db85Sdougm ret = sa_extract_pgroup(node, handle, 834*25a68471Sdougm handle->pg, "security", proto, 8356185db85Sdougm sectype); 8366185db85Sdougm has_proto++; 8376185db85Sdougm } 838*25a68471Sdougm /* Ignore everything else */ 8396185db85Sdougm } 8406185db85Sdougm } 8416185db85Sdougm /* 8426185db85Sdougm * Make sure we have a valid default group. 8436185db85Sdougm * On first boot, default won't have any 8446185db85Sdougm * protocols defined and won't be enabled (but 8456185db85Sdougm * should be). 8466185db85Sdougm */ 8476185db85Sdougm if (is_default) { 8486185db85Sdougm char *state = sa_get_group_attr((sa_group_t)node, 8496185db85Sdougm "state"); 8506185db85Sdougm char **protos; 8516185db85Sdougm int numprotos; 8526185db85Sdougm int i; 8536185db85Sdougm 8546185db85Sdougm if (state == NULL) { 8556185db85Sdougm /* set attribute to enabled */ 8566185db85Sdougm (void) sa_set_group_attr((sa_group_t)node, 857*25a68471Sdougm "state", "enabled"); 858*25a68471Sdougm /* We can assume no protocols */ 8596185db85Sdougm numprotos = sa_get_protocols(&protos); 8606185db85Sdougm for (i = 0; i < numprotos; i++) 861*25a68471Sdougm (void) sa_create_optionset( 862*25a68471Sdougm (sa_group_t)node, protos[i]); 8636185db85Sdougm if (numprotos > 0) 8646185db85Sdougm free(protos); 8656185db85Sdougm } else { 8666185db85Sdougm sa_free_attr_string(state); 8676185db85Sdougm } 8686185db85Sdougm } 869*25a68471Sdougm /* Do a second pass if shares were found */ 870*25a68471Sdougm if (have_shares && scf_iter_instance_pgs(iter, instance) == 0) { 8716185db85Sdougm while (scf_iter_next_pg(iter, handle->pg) > 0) { 8726185db85Sdougm /* 873*25a68471Sdougm * Have a pgroup so see if it is a 8746185db85Sdougm * share optionset 8756185db85Sdougm */ 8766185db85Sdougm err = scf_pg_get_name(handle->pg, buff, 8776185db85Sdougm scf_max_name_len); 878*25a68471Sdougm if (err <= 0) 879*25a68471Sdougm continue; 8806185db85Sdougm if (buff[0] == SA_SHARE_PG_PREFIX[0]) { 8816185db85Sdougm ret = sa_share_props_from_pgroup(node, 882*25a68471Sdougm handle, handle->pg, buff, 883*25a68471Sdougm sahandle); 8846185db85Sdougm } 8856185db85Sdougm } 8866185db85Sdougm } 8876185db85Sdougm } 888*25a68471Sdougm out: 8896185db85Sdougm if (iter != NULL) 8906185db85Sdougm scf_iter_destroy(iter); 8916185db85Sdougm if (buff != NULL) 8926185db85Sdougm free(buff); 8936185db85Sdougm return (ret); 8946185db85Sdougm } 8956185db85Sdougm 8966185db85Sdougm /* 8976185db85Sdougm * sa_extract_defaults(root, handle, instance) 8986185db85Sdougm * 899*25a68471Sdougm * Local function to find the default properties that live in the 9006185db85Sdougm * default instance's "operation" proprerty group. 9016185db85Sdougm */ 9026185db85Sdougm 9036185db85Sdougm static void 9046185db85Sdougm sa_extract_defaults(xmlNodePtr root, scfutilhandle_t *handle, 9056185db85Sdougm scf_instance_t *instance) 9066185db85Sdougm { 9076185db85Sdougm xmlNodePtr node; 9086185db85Sdougm scf_property_t *prop; 9096185db85Sdougm scf_value_t *value; 9106185db85Sdougm char *valuestr; 9116185db85Sdougm ssize_t vallen; 9126185db85Sdougm 9136185db85Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 9146185db85Sdougm prop = scf_property_create(handle->handle); 9156185db85Sdougm value = scf_value_create(handle->handle); 9166185db85Sdougm valuestr = malloc(vallen); 917*25a68471Sdougm 918*25a68471Sdougm if (prop == NULL || value == NULL || vallen == 0 || 919*25a68471Sdougm scf_instance_get_pg(instance, "operation", handle->pg) != 0) 920*25a68471Sdougm goto out; 921*25a68471Sdougm 922*25a68471Sdougm if (scf_pg_get_property(handle->pg, "legacy-timestamp", prop) != 0) 923*25a68471Sdougm goto out; 924*25a68471Sdougm 925*25a68471Sdougm /* Found the property so get the value */ 9266185db85Sdougm if (scf_property_get_value(prop, value) == 0) { 9276185db85Sdougm if (scf_value_get_astring(value, valuestr, vallen) > 0) { 9286185db85Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"legacy", 9296185db85Sdougm NULL); 9306185db85Sdougm if (node != NULL) { 9316185db85Sdougm xmlSetProp(node, (xmlChar *)"timestamp", 9326185db85Sdougm (xmlChar *)valuestr); 9336185db85Sdougm xmlSetProp(node, (xmlChar *)"path", 9346185db85Sdougm (xmlChar *)SA_LEGACY_DFSTAB); 9356185db85Sdougm } 9366185db85Sdougm } 9376185db85Sdougm } 938*25a68471Sdougm out: 9396185db85Sdougm if (valuestr != NULL) 9406185db85Sdougm free(valuestr); 9416185db85Sdougm if (value != NULL) 9426185db85Sdougm scf_value_destroy(value); 9436185db85Sdougm if (prop != NULL) 9446185db85Sdougm scf_property_destroy(prop); 9456185db85Sdougm } 9466185db85Sdougm 9476185db85Sdougm 9486185db85Sdougm /* 949549ec3ffSdougm * sa_get_config(handle, root, doc, sahandlec) 9506185db85Sdougm * 951*25a68471Sdougm * Walk the SMF repository for /network/shares/group and find all the 9526185db85Sdougm * instances. These become group names. Then add the XML structure 9536185db85Sdougm * below the groups based on property groups and properties. 9546185db85Sdougm */ 9556185db85Sdougm int 9561d1813a7Sdougm sa_get_config(scfutilhandle_t *handle, xmlNodePtr root, sa_handle_t sahandle) 9576185db85Sdougm { 9586185db85Sdougm int ret = SA_OK; 9596185db85Sdougm scf_instance_t *instance; 9606185db85Sdougm scf_iter_t *iter; 9616185db85Sdougm char buff[BUFSIZ * 2]; 9626185db85Sdougm 9636185db85Sdougm instance = scf_instance_create(handle->handle); 9646185db85Sdougm iter = scf_iter_create(handle->handle); 9651d1813a7Sdougm if (instance != NULL && iter != NULL) { 9666185db85Sdougm if ((ret = scf_iter_service_instances(iter, 9676185db85Sdougm handle->service)) == 0) { 9686185db85Sdougm while ((ret = scf_iter_next_instance(iter, 9696185db85Sdougm instance)) > 0) { 9706185db85Sdougm if (scf_instance_get_name(instance, buff, 9716185db85Sdougm sizeof (buff)) > 0) { 9726185db85Sdougm if (strcmp(buff, "default") == 0) 973*25a68471Sdougm sa_extract_defaults(root, 974*25a68471Sdougm handle, instance); 975*25a68471Sdougm ret = sa_extract_group(root, handle, 976*25a68471Sdougm instance, sahandle); 9776185db85Sdougm } 9786185db85Sdougm } 9796185db85Sdougm } 9806185db85Sdougm } 9811d1813a7Sdougm 982*25a68471Sdougm /* Always cleanup these */ 9836185db85Sdougm if (instance != NULL) 9846185db85Sdougm scf_instance_destroy(instance); 9856185db85Sdougm if (iter != NULL) 9866185db85Sdougm scf_iter_destroy(iter); 9876185db85Sdougm return (ret); 9886185db85Sdougm } 9896185db85Sdougm 9906185db85Sdougm /* 9916185db85Sdougm * sa_get_instance(handle, instance) 9926185db85Sdougm * 993*25a68471Sdougm * Get the instance of the group service. This is actually the 9946185db85Sdougm * specific group name. The instance is needed for all property and 9956185db85Sdougm * control operations. 9966185db85Sdougm */ 9976185db85Sdougm 9986185db85Sdougm int 9996185db85Sdougm sa_get_instance(scfutilhandle_t *handle, char *instname) 10006185db85Sdougm { 10016185db85Sdougm if (scf_service_get_instance(handle->service, instname, 10026185db85Sdougm handle->instance) != 0) { 10036185db85Sdougm return (SA_NO_SUCH_GROUP); 10046185db85Sdougm } 10056185db85Sdougm return (SA_OK); 10066185db85Sdougm } 10076185db85Sdougm 10086185db85Sdougm /* 10096185db85Sdougm * sa_create_instance(handle, instname) 10106185db85Sdougm * 10116185db85Sdougm * Create a new SMF service instance. There can only be one with a 10126185db85Sdougm * given name. 10136185db85Sdougm */ 10146185db85Sdougm 10156185db85Sdougm int 10166185db85Sdougm sa_create_instance(scfutilhandle_t *handle, char *instname) 10176185db85Sdougm { 10186185db85Sdougm int ret = SA_OK; 10196185db85Sdougm char instance[SA_GROUP_INST_LEN]; 10206185db85Sdougm if (scf_service_add_instance(handle->service, instname, 10216185db85Sdougm handle->instance) != 0) { 10226185db85Sdougm /* better error returns need to be added based on real error */ 10236185db85Sdougm if (scf_error() == SCF_ERROR_PERMISSION_DENIED) 10246185db85Sdougm ret = SA_NO_PERMISSION; 10256185db85Sdougm else 10266185db85Sdougm ret = SA_DUPLICATE_NAME; 10276185db85Sdougm } else { 10286185db85Sdougm /* have the service created, so enable it */ 10296185db85Sdougm (void) snprintf(instance, sizeof (instance), "%s:%s", 10306185db85Sdougm SA_SVC_FMRI_BASE, instname); 10316185db85Sdougm (void) smf_enable_instance(instance, 0); 10326185db85Sdougm } 10336185db85Sdougm return (ret); 10346185db85Sdougm } 10356185db85Sdougm 10366185db85Sdougm /* 10376185db85Sdougm * sa_delete_instance(handle, instname) 10386185db85Sdougm * 10396185db85Sdougm * When a group goes away, we also remove the service instance. 10406185db85Sdougm */ 10416185db85Sdougm 10426185db85Sdougm int 10436185db85Sdougm sa_delete_instance(scfutilhandle_t *handle, char *instname) 10446185db85Sdougm { 10456185db85Sdougm int ret; 10466185db85Sdougm 10476185db85Sdougm if (strcmp(instname, "default") == 0) { 10486185db85Sdougm ret = SA_NO_PERMISSION; 10496185db85Sdougm } else { 10506185db85Sdougm if ((ret = sa_get_instance(handle, instname)) == SA_OK) { 10516185db85Sdougm if (scf_instance_delete(handle->instance) != 0) 10526185db85Sdougm /* need better analysis */ 10536185db85Sdougm ret = SA_NO_PERMISSION; 10546185db85Sdougm } 10556185db85Sdougm } 10566185db85Sdougm return (ret); 10576185db85Sdougm } 10586185db85Sdougm 10596185db85Sdougm /* 10606185db85Sdougm * sa_create_pgroup(handle, pgroup) 10616185db85Sdougm * 10626185db85Sdougm * create a new property group 10636185db85Sdougm */ 10646185db85Sdougm 10656185db85Sdougm int 10666185db85Sdougm sa_create_pgroup(scfutilhandle_t *handle, char *pgroup) 10676185db85Sdougm { 10686185db85Sdougm int ret = SA_OK; 10696185db85Sdougm /* 1070*25a68471Sdougm * Only create a handle if it doesn't exist. It is ok to exist 10716185db85Sdougm * since the pg handle will be set as a side effect. 10726185db85Sdougm */ 1073*25a68471Sdougm if (handle->pg == NULL) 10746185db85Sdougm handle->pg = scf_pg_create(handle->handle); 1075*25a68471Sdougm 10766185db85Sdougm /* 1077*25a68471Sdougm * If the pgroup exists, we are done. If it doesn't, then we 10786185db85Sdougm * need to actually add one to the service instance. 10796185db85Sdougm */ 10806185db85Sdougm if (scf_instance_get_pg(handle->instance, 10816185db85Sdougm pgroup, handle->pg) != 0) { 1082*25a68471Sdougm /* Doesn't exist so create one */ 10836185db85Sdougm if (scf_instance_add_pg(handle->instance, pgroup, 1084*25a68471Sdougm SCF_GROUP_APPLICATION, 0, handle->pg) != 0) { 10856185db85Sdougm switch (scf_error()) { 10866185db85Sdougm case SCF_ERROR_PERMISSION_DENIED: 10876185db85Sdougm ret = SA_NO_PERMISSION; 10886185db85Sdougm break; 10896185db85Sdougm default: 10906185db85Sdougm ret = SA_SYSTEM_ERR; 10916185db85Sdougm break; 10926185db85Sdougm } 10936185db85Sdougm } 10946185db85Sdougm } 10956185db85Sdougm return (ret); 10966185db85Sdougm } 10976185db85Sdougm 10986185db85Sdougm /* 10996185db85Sdougm * sa_delete_pgroup(handle, pgroup) 11006185db85Sdougm * 1101*25a68471Sdougm * Remove the property group from the current instance of the service, 11026185db85Sdougm * but only if it actually exists. 11036185db85Sdougm */ 11046185db85Sdougm 11056185db85Sdougm int 11066185db85Sdougm sa_delete_pgroup(scfutilhandle_t *handle, char *pgroup) 11076185db85Sdougm { 11086185db85Sdougm int ret = SA_OK; 11096185db85Sdougm /* 1110*25a68471Sdougm * Only delete if it does exist. 11116185db85Sdougm */ 1112*25a68471Sdougm if (scf_instance_get_pg(handle->instance, pgroup, handle->pg) == 0) { 11136185db85Sdougm /* does exist so delete it */ 1114*25a68471Sdougm if (scf_pg_delete(handle->pg) != 0) 11156185db85Sdougm ret = SA_SYSTEM_ERR; 11166185db85Sdougm } else { 11176185db85Sdougm ret = SA_SYSTEM_ERR; 11186185db85Sdougm } 11196185db85Sdougm if (ret == SA_SYSTEM_ERR && 11206185db85Sdougm scf_error() == SCF_ERROR_PERMISSION_DENIED) { 11216185db85Sdougm ret = SA_NO_PERMISSION; 11226185db85Sdougm } 11236185db85Sdougm return (ret); 11246185db85Sdougm } 11256185db85Sdougm 11266185db85Sdougm /* 11276185db85Sdougm * sa_start_transaction(handle, pgroup) 11286185db85Sdougm * 11296185db85Sdougm * Start an SMF transaction so we can deal with properties. it would 11306185db85Sdougm * be nice to not have to expose this, but we have to in order to 11316185db85Sdougm * optimize. 11326185db85Sdougm * 11336185db85Sdougm * Basic model is to hold the transaction in the handle and allow 11346185db85Sdougm * property adds/deletes/updates to be added then close the 11356185db85Sdougm * transaction (or abort). There may eventually be a need to handle 11366185db85Sdougm * other types of transaction mechanisms but we don't do that now. 11376185db85Sdougm * 11386185db85Sdougm * An sa_start_transaction must be followed by either an 11396185db85Sdougm * sa_end_transaction or sa_abort_transaction before another 11406185db85Sdougm * sa_start_transaction can be done. 11416185db85Sdougm */ 11426185db85Sdougm 11436185db85Sdougm int 11446185db85Sdougm sa_start_transaction(scfutilhandle_t *handle, char *propgroup) 11456185db85Sdougm { 11466185db85Sdougm int ret = SA_OK; 11476185db85Sdougm /* 1148*25a68471Sdougm * Lookup the property group and create it if it doesn't already 11496185db85Sdougm * exist. 11506185db85Sdougm */ 11516185db85Sdougm if (handle->scf_state == SCH_STATE_INIT) { 11526185db85Sdougm ret = sa_create_pgroup(handle, propgroup); 11536185db85Sdougm if (ret == SA_OK) { 11546185db85Sdougm handle->trans = scf_transaction_create(handle->handle); 11556185db85Sdougm if (handle->trans != NULL) { 1156*25a68471Sdougm if (scf_transaction_start(handle->trans, 1157*25a68471Sdougm handle->pg) != 0) { 11586185db85Sdougm ret = SA_SYSTEM_ERR; 11596185db85Sdougm } 11606185db85Sdougm if (ret != SA_OK) { 11616185db85Sdougm scf_transaction_destroy(handle->trans); 11626185db85Sdougm handle->trans = NULL; 11636185db85Sdougm } 11646185db85Sdougm } else { 11656185db85Sdougm ret = SA_SYSTEM_ERR; 11666185db85Sdougm } 11676185db85Sdougm } 11686185db85Sdougm } 11696185db85Sdougm if (ret == SA_SYSTEM_ERR && 11706185db85Sdougm scf_error() == SCF_ERROR_PERMISSION_DENIED) { 11716185db85Sdougm ret = SA_NO_PERMISSION; 11726185db85Sdougm } 11736185db85Sdougm return (ret); 11746185db85Sdougm } 11756185db85Sdougm 11766185db85Sdougm /* 11776185db85Sdougm * sa_end_transaction(handle) 11786185db85Sdougm * 11796185db85Sdougm * Commit the changes that were added to the transaction in the 11806185db85Sdougm * handle. Do all necessary cleanup. 11816185db85Sdougm */ 11826185db85Sdougm 11836185db85Sdougm int 11846185db85Sdougm sa_end_transaction(scfutilhandle_t *handle) 11856185db85Sdougm { 11866185db85Sdougm int ret = SA_OK; 11876185db85Sdougm 11886185db85Sdougm if (handle->trans == NULL) { 11896185db85Sdougm ret = SA_SYSTEM_ERR; 11906185db85Sdougm } else { 11916185db85Sdougm if (scf_transaction_commit(handle->trans) < 0) 11926185db85Sdougm ret = SA_SYSTEM_ERR; 11936185db85Sdougm scf_transaction_destroy_children(handle->trans); 11946185db85Sdougm scf_transaction_destroy(handle->trans); 11956185db85Sdougm handle->trans = NULL; 11966185db85Sdougm } 11976185db85Sdougm return (ret); 11986185db85Sdougm } 11996185db85Sdougm 12006185db85Sdougm /* 12016185db85Sdougm * sa_abort_transaction(handle) 12026185db85Sdougm * 12036185db85Sdougm * Abort the changes that were added to the transaction in the 12046185db85Sdougm * handle. Do all necessary cleanup. 12056185db85Sdougm */ 12066185db85Sdougm 12076185db85Sdougm void 12086185db85Sdougm sa_abort_transaction(scfutilhandle_t *handle) 12096185db85Sdougm { 12106185db85Sdougm if (handle->trans != NULL) { 12116185db85Sdougm scf_transaction_reset_all(handle->trans); 12126185db85Sdougm scf_transaction_destroy_children(handle->trans); 12136185db85Sdougm scf_transaction_destroy(handle->trans); 12146185db85Sdougm handle->trans = NULL; 12156185db85Sdougm } 12166185db85Sdougm } 12176185db85Sdougm 12186185db85Sdougm /* 12196185db85Sdougm * sa_set_property(handle, prop, value) 12206185db85Sdougm * 1221*25a68471Sdougm * Set a property transaction entry into the pending SMF transaction. 12226185db85Sdougm */ 12236185db85Sdougm 12246185db85Sdougm int 12256185db85Sdougm sa_set_property(scfutilhandle_t *handle, char *propname, char *valstr) 12266185db85Sdougm { 12276185db85Sdougm int ret = SA_OK; 12286185db85Sdougm scf_value_t *value; 12296185db85Sdougm scf_transaction_entry_t *entry; 12306185db85Sdougm /* 1231*25a68471Sdougm * Properties must be set in transactions and don't take 12326185db85Sdougm * effect until the transaction has been ended/committed. 12336185db85Sdougm */ 12346185db85Sdougm value = scf_value_create(handle->handle); 12356185db85Sdougm entry = scf_entry_create(handle->handle); 12366185db85Sdougm if (value != NULL && entry != NULL) { 12376185db85Sdougm if (scf_transaction_property_change(handle->trans, entry, 1238*25a68471Sdougm propname, SCF_TYPE_ASTRING) == 0 || 12396185db85Sdougm scf_transaction_property_new(handle->trans, entry, 1240*25a68471Sdougm propname, SCF_TYPE_ASTRING) == 0) { 12416185db85Sdougm if (scf_value_set_astring(value, valstr) == 0) { 12426185db85Sdougm if (scf_entry_add_value(entry, value) != 0) { 12436185db85Sdougm ret = SA_SYSTEM_ERR; 12446185db85Sdougm scf_value_destroy(value); 12456185db85Sdougm } 1246*25a68471Sdougm /* The value is in the transaction */ 12476185db85Sdougm value = NULL; 12486185db85Sdougm } else { 1249*25a68471Sdougm /* Value couldn't be constructed */ 12506185db85Sdougm ret = SA_SYSTEM_ERR; 12516185db85Sdougm } 1252*25a68471Sdougm /* The entry is in the transaction */ 12536185db85Sdougm entry = NULL; 12546185db85Sdougm } else { 12556185db85Sdougm ret = SA_SYSTEM_ERR; 12566185db85Sdougm } 12576185db85Sdougm } else { 12586185db85Sdougm ret = SA_SYSTEM_ERR; 12596185db85Sdougm } 12606185db85Sdougm if (ret == SA_SYSTEM_ERR) { 12616185db85Sdougm switch (scf_error()) { 12626185db85Sdougm case SCF_ERROR_PERMISSION_DENIED: 12636185db85Sdougm ret = SA_NO_PERMISSION; 12646185db85Sdougm break; 12656185db85Sdougm } 12666185db85Sdougm } 12676185db85Sdougm /* 1268*25a68471Sdougm * Cleanup if there were any errors that didn't leave these 12696185db85Sdougm * values where they would be cleaned up later. 12706185db85Sdougm */ 12716185db85Sdougm if (value != NULL) 12726185db85Sdougm scf_value_destroy(value); 12736185db85Sdougm if (entry != NULL) 12746185db85Sdougm scf_entry_destroy(entry); 12756185db85Sdougm return (ret); 12766185db85Sdougm } 12776185db85Sdougm 12786185db85Sdougm /* 12796185db85Sdougm * sa_commit_share(handle, group, share) 12806185db85Sdougm * 1281*25a68471Sdougm * Commit this share to the repository. 12826185db85Sdougm * properties are added if they exist but can be added later. 12836185db85Sdougm * Need to add to dfstab and sharetab, if appropriate. 12846185db85Sdougm */ 12856185db85Sdougm int 12866185db85Sdougm sa_commit_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share) 12876185db85Sdougm { 12886185db85Sdougm int ret = SA_OK; 12896185db85Sdougm char *groupname; 12906185db85Sdougm char *name; 12916185db85Sdougm char *resource; 12926185db85Sdougm char *description; 12936185db85Sdougm char *sharename; 12946185db85Sdougm ssize_t proplen; 12956185db85Sdougm char *propstring; 12966185db85Sdougm 12976185db85Sdougm /* 1298*25a68471Sdougm * Don't commit in the zfs group. We do commit legacy 12996185db85Sdougm * (default) and all other groups/shares. ZFS is handled 13006185db85Sdougm * through the ZFS configuration rather than SMF. 13016185db85Sdougm */ 13026185db85Sdougm 13036185db85Sdougm groupname = sa_get_group_attr(group, "name"); 13046185db85Sdougm if (groupname != NULL) { 13056185db85Sdougm if (strcmp(groupname, "zfs") == 0) { 13066185db85Sdougm /* 1307*25a68471Sdougm * Adding to the ZFS group will result in the sharenfs 13086185db85Sdougm * property being set but we don't want to do anything 13096185db85Sdougm * SMF related at this point. 13106185db85Sdougm */ 13116185db85Sdougm sa_free_attr_string(groupname); 13126185db85Sdougm return (ret); 13136185db85Sdougm } 13146185db85Sdougm } 13156185db85Sdougm 13166185db85Sdougm proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 13176185db85Sdougm propstring = malloc(proplen); 13186185db85Sdougm if (propstring == NULL) 13196185db85Sdougm ret = SA_NO_MEMORY; 13206185db85Sdougm 13216185db85Sdougm if (groupname != NULL && ret == SA_OK) { 13226185db85Sdougm ret = sa_get_instance(handle, groupname); 13236185db85Sdougm sa_free_attr_string(groupname); 13246185db85Sdougm groupname = NULL; 13256185db85Sdougm sharename = sa_get_share_attr(share, "id"); 13266185db85Sdougm if (sharename == NULL) { 13276185db85Sdougm /* slipped by */ 13286185db85Sdougm char shname[SA_SHARE_UUID_BUFLEN]; 13296185db85Sdougm generate_unique_sharename(shname); 13306185db85Sdougm xmlSetProp((xmlNodePtr)share, (xmlChar *)"id", 13316185db85Sdougm (xmlChar *)shname); 13326185db85Sdougm sharename = strdup(shname); 13336185db85Sdougm } 13346185db85Sdougm if (sharename != NULL) { 1335f345c0beSdougm sigset_t old, new; 13366185db85Sdougm /* 1337*25a68471Sdougm * Have a share name allocated so create a pgroup for 1338f345c0beSdougm * it. It may already exist, but that is OK. In order 1339f345c0beSdougm * to avoid creating a share pgroup that doesn't have 1340f345c0beSdougm * a path property, block signals around the critical 1341f345c0beSdougm * region of creating the share pgroup and props. 13426185db85Sdougm */ 1343f345c0beSdougm (void) sigprocmask(SIG_BLOCK, NULL, &new); 1344f345c0beSdougm (void) sigaddset(&new, SIGHUP); 1345f345c0beSdougm (void) sigaddset(&new, SIGINT); 1346f345c0beSdougm (void) sigaddset(&new, SIGQUIT); 1347f345c0beSdougm (void) sigaddset(&new, SIGTSTP); 1348f345c0beSdougm (void) sigprocmask(SIG_SETMASK, &new, &old); 1349f345c0beSdougm 13506185db85Sdougm ret = sa_create_pgroup(handle, sharename); 13516185db85Sdougm if (ret == SA_OK) { 13526185db85Sdougm /* 1353*25a68471Sdougm * Now start the transaction for the 13546185db85Sdougm * properties that define this share. They may 13556185db85Sdougm * exist so attempt to update before create. 13566185db85Sdougm */ 13576185db85Sdougm ret = sa_start_transaction(handle, sharename); 13586185db85Sdougm } 13596185db85Sdougm if (ret == SA_OK) { 13606185db85Sdougm name = sa_get_share_attr(share, "path"); 13616185db85Sdougm if (name != NULL) { 1362*25a68471Sdougm /* 1363*25a68471Sdougm * There needs to be a path 1364*25a68471Sdougm * for a share to exist. 1365*25a68471Sdougm */ 1366*25a68471Sdougm ret = sa_set_property(handle, "path", 1367*25a68471Sdougm name); 13686185db85Sdougm sa_free_attr_string(name); 13696185db85Sdougm } else { 13706185db85Sdougm ret = SA_NO_MEMORY; 13716185db85Sdougm } 13726185db85Sdougm } 13736185db85Sdougm if (ret == SA_OK) { 1374*25a68471Sdougm resource = sa_get_share_attr(share, 1375*25a68471Sdougm "resource"); 13766185db85Sdougm if (resource != NULL) { 1377*25a68471Sdougm ret = sa_set_property(handle, 1378*25a68471Sdougm "resource", resource); 13796185db85Sdougm sa_free_attr_string(resource); 13806185db85Sdougm } 13816185db85Sdougm } 13826185db85Sdougm if (ret == SA_OK) { 13836185db85Sdougm description = sa_get_share_description(share); 13846185db85Sdougm if (description != NULL) { 1385*25a68471Sdougm ret = sa_set_property(handle, 1386*25a68471Sdougm "description", 13876185db85Sdougm description); 13886185db85Sdougm sa_free_share_description(description); 13896185db85Sdougm } 13906185db85Sdougm } 1391*25a68471Sdougm /* Make sure we cleanup the transaction */ 13926185db85Sdougm if (ret == SA_OK) { 13936185db85Sdougm ret = sa_end_transaction(handle); 13946185db85Sdougm } else { 13956185db85Sdougm sa_abort_transaction(handle); 13966185db85Sdougm } 1397f345c0beSdougm 1398f345c0beSdougm (void) sigprocmask(SIG_SETMASK, &old, NULL); 1399f345c0beSdougm 14006185db85Sdougm free(sharename); 14016185db85Sdougm } 14026185db85Sdougm } 14036185db85Sdougm if (ret == SA_SYSTEM_ERR) { 14046185db85Sdougm int err = scf_error(); 14056185db85Sdougm if (err == SCF_ERROR_PERMISSION_DENIED) 14066185db85Sdougm ret = SA_NO_PERMISSION; 14076185db85Sdougm } 14086185db85Sdougm if (propstring != NULL) 14096185db85Sdougm free(propstring); 14106185db85Sdougm if (groupname != NULL) 14116185db85Sdougm sa_free_attr_string(groupname); 14126185db85Sdougm 14136185db85Sdougm return (ret); 14146185db85Sdougm } 14156185db85Sdougm 14166185db85Sdougm /* 14176185db85Sdougm * sa_delete_share(handle, group, share) 14186185db85Sdougm * 1419*25a68471Sdougm * Remove the specified share from the group (and service instance). 14206185db85Sdougm */ 14216185db85Sdougm 14226185db85Sdougm int 14236185db85Sdougm sa_delete_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share) 14246185db85Sdougm { 14256185db85Sdougm int ret = SA_OK; 14266185db85Sdougm char *groupname = NULL; 14276185db85Sdougm char *shareid = NULL; 14286185db85Sdougm sa_optionset_t opt; 14296185db85Sdougm sa_security_t sec; 14306185db85Sdougm ssize_t proplen; 14316185db85Sdougm char *propstring; 14326185db85Sdougm 14336185db85Sdougm proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 14346185db85Sdougm propstring = malloc(proplen); 14356185db85Sdougm if (propstring == NULL) 14366185db85Sdougm ret = SA_NO_MEMORY; 14376185db85Sdougm 14386185db85Sdougm if (ret == SA_OK) { 14396185db85Sdougm groupname = sa_get_group_attr(group, "name"); 14406185db85Sdougm shareid = sa_get_share_attr(share, "id"); 1441*25a68471Sdougm if (groupname == NULL || shareid == NULL) { 1442*25a68471Sdougm ret = SA_CONFIG_ERR; 1443*25a68471Sdougm goto out; 1444*25a68471Sdougm } 14456185db85Sdougm ret = sa_get_instance(handle, groupname); 14466185db85Sdougm if (ret == SA_OK) { 1447*25a68471Sdougm /* If a share has properties, remove them */ 14486185db85Sdougm ret = sa_delete_pgroup(handle, shareid); 1449*25a68471Sdougm for (opt = sa_get_optionset(share, NULL); 1450*25a68471Sdougm opt != NULL; 14516185db85Sdougm opt = sa_get_next_optionset(opt)) { 14526185db85Sdougm char *proto; 14536185db85Sdougm proto = sa_get_optionset_attr(opt, "type"); 14546185db85Sdougm if (proto != NULL) { 1455*25a68471Sdougm (void) snprintf(propstring, 1456*25a68471Sdougm proplen, "%s_%s", shareid, 1457*25a68471Sdougm proto); 1458*25a68471Sdougm ret = sa_delete_pgroup(handle, 1459*25a68471Sdougm propstring); 14606185db85Sdougm sa_free_attr_string(proto); 14616185db85Sdougm } else { 14626185db85Sdougm ret = SA_NO_MEMORY; 14636185db85Sdougm } 14646185db85Sdougm } 14656185db85Sdougm /* 1466*25a68471Sdougm * If a share has security/negotiable 14676185db85Sdougm * properties, remove them. 14686185db85Sdougm */ 1469*25a68471Sdougm for (sec = sa_get_security(share, NULL, NULL); 1470*25a68471Sdougm sec != NULL; 14716185db85Sdougm sec = sa_get_next_security(sec)) { 14726185db85Sdougm char *proto; 14736185db85Sdougm char *sectype; 14746185db85Sdougm proto = sa_get_security_attr(sec, "type"); 14756185db85Sdougm sectype = sa_get_security_attr(sec, "sectype"); 14766185db85Sdougm if (proto != NULL && sectype != NULL) { 1477*25a68471Sdougm (void) snprintf(propstring, proplen, 1478*25a68471Sdougm "%s_%s_%s", shareid, proto, 1479*25a68471Sdougm sectype); 1480*25a68471Sdougm ret = sa_delete_pgroup(handle, 1481*25a68471Sdougm propstring); 14826185db85Sdougm } else { 14836185db85Sdougm ret = SA_NO_MEMORY; 14846185db85Sdougm } 14856185db85Sdougm if (proto != NULL) 14866185db85Sdougm sa_free_attr_string(proto); 14876185db85Sdougm if (sectype != NULL) 14886185db85Sdougm sa_free_attr_string(sectype); 14896185db85Sdougm } 14906185db85Sdougm } 14916185db85Sdougm } 1492*25a68471Sdougm out: 14936185db85Sdougm if (groupname != NULL) 14946185db85Sdougm sa_free_attr_string(groupname); 14956185db85Sdougm if (shareid != NULL) 14966185db85Sdougm sa_free_attr_string(shareid); 14976185db85Sdougm if (propstring != NULL) 14986185db85Sdougm free(propstring); 14996185db85Sdougm 15006185db85Sdougm return (ret); 15016185db85Sdougm } 1502