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 /* 235b6e0c46Sdougm * Copyright 2008 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> 38da6c28aaSamw #include <ctype.h> 396185db85Sdougm #include <errno.h> 406185db85Sdougm #include <uuid/uuid.h> 416185db85Sdougm #include <sys/param.h> 42f345c0beSdougm #include <signal.h> 435b6e0c46Sdougm #include <sys/time.h> 441f29d134Sdougm #include <libintl.h> 456185db85Sdougm 466185db85Sdougm ssize_t scf_max_name_len; 476185db85Sdougm extern struct sa_proto_plugin *sap_proto_list; 48549ec3ffSdougm extern sa_handle_impl_t get_handle_for_root(xmlNodePtr); 495b6e0c46Sdougm static void set_transaction_tstamp(sa_handle_impl_t); 506185db85Sdougm /* 516185db85Sdougm * The SMF facility uses some properties that must exist. We want to 526185db85Sdougm * skip over these when processing protocol options. 536185db85Sdougm */ 546185db85Sdougm static char *skip_props[] = { 556185db85Sdougm "modify_authorization", 566185db85Sdougm "action_authorization", 576185db85Sdougm "value_authorization", 586185db85Sdougm NULL 596185db85Sdougm }; 606185db85Sdougm 616185db85Sdougm /* 626185db85Sdougm * sa_scf_fini(handle) 636185db85Sdougm * 6425a68471Sdougm * Must be called when done. Called with the handle allocated in 656185db85Sdougm * sa_scf_init(), it cleans up the state and frees any SCF resources 666185db85Sdougm * still in use. Called by sa_fini(). 676185db85Sdougm */ 686185db85Sdougm 696185db85Sdougm void 706185db85Sdougm sa_scf_fini(scfutilhandle_t *handle) 716185db85Sdougm { 726185db85Sdougm if (handle != NULL) { 736185db85Sdougm int unbind = 0; 746185db85Sdougm if (handle->scope != NULL) { 756185db85Sdougm unbind = 1; 766185db85Sdougm scf_scope_destroy(handle->scope); 776185db85Sdougm } 78a3351425Sdougm if (handle->instance != NULL) 79a3351425Sdougm scf_instance_destroy(handle->instance); 806185db85Sdougm if (handle->service != NULL) 816185db85Sdougm scf_service_destroy(handle->service); 826185db85Sdougm if (handle->pg != NULL) 836185db85Sdougm scf_pg_destroy(handle->pg); 846185db85Sdougm if (handle->handle != NULL) { 856185db85Sdougm handle->scf_state = SCH_STATE_UNINIT; 866185db85Sdougm if (unbind) 876185db85Sdougm (void) scf_handle_unbind(handle->handle); 886185db85Sdougm scf_handle_destroy(handle->handle); 896185db85Sdougm } 906185db85Sdougm free(handle); 916185db85Sdougm } 926185db85Sdougm } 936185db85Sdougm 946185db85Sdougm /* 956185db85Sdougm * sa_scf_init() 966185db85Sdougm * 9725a68471Sdougm * Must be called before using any of the SCF functions. Called by 986185db85Sdougm * sa_init() during the API setup. 996185db85Sdougm */ 1006185db85Sdougm 1016185db85Sdougm scfutilhandle_t * 102549ec3ffSdougm sa_scf_init(sa_handle_impl_t ihandle) 1036185db85Sdougm { 1046185db85Sdougm scfutilhandle_t *handle; 1056185db85Sdougm 1066185db85Sdougm scf_max_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH); 1076185db85Sdougm if (scf_max_name_len <= 0) 1086185db85Sdougm scf_max_name_len = SA_MAX_NAME_LEN + 1; 1096185db85Sdougm 1106185db85Sdougm handle = calloc(1, sizeof (scfutilhandle_t)); 11125a68471Sdougm if (handle == NULL) 11225a68471Sdougm return (handle); 11325a68471Sdougm 114549ec3ffSdougm ihandle->scfhandle = handle; 1156185db85Sdougm handle->scf_state = SCH_STATE_INITIALIZING; 1166185db85Sdougm handle->handle = scf_handle_create(SCF_VERSION); 11725a68471Sdougm if (handle->handle == NULL) { 11825a68471Sdougm free(handle); 11925a68471Sdougm handle = NULL; 12025a68471Sdougm (void) printf("libshare could not access SMF repository: %s\n", 12125a68471Sdougm scf_strerror(scf_error())); 12225a68471Sdougm return (handle); 12325a68471Sdougm } 12425a68471Sdougm if (scf_handle_bind(handle->handle) != 0) 12525a68471Sdougm goto err; 12625a68471Sdougm 1276185db85Sdougm handle->scope = scf_scope_create(handle->handle); 1286185db85Sdougm handle->service = scf_service_create(handle->handle); 1296185db85Sdougm handle->pg = scf_pg_create(handle->handle); 130a3351425Sdougm 13125a68471Sdougm /* Make sure we have sufficient SMF running */ 1326185db85Sdougm handle->instance = scf_instance_create(handle->handle); 133a3351425Sdougm if (handle->scope == NULL || handle->service == NULL || 134a3351425Sdougm handle->pg == NULL || handle->instance == NULL) 135a3351425Sdougm goto err; 1366185db85Sdougm if (scf_handle_get_scope(handle->handle, 13725a68471Sdougm SCF_SCOPE_LOCAL, handle->scope) != 0) 1386185db85Sdougm goto err; 13925a68471Sdougm if (scf_scope_get_service(handle->scope, 14025a68471Sdougm SA_GROUP_SVC_NAME, handle->service) != 0) 14125a68471Sdougm goto err; 14225a68471Sdougm 1436185db85Sdougm handle->scf_state = SCH_STATE_INIT; 1446185db85Sdougm if (sa_get_instance(handle, "default") != SA_OK) { 1456185db85Sdougm sa_group_t defgrp; 14625a68471Sdougm defgrp = sa_create_group((sa_handle_t)ihandle, "default", NULL); 1471f29d134Sdougm /* Only NFS enabled for "default" group. */ 1481f29d134Sdougm if (defgrp != NULL) 1491f29d134Sdougm (void) sa_create_optionset(defgrp, "nfs"); 1506185db85Sdougm } 15125a68471Sdougm 1526185db85Sdougm return (handle); 1536185db85Sdougm 15425a68471Sdougm /* Error handling/unwinding */ 1556185db85Sdougm err: 1566185db85Sdougm (void) sa_scf_fini(handle); 1576185db85Sdougm (void) printf("libshare SMF initialization problem: %s\n", 1586185db85Sdougm scf_strerror(scf_error())); 1596185db85Sdougm return (NULL); 1606185db85Sdougm } 1616185db85Sdougm 1626185db85Sdougm /* 1636185db85Sdougm * get_scf_limit(name) 1646185db85Sdougm * 1656185db85Sdougm * Since we use scf_limit a lot and do the same check and return the 1666185db85Sdougm * same value if it fails, implement as a function for code 1676185db85Sdougm * simplification. Basically, if name isn't found, return MAXPATHLEN 1686185db85Sdougm * (1024) so we have a reasonable default buffer size. 1696185db85Sdougm */ 1706185db85Sdougm static ssize_t 1716185db85Sdougm get_scf_limit(uint32_t name) 1726185db85Sdougm { 1736185db85Sdougm ssize_t vallen; 1746185db85Sdougm 1756185db85Sdougm vallen = scf_limit(name); 1766185db85Sdougm if (vallen == (ssize_t)-1) 1776185db85Sdougm vallen = MAXPATHLEN; 1786185db85Sdougm return (vallen); 1796185db85Sdougm } 1806185db85Sdougm 1816185db85Sdougm /* 1826185db85Sdougm * skip_property(name) 1836185db85Sdougm * 18425a68471Sdougm * Internal function to check to see if a property is an SMF magic 1856185db85Sdougm * property that needs to be skipped. 1866185db85Sdougm */ 1876185db85Sdougm static int 1886185db85Sdougm skip_property(char *name) 1896185db85Sdougm { 1906185db85Sdougm int i; 1916185db85Sdougm 1926185db85Sdougm for (i = 0; skip_props[i] != NULL; i++) 1936185db85Sdougm if (strcmp(name, skip_props[i]) == 0) 1946185db85Sdougm return (1); 1956185db85Sdougm return (0); 1966185db85Sdougm } 1976185db85Sdougm 1986185db85Sdougm /* 1996185db85Sdougm * generate_unique_sharename(sharename) 2006185db85Sdougm * 2016185db85Sdougm * Shares are represented in SMF as property groups. Due to share 2026185db85Sdougm * paths containing characters that are not allowed in SMF names and 2036185db85Sdougm * the need to be unique, we use UUIDs to construct a unique name. 2046185db85Sdougm */ 2056185db85Sdougm 2066185db85Sdougm static void 2076185db85Sdougm generate_unique_sharename(char *sharename) 2086185db85Sdougm { 2096185db85Sdougm uuid_t uuid; 2106185db85Sdougm 2116185db85Sdougm uuid_generate(uuid); 2126185db85Sdougm (void) strcpy(sharename, "S-"); 2136185db85Sdougm uuid_unparse(uuid, sharename + 2); 2146185db85Sdougm } 2156185db85Sdougm 2166185db85Sdougm /* 2176185db85Sdougm * valid_protocol(proto) 2186185db85Sdougm * 21925a68471Sdougm * Check to see if the specified protocol is a valid one for the 2206185db85Sdougm * general sharemgr facility. We determine this by checking which 2216185db85Sdougm * plugin protocols were found. 2226185db85Sdougm */ 2236185db85Sdougm 2246185db85Sdougm static int 2256185db85Sdougm valid_protocol(char *proto) 2266185db85Sdougm { 2276185db85Sdougm struct sa_proto_plugin *plugin; 2286185db85Sdougm for (plugin = sap_proto_list; plugin != NULL; 2296185db85Sdougm plugin = plugin->plugin_next) 2306185db85Sdougm if (strcmp(proto, plugin->plugin_ops->sa_protocol) == 0) 2316185db85Sdougm return (1); 2326185db85Sdougm return (0); 2336185db85Sdougm } 2346185db85Sdougm 2356185db85Sdougm /* 2366185db85Sdougm * sa_extract_pgroup(root, handle, pg, nodetype, proto, sectype) 2376185db85Sdougm * 23825a68471Sdougm * Extract the name property group and create the specified type of 2396185db85Sdougm * node on the provided group. type will be optionset or security. 2406185db85Sdougm */ 2416185db85Sdougm 2426185db85Sdougm static int 2436185db85Sdougm sa_extract_pgroup(xmlNodePtr root, scfutilhandle_t *handle, 2446185db85Sdougm scf_propertygroup_t *pg, 2456185db85Sdougm char *nodetype, char *proto, char *sectype) 2466185db85Sdougm { 2476185db85Sdougm xmlNodePtr node; 2486185db85Sdougm scf_iter_t *iter; 2496185db85Sdougm scf_property_t *prop; 2506185db85Sdougm scf_value_t *value; 2516185db85Sdougm char *name; 2526185db85Sdougm char *valuestr; 2536185db85Sdougm ssize_t vallen; 2546185db85Sdougm int ret = SA_OK; 2556185db85Sdougm 2566185db85Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 2576185db85Sdougm 2586185db85Sdougm node = xmlNewChild(root, NULL, (xmlChar *)nodetype, NULL); 25925a68471Sdougm if (node == NULL) 26025a68471Sdougm return (ret); 26125a68471Sdougm 2626185db85Sdougm if (proto != NULL) 263*7a9d7716Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto); 2646185db85Sdougm if (sectype != NULL) 265*7a9d7716Sthurlow (void) xmlSetProp(node, (xmlChar *)"sectype", 266*7a9d7716Sthurlow (xmlChar *)sectype); 2676185db85Sdougm /* 26825a68471Sdougm * Have node to work with so iterate over the properties 2696185db85Sdougm * in the pg and create option sub nodes. 2706185db85Sdougm */ 2716185db85Sdougm iter = scf_iter_create(handle->handle); 2726185db85Sdougm value = scf_value_create(handle->handle); 2736185db85Sdougm prop = scf_property_create(handle->handle); 2746185db85Sdougm name = malloc(scf_max_name_len); 2756185db85Sdougm valuestr = malloc(vallen); 2766185db85Sdougm /* 27725a68471Sdougm * Want to iterate through the properties and add them 2786185db85Sdougm * to the base optionset. 2796185db85Sdougm */ 28025a68471Sdougm if (iter == NULL || value == NULL || prop == NULL || 28125a68471Sdougm valuestr == NULL || name == NULL) { 28225a68471Sdougm ret = SA_NO_MEMORY; 28325a68471Sdougm goto out; 28425a68471Sdougm } 2856185db85Sdougm if (scf_iter_pg_properties(iter, pg) == 0) { 28625a68471Sdougm /* Now iterate the properties in the group */ 2876185db85Sdougm while (scf_iter_next_property(iter, prop) > 0) { 2886185db85Sdougm /* have a property */ 2896185db85Sdougm if (scf_property_get_name(prop, name, 2906185db85Sdougm scf_max_name_len) > 0) { 29125a68471Sdougm sa_property_t saprop; 29225a68471Sdougm /* Some properties are part of the framework */ 2936185db85Sdougm if (skip_property(name)) 2946185db85Sdougm continue; 29525a68471Sdougm if (scf_property_get_value(prop, value) != 0) 29625a68471Sdougm continue; 2976185db85Sdougm if (scf_value_get_astring(value, valuestr, 29825a68471Sdougm vallen) < 0) 29925a68471Sdougm continue; 30025a68471Sdougm saprop = sa_create_property(name, valuestr); 3016185db85Sdougm if (saprop != NULL) { 3026185db85Sdougm /* 30325a68471Sdougm * Since in SMF, don't 3046185db85Sdougm * recurse. Use xmlAddChild 3056185db85Sdougm * directly, instead. 3066185db85Sdougm */ 307*7a9d7716Sthurlow (void) xmlAddChild(node, 3086185db85Sdougm (xmlNodePtr) saprop); 3096185db85Sdougm } 3106185db85Sdougm } 3116185db85Sdougm } 3126185db85Sdougm } 31325a68471Sdougm out: 3146185db85Sdougm /* cleanup to avoid memory leaks */ 3156185db85Sdougm if (value != NULL) 3166185db85Sdougm scf_value_destroy(value); 3176185db85Sdougm if (iter != NULL) 3186185db85Sdougm scf_iter_destroy(iter); 3196185db85Sdougm if (prop != NULL) 3206185db85Sdougm scf_property_destroy(prop); 3216185db85Sdougm if (name != NULL) 3226185db85Sdougm free(name); 3236185db85Sdougm if (valuestr != NULL) 3246185db85Sdougm free(valuestr); 32525a68471Sdougm 3266185db85Sdougm return (ret); 3276185db85Sdougm } 3286185db85Sdougm 3296185db85Sdougm /* 3306185db85Sdougm * sa_extract_attrs(root, handle, instance) 3316185db85Sdougm * 33225a68471Sdougm * Local function to extract the actual attributes/properties from the 3336185db85Sdougm * property group of the service instance. These are the well known 3346185db85Sdougm * attributes of "state" and "zfs". If additional attributes are 3356185db85Sdougm * added, they should be added here. 3366185db85Sdougm */ 3376185db85Sdougm 3386185db85Sdougm static void 3396185db85Sdougm sa_extract_attrs(xmlNodePtr root, scfutilhandle_t *handle, 3406185db85Sdougm scf_instance_t *instance) 3416185db85Sdougm { 3426185db85Sdougm scf_property_t *prop; 3436185db85Sdougm scf_value_t *value; 3446185db85Sdougm char *valuestr; 3456185db85Sdougm ssize_t vallen; 3466185db85Sdougm 3476185db85Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 3486185db85Sdougm prop = scf_property_create(handle->handle); 3496185db85Sdougm value = scf_value_create(handle->handle); 3506185db85Sdougm valuestr = malloc(vallen); 35125a68471Sdougm if (prop == NULL || value == NULL || valuestr == NULL || 35225a68471Sdougm scf_instance_get_pg(instance, "operation", handle->pg) != 0) { 35325a68471Sdougm goto out; 35425a68471Sdougm } 3556185db85Sdougm /* 35625a68471Sdougm * Have a property group with desired name so now get 3576185db85Sdougm * the known attributes. 3586185db85Sdougm */ 3596185db85Sdougm if (scf_pg_get_property(handle->pg, "state", prop) == 0) { 36025a68471Sdougm /* Found the property so get the value */ 3616185db85Sdougm if (scf_property_get_value(prop, value) == 0) { 36225a68471Sdougm if (scf_value_get_astring(value, valuestr, 36325a68471Sdougm vallen) >= 0) { 364*7a9d7716Sthurlow (void) xmlSetProp(root, (xmlChar *)"state", 3656185db85Sdougm (xmlChar *)valuestr); 3666185db85Sdougm } 3676185db85Sdougm } 3686185db85Sdougm } 3696185db85Sdougm if (scf_pg_get_property(handle->pg, "zfs", prop) == 0) { 37025a68471Sdougm /* Found the property so get the value */ 3716185db85Sdougm if (scf_property_get_value(prop, value) == 0) { 37225a68471Sdougm if (scf_value_get_astring(value, valuestr, 37325a68471Sdougm vallen) > 0) { 374*7a9d7716Sthurlow (void) xmlSetProp(root, (xmlChar *)"zfs", 3756185db85Sdougm (xmlChar *)valuestr); 3766185db85Sdougm } 3776185db85Sdougm } 3786185db85Sdougm } 37925a68471Sdougm out: 3806185db85Sdougm if (valuestr != NULL) 3816185db85Sdougm free(valuestr); 3826185db85Sdougm if (value != NULL) 3836185db85Sdougm scf_value_destroy(value); 3846185db85Sdougm if (prop != NULL) 3856185db85Sdougm scf_property_destroy(prop); 3866185db85Sdougm } 3876185db85Sdougm 3886185db85Sdougm /* 38925a68471Sdougm * List of known share attributes. 3906185db85Sdougm */ 3916185db85Sdougm 3926185db85Sdougm static char *share_attr[] = { 3936185db85Sdougm "path", 3946185db85Sdougm "id", 395da6c28aaSamw "drive-letter", 396da6c28aaSamw "exclude", 3976185db85Sdougm NULL, 3986185db85Sdougm }; 3996185db85Sdougm 4006185db85Sdougm static int 4016185db85Sdougm is_share_attr(char *name) 4026185db85Sdougm { 4036185db85Sdougm int i; 4046185db85Sdougm for (i = 0; share_attr[i] != NULL; i++) 4056185db85Sdougm if (strcmp(name, share_attr[i]) == 0) 4066185db85Sdougm return (1); 4076185db85Sdougm return (0); 4086185db85Sdougm } 4096185db85Sdougm 4106185db85Sdougm /* 411da6c28aaSamw * _sa_make_resource(node, valuestr) 412da6c28aaSamw * 413da6c28aaSamw * Make a resource node on the share node. The valusestr will either 414da6c28aaSamw * be old format (SMF acceptable string) or new format (pretty much an 415da6c28aaSamw * arbitrary string with "nnn:" prefixing in order to persist 416da6c28aaSamw * mapping). The input valuestr will get modified in place. This is 417da6c28aaSamw * only used in SMF repository parsing. A possible third field will be 418da6c28aaSamw * a "description" string. 419da6c28aaSamw */ 420da6c28aaSamw 421da6c28aaSamw static void 422da6c28aaSamw _sa_make_resource(xmlNodePtr node, char *valuestr) 423da6c28aaSamw { 424da6c28aaSamw char *idx; 425da6c28aaSamw char *name; 426da6c28aaSamw char *description = NULL; 427da6c28aaSamw 428da6c28aaSamw idx = valuestr; 429da6c28aaSamw name = strchr(valuestr, ':'); 430da6c28aaSamw if (name == NULL) { 431da6c28aaSamw /* this is old form so give an index of "0" */ 432da6c28aaSamw idx = "0"; 433da6c28aaSamw name = valuestr; 434da6c28aaSamw } else { 435da6c28aaSamw /* NUL the ':' and move past it */ 436da6c28aaSamw *name++ = '\0'; 437da6c28aaSamw /* There could also be a description string */ 438da6c28aaSamw description = strchr(name, ':'); 439da6c28aaSamw if (description != NULL) 440da6c28aaSamw *description++ = '\0'; 441da6c28aaSamw } 442da6c28aaSamw node = xmlNewChild(node, NULL, (xmlChar *)"resource", NULL); 443da6c28aaSamw if (node != NULL) { 444*7a9d7716Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", (xmlChar *)name); 445*7a9d7716Sthurlow (void) xmlSetProp(node, (xmlChar *)"id", (xmlChar *)idx); 446da6c28aaSamw /* SMF values are always persistent */ 447*7a9d7716Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", 448*7a9d7716Sthurlow (xmlChar *)"persist"); 449da6c28aaSamw if (description != NULL && strlen(description) > 0) { 450da6c28aaSamw (void) xmlNewChild(node, NULL, (xmlChar *)"description", 451da6c28aaSamw (xmlChar *)description); 452da6c28aaSamw } 453da6c28aaSamw } 454da6c28aaSamw } 455da6c28aaSamw 456da6c28aaSamw 457da6c28aaSamw /* 4586185db85Sdougm * sa_share_from_pgroup 4596185db85Sdougm * 46025a68471Sdougm * Extract the share definition from the share property group. We do 4616185db85Sdougm * some sanity checking to avoid bad data. 4626185db85Sdougm * 4636185db85Sdougm * Since this is only constructing the internal data structures, we 4646185db85Sdougm * don't use the sa_* functions most of the time. 4656185db85Sdougm */ 4666185db85Sdougm void 4676185db85Sdougm sa_share_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle, 4686185db85Sdougm scf_propertygroup_t *pg, char *id) 4696185db85Sdougm { 4706185db85Sdougm xmlNodePtr node; 4716185db85Sdougm char *name; 4726185db85Sdougm scf_iter_t *iter; 4736185db85Sdougm scf_property_t *prop; 4746185db85Sdougm scf_value_t *value; 4756185db85Sdougm ssize_t vallen; 4766185db85Sdougm char *valuestr; 4776185db85Sdougm int ret = SA_OK; 478f345c0beSdougm int have_path = 0; 4796185db85Sdougm 4806185db85Sdougm /* 4816185db85Sdougm * While preliminary check (starts with 'S') passed before 4826185db85Sdougm * getting here. Need to make sure it is in ID syntax 4836185db85Sdougm * (Snnnnnn). Note that shares with properties have similar 4846185db85Sdougm * pgroups. 4856185db85Sdougm */ 4866185db85Sdougm vallen = strlen(id); 4876185db85Sdougm if (*id == SA_SHARE_PG_PREFIX[0] && vallen == SA_SHARE_PG_LEN) { 4886185db85Sdougm uuid_t uuid; 48925a68471Sdougm if (strncmp(id, SA_SHARE_PG_PREFIX, 49025a68471Sdougm SA_SHARE_PG_PREFIXLEN) != 0 || 4916185db85Sdougm uuid_parse(id + 2, uuid) < 0) 4926185db85Sdougm return; 4936185db85Sdougm } else { 4946185db85Sdougm return; 4956185db85Sdougm } 4966185db85Sdougm 4976185db85Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 4986185db85Sdougm 4996185db85Sdougm iter = scf_iter_create(handle->handle); 5006185db85Sdougm value = scf_value_create(handle->handle); 5016185db85Sdougm prop = scf_property_create(handle->handle); 5026185db85Sdougm name = malloc(scf_max_name_len); 5036185db85Sdougm valuestr = malloc(vallen); 5046185db85Sdougm 5056185db85Sdougm /* 50625a68471Sdougm * Construct the share XML node. It is similar to sa_add_share 5076185db85Sdougm * but never changes the repository. Also, there won't be any 5086185db85Sdougm * ZFS or transient shares. Root will be the group it is 5096185db85Sdougm * associated with. 5106185db85Sdougm */ 5116185db85Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"share", NULL); 5126185db85Sdougm if (node != NULL) { 5136185db85Sdougm /* 51425a68471Sdougm * Make sure the UUID part of the property group is 5156185db85Sdougm * stored in the share "id" property. We use this 5166185db85Sdougm * later. 5176185db85Sdougm */ 518*7a9d7716Sthurlow (void) xmlSetProp(node, (xmlChar *)"id", (xmlChar *)id); 519*7a9d7716Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", 520*7a9d7716Sthurlow (xmlChar *)"persist"); 5216185db85Sdougm } 5226185db85Sdougm 52325a68471Sdougm if (iter == NULL || value == NULL || prop == NULL || name == NULL) 52425a68471Sdougm goto out; 52525a68471Sdougm 52625a68471Sdougm /* Iterate over the share pg properties */ 52725a68471Sdougm if (scf_iter_pg_properties(iter, pg) != 0) 52825a68471Sdougm goto out; 52925a68471Sdougm 5306185db85Sdougm while (scf_iter_next_property(iter, prop) > 0) { 5316185db85Sdougm ret = SA_SYSTEM_ERR; /* assume the worst */ 53225a68471Sdougm if (scf_property_get_name(prop, name, scf_max_name_len) > 0) { 5336185db85Sdougm if (scf_property_get_value(prop, value) == 0) { 5346185db85Sdougm if (scf_value_get_astring(value, valuestr, 5356185db85Sdougm vallen) >= 0) { 5366185db85Sdougm ret = SA_OK; 5376185db85Sdougm } 538da6c28aaSamw } else if (strcmp(name, "resource") == 0) { 539da6c28aaSamw ret = SA_OK; 5406185db85Sdougm } 5416185db85Sdougm } 542da6c28aaSamw if (ret != SA_OK) 543da6c28aaSamw continue; 544f345c0beSdougm /* 54525a68471Sdougm * Check that we have the "path" property in 546f345c0beSdougm * name. The string in name will always be nul 547f345c0beSdougm * terminated if scf_property_get_name() 548f345c0beSdougm * succeeded. 549f345c0beSdougm */ 550f345c0beSdougm if (strcmp(name, "path") == 0) 551f345c0beSdougm have_path = 1; 5526185db85Sdougm if (is_share_attr(name)) { 5536185db85Sdougm /* 55425a68471Sdougm * If a share attr, then simple - 555da6c28aaSamw * usually path and id name 5566185db85Sdougm */ 557*7a9d7716Sthurlow (void) xmlSetProp(node, (xmlChar *)name, 5586185db85Sdougm (xmlChar *)valuestr); 559da6c28aaSamw } else if (strcmp(name, "resource") == 0) { 560da6c28aaSamw /* 561da6c28aaSamw * Resource names handled differently since 562da6c28aaSamw * there can be multiple on each share. The 563da6c28aaSamw * "resource" id must be preserved since this 564da6c28aaSamw * will be used by some protocols in mapping 565da6c28aaSamw * "property spaces" to names and is always 566da6c28aaSamw * used to create SMF property groups specific 567da6c28aaSamw * to resources. CIFS needs this. The first 568da6c28aaSamw * value is present so add and then loop for 569da6c28aaSamw * any additional. Since this is new and 570da6c28aaSamw * previous values may exist, handle 571da6c28aaSamw * conversions. 572da6c28aaSamw */ 573da6c28aaSamw scf_iter_t *viter; 574da6c28aaSamw viter = scf_iter_create(handle->handle); 575da6c28aaSamw if (viter != NULL && 576da6c28aaSamw scf_iter_property_values(viter, prop) == 0) { 577da6c28aaSamw while (scf_iter_next_value(viter, value) > 0) { 578da6c28aaSamw /* Have a value so process it */ 579da6c28aaSamw if (scf_value_get_ustring(value, 580da6c28aaSamw valuestr, vallen) >= 0) { 581da6c28aaSamw /* have a ustring */ 582da6c28aaSamw _sa_make_resource(node, 583da6c28aaSamw valuestr); 584da6c28aaSamw } else if (scf_value_get_astring(value, 585da6c28aaSamw valuestr, vallen) >= 0) { 586da6c28aaSamw /* have an astring */ 587da6c28aaSamw _sa_make_resource(node, 588da6c28aaSamw valuestr); 589da6c28aaSamw } 590da6c28aaSamw } 591da6c28aaSamw scf_iter_destroy(viter); 592da6c28aaSamw } 5936185db85Sdougm } else { 5946185db85Sdougm if (strcmp(name, "description") == 0) { 59525a68471Sdougm /* We have a description node */ 5966185db85Sdougm xmlNodePtr desc; 5976185db85Sdougm desc = xmlNewChild(node, NULL, 59825a68471Sdougm (xmlChar *)"description", NULL); 5996185db85Sdougm if (desc != NULL) 6006185db85Sdougm xmlNodeSetContent(desc, 6016185db85Sdougm (xmlChar *)valuestr); 6026185db85Sdougm } 6036185db85Sdougm } 6046185db85Sdougm } 60525a68471Sdougm out: 606f345c0beSdougm /* 60725a68471Sdougm * A share without a path is broken so we want to not include 608f345c0beSdougm * these. They shouldn't happen but if you kill a sharemgr in 609f345c0beSdougm * the process of creating a share, it could happen. They 610f345c0beSdougm * should be harmless. It is also possible that another 611f345c0beSdougm * sharemgr is running and in the process of creating a share. 612f345c0beSdougm */ 613f345c0beSdougm if (have_path == 0 && node != NULL) { 614f345c0beSdougm xmlUnlinkNode(node); 615f345c0beSdougm xmlFreeNode(node); 616f345c0beSdougm } 6176185db85Sdougm if (name != NULL) 6186185db85Sdougm free(name); 6196185db85Sdougm if (valuestr != NULL) 6206185db85Sdougm free(valuestr); 6216185db85Sdougm if (value != NULL) 6226185db85Sdougm scf_value_destroy(value); 6236185db85Sdougm if (iter != NULL) 6246185db85Sdougm scf_iter_destroy(iter); 6256185db85Sdougm if (prop != NULL) 6266185db85Sdougm scf_property_destroy(prop); 6276185db85Sdougm } 6286185db85Sdougm 6296185db85Sdougm /* 6306185db85Sdougm * find_share_by_id(shareid) 6316185db85Sdougm * 6326185db85Sdougm * Search all shares in all groups until we find the share represented 6336185db85Sdougm * by "id". 6346185db85Sdougm */ 6356185db85Sdougm 6366185db85Sdougm static sa_share_t 637549ec3ffSdougm find_share_by_id(sa_handle_t handle, char *shareid) 6386185db85Sdougm { 6396185db85Sdougm sa_group_t group; 6406185db85Sdougm sa_share_t share = NULL; 6416185db85Sdougm char *id = NULL; 6426185db85Sdougm int done = 0; 6436185db85Sdougm 64425a68471Sdougm for (group = sa_get_group(handle, NULL); 64525a68471Sdougm group != NULL && !done; 6466185db85Sdougm group = sa_get_next_group(group)) { 64725a68471Sdougm for (share = sa_get_share(group, NULL); 64825a68471Sdougm share != NULL; 6496185db85Sdougm share = sa_get_next_share(share)) { 6506185db85Sdougm id = sa_get_share_attr(share, "id"); 6516185db85Sdougm if (id != NULL && strcmp(id, shareid) == 0) { 6526185db85Sdougm sa_free_attr_string(id); 6536185db85Sdougm id = NULL; 6546185db85Sdougm done++; 6556185db85Sdougm break; 6566185db85Sdougm } 6576185db85Sdougm if (id != NULL) { 6586185db85Sdougm sa_free_attr_string(id); 6596185db85Sdougm id = NULL; 6606185db85Sdougm } 6616185db85Sdougm } 6626185db85Sdougm } 6636185db85Sdougm return (share); 6646185db85Sdougm } 6656185db85Sdougm 6666185db85Sdougm /* 667da6c28aaSamw * find_resource_by_index(share, index) 668da6c28aaSamw * 669da6c28aaSamw * Search the resource records on the share for the id index. 670da6c28aaSamw */ 671da6c28aaSamw static sa_resource_t 672da6c28aaSamw find_resource_by_index(sa_share_t share, char *index) 673da6c28aaSamw { 674da6c28aaSamw sa_resource_t resource; 675da6c28aaSamw sa_resource_t found = NULL; 676da6c28aaSamw char *id; 677da6c28aaSamw 678da6c28aaSamw for (resource = sa_get_share_resource(share, NULL); 679da6c28aaSamw resource != NULL && found == NULL; 680da6c28aaSamw resource = sa_get_next_resource(resource)) { 681da6c28aaSamw id = (char *)xmlGetProp((xmlNodePtr)resource, (xmlChar *)"id"); 682da6c28aaSamw if (id != NULL) { 683da6c28aaSamw if (strcmp(id, index) == 0) { 684da6c28aaSamw /* found it so save in "found" */ 685da6c28aaSamw found = resource; 686da6c28aaSamw } 687da6c28aaSamw sa_free_attr_string(id); 688da6c28aaSamw } 689da6c28aaSamw } 690da6c28aaSamw return (found); 691da6c28aaSamw } 692da6c28aaSamw 693da6c28aaSamw /* 694da6c28aaSamw * sa_share_props_from_pgroup(root, handle, pg, id, sahandle) 6956185db85Sdougm * 69625a68471Sdougm * Extract share properties from the SMF property group. More sanity 6976185db85Sdougm * checks are done and the share object is created. We ignore some 6986185db85Sdougm * errors that could exist in the repository and only worry about 6996185db85Sdougm * property groups that validate in naming. 7006185db85Sdougm */ 7016185db85Sdougm 7026185db85Sdougm static int 7036185db85Sdougm sa_share_props_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle, 704549ec3ffSdougm scf_propertygroup_t *pg, char *id, sa_handle_t sahandle) 7056185db85Sdougm { 7066185db85Sdougm xmlNodePtr node; 70725a68471Sdougm char *name = NULL; 70825a68471Sdougm scf_iter_t *iter = NULL; 70925a68471Sdougm scf_property_t *prop = NULL; 71025a68471Sdougm scf_value_t *value = NULL; 7116185db85Sdougm ssize_t vallen; 71225a68471Sdougm char *valuestr = NULL; 7136185db85Sdougm int ret = SA_OK; 7146185db85Sdougm char *sectype = NULL; 7156185db85Sdougm char *proto; 7166185db85Sdougm sa_share_t share; 71725a68471Sdougm uuid_t uuid; 7186185db85Sdougm 7196185db85Sdougm /* 7206185db85Sdougm * While preliminary check (starts with 'S') passed before 7216185db85Sdougm * getting here. Need to make sure it is in ID syntax 7226185db85Sdougm * (Snnnnnn). Note that shares with properties have similar 7236185db85Sdougm * pgroups. If the pg name is more than SA_SHARE_PG_LEN 7246185db85Sdougm * characters, it is likely one of the protocol/security 7256185db85Sdougm * versions. 7266185db85Sdougm */ 7276185db85Sdougm vallen = strlen(id); 72825a68471Sdougm if (*id != SA_SHARE_PG_PREFIX[0] || vallen <= SA_SHARE_PG_LEN) { 72925a68471Sdougm /* 73025a68471Sdougm * It is ok to not have what we thought since someone might 73125a68471Sdougm * have added a name via SMF. 73225a68471Sdougm */ 73325a68471Sdougm return (ret); 73425a68471Sdougm } 7356185db85Sdougm if (strncmp(id, SA_SHARE_PG_PREFIX, SA_SHARE_PG_PREFIXLEN) == 0) { 7366185db85Sdougm proto = strchr(id, '_'); 7376185db85Sdougm if (proto == NULL) 7386185db85Sdougm return (ret); 7396185db85Sdougm *proto++ = '\0'; 7406185db85Sdougm if (uuid_parse(id + SA_SHARE_PG_PREFIXLEN, uuid) < 0) 7416185db85Sdougm return (ret); 7426185db85Sdougm /* 7436185db85Sdougm * probably a legal optionset so check a few more 7446185db85Sdougm * syntax points below. 7456185db85Sdougm */ 7466185db85Sdougm if (*proto == '\0') { 7476185db85Sdougm /* not a valid proto (null) */ 7486185db85Sdougm return (ret); 7496185db85Sdougm } 750da6c28aaSamw 7516185db85Sdougm sectype = strchr(proto, '_'); 7526185db85Sdougm if (sectype != NULL) 7536185db85Sdougm *sectype++ = '\0'; 7546185db85Sdougm if (!valid_protocol(proto)) 7556185db85Sdougm return (ret); 7566185db85Sdougm } 7576185db85Sdougm 7586185db85Sdougm /* 75925a68471Sdougm * To get here, we have a valid protocol and possibly a 7606185db85Sdougm * security. We now have to find the share that it is really 7616185db85Sdougm * associated with. The "id" portion of the pgroup name will 7626185db85Sdougm * match. 7636185db85Sdougm */ 7646185db85Sdougm 765549ec3ffSdougm share = find_share_by_id(sahandle, id); 7666185db85Sdougm if (share == NULL) 7676185db85Sdougm return (SA_BAD_PATH); 7686185db85Sdougm 7696185db85Sdougm root = (xmlNodePtr)share; 7706185db85Sdougm 7716185db85Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 7726185db85Sdougm 77325a68471Sdougm if (sectype == NULL) 77425a68471Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"optionset", NULL); 77525a68471Sdougm else { 776da6c28aaSamw if (isdigit((int)*sectype)) { 777da6c28aaSamw sa_resource_t resource; 778da6c28aaSamw /* 779da6c28aaSamw * If sectype[0] is a digit, then it is an index into 780da6c28aaSamw * the resource names. We need to find a resource 781da6c28aaSamw * record and then get the properties into an 782da6c28aaSamw * optionset. The optionset becomes the "node" and the 783da6c28aaSamw * rest is hung off of the share. 784da6c28aaSamw */ 785da6c28aaSamw resource = find_resource_by_index(share, sectype); 786da6c28aaSamw if (resource != NULL) { 787da6c28aaSamw node = xmlNewChild(resource, NULL, 788da6c28aaSamw (xmlChar *)"optionset", NULL); 789da6c28aaSamw } else { 79055bf511dSas200622 /* This shouldn't happen. */ 791da6c28aaSamw ret = SA_SYSTEM_ERR; 79255bf511dSas200622 goto out; 793da6c28aaSamw } 794da6c28aaSamw } else { 795da6c28aaSamw /* 796da6c28aaSamw * If not a digit, then it is a security type 797da6c28aaSamw * (alternate option space). Security types start with 798da6c28aaSamw * an alphabetic. 799da6c28aaSamw */ 800da6c28aaSamw node = xmlNewChild(root, NULL, (xmlChar *)"security", 801da6c28aaSamw NULL); 80225a68471Sdougm if (node != NULL) 803*7a9d7716Sthurlow (void) xmlSetProp(node, (xmlChar *)"sectype", 80425a68471Sdougm (xmlChar *)sectype); 80525a68471Sdougm } 806da6c28aaSamw } 80725a68471Sdougm if (node == NULL) { 80825a68471Sdougm ret = SA_NO_MEMORY; 80925a68471Sdougm goto out; 81025a68471Sdougm } 81125a68471Sdougm 812*7a9d7716Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto); 81325a68471Sdougm /* now find the properties */ 8146185db85Sdougm iter = scf_iter_create(handle->handle); 8156185db85Sdougm value = scf_value_create(handle->handle); 8166185db85Sdougm prop = scf_property_create(handle->handle); 8176185db85Sdougm name = malloc(scf_max_name_len); 8186185db85Sdougm valuestr = malloc(vallen); 8196185db85Sdougm 82025a68471Sdougm if (iter == NULL || value == NULL || prop == NULL || name == NULL) 82125a68471Sdougm goto out; 82225a68471Sdougm 823da6c28aaSamw /* iterate over the share pg properties */ 8246185db85Sdougm if (scf_iter_pg_properties(iter, pg) == 0) { 8256185db85Sdougm while (scf_iter_next_property(iter, prop) > 0) { 8266185db85Sdougm ret = SA_SYSTEM_ERR; /* assume the worst */ 8276185db85Sdougm if (scf_property_get_name(prop, name, 8286185db85Sdougm scf_max_name_len) > 0) { 8296185db85Sdougm if (scf_property_get_value(prop, value) == 0) { 83025a68471Sdougm if (scf_value_get_astring(value, 83125a68471Sdougm valuestr, vallen) >= 0) { 8326185db85Sdougm ret = SA_OK; 8336185db85Sdougm } 8346185db85Sdougm } 8356185db85Sdougm } else { 8366185db85Sdougm ret = SA_SYSTEM_ERR; 8376185db85Sdougm } 8386185db85Sdougm if (ret == SA_OK) { 8396185db85Sdougm sa_property_t prop; 8406185db85Sdougm prop = sa_create_property(name, valuestr); 8416185db85Sdougm if (prop != NULL) 8426185db85Sdougm prop = (sa_property_t)xmlAddChild(node, 8436185db85Sdougm (xmlNodePtr)prop); 8446185db85Sdougm else 8456185db85Sdougm ret = SA_NO_MEMORY; 8466185db85Sdougm } 8476185db85Sdougm } 8486185db85Sdougm } else { 8496185db85Sdougm ret = SA_SYSTEM_ERR; 8506185db85Sdougm } 85125a68471Sdougm out: 8526185db85Sdougm if (iter != NULL) 8536185db85Sdougm scf_iter_destroy(iter); 8546185db85Sdougm if (value != NULL) 8556185db85Sdougm scf_value_destroy(value); 8566185db85Sdougm if (prop != NULL) 8576185db85Sdougm scf_property_destroy(prop); 8586185db85Sdougm if (name != NULL) 8596185db85Sdougm free(name); 8606185db85Sdougm if (valuestr != NULL) 8616185db85Sdougm free(valuestr); 8626185db85Sdougm return (ret); 8636185db85Sdougm } 8646185db85Sdougm 8656185db85Sdougm /* 8666185db85Sdougm * sa_extract_group(root, handle, instance) 8676185db85Sdougm * 86825a68471Sdougm * Get the config info for this instance of a group and create the XML 8696185db85Sdougm * subtree from it. 8706185db85Sdougm */ 8716185db85Sdougm 8726185db85Sdougm static int 8736185db85Sdougm sa_extract_group(xmlNodePtr root, scfutilhandle_t *handle, 874549ec3ffSdougm scf_instance_t *instance, sa_handle_t sahandle) 8756185db85Sdougm { 8766185db85Sdougm char *buff; 8776185db85Sdougm xmlNodePtr node; 8786185db85Sdougm scf_iter_t *iter; 8796185db85Sdougm char *proto; 8806185db85Sdougm char *sectype; 8811f29d134Sdougm boolean_t have_shares = B_FALSE; 8821f29d134Sdougm boolean_t is_default = B_FALSE; 8831f29d134Sdougm boolean_t is_nfs = B_FALSE; 8846185db85Sdougm int ret = SA_OK; 8856185db85Sdougm int err; 8866185db85Sdougm 8876185db85Sdougm buff = malloc(scf_max_name_len); 88825a68471Sdougm if (buff == NULL) 88925a68471Sdougm return (SA_NO_MEMORY); 89025a68471Sdougm 8916185db85Sdougm iter = scf_iter_create(handle->handle); 89225a68471Sdougm if (iter == NULL) { 89325a68471Sdougm ret = SA_NO_MEMORY; 89425a68471Sdougm goto out; 89525a68471Sdougm } 89625a68471Sdougm 89725a68471Sdougm if (scf_instance_get_name(instance, buff, scf_max_name_len) > 0) { 8986185db85Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"group", NULL); 89925a68471Sdougm if (node == NULL) { 90025a68471Sdougm ret = SA_NO_MEMORY; 90125a68471Sdougm goto out; 90225a68471Sdougm } 903*7a9d7716Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", (xmlChar *)buff); 9046185db85Sdougm if (strcmp(buff, "default") == 0) 9051f29d134Sdougm is_default = B_TRUE; 90625a68471Sdougm 9076185db85Sdougm sa_extract_attrs(node, handle, instance); 9086185db85Sdougm /* 9096185db85Sdougm * Iterate through all the property groups 9106185db85Sdougm * looking for those with security or 9116185db85Sdougm * optionset prefixes. The names of the 9126185db85Sdougm * matching pgroups are parsed to get the 9136185db85Sdougm * protocol, and for security, the sectype. 9146185db85Sdougm * Syntax is as follows: 9156185db85Sdougm * optionset | optionset_<proto> 9166185db85Sdougm * security_default | security_<proto>_<sectype> 9176185db85Sdougm * "operation" is handled by 9186185db85Sdougm * sa_extract_attrs(). 9196185db85Sdougm */ 92025a68471Sdougm if (scf_iter_instance_pgs(iter, instance) != 0) { 92125a68471Sdougm ret = SA_NO_MEMORY; 92225a68471Sdougm goto out; 92325a68471Sdougm } 9246185db85Sdougm while (scf_iter_next_pg(iter, handle->pg) > 0) { 92525a68471Sdougm /* Have a pgroup so sort it out */ 9266185db85Sdougm ret = scf_pg_get_name(handle->pg, buff, 9276185db85Sdougm scf_max_name_len); 9281f29d134Sdougm if (ret <= 0) 9291f29d134Sdougm continue; 9301f29d134Sdougm is_nfs = B_FALSE; 9311f29d134Sdougm 9326185db85Sdougm if (buff[0] == SA_SHARE_PG_PREFIX[0]) { 9336185db85Sdougm sa_share_from_pgroup(node, handle, 93425a68471Sdougm handle->pg, buff); 9351f29d134Sdougm have_shares = B_TRUE; 9361f29d134Sdougm } else if (strncmp(buff, "optionset", 9) == 0) { 9376185db85Sdougm char *nodetype = "optionset"; 93825a68471Sdougm /* Have an optionset */ 9396185db85Sdougm sectype = NULL; 9406185db85Sdougm proto = strchr(buff, '_'); 9416185db85Sdougm if (proto != NULL) { 9426185db85Sdougm *proto++ = '\0'; 9436185db85Sdougm sectype = strchr(proto, '_'); 9446185db85Sdougm if (sectype != NULL) { 9456185db85Sdougm *sectype++ = '\0'; 9466185db85Sdougm nodetype = "security"; 9476185db85Sdougm } 9481f29d134Sdougm is_nfs = strcmp(proto, "nfs") == 0; 9491f29d134Sdougm } else if (strlen(buff) > 9) { 9501f29d134Sdougm /* 9511f29d134Sdougm * This can only occur if 9521f29d134Sdougm * someone has made changes 9531f29d134Sdougm * via an SMF command. Since 9541f29d134Sdougm * this would be an unknown 9551f29d134Sdougm * syntax, we just ignore it. 9561f29d134Sdougm */ 9571f29d134Sdougm continue; 9586185db85Sdougm } 9591f29d134Sdougm /* 9601f29d134Sdougm * If the group is not "default" or is 9611f29d134Sdougm * "default" and is_nfs, then extract the 9621f29d134Sdougm * pgroup. If it is_default and !is_nfs, 9631f29d134Sdougm * then we have an error and should remove 9641f29d134Sdougm * the extraneous protocols. We don't care 9651f29d134Sdougm * about errors on scf_pg_delete since we 9661f29d134Sdougm * might not have permission during an 9671f29d134Sdougm * extract only. 9681f29d134Sdougm */ 9691f29d134Sdougm if (!is_default || is_nfs) { 9706185db85Sdougm ret = sa_extract_pgroup(node, handle, 97125a68471Sdougm handle->pg, nodetype, proto, 97225a68471Sdougm sectype); 9731f29d134Sdougm } else { 9741f29d134Sdougm err = scf_pg_delete(handle->pg); 9751f29d134Sdougm if (err == 0) 9761f29d134Sdougm (void) fprintf(stderr, 9771f29d134Sdougm dgettext(TEXT_DOMAIN, 9781f29d134Sdougm "Removed protocol \"%s\" " 9791f29d134Sdougm "from group \"default\"\n"), 9801f29d134Sdougm proto); 9811f29d134Sdougm } 98225a68471Sdougm } else if (strncmp(buff, "security", 8) == 0) { 9836185db85Sdougm /* 98425a68471Sdougm * Have a security (note that 9856185db85Sdougm * this should change in the 9866185db85Sdougm * future) 9876185db85Sdougm */ 9886185db85Sdougm proto = strchr(buff, '_'); 9896185db85Sdougm sectype = NULL; 9906185db85Sdougm if (proto != NULL) { 9916185db85Sdougm *proto++ = '\0'; 9926185db85Sdougm sectype = strchr(proto, '_'); 9936185db85Sdougm if (sectype != NULL) 9946185db85Sdougm *sectype++ = '\0'; 9951f29d134Sdougm if (strcmp(proto, "default") == 0) 9966185db85Sdougm proto = NULL; 9976185db85Sdougm } 9986185db85Sdougm ret = sa_extract_pgroup(node, handle, 9991f29d134Sdougm handle->pg, "security", proto, sectype); 10006185db85Sdougm } 100125a68471Sdougm /* Ignore everything else */ 10026185db85Sdougm } 10036185db85Sdougm /* 10046185db85Sdougm * Make sure we have a valid default group. 10056185db85Sdougm * On first boot, default won't have any 10066185db85Sdougm * protocols defined and won't be enabled (but 10071f29d134Sdougm * should be). "default" only has NFS enabled on it. 10086185db85Sdougm */ 10096185db85Sdougm if (is_default) { 10106185db85Sdougm char *state = sa_get_group_attr((sa_group_t)node, 10116185db85Sdougm "state"); 10126185db85Sdougm 10136185db85Sdougm if (state == NULL) { 10146185db85Sdougm /* set attribute to enabled */ 10156185db85Sdougm (void) sa_set_group_attr((sa_group_t)node, 101625a68471Sdougm "state", "enabled"); 10171f29d134Sdougm (void) sa_create_optionset((sa_group_t)node, 10181f29d134Sdougm "nfs"); 10196185db85Sdougm } else { 10206185db85Sdougm sa_free_attr_string(state); 10216185db85Sdougm } 10226185db85Sdougm } 102325a68471Sdougm /* Do a second pass if shares were found */ 102425a68471Sdougm if (have_shares && scf_iter_instance_pgs(iter, instance) == 0) { 10256185db85Sdougm while (scf_iter_next_pg(iter, handle->pg) > 0) { 10266185db85Sdougm /* 102725a68471Sdougm * Have a pgroup so see if it is a 10286185db85Sdougm * share optionset 10296185db85Sdougm */ 10306185db85Sdougm err = scf_pg_get_name(handle->pg, buff, 10316185db85Sdougm scf_max_name_len); 103225a68471Sdougm if (err <= 0) 103325a68471Sdougm continue; 10346185db85Sdougm if (buff[0] == SA_SHARE_PG_PREFIX[0]) { 10356185db85Sdougm ret = sa_share_props_from_pgroup(node, 103625a68471Sdougm handle, handle->pg, buff, 103725a68471Sdougm sahandle); 10386185db85Sdougm } 10396185db85Sdougm } 10406185db85Sdougm } 10416185db85Sdougm } 104225a68471Sdougm out: 10436185db85Sdougm if (iter != NULL) 10446185db85Sdougm scf_iter_destroy(iter); 10456185db85Sdougm if (buff != NULL) 10466185db85Sdougm free(buff); 10476185db85Sdougm return (ret); 10486185db85Sdougm } 10496185db85Sdougm 10506185db85Sdougm /* 10516185db85Sdougm * sa_extract_defaults(root, handle, instance) 10526185db85Sdougm * 105325a68471Sdougm * Local function to find the default properties that live in the 1054da6c28aaSamw * default instance's "operation" property group. 10556185db85Sdougm */ 10566185db85Sdougm 10576185db85Sdougm static void 10586185db85Sdougm sa_extract_defaults(xmlNodePtr root, scfutilhandle_t *handle, 10596185db85Sdougm scf_instance_t *instance) 10606185db85Sdougm { 10616185db85Sdougm xmlNodePtr node; 10626185db85Sdougm scf_property_t *prop; 10636185db85Sdougm scf_value_t *value; 10646185db85Sdougm char *valuestr; 10656185db85Sdougm ssize_t vallen; 10666185db85Sdougm 10676185db85Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 10686185db85Sdougm prop = scf_property_create(handle->handle); 10696185db85Sdougm value = scf_value_create(handle->handle); 10706185db85Sdougm valuestr = malloc(vallen); 107125a68471Sdougm 107225a68471Sdougm if (prop == NULL || value == NULL || vallen == 0 || 107325a68471Sdougm scf_instance_get_pg(instance, "operation", handle->pg) != 0) 107425a68471Sdougm goto out; 107525a68471Sdougm 107625a68471Sdougm if (scf_pg_get_property(handle->pg, "legacy-timestamp", prop) != 0) 107725a68471Sdougm goto out; 107825a68471Sdougm 107925a68471Sdougm /* Found the property so get the value */ 10806185db85Sdougm if (scf_property_get_value(prop, value) == 0) { 10816185db85Sdougm if (scf_value_get_astring(value, valuestr, vallen) > 0) { 10826185db85Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"legacy", 10836185db85Sdougm NULL); 10846185db85Sdougm if (node != NULL) { 1085*7a9d7716Sthurlow (void) xmlSetProp(node, (xmlChar *)"timestamp", 10866185db85Sdougm (xmlChar *)valuestr); 1087*7a9d7716Sthurlow (void) xmlSetProp(node, (xmlChar *)"path", 10886185db85Sdougm (xmlChar *)SA_LEGACY_DFSTAB); 10896185db85Sdougm } 10906185db85Sdougm } 10916185db85Sdougm } 109225a68471Sdougm out: 10936185db85Sdougm if (valuestr != NULL) 10946185db85Sdougm free(valuestr); 10956185db85Sdougm if (value != NULL) 10966185db85Sdougm scf_value_destroy(value); 10976185db85Sdougm if (prop != NULL) 10986185db85Sdougm scf_property_destroy(prop); 10996185db85Sdougm } 11006185db85Sdougm 11016185db85Sdougm 11026185db85Sdougm /* 1103da6c28aaSamw * sa_get_config(handle, root, doc, sahandle) 11046185db85Sdougm * 110525a68471Sdougm * Walk the SMF repository for /network/shares/group and find all the 11066185db85Sdougm * instances. These become group names. Then add the XML structure 11076185db85Sdougm * below the groups based on property groups and properties. 11086185db85Sdougm */ 11096185db85Sdougm int 11101d1813a7Sdougm sa_get_config(scfutilhandle_t *handle, xmlNodePtr root, sa_handle_t sahandle) 11116185db85Sdougm { 11126185db85Sdougm int ret = SA_OK; 11136185db85Sdougm scf_instance_t *instance; 11146185db85Sdougm scf_iter_t *iter; 11156185db85Sdougm char buff[BUFSIZ * 2]; 11166185db85Sdougm 11176185db85Sdougm instance = scf_instance_create(handle->handle); 11186185db85Sdougm iter = scf_iter_create(handle->handle); 11191d1813a7Sdougm if (instance != NULL && iter != NULL) { 11206185db85Sdougm if ((ret = scf_iter_service_instances(iter, 11216185db85Sdougm handle->service)) == 0) { 11226185db85Sdougm while ((ret = scf_iter_next_instance(iter, 11236185db85Sdougm instance)) > 0) { 11246185db85Sdougm if (scf_instance_get_name(instance, buff, 11256185db85Sdougm sizeof (buff)) > 0) { 11266185db85Sdougm if (strcmp(buff, "default") == 0) 112725a68471Sdougm sa_extract_defaults(root, 112825a68471Sdougm handle, instance); 112925a68471Sdougm ret = sa_extract_group(root, handle, 113025a68471Sdougm instance, sahandle); 11316185db85Sdougm } 11326185db85Sdougm } 11336185db85Sdougm } 11346185db85Sdougm } 11351d1813a7Sdougm 113625a68471Sdougm /* Always cleanup these */ 11376185db85Sdougm if (instance != NULL) 11386185db85Sdougm scf_instance_destroy(instance); 11396185db85Sdougm if (iter != NULL) 11406185db85Sdougm scf_iter_destroy(iter); 11416185db85Sdougm return (ret); 11426185db85Sdougm } 11436185db85Sdougm 11446185db85Sdougm /* 11456185db85Sdougm * sa_get_instance(handle, instance) 11466185db85Sdougm * 114725a68471Sdougm * Get the instance of the group service. This is actually the 11486185db85Sdougm * specific group name. The instance is needed for all property and 11496185db85Sdougm * control operations. 11506185db85Sdougm */ 11516185db85Sdougm 11526185db85Sdougm int 11536185db85Sdougm sa_get_instance(scfutilhandle_t *handle, char *instname) 11546185db85Sdougm { 11556185db85Sdougm if (scf_service_get_instance(handle->service, instname, 11566185db85Sdougm handle->instance) != 0) { 11576185db85Sdougm return (SA_NO_SUCH_GROUP); 11586185db85Sdougm } 11596185db85Sdougm return (SA_OK); 11606185db85Sdougm } 11616185db85Sdougm 11626185db85Sdougm /* 11636185db85Sdougm * sa_create_instance(handle, instname) 11646185db85Sdougm * 11656185db85Sdougm * Create a new SMF service instance. There can only be one with a 11666185db85Sdougm * given name. 11676185db85Sdougm */ 11686185db85Sdougm 11696185db85Sdougm int 11706185db85Sdougm sa_create_instance(scfutilhandle_t *handle, char *instname) 11716185db85Sdougm { 11726185db85Sdougm int ret = SA_OK; 11736185db85Sdougm char instance[SA_GROUP_INST_LEN]; 11746185db85Sdougm if (scf_service_add_instance(handle->service, instname, 11756185db85Sdougm handle->instance) != 0) { 11766185db85Sdougm /* better error returns need to be added based on real error */ 11776185db85Sdougm if (scf_error() == SCF_ERROR_PERMISSION_DENIED) 11786185db85Sdougm ret = SA_NO_PERMISSION; 11796185db85Sdougm else 11806185db85Sdougm ret = SA_DUPLICATE_NAME; 11816185db85Sdougm } else { 11826185db85Sdougm /* have the service created, so enable it */ 11836185db85Sdougm (void) snprintf(instance, sizeof (instance), "%s:%s", 11846185db85Sdougm SA_SVC_FMRI_BASE, instname); 11856185db85Sdougm (void) smf_enable_instance(instance, 0); 11866185db85Sdougm } 11876185db85Sdougm return (ret); 11886185db85Sdougm } 11896185db85Sdougm 11906185db85Sdougm /* 11916185db85Sdougm * sa_delete_instance(handle, instname) 11926185db85Sdougm * 11936185db85Sdougm * When a group goes away, we also remove the service instance. 11946185db85Sdougm */ 11956185db85Sdougm 11966185db85Sdougm int 11976185db85Sdougm sa_delete_instance(scfutilhandle_t *handle, char *instname) 11986185db85Sdougm { 11996185db85Sdougm int ret; 12006185db85Sdougm 12016185db85Sdougm if (strcmp(instname, "default") == 0) { 12026185db85Sdougm ret = SA_NO_PERMISSION; 12036185db85Sdougm } else { 12046185db85Sdougm if ((ret = sa_get_instance(handle, instname)) == SA_OK) { 12056185db85Sdougm if (scf_instance_delete(handle->instance) != 0) 12066185db85Sdougm /* need better analysis */ 12076185db85Sdougm ret = SA_NO_PERMISSION; 12086185db85Sdougm } 12096185db85Sdougm } 12106185db85Sdougm return (ret); 12116185db85Sdougm } 12126185db85Sdougm 12136185db85Sdougm /* 12146185db85Sdougm * sa_create_pgroup(handle, pgroup) 12156185db85Sdougm * 12166185db85Sdougm * create a new property group 12176185db85Sdougm */ 12186185db85Sdougm 12196185db85Sdougm int 12206185db85Sdougm sa_create_pgroup(scfutilhandle_t *handle, char *pgroup) 12216185db85Sdougm { 12226185db85Sdougm int ret = SA_OK; 12235b6e0c46Sdougm int persist = 0; 12245b6e0c46Sdougm 12256185db85Sdougm /* 122625a68471Sdougm * Only create a handle if it doesn't exist. It is ok to exist 12276185db85Sdougm * since the pg handle will be set as a side effect. 12286185db85Sdougm */ 122925a68471Sdougm if (handle->pg == NULL) 12306185db85Sdougm handle->pg = scf_pg_create(handle->handle); 123125a68471Sdougm 12326185db85Sdougm /* 12335b6e0c46Sdougm * Special case for a non-persistent property group. This is 12345b6e0c46Sdougm * internal use only. 12355b6e0c46Sdougm */ 12365b6e0c46Sdougm if (*pgroup == '*') { 12375b6e0c46Sdougm persist = SCF_PG_FLAG_NONPERSISTENT; 12385b6e0c46Sdougm pgroup++; 12395b6e0c46Sdougm } 12405b6e0c46Sdougm 12415b6e0c46Sdougm /* 124225a68471Sdougm * If the pgroup exists, we are done. If it doesn't, then we 12436185db85Sdougm * need to actually add one to the service instance. 12446185db85Sdougm */ 12456185db85Sdougm if (scf_instance_get_pg(handle->instance, 12466185db85Sdougm pgroup, handle->pg) != 0) { 12475b6e0c46Sdougm 124825a68471Sdougm /* Doesn't exist so create one */ 12496185db85Sdougm if (scf_instance_add_pg(handle->instance, pgroup, 12505b6e0c46Sdougm SCF_GROUP_APPLICATION, persist, handle->pg) != 0) { 12516185db85Sdougm switch (scf_error()) { 12526185db85Sdougm case SCF_ERROR_PERMISSION_DENIED: 12536185db85Sdougm ret = SA_NO_PERMISSION; 12546185db85Sdougm break; 12556185db85Sdougm default: 12566185db85Sdougm ret = SA_SYSTEM_ERR; 12576185db85Sdougm break; 12586185db85Sdougm } 12596185db85Sdougm } 12606185db85Sdougm } 12616185db85Sdougm return (ret); 12626185db85Sdougm } 12636185db85Sdougm 12646185db85Sdougm /* 12656185db85Sdougm * sa_delete_pgroup(handle, pgroup) 12666185db85Sdougm * 126725a68471Sdougm * Remove the property group from the current instance of the service, 12686185db85Sdougm * but only if it actually exists. 12696185db85Sdougm */ 12706185db85Sdougm 12716185db85Sdougm int 12726185db85Sdougm sa_delete_pgroup(scfutilhandle_t *handle, char *pgroup) 12736185db85Sdougm { 12746185db85Sdougm int ret = SA_OK; 12756185db85Sdougm /* 127625a68471Sdougm * Only delete if it does exist. 12776185db85Sdougm */ 127825a68471Sdougm if (scf_instance_get_pg(handle->instance, pgroup, handle->pg) == 0) { 12796185db85Sdougm /* does exist so delete it */ 128025a68471Sdougm if (scf_pg_delete(handle->pg) != 0) 12816185db85Sdougm ret = SA_SYSTEM_ERR; 12826185db85Sdougm } else { 12836185db85Sdougm ret = SA_SYSTEM_ERR; 12846185db85Sdougm } 12856185db85Sdougm if (ret == SA_SYSTEM_ERR && 12866185db85Sdougm scf_error() == SCF_ERROR_PERMISSION_DENIED) { 12876185db85Sdougm ret = SA_NO_PERMISSION; 12886185db85Sdougm } 12896185db85Sdougm return (ret); 12906185db85Sdougm } 12916185db85Sdougm 12926185db85Sdougm /* 12936185db85Sdougm * sa_start_transaction(handle, pgroup) 12946185db85Sdougm * 12956185db85Sdougm * Start an SMF transaction so we can deal with properties. it would 12966185db85Sdougm * be nice to not have to expose this, but we have to in order to 12976185db85Sdougm * optimize. 12986185db85Sdougm * 12996185db85Sdougm * Basic model is to hold the transaction in the handle and allow 13006185db85Sdougm * property adds/deletes/updates to be added then close the 13016185db85Sdougm * transaction (or abort). There may eventually be a need to handle 13026185db85Sdougm * other types of transaction mechanisms but we don't do that now. 13036185db85Sdougm * 13046185db85Sdougm * An sa_start_transaction must be followed by either an 13056185db85Sdougm * sa_end_transaction or sa_abort_transaction before another 13066185db85Sdougm * sa_start_transaction can be done. 13076185db85Sdougm */ 13086185db85Sdougm 13096185db85Sdougm int 13106185db85Sdougm sa_start_transaction(scfutilhandle_t *handle, char *propgroup) 13116185db85Sdougm { 13126185db85Sdougm int ret = SA_OK; 13136185db85Sdougm /* 131425a68471Sdougm * Lookup the property group and create it if it doesn't already 13156185db85Sdougm * exist. 13166185db85Sdougm */ 13175b6e0c46Sdougm if (handle == NULL) 13185b6e0c46Sdougm return (SA_CONFIG_ERR); 13195b6e0c46Sdougm 13206185db85Sdougm if (handle->scf_state == SCH_STATE_INIT) { 13216185db85Sdougm ret = sa_create_pgroup(handle, propgroup); 13226185db85Sdougm if (ret == SA_OK) { 13236185db85Sdougm handle->trans = scf_transaction_create(handle->handle); 13246185db85Sdougm if (handle->trans != NULL) { 132525a68471Sdougm if (scf_transaction_start(handle->trans, 132625a68471Sdougm handle->pg) != 0) { 13276185db85Sdougm ret = SA_SYSTEM_ERR; 13286185db85Sdougm } 13296185db85Sdougm if (ret != SA_OK) { 13306185db85Sdougm scf_transaction_destroy(handle->trans); 13316185db85Sdougm handle->trans = NULL; 13326185db85Sdougm } 13336185db85Sdougm } else { 13346185db85Sdougm ret = SA_SYSTEM_ERR; 13356185db85Sdougm } 13366185db85Sdougm } 13376185db85Sdougm } 13386185db85Sdougm if (ret == SA_SYSTEM_ERR && 13396185db85Sdougm scf_error() == SCF_ERROR_PERMISSION_DENIED) { 13406185db85Sdougm ret = SA_NO_PERMISSION; 13416185db85Sdougm } 13426185db85Sdougm return (ret); 13436185db85Sdougm } 13446185db85Sdougm 13455b6e0c46Sdougm 13466185db85Sdougm /* 13475b6e0c46Sdougm * sa_end_transaction(scfhandle, sahandle) 13486185db85Sdougm * 13496185db85Sdougm * Commit the changes that were added to the transaction in the 13506185db85Sdougm * handle. Do all necessary cleanup. 13516185db85Sdougm */ 13526185db85Sdougm 13536185db85Sdougm int 13545b6e0c46Sdougm sa_end_transaction(scfutilhandle_t *handle, sa_handle_impl_t sahandle) 13556185db85Sdougm { 13566185db85Sdougm int ret = SA_OK; 13576185db85Sdougm 13585b6e0c46Sdougm if (handle == NULL || handle->trans == NULL || sahandle == NULL) { 13596185db85Sdougm ret = SA_SYSTEM_ERR; 13606185db85Sdougm } else { 13616185db85Sdougm if (scf_transaction_commit(handle->trans) < 0) 13626185db85Sdougm ret = SA_SYSTEM_ERR; 13636185db85Sdougm scf_transaction_destroy_children(handle->trans); 13646185db85Sdougm scf_transaction_destroy(handle->trans); 13655b6e0c46Sdougm if (ret == SA_OK) 13665b6e0c46Sdougm set_transaction_tstamp(sahandle); 13676185db85Sdougm handle->trans = NULL; 13686185db85Sdougm } 13696185db85Sdougm return (ret); 13706185db85Sdougm } 13716185db85Sdougm 13726185db85Sdougm /* 13736185db85Sdougm * sa_abort_transaction(handle) 13746185db85Sdougm * 13756185db85Sdougm * Abort the changes that were added to the transaction in the 13766185db85Sdougm * handle. Do all necessary cleanup. 13776185db85Sdougm */ 13786185db85Sdougm 13796185db85Sdougm void 13806185db85Sdougm sa_abort_transaction(scfutilhandle_t *handle) 13816185db85Sdougm { 13826185db85Sdougm if (handle->trans != NULL) { 13836185db85Sdougm scf_transaction_reset_all(handle->trans); 13846185db85Sdougm scf_transaction_destroy_children(handle->trans); 13856185db85Sdougm scf_transaction_destroy(handle->trans); 13866185db85Sdougm handle->trans = NULL; 13876185db85Sdougm } 13886185db85Sdougm } 13896185db85Sdougm 13906185db85Sdougm /* 13915b6e0c46Sdougm * set_transaction_tstamp(sahandle) 13925b6e0c46Sdougm * 13935b6e0c46Sdougm * After a successful transaction commit, update the timestamp of the 13945b6e0c46Sdougm * last transaction. This lets us detect changes from other processes. 13955b6e0c46Sdougm */ 13965b6e0c46Sdougm static void 13975b6e0c46Sdougm set_transaction_tstamp(sa_handle_impl_t sahandle) 13985b6e0c46Sdougm { 13995b6e0c46Sdougm char tstring[32]; 14005b6e0c46Sdougm struct timeval tv; 14015b6e0c46Sdougm scfutilhandle_t *scfhandle; 14025b6e0c46Sdougm 14035b6e0c46Sdougm if (sahandle == NULL || sahandle->scfhandle == NULL) 14045b6e0c46Sdougm return; 14055b6e0c46Sdougm 14065b6e0c46Sdougm scfhandle = sahandle->scfhandle; 14075b6e0c46Sdougm 14085b6e0c46Sdougm if (sa_get_instance(scfhandle, "default") != SA_OK) 14095b6e0c46Sdougm return; 14105b6e0c46Sdougm 14115b6e0c46Sdougm if (gettimeofday(&tv, NULL) != 0) 14125b6e0c46Sdougm return; 14135b6e0c46Sdougm 14145b6e0c46Sdougm if (sa_start_transaction(scfhandle, "*state") != SA_OK) 14155b6e0c46Sdougm return; 14165b6e0c46Sdougm 14175b6e0c46Sdougm sahandle->tstrans = TSTAMP((*(timestruc_t *)&tv)); 14185b6e0c46Sdougm (void) snprintf(tstring, sizeof (tstring), "%lld", sahandle->tstrans); 14195b6e0c46Sdougm if (sa_set_property(sahandle->scfhandle, "lastupdate", tstring) == 14205b6e0c46Sdougm SA_OK) { 14215b6e0c46Sdougm /* 14225b6e0c46Sdougm * While best if it succeeds, a failure doesn't cause 14235b6e0c46Sdougm * problems and we will ignore it anyway. 14245b6e0c46Sdougm */ 14255b6e0c46Sdougm (void) scf_transaction_commit(scfhandle->trans); 14265b6e0c46Sdougm scf_transaction_destroy_children(scfhandle->trans); 14275b6e0c46Sdougm scf_transaction_destroy(scfhandle->trans); 14285b6e0c46Sdougm } else { 14295b6e0c46Sdougm sa_abort_transaction(scfhandle); 14305b6e0c46Sdougm } 14315b6e0c46Sdougm } 14325b6e0c46Sdougm 14335b6e0c46Sdougm /* 14346185db85Sdougm * sa_set_property(handle, prop, value) 14356185db85Sdougm * 143625a68471Sdougm * Set a property transaction entry into the pending SMF transaction. 14376185db85Sdougm */ 14386185db85Sdougm 14396185db85Sdougm int 14406185db85Sdougm sa_set_property(scfutilhandle_t *handle, char *propname, char *valstr) 14416185db85Sdougm { 14426185db85Sdougm int ret = SA_OK; 14436185db85Sdougm scf_value_t *value; 14446185db85Sdougm scf_transaction_entry_t *entry; 14456185db85Sdougm /* 144625a68471Sdougm * Properties must be set in transactions and don't take 14476185db85Sdougm * effect until the transaction has been ended/committed. 14486185db85Sdougm */ 14496185db85Sdougm value = scf_value_create(handle->handle); 14506185db85Sdougm entry = scf_entry_create(handle->handle); 14516185db85Sdougm if (value != NULL && entry != NULL) { 14526185db85Sdougm if (scf_transaction_property_change(handle->trans, entry, 145325a68471Sdougm propname, SCF_TYPE_ASTRING) == 0 || 14546185db85Sdougm scf_transaction_property_new(handle->trans, entry, 145525a68471Sdougm propname, SCF_TYPE_ASTRING) == 0) { 14566185db85Sdougm if (scf_value_set_astring(value, valstr) == 0) { 14576185db85Sdougm if (scf_entry_add_value(entry, value) != 0) { 14586185db85Sdougm ret = SA_SYSTEM_ERR; 14596185db85Sdougm scf_value_destroy(value); 14606185db85Sdougm } 146125a68471Sdougm /* The value is in the transaction */ 14626185db85Sdougm value = NULL; 14636185db85Sdougm } else { 146425a68471Sdougm /* Value couldn't be constructed */ 14656185db85Sdougm ret = SA_SYSTEM_ERR; 14666185db85Sdougm } 146725a68471Sdougm /* The entry is in the transaction */ 14686185db85Sdougm entry = NULL; 14696185db85Sdougm } else { 14706185db85Sdougm ret = SA_SYSTEM_ERR; 14716185db85Sdougm } 14726185db85Sdougm } else { 14736185db85Sdougm ret = SA_SYSTEM_ERR; 14746185db85Sdougm } 14756185db85Sdougm if (ret == SA_SYSTEM_ERR) { 14766185db85Sdougm switch (scf_error()) { 14776185db85Sdougm case SCF_ERROR_PERMISSION_DENIED: 14786185db85Sdougm ret = SA_NO_PERMISSION; 14796185db85Sdougm break; 14806185db85Sdougm } 14816185db85Sdougm } 14826185db85Sdougm /* 148325a68471Sdougm * Cleanup if there were any errors that didn't leave these 14846185db85Sdougm * values where they would be cleaned up later. 14856185db85Sdougm */ 14866185db85Sdougm if (value != NULL) 14876185db85Sdougm scf_value_destroy(value); 14886185db85Sdougm if (entry != NULL) 14896185db85Sdougm scf_entry_destroy(entry); 14906185db85Sdougm return (ret); 14916185db85Sdougm } 14926185db85Sdougm 14936185db85Sdougm /* 1494da6c28aaSamw * check_resource(share) 1495da6c28aaSamw * 1496da6c28aaSamw * Check to see if share has any persistent resources. We don't want 1497da6c28aaSamw * to save if they are all transient. 1498da6c28aaSamw */ 1499da6c28aaSamw static int 1500da6c28aaSamw check_resource(sa_share_t share) 1501da6c28aaSamw { 1502da6c28aaSamw sa_resource_t resource; 1503da6c28aaSamw int ret = B_FALSE; 1504da6c28aaSamw 1505da6c28aaSamw for (resource = sa_get_share_resource(share, NULL); 1506da6c28aaSamw resource != NULL && ret == B_FALSE; 1507da6c28aaSamw resource = sa_get_next_resource(resource)) { 1508da6c28aaSamw char *type; 1509da6c28aaSamw type = sa_get_resource_attr(resource, "type"); 1510da6c28aaSamw if (type != NULL) { 1511da6c28aaSamw if (strcmp(type, "transient") != 0) { 1512da6c28aaSamw ret = B_TRUE; 1513da6c28aaSamw } 1514da6c28aaSamw sa_free_attr_string(type); 1515da6c28aaSamw } 1516da6c28aaSamw } 1517da6c28aaSamw return (ret); 1518da6c28aaSamw } 1519da6c28aaSamw 1520da6c28aaSamw /* 1521da6c28aaSamw * sa_set_resource_property(handle, prop, value) 1522da6c28aaSamw * 1523da6c28aaSamw * set a property transaction entry into the pending SMF 1524da6c28aaSamw * transaction. We don't want to include any transient resources 1525da6c28aaSamw */ 1526da6c28aaSamw 1527da6c28aaSamw static int 1528da6c28aaSamw sa_set_resource_property(scfutilhandle_t *handle, sa_share_t share) 1529da6c28aaSamw { 1530da6c28aaSamw int ret = SA_OK; 1531da6c28aaSamw scf_value_t *value; 1532da6c28aaSamw scf_transaction_entry_t *entry; 1533da6c28aaSamw sa_resource_t resource; 1534da6c28aaSamw char *valstr; 1535da6c28aaSamw char *idstr; 1536da6c28aaSamw char *description; 1537da6c28aaSamw char *propstr = NULL; 1538da6c28aaSamw size_t strsize; 1539da6c28aaSamw 1540da6c28aaSamw /* don't bother if no persistent resources */ 1541da6c28aaSamw if (check_resource(share) == B_FALSE) 1542da6c28aaSamw return (ret); 1543da6c28aaSamw 1544da6c28aaSamw /* 1545da6c28aaSamw * properties must be set in transactions and don't take 1546da6c28aaSamw * effect until the transaction has been ended/committed. 1547da6c28aaSamw */ 1548da6c28aaSamw entry = scf_entry_create(handle->handle); 1549da6c28aaSamw if (entry == NULL) 1550da6c28aaSamw return (SA_SYSTEM_ERR); 1551da6c28aaSamw 1552da6c28aaSamw if (scf_transaction_property_change(handle->trans, entry, 1553da6c28aaSamw "resource", SCF_TYPE_ASTRING) != 0 && 1554da6c28aaSamw scf_transaction_property_new(handle->trans, entry, 1555da6c28aaSamw "resource", SCF_TYPE_ASTRING) != 0) { 1556da6c28aaSamw scf_entry_destroy(entry); 1557da6c28aaSamw return (SA_SYSTEM_ERR); 1558da6c28aaSamw 1559da6c28aaSamw } 1560da6c28aaSamw for (resource = sa_get_share_resource(share, NULL); 1561da6c28aaSamw resource != NULL; 1562da6c28aaSamw resource = sa_get_next_resource(resource)) { 1563da6c28aaSamw value = scf_value_create(handle->handle); 1564da6c28aaSamw if (value == NULL) { 1565da6c28aaSamw ret = SA_NO_MEMORY; 1566da6c28aaSamw break; 1567da6c28aaSamw } 1568da6c28aaSamw /* Get size of complete string */ 1569da6c28aaSamw valstr = sa_get_resource_attr(resource, "name"); 1570da6c28aaSamw idstr = sa_get_resource_attr(resource, "id"); 1571da6c28aaSamw description = sa_get_resource_description(resource); 1572da6c28aaSamw strsize = (valstr != NULL) ? strlen(valstr) : 0; 1573da6c28aaSamw strsize += (idstr != NULL) ? strlen(idstr) : 0; 1574da6c28aaSamw strsize += (description != NULL) ? strlen(description) : 0; 1575da6c28aaSamw if (strsize > 0) { 1576da6c28aaSamw strsize += 3; /* add nul and ':' */ 1577da6c28aaSamw propstr = (char *)malloc(strsize); 1578da6c28aaSamw if (propstr == NULL) { 1579da6c28aaSamw scf_value_destroy(value); 1580da6c28aaSamw ret = SA_NO_MEMORY; 1581da6c28aaSamw goto err; 1582da6c28aaSamw } 1583da6c28aaSamw if (idstr == NULL) 1584da6c28aaSamw (void) snprintf(propstr, strsize, "%s", 1585da6c28aaSamw valstr ? valstr : ""); 1586da6c28aaSamw else 1587da6c28aaSamw (void) snprintf(propstr, strsize, "%s:%s:%s", 1588da6c28aaSamw idstr ? idstr : "", valstr ? valstr : "", 1589da6c28aaSamw description ? description : ""); 1590da6c28aaSamw if (scf_value_set_astring(value, propstr) != 0) { 1591da6c28aaSamw ret = SA_SYSTEM_ERR; 1592da6c28aaSamw free(propstr); 1593da6c28aaSamw scf_value_destroy(value); 1594da6c28aaSamw break; 1595da6c28aaSamw } 1596da6c28aaSamw if (scf_entry_add_value(entry, value) != 0) { 1597da6c28aaSamw ret = SA_SYSTEM_ERR; 1598da6c28aaSamw free(propstr); 1599da6c28aaSamw scf_value_destroy(value); 1600da6c28aaSamw break; 1601da6c28aaSamw } 1602da6c28aaSamw /* the value is in the transaction */ 1603da6c28aaSamw value = NULL; 1604da6c28aaSamw free(propstr); 1605da6c28aaSamw } 1606da6c28aaSamw err: 1607da6c28aaSamw if (valstr != NULL) 1608da6c28aaSamw sa_free_attr_string(valstr); 1609da6c28aaSamw if (idstr != NULL) 1610da6c28aaSamw sa_free_attr_string(idstr); 1611da6c28aaSamw if (description != NULL) 1612da6c28aaSamw sa_free_share_description(description); 1613da6c28aaSamw } 1614da6c28aaSamw /* the entry is in the transaction */ 1615da6c28aaSamw entry = NULL; 1616da6c28aaSamw 1617da6c28aaSamw if (ret == SA_SYSTEM_ERR) { 1618da6c28aaSamw switch (scf_error()) { 1619da6c28aaSamw case SCF_ERROR_PERMISSION_DENIED: 1620da6c28aaSamw ret = SA_NO_PERMISSION; 1621da6c28aaSamw break; 1622da6c28aaSamw } 1623da6c28aaSamw } 1624da6c28aaSamw /* 1625da6c28aaSamw * cleanup if there were any errors that didn't leave 1626da6c28aaSamw * these values where they would be cleaned up later. 1627da6c28aaSamw */ 1628da6c28aaSamw if (entry != NULL) 1629da6c28aaSamw scf_entry_destroy(entry); 1630da6c28aaSamw 1631da6c28aaSamw return (ret); 1632da6c28aaSamw } 1633da6c28aaSamw 1634da6c28aaSamw /* 16356185db85Sdougm * sa_commit_share(handle, group, share) 16366185db85Sdougm * 163725a68471Sdougm * Commit this share to the repository. 16386185db85Sdougm * properties are added if they exist but can be added later. 16396185db85Sdougm * Need to add to dfstab and sharetab, if appropriate. 16406185db85Sdougm */ 16416185db85Sdougm int 16426185db85Sdougm sa_commit_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share) 16436185db85Sdougm { 16446185db85Sdougm int ret = SA_OK; 16456185db85Sdougm char *groupname; 16466185db85Sdougm char *name; 16476185db85Sdougm char *description; 16486185db85Sdougm char *sharename; 16496185db85Sdougm ssize_t proplen; 16506185db85Sdougm char *propstring; 16516185db85Sdougm 16526185db85Sdougm /* 165325a68471Sdougm * Don't commit in the zfs group. We do commit legacy 16546185db85Sdougm * (default) and all other groups/shares. ZFS is handled 16556185db85Sdougm * through the ZFS configuration rather than SMF. 16566185db85Sdougm */ 16576185db85Sdougm 16586185db85Sdougm groupname = sa_get_group_attr(group, "name"); 16596185db85Sdougm if (groupname != NULL) { 16606185db85Sdougm if (strcmp(groupname, "zfs") == 0) { 16616185db85Sdougm /* 166225a68471Sdougm * Adding to the ZFS group will result in the sharenfs 16636185db85Sdougm * property being set but we don't want to do anything 16646185db85Sdougm * SMF related at this point. 16656185db85Sdougm */ 16666185db85Sdougm sa_free_attr_string(groupname); 16676185db85Sdougm return (ret); 16686185db85Sdougm } 16696185db85Sdougm } 16706185db85Sdougm 16716185db85Sdougm proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 16726185db85Sdougm propstring = malloc(proplen); 16736185db85Sdougm if (propstring == NULL) 16746185db85Sdougm ret = SA_NO_MEMORY; 16756185db85Sdougm 16766185db85Sdougm if (groupname != NULL && ret == SA_OK) { 16776185db85Sdougm ret = sa_get_instance(handle, groupname); 16786185db85Sdougm sa_free_attr_string(groupname); 16796185db85Sdougm groupname = NULL; 16806185db85Sdougm sharename = sa_get_share_attr(share, "id"); 16816185db85Sdougm if (sharename == NULL) { 16826185db85Sdougm /* slipped by */ 16836185db85Sdougm char shname[SA_SHARE_UUID_BUFLEN]; 16846185db85Sdougm generate_unique_sharename(shname); 1685*7a9d7716Sthurlow (void) xmlSetProp((xmlNodePtr)share, (xmlChar *)"id", 16866185db85Sdougm (xmlChar *)shname); 16876185db85Sdougm sharename = strdup(shname); 16886185db85Sdougm } 16896185db85Sdougm if (sharename != NULL) { 1690f345c0beSdougm sigset_t old, new; 16916185db85Sdougm /* 169225a68471Sdougm * Have a share name allocated so create a pgroup for 1693f345c0beSdougm * it. It may already exist, but that is OK. In order 1694f345c0beSdougm * to avoid creating a share pgroup that doesn't have 1695f345c0beSdougm * a path property, block signals around the critical 1696f345c0beSdougm * region of creating the share pgroup and props. 16976185db85Sdougm */ 1698f345c0beSdougm (void) sigprocmask(SIG_BLOCK, NULL, &new); 1699f345c0beSdougm (void) sigaddset(&new, SIGHUP); 1700f345c0beSdougm (void) sigaddset(&new, SIGINT); 1701f345c0beSdougm (void) sigaddset(&new, SIGQUIT); 1702f345c0beSdougm (void) sigaddset(&new, SIGTSTP); 1703f345c0beSdougm (void) sigprocmask(SIG_SETMASK, &new, &old); 1704f345c0beSdougm 17056185db85Sdougm ret = sa_create_pgroup(handle, sharename); 17066185db85Sdougm if (ret == SA_OK) { 17076185db85Sdougm /* 170825a68471Sdougm * Now start the transaction for the 17096185db85Sdougm * properties that define this share. They may 17106185db85Sdougm * exist so attempt to update before create. 17116185db85Sdougm */ 17126185db85Sdougm ret = sa_start_transaction(handle, sharename); 17136185db85Sdougm } 17146185db85Sdougm if (ret == SA_OK) { 17156185db85Sdougm name = sa_get_share_attr(share, "path"); 17166185db85Sdougm if (name != NULL) { 171725a68471Sdougm /* 171825a68471Sdougm * There needs to be a path 171925a68471Sdougm * for a share to exist. 172025a68471Sdougm */ 172125a68471Sdougm ret = sa_set_property(handle, "path", 172225a68471Sdougm name); 17236185db85Sdougm sa_free_attr_string(name); 17246185db85Sdougm } else { 17256185db85Sdougm ret = SA_NO_MEMORY; 17266185db85Sdougm } 17276185db85Sdougm } 17286185db85Sdougm if (ret == SA_OK) { 1729da6c28aaSamw name = sa_get_share_attr(share, "drive-letter"); 1730da6c28aaSamw if (name != NULL) { 1731da6c28aaSamw /* A drive letter may exist for SMB */ 173225a68471Sdougm ret = sa_set_property(handle, 1733da6c28aaSamw "drive-letter", name); 1734da6c28aaSamw sa_free_attr_string(name); 17356185db85Sdougm } 17366185db85Sdougm } 17376185db85Sdougm if (ret == SA_OK) { 1738da6c28aaSamw name = sa_get_share_attr(share, "exclude"); 1739da6c28aaSamw if (name != NULL) { 1740da6c28aaSamw /* 1741da6c28aaSamw * In special cases need to 1742da6c28aaSamw * exclude proto enable. 1743da6c28aaSamw */ 1744da6c28aaSamw ret = sa_set_property(handle, 1745da6c28aaSamw "exclude", name); 1746da6c28aaSamw sa_free_attr_string(name); 1747da6c28aaSamw } 1748da6c28aaSamw } 1749da6c28aaSamw if (ret == SA_OK) { 1750da6c28aaSamw /* 1751da6c28aaSamw * If there are resource names, bundle them up 1752da6c28aaSamw * and save appropriately. 1753da6c28aaSamw */ 1754da6c28aaSamw ret = sa_set_resource_property(handle, share); 1755da6c28aaSamw } 1756da6c28aaSamw 1757da6c28aaSamw if (ret == SA_OK) { 17586185db85Sdougm description = sa_get_share_description(share); 17596185db85Sdougm if (description != NULL) { 176025a68471Sdougm ret = sa_set_property(handle, 176125a68471Sdougm "description", 17626185db85Sdougm description); 17636185db85Sdougm sa_free_share_description(description); 17646185db85Sdougm } 17656185db85Sdougm } 176625a68471Sdougm /* Make sure we cleanup the transaction */ 17676185db85Sdougm if (ret == SA_OK) { 17685b6e0c46Sdougm sa_handle_impl_t sahandle; 17695b6e0c46Sdougm sahandle = (sa_handle_impl_t) 17705b6e0c46Sdougm sa_find_group_handle(group); 17715b6e0c46Sdougm if (sahandle != NULL) 17725b6e0c46Sdougm ret = sa_end_transaction(handle, 17735b6e0c46Sdougm sahandle); 17745b6e0c46Sdougm else 17755b6e0c46Sdougm ret = SA_SYSTEM_ERR; 17766185db85Sdougm } else { 17776185db85Sdougm sa_abort_transaction(handle); 17786185db85Sdougm } 1779f345c0beSdougm 1780f345c0beSdougm (void) sigprocmask(SIG_SETMASK, &old, NULL); 1781f345c0beSdougm 17826185db85Sdougm free(sharename); 17836185db85Sdougm } 17846185db85Sdougm } 17856185db85Sdougm if (ret == SA_SYSTEM_ERR) { 17866185db85Sdougm int err = scf_error(); 17876185db85Sdougm if (err == SCF_ERROR_PERMISSION_DENIED) 17886185db85Sdougm ret = SA_NO_PERMISSION; 17896185db85Sdougm } 17906185db85Sdougm if (propstring != NULL) 17916185db85Sdougm free(propstring); 17926185db85Sdougm if (groupname != NULL) 17936185db85Sdougm sa_free_attr_string(groupname); 17946185db85Sdougm 17956185db85Sdougm return (ret); 17966185db85Sdougm } 17976185db85Sdougm 17986185db85Sdougm /* 1799da6c28aaSamw * remove_resources(handle, share, shareid) 1800da6c28aaSamw * 1801da6c28aaSamw * If the share has resources, remove all of them and their 1802da6c28aaSamw * optionsets. 1803da6c28aaSamw */ 1804da6c28aaSamw static int 1805da6c28aaSamw remove_resources(scfutilhandle_t *handle, sa_share_t share, char *shareid) 1806da6c28aaSamw { 1807da6c28aaSamw sa_resource_t resource; 1808da6c28aaSamw sa_optionset_t opt; 1809da6c28aaSamw char *proto; 1810da6c28aaSamw char *id; 1811da6c28aaSamw ssize_t proplen; 1812da6c28aaSamw char *propstring; 1813da6c28aaSamw int ret = SA_OK; 1814da6c28aaSamw 1815da6c28aaSamw proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 1816da6c28aaSamw propstring = malloc(proplen); 1817da6c28aaSamw if (propstring == NULL) 1818da6c28aaSamw return (SA_NO_MEMORY); 1819da6c28aaSamw 1820da6c28aaSamw for (resource = sa_get_share_resource(share, NULL); 1821da6c28aaSamw resource != NULL; resource = sa_get_next_resource(resource)) { 1822da6c28aaSamw id = sa_get_resource_attr(resource, "id"); 1823da6c28aaSamw if (id == NULL) 1824da6c28aaSamw continue; 1825da6c28aaSamw for (opt = sa_get_optionset(resource, NULL); 1826da6c28aaSamw opt != NULL; opt = sa_get_next_optionset(resource)) { 1827da6c28aaSamw proto = sa_get_optionset_attr(opt, "type"); 1828da6c28aaSamw if (proto != NULL) { 1829da6c28aaSamw (void) snprintf(propstring, proplen, 1830da6c28aaSamw "%s_%s_%s", shareid, proto, id); 1831da6c28aaSamw ret = sa_delete_pgroup(handle, propstring); 1832da6c28aaSamw sa_free_attr_string(proto); 1833da6c28aaSamw } 1834da6c28aaSamw } 1835da6c28aaSamw sa_free_attr_string(id); 1836da6c28aaSamw } 1837da6c28aaSamw free(propstring); 1838da6c28aaSamw return (ret); 1839da6c28aaSamw } 1840da6c28aaSamw 1841da6c28aaSamw /* 18426185db85Sdougm * sa_delete_share(handle, group, share) 18436185db85Sdougm * 184425a68471Sdougm * Remove the specified share from the group (and service instance). 18456185db85Sdougm */ 18466185db85Sdougm 18476185db85Sdougm int 18486185db85Sdougm sa_delete_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share) 18496185db85Sdougm { 18506185db85Sdougm int ret = SA_OK; 18516185db85Sdougm char *groupname = NULL; 18526185db85Sdougm char *shareid = NULL; 18536185db85Sdougm sa_optionset_t opt; 18546185db85Sdougm sa_security_t sec; 18556185db85Sdougm ssize_t proplen; 18566185db85Sdougm char *propstring; 18576185db85Sdougm 18586185db85Sdougm proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 18596185db85Sdougm propstring = malloc(proplen); 18606185db85Sdougm if (propstring == NULL) 18616185db85Sdougm ret = SA_NO_MEMORY; 18626185db85Sdougm 18636185db85Sdougm if (ret == SA_OK) { 18646185db85Sdougm groupname = sa_get_group_attr(group, "name"); 18656185db85Sdougm shareid = sa_get_share_attr(share, "id"); 186625a68471Sdougm if (groupname == NULL || shareid == NULL) { 186725a68471Sdougm ret = SA_CONFIG_ERR; 186825a68471Sdougm goto out; 186925a68471Sdougm } 18706185db85Sdougm ret = sa_get_instance(handle, groupname); 18716185db85Sdougm if (ret == SA_OK) { 1872da6c28aaSamw /* If a share has resources, remove them */ 1873da6c28aaSamw ret = remove_resources(handle, share, shareid); 187425a68471Sdougm /* If a share has properties, remove them */ 18756185db85Sdougm ret = sa_delete_pgroup(handle, shareid); 187625a68471Sdougm for (opt = sa_get_optionset(share, NULL); 187725a68471Sdougm opt != NULL; 18786185db85Sdougm opt = sa_get_next_optionset(opt)) { 18796185db85Sdougm char *proto; 18806185db85Sdougm proto = sa_get_optionset_attr(opt, "type"); 18816185db85Sdougm if (proto != NULL) { 188225a68471Sdougm (void) snprintf(propstring, 188325a68471Sdougm proplen, "%s_%s", shareid, 188425a68471Sdougm proto); 188525a68471Sdougm ret = sa_delete_pgroup(handle, 188625a68471Sdougm propstring); 18876185db85Sdougm sa_free_attr_string(proto); 18886185db85Sdougm } else { 18896185db85Sdougm ret = SA_NO_MEMORY; 18906185db85Sdougm } 18916185db85Sdougm } 18926185db85Sdougm /* 189325a68471Sdougm * If a share has security/negotiable 18946185db85Sdougm * properties, remove them. 18956185db85Sdougm */ 189625a68471Sdougm for (sec = sa_get_security(share, NULL, NULL); 189725a68471Sdougm sec != NULL; 18986185db85Sdougm sec = sa_get_next_security(sec)) { 18996185db85Sdougm char *proto; 19006185db85Sdougm char *sectype; 19016185db85Sdougm proto = sa_get_security_attr(sec, "type"); 19026185db85Sdougm sectype = sa_get_security_attr(sec, "sectype"); 19036185db85Sdougm if (proto != NULL && sectype != NULL) { 190425a68471Sdougm (void) snprintf(propstring, proplen, 190525a68471Sdougm "%s_%s_%s", shareid, proto, 190625a68471Sdougm sectype); 190725a68471Sdougm ret = sa_delete_pgroup(handle, 190825a68471Sdougm propstring); 19096185db85Sdougm } else { 19106185db85Sdougm ret = SA_NO_MEMORY; 19116185db85Sdougm } 19126185db85Sdougm if (proto != NULL) 19136185db85Sdougm sa_free_attr_string(proto); 19146185db85Sdougm if (sectype != NULL) 19156185db85Sdougm sa_free_attr_string(sectype); 19166185db85Sdougm } 19176185db85Sdougm } 19186185db85Sdougm } 191925a68471Sdougm out: 19206185db85Sdougm if (groupname != NULL) 19216185db85Sdougm sa_free_attr_string(groupname); 19226185db85Sdougm if (shareid != NULL) 19236185db85Sdougm sa_free_attr_string(shareid); 19246185db85Sdougm if (propstring != NULL) 19256185db85Sdougm free(propstring); 19266185db85Sdougm 19276185db85Sdougm return (ret); 19286185db85Sdougm } 1929