13034Sdougm /* 23034Sdougm * CDDL HEADER START 33034Sdougm * 43034Sdougm * The contents of this file are subject to the terms of the 53034Sdougm * Common Development and Distribution License (the "License"). 63034Sdougm * You may not use this file except in compliance with the License. 73034Sdougm * 83034Sdougm * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 93034Sdougm * or http://www.opensolaris.org/os/licensing. 103034Sdougm * See the License for the specific language governing permissions 113034Sdougm * and limitations under the License. 123034Sdougm * 133034Sdougm * When distributing Covered Code, include this CDDL HEADER in each 143034Sdougm * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 153034Sdougm * If applicable, add the following below this CDDL HEADER, with the 163034Sdougm * fields enclosed by brackets "[]" replaced with your own identifying 173034Sdougm * information: Portions Copyright [yyyy] [name of copyright owner] 183034Sdougm * 193034Sdougm * CDDL HEADER END 203034Sdougm */ 213034Sdougm 223034Sdougm /* 233348Sdougm * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 243034Sdougm * Use is subject to license terms. 253034Sdougm */ 263034Sdougm 273034Sdougm #pragma ident "%Z%%M% %I% %E% SMI" 283034Sdougm 293034Sdougm /* helper functions for using libscf with sharemgr */ 303034Sdougm 313034Sdougm #include <libscf.h> 323034Sdougm #include <libxml/parser.h> 333034Sdougm #include <libxml/tree.h> 343034Sdougm #include "libshare.h" 353034Sdougm #include "libshare_impl.h" 363034Sdougm #include "scfutil.h" 373034Sdougm #include <string.h> 38*5331Samw #include <ctype.h> 393034Sdougm #include <errno.h> 403034Sdougm #include <uuid/uuid.h> 413034Sdougm #include <sys/param.h> 423348Sdougm #include <signal.h> 433034Sdougm 443034Sdougm ssize_t scf_max_name_len; 453034Sdougm extern struct sa_proto_plugin *sap_proto_list; 463910Sdougm extern sa_handle_impl_t get_handle_for_root(xmlNodePtr); 473034Sdougm 483034Sdougm /* 493034Sdougm * The SMF facility uses some properties that must exist. We want to 503034Sdougm * skip over these when processing protocol options. 513034Sdougm */ 523034Sdougm static char *skip_props[] = { 533034Sdougm "modify_authorization", 543034Sdougm "action_authorization", 553034Sdougm "value_authorization", 563034Sdougm NULL 573034Sdougm }; 583034Sdougm 593034Sdougm /* 603034Sdougm * sa_scf_fini(handle) 613034Sdougm * 624653Sdougm * Must be called when done. Called with the handle allocated in 633034Sdougm * sa_scf_init(), it cleans up the state and frees any SCF resources 643034Sdougm * still in use. Called by sa_fini(). 653034Sdougm */ 663034Sdougm 673034Sdougm void 683034Sdougm sa_scf_fini(scfutilhandle_t *handle) 693034Sdougm { 703034Sdougm if (handle != NULL) { 714653Sdougm int unbind = 0; 724653Sdougm if (handle->scope != NULL) { 734653Sdougm unbind = 1; 744653Sdougm scf_scope_destroy(handle->scope); 754653Sdougm } 764653Sdougm if (handle->instance != NULL) 774653Sdougm scf_instance_destroy(handle->instance); 784653Sdougm if (handle->service != NULL) 794653Sdougm scf_service_destroy(handle->service); 804653Sdougm if (handle->pg != NULL) 814653Sdougm scf_pg_destroy(handle->pg); 824653Sdougm if (handle->handle != NULL) { 834653Sdougm handle->scf_state = SCH_STATE_UNINIT; 844653Sdougm if (unbind) 854653Sdougm (void) scf_handle_unbind(handle->handle); 864653Sdougm scf_handle_destroy(handle->handle); 874653Sdougm } 884653Sdougm free(handle); 893034Sdougm } 903034Sdougm } 913034Sdougm 923034Sdougm /* 933034Sdougm * sa_scf_init() 943034Sdougm * 954653Sdougm * Must be called before using any of the SCF functions. Called by 963034Sdougm * sa_init() during the API setup. 973034Sdougm */ 983034Sdougm 993034Sdougm scfutilhandle_t * 1003910Sdougm sa_scf_init(sa_handle_impl_t ihandle) 1013034Sdougm { 1023034Sdougm scfutilhandle_t *handle; 1033034Sdougm 1043034Sdougm scf_max_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH); 1053034Sdougm if (scf_max_name_len <= 0) 1064653Sdougm scf_max_name_len = SA_MAX_NAME_LEN + 1; 1073034Sdougm 1083034Sdougm handle = calloc(1, sizeof (scfutilhandle_t)); 1094653Sdougm if (handle == NULL) 1104653Sdougm return (handle); 1114345Sdougm 1124653Sdougm ihandle->scfhandle = handle; 1134653Sdougm handle->scf_state = SCH_STATE_INITIALIZING; 1144653Sdougm handle->handle = scf_handle_create(SCF_VERSION); 1154653Sdougm if (handle->handle == NULL) { 1163034Sdougm free(handle); 1173034Sdougm handle = NULL; 1183034Sdougm (void) printf("libshare could not access SMF repository: %s\n", 1194653Sdougm scf_strerror(scf_error())); 1204653Sdougm return (handle); 1213034Sdougm } 1224653Sdougm if (scf_handle_bind(handle->handle) != 0) 1234653Sdougm goto err; 1244653Sdougm 1254653Sdougm handle->scope = scf_scope_create(handle->handle); 1264653Sdougm handle->service = scf_service_create(handle->handle); 1274653Sdougm handle->pg = scf_pg_create(handle->handle); 1284653Sdougm 1294653Sdougm /* Make sure we have sufficient SMF running */ 1304653Sdougm handle->instance = scf_instance_create(handle->handle); 1314653Sdougm if (handle->scope == NULL || handle->service == NULL || 1324653Sdougm handle->pg == NULL || handle->instance == NULL) 1334653Sdougm goto err; 1344653Sdougm if (scf_handle_get_scope(handle->handle, 1354653Sdougm SCF_SCOPE_LOCAL, handle->scope) != 0) 1364653Sdougm goto err; 1374653Sdougm if (scf_scope_get_service(handle->scope, 1384653Sdougm SA_GROUP_SVC_NAME, handle->service) != 0) 1394653Sdougm goto err; 1404653Sdougm 1414653Sdougm handle->scf_state = SCH_STATE_INIT; 1424653Sdougm if (sa_get_instance(handle, "default") != SA_OK) { 1434653Sdougm char **protolist; 1444653Sdougm int numprotos, i; 1454653Sdougm sa_group_t defgrp; 1464653Sdougm defgrp = sa_create_group((sa_handle_t)ihandle, "default", NULL); 1474653Sdougm if (defgrp != NULL) { 1484653Sdougm numprotos = sa_get_protocols( 1494653Sdougm &protolist); 1504653Sdougm for (i = 0; i < numprotos; i++) 1514653Sdougm (void) sa_create_optionset(defgrp, 1524653Sdougm protolist[i]); 1534653Sdougm if (protolist != NULL) 1544653Sdougm free(protolist); 1554653Sdougm } 1564653Sdougm } 1574653Sdougm 1583034Sdougm return (handle); 1593034Sdougm 1604653Sdougm /* Error handling/unwinding */ 1613034Sdougm err: 1623034Sdougm (void) sa_scf_fini(handle); 1633034Sdougm (void) printf("libshare SMF initialization problem: %s\n", 1644653Sdougm scf_strerror(scf_error())); 1653034Sdougm return (NULL); 1663034Sdougm } 1673034Sdougm 1683034Sdougm /* 1693034Sdougm * get_scf_limit(name) 1703034Sdougm * 1713034Sdougm * Since we use scf_limit a lot and do the same check and return the 1723034Sdougm * same value if it fails, implement as a function for code 1733034Sdougm * simplification. Basically, if name isn't found, return MAXPATHLEN 1743034Sdougm * (1024) so we have a reasonable default buffer size. 1753034Sdougm */ 1763034Sdougm static ssize_t 1773034Sdougm get_scf_limit(uint32_t name) 1783034Sdougm { 1793034Sdougm ssize_t vallen; 1803034Sdougm 1813034Sdougm vallen = scf_limit(name); 1823034Sdougm if (vallen == (ssize_t)-1) 1834653Sdougm vallen = MAXPATHLEN; 1843034Sdougm return (vallen); 1853034Sdougm } 1863034Sdougm 1873034Sdougm /* 1883034Sdougm * skip_property(name) 1893034Sdougm * 1904653Sdougm * Internal function to check to see if a property is an SMF magic 1913034Sdougm * property that needs to be skipped. 1923034Sdougm */ 1933034Sdougm static int 1943034Sdougm skip_property(char *name) 1953034Sdougm { 1963034Sdougm int i; 1973034Sdougm 1983034Sdougm for (i = 0; skip_props[i] != NULL; i++) 1994653Sdougm if (strcmp(name, skip_props[i]) == 0) 2003034Sdougm return (1); 2013034Sdougm return (0); 2023034Sdougm } 2033034Sdougm 2043034Sdougm /* 2053034Sdougm * generate_unique_sharename(sharename) 2063034Sdougm * 2073034Sdougm * Shares are represented in SMF as property groups. Due to share 2083034Sdougm * paths containing characters that are not allowed in SMF names and 2093034Sdougm * the need to be unique, we use UUIDs to construct a unique name. 2103034Sdougm */ 2113034Sdougm 2123034Sdougm static void 2133034Sdougm generate_unique_sharename(char *sharename) 2143034Sdougm { 2153034Sdougm uuid_t uuid; 2163034Sdougm 2173034Sdougm uuid_generate(uuid); 2183034Sdougm (void) strcpy(sharename, "S-"); 2193034Sdougm uuid_unparse(uuid, sharename + 2); 2203034Sdougm } 2213034Sdougm 2223034Sdougm /* 2233034Sdougm * valid_protocol(proto) 2243034Sdougm * 2254653Sdougm * Check to see if the specified protocol is a valid one for the 2263034Sdougm * general sharemgr facility. We determine this by checking which 2273034Sdougm * plugin protocols were found. 2283034Sdougm */ 2293034Sdougm 2303034Sdougm static int 2313034Sdougm valid_protocol(char *proto) 2323034Sdougm { 2333034Sdougm struct sa_proto_plugin *plugin; 2343034Sdougm for (plugin = sap_proto_list; plugin != NULL; 2353034Sdougm plugin = plugin->plugin_next) 2364653Sdougm if (strcmp(proto, plugin->plugin_ops->sa_protocol) == 0) 2374653Sdougm return (1); 2383034Sdougm return (0); 2393034Sdougm } 2403034Sdougm 2413034Sdougm /* 2423034Sdougm * sa_extract_pgroup(root, handle, pg, nodetype, proto, sectype) 2433034Sdougm * 2444653Sdougm * Extract the name property group and create the specified type of 2453034Sdougm * node on the provided group. type will be optionset or security. 2463034Sdougm */ 2473034Sdougm 2483034Sdougm static int 2493034Sdougm sa_extract_pgroup(xmlNodePtr root, scfutilhandle_t *handle, 2503034Sdougm scf_propertygroup_t *pg, 2513034Sdougm char *nodetype, char *proto, char *sectype) 2523034Sdougm { 2533034Sdougm xmlNodePtr node; 2543034Sdougm scf_iter_t *iter; 2553034Sdougm scf_property_t *prop; 2563034Sdougm scf_value_t *value; 2573034Sdougm char *name; 2583034Sdougm char *valuestr; 2593034Sdougm ssize_t vallen; 2603034Sdougm int ret = SA_OK; 2613034Sdougm 2623034Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 2633034Sdougm 2643034Sdougm node = xmlNewChild(root, NULL, (xmlChar *)nodetype, NULL); 2654653Sdougm if (node == NULL) 2664653Sdougm return (ret); 2674653Sdougm 2684653Sdougm if (proto != NULL) 2693034Sdougm xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto); 2704653Sdougm if (sectype != NULL) 2713034Sdougm xmlSetProp(node, (xmlChar *)"sectype", (xmlChar *)sectype); 2724653Sdougm /* 2734653Sdougm * Have node to work with so iterate over the properties 2744653Sdougm * in the pg and create option sub nodes. 2754653Sdougm */ 2764653Sdougm iter = scf_iter_create(handle->handle); 2774653Sdougm value = scf_value_create(handle->handle); 2784653Sdougm prop = scf_property_create(handle->handle); 2794653Sdougm name = malloc(scf_max_name_len); 2804653Sdougm valuestr = malloc(vallen); 2814653Sdougm /* 2824653Sdougm * Want to iterate through the properties and add them 2834653Sdougm * to the base optionset. 2844653Sdougm */ 2854653Sdougm if (iter == NULL || value == NULL || prop == NULL || 2864653Sdougm valuestr == NULL || name == NULL) { 2874653Sdougm ret = SA_NO_MEMORY; 2884653Sdougm goto out; 2894653Sdougm } 2904653Sdougm if (scf_iter_pg_properties(iter, pg) == 0) { 2914653Sdougm /* Now iterate the properties in the group */ 2924653Sdougm while (scf_iter_next_property(iter, prop) > 0) { 2934653Sdougm /* have a property */ 2944653Sdougm if (scf_property_get_name(prop, name, 2954653Sdougm scf_max_name_len) > 0) { 2964653Sdougm sa_property_t saprop; 2974653Sdougm /* Some properties are part of the framework */ 2983034Sdougm if (skip_property(name)) 2994653Sdougm continue; 3004653Sdougm if (scf_property_get_value(prop, value) != 0) 3014653Sdougm continue; 3024653Sdougm if (scf_value_get_astring(value, valuestr, 3034653Sdougm vallen) < 0) 3044653Sdougm continue; 3054653Sdougm saprop = sa_create_property(name, valuestr); 3064653Sdougm if (saprop != NULL) { 3073034Sdougm /* 3084653Sdougm * Since in SMF, don't 3093034Sdougm * recurse. Use xmlAddChild 3103034Sdougm * directly, instead. 3113034Sdougm */ 3124653Sdougm xmlAddChild(node, 3134653Sdougm (xmlNodePtr) saprop); 3143034Sdougm } 3153034Sdougm } 3163034Sdougm } 3173034Sdougm } 3184653Sdougm out: 3194653Sdougm /* cleanup to avoid memory leaks */ 3204653Sdougm if (value != NULL) 3214653Sdougm scf_value_destroy(value); 3224653Sdougm if (iter != NULL) 3234653Sdougm scf_iter_destroy(iter); 3244653Sdougm if (prop != NULL) 3254653Sdougm scf_property_destroy(prop); 3264653Sdougm if (name != NULL) 3274653Sdougm free(name); 3284653Sdougm if (valuestr != NULL) 3294653Sdougm free(valuestr); 3304653Sdougm 3313034Sdougm return (ret); 3323034Sdougm } 3333034Sdougm 3343034Sdougm /* 3353034Sdougm * sa_extract_attrs(root, handle, instance) 3363034Sdougm * 3374653Sdougm * Local function to extract the actual attributes/properties from the 3383034Sdougm * property group of the service instance. These are the well known 3393034Sdougm * attributes of "state" and "zfs". If additional attributes are 3403034Sdougm * added, they should be added here. 3413034Sdougm */ 3423034Sdougm 3433034Sdougm static void 3443034Sdougm sa_extract_attrs(xmlNodePtr root, scfutilhandle_t *handle, 3453034Sdougm scf_instance_t *instance) 3463034Sdougm { 3473034Sdougm scf_property_t *prop; 3483034Sdougm scf_value_t *value; 3493034Sdougm char *valuestr; 3503034Sdougm ssize_t vallen; 3513034Sdougm 3523034Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 3533034Sdougm prop = scf_property_create(handle->handle); 3543034Sdougm value = scf_value_create(handle->handle); 3553034Sdougm valuestr = malloc(vallen); 3564653Sdougm if (prop == NULL || value == NULL || valuestr == NULL || 3574653Sdougm scf_instance_get_pg(instance, "operation", handle->pg) != 0) { 3584653Sdougm goto out; 3594653Sdougm } 3604653Sdougm /* 3614653Sdougm * Have a property group with desired name so now get 3624653Sdougm * the known attributes. 3634653Sdougm */ 3644653Sdougm if (scf_pg_get_property(handle->pg, "state", prop) == 0) { 3654653Sdougm /* Found the property so get the value */ 3663034Sdougm if (scf_property_get_value(prop, value) == 0) { 3674653Sdougm if (scf_value_get_astring(value, valuestr, 3684653Sdougm vallen) >= 0) { 3694653Sdougm xmlSetProp(root, (xmlChar *)"state", 3703034Sdougm (xmlChar *)valuestr); 3714653Sdougm } 3723034Sdougm } 3734653Sdougm } 3744653Sdougm if (scf_pg_get_property(handle->pg, "zfs", prop) == 0) { 3754653Sdougm /* Found the property so get the value */ 3763034Sdougm if (scf_property_get_value(prop, value) == 0) { 3774653Sdougm if (scf_value_get_astring(value, valuestr, 3784653Sdougm vallen) > 0) { 3794653Sdougm xmlSetProp(root, (xmlChar *)"zfs", 3803034Sdougm (xmlChar *)valuestr); 3814653Sdougm } 3823034Sdougm } 3833034Sdougm } 3844653Sdougm out: 3853034Sdougm if (valuestr != NULL) 3864653Sdougm free(valuestr); 3873034Sdougm if (value != NULL) 3884653Sdougm scf_value_destroy(value); 3893034Sdougm if (prop != NULL) 3904653Sdougm scf_property_destroy(prop); 3913034Sdougm } 3923034Sdougm 3933034Sdougm /* 3944653Sdougm * List of known share attributes. 3953034Sdougm */ 3963034Sdougm 3973034Sdougm static char *share_attr[] = { 3983034Sdougm "path", 3993034Sdougm "id", 400*5331Samw "drive-letter", 401*5331Samw "exclude", 4023034Sdougm NULL, 4033034Sdougm }; 4043034Sdougm 4053034Sdougm static int 4063034Sdougm is_share_attr(char *name) 4073034Sdougm { 4083034Sdougm int i; 4093034Sdougm for (i = 0; share_attr[i] != NULL; i++) 4104653Sdougm if (strcmp(name, share_attr[i]) == 0) 4114653Sdougm return (1); 4123034Sdougm return (0); 4133034Sdougm } 4143034Sdougm 4153034Sdougm /* 416*5331Samw * _sa_make_resource(node, valuestr) 417*5331Samw * 418*5331Samw * Make a resource node on the share node. The valusestr will either 419*5331Samw * be old format (SMF acceptable string) or new format (pretty much an 420*5331Samw * arbitrary string with "nnn:" prefixing in order to persist 421*5331Samw * mapping). The input valuestr will get modified in place. This is 422*5331Samw * only used in SMF repository parsing. A possible third field will be 423*5331Samw * a "description" string. 424*5331Samw */ 425*5331Samw 426*5331Samw static void 427*5331Samw _sa_make_resource(xmlNodePtr node, char *valuestr) 428*5331Samw { 429*5331Samw char *idx; 430*5331Samw char *name; 431*5331Samw char *description = NULL; 432*5331Samw 433*5331Samw idx = valuestr; 434*5331Samw name = strchr(valuestr, ':'); 435*5331Samw if (name == NULL) { 436*5331Samw /* this is old form so give an index of "0" */ 437*5331Samw idx = "0"; 438*5331Samw name = valuestr; 439*5331Samw } else { 440*5331Samw /* NUL the ':' and move past it */ 441*5331Samw *name++ = '\0'; 442*5331Samw /* There could also be a description string */ 443*5331Samw description = strchr(name, ':'); 444*5331Samw if (description != NULL) 445*5331Samw *description++ = '\0'; 446*5331Samw } 447*5331Samw node = xmlNewChild(node, NULL, (xmlChar *)"resource", NULL); 448*5331Samw if (node != NULL) { 449*5331Samw xmlSetProp(node, (xmlChar *)"name", (xmlChar *)name); 450*5331Samw xmlSetProp(node, (xmlChar *)"id", (xmlChar *)idx); 451*5331Samw /* SMF values are always persistent */ 452*5331Samw xmlSetProp(node, (xmlChar *)"type", (xmlChar *)"persist"); 453*5331Samw if (description != NULL && strlen(description) > 0) { 454*5331Samw (void) xmlNewChild(node, NULL, (xmlChar *)"description", 455*5331Samw (xmlChar *)description); 456*5331Samw } 457*5331Samw } 458*5331Samw } 459*5331Samw 460*5331Samw 461*5331Samw /* 4623034Sdougm * sa_share_from_pgroup 4633034Sdougm * 4644653Sdougm * Extract the share definition from the share property group. We do 4653034Sdougm * some sanity checking to avoid bad data. 4663034Sdougm * 4673034Sdougm * Since this is only constructing the internal data structures, we 4683034Sdougm * don't use the sa_* functions most of the time. 4693034Sdougm */ 4703034Sdougm void 4713034Sdougm sa_share_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle, 4723034Sdougm scf_propertygroup_t *pg, char *id) 4733034Sdougm { 4743034Sdougm xmlNodePtr node; 4753034Sdougm char *name; 4763034Sdougm scf_iter_t *iter; 4773034Sdougm scf_property_t *prop; 4783034Sdougm scf_value_t *value; 4793034Sdougm ssize_t vallen; 4803034Sdougm char *valuestr; 4813034Sdougm int ret = SA_OK; 4823348Sdougm int have_path = 0; 4833034Sdougm 4843034Sdougm /* 4853034Sdougm * While preliminary check (starts with 'S') passed before 4863034Sdougm * getting here. Need to make sure it is in ID syntax 4873034Sdougm * (Snnnnnn). Note that shares with properties have similar 4883034Sdougm * pgroups. 4893034Sdougm */ 4903034Sdougm vallen = strlen(id); 4913034Sdougm if (*id == SA_SHARE_PG_PREFIX[0] && vallen == SA_SHARE_PG_LEN) { 4924653Sdougm uuid_t uuid; 4934653Sdougm if (strncmp(id, SA_SHARE_PG_PREFIX, 4944653Sdougm SA_SHARE_PG_PREFIXLEN) != 0 || 4954653Sdougm uuid_parse(id + 2, uuid) < 0) 4964653Sdougm return; 4974653Sdougm } else { 4983034Sdougm return; 4993034Sdougm } 5003034Sdougm 5013034Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 5023034Sdougm 5033034Sdougm iter = scf_iter_create(handle->handle); 5043034Sdougm value = scf_value_create(handle->handle); 5053034Sdougm prop = scf_property_create(handle->handle); 5063034Sdougm name = malloc(scf_max_name_len); 5073034Sdougm valuestr = malloc(vallen); 5083034Sdougm 5093034Sdougm /* 5104653Sdougm * Construct the share XML node. It is similar to sa_add_share 5113034Sdougm * but never changes the repository. Also, there won't be any 5123034Sdougm * ZFS or transient shares. Root will be the group it is 5133034Sdougm * associated with. 5143034Sdougm */ 5153034Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"share", NULL); 5163034Sdougm if (node != NULL) { 5173034Sdougm /* 5184653Sdougm * Make sure the UUID part of the property group is 5193034Sdougm * stored in the share "id" property. We use this 5203034Sdougm * later. 5213034Sdougm */ 5224653Sdougm xmlSetProp(node, (xmlChar *)"id", (xmlChar *)id); 5234653Sdougm xmlSetProp(node, (xmlChar *)"type", (xmlChar *)"persist"); 5243034Sdougm } 5253034Sdougm 5264653Sdougm if (iter == NULL || value == NULL || prop == NULL || name == NULL) 5274653Sdougm goto out; 5284653Sdougm 5294653Sdougm /* Iterate over the share pg properties */ 5304653Sdougm if (scf_iter_pg_properties(iter, pg) != 0) 5314653Sdougm goto out; 5324653Sdougm 5334653Sdougm while (scf_iter_next_property(iter, prop) > 0) { 5344653Sdougm ret = SA_SYSTEM_ERR; /* assume the worst */ 5354653Sdougm if (scf_property_get_name(prop, name, scf_max_name_len) > 0) { 5363034Sdougm if (scf_property_get_value(prop, value) == 0) { 5374653Sdougm if (scf_value_get_astring(value, valuestr, 5384653Sdougm vallen) >= 0) { 5394653Sdougm ret = SA_OK; 5404653Sdougm } 541*5331Samw } else if (strcmp(name, "resource") == 0) { 542*5331Samw ret = SA_OK; 5433034Sdougm } 5444653Sdougm } 545*5331Samw if (ret != SA_OK) 546*5331Samw continue; 547*5331Samw /* 548*5331Samw * Check that we have the "path" property in 549*5331Samw * name. The string in name will always be nul 550*5331Samw * terminated if scf_property_get_name() 551*5331Samw * succeeded. 552*5331Samw */ 553*5331Samw if (strcmp(name, "path") == 0) 554*5331Samw have_path = 1; 555*5331Samw if (is_share_attr(name)) { 5563348Sdougm /* 557*5331Samw * If a share attr, then simple - 558*5331Samw * usually path and id name 5593348Sdougm */ 560*5331Samw xmlSetProp(node, (xmlChar *)name, 561*5331Samw (xmlChar *)valuestr); 562*5331Samw } else if (strcmp(name, "resource") == 0) { 563*5331Samw /* 564*5331Samw * Resource names handled differently since 565*5331Samw * there can be multiple on each share. The 566*5331Samw * "resource" id must be preserved since this 567*5331Samw * will be used by some protocols in mapping 568*5331Samw * "property spaces" to names and is always 569*5331Samw * used to create SMF property groups specific 570*5331Samw * to resources. CIFS needs this. The first 571*5331Samw * value is present so add and then loop for 572*5331Samw * any additional. Since this is new and 573*5331Samw * previous values may exist, handle 574*5331Samw * conversions. 575*5331Samw */ 576*5331Samw scf_iter_t *viter; 577*5331Samw viter = scf_iter_create(handle->handle); 578*5331Samw if (viter != NULL && 579*5331Samw scf_iter_property_values(viter, prop) == 0) { 580*5331Samw while (scf_iter_next_value(viter, value) > 0) { 581*5331Samw /* Have a value so process it */ 582*5331Samw if (scf_value_get_ustring(value, 583*5331Samw valuestr, vallen) >= 0) { 584*5331Samw /* have a ustring */ 585*5331Samw _sa_make_resource(node, 586*5331Samw valuestr); 587*5331Samw } else if (scf_value_get_astring(value, 588*5331Samw valuestr, vallen) >= 0) { 589*5331Samw /* have an astring */ 590*5331Samw _sa_make_resource(node, 591*5331Samw valuestr); 592*5331Samw } 5934653Sdougm } 594*5331Samw scf_iter_destroy(viter); 595*5331Samw } 596*5331Samw } else { 597*5331Samw if (strcmp(name, "description") == 0) { 598*5331Samw /* We have a description node */ 599*5331Samw xmlNodePtr desc; 600*5331Samw desc = xmlNewChild(node, NULL, 601*5331Samw (xmlChar *)"description", NULL); 602*5331Samw if (desc != NULL) 603*5331Samw xmlNodeSetContent(desc, 604*5331Samw (xmlChar *)valuestr); 6053034Sdougm } 6063034Sdougm } 6073034Sdougm } 6084653Sdougm out: 6093348Sdougm /* 6104653Sdougm * A share without a path is broken so we want to not include 6113348Sdougm * these. They shouldn't happen but if you kill a sharemgr in 6123348Sdougm * the process of creating a share, it could happen. They 6133348Sdougm * should be harmless. It is also possible that another 6143348Sdougm * sharemgr is running and in the process of creating a share. 6153348Sdougm */ 6163348Sdougm if (have_path == 0 && node != NULL) { 6174653Sdougm xmlUnlinkNode(node); 6184653Sdougm xmlFreeNode(node); 6193348Sdougm } 6203034Sdougm if (name != NULL) 6214653Sdougm free(name); 6223034Sdougm if (valuestr != NULL) 6234653Sdougm free(valuestr); 6243034Sdougm if (value != NULL) 6254653Sdougm scf_value_destroy(value); 6263034Sdougm if (iter != NULL) 6274653Sdougm scf_iter_destroy(iter); 6283034Sdougm if (prop != NULL) 6294653Sdougm scf_property_destroy(prop); 6303034Sdougm } 6313034Sdougm 6323034Sdougm /* 6333034Sdougm * find_share_by_id(shareid) 6343034Sdougm * 6353034Sdougm * Search all shares in all groups until we find the share represented 6363034Sdougm * by "id". 6373034Sdougm */ 6383034Sdougm 6393034Sdougm static sa_share_t 6403910Sdougm find_share_by_id(sa_handle_t handle, char *shareid) 6413034Sdougm { 6423034Sdougm sa_group_t group; 6433034Sdougm sa_share_t share = NULL; 6443034Sdougm char *id = NULL; 6453034Sdougm int done = 0; 6463034Sdougm 6474653Sdougm for (group = sa_get_group(handle, NULL); 6484653Sdougm group != NULL && !done; 6494653Sdougm group = sa_get_next_group(group)) { 6504653Sdougm for (share = sa_get_share(group, NULL); 6514653Sdougm share != NULL; 6524653Sdougm share = sa_get_next_share(share)) { 6533034Sdougm id = sa_get_share_attr(share, "id"); 6543034Sdougm if (id != NULL && strcmp(id, shareid) == 0) { 6553034Sdougm sa_free_attr_string(id); 6563034Sdougm id = NULL; 6573034Sdougm done++; 6583034Sdougm break; 6593034Sdougm } 6603034Sdougm if (id != NULL) { 6614653Sdougm sa_free_attr_string(id); 6624653Sdougm id = NULL; 6633034Sdougm } 6643034Sdougm } 6653034Sdougm } 6663034Sdougm return (share); 6673034Sdougm } 6683034Sdougm 6693034Sdougm /* 670*5331Samw * find_resource_by_index(share, index) 671*5331Samw * 672*5331Samw * Search the resource records on the share for the id index. 673*5331Samw */ 674*5331Samw static sa_resource_t 675*5331Samw find_resource_by_index(sa_share_t share, char *index) 676*5331Samw { 677*5331Samw sa_resource_t resource; 678*5331Samw sa_resource_t found = NULL; 679*5331Samw char *id; 680*5331Samw 681*5331Samw for (resource = sa_get_share_resource(share, NULL); 682*5331Samw resource != NULL && found == NULL; 683*5331Samw resource = sa_get_next_resource(resource)) { 684*5331Samw id = (char *)xmlGetProp((xmlNodePtr)resource, (xmlChar *)"id"); 685*5331Samw if (id != NULL) { 686*5331Samw if (strcmp(id, index) == 0) { 687*5331Samw /* found it so save in "found" */ 688*5331Samw found = resource; 689*5331Samw } 690*5331Samw sa_free_attr_string(id); 691*5331Samw } 692*5331Samw } 693*5331Samw return (found); 694*5331Samw } 695*5331Samw 696*5331Samw /* 697*5331Samw * sa_share_props_from_pgroup(root, handle, pg, id, sahandle) 6983034Sdougm * 6994653Sdougm * Extract share properties from the SMF property group. More sanity 7003034Sdougm * checks are done and the share object is created. We ignore some 7013034Sdougm * errors that could exist in the repository and only worry about 7023034Sdougm * property groups that validate in naming. 7033034Sdougm */ 7043034Sdougm 7053034Sdougm static int 7063034Sdougm sa_share_props_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle, 7073910Sdougm scf_propertygroup_t *pg, char *id, sa_handle_t sahandle) 7083034Sdougm { 7093034Sdougm xmlNodePtr node; 7104653Sdougm char *name = NULL; 7114653Sdougm scf_iter_t *iter = NULL; 7124653Sdougm scf_property_t *prop = NULL; 7134653Sdougm scf_value_t *value = NULL; 7143034Sdougm ssize_t vallen; 7154653Sdougm char *valuestr = NULL; 7163034Sdougm int ret = SA_OK; 7173034Sdougm char *sectype = NULL; 7183034Sdougm char *proto; 7193034Sdougm sa_share_t share; 7204653Sdougm uuid_t uuid; 7213034Sdougm 7223034Sdougm /* 7233034Sdougm * While preliminary check (starts with 'S') passed before 7243034Sdougm * getting here. Need to make sure it is in ID syntax 7253034Sdougm * (Snnnnnn). Note that shares with properties have similar 7263034Sdougm * pgroups. If the pg name is more than SA_SHARE_PG_LEN 7273034Sdougm * characters, it is likely one of the protocol/security 7283034Sdougm * versions. 7293034Sdougm */ 7303034Sdougm vallen = strlen(id); 7314653Sdougm if (*id != SA_SHARE_PG_PREFIX[0] || vallen <= SA_SHARE_PG_LEN) { 7324653Sdougm /* 7334653Sdougm * It is ok to not have what we thought since someone might 7344653Sdougm * have added a name via SMF. 7354653Sdougm */ 7364653Sdougm return (ret); 7374653Sdougm } 7384653Sdougm if (strncmp(id, SA_SHARE_PG_PREFIX, SA_SHARE_PG_PREFIXLEN) == 0) { 7393034Sdougm proto = strchr(id, '_'); 7403034Sdougm if (proto == NULL) 7414653Sdougm return (ret); 7423034Sdougm *proto++ = '\0'; 7433034Sdougm if (uuid_parse(id + SA_SHARE_PG_PREFIXLEN, uuid) < 0) 7444653Sdougm return (ret); 7453034Sdougm /* 7463034Sdougm * probably a legal optionset so check a few more 7473034Sdougm * syntax points below. 7483034Sdougm */ 7493034Sdougm if (*proto == '\0') { 7504653Sdougm /* not a valid proto (null) */ 7514653Sdougm return (ret); 7523034Sdougm } 753*5331Samw 7543034Sdougm sectype = strchr(proto, '_'); 7553034Sdougm if (sectype != NULL) 7564653Sdougm *sectype++ = '\0'; 7573034Sdougm if (!valid_protocol(proto)) 7584653Sdougm return (ret); 7593034Sdougm } 7603034Sdougm 7613034Sdougm /* 7624653Sdougm * To get here, we have a valid protocol and possibly a 7633034Sdougm * security. We now have to find the share that it is really 7643034Sdougm * associated with. The "id" portion of the pgroup name will 7653034Sdougm * match. 7663034Sdougm */ 7673034Sdougm 7683910Sdougm share = find_share_by_id(sahandle, id); 7693034Sdougm if (share == NULL) 7704653Sdougm return (SA_BAD_PATH); 7713034Sdougm 7723034Sdougm root = (xmlNodePtr)share; 7733034Sdougm 7743034Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 7753034Sdougm 7764653Sdougm if (sectype == NULL) 7774653Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"optionset", NULL); 7784653Sdougm else { 779*5331Samw if (isdigit((int)*sectype)) { 780*5331Samw sa_resource_t resource; 781*5331Samw /* 782*5331Samw * If sectype[0] is a digit, then it is an index into 783*5331Samw * the resource names. We need to find a resource 784*5331Samw * record and then get the properties into an 785*5331Samw * optionset. The optionset becomes the "node" and the 786*5331Samw * rest is hung off of the share. 787*5331Samw */ 788*5331Samw resource = find_resource_by_index(share, sectype); 789*5331Samw if (resource != NULL) { 790*5331Samw node = xmlNewChild(resource, NULL, 791*5331Samw (xmlChar *)"optionset", NULL); 792*5331Samw } else { 793*5331Samw /* this shouldn't happen */ 794*5331Samw ret = SA_SYSTEM_ERR; 795*5331Samw } 796*5331Samw } else { 797*5331Samw /* 798*5331Samw * If not a digit, then it is a security type 799*5331Samw * (alternate option space). Security types start with 800*5331Samw * an alphabetic. 801*5331Samw */ 802*5331Samw node = xmlNewChild(root, NULL, (xmlChar *)"security", 803*5331Samw NULL); 804*5331Samw if (node != NULL) 805*5331Samw xmlSetProp(node, (xmlChar *)"sectype", 806*5331Samw (xmlChar *)sectype); 807*5331Samw } 8084653Sdougm } 8094653Sdougm if (node == NULL) { 8104653Sdougm ret = SA_NO_MEMORY; 8114653Sdougm goto out; 8124653Sdougm } 8134653Sdougm 8144653Sdougm xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto); 8154653Sdougm /* now find the properties */ 8163034Sdougm iter = scf_iter_create(handle->handle); 8173034Sdougm value = scf_value_create(handle->handle); 8183034Sdougm prop = scf_property_create(handle->handle); 8193034Sdougm name = malloc(scf_max_name_len); 8203034Sdougm valuestr = malloc(vallen); 8213034Sdougm 8224653Sdougm if (iter == NULL || value == NULL || prop == NULL || name == NULL) 8234653Sdougm goto out; 8244653Sdougm 825*5331Samw /* iterate over the share pg properties */ 8264653Sdougm if (scf_iter_pg_properties(iter, pg) == 0) { 8274653Sdougm while (scf_iter_next_property(iter, prop) > 0) { 8283034Sdougm ret = SA_SYSTEM_ERR; /* assume the worst */ 8293034Sdougm if (scf_property_get_name(prop, name, 8304653Sdougm scf_max_name_len) > 0) { 8314653Sdougm if (scf_property_get_value(prop, value) == 0) { 8324653Sdougm if (scf_value_get_astring(value, 8334653Sdougm valuestr, vallen) >= 0) { 8344653Sdougm ret = SA_OK; 8354653Sdougm } 8363034Sdougm } 8373034Sdougm } else { 8384653Sdougm ret = SA_SYSTEM_ERR; 8393034Sdougm } 8403034Sdougm if (ret == SA_OK) { 8414653Sdougm sa_property_t prop; 8424653Sdougm prop = sa_create_property(name, valuestr); 8434653Sdougm if (prop != NULL) 8444653Sdougm prop = (sa_property_t)xmlAddChild(node, 8454653Sdougm (xmlNodePtr)prop); 8464653Sdougm else 8474653Sdougm ret = SA_NO_MEMORY; 8483034Sdougm } 8493034Sdougm } 8503034Sdougm } else { 8514653Sdougm ret = SA_SYSTEM_ERR; 8523034Sdougm } 8534653Sdougm out: 8543034Sdougm if (iter != NULL) 8554653Sdougm scf_iter_destroy(iter); 8563034Sdougm if (value != NULL) 8574653Sdougm scf_value_destroy(value); 8583034Sdougm if (prop != NULL) 8594653Sdougm scf_property_destroy(prop); 8603034Sdougm if (name != NULL) 8614653Sdougm free(name); 8623034Sdougm if (valuestr != NULL) 8634653Sdougm free(valuestr); 8643034Sdougm return (ret); 8653034Sdougm } 8663034Sdougm 8673034Sdougm /* 8683034Sdougm * sa_extract_group(root, handle, instance) 8693034Sdougm * 8704653Sdougm * Get the config info for this instance of a group and create the XML 8713034Sdougm * subtree from it. 8723034Sdougm */ 8733034Sdougm 8743034Sdougm static int 8753034Sdougm sa_extract_group(xmlNodePtr root, scfutilhandle_t *handle, 8763910Sdougm scf_instance_t *instance, sa_handle_t sahandle) 8773034Sdougm { 8783034Sdougm char *buff; 8793034Sdougm xmlNodePtr node; 8803034Sdougm scf_iter_t *iter; 8813034Sdougm char *proto; 8823034Sdougm char *sectype; 8833034Sdougm int have_shares = 0; 8843034Sdougm int has_proto = 0; 8853034Sdougm int is_default = 0; 8863034Sdougm int ret = SA_OK; 8873034Sdougm int err; 8883034Sdougm 8893034Sdougm buff = malloc(scf_max_name_len); 8904653Sdougm if (buff == NULL) 8914653Sdougm return (SA_NO_MEMORY); 8924653Sdougm 8933034Sdougm iter = scf_iter_create(handle->handle); 8944653Sdougm if (iter == NULL) { 8954653Sdougm ret = SA_NO_MEMORY; 8964653Sdougm goto out; 8974653Sdougm } 8984653Sdougm 8994653Sdougm if (scf_instance_get_name(instance, buff, scf_max_name_len) > 0) { 9003034Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"group", NULL); 9014653Sdougm if (node == NULL) { 9024653Sdougm ret = SA_NO_MEMORY; 9034653Sdougm goto out; 9044653Sdougm } 9054653Sdougm xmlSetProp(node, (xmlChar *)"name", (xmlChar *)buff); 9064653Sdougm if (strcmp(buff, "default") == 0) 9073034Sdougm is_default++; 9084653Sdougm 9094653Sdougm sa_extract_attrs(node, handle, instance); 9104653Sdougm /* 9114653Sdougm * Iterate through all the property groups 9124653Sdougm * looking for those with security or 9134653Sdougm * optionset prefixes. The names of the 9144653Sdougm * matching pgroups are parsed to get the 9154653Sdougm * protocol, and for security, the sectype. 9164653Sdougm * Syntax is as follows: 9174653Sdougm * optionset | optionset_<proto> 9184653Sdougm * security_default | security_<proto>_<sectype> 9194653Sdougm * "operation" is handled by 9204653Sdougm * sa_extract_attrs(). 9214653Sdougm */ 9224653Sdougm if (scf_iter_instance_pgs(iter, instance) != 0) { 9234653Sdougm ret = SA_NO_MEMORY; 9244653Sdougm goto out; 9254653Sdougm } 9264653Sdougm while (scf_iter_next_pg(iter, handle->pg) > 0) { 9274653Sdougm /* Have a pgroup so sort it out */ 9284653Sdougm ret = scf_pg_get_name(handle->pg, buff, 9294653Sdougm scf_max_name_len); 9304653Sdougm if (ret > 0) { 9314653Sdougm if (buff[0] == SA_SHARE_PG_PREFIX[0]) { 9323034Sdougm sa_share_from_pgroup(node, handle, 9334653Sdougm handle->pg, buff); 9343034Sdougm have_shares++; 9354653Sdougm } else if (strncmp(buff, "optionset", 9) == 9364653Sdougm 0) { 9373034Sdougm char *nodetype = "optionset"; 9384653Sdougm /* Have an optionset */ 9393034Sdougm sectype = NULL; 9403034Sdougm proto = strchr(buff, '_'); 9413034Sdougm if (proto != NULL) { 9424653Sdougm *proto++ = '\0'; 9434653Sdougm sectype = strchr(proto, '_'); 9444653Sdougm if (sectype != NULL) { 9454653Sdougm *sectype++ = '\0'; 9464653Sdougm nodetype = "security"; 9474653Sdougm } 9483034Sdougm } 9493034Sdougm ret = sa_extract_pgroup(node, handle, 9504653Sdougm handle->pg, nodetype, proto, 9514653Sdougm sectype); 9523034Sdougm has_proto++; 9534653Sdougm } else if (strncmp(buff, "security", 8) == 0) { 9543034Sdougm /* 9554653Sdougm * Have a security (note that 9563034Sdougm * this should change in the 9573034Sdougm * future) 9583034Sdougm */ 9593034Sdougm proto = strchr(buff, '_'); 9603034Sdougm sectype = NULL; 9613034Sdougm if (proto != NULL) { 9624653Sdougm *proto++ = '\0'; 9634653Sdougm sectype = strchr(proto, '_'); 9644653Sdougm if (sectype != NULL) 9654653Sdougm *sectype++ = '\0'; 9664653Sdougm if (strcmp(proto, "default") == 9674653Sdougm 0) 9684653Sdougm proto = NULL; 9693034Sdougm } 9703034Sdougm ret = sa_extract_pgroup(node, handle, 9714653Sdougm handle->pg, "security", proto, 9724653Sdougm sectype); 9733034Sdougm has_proto++; 9743034Sdougm } 9754653Sdougm /* Ignore everything else */ 9763034Sdougm } 9774653Sdougm } 9784653Sdougm /* 9794653Sdougm * Make sure we have a valid default group. 9804653Sdougm * On first boot, default won't have any 9814653Sdougm * protocols defined and won't be enabled (but 9824653Sdougm * should be). 9834653Sdougm */ 9844653Sdougm if (is_default) { 9854653Sdougm char *state = sa_get_group_attr((sa_group_t)node, 9864653Sdougm "state"); 9874653Sdougm char **protos; 9884653Sdougm int numprotos; 9894653Sdougm int i; 9903034Sdougm 9914653Sdougm if (state == NULL) { 9923034Sdougm /* set attribute to enabled */ 9933034Sdougm (void) sa_set_group_attr((sa_group_t)node, 9944653Sdougm "state", "enabled"); 9954653Sdougm /* We can assume no protocols */ 9963034Sdougm numprotos = sa_get_protocols(&protos); 9973034Sdougm for (i = 0; i < numprotos; i++) 9984653Sdougm (void) sa_create_optionset( 9994653Sdougm (sa_group_t)node, protos[i]); 10003034Sdougm if (numprotos > 0) 10014653Sdougm free(protos); 10024653Sdougm } else { 10033034Sdougm sa_free_attr_string(state); 10043034Sdougm } 10054653Sdougm } 10064653Sdougm /* Do a second pass if shares were found */ 10074653Sdougm if (have_shares && scf_iter_instance_pgs(iter, instance) == 0) { 10084653Sdougm while (scf_iter_next_pg(iter, handle->pg) > 0) { 10093034Sdougm /* 10104653Sdougm * Have a pgroup so see if it is a 10113034Sdougm * share optionset 10123034Sdougm */ 10133034Sdougm err = scf_pg_get_name(handle->pg, buff, 10144653Sdougm scf_max_name_len); 10154653Sdougm if (err <= 0) 10164653Sdougm continue; 10174653Sdougm if (buff[0] == SA_SHARE_PG_PREFIX[0]) { 10183034Sdougm ret = sa_share_props_from_pgroup(node, 10194653Sdougm handle, handle->pg, buff, 10204653Sdougm sahandle); 10213034Sdougm } 10223034Sdougm } 10233034Sdougm } 10243034Sdougm } 10254653Sdougm out: 10263034Sdougm if (iter != NULL) 10274653Sdougm scf_iter_destroy(iter); 10283034Sdougm if (buff != NULL) 10294653Sdougm free(buff); 10303034Sdougm return (ret); 10313034Sdougm } 10323034Sdougm 10333034Sdougm /* 10343034Sdougm * sa_extract_defaults(root, handle, instance) 10353034Sdougm * 10364653Sdougm * Local function to find the default properties that live in the 1037*5331Samw * default instance's "operation" property group. 10383034Sdougm */ 10393034Sdougm 10403034Sdougm static void 10413034Sdougm sa_extract_defaults(xmlNodePtr root, scfutilhandle_t *handle, 10423034Sdougm scf_instance_t *instance) 10433034Sdougm { 10443034Sdougm xmlNodePtr node; 10453034Sdougm scf_property_t *prop; 10463034Sdougm scf_value_t *value; 10473034Sdougm char *valuestr; 10483034Sdougm ssize_t vallen; 10493034Sdougm 10503034Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 10513034Sdougm prop = scf_property_create(handle->handle); 10523034Sdougm value = scf_value_create(handle->handle); 10533034Sdougm valuestr = malloc(vallen); 10544653Sdougm 10554653Sdougm if (prop == NULL || value == NULL || vallen == 0 || 10564653Sdougm scf_instance_get_pg(instance, "operation", handle->pg) != 0) 10574653Sdougm goto out; 10584653Sdougm 10594653Sdougm if (scf_pg_get_property(handle->pg, "legacy-timestamp", prop) != 0) 10604653Sdougm goto out; 10614653Sdougm 10624653Sdougm /* Found the property so get the value */ 10634653Sdougm if (scf_property_get_value(prop, value) == 0) { 10644653Sdougm if (scf_value_get_astring(value, valuestr, vallen) > 0) { 10653034Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"legacy", 10664653Sdougm NULL); 10673034Sdougm if (node != NULL) { 10684653Sdougm xmlSetProp(node, (xmlChar *)"timestamp", 10694653Sdougm (xmlChar *)valuestr); 10704653Sdougm xmlSetProp(node, (xmlChar *)"path", 10714653Sdougm (xmlChar *)SA_LEGACY_DFSTAB); 10723034Sdougm } 10733034Sdougm } 10743034Sdougm } 10754653Sdougm out: 10763034Sdougm if (valuestr != NULL) 10774653Sdougm free(valuestr); 10783034Sdougm if (value != NULL) 10794653Sdougm scf_value_destroy(value); 10803034Sdougm if (prop != NULL) 10814653Sdougm scf_property_destroy(prop); 10823034Sdougm } 10833034Sdougm 10843034Sdougm 10853034Sdougm /* 1086*5331Samw * sa_get_config(handle, root, doc, sahandle) 10873034Sdougm * 10884653Sdougm * Walk the SMF repository for /network/shares/group and find all the 10893034Sdougm * instances. These become group names. Then add the XML structure 10903034Sdougm * below the groups based on property groups and properties. 10913034Sdougm */ 10923034Sdougm int 10933973Sdougm sa_get_config(scfutilhandle_t *handle, xmlNodePtr root, sa_handle_t sahandle) 10943034Sdougm { 10953034Sdougm int ret = SA_OK; 10963034Sdougm scf_instance_t *instance; 10973034Sdougm scf_iter_t *iter; 10983034Sdougm char buff[BUFSIZ * 2]; 10993034Sdougm 11003034Sdougm instance = scf_instance_create(handle->handle); 11013034Sdougm iter = scf_iter_create(handle->handle); 11023973Sdougm if (instance != NULL && iter != NULL) { 11034653Sdougm if ((ret = scf_iter_service_instances(iter, 11044653Sdougm handle->service)) == 0) { 11054653Sdougm while ((ret = scf_iter_next_instance(iter, 11064653Sdougm instance)) > 0) { 11074653Sdougm if (scf_instance_get_name(instance, buff, 11084653Sdougm sizeof (buff)) > 0) { 11094653Sdougm if (strcmp(buff, "default") == 0) 11104653Sdougm sa_extract_defaults(root, 11114653Sdougm handle, instance); 11124653Sdougm ret = sa_extract_group(root, handle, 11134653Sdougm instance, sahandle); 11144653Sdougm } 11154653Sdougm } 11163034Sdougm } 11173034Sdougm } 11183973Sdougm 11194653Sdougm /* Always cleanup these */ 11203034Sdougm if (instance != NULL) 11214653Sdougm scf_instance_destroy(instance); 11223034Sdougm if (iter != NULL) 11234653Sdougm scf_iter_destroy(iter); 11243034Sdougm return (ret); 11253034Sdougm } 11263034Sdougm 11273034Sdougm /* 11283034Sdougm * sa_get_instance(handle, instance) 11293034Sdougm * 11304653Sdougm * Get the instance of the group service. This is actually the 11313034Sdougm * specific group name. The instance is needed for all property and 11323034Sdougm * control operations. 11333034Sdougm */ 11343034Sdougm 11353034Sdougm int 11363034Sdougm sa_get_instance(scfutilhandle_t *handle, char *instname) 11373034Sdougm { 11383034Sdougm if (scf_service_get_instance(handle->service, instname, 11394653Sdougm handle->instance) != 0) { 11404653Sdougm return (SA_NO_SUCH_GROUP); 11413034Sdougm } 11423034Sdougm return (SA_OK); 11433034Sdougm } 11443034Sdougm 11453034Sdougm /* 11463034Sdougm * sa_create_instance(handle, instname) 11473034Sdougm * 11483034Sdougm * Create a new SMF service instance. There can only be one with a 11493034Sdougm * given name. 11503034Sdougm */ 11513034Sdougm 11523034Sdougm int 11533034Sdougm sa_create_instance(scfutilhandle_t *handle, char *instname) 11543034Sdougm { 11553034Sdougm int ret = SA_OK; 11563034Sdougm char instance[SA_GROUP_INST_LEN]; 11573034Sdougm if (scf_service_add_instance(handle->service, instname, 11584653Sdougm handle->instance) != 0) { 11593034Sdougm /* better error returns need to be added based on real error */ 11604653Sdougm if (scf_error() == SCF_ERROR_PERMISSION_DENIED) 11614653Sdougm ret = SA_NO_PERMISSION; 11624653Sdougm else 11634653Sdougm ret = SA_DUPLICATE_NAME; 11643034Sdougm } else { 11654653Sdougm /* have the service created, so enable it */ 11664653Sdougm (void) snprintf(instance, sizeof (instance), "%s:%s", 11674653Sdougm SA_SVC_FMRI_BASE, instname); 11684653Sdougm (void) smf_enable_instance(instance, 0); 11693034Sdougm } 11703034Sdougm return (ret); 11713034Sdougm } 11723034Sdougm 11733034Sdougm /* 11743034Sdougm * sa_delete_instance(handle, instname) 11753034Sdougm * 11763034Sdougm * When a group goes away, we also remove the service instance. 11773034Sdougm */ 11783034Sdougm 11793034Sdougm int 11803034Sdougm sa_delete_instance(scfutilhandle_t *handle, char *instname) 11813034Sdougm { 11823034Sdougm int ret; 11833034Sdougm 11843034Sdougm if (strcmp(instname, "default") == 0) { 11854653Sdougm ret = SA_NO_PERMISSION; 11863034Sdougm } else { 11874653Sdougm if ((ret = sa_get_instance(handle, instname)) == SA_OK) { 11884653Sdougm if (scf_instance_delete(handle->instance) != 0) 11894653Sdougm /* need better analysis */ 11904653Sdougm ret = SA_NO_PERMISSION; 11914653Sdougm } 11923034Sdougm } 11933034Sdougm return (ret); 11943034Sdougm } 11953034Sdougm 11963034Sdougm /* 11973034Sdougm * sa_create_pgroup(handle, pgroup) 11983034Sdougm * 11993034Sdougm * create a new property group 12003034Sdougm */ 12013034Sdougm 12023034Sdougm int 12033034Sdougm sa_create_pgroup(scfutilhandle_t *handle, char *pgroup) 12043034Sdougm { 12053034Sdougm int ret = SA_OK; 12063034Sdougm /* 12074653Sdougm * Only create a handle if it doesn't exist. It is ok to exist 12083034Sdougm * since the pg handle will be set as a side effect. 12093034Sdougm */ 12104653Sdougm if (handle->pg == NULL) 12114653Sdougm handle->pg = scf_pg_create(handle->handle); 12124653Sdougm 12133034Sdougm /* 12144653Sdougm * If the pgroup exists, we are done. If it doesn't, then we 12153034Sdougm * need to actually add one to the service instance. 12163034Sdougm */ 12173034Sdougm if (scf_instance_get_pg(handle->instance, 12184653Sdougm pgroup, handle->pg) != 0) { 12194653Sdougm /* Doesn't exist so create one */ 12204653Sdougm if (scf_instance_add_pg(handle->instance, pgroup, 12214653Sdougm SCF_GROUP_APPLICATION, 0, handle->pg) != 0) { 12224653Sdougm switch (scf_error()) { 12234653Sdougm case SCF_ERROR_PERMISSION_DENIED: 12244653Sdougm ret = SA_NO_PERMISSION; 12254653Sdougm break; 12264653Sdougm default: 12274653Sdougm ret = SA_SYSTEM_ERR; 12284653Sdougm break; 12294653Sdougm } 12303034Sdougm } 12313034Sdougm } 12323034Sdougm return (ret); 12333034Sdougm } 12343034Sdougm 12353034Sdougm /* 12363034Sdougm * sa_delete_pgroup(handle, pgroup) 12373034Sdougm * 12384653Sdougm * Remove the property group from the current instance of the service, 12393034Sdougm * but only if it actually exists. 12403034Sdougm */ 12413034Sdougm 12423034Sdougm int 12433034Sdougm sa_delete_pgroup(scfutilhandle_t *handle, char *pgroup) 12443034Sdougm { 12453034Sdougm int ret = SA_OK; 12463034Sdougm /* 12474653Sdougm * Only delete if it does exist. 12483034Sdougm */ 12494653Sdougm if (scf_instance_get_pg(handle->instance, pgroup, handle->pg) == 0) { 12504653Sdougm /* does exist so delete it */ 12514653Sdougm if (scf_pg_delete(handle->pg) != 0) 12524653Sdougm ret = SA_SYSTEM_ERR; 12534653Sdougm } else { 12543034Sdougm ret = SA_SYSTEM_ERR; 12553034Sdougm } 12563034Sdougm if (ret == SA_SYSTEM_ERR && 12573034Sdougm scf_error() == SCF_ERROR_PERMISSION_DENIED) { 12583034Sdougm ret = SA_NO_PERMISSION; 12593034Sdougm } 12603034Sdougm return (ret); 12613034Sdougm } 12623034Sdougm 12633034Sdougm /* 12643034Sdougm * sa_start_transaction(handle, pgroup) 12653034Sdougm * 12663034Sdougm * Start an SMF transaction so we can deal with properties. it would 12673034Sdougm * be nice to not have to expose this, but we have to in order to 12683034Sdougm * optimize. 12693034Sdougm * 12703034Sdougm * Basic model is to hold the transaction in the handle and allow 12713034Sdougm * property adds/deletes/updates to be added then close the 12723034Sdougm * transaction (or abort). There may eventually be a need to handle 12733034Sdougm * other types of transaction mechanisms but we don't do that now. 12743034Sdougm * 12753034Sdougm * An sa_start_transaction must be followed by either an 12763034Sdougm * sa_end_transaction or sa_abort_transaction before another 12773034Sdougm * sa_start_transaction can be done. 12783034Sdougm */ 12793034Sdougm 12803034Sdougm int 12813034Sdougm sa_start_transaction(scfutilhandle_t *handle, char *propgroup) 12823034Sdougm { 12833034Sdougm int ret = SA_OK; 12843034Sdougm /* 12854653Sdougm * Lookup the property group and create it if it doesn't already 12863034Sdougm * exist. 12873034Sdougm */ 12883034Sdougm if (handle->scf_state == SCH_STATE_INIT) { 12894653Sdougm ret = sa_create_pgroup(handle, propgroup); 12904653Sdougm if (ret == SA_OK) { 12914653Sdougm handle->trans = scf_transaction_create(handle->handle); 12924653Sdougm if (handle->trans != NULL) { 12934653Sdougm if (scf_transaction_start(handle->trans, 12944653Sdougm handle->pg) != 0) { 12954653Sdougm ret = SA_SYSTEM_ERR; 12964653Sdougm } 12974653Sdougm if (ret != SA_OK) { 12984653Sdougm scf_transaction_destroy(handle->trans); 12994653Sdougm handle->trans = NULL; 13004653Sdougm } 13014653Sdougm } else { 13024653Sdougm ret = SA_SYSTEM_ERR; 13034653Sdougm } 13043034Sdougm } 13053034Sdougm } 13063034Sdougm if (ret == SA_SYSTEM_ERR && 13073034Sdougm scf_error() == SCF_ERROR_PERMISSION_DENIED) { 13083034Sdougm ret = SA_NO_PERMISSION; 13093034Sdougm } 13103034Sdougm return (ret); 13113034Sdougm } 13123034Sdougm 13133034Sdougm /* 13143034Sdougm * sa_end_transaction(handle) 13153034Sdougm * 13163034Sdougm * Commit the changes that were added to the transaction in the 13173034Sdougm * handle. Do all necessary cleanup. 13183034Sdougm */ 13193034Sdougm 13203034Sdougm int 13213034Sdougm sa_end_transaction(scfutilhandle_t *handle) 13223034Sdougm { 13233034Sdougm int ret = SA_OK; 13243034Sdougm 13253034Sdougm if (handle->trans == NULL) { 13264653Sdougm ret = SA_SYSTEM_ERR; 13273034Sdougm } else { 13284653Sdougm if (scf_transaction_commit(handle->trans) < 0) 13294653Sdougm ret = SA_SYSTEM_ERR; 13304653Sdougm scf_transaction_destroy_children(handle->trans); 13314653Sdougm scf_transaction_destroy(handle->trans); 13324653Sdougm handle->trans = NULL; 13333034Sdougm } 13343034Sdougm return (ret); 13353034Sdougm } 13363034Sdougm 13373034Sdougm /* 13383034Sdougm * sa_abort_transaction(handle) 13393034Sdougm * 13403034Sdougm * Abort the changes that were added to the transaction in the 13413034Sdougm * handle. Do all necessary cleanup. 13423034Sdougm */ 13433034Sdougm 13443034Sdougm void 13453034Sdougm sa_abort_transaction(scfutilhandle_t *handle) 13463034Sdougm { 13473034Sdougm if (handle->trans != NULL) { 13484653Sdougm scf_transaction_reset_all(handle->trans); 13494653Sdougm scf_transaction_destroy_children(handle->trans); 13504653Sdougm scf_transaction_destroy(handle->trans); 13514653Sdougm handle->trans = NULL; 13523034Sdougm } 13533034Sdougm } 13543034Sdougm 13553034Sdougm /* 13563034Sdougm * sa_set_property(handle, prop, value) 13573034Sdougm * 13584653Sdougm * Set a property transaction entry into the pending SMF transaction. 13593034Sdougm */ 13603034Sdougm 13613034Sdougm int 13623034Sdougm sa_set_property(scfutilhandle_t *handle, char *propname, char *valstr) 13633034Sdougm { 13643034Sdougm int ret = SA_OK; 13653034Sdougm scf_value_t *value; 13663034Sdougm scf_transaction_entry_t *entry; 13673034Sdougm /* 13684653Sdougm * Properties must be set in transactions and don't take 13693034Sdougm * effect until the transaction has been ended/committed. 13703034Sdougm */ 13713034Sdougm value = scf_value_create(handle->handle); 13723034Sdougm entry = scf_entry_create(handle->handle); 13733034Sdougm if (value != NULL && entry != NULL) { 13744653Sdougm if (scf_transaction_property_change(handle->trans, entry, 13754653Sdougm propname, SCF_TYPE_ASTRING) == 0 || 13764653Sdougm scf_transaction_property_new(handle->trans, entry, 13774653Sdougm propname, SCF_TYPE_ASTRING) == 0) { 13784653Sdougm if (scf_value_set_astring(value, valstr) == 0) { 13794653Sdougm if (scf_entry_add_value(entry, value) != 0) { 13804653Sdougm ret = SA_SYSTEM_ERR; 13814653Sdougm scf_value_destroy(value); 13824653Sdougm } 13834653Sdougm /* The value is in the transaction */ 13844653Sdougm value = NULL; 13854653Sdougm } else { 13864653Sdougm /* Value couldn't be constructed */ 13874653Sdougm ret = SA_SYSTEM_ERR; 13884653Sdougm } 13894653Sdougm /* The entry is in the transaction */ 13904653Sdougm entry = NULL; 13914653Sdougm } else { 13923034Sdougm ret = SA_SYSTEM_ERR; 13933034Sdougm } 13944653Sdougm } else { 13953034Sdougm ret = SA_SYSTEM_ERR; 13963034Sdougm } 13973034Sdougm if (ret == SA_SYSTEM_ERR) { 13984653Sdougm switch (scf_error()) { 13994653Sdougm case SCF_ERROR_PERMISSION_DENIED: 14004653Sdougm ret = SA_NO_PERMISSION; 14014653Sdougm break; 14024653Sdougm } 14033034Sdougm } 14043034Sdougm /* 14054653Sdougm * Cleanup if there were any errors that didn't leave these 14063034Sdougm * values where they would be cleaned up later. 14073034Sdougm */ 14083034Sdougm if (value != NULL) 14094653Sdougm scf_value_destroy(value); 14103034Sdougm if (entry != NULL) 14114653Sdougm scf_entry_destroy(entry); 14123034Sdougm return (ret); 14133034Sdougm } 14143034Sdougm 14153034Sdougm /* 1416*5331Samw * check_resource(share) 1417*5331Samw * 1418*5331Samw * Check to see if share has any persistent resources. We don't want 1419*5331Samw * to save if they are all transient. 1420*5331Samw */ 1421*5331Samw static int 1422*5331Samw check_resource(sa_share_t share) 1423*5331Samw { 1424*5331Samw sa_resource_t resource; 1425*5331Samw int ret = B_FALSE; 1426*5331Samw 1427*5331Samw for (resource = sa_get_share_resource(share, NULL); 1428*5331Samw resource != NULL && ret == B_FALSE; 1429*5331Samw resource = sa_get_next_resource(resource)) { 1430*5331Samw char *type; 1431*5331Samw type = sa_get_resource_attr(resource, "type"); 1432*5331Samw if (type != NULL) { 1433*5331Samw if (strcmp(type, "transient") != 0) { 1434*5331Samw ret = B_TRUE; 1435*5331Samw } 1436*5331Samw sa_free_attr_string(type); 1437*5331Samw } 1438*5331Samw } 1439*5331Samw return (ret); 1440*5331Samw } 1441*5331Samw 1442*5331Samw /* 1443*5331Samw * sa_set_resource_property(handle, prop, value) 1444*5331Samw * 1445*5331Samw * set a property transaction entry into the pending SMF 1446*5331Samw * transaction. We don't want to include any transient resources 1447*5331Samw */ 1448*5331Samw 1449*5331Samw static int 1450*5331Samw sa_set_resource_property(scfutilhandle_t *handle, sa_share_t share) 1451*5331Samw { 1452*5331Samw int ret = SA_OK; 1453*5331Samw scf_value_t *value; 1454*5331Samw scf_transaction_entry_t *entry; 1455*5331Samw sa_resource_t resource; 1456*5331Samw char *valstr; 1457*5331Samw char *idstr; 1458*5331Samw char *description; 1459*5331Samw char *propstr = NULL; 1460*5331Samw size_t strsize; 1461*5331Samw 1462*5331Samw /* don't bother if no persistent resources */ 1463*5331Samw if (check_resource(share) == B_FALSE) 1464*5331Samw return (ret); 1465*5331Samw 1466*5331Samw /* 1467*5331Samw * properties must be set in transactions and don't take 1468*5331Samw * effect until the transaction has been ended/committed. 1469*5331Samw */ 1470*5331Samw entry = scf_entry_create(handle->handle); 1471*5331Samw if (entry == NULL) 1472*5331Samw return (SA_SYSTEM_ERR); 1473*5331Samw 1474*5331Samw if (scf_transaction_property_change(handle->trans, entry, 1475*5331Samw "resource", SCF_TYPE_ASTRING) != 0 && 1476*5331Samw scf_transaction_property_new(handle->trans, entry, 1477*5331Samw "resource", SCF_TYPE_ASTRING) != 0) { 1478*5331Samw scf_entry_destroy(entry); 1479*5331Samw return (SA_SYSTEM_ERR); 1480*5331Samw 1481*5331Samw } 1482*5331Samw for (resource = sa_get_share_resource(share, NULL); 1483*5331Samw resource != NULL; 1484*5331Samw resource = sa_get_next_resource(resource)) { 1485*5331Samw value = scf_value_create(handle->handle); 1486*5331Samw if (value == NULL) { 1487*5331Samw ret = SA_NO_MEMORY; 1488*5331Samw break; 1489*5331Samw } 1490*5331Samw /* Get size of complete string */ 1491*5331Samw valstr = sa_get_resource_attr(resource, "name"); 1492*5331Samw idstr = sa_get_resource_attr(resource, "id"); 1493*5331Samw description = sa_get_resource_description(resource); 1494*5331Samw strsize = (valstr != NULL) ? strlen(valstr) : 0; 1495*5331Samw strsize += (idstr != NULL) ? strlen(idstr) : 0; 1496*5331Samw strsize += (description != NULL) ? strlen(description) : 0; 1497*5331Samw if (strsize > 0) { 1498*5331Samw strsize += 3; /* add nul and ':' */ 1499*5331Samw propstr = (char *)malloc(strsize); 1500*5331Samw if (propstr == NULL) { 1501*5331Samw scf_value_destroy(value); 1502*5331Samw ret = SA_NO_MEMORY; 1503*5331Samw goto err; 1504*5331Samw } 1505*5331Samw if (idstr == NULL) 1506*5331Samw (void) snprintf(propstr, strsize, "%s", 1507*5331Samw valstr ? valstr : ""); 1508*5331Samw else 1509*5331Samw (void) snprintf(propstr, strsize, "%s:%s:%s", 1510*5331Samw idstr ? idstr : "", valstr ? valstr : "", 1511*5331Samw description ? description : ""); 1512*5331Samw if (scf_value_set_astring(value, propstr) != 0) { 1513*5331Samw ret = SA_SYSTEM_ERR; 1514*5331Samw free(propstr); 1515*5331Samw scf_value_destroy(value); 1516*5331Samw break; 1517*5331Samw } 1518*5331Samw if (scf_entry_add_value(entry, value) != 0) { 1519*5331Samw ret = SA_SYSTEM_ERR; 1520*5331Samw free(propstr); 1521*5331Samw scf_value_destroy(value); 1522*5331Samw break; 1523*5331Samw } 1524*5331Samw /* the value is in the transaction */ 1525*5331Samw value = NULL; 1526*5331Samw free(propstr); 1527*5331Samw } 1528*5331Samw err: 1529*5331Samw if (valstr != NULL) 1530*5331Samw sa_free_attr_string(valstr); 1531*5331Samw if (idstr != NULL) 1532*5331Samw sa_free_attr_string(idstr); 1533*5331Samw if (description != NULL) 1534*5331Samw sa_free_share_description(description); 1535*5331Samw } 1536*5331Samw /* the entry is in the transaction */ 1537*5331Samw entry = NULL; 1538*5331Samw 1539*5331Samw if (ret == SA_SYSTEM_ERR) { 1540*5331Samw switch (scf_error()) { 1541*5331Samw case SCF_ERROR_PERMISSION_DENIED: 1542*5331Samw ret = SA_NO_PERMISSION; 1543*5331Samw break; 1544*5331Samw } 1545*5331Samw } 1546*5331Samw /* 1547*5331Samw * cleanup if there were any errors that didn't leave 1548*5331Samw * these values where they would be cleaned up later. 1549*5331Samw */ 1550*5331Samw if (entry != NULL) 1551*5331Samw scf_entry_destroy(entry); 1552*5331Samw 1553*5331Samw return (ret); 1554*5331Samw } 1555*5331Samw 1556*5331Samw /* 15573034Sdougm * sa_commit_share(handle, group, share) 15583034Sdougm * 15594653Sdougm * Commit this share to the repository. 15603034Sdougm * properties are added if they exist but can be added later. 15613034Sdougm * Need to add to dfstab and sharetab, if appropriate. 15623034Sdougm */ 15633034Sdougm int 15643034Sdougm sa_commit_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share) 15653034Sdougm { 15663034Sdougm int ret = SA_OK; 15673034Sdougm char *groupname; 15683034Sdougm char *name; 15693034Sdougm char *description; 15703034Sdougm char *sharename; 15713034Sdougm ssize_t proplen; 15723034Sdougm char *propstring; 15733034Sdougm 15743034Sdougm /* 15754653Sdougm * Don't commit in the zfs group. We do commit legacy 15763034Sdougm * (default) and all other groups/shares. ZFS is handled 15773034Sdougm * through the ZFS configuration rather than SMF. 15783034Sdougm */ 15793034Sdougm 15803034Sdougm groupname = sa_get_group_attr(group, "name"); 15813034Sdougm if (groupname != NULL) { 15824653Sdougm if (strcmp(groupname, "zfs") == 0) { 15834653Sdougm /* 15844653Sdougm * Adding to the ZFS group will result in the sharenfs 15854653Sdougm * property being set but we don't want to do anything 15864653Sdougm * SMF related at this point. 15874653Sdougm */ 15884653Sdougm sa_free_attr_string(groupname); 15894653Sdougm return (ret); 15904653Sdougm } 15913034Sdougm } 15923034Sdougm 15933034Sdougm proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 15943034Sdougm propstring = malloc(proplen); 15953034Sdougm if (propstring == NULL) 15964653Sdougm ret = SA_NO_MEMORY; 15973034Sdougm 15983034Sdougm if (groupname != NULL && ret == SA_OK) { 15994653Sdougm ret = sa_get_instance(handle, groupname); 16004653Sdougm sa_free_attr_string(groupname); 16014653Sdougm groupname = NULL; 16024653Sdougm sharename = sa_get_share_attr(share, "id"); 16034653Sdougm if (sharename == NULL) { 16044653Sdougm /* slipped by */ 16054653Sdougm char shname[SA_SHARE_UUID_BUFLEN]; 16064653Sdougm generate_unique_sharename(shname); 16074653Sdougm xmlSetProp((xmlNodePtr)share, (xmlChar *)"id", 16083034Sdougm (xmlChar *)shname); 16094653Sdougm sharename = strdup(shname); 16103034Sdougm } 16114653Sdougm if (sharename != NULL) { 16124653Sdougm sigset_t old, new; 16134653Sdougm /* 16144653Sdougm * Have a share name allocated so create a pgroup for 16154653Sdougm * it. It may already exist, but that is OK. In order 16164653Sdougm * to avoid creating a share pgroup that doesn't have 16174653Sdougm * a path property, block signals around the critical 16184653Sdougm * region of creating the share pgroup and props. 16194653Sdougm */ 16204653Sdougm (void) sigprocmask(SIG_BLOCK, NULL, &new); 16214653Sdougm (void) sigaddset(&new, SIGHUP); 16224653Sdougm (void) sigaddset(&new, SIGINT); 16234653Sdougm (void) sigaddset(&new, SIGQUIT); 16244653Sdougm (void) sigaddset(&new, SIGTSTP); 16254653Sdougm (void) sigprocmask(SIG_SETMASK, &new, &old); 16264653Sdougm 16274653Sdougm ret = sa_create_pgroup(handle, sharename); 16284653Sdougm if (ret == SA_OK) { 16294653Sdougm /* 16304653Sdougm * Now start the transaction for the 16314653Sdougm * properties that define this share. They may 16324653Sdougm * exist so attempt to update before create. 16334653Sdougm */ 16344653Sdougm ret = sa_start_transaction(handle, sharename); 16354653Sdougm } 16364653Sdougm if (ret == SA_OK) { 16374653Sdougm name = sa_get_share_attr(share, "path"); 16384653Sdougm if (name != NULL) { 16394653Sdougm /* 16404653Sdougm * There needs to be a path 16414653Sdougm * for a share to exist. 16424653Sdougm */ 16434653Sdougm ret = sa_set_property(handle, "path", 16444653Sdougm name); 16454653Sdougm sa_free_attr_string(name); 16464653Sdougm } else { 16474653Sdougm ret = SA_NO_MEMORY; 16484653Sdougm } 16494653Sdougm } 16504653Sdougm if (ret == SA_OK) { 1651*5331Samw name = sa_get_share_attr(share, "drive-letter"); 1652*5331Samw if (name != NULL) { 1653*5331Samw /* A drive letter may exist for SMB */ 16544653Sdougm ret = sa_set_property(handle, 1655*5331Samw "drive-letter", name); 1656*5331Samw sa_free_attr_string(name); 16574653Sdougm } 16584653Sdougm } 16594653Sdougm if (ret == SA_OK) { 1660*5331Samw name = sa_get_share_attr(share, "exclude"); 1661*5331Samw if (name != NULL) { 1662*5331Samw /* 1663*5331Samw * In special cases need to 1664*5331Samw * exclude proto enable. 1665*5331Samw */ 1666*5331Samw ret = sa_set_property(handle, 1667*5331Samw "exclude", name); 1668*5331Samw sa_free_attr_string(name); 1669*5331Samw } 1670*5331Samw } 1671*5331Samw if (ret == SA_OK) { 1672*5331Samw /* 1673*5331Samw * If there are resource names, bundle them up 1674*5331Samw * and save appropriately. 1675*5331Samw */ 1676*5331Samw ret = sa_set_resource_property(handle, share); 1677*5331Samw } 1678*5331Samw 1679*5331Samw if (ret == SA_OK) { 16804653Sdougm description = sa_get_share_description(share); 16814653Sdougm if (description != NULL) { 16824653Sdougm ret = sa_set_property(handle, 16834653Sdougm "description", 16844653Sdougm description); 16854653Sdougm sa_free_share_description(description); 16864653Sdougm } 16874653Sdougm } 16884653Sdougm /* Make sure we cleanup the transaction */ 16894653Sdougm if (ret == SA_OK) { 16904653Sdougm ret = sa_end_transaction(handle); 16914653Sdougm } else { 16924653Sdougm sa_abort_transaction(handle); 16934653Sdougm } 16944653Sdougm 16954653Sdougm (void) sigprocmask(SIG_SETMASK, &old, NULL); 16964653Sdougm 16974653Sdougm free(sharename); 16983034Sdougm } 16993034Sdougm } 17003034Sdougm if (ret == SA_SYSTEM_ERR) { 17014653Sdougm int err = scf_error(); 17024653Sdougm if (err == SCF_ERROR_PERMISSION_DENIED) 17034653Sdougm ret = SA_NO_PERMISSION; 17043034Sdougm } 17053034Sdougm if (propstring != NULL) 17064653Sdougm free(propstring); 17073034Sdougm if (groupname != NULL) 17084653Sdougm sa_free_attr_string(groupname); 17093034Sdougm 17103034Sdougm return (ret); 17113034Sdougm } 17123034Sdougm 17133034Sdougm /* 1714*5331Samw * remove_resources(handle, share, shareid) 1715*5331Samw * 1716*5331Samw * If the share has resources, remove all of them and their 1717*5331Samw * optionsets. 1718*5331Samw */ 1719*5331Samw static int 1720*5331Samw remove_resources(scfutilhandle_t *handle, sa_share_t share, char *shareid) 1721*5331Samw { 1722*5331Samw sa_resource_t resource; 1723*5331Samw sa_optionset_t opt; 1724*5331Samw char *proto; 1725*5331Samw char *id; 1726*5331Samw ssize_t proplen; 1727*5331Samw char *propstring; 1728*5331Samw int ret = SA_OK; 1729*5331Samw 1730*5331Samw proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 1731*5331Samw propstring = malloc(proplen); 1732*5331Samw if (propstring == NULL) 1733*5331Samw return (SA_NO_MEMORY); 1734*5331Samw 1735*5331Samw for (resource = sa_get_share_resource(share, NULL); 1736*5331Samw resource != NULL; resource = sa_get_next_resource(resource)) { 1737*5331Samw id = sa_get_resource_attr(resource, "id"); 1738*5331Samw if (id == NULL) 1739*5331Samw continue; 1740*5331Samw for (opt = sa_get_optionset(resource, NULL); 1741*5331Samw opt != NULL; opt = sa_get_next_optionset(resource)) { 1742*5331Samw proto = sa_get_optionset_attr(opt, "type"); 1743*5331Samw if (proto != NULL) { 1744*5331Samw (void) snprintf(propstring, proplen, 1745*5331Samw "%s_%s_%s", shareid, proto, id); 1746*5331Samw ret = sa_delete_pgroup(handle, propstring); 1747*5331Samw sa_free_attr_string(proto); 1748*5331Samw } 1749*5331Samw } 1750*5331Samw sa_free_attr_string(id); 1751*5331Samw } 1752*5331Samw free(propstring); 1753*5331Samw return (ret); 1754*5331Samw } 1755*5331Samw 1756*5331Samw /* 17573034Sdougm * sa_delete_share(handle, group, share) 17583034Sdougm * 17594653Sdougm * Remove the specified share from the group (and service instance). 17603034Sdougm */ 17613034Sdougm 17623034Sdougm int 17633034Sdougm sa_delete_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share) 17643034Sdougm { 17653034Sdougm int ret = SA_OK; 17663034Sdougm char *groupname = NULL; 17673034Sdougm char *shareid = NULL; 17683034Sdougm sa_optionset_t opt; 17693034Sdougm sa_security_t sec; 17703034Sdougm ssize_t proplen; 17713034Sdougm char *propstring; 17723034Sdougm 17733034Sdougm proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 17743034Sdougm propstring = malloc(proplen); 17753034Sdougm if (propstring == NULL) 17764653Sdougm ret = SA_NO_MEMORY; 17773034Sdougm 17783034Sdougm if (ret == SA_OK) { 17794653Sdougm groupname = sa_get_group_attr(group, "name"); 17804653Sdougm shareid = sa_get_share_attr(share, "id"); 17814653Sdougm if (groupname == NULL || shareid == NULL) { 17824653Sdougm ret = SA_CONFIG_ERR; 17834653Sdougm goto out; 17844653Sdougm } 17853034Sdougm ret = sa_get_instance(handle, groupname); 17863034Sdougm if (ret == SA_OK) { 1787*5331Samw /* If a share has resources, remove them */ 1788*5331Samw ret = remove_resources(handle, share, shareid); 17894653Sdougm /* If a share has properties, remove them */ 17904653Sdougm ret = sa_delete_pgroup(handle, shareid); 17914653Sdougm for (opt = sa_get_optionset(share, NULL); 17924653Sdougm opt != NULL; 17934653Sdougm opt = sa_get_next_optionset(opt)) { 17944653Sdougm char *proto; 17954653Sdougm proto = sa_get_optionset_attr(opt, "type"); 17964653Sdougm if (proto != NULL) { 17974653Sdougm (void) snprintf(propstring, 17984653Sdougm proplen, "%s_%s", shareid, 17994653Sdougm proto); 18004653Sdougm ret = sa_delete_pgroup(handle, 18014653Sdougm propstring); 18024653Sdougm sa_free_attr_string(proto); 18034653Sdougm } else { 18044653Sdougm ret = SA_NO_MEMORY; 18054653Sdougm } 18063034Sdougm } 18073034Sdougm /* 18084653Sdougm * If a share has security/negotiable 18093034Sdougm * properties, remove them. 18103034Sdougm */ 18114653Sdougm for (sec = sa_get_security(share, NULL, NULL); 18124653Sdougm sec != NULL; 18134653Sdougm sec = sa_get_next_security(sec)) { 18144653Sdougm char *proto; 18154653Sdougm char *sectype; 18164653Sdougm proto = sa_get_security_attr(sec, "type"); 18174653Sdougm sectype = sa_get_security_attr(sec, "sectype"); 18184653Sdougm if (proto != NULL && sectype != NULL) { 18194653Sdougm (void) snprintf(propstring, proplen, 18204653Sdougm "%s_%s_%s", shareid, proto, 18214653Sdougm sectype); 18224653Sdougm ret = sa_delete_pgroup(handle, 18234653Sdougm propstring); 18244653Sdougm } else { 18254653Sdougm ret = SA_NO_MEMORY; 18264653Sdougm } 18274653Sdougm if (proto != NULL) 18284653Sdougm sa_free_attr_string(proto); 18294653Sdougm if (sectype != NULL) 18304653Sdougm sa_free_attr_string(sectype); 18313034Sdougm } 18323034Sdougm } 18333034Sdougm } 18344653Sdougm out: 18353034Sdougm if (groupname != NULL) 18364653Sdougm sa_free_attr_string(groupname); 18373034Sdougm if (shareid != NULL) 18384653Sdougm sa_free_attr_string(shareid); 18393034Sdougm if (propstring != NULL) 18404653Sdougm free(propstring); 18413034Sdougm 18423034Sdougm return (ret); 18433034Sdougm } 1844