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 /* 23*11337SWilliam.Krier@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 243034Sdougm * Use is subject to license terms. 253034Sdougm */ 263034Sdougm 273034Sdougm /* helper functions for using libscf with sharemgr */ 283034Sdougm 293034Sdougm #include <libscf.h> 303034Sdougm #include <libxml/parser.h> 313034Sdougm #include <libxml/tree.h> 323034Sdougm #include "libshare.h" 333034Sdougm #include "libshare_impl.h" 343034Sdougm #include "scfutil.h" 353034Sdougm #include <string.h> 365331Samw #include <ctype.h> 373034Sdougm #include <errno.h> 383034Sdougm #include <uuid/uuid.h> 393034Sdougm #include <sys/param.h> 403348Sdougm #include <signal.h> 415951Sdougm #include <sys/time.h> 425997Sdougm #include <libintl.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); 475951Sdougm static void set_transaction_tstamp(sa_handle_impl_t); 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 sa_group_t defgrp; 1444653Sdougm defgrp = sa_create_group((sa_handle_t)ihandle, "default", NULL); 1455997Sdougm /* Only NFS enabled for "default" group. */ 1465997Sdougm if (defgrp != NULL) 1475997Sdougm (void) sa_create_optionset(defgrp, "nfs"); 1484653Sdougm } 1494653Sdougm 1503034Sdougm return (handle); 1513034Sdougm 1524653Sdougm /* Error handling/unwinding */ 1533034Sdougm err: 1543034Sdougm (void) sa_scf_fini(handle); 1553034Sdougm (void) printf("libshare SMF initialization problem: %s\n", 1564653Sdougm scf_strerror(scf_error())); 1573034Sdougm return (NULL); 1583034Sdougm } 1593034Sdougm 1603034Sdougm /* 1613034Sdougm * get_scf_limit(name) 1623034Sdougm * 1633034Sdougm * Since we use scf_limit a lot and do the same check and return the 1643034Sdougm * same value if it fails, implement as a function for code 1653034Sdougm * simplification. Basically, if name isn't found, return MAXPATHLEN 1663034Sdougm * (1024) so we have a reasonable default buffer size. 1673034Sdougm */ 1683034Sdougm static ssize_t 1693034Sdougm get_scf_limit(uint32_t name) 1703034Sdougm { 1713034Sdougm ssize_t vallen; 1723034Sdougm 1733034Sdougm vallen = scf_limit(name); 1743034Sdougm if (vallen == (ssize_t)-1) 1754653Sdougm vallen = MAXPATHLEN; 1763034Sdougm return (vallen); 1773034Sdougm } 1783034Sdougm 1793034Sdougm /* 1803034Sdougm * skip_property(name) 1813034Sdougm * 1824653Sdougm * Internal function to check to see if a property is an SMF magic 1833034Sdougm * property that needs to be skipped. 1843034Sdougm */ 1853034Sdougm static int 1863034Sdougm skip_property(char *name) 1873034Sdougm { 1883034Sdougm int i; 1893034Sdougm 1903034Sdougm for (i = 0; skip_props[i] != NULL; i++) 1914653Sdougm if (strcmp(name, skip_props[i]) == 0) 1923034Sdougm return (1); 1933034Sdougm return (0); 1943034Sdougm } 1953034Sdougm 1963034Sdougm /* 1973034Sdougm * generate_unique_sharename(sharename) 1983034Sdougm * 1993034Sdougm * Shares are represented in SMF as property groups. Due to share 2003034Sdougm * paths containing characters that are not allowed in SMF names and 2013034Sdougm * the need to be unique, we use UUIDs to construct a unique name. 2023034Sdougm */ 2033034Sdougm 2043034Sdougm static void 2053034Sdougm generate_unique_sharename(char *sharename) 2063034Sdougm { 2073034Sdougm uuid_t uuid; 2083034Sdougm 2093034Sdougm uuid_generate(uuid); 2103034Sdougm (void) strcpy(sharename, "S-"); 2113034Sdougm uuid_unparse(uuid, sharename + 2); 2123034Sdougm } 2133034Sdougm 2143034Sdougm /* 2153034Sdougm * valid_protocol(proto) 2163034Sdougm * 2174653Sdougm * Check to see if the specified protocol is a valid one for the 2183034Sdougm * general sharemgr facility. We determine this by checking which 2193034Sdougm * plugin protocols were found. 2203034Sdougm */ 2213034Sdougm 2223034Sdougm static int 2233034Sdougm valid_protocol(char *proto) 2243034Sdougm { 2253034Sdougm struct sa_proto_plugin *plugin; 2263034Sdougm for (plugin = sap_proto_list; plugin != NULL; 2273034Sdougm plugin = plugin->plugin_next) 2284653Sdougm if (strcmp(proto, plugin->plugin_ops->sa_protocol) == 0) 2294653Sdougm return (1); 2303034Sdougm return (0); 2313034Sdougm } 2323034Sdougm 2333034Sdougm /* 2343034Sdougm * sa_extract_pgroup(root, handle, pg, nodetype, proto, sectype) 2353034Sdougm * 2364653Sdougm * Extract the name property group and create the specified type of 2373034Sdougm * node on the provided group. type will be optionset or security. 2383034Sdougm */ 2393034Sdougm 2403034Sdougm static int 2413034Sdougm sa_extract_pgroup(xmlNodePtr root, scfutilhandle_t *handle, 2423034Sdougm scf_propertygroup_t *pg, 2433034Sdougm char *nodetype, char *proto, char *sectype) 2443034Sdougm { 2453034Sdougm xmlNodePtr node; 2463034Sdougm scf_iter_t *iter; 2473034Sdougm scf_property_t *prop; 2483034Sdougm scf_value_t *value; 2493034Sdougm char *name; 2503034Sdougm char *valuestr; 2513034Sdougm ssize_t vallen; 2523034Sdougm int ret = SA_OK; 2533034Sdougm 2543034Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 2553034Sdougm 2563034Sdougm node = xmlNewChild(root, NULL, (xmlChar *)nodetype, NULL); 2574653Sdougm if (node == NULL) 2584653Sdougm return (ret); 2594653Sdougm 2604653Sdougm if (proto != NULL) 2616012Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto); 2624653Sdougm if (sectype != NULL) 2636012Sthurlow (void) xmlSetProp(node, (xmlChar *)"sectype", 2646012Sthurlow (xmlChar *)sectype); 2654653Sdougm /* 2664653Sdougm * Have node to work with so iterate over the properties 2674653Sdougm * in the pg and create option sub nodes. 2684653Sdougm */ 2694653Sdougm iter = scf_iter_create(handle->handle); 2704653Sdougm value = scf_value_create(handle->handle); 2714653Sdougm prop = scf_property_create(handle->handle); 2724653Sdougm name = malloc(scf_max_name_len); 2734653Sdougm valuestr = malloc(vallen); 2744653Sdougm /* 2754653Sdougm * Want to iterate through the properties and add them 2764653Sdougm * to the base optionset. 2774653Sdougm */ 2784653Sdougm if (iter == NULL || value == NULL || prop == NULL || 2794653Sdougm valuestr == NULL || name == NULL) { 2804653Sdougm ret = SA_NO_MEMORY; 2814653Sdougm goto out; 2824653Sdougm } 2834653Sdougm if (scf_iter_pg_properties(iter, pg) == 0) { 2844653Sdougm /* Now iterate the properties in the group */ 2854653Sdougm while (scf_iter_next_property(iter, prop) > 0) { 2864653Sdougm /* have a property */ 2874653Sdougm if (scf_property_get_name(prop, name, 2884653Sdougm scf_max_name_len) > 0) { 2894653Sdougm sa_property_t saprop; 2904653Sdougm /* Some properties are part of the framework */ 2913034Sdougm if (skip_property(name)) 2924653Sdougm continue; 2934653Sdougm if (scf_property_get_value(prop, value) != 0) 2944653Sdougm continue; 2954653Sdougm if (scf_value_get_astring(value, valuestr, 2964653Sdougm vallen) < 0) 2974653Sdougm continue; 2984653Sdougm saprop = sa_create_property(name, valuestr); 2994653Sdougm if (saprop != NULL) { 3003034Sdougm /* 3014653Sdougm * Since in SMF, don't 3023034Sdougm * recurse. Use xmlAddChild 3033034Sdougm * directly, instead. 3043034Sdougm */ 3056012Sthurlow (void) xmlAddChild(node, 3064653Sdougm (xmlNodePtr) saprop); 3073034Sdougm } 3083034Sdougm } 3093034Sdougm } 3103034Sdougm } 3114653Sdougm out: 3124653Sdougm /* cleanup to avoid memory leaks */ 3134653Sdougm if (value != NULL) 3144653Sdougm scf_value_destroy(value); 3154653Sdougm if (iter != NULL) 3164653Sdougm scf_iter_destroy(iter); 3174653Sdougm if (prop != NULL) 3184653Sdougm scf_property_destroy(prop); 3194653Sdougm if (name != NULL) 3204653Sdougm free(name); 3214653Sdougm if (valuestr != NULL) 3224653Sdougm free(valuestr); 3234653Sdougm 3243034Sdougm return (ret); 3253034Sdougm } 3263034Sdougm 3273034Sdougm /* 3283034Sdougm * sa_extract_attrs(root, handle, instance) 3293034Sdougm * 3304653Sdougm * Local function to extract the actual attributes/properties from the 3313034Sdougm * property group of the service instance. These are the well known 3323034Sdougm * attributes of "state" and "zfs". If additional attributes are 3333034Sdougm * added, they should be added here. 3343034Sdougm */ 3353034Sdougm 3363034Sdougm static void 3373034Sdougm sa_extract_attrs(xmlNodePtr root, scfutilhandle_t *handle, 3383034Sdougm scf_instance_t *instance) 3393034Sdougm { 3403034Sdougm scf_property_t *prop; 3413034Sdougm scf_value_t *value; 3423034Sdougm char *valuestr; 3433034Sdougm ssize_t vallen; 3443034Sdougm 3453034Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 3463034Sdougm prop = scf_property_create(handle->handle); 3473034Sdougm value = scf_value_create(handle->handle); 3483034Sdougm valuestr = malloc(vallen); 3494653Sdougm if (prop == NULL || value == NULL || valuestr == NULL || 3504653Sdougm scf_instance_get_pg(instance, "operation", handle->pg) != 0) { 3514653Sdougm goto out; 3524653Sdougm } 3534653Sdougm /* 3544653Sdougm * Have a property group with desired name so now get 3554653Sdougm * the known attributes. 3564653Sdougm */ 3574653Sdougm if (scf_pg_get_property(handle->pg, "state", prop) == 0) { 3584653Sdougm /* Found the property so get the value */ 3593034Sdougm if (scf_property_get_value(prop, value) == 0) { 3604653Sdougm if (scf_value_get_astring(value, valuestr, 3614653Sdougm vallen) >= 0) { 3626012Sthurlow (void) xmlSetProp(root, (xmlChar *)"state", 3633034Sdougm (xmlChar *)valuestr); 3644653Sdougm } 3653034Sdougm } 3664653Sdougm } 3674653Sdougm if (scf_pg_get_property(handle->pg, "zfs", prop) == 0) { 3684653Sdougm /* Found the property so get the value */ 3693034Sdougm if (scf_property_get_value(prop, value) == 0) { 3704653Sdougm if (scf_value_get_astring(value, valuestr, 3714653Sdougm vallen) > 0) { 3726012Sthurlow (void) xmlSetProp(root, (xmlChar *)"zfs", 3733034Sdougm (xmlChar *)valuestr); 3744653Sdougm } 3753034Sdougm } 3763034Sdougm } 3774653Sdougm out: 3783034Sdougm if (valuestr != NULL) 3794653Sdougm free(valuestr); 3803034Sdougm if (value != NULL) 3814653Sdougm scf_value_destroy(value); 3823034Sdougm if (prop != NULL) 3834653Sdougm scf_property_destroy(prop); 3843034Sdougm } 3853034Sdougm 3863034Sdougm /* 3874653Sdougm * List of known share attributes. 3883034Sdougm */ 3893034Sdougm 3903034Sdougm static char *share_attr[] = { 3913034Sdougm "path", 3923034Sdougm "id", 3935331Samw "drive-letter", 3945331Samw "exclude", 3953034Sdougm NULL, 3963034Sdougm }; 3973034Sdougm 3983034Sdougm static int 3993034Sdougm is_share_attr(char *name) 4003034Sdougm { 4013034Sdougm int i; 4023034Sdougm for (i = 0; share_attr[i] != NULL; i++) 4034653Sdougm if (strcmp(name, share_attr[i]) == 0) 4044653Sdougm return (1); 4053034Sdougm return (0); 4063034Sdougm } 4073034Sdougm 4083034Sdougm /* 4095331Samw * _sa_make_resource(node, valuestr) 4105331Samw * 4115331Samw * Make a resource node on the share node. The valusestr will either 4125331Samw * be old format (SMF acceptable string) or new format (pretty much an 4135331Samw * arbitrary string with "nnn:" prefixing in order to persist 4145331Samw * mapping). The input valuestr will get modified in place. This is 4155331Samw * only used in SMF repository parsing. A possible third field will be 4165331Samw * a "description" string. 4175331Samw */ 4185331Samw 4195331Samw static void 4205331Samw _sa_make_resource(xmlNodePtr node, char *valuestr) 4215331Samw { 4225331Samw char *idx; 4235331Samw char *name; 4245331Samw char *description = NULL; 4255331Samw 4265331Samw idx = valuestr; 4275331Samw name = strchr(valuestr, ':'); 4285331Samw if (name == NULL) { 4295331Samw /* this is old form so give an index of "0" */ 4305331Samw idx = "0"; 4315331Samw name = valuestr; 4325331Samw } else { 4335331Samw /* NUL the ':' and move past it */ 4345331Samw *name++ = '\0'; 4355331Samw /* There could also be a description string */ 4365331Samw description = strchr(name, ':'); 4375331Samw if (description != NULL) 4385331Samw *description++ = '\0'; 4395331Samw } 4405331Samw node = xmlNewChild(node, NULL, (xmlChar *)"resource", NULL); 4415331Samw if (node != NULL) { 4426012Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", (xmlChar *)name); 4436012Sthurlow (void) xmlSetProp(node, (xmlChar *)"id", (xmlChar *)idx); 4445331Samw /* SMF values are always persistent */ 4456012Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", 4466012Sthurlow (xmlChar *)"persist"); 4475331Samw if (description != NULL && strlen(description) > 0) { 4485331Samw (void) xmlNewChild(node, NULL, (xmlChar *)"description", 4495331Samw (xmlChar *)description); 4505331Samw } 4515331Samw } 4525331Samw } 4535331Samw 4545331Samw 4555331Samw /* 4563034Sdougm * sa_share_from_pgroup 4573034Sdougm * 4584653Sdougm * Extract the share definition from the share property group. We do 4593034Sdougm * some sanity checking to avoid bad data. 4603034Sdougm * 4613034Sdougm * Since this is only constructing the internal data structures, we 4623034Sdougm * don't use the sa_* functions most of the time. 4633034Sdougm */ 4643034Sdougm void 4653034Sdougm sa_share_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle, 4663034Sdougm scf_propertygroup_t *pg, char *id) 4673034Sdougm { 4683034Sdougm xmlNodePtr node; 4693034Sdougm char *name; 4703034Sdougm scf_iter_t *iter; 4713034Sdougm scf_property_t *prop; 4723034Sdougm scf_value_t *value; 4733034Sdougm ssize_t vallen; 4743034Sdougm char *valuestr; 4753034Sdougm int ret = SA_OK; 4763348Sdougm int have_path = 0; 4773034Sdougm 4783034Sdougm /* 4793034Sdougm * While preliminary check (starts with 'S') passed before 4803034Sdougm * getting here. Need to make sure it is in ID syntax 4813034Sdougm * (Snnnnnn). Note that shares with properties have similar 4823034Sdougm * pgroups. 4833034Sdougm */ 4843034Sdougm vallen = strlen(id); 4853034Sdougm if (*id == SA_SHARE_PG_PREFIX[0] && vallen == SA_SHARE_PG_LEN) { 4864653Sdougm uuid_t uuid; 4874653Sdougm if (strncmp(id, SA_SHARE_PG_PREFIX, 4884653Sdougm SA_SHARE_PG_PREFIXLEN) != 0 || 4894653Sdougm uuid_parse(id + 2, uuid) < 0) 4904653Sdougm return; 4914653Sdougm } else { 4923034Sdougm return; 4933034Sdougm } 4943034Sdougm 4953034Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 4963034Sdougm 4973034Sdougm iter = scf_iter_create(handle->handle); 4983034Sdougm value = scf_value_create(handle->handle); 4993034Sdougm prop = scf_property_create(handle->handle); 5003034Sdougm name = malloc(scf_max_name_len); 5013034Sdougm valuestr = malloc(vallen); 5023034Sdougm 5033034Sdougm /* 5044653Sdougm * Construct the share XML node. It is similar to sa_add_share 5053034Sdougm * but never changes the repository. Also, there won't be any 5063034Sdougm * ZFS or transient shares. Root will be the group it is 5073034Sdougm * associated with. 5083034Sdougm */ 5093034Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"share", NULL); 5103034Sdougm if (node != NULL) { 5113034Sdougm /* 5124653Sdougm * Make sure the UUID part of the property group is 5133034Sdougm * stored in the share "id" property. We use this 5143034Sdougm * later. 5153034Sdougm */ 5166012Sthurlow (void) xmlSetProp(node, (xmlChar *)"id", (xmlChar *)id); 5176012Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", 5186012Sthurlow (xmlChar *)"persist"); 5193034Sdougm } 5203034Sdougm 5214653Sdougm if (iter == NULL || value == NULL || prop == NULL || name == NULL) 5224653Sdougm goto out; 5234653Sdougm 5244653Sdougm /* Iterate over the share pg properties */ 5254653Sdougm if (scf_iter_pg_properties(iter, pg) != 0) 5264653Sdougm goto out; 5274653Sdougm 5284653Sdougm while (scf_iter_next_property(iter, prop) > 0) { 5294653Sdougm ret = SA_SYSTEM_ERR; /* assume the worst */ 5304653Sdougm if (scf_property_get_name(prop, name, scf_max_name_len) > 0) { 5313034Sdougm if (scf_property_get_value(prop, value) == 0) { 5324653Sdougm if (scf_value_get_astring(value, valuestr, 5334653Sdougm vallen) >= 0) { 5344653Sdougm ret = SA_OK; 5354653Sdougm } 5365331Samw } else if (strcmp(name, "resource") == 0) { 5375331Samw ret = SA_OK; 5383034Sdougm } 5394653Sdougm } 5405331Samw if (ret != SA_OK) 5415331Samw continue; 5425331Samw /* 5435331Samw * Check that we have the "path" property in 5445331Samw * name. The string in name will always be nul 5455331Samw * terminated if scf_property_get_name() 5465331Samw * succeeded. 5475331Samw */ 5485331Samw if (strcmp(name, "path") == 0) 5495331Samw have_path = 1; 5505331Samw if (is_share_attr(name)) { 5513348Sdougm /* 5525331Samw * If a share attr, then simple - 5535331Samw * usually path and id name 5543348Sdougm */ 5556012Sthurlow (void) xmlSetProp(node, (xmlChar *)name, 5565331Samw (xmlChar *)valuestr); 5575331Samw } else if (strcmp(name, "resource") == 0) { 5585331Samw /* 5595331Samw * Resource names handled differently since 5605331Samw * there can be multiple on each share. The 5615331Samw * "resource" id must be preserved since this 5625331Samw * will be used by some protocols in mapping 5635331Samw * "property spaces" to names and is always 5645331Samw * used to create SMF property groups specific 5655331Samw * to resources. CIFS needs this. The first 5665331Samw * value is present so add and then loop for 5675331Samw * any additional. Since this is new and 5685331Samw * previous values may exist, handle 5695331Samw * conversions. 5705331Samw */ 5715331Samw scf_iter_t *viter; 5725331Samw viter = scf_iter_create(handle->handle); 5735331Samw if (viter != NULL && 5745331Samw scf_iter_property_values(viter, prop) == 0) { 5755331Samw while (scf_iter_next_value(viter, value) > 0) { 5765331Samw /* Have a value so process it */ 5775331Samw if (scf_value_get_ustring(value, 5785331Samw valuestr, vallen) >= 0) { 5795331Samw /* have a ustring */ 5805331Samw _sa_make_resource(node, 5815331Samw valuestr); 5825331Samw } else if (scf_value_get_astring(value, 5835331Samw valuestr, vallen) >= 0) { 5845331Samw /* have an astring */ 5855331Samw _sa_make_resource(node, 5865331Samw valuestr); 5875331Samw } 5884653Sdougm } 5895331Samw scf_iter_destroy(viter); 5905331Samw } 5915331Samw } else { 5925331Samw if (strcmp(name, "description") == 0) { 5935331Samw /* We have a description node */ 5945331Samw xmlNodePtr desc; 5955331Samw desc = xmlNewChild(node, NULL, 5965331Samw (xmlChar *)"description", NULL); 5975331Samw if (desc != NULL) 5985331Samw xmlNodeSetContent(desc, 5995331Samw (xmlChar *)valuestr); 6003034Sdougm } 6013034Sdougm } 6023034Sdougm } 6034653Sdougm out: 6043348Sdougm /* 6054653Sdougm * A share without a path is broken so we want to not include 6063348Sdougm * these. They shouldn't happen but if you kill a sharemgr in 6073348Sdougm * the process of creating a share, it could happen. They 6083348Sdougm * should be harmless. It is also possible that another 6093348Sdougm * sharemgr is running and in the process of creating a share. 6103348Sdougm */ 6113348Sdougm if (have_path == 0 && node != NULL) { 6124653Sdougm xmlUnlinkNode(node); 6134653Sdougm xmlFreeNode(node); 6143348Sdougm } 6153034Sdougm if (name != NULL) 6164653Sdougm free(name); 6173034Sdougm if (valuestr != NULL) 6184653Sdougm free(valuestr); 6193034Sdougm if (value != NULL) 6204653Sdougm scf_value_destroy(value); 6213034Sdougm if (iter != NULL) 6224653Sdougm scf_iter_destroy(iter); 6233034Sdougm if (prop != NULL) 6244653Sdougm scf_property_destroy(prop); 6253034Sdougm } 6263034Sdougm 6273034Sdougm /* 6283034Sdougm * find_share_by_id(shareid) 6293034Sdougm * 6303034Sdougm * Search all shares in all groups until we find the share represented 6313034Sdougm * by "id". 6323034Sdougm */ 6333034Sdougm 6343034Sdougm static sa_share_t 6353910Sdougm find_share_by_id(sa_handle_t handle, char *shareid) 6363034Sdougm { 6373034Sdougm sa_group_t group; 6383034Sdougm sa_share_t share = NULL; 6393034Sdougm char *id = NULL; 6403034Sdougm int done = 0; 6413034Sdougm 6424653Sdougm for (group = sa_get_group(handle, NULL); 6434653Sdougm group != NULL && !done; 6444653Sdougm group = sa_get_next_group(group)) { 6454653Sdougm for (share = sa_get_share(group, NULL); 6464653Sdougm share != NULL; 6474653Sdougm share = sa_get_next_share(share)) { 6483034Sdougm id = sa_get_share_attr(share, "id"); 6493034Sdougm if (id != NULL && strcmp(id, shareid) == 0) { 6503034Sdougm sa_free_attr_string(id); 6513034Sdougm id = NULL; 6523034Sdougm done++; 6533034Sdougm break; 6543034Sdougm } 6553034Sdougm if (id != NULL) { 6564653Sdougm sa_free_attr_string(id); 6574653Sdougm id = NULL; 6583034Sdougm } 6593034Sdougm } 6603034Sdougm } 6613034Sdougm return (share); 6623034Sdougm } 6633034Sdougm 6643034Sdougm /* 6655331Samw * find_resource_by_index(share, index) 6665331Samw * 6675331Samw * Search the resource records on the share for the id index. 6685331Samw */ 6695331Samw static sa_resource_t 6705331Samw find_resource_by_index(sa_share_t share, char *index) 6715331Samw { 6725331Samw sa_resource_t resource; 6735331Samw sa_resource_t found = NULL; 6745331Samw char *id; 6755331Samw 6765331Samw for (resource = sa_get_share_resource(share, NULL); 6775331Samw resource != NULL && found == NULL; 6785331Samw resource = sa_get_next_resource(resource)) { 6795331Samw id = (char *)xmlGetProp((xmlNodePtr)resource, (xmlChar *)"id"); 6805331Samw if (id != NULL) { 6815331Samw if (strcmp(id, index) == 0) { 6825331Samw /* found it so save in "found" */ 6835331Samw found = resource; 6845331Samw } 6855331Samw sa_free_attr_string(id); 6865331Samw } 6875331Samw } 6885331Samw return (found); 6895331Samw } 6905331Samw 6915331Samw /* 6925331Samw * sa_share_props_from_pgroup(root, handle, pg, id, sahandle) 6933034Sdougm * 6944653Sdougm * Extract share properties from the SMF property group. More sanity 6953034Sdougm * checks are done and the share object is created. We ignore some 6963034Sdougm * errors that could exist in the repository and only worry about 6973034Sdougm * property groups that validate in naming. 6983034Sdougm */ 6993034Sdougm 7003034Sdougm static int 7013034Sdougm sa_share_props_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle, 7023910Sdougm scf_propertygroup_t *pg, char *id, sa_handle_t sahandle) 7033034Sdougm { 7043034Sdougm xmlNodePtr node; 7054653Sdougm char *name = NULL; 7064653Sdougm scf_iter_t *iter = NULL; 7074653Sdougm scf_property_t *prop = NULL; 7084653Sdougm scf_value_t *value = NULL; 7093034Sdougm ssize_t vallen; 7104653Sdougm char *valuestr = NULL; 7113034Sdougm int ret = SA_OK; 7123034Sdougm char *sectype = NULL; 7133034Sdougm char *proto; 7143034Sdougm sa_share_t share; 7154653Sdougm uuid_t uuid; 7163034Sdougm 7173034Sdougm /* 7183034Sdougm * While preliminary check (starts with 'S') passed before 7193034Sdougm * getting here. Need to make sure it is in ID syntax 7203034Sdougm * (Snnnnnn). Note that shares with properties have similar 7213034Sdougm * pgroups. If the pg name is more than SA_SHARE_PG_LEN 7223034Sdougm * characters, it is likely one of the protocol/security 7233034Sdougm * versions. 7243034Sdougm */ 7253034Sdougm vallen = strlen(id); 7264653Sdougm if (*id != SA_SHARE_PG_PREFIX[0] || vallen <= SA_SHARE_PG_LEN) { 7274653Sdougm /* 7284653Sdougm * It is ok to not have what we thought since someone might 7294653Sdougm * have added a name via SMF. 7304653Sdougm */ 7314653Sdougm return (ret); 7324653Sdougm } 7334653Sdougm if (strncmp(id, SA_SHARE_PG_PREFIX, SA_SHARE_PG_PREFIXLEN) == 0) { 7343034Sdougm proto = strchr(id, '_'); 7353034Sdougm if (proto == NULL) 7364653Sdougm return (ret); 7373034Sdougm *proto++ = '\0'; 7383034Sdougm if (uuid_parse(id + SA_SHARE_PG_PREFIXLEN, uuid) < 0) 7394653Sdougm return (ret); 7403034Sdougm /* 7413034Sdougm * probably a legal optionset so check a few more 7423034Sdougm * syntax points below. 7433034Sdougm */ 7443034Sdougm if (*proto == '\0') { 7454653Sdougm /* not a valid proto (null) */ 7464653Sdougm return (ret); 7473034Sdougm } 7485331Samw 7493034Sdougm sectype = strchr(proto, '_'); 7503034Sdougm if (sectype != NULL) 7514653Sdougm *sectype++ = '\0'; 7523034Sdougm if (!valid_protocol(proto)) 7534653Sdougm return (ret); 7543034Sdougm } 7553034Sdougm 7563034Sdougm /* 7574653Sdougm * To get here, we have a valid protocol and possibly a 7583034Sdougm * security. We now have to find the share that it is really 7593034Sdougm * associated with. The "id" portion of the pgroup name will 7603034Sdougm * match. 7613034Sdougm */ 7623034Sdougm 7633910Sdougm share = find_share_by_id(sahandle, id); 7643034Sdougm if (share == NULL) 7654653Sdougm return (SA_BAD_PATH); 7663034Sdougm 7673034Sdougm root = (xmlNodePtr)share; 7683034Sdougm 7693034Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 7703034Sdougm 7714653Sdougm if (sectype == NULL) 7724653Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"optionset", NULL); 7734653Sdougm else { 7745331Samw if (isdigit((int)*sectype)) { 7755331Samw sa_resource_t resource; 7765331Samw /* 7775331Samw * If sectype[0] is a digit, then it is an index into 7785331Samw * the resource names. We need to find a resource 7795331Samw * record and then get the properties into an 7805331Samw * optionset. The optionset becomes the "node" and the 7815331Samw * rest is hung off of the share. 7825331Samw */ 7835331Samw resource = find_resource_by_index(share, sectype); 7845331Samw if (resource != NULL) { 7855331Samw node = xmlNewChild(resource, NULL, 7865331Samw (xmlChar *)"optionset", NULL); 7875331Samw } else { 7885521Sas200622 /* This shouldn't happen. */ 7895331Samw ret = SA_SYSTEM_ERR; 7905521Sas200622 goto out; 7915331Samw } 7925331Samw } else { 7935331Samw /* 7945331Samw * If not a digit, then it is a security type 7955331Samw * (alternate option space). Security types start with 7965331Samw * an alphabetic. 7975331Samw */ 7985331Samw node = xmlNewChild(root, NULL, (xmlChar *)"security", 7995331Samw NULL); 8005331Samw if (node != NULL) 8016012Sthurlow (void) xmlSetProp(node, (xmlChar *)"sectype", 8025331Samw (xmlChar *)sectype); 8035331Samw } 8044653Sdougm } 8054653Sdougm if (node == NULL) { 8064653Sdougm ret = SA_NO_MEMORY; 8074653Sdougm goto out; 8084653Sdougm } 8094653Sdougm 8106012Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto); 8114653Sdougm /* now find the properties */ 8123034Sdougm iter = scf_iter_create(handle->handle); 8133034Sdougm value = scf_value_create(handle->handle); 8143034Sdougm prop = scf_property_create(handle->handle); 8153034Sdougm name = malloc(scf_max_name_len); 8163034Sdougm valuestr = malloc(vallen); 8173034Sdougm 8184653Sdougm if (iter == NULL || value == NULL || prop == NULL || name == NULL) 8194653Sdougm goto out; 8204653Sdougm 8215331Samw /* iterate over the share pg properties */ 8224653Sdougm if (scf_iter_pg_properties(iter, pg) == 0) { 8234653Sdougm while (scf_iter_next_property(iter, prop) > 0) { 8243034Sdougm ret = SA_SYSTEM_ERR; /* assume the worst */ 8253034Sdougm if (scf_property_get_name(prop, name, 8264653Sdougm scf_max_name_len) > 0) { 8274653Sdougm if (scf_property_get_value(prop, value) == 0) { 8284653Sdougm if (scf_value_get_astring(value, 8294653Sdougm valuestr, vallen) >= 0) { 8304653Sdougm ret = SA_OK; 8314653Sdougm } 8323034Sdougm } 8333034Sdougm } else { 8344653Sdougm ret = SA_SYSTEM_ERR; 8353034Sdougm } 8363034Sdougm if (ret == SA_OK) { 8374653Sdougm sa_property_t prop; 8384653Sdougm prop = sa_create_property(name, valuestr); 8394653Sdougm if (prop != NULL) 8404653Sdougm prop = (sa_property_t)xmlAddChild(node, 8414653Sdougm (xmlNodePtr)prop); 8424653Sdougm else 8434653Sdougm ret = SA_NO_MEMORY; 8443034Sdougm } 8453034Sdougm } 8463034Sdougm } else { 8474653Sdougm ret = SA_SYSTEM_ERR; 8483034Sdougm } 8494653Sdougm out: 8503034Sdougm if (iter != NULL) 8514653Sdougm scf_iter_destroy(iter); 8523034Sdougm if (value != NULL) 8534653Sdougm scf_value_destroy(value); 8543034Sdougm if (prop != NULL) 8554653Sdougm scf_property_destroy(prop); 8563034Sdougm if (name != NULL) 8574653Sdougm free(name); 8583034Sdougm if (valuestr != NULL) 8594653Sdougm free(valuestr); 8603034Sdougm return (ret); 8613034Sdougm } 8623034Sdougm 8633034Sdougm /* 8643034Sdougm * sa_extract_group(root, handle, instance) 8653034Sdougm * 8664653Sdougm * Get the config info for this instance of a group and create the XML 8673034Sdougm * subtree from it. 8683034Sdougm */ 8693034Sdougm 8703034Sdougm static int 8713034Sdougm sa_extract_group(xmlNodePtr root, scfutilhandle_t *handle, 8725951Sdougm scf_instance_t *instance, sa_handle_t sahandle) 8733034Sdougm { 8743034Sdougm char *buff; 8753034Sdougm xmlNodePtr node; 8763034Sdougm scf_iter_t *iter; 8773034Sdougm char *proto; 8783034Sdougm char *sectype; 8795997Sdougm boolean_t have_shares = B_FALSE; 8805997Sdougm boolean_t is_default = B_FALSE; 8815997Sdougm boolean_t is_nfs = B_FALSE; 8823034Sdougm int ret = SA_OK; 8833034Sdougm int err; 8843034Sdougm 8853034Sdougm buff = malloc(scf_max_name_len); 8864653Sdougm if (buff == NULL) 8874653Sdougm return (SA_NO_MEMORY); 8884653Sdougm 8893034Sdougm iter = scf_iter_create(handle->handle); 8904653Sdougm if (iter == NULL) { 8914653Sdougm ret = SA_NO_MEMORY; 8924653Sdougm goto out; 8934653Sdougm } 8944653Sdougm 8954653Sdougm if (scf_instance_get_name(instance, buff, scf_max_name_len) > 0) { 8963034Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"group", NULL); 8974653Sdougm if (node == NULL) { 8984653Sdougm ret = SA_NO_MEMORY; 8994653Sdougm goto out; 9004653Sdougm } 9016012Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", (xmlChar *)buff); 9024653Sdougm if (strcmp(buff, "default") == 0) 9035997Sdougm is_default = B_TRUE; 9044653Sdougm 9054653Sdougm sa_extract_attrs(node, handle, instance); 9064653Sdougm /* 9074653Sdougm * Iterate through all the property groups 9084653Sdougm * looking for those with security or 9094653Sdougm * optionset prefixes. The names of the 9104653Sdougm * matching pgroups are parsed to get the 9114653Sdougm * protocol, and for security, the sectype. 9124653Sdougm * Syntax is as follows: 9134653Sdougm * optionset | optionset_<proto> 9144653Sdougm * security_default | security_<proto>_<sectype> 9154653Sdougm * "operation" is handled by 9164653Sdougm * sa_extract_attrs(). 9174653Sdougm */ 9184653Sdougm if (scf_iter_instance_pgs(iter, instance) != 0) { 9194653Sdougm ret = SA_NO_MEMORY; 9204653Sdougm goto out; 9214653Sdougm } 9224653Sdougm while (scf_iter_next_pg(iter, handle->pg) > 0) { 9234653Sdougm /* Have a pgroup so sort it out */ 9244653Sdougm ret = scf_pg_get_name(handle->pg, buff, 9254653Sdougm scf_max_name_len); 9265997Sdougm if (ret <= 0) 9275997Sdougm continue; 9285997Sdougm is_nfs = B_FALSE; 9295997Sdougm 9305997Sdougm if (buff[0] == SA_SHARE_PG_PREFIX[0]) { 9315997Sdougm sa_share_from_pgroup(node, handle, 9325997Sdougm handle->pg, buff); 9335997Sdougm have_shares = B_TRUE; 9345997Sdougm } else if (strncmp(buff, "optionset", 9) == 0) { 9355997Sdougm char *nodetype = "optionset"; 9365997Sdougm /* Have an optionset */ 9375997Sdougm sectype = NULL; 9385997Sdougm proto = strchr(buff, '_'); 9395997Sdougm if (proto != NULL) { 9405997Sdougm *proto++ = '\0'; 9415997Sdougm sectype = strchr(proto, '_'); 9425997Sdougm if (sectype != NULL) { 9435997Sdougm *sectype++ = '\0'; 9445997Sdougm nodetype = "security"; 9453034Sdougm } 9465997Sdougm is_nfs = strcmp(proto, "nfs") == 0; 9475997Sdougm } else if (strlen(buff) > 9) { 9485997Sdougm /* 9495997Sdougm * This can only occur if 9505997Sdougm * someone has made changes 9515997Sdougm * via an SMF command. Since 9525997Sdougm * this would be an unknown 9535997Sdougm * syntax, we just ignore it. 9545997Sdougm */ 9555997Sdougm continue; 9565997Sdougm } 9575997Sdougm /* 9585997Sdougm * If the group is not "default" or is 9595997Sdougm * "default" and is_nfs, then extract the 9605997Sdougm * pgroup. If it is_default and !is_nfs, 9615997Sdougm * then we have an error and should remove 9625997Sdougm * the extraneous protocols. We don't care 9635997Sdougm * about errors on scf_pg_delete since we 9645997Sdougm * might not have permission during an 9655997Sdougm * extract only. 9665997Sdougm */ 9675997Sdougm if (!is_default || is_nfs) { 9683034Sdougm ret = sa_extract_pgroup(node, handle, 9694653Sdougm handle->pg, nodetype, proto, 9704653Sdougm sectype); 9715997Sdougm } else { 9725997Sdougm err = scf_pg_delete(handle->pg); 9735997Sdougm if (err == 0) 9745997Sdougm (void) fprintf(stderr, 9755997Sdougm dgettext(TEXT_DOMAIN, 9765997Sdougm "Removed protocol \"%s\" " 9775997Sdougm "from group \"default\"\n"), 9785997Sdougm proto); 9793034Sdougm } 9805997Sdougm } else if (strncmp(buff, "security", 8) == 0) { 9815997Sdougm /* 9825997Sdougm * Have a security (note that 9835997Sdougm * this should change in the 9845997Sdougm * future) 9855997Sdougm */ 9865997Sdougm proto = strchr(buff, '_'); 9875997Sdougm sectype = NULL; 9885997Sdougm if (proto != NULL) { 9895997Sdougm *proto++ = '\0'; 9905997Sdougm sectype = strchr(proto, '_'); 9915997Sdougm if (sectype != NULL) 9925997Sdougm *sectype++ = '\0'; 9935997Sdougm if (strcmp(proto, "default") == 0) 9945997Sdougm proto = NULL; 9955997Sdougm } 9965997Sdougm ret = sa_extract_pgroup(node, handle, 9975997Sdougm handle->pg, "security", proto, sectype); 9983034Sdougm } 9995997Sdougm /* Ignore everything else */ 10004653Sdougm } 10014653Sdougm /* 10024653Sdougm * Make sure we have a valid default group. 10034653Sdougm * On first boot, default won't have any 10044653Sdougm * protocols defined and won't be enabled (but 10055997Sdougm * should be). "default" only has NFS enabled on it. 10064653Sdougm */ 10074653Sdougm if (is_default) { 10084653Sdougm char *state = sa_get_group_attr((sa_group_t)node, 10094653Sdougm "state"); 10103034Sdougm 10114653Sdougm if (state == NULL) { 10123034Sdougm /* set attribute to enabled */ 10133034Sdougm (void) sa_set_group_attr((sa_group_t)node, 10144653Sdougm "state", "enabled"); 10155997Sdougm (void) sa_create_optionset((sa_group_t)node, 10165997Sdougm "nfs"); 10174653Sdougm } else { 10183034Sdougm sa_free_attr_string(state); 10193034Sdougm } 10204653Sdougm } 10214653Sdougm /* Do a second pass if shares were found */ 10224653Sdougm if (have_shares && scf_iter_instance_pgs(iter, instance) == 0) { 10234653Sdougm while (scf_iter_next_pg(iter, handle->pg) > 0) { 10243034Sdougm /* 10254653Sdougm * Have a pgroup so see if it is a 10263034Sdougm * share optionset 10273034Sdougm */ 10283034Sdougm err = scf_pg_get_name(handle->pg, buff, 10294653Sdougm scf_max_name_len); 10304653Sdougm if (err <= 0) 10314653Sdougm continue; 10324653Sdougm if (buff[0] == SA_SHARE_PG_PREFIX[0]) { 10333034Sdougm ret = sa_share_props_from_pgroup(node, 10344653Sdougm handle, handle->pg, buff, 10354653Sdougm sahandle); 10363034Sdougm } 10373034Sdougm } 10383034Sdougm } 10393034Sdougm } 10404653Sdougm out: 10413034Sdougm if (iter != NULL) 10424653Sdougm scf_iter_destroy(iter); 10433034Sdougm if (buff != NULL) 10444653Sdougm free(buff); 10453034Sdougm return (ret); 10463034Sdougm } 10473034Sdougm 10483034Sdougm /* 10493034Sdougm * sa_extract_defaults(root, handle, instance) 10503034Sdougm * 10514653Sdougm * Local function to find the default properties that live in the 10525331Samw * default instance's "operation" property group. 10533034Sdougm */ 10543034Sdougm 10553034Sdougm static void 10563034Sdougm sa_extract_defaults(xmlNodePtr root, scfutilhandle_t *handle, 10573034Sdougm scf_instance_t *instance) 10583034Sdougm { 10593034Sdougm xmlNodePtr node; 10603034Sdougm scf_property_t *prop; 10613034Sdougm scf_value_t *value; 10623034Sdougm char *valuestr; 10633034Sdougm ssize_t vallen; 10643034Sdougm 10653034Sdougm vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 10663034Sdougm prop = scf_property_create(handle->handle); 10673034Sdougm value = scf_value_create(handle->handle); 10683034Sdougm valuestr = malloc(vallen); 10694653Sdougm 10704653Sdougm if (prop == NULL || value == NULL || vallen == 0 || 10714653Sdougm scf_instance_get_pg(instance, "operation", handle->pg) != 0) 10724653Sdougm goto out; 10734653Sdougm 10744653Sdougm if (scf_pg_get_property(handle->pg, "legacy-timestamp", prop) != 0) 10754653Sdougm goto out; 10764653Sdougm 10774653Sdougm /* Found the property so get the value */ 10784653Sdougm if (scf_property_get_value(prop, value) == 0) { 10794653Sdougm if (scf_value_get_astring(value, valuestr, vallen) > 0) { 10803034Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"legacy", 10814653Sdougm NULL); 10823034Sdougm if (node != NULL) { 10836012Sthurlow (void) xmlSetProp(node, (xmlChar *)"timestamp", 10844653Sdougm (xmlChar *)valuestr); 10856012Sthurlow (void) xmlSetProp(node, (xmlChar *)"path", 10864653Sdougm (xmlChar *)SA_LEGACY_DFSTAB); 10873034Sdougm } 10883034Sdougm } 10893034Sdougm } 10904653Sdougm out: 10913034Sdougm if (valuestr != NULL) 10924653Sdougm free(valuestr); 10933034Sdougm if (value != NULL) 10944653Sdougm scf_value_destroy(value); 10953034Sdougm if (prop != NULL) 10964653Sdougm scf_property_destroy(prop); 10973034Sdougm } 10983034Sdougm 10993034Sdougm 11003034Sdougm /* 11015331Samw * sa_get_config(handle, root, doc, sahandle) 11023034Sdougm * 11034653Sdougm * Walk the SMF repository for /network/shares/group and find all the 11043034Sdougm * instances. These become group names. Then add the XML structure 11053034Sdougm * below the groups based on property groups and properties. 11063034Sdougm */ 11073034Sdougm int 11083973Sdougm sa_get_config(scfutilhandle_t *handle, xmlNodePtr root, sa_handle_t sahandle) 11093034Sdougm { 11103034Sdougm int ret = SA_OK; 11113034Sdougm scf_instance_t *instance; 11123034Sdougm scf_iter_t *iter; 11133034Sdougm char buff[BUFSIZ * 2]; 11143034Sdougm 11153034Sdougm instance = scf_instance_create(handle->handle); 11163034Sdougm iter = scf_iter_create(handle->handle); 11173973Sdougm if (instance != NULL && iter != NULL) { 11184653Sdougm if ((ret = scf_iter_service_instances(iter, 11194653Sdougm handle->service)) == 0) { 11204653Sdougm while ((ret = scf_iter_next_instance(iter, 11214653Sdougm instance)) > 0) { 11224653Sdougm if (scf_instance_get_name(instance, buff, 11234653Sdougm sizeof (buff)) > 0) { 11244653Sdougm if (strcmp(buff, "default") == 0) 11254653Sdougm sa_extract_defaults(root, 11264653Sdougm handle, instance); 11274653Sdougm ret = sa_extract_group(root, handle, 11284653Sdougm instance, sahandle); 11294653Sdougm } 11304653Sdougm } 11313034Sdougm } 11323034Sdougm } 11333973Sdougm 11344653Sdougm /* Always cleanup these */ 11353034Sdougm if (instance != NULL) 11364653Sdougm scf_instance_destroy(instance); 11373034Sdougm if (iter != NULL) 11384653Sdougm scf_iter_destroy(iter); 11393034Sdougm return (ret); 11403034Sdougm } 11413034Sdougm 11423034Sdougm /* 11433034Sdougm * sa_get_instance(handle, instance) 11443034Sdougm * 11454653Sdougm * Get the instance of the group service. This is actually the 11463034Sdougm * specific group name. The instance is needed for all property and 11473034Sdougm * control operations. 11483034Sdougm */ 11493034Sdougm 11503034Sdougm int 11513034Sdougm sa_get_instance(scfutilhandle_t *handle, char *instname) 11523034Sdougm { 11533034Sdougm if (scf_service_get_instance(handle->service, instname, 11544653Sdougm handle->instance) != 0) { 11554653Sdougm return (SA_NO_SUCH_GROUP); 11563034Sdougm } 11573034Sdougm return (SA_OK); 11583034Sdougm } 11593034Sdougm 11603034Sdougm /* 11613034Sdougm * sa_create_instance(handle, instname) 11623034Sdougm * 11633034Sdougm * Create a new SMF service instance. There can only be one with a 11643034Sdougm * given name. 11653034Sdougm */ 11663034Sdougm 11673034Sdougm int 11683034Sdougm sa_create_instance(scfutilhandle_t *handle, char *instname) 11693034Sdougm { 11703034Sdougm int ret = SA_OK; 11713034Sdougm char instance[SA_GROUP_INST_LEN]; 11723034Sdougm if (scf_service_add_instance(handle->service, instname, 11734653Sdougm handle->instance) != 0) { 11743034Sdougm /* better error returns need to be added based on real error */ 11754653Sdougm if (scf_error() == SCF_ERROR_PERMISSION_DENIED) 11764653Sdougm ret = SA_NO_PERMISSION; 11774653Sdougm else 11784653Sdougm ret = SA_DUPLICATE_NAME; 11793034Sdougm } else { 11804653Sdougm /* have the service created, so enable it */ 11814653Sdougm (void) snprintf(instance, sizeof (instance), "%s:%s", 11824653Sdougm SA_SVC_FMRI_BASE, instname); 11834653Sdougm (void) smf_enable_instance(instance, 0); 11843034Sdougm } 11853034Sdougm return (ret); 11863034Sdougm } 11873034Sdougm 11883034Sdougm /* 11893034Sdougm * sa_delete_instance(handle, instname) 11903034Sdougm * 11913034Sdougm * When a group goes away, we also remove the service instance. 11923034Sdougm */ 11933034Sdougm 11943034Sdougm int 11953034Sdougm sa_delete_instance(scfutilhandle_t *handle, char *instname) 11963034Sdougm { 11973034Sdougm int ret; 11983034Sdougm 11993034Sdougm if (strcmp(instname, "default") == 0) { 12004653Sdougm ret = SA_NO_PERMISSION; 12013034Sdougm } else { 12024653Sdougm if ((ret = sa_get_instance(handle, instname)) == SA_OK) { 12034653Sdougm if (scf_instance_delete(handle->instance) != 0) 12044653Sdougm /* need better analysis */ 12054653Sdougm ret = SA_NO_PERMISSION; 12064653Sdougm } 12073034Sdougm } 12083034Sdougm return (ret); 12093034Sdougm } 12103034Sdougm 12113034Sdougm /* 12123034Sdougm * sa_create_pgroup(handle, pgroup) 12133034Sdougm * 12143034Sdougm * create a new property group 12153034Sdougm */ 12163034Sdougm 12173034Sdougm int 12183034Sdougm sa_create_pgroup(scfutilhandle_t *handle, char *pgroup) 12193034Sdougm { 12203034Sdougm int ret = SA_OK; 12215951Sdougm int persist = 0; 12225951Sdougm 12233034Sdougm /* 12244653Sdougm * Only create a handle if it doesn't exist. It is ok to exist 12253034Sdougm * since the pg handle will be set as a side effect. 12263034Sdougm */ 12274653Sdougm if (handle->pg == NULL) 12284653Sdougm handle->pg = scf_pg_create(handle->handle); 12294653Sdougm 12303034Sdougm /* 12315951Sdougm * Special case for a non-persistent property group. This is 12325951Sdougm * internal use only. 12335951Sdougm */ 12345951Sdougm if (*pgroup == '*') { 12355951Sdougm persist = SCF_PG_FLAG_NONPERSISTENT; 12365951Sdougm pgroup++; 12375951Sdougm } 12385951Sdougm 12395951Sdougm /* 12404653Sdougm * If the pgroup exists, we are done. If it doesn't, then we 12413034Sdougm * need to actually add one to the service instance. 12423034Sdougm */ 12433034Sdougm if (scf_instance_get_pg(handle->instance, 12444653Sdougm pgroup, handle->pg) != 0) { 12455951Sdougm 12464653Sdougm /* Doesn't exist so create one */ 12474653Sdougm if (scf_instance_add_pg(handle->instance, pgroup, 12485951Sdougm SCF_GROUP_APPLICATION, persist, handle->pg) != 0) { 12494653Sdougm switch (scf_error()) { 12504653Sdougm case SCF_ERROR_PERMISSION_DENIED: 12514653Sdougm ret = SA_NO_PERMISSION; 12524653Sdougm break; 12534653Sdougm default: 12544653Sdougm ret = SA_SYSTEM_ERR; 12554653Sdougm break; 12564653Sdougm } 12573034Sdougm } 12583034Sdougm } 12593034Sdougm return (ret); 12603034Sdougm } 12613034Sdougm 12623034Sdougm /* 12633034Sdougm * sa_delete_pgroup(handle, pgroup) 12643034Sdougm * 12654653Sdougm * Remove the property group from the current instance of the service, 12663034Sdougm * but only if it actually exists. 12673034Sdougm */ 12683034Sdougm 12693034Sdougm int 12703034Sdougm sa_delete_pgroup(scfutilhandle_t *handle, char *pgroup) 12713034Sdougm { 12723034Sdougm int ret = SA_OK; 12733034Sdougm /* 12744653Sdougm * Only delete if it does exist. 12753034Sdougm */ 12764653Sdougm if (scf_instance_get_pg(handle->instance, pgroup, handle->pg) == 0) { 12774653Sdougm /* does exist so delete it */ 12784653Sdougm if (scf_pg_delete(handle->pg) != 0) 12794653Sdougm ret = SA_SYSTEM_ERR; 12804653Sdougm } else { 12813034Sdougm ret = SA_SYSTEM_ERR; 12823034Sdougm } 12833034Sdougm if (ret == SA_SYSTEM_ERR && 12843034Sdougm scf_error() == SCF_ERROR_PERMISSION_DENIED) { 12853034Sdougm ret = SA_NO_PERMISSION; 12863034Sdougm } 12873034Sdougm return (ret); 12883034Sdougm } 12893034Sdougm 12903034Sdougm /* 12913034Sdougm * sa_start_transaction(handle, pgroup) 12923034Sdougm * 12933034Sdougm * Start an SMF transaction so we can deal with properties. it would 12943034Sdougm * be nice to not have to expose this, but we have to in order to 12953034Sdougm * optimize. 12963034Sdougm * 12973034Sdougm * Basic model is to hold the transaction in the handle and allow 12983034Sdougm * property adds/deletes/updates to be added then close the 12993034Sdougm * transaction (or abort). There may eventually be a need to handle 13003034Sdougm * other types of transaction mechanisms but we don't do that now. 13013034Sdougm * 13023034Sdougm * An sa_start_transaction must be followed by either an 13033034Sdougm * sa_end_transaction or sa_abort_transaction before another 13043034Sdougm * sa_start_transaction can be done. 13053034Sdougm */ 13063034Sdougm 13073034Sdougm int 13083034Sdougm sa_start_transaction(scfutilhandle_t *handle, char *propgroup) 13093034Sdougm { 13103034Sdougm int ret = SA_OK; 13113034Sdougm /* 13124653Sdougm * Lookup the property group and create it if it doesn't already 13133034Sdougm * exist. 13143034Sdougm */ 13155951Sdougm if (handle == NULL) 13165951Sdougm return (SA_CONFIG_ERR); 13175951Sdougm 13183034Sdougm if (handle->scf_state == SCH_STATE_INIT) { 13194653Sdougm ret = sa_create_pgroup(handle, propgroup); 13204653Sdougm if (ret == SA_OK) { 13214653Sdougm handle->trans = scf_transaction_create(handle->handle); 13224653Sdougm if (handle->trans != NULL) { 13234653Sdougm if (scf_transaction_start(handle->trans, 13244653Sdougm handle->pg) != 0) { 13254653Sdougm ret = SA_SYSTEM_ERR; 13264653Sdougm } 13274653Sdougm if (ret != SA_OK) { 13284653Sdougm scf_transaction_destroy(handle->trans); 13294653Sdougm handle->trans = NULL; 13304653Sdougm } 13314653Sdougm } else { 13324653Sdougm ret = SA_SYSTEM_ERR; 13334653Sdougm } 13343034Sdougm } 13353034Sdougm } 13363034Sdougm if (ret == SA_SYSTEM_ERR && 13373034Sdougm scf_error() == SCF_ERROR_PERMISSION_DENIED) { 13383034Sdougm ret = SA_NO_PERMISSION; 13393034Sdougm } 13403034Sdougm return (ret); 13413034Sdougm } 13423034Sdougm 13435951Sdougm 13443034Sdougm /* 13455951Sdougm * sa_end_transaction(scfhandle, sahandle) 13463034Sdougm * 13473034Sdougm * Commit the changes that were added to the transaction in the 13483034Sdougm * handle. Do all necessary cleanup. 13493034Sdougm */ 13503034Sdougm 13513034Sdougm int 13525951Sdougm sa_end_transaction(scfutilhandle_t *handle, sa_handle_impl_t sahandle) 13533034Sdougm { 13543034Sdougm int ret = SA_OK; 13553034Sdougm 13565951Sdougm if (handle == NULL || handle->trans == NULL || sahandle == NULL) { 13574653Sdougm ret = SA_SYSTEM_ERR; 13583034Sdougm } else { 13594653Sdougm if (scf_transaction_commit(handle->trans) < 0) 13604653Sdougm ret = SA_SYSTEM_ERR; 13614653Sdougm scf_transaction_destroy_children(handle->trans); 13624653Sdougm scf_transaction_destroy(handle->trans); 13635951Sdougm if (ret == SA_OK) 13645951Sdougm set_transaction_tstamp(sahandle); 13654653Sdougm handle->trans = NULL; 13663034Sdougm } 13673034Sdougm return (ret); 13683034Sdougm } 13693034Sdougm 13703034Sdougm /* 13713034Sdougm * sa_abort_transaction(handle) 13723034Sdougm * 13733034Sdougm * Abort the changes that were added to the transaction in the 13743034Sdougm * handle. Do all necessary cleanup. 13753034Sdougm */ 13763034Sdougm 13773034Sdougm void 13783034Sdougm sa_abort_transaction(scfutilhandle_t *handle) 13793034Sdougm { 13803034Sdougm if (handle->trans != NULL) { 13814653Sdougm scf_transaction_reset_all(handle->trans); 13824653Sdougm scf_transaction_destroy_children(handle->trans); 13834653Sdougm scf_transaction_destroy(handle->trans); 13844653Sdougm handle->trans = NULL; 13853034Sdougm } 13863034Sdougm } 13873034Sdougm 13883034Sdougm /* 13895951Sdougm * set_transaction_tstamp(sahandle) 13905951Sdougm * 13915951Sdougm * After a successful transaction commit, update the timestamp of the 13925951Sdougm * last transaction. This lets us detect changes from other processes. 13935951Sdougm */ 13945951Sdougm static void 13955951Sdougm set_transaction_tstamp(sa_handle_impl_t sahandle) 13965951Sdougm { 13975951Sdougm char tstring[32]; 13985951Sdougm struct timeval tv; 13995951Sdougm scfutilhandle_t *scfhandle; 14005951Sdougm 14015951Sdougm if (sahandle == NULL || sahandle->scfhandle == NULL) 14025951Sdougm return; 14035951Sdougm 14045951Sdougm scfhandle = sahandle->scfhandle; 14055951Sdougm 14065951Sdougm if (sa_get_instance(scfhandle, "default") != SA_OK) 14075951Sdougm return; 14085951Sdougm 14095951Sdougm if (gettimeofday(&tv, NULL) != 0) 14105951Sdougm return; 14115951Sdougm 14125951Sdougm if (sa_start_transaction(scfhandle, "*state") != SA_OK) 14135951Sdougm return; 14145951Sdougm 14155951Sdougm sahandle->tstrans = TSTAMP((*(timestruc_t *)&tv)); 14165951Sdougm (void) snprintf(tstring, sizeof (tstring), "%lld", sahandle->tstrans); 14175951Sdougm if (sa_set_property(sahandle->scfhandle, "lastupdate", tstring) == 14185951Sdougm SA_OK) { 14195951Sdougm /* 14205951Sdougm * While best if it succeeds, a failure doesn't cause 14215951Sdougm * problems and we will ignore it anyway. 14225951Sdougm */ 14235951Sdougm (void) scf_transaction_commit(scfhandle->trans); 14245951Sdougm scf_transaction_destroy_children(scfhandle->trans); 14255951Sdougm scf_transaction_destroy(scfhandle->trans); 14265951Sdougm } else { 14275951Sdougm sa_abort_transaction(scfhandle); 14285951Sdougm } 14295951Sdougm } 14305951Sdougm 14315951Sdougm /* 14323034Sdougm * sa_set_property(handle, prop, value) 14333034Sdougm * 14344653Sdougm * Set a property transaction entry into the pending SMF transaction. 14353034Sdougm */ 14363034Sdougm 14373034Sdougm int 14383034Sdougm sa_set_property(scfutilhandle_t *handle, char *propname, char *valstr) 14393034Sdougm { 14403034Sdougm int ret = SA_OK; 14413034Sdougm scf_value_t *value; 14423034Sdougm scf_transaction_entry_t *entry; 14433034Sdougm /* 14444653Sdougm * Properties must be set in transactions and don't take 14453034Sdougm * effect until the transaction has been ended/committed. 14463034Sdougm */ 14473034Sdougm value = scf_value_create(handle->handle); 14483034Sdougm entry = scf_entry_create(handle->handle); 14493034Sdougm if (value != NULL && entry != NULL) { 14504653Sdougm if (scf_transaction_property_change(handle->trans, entry, 14514653Sdougm propname, SCF_TYPE_ASTRING) == 0 || 14524653Sdougm scf_transaction_property_new(handle->trans, entry, 14534653Sdougm propname, SCF_TYPE_ASTRING) == 0) { 14544653Sdougm if (scf_value_set_astring(value, valstr) == 0) { 14554653Sdougm if (scf_entry_add_value(entry, value) != 0) { 14564653Sdougm ret = SA_SYSTEM_ERR; 14574653Sdougm scf_value_destroy(value); 14584653Sdougm } 14594653Sdougm /* The value is in the transaction */ 14604653Sdougm value = NULL; 14614653Sdougm } else { 14624653Sdougm /* Value couldn't be constructed */ 14634653Sdougm ret = SA_SYSTEM_ERR; 14644653Sdougm } 14654653Sdougm /* The entry is in the transaction */ 14664653Sdougm entry = NULL; 14674653Sdougm } else { 14683034Sdougm ret = SA_SYSTEM_ERR; 14693034Sdougm } 14704653Sdougm } else { 14713034Sdougm ret = SA_SYSTEM_ERR; 14723034Sdougm } 14733034Sdougm if (ret == SA_SYSTEM_ERR) { 14744653Sdougm switch (scf_error()) { 14754653Sdougm case SCF_ERROR_PERMISSION_DENIED: 14764653Sdougm ret = SA_NO_PERMISSION; 14774653Sdougm break; 14784653Sdougm } 14793034Sdougm } 14803034Sdougm /* 14814653Sdougm * Cleanup if there were any errors that didn't leave these 14823034Sdougm * values where they would be cleaned up later. 14833034Sdougm */ 14843034Sdougm if (value != NULL) 14854653Sdougm scf_value_destroy(value); 14863034Sdougm if (entry != NULL) 14874653Sdougm scf_entry_destroy(entry); 14883034Sdougm return (ret); 14893034Sdougm } 14903034Sdougm 14913034Sdougm /* 14925331Samw * check_resource(share) 14935331Samw * 14945331Samw * Check to see if share has any persistent resources. We don't want 14955331Samw * to save if they are all transient. 14965331Samw */ 14975331Samw static int 14985331Samw check_resource(sa_share_t share) 14995331Samw { 15005331Samw sa_resource_t resource; 15015331Samw int ret = B_FALSE; 15025331Samw 15035331Samw for (resource = sa_get_share_resource(share, NULL); 15045331Samw resource != NULL && ret == B_FALSE; 15055331Samw resource = sa_get_next_resource(resource)) { 15065331Samw char *type; 15075331Samw type = sa_get_resource_attr(resource, "type"); 15085331Samw if (type != NULL) { 15095331Samw if (strcmp(type, "transient") != 0) { 15105331Samw ret = B_TRUE; 15115331Samw } 15125331Samw sa_free_attr_string(type); 15135331Samw } 15145331Samw } 15155331Samw return (ret); 15165331Samw } 15175331Samw 15185331Samw /* 15195331Samw * sa_set_resource_property(handle, prop, value) 15205331Samw * 15215331Samw * set a property transaction entry into the pending SMF 15225331Samw * transaction. We don't want to include any transient resources 15235331Samw */ 15245331Samw 15255331Samw static int 15265331Samw sa_set_resource_property(scfutilhandle_t *handle, sa_share_t share) 15275331Samw { 15285331Samw int ret = SA_OK; 15295331Samw scf_value_t *value; 15305331Samw scf_transaction_entry_t *entry; 15315331Samw sa_resource_t resource; 15325331Samw char *valstr; 15335331Samw char *idstr; 15345331Samw char *description; 15355331Samw char *propstr = NULL; 15365331Samw size_t strsize; 15375331Samw 15385331Samw /* don't bother if no persistent resources */ 15395331Samw if (check_resource(share) == B_FALSE) 15405331Samw return (ret); 15415331Samw 15425331Samw /* 15435331Samw * properties must be set in transactions and don't take 15445331Samw * effect until the transaction has been ended/committed. 15455331Samw */ 15465331Samw entry = scf_entry_create(handle->handle); 15475331Samw if (entry == NULL) 15485331Samw return (SA_SYSTEM_ERR); 15495331Samw 15505331Samw if (scf_transaction_property_change(handle->trans, entry, 15515331Samw "resource", SCF_TYPE_ASTRING) != 0 && 15525331Samw scf_transaction_property_new(handle->trans, entry, 15535331Samw "resource", SCF_TYPE_ASTRING) != 0) { 15545331Samw scf_entry_destroy(entry); 15555331Samw return (SA_SYSTEM_ERR); 15565331Samw 15575331Samw } 15585331Samw for (resource = sa_get_share_resource(share, NULL); 15595331Samw resource != NULL; 15605331Samw resource = sa_get_next_resource(resource)) { 15615331Samw value = scf_value_create(handle->handle); 15625331Samw if (value == NULL) { 15635331Samw ret = SA_NO_MEMORY; 15645331Samw break; 15655331Samw } 15665331Samw /* Get size of complete string */ 15675331Samw valstr = sa_get_resource_attr(resource, "name"); 15685331Samw idstr = sa_get_resource_attr(resource, "id"); 15695331Samw description = sa_get_resource_description(resource); 15705331Samw strsize = (valstr != NULL) ? strlen(valstr) : 0; 15715331Samw strsize += (idstr != NULL) ? strlen(idstr) : 0; 15725331Samw strsize += (description != NULL) ? strlen(description) : 0; 15735331Samw if (strsize > 0) { 15745331Samw strsize += 3; /* add nul and ':' */ 15755331Samw propstr = (char *)malloc(strsize); 15765331Samw if (propstr == NULL) { 15775331Samw scf_value_destroy(value); 15785331Samw ret = SA_NO_MEMORY; 15795331Samw goto err; 15805331Samw } 15815331Samw if (idstr == NULL) 15825331Samw (void) snprintf(propstr, strsize, "%s", 15835331Samw valstr ? valstr : ""); 15845331Samw else 15855331Samw (void) snprintf(propstr, strsize, "%s:%s:%s", 1586*11337SWilliam.Krier@Sun.COM idstr, valstr ? valstr : "", 15875331Samw description ? description : ""); 15885331Samw if (scf_value_set_astring(value, propstr) != 0) { 15895331Samw ret = SA_SYSTEM_ERR; 15905331Samw free(propstr); 15915331Samw scf_value_destroy(value); 15925331Samw break; 15935331Samw } 15945331Samw if (scf_entry_add_value(entry, value) != 0) { 15955331Samw ret = SA_SYSTEM_ERR; 15965331Samw free(propstr); 15975331Samw scf_value_destroy(value); 15985331Samw break; 15995331Samw } 16005331Samw /* the value is in the transaction */ 16015331Samw value = NULL; 16025331Samw free(propstr); 16035331Samw } 16045331Samw err: 1605*11337SWilliam.Krier@Sun.COM if (valstr != NULL) { 16065331Samw sa_free_attr_string(valstr); 1607*11337SWilliam.Krier@Sun.COM valstr = NULL; 1608*11337SWilliam.Krier@Sun.COM } 1609*11337SWilliam.Krier@Sun.COM if (idstr != NULL) { 16105331Samw sa_free_attr_string(idstr); 1611*11337SWilliam.Krier@Sun.COM idstr = NULL; 1612*11337SWilliam.Krier@Sun.COM } 1613*11337SWilliam.Krier@Sun.COM if (description != NULL) { 16145331Samw sa_free_share_description(description); 1615*11337SWilliam.Krier@Sun.COM description = NULL; 1616*11337SWilliam.Krier@Sun.COM } 16175331Samw } 16185331Samw /* the entry is in the transaction */ 16195331Samw entry = NULL; 16205331Samw 1621*11337SWilliam.Krier@Sun.COM if (valstr != NULL) 1622*11337SWilliam.Krier@Sun.COM sa_free_attr_string(valstr); 1623*11337SWilliam.Krier@Sun.COM if (idstr != NULL) 1624*11337SWilliam.Krier@Sun.COM sa_free_attr_string(idstr); 1625*11337SWilliam.Krier@Sun.COM if (description != NULL) 1626*11337SWilliam.Krier@Sun.COM sa_free_share_description(description); 1627*11337SWilliam.Krier@Sun.COM 16285331Samw if (ret == SA_SYSTEM_ERR) { 16295331Samw switch (scf_error()) { 16305331Samw case SCF_ERROR_PERMISSION_DENIED: 16315331Samw ret = SA_NO_PERMISSION; 16325331Samw break; 16335331Samw } 16345331Samw } 16355331Samw /* 16365331Samw * cleanup if there were any errors that didn't leave 16375331Samw * these values where they would be cleaned up later. 16385331Samw */ 16395331Samw if (entry != NULL) 16405331Samw scf_entry_destroy(entry); 16415331Samw 16425331Samw return (ret); 16435331Samw } 16445331Samw 16455331Samw /* 16463034Sdougm * sa_commit_share(handle, group, share) 16473034Sdougm * 16484653Sdougm * Commit this share to the repository. 16493034Sdougm * properties are added if they exist but can be added later. 16503034Sdougm * Need to add to dfstab and sharetab, if appropriate. 16513034Sdougm */ 16523034Sdougm int 16533034Sdougm sa_commit_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share) 16543034Sdougm { 16553034Sdougm int ret = SA_OK; 16563034Sdougm char *groupname; 16573034Sdougm char *name; 16583034Sdougm char *description; 16593034Sdougm char *sharename; 16603034Sdougm ssize_t proplen; 16613034Sdougm char *propstring; 16623034Sdougm 16633034Sdougm /* 16644653Sdougm * Don't commit in the zfs group. We do commit legacy 16653034Sdougm * (default) and all other groups/shares. ZFS is handled 16663034Sdougm * through the ZFS configuration rather than SMF. 16673034Sdougm */ 16683034Sdougm 16693034Sdougm groupname = sa_get_group_attr(group, "name"); 16703034Sdougm if (groupname != NULL) { 16714653Sdougm if (strcmp(groupname, "zfs") == 0) { 16724653Sdougm /* 16734653Sdougm * Adding to the ZFS group will result in the sharenfs 16744653Sdougm * property being set but we don't want to do anything 16754653Sdougm * SMF related at this point. 16764653Sdougm */ 16774653Sdougm sa_free_attr_string(groupname); 16784653Sdougm return (ret); 16794653Sdougm } 16803034Sdougm } 16813034Sdougm 16823034Sdougm proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 16833034Sdougm propstring = malloc(proplen); 16843034Sdougm if (propstring == NULL) 16854653Sdougm ret = SA_NO_MEMORY; 16863034Sdougm 16873034Sdougm if (groupname != NULL && ret == SA_OK) { 16884653Sdougm ret = sa_get_instance(handle, groupname); 16894653Sdougm sa_free_attr_string(groupname); 16904653Sdougm groupname = NULL; 16914653Sdougm sharename = sa_get_share_attr(share, "id"); 16924653Sdougm if (sharename == NULL) { 16934653Sdougm /* slipped by */ 16944653Sdougm char shname[SA_SHARE_UUID_BUFLEN]; 16954653Sdougm generate_unique_sharename(shname); 16966012Sthurlow (void) xmlSetProp((xmlNodePtr)share, (xmlChar *)"id", 16973034Sdougm (xmlChar *)shname); 16984653Sdougm sharename = strdup(shname); 16993034Sdougm } 17004653Sdougm if (sharename != NULL) { 17014653Sdougm sigset_t old, new; 17024653Sdougm /* 17034653Sdougm * Have a share name allocated so create a pgroup for 17044653Sdougm * it. It may already exist, but that is OK. In order 17054653Sdougm * to avoid creating a share pgroup that doesn't have 17064653Sdougm * a path property, block signals around the critical 17074653Sdougm * region of creating the share pgroup and props. 17084653Sdougm */ 17094653Sdougm (void) sigprocmask(SIG_BLOCK, NULL, &new); 17104653Sdougm (void) sigaddset(&new, SIGHUP); 17114653Sdougm (void) sigaddset(&new, SIGINT); 17124653Sdougm (void) sigaddset(&new, SIGQUIT); 17134653Sdougm (void) sigaddset(&new, SIGTSTP); 17144653Sdougm (void) sigprocmask(SIG_SETMASK, &new, &old); 17154653Sdougm 17164653Sdougm ret = sa_create_pgroup(handle, sharename); 17174653Sdougm if (ret == SA_OK) { 17184653Sdougm /* 17194653Sdougm * Now start the transaction for the 17204653Sdougm * properties that define this share. They may 17214653Sdougm * exist so attempt to update before create. 17224653Sdougm */ 17234653Sdougm ret = sa_start_transaction(handle, sharename); 17244653Sdougm } 17254653Sdougm if (ret == SA_OK) { 17264653Sdougm name = sa_get_share_attr(share, "path"); 17274653Sdougm if (name != NULL) { 17284653Sdougm /* 17294653Sdougm * There needs to be a path 17304653Sdougm * for a share to exist. 17314653Sdougm */ 17324653Sdougm ret = sa_set_property(handle, "path", 17334653Sdougm name); 17344653Sdougm sa_free_attr_string(name); 17354653Sdougm } else { 17364653Sdougm ret = SA_NO_MEMORY; 17374653Sdougm } 17384653Sdougm } 17394653Sdougm if (ret == SA_OK) { 17405331Samw name = sa_get_share_attr(share, "drive-letter"); 17415331Samw if (name != NULL) { 17425331Samw /* A drive letter may exist for SMB */ 17434653Sdougm ret = sa_set_property(handle, 17445331Samw "drive-letter", name); 17455331Samw sa_free_attr_string(name); 17464653Sdougm } 17474653Sdougm } 17484653Sdougm if (ret == SA_OK) { 17495331Samw name = sa_get_share_attr(share, "exclude"); 17505331Samw if (name != NULL) { 17515331Samw /* 17525331Samw * In special cases need to 17535331Samw * exclude proto enable. 17545331Samw */ 17555331Samw ret = sa_set_property(handle, 17565331Samw "exclude", name); 17575331Samw sa_free_attr_string(name); 17585331Samw } 17595331Samw } 17605331Samw if (ret == SA_OK) { 17615331Samw /* 17625331Samw * If there are resource names, bundle them up 17635331Samw * and save appropriately. 17645331Samw */ 17655331Samw ret = sa_set_resource_property(handle, share); 17665331Samw } 17675331Samw 17685331Samw if (ret == SA_OK) { 17694653Sdougm description = sa_get_share_description(share); 17704653Sdougm if (description != NULL) { 17714653Sdougm ret = sa_set_property(handle, 17724653Sdougm "description", 17734653Sdougm description); 17744653Sdougm sa_free_share_description(description); 17754653Sdougm } 17764653Sdougm } 17774653Sdougm /* Make sure we cleanup the transaction */ 17784653Sdougm if (ret == SA_OK) { 17795951Sdougm sa_handle_impl_t sahandle; 17805951Sdougm sahandle = (sa_handle_impl_t) 17815951Sdougm sa_find_group_handle(group); 17825951Sdougm if (sahandle != NULL) 17835951Sdougm ret = sa_end_transaction(handle, 17845951Sdougm sahandle); 17855951Sdougm else 17865951Sdougm ret = SA_SYSTEM_ERR; 17874653Sdougm } else { 17884653Sdougm sa_abort_transaction(handle); 17894653Sdougm } 17904653Sdougm 17914653Sdougm (void) sigprocmask(SIG_SETMASK, &old, NULL); 17924653Sdougm 17934653Sdougm free(sharename); 17943034Sdougm } 17953034Sdougm } 17963034Sdougm if (ret == SA_SYSTEM_ERR) { 17974653Sdougm int err = scf_error(); 17984653Sdougm if (err == SCF_ERROR_PERMISSION_DENIED) 17994653Sdougm ret = SA_NO_PERMISSION; 18003034Sdougm } 18013034Sdougm if (propstring != NULL) 18024653Sdougm free(propstring); 18033034Sdougm if (groupname != NULL) 18044653Sdougm sa_free_attr_string(groupname); 18053034Sdougm 18063034Sdougm return (ret); 18073034Sdougm } 18083034Sdougm 18093034Sdougm /* 18105331Samw * remove_resources(handle, share, shareid) 18115331Samw * 18125331Samw * If the share has resources, remove all of them and their 18135331Samw * optionsets. 18145331Samw */ 18155331Samw static int 18165331Samw remove_resources(scfutilhandle_t *handle, sa_share_t share, char *shareid) 18175331Samw { 18185331Samw sa_resource_t resource; 18195331Samw sa_optionset_t opt; 18205331Samw char *proto; 18215331Samw char *id; 18225331Samw ssize_t proplen; 18235331Samw char *propstring; 18245331Samw int ret = SA_OK; 18255331Samw 18265331Samw proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 18275331Samw propstring = malloc(proplen); 18285331Samw if (propstring == NULL) 18295331Samw return (SA_NO_MEMORY); 18305331Samw 18315331Samw for (resource = sa_get_share_resource(share, NULL); 18325331Samw resource != NULL; resource = sa_get_next_resource(resource)) { 18335331Samw id = sa_get_resource_attr(resource, "id"); 18345331Samw if (id == NULL) 18355331Samw continue; 18365331Samw for (opt = sa_get_optionset(resource, NULL); 18375331Samw opt != NULL; opt = sa_get_next_optionset(resource)) { 18385331Samw proto = sa_get_optionset_attr(opt, "type"); 18395331Samw if (proto != NULL) { 18405331Samw (void) snprintf(propstring, proplen, 18415331Samw "%s_%s_%s", shareid, proto, id); 18425331Samw ret = sa_delete_pgroup(handle, propstring); 18435331Samw sa_free_attr_string(proto); 18445331Samw } 18455331Samw } 18465331Samw sa_free_attr_string(id); 18475331Samw } 18485331Samw free(propstring); 18495331Samw return (ret); 18505331Samw } 18515331Samw 18525331Samw /* 18533034Sdougm * sa_delete_share(handle, group, share) 18543034Sdougm * 18554653Sdougm * Remove the specified share from the group (and service instance). 18563034Sdougm */ 18573034Sdougm 18583034Sdougm int 18593034Sdougm sa_delete_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share) 18603034Sdougm { 18613034Sdougm int ret = SA_OK; 18623034Sdougm char *groupname = NULL; 18633034Sdougm char *shareid = NULL; 18643034Sdougm sa_optionset_t opt; 18653034Sdougm sa_security_t sec; 18663034Sdougm ssize_t proplen; 18673034Sdougm char *propstring; 18683034Sdougm 18693034Sdougm proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 18703034Sdougm propstring = malloc(proplen); 18713034Sdougm if (propstring == NULL) 18724653Sdougm ret = SA_NO_MEMORY; 18733034Sdougm 18743034Sdougm if (ret == SA_OK) { 18754653Sdougm groupname = sa_get_group_attr(group, "name"); 18764653Sdougm shareid = sa_get_share_attr(share, "id"); 18774653Sdougm if (groupname == NULL || shareid == NULL) { 18784653Sdougm ret = SA_CONFIG_ERR; 18794653Sdougm goto out; 18804653Sdougm } 18813034Sdougm ret = sa_get_instance(handle, groupname); 18823034Sdougm if (ret == SA_OK) { 18835331Samw /* If a share has resources, remove them */ 18845331Samw ret = remove_resources(handle, share, shareid); 18854653Sdougm /* If a share has properties, remove them */ 18864653Sdougm ret = sa_delete_pgroup(handle, shareid); 18874653Sdougm for (opt = sa_get_optionset(share, NULL); 18884653Sdougm opt != NULL; 18894653Sdougm opt = sa_get_next_optionset(opt)) { 18904653Sdougm char *proto; 18914653Sdougm proto = sa_get_optionset_attr(opt, "type"); 18924653Sdougm if (proto != NULL) { 18934653Sdougm (void) snprintf(propstring, 18944653Sdougm proplen, "%s_%s", shareid, 18954653Sdougm proto); 18964653Sdougm ret = sa_delete_pgroup(handle, 18974653Sdougm propstring); 18984653Sdougm sa_free_attr_string(proto); 18994653Sdougm } else { 19004653Sdougm ret = SA_NO_MEMORY; 19014653Sdougm } 19023034Sdougm } 19033034Sdougm /* 19044653Sdougm * If a share has security/negotiable 19053034Sdougm * properties, remove them. 19063034Sdougm */ 19074653Sdougm for (sec = sa_get_security(share, NULL, NULL); 19084653Sdougm sec != NULL; 19094653Sdougm sec = sa_get_next_security(sec)) { 19104653Sdougm char *proto; 19114653Sdougm char *sectype; 19124653Sdougm proto = sa_get_security_attr(sec, "type"); 19134653Sdougm sectype = sa_get_security_attr(sec, "sectype"); 19144653Sdougm if (proto != NULL && sectype != NULL) { 19154653Sdougm (void) snprintf(propstring, proplen, 19164653Sdougm "%s_%s_%s", shareid, proto, 19174653Sdougm sectype); 19184653Sdougm ret = sa_delete_pgroup(handle, 19194653Sdougm propstring); 19204653Sdougm } else { 19214653Sdougm ret = SA_NO_MEMORY; 19224653Sdougm } 19234653Sdougm if (proto != NULL) 19244653Sdougm sa_free_attr_string(proto); 19254653Sdougm if (sectype != NULL) 19264653Sdougm sa_free_attr_string(sectype); 19273034Sdougm } 19283034Sdougm } 19293034Sdougm } 19304653Sdougm out: 19313034Sdougm if (groupname != NULL) 19324653Sdougm sa_free_attr_string(groupname); 19333034Sdougm if (shareid != NULL) 19344653Sdougm sa_free_attr_string(shareid); 19353034Sdougm if (propstring != NULL) 19364653Sdougm free(propstring); 19373034Sdougm 19383034Sdougm return (ret); 19393034Sdougm } 1940