/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2012 Milan Jurik. All rights reserved. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * This file's functions are responsible for all store and retrieve operations * against the STMF smf(5) database. The following shows the currently defined * schema for the STMF database: * * Description of property groups for service: svc:/system/stmf * * Stability: Volatile * * 1. Property Group: host_groups * Properties: group_name- where is an unsigned integer * type: ustring * contains: group name * group_name--member_list where is an unsigned * integer matching a group_name- property. * type: ustring * contains: list of members * * Description: * Contains the host group names as well as the host group members * for each host group. * * 2. Property Group: target_groups * Properties: group_name- where is an unsigned integer * type: ustring * contains: group name * group_name--member_list where is an unsigned * integer matching a group_name- property. * type: ustring * contains: list of members * * Description: * Contains the target group names as well as the target group * members for each target group. * * 3. Property Group: lu- * where is a 32 character hexadecimal string. * Properties: ve_cnt * type: count * contains: the number of current view entries * view-entry-- where is an unsigned integer * type: ustring * contains: nothing. Used as reference to the view * entry property group * * Description: * Contains the references to each view entry. One lu- * property group will exist for each logical unit with 1 or more * view entries. * Potentially can hold any other data that can be managed on a per * logical unit basis. * * 4. Property Group: view_entry-- (matches property in lu- * property group) * Properties: all_hosts * type: boolean * contains: when true, the value of host_group is * ignored * all_targets * type: boolean * contains: when true, the value of target_group is * ignored * host_group * type: ustring * contains: host group for logical unit mapping and * masking purposes * target_group * type: ustring * contains: target group for logical unit mapping and * masking purposes * lu_nbr * type: opaque * contains: the 8-byte SCSI logical unit number for * mapping and masking purposes * Description: * One "view_entry--" property group will exist for each * view entry in the system. This property group name maps * directly to the "lu-" property group with a matching * . * * 5. Property Group: provider_data_pg_ * where is the name of the provider * registered with stmf. * Properties: provider_data_prop- * where is a sequential identifier for the data * chunk. * type: opaque * contains: up to STMF_PROVIDER_DATA_PROP_SIZE bytes * of nvlist packed data. * provider_data_count * type: count * contains: the number of provider data chunks * provider_data_type * type: integer * contains: STMF_PORT_PROVIDER_TYPE or * STMF_LU_PROVIDER_TYPE * * Description: * Holds the nvlist packed provider data set via * stmfSetProviderData and retrieved via stmfGetProviderData. Data * is stored in STMF_PROVIDER_DATA_PROP_SIZE chunks. On retrieve, * these chunks are reassembled and unpacked. * */ static int iPsInit(scf_handle_t **, scf_service_t **); static int iPsCreateDeleteGroup(char *, char *, int); static int iPsAddRemoveGroupMember(char *, char *, char *, int); static int iPsGetGroupList(char *, stmfGroupList **); static int iPsGetGroupMemberList(char *, char *, stmfGroupProperties **); static int iPsAddViewEntry(char *, char *, stmfViewEntry *); static int iPsAddRemoveLuViewEntry(char *, char *, int); static int iPsGetViewEntry(char *, stmfViewEntry *); static int iPsGetActualGroupName(char *, char *, char *); static int iPsGetServiceVersion(uint64_t *, scf_handle_t *, scf_service_t *); static int iPsGetSetPersistType(uint8_t *, scf_handle_t *, scf_service_t *, int); static int iPsGetSetStmfProp(int, char *, int); static int viewEntryCompare(const void *, const void *); static int holdSignal(sigset_t *); static int releaseSignal(sigset_t *); static void sigHandler(); static pthread_mutex_t sigSetLock = PTHREAD_MUTEX_INITIALIZER; sigset_t sigSet; sigset_t signalsCaught; struct sigaction currentActionQuit; struct sigaction currentActionTerm; struct sigaction currentActionInt; boolean_t actionSet = B_FALSE; /* * Version info for the SMF schema */ #define STMF_SMF_VERSION 1 /* * Note: Do not change these property names and size values. * They represent fields in the persistent config and once modified * will have a nasty side effect of invalidating the existing store. * If you do need to change them, you'll need to use the versioning above * to retain backward compatiblity with the previous configuration schema. */ /* BEGIN STORE PROPERTY DEFINITIONS */ /* * Property Group Names and prefixes */ #define STMF_HOST_GROUPS "host_groups" #define STMF_TARGET_GROUPS "target_groups" #define STMF_VE_PREFIX "view_entry" #define STMF_LU_PREFIX "lu" #define STMF_DATA_GROUP "stmf_data" /* * Property names and prefix for logical unit property group */ #define STMF_VE_CNT "ve_cnt" #define STMF_GROUP_PREFIX "group_name" #define STMF_MEMBER_LIST_SUFFIX "member_list" #define STMF_VERSION_NAME "version_name" #define STMF_PERSIST_TYPE "persist_method" /* Property names for stmf properties */ #define DEFAULT_LU_STATE "default_lu_state" #define DEFAULT_TARGET_PORT_STATE "default_target_state" /* * Property names for view entry */ #define STMF_VE_ALLHOSTS "all_hosts" #define STMF_VE_HOSTGROUP "host_group" #define STMF_VE_ALLTARGETS "all_targets" #define STMF_VE_TARGETGROUP "target_group" #define STMF_VE_LUNBR "lu_nbr" /* Property group suffix for provider data */ #define STMF_PROVIDER_DATA_PREFIX "provider_data_pg_" #define STMF_PROVIDER_DATA_PROP_PREFIX "provider_data_prop" #define STMF_PROVIDER_DATA_PROP_NAME_SIZE 256 #define STMF_PROVIDER_DATA_PROP_TYPE "provider_type" #define STMF_PROVIDER_DATA_PROP_SET_COUNT "provider_data_set_cnt" #define STMF_PROVIDER_DATA_PROP_COUNT "provider_data_cnt" #define STMF_SMF_READ_ATTR "solaris.smf.read.stmf" #define STMF_PS_PERSIST_NONE "none" #define STMF_PS_PERSIST_SMF "smf" #define STMF_PROVIDER_DATA_PROP_SIZE 4000 #define STMF_PS_LU_ONLINE "default_lu_online" #define STMF_PS_LU_OFFLINE "default_lu_offline" #define STMF_PS_TARGET_PORT_ONLINE "default_target_online" #define STMF_PS_TARGET_PORT_OFFLINE "default_target_offline" /* END STORE PROPERTY DEFINITIONS */ /* service name */ #define STMF_SERVICE "system/stmf" /* limits and flag values */ #define GROUP_MEMBER_ALLOC 100 #define VIEW_ENTRY_STRUCT_CNT 6 #define VIEW_ENTRY_PG_SIZE 256 #define LOGICAL_UNIT_PG_SIZE 256 #define VIEW_ENTRY_MAX UINT32_MAX #define GROUP_MAX UINT64_MAX #define ADD 0 #define REMOVE 1 #define GET 0 #define SET 1 /* * sigHandler * * Catch the signal and set the global signalsCaught to the signal received * * signalsCaught will be used by releaseSignal to raise this signal when * we're done processing our critical code. * */ static void sigHandler(int sig) { (void) sigaddset(&signalsCaught, sig); } /* * iPsAddRemoveGroupMember * * Add or remove a member for a given group * * pgName - Property group name * groupName - group name to which the member is added/removed * memberName - member to be added/removed * addRemoveFlag - ADD/REMOVE * * returns: * STMF_PS_SUCCESS on success * STMF_PS_ERROR_* on failure */ static int iPsAddRemoveGroupMember(char *pgName, char *groupName, char *memberName, int addRemoveFlag) { scf_handle_t *handle = NULL; scf_service_t *svc = NULL; scf_propertygroup_t *pg = NULL; scf_property_t *prop = NULL; scf_value_t *valueLookup = NULL; scf_value_t **valueSet = NULL; scf_iter_t *valueIter = NULL; scf_transaction_t *tran = NULL; scf_transaction_entry_t *entry = NULL; int i = 0; int lastAlloc; int valueArraySize = 0; int ret = STMF_PS_SUCCESS; char buf[STMF_IDENT_LENGTH]; int commitRet; boolean_t found = B_FALSE; assert(pgName != NULL && groupName != NULL && memberName != NULL); /* * Init the service handle */ ret = iPsInit(&handle, &svc); if (ret != STMF_PS_SUCCESS) { goto out; } /* * Allocate scf resources */ if (((pg = scf_pg_create(handle)) == NULL) || ((tran = scf_transaction_create(handle)) == NULL) || ((entry = scf_entry_create(handle)) == NULL) || ((prop = scf_property_create(handle)) == NULL) || ((valueIter = scf_iter_create(handle)) == NULL)) { syslog(LOG_ERR, "scf alloc resource failed - %s", scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* * Get the service property group handle */ if (scf_service_get_pg(svc, pgName, pg) == -1) { if (scf_error() == SCF_ERROR_NOT_FOUND) { ret = STMF_PS_ERROR_NOT_FOUND; } else { ret = STMF_PS_ERROR; } syslog(LOG_ERR, "get pg %s failed - %s", pgName, scf_strerror(scf_error())); goto out; } /* * Begin the transaction */ if (scf_transaction_start(tran, pg) == -1) { syslog(LOG_ERR, "start transaction for %s failed - %s", pgName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* * We're changing an existing property by adding a propval * There are no add semantics in libscf for a property value. We'll * need to read in the current properties and apply them all to the * set and then add the one we were asked to add or omit the one * we were asked to remove. */ if (scf_transaction_property_change(tran, entry, groupName, SCF_TYPE_USTRING) == -1) { if (scf_error() == SCF_ERROR_NOT_FOUND) { ret = STMF_PS_ERROR_GROUP_NOT_FOUND; } else { ret = STMF_PS_ERROR; syslog(LOG_ERR, "tran property change %s/%s " "failed - %s", pgName, groupName, scf_strerror(scf_error())); } goto out; } /* * Get the property handle */ if (scf_pg_get_property(pg, groupName, prop) == -1) { syslog(LOG_ERR, "get property %s/%s failed - %s", pgName, groupName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* * Value lookup is used to lookup the existing values */ valueLookup = scf_value_create(handle); if (valueLookup == NULL) { syslog(LOG_ERR, "scf value alloc for %s failed - %s", pgName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* * valueIter is the iterator handle, create the resource */ if (scf_iter_property_values(valueIter, prop) == -1) { syslog(LOG_ERR, "iter values for %s/%s failed - %s", pgName, groupName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* * Allocate value resource pointers. * We need a value resource for each value as value pointers passed * to libscf cannot be destroyed until the commit or destroy on the * transaction is done. * * We're using GROUP_MEMBER_ALLOC initially. If it's not large * enough, we'll realloc on the fly */ valueSet = (scf_value_t **)calloc(1, sizeof (*valueSet) * (lastAlloc = GROUP_MEMBER_ALLOC)); if (valueSet == NULL) { ret = STMF_PS_ERROR_NOMEM; goto out; } /* * Iterate through the existing values */ while (scf_iter_next_value(valueIter, valueLookup) == 1) { bzero(buf, sizeof (buf)); if (scf_value_get_ustring(valueLookup, buf, MAXNAMELEN) == -1) { syslog(LOG_ERR, "iter %s/%s value failed - %s", pgName, groupName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; break; } /* * Check for existing * If we're adding, it's an error * If we're removing, we skip it and simply not * add it to the set. Subtraction by omission. */ if ((strlen(buf) == strlen(memberName)) && bcmp(buf, memberName, strlen(buf)) == 0) { if (addRemoveFlag == ADD) { ret = STMF_PS_ERROR_EXISTS; break; } else { found = B_TRUE; continue; } } /* * Create the value resource for this iteration */ valueSet[i] = scf_value_create(handle); if (valueSet[i] == NULL) { syslog(LOG_ERR, "scf value alloc for %s failed - %s", pgName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; break; } /* * Set the value */ if (scf_value_set_ustring(valueSet[i], buf) == -1) { syslog(LOG_ERR, "set value for %s/%s failed - %s", pgName, groupName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; break; } /* * Now add the value */ if (scf_entry_add_value(entry, valueSet[i]) == -1) { syslog(LOG_ERR, "add value for %s/%s failed - %s", pgName, groupName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; break; } i++; /* * realloc if we've hit the previous alloc size */ if (i >= lastAlloc) { lastAlloc += GROUP_MEMBER_ALLOC; valueSet = realloc(valueSet, sizeof (*valueSet) * lastAlloc); if (valueSet == NULL) { ret = STMF_PS_ERROR; break; } } } /* * set valueArraySize to final allocated length * so we can use it to destroy the resources correctly */ valueArraySize = i; if (!found && (addRemoveFlag == REMOVE)) { ret = STMF_PS_ERROR_MEMBER_NOT_FOUND; } if (ret != STMF_PS_SUCCESS) { goto out; } /* * If we're adding, we have one more step. Add the member to the * propval list */ if (addRemoveFlag == ADD) { /* * Now create the new entry */ valueSet[i] = scf_value_create(handle); if (valueSet[i] == NULL) { syslog(LOG_ERR, "scf value alloc for %s/%s failed - %s", pgName, groupName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } else { valueArraySize++; } /* * Set the new member name */ if (scf_value_set_ustring(valueSet[i], memberName) == -1) { syslog(LOG_ERR, "set value for %s/%s failed - %s", pgName, groupName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* * Add the new member */ if (scf_entry_add_value(entry, valueSet[i]) == -1) { syslog(LOG_ERR, "add value for %s/%s failed - %s", pgName, groupName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } } /* * Yes, we're finally done. We actually added or removed one entry * from the list. * Woohoo! */ if ((commitRet = scf_transaction_commit(tran)) != 1) { syslog(LOG_ERR, "transaction commit for %s failed - %s", pgName, scf_strerror(scf_error())); if (commitRet == 0) { ret = STMF_PS_ERROR_BUSY; } else { ret = STMF_PS_ERROR; } goto out; } out: /* * Free resources */ if (handle != NULL) { scf_handle_destroy(handle); } if (svc != NULL) { scf_service_destroy(svc); } if (pg != NULL) { scf_pg_destroy(pg); } if (tran != NULL) { scf_transaction_destroy(tran); } if (entry != NULL) { scf_entry_destroy(entry); } if (prop != NULL) { scf_property_destroy(prop); } if (valueLookup != NULL) { scf_value_destroy(valueLookup); } if (valueIter != NULL) { scf_iter_destroy(valueIter); } /* * Free valueSet scf resources */ if (valueArraySize > 0) { for (i = 0; i < valueArraySize; i++) { scf_value_destroy(valueSet[i]); } } /* * Now free the pointer array to the resources */ if (valueSet != NULL) { free(valueSet); } return (ret); } /* * iPsAddRemoveLuViewEntry * * Adds or removes a view entry name property for a given logical unit * property group. There is one logical unit property group for every logical * unit that has one or more associated view entries. * * luPgName - Property group name of logical unit * viewEntryPgName - Property group name of view entry * addRemoveFlag - ADD_VE/REMOVE_VE * * returns: * STMF_PS_SUCCESS on success * STMF_PS_ERROR_* on failure */ static int iPsAddRemoveLuViewEntry(char *luPgName, char *viewEntryPgName, int addRemoveFlag) { scf_handle_t *handle = NULL; scf_service_t *svc = NULL; scf_propertygroup_t *pg = NULL; scf_property_t *prop = NULL; scf_value_t *value = NULL; scf_transaction_t *tran = NULL; scf_transaction_entry_t *entry = NULL; scf_transaction_entry_t *entryVeName = NULL; boolean_t createVeCnt = B_FALSE; uint64_t veCnt = 0; int ret = STMF_PS_SUCCESS; int commitRet; assert(luPgName != NULL || viewEntryPgName != NULL); assert(!(addRemoveFlag != ADD && addRemoveFlag != REMOVE)); /* * Init the service handle */ ret = iPsInit(&handle, &svc); if (ret != STMF_PS_SUCCESS) { goto out; } /* * Allocate scf resources */ if (((pg = scf_pg_create(handle)) == NULL) || ((tran = scf_transaction_create(handle)) == NULL) || ((entry = scf_entry_create(handle)) == NULL) || ((prop = scf_property_create(handle)) == NULL) || ((value = scf_value_create(handle)) == NULL)) { syslog(LOG_ERR, "scf alloc resource failed - %s", scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* get the LU property group */ if (scf_service_get_pg(svc, luPgName, pg) == -1) { if (scf_error() == SCF_ERROR_NOT_FOUND && addRemoveFlag == ADD) { /* if it doesn't exist, create it */ if (scf_service_add_pg(svc, luPgName, SCF_GROUP_APPLICATION, 0, pg) == -1) { syslog(LOG_ERR, "add pg %s failed - %s", luPgName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; } else { /* we need to create the VE_CNT property */ createVeCnt = B_TRUE; ret = STMF_PS_SUCCESS; } } else if (scf_error() == SCF_ERROR_NOT_FOUND) { ret = STMF_PS_ERROR_NOT_FOUND; } else { syslog(LOG_ERR, "get lu pg %s failed - %s", luPgName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; } if (ret != STMF_PS_SUCCESS) { goto out; } } /* * Begin the transaction */ if (scf_transaction_start(tran, pg) == -1) { syslog(LOG_ERR, "start transaction for %s failed - %s", luPgName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } if (createVeCnt) { /* * Create the STMF_VE_CNT property. This will keep the current * total view entries for this logical unit. */ if (scf_transaction_property_new(tran, entry, STMF_VE_CNT, SCF_TYPE_COUNT) == -1) { if (scf_error() == SCF_ERROR_EXISTS) { ret = STMF_PS_ERROR_EXISTS; } else { syslog(LOG_ERR, "transaction property new %s/%s " "failed - %s", luPgName, STMF_VE_CNT, scf_strerror(scf_error())); ret = STMF_PS_ERROR; } goto out; } } else { /* * The STMF_VE_CNT property already exists. Just update * it. */ if (scf_transaction_property_change(tran, entry, STMF_VE_CNT, SCF_TYPE_COUNT) == -1) { syslog(LOG_ERR, "transaction property %s/%s change " "failed - %s", luPgName, STMF_VE_CNT, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* * Get the STMF_VE_CNT property */ if (scf_pg_get_property(pg, STMF_VE_CNT, prop) == -1) { syslog(LOG_ERR, "get property %s/%s failed - %s", luPgName, STMF_VE_CNT, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* * Get the STMF_VE_CNT value */ if (scf_property_get_value(prop, value) == -1) { syslog(LOG_ERR, "get property %s/%s value failed - %s", luPgName, STMF_VE_CNT, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* * Now get the actual value from the value handle */ if (scf_value_get_count(value, &veCnt) == -1) { syslog(LOG_ERR, "get count value %s/%s failed - %s", luPgName, STMF_VE_CNT, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* * Reset the value resource as it is used below */ scf_value_reset(value); } if (addRemoveFlag == ADD) { veCnt++; } else { /* Check if this is the last one being removed */ if (veCnt == 1) { /* * Delete the pg and get out if this is the last * view entry */ if (scf_pg_delete(pg) == -1) { syslog(LOG_ERR, "delete pg %s failed - %s", luPgName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; } goto out; } else { veCnt--; } } /* * Set the view entry count */ scf_value_set_count(value, veCnt); /* * Add the value to the transaction entry */ if (scf_entry_add_value(entry, value) == -1) { syslog(LOG_ERR, "add value %s/%s failed - %s", luPgName, STMF_VE_CNT, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* * Create a transaction entry resource for the view entry name */ entryVeName = scf_entry_create(handle); if (entryVeName == NULL) { syslog(LOG_ERR, "scf transaction entry alloc %s/%s failed - %s", luPgName, viewEntryPgName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } if (addRemoveFlag == ADD) { /* * If adding, create a property with the view entry name */ if (scf_transaction_property_new(tran, entryVeName, viewEntryPgName, SCF_TYPE_USTRING) == -1) { if (scf_error() == SCF_ERROR_EXISTS) { ret = STMF_PS_ERROR_EXISTS; } else { syslog(LOG_ERR, "transaction property new %s/%s " "failed - %s", luPgName, viewEntryPgName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; } goto out; } } else { /* * If removing, delete the existing property with the view * entry name */ if (scf_transaction_property_delete(tran, entryVeName, viewEntryPgName) == -1) { if (scf_error() == SCF_ERROR_NOT_FOUND) { ret = STMF_PS_ERROR_NOT_FOUND; } else { syslog(LOG_ERR, "transaction property delete %s/%s " "failed - %s", luPgName, viewEntryPgName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; } goto out; } } /* * Commit property transaction */ if ((commitRet = scf_transaction_commit(tran)) != 1) { syslog(LOG_ERR, "transaction commit for %s failed - %s", luPgName, scf_strerror(scf_error())); if (commitRet == 0) { ret = STMF_PS_ERROR_BUSY; } else { ret = STMF_PS_ERROR; } goto out; } out: /* * Free resources */ if (handle != NULL) { scf_handle_destroy(handle); } if (svc != NULL) { scf_service_destroy(svc); } if (pg != NULL) { scf_pg_destroy(pg); } if (tran != NULL) { scf_transaction_destroy(tran); } if (entry != NULL) { scf_entry_destroy(entry); } if (entryVeName != NULL) { scf_entry_destroy(entryVeName); } if (prop != NULL) { scf_property_destroy(prop); } if (value != NULL) { scf_value_destroy(value); } return (ret); } /* * iPsAddViewEntry * * Add a view entry property group and optionally, a logical unit property * group if it does not exist. * * luName - ascii hexadecimal logical unit identifier * viewEntryName - name of view entry (VIEW_ENTRY_nn) * viewEntry - pointer to stmfViewEntry structure */ static int iPsAddViewEntry(char *luPgName, char *viewEntryPgName, stmfViewEntry *viewEntry) { scf_handle_t *handle = NULL; scf_service_t *svc = NULL; scf_propertygroup_t *pg = NULL; scf_value_t *value[VIEW_ENTRY_STRUCT_CNT]; scf_transaction_t *tran = NULL; scf_transaction_entry_t *entry[VIEW_ENTRY_STRUCT_CNT]; int i = 0; int j = 0; int ret; uint8_t scfBool; boolean_t createdVePg = B_FALSE; int backoutRet; int commitRet; assert(luPgName != NULL || viewEntryPgName != NULL || viewEntry == NULL); bzero(value, sizeof (value)); bzero(entry, sizeof (entry)); /* * Init the service handle */ ret = iPsInit(&handle, &svc); if (ret != STMF_PS_SUCCESS) { goto out; } /* * Allocate scf resources */ if (((pg = scf_pg_create(handle)) == NULL) || ((tran = scf_transaction_create(handle)) == NULL)) { syslog(LOG_ERR, "scf alloc resource failed - %s", scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* * allocate value and entry resources for scf */ for (i = 0; i < VIEW_ENTRY_STRUCT_CNT; i++) { if (((value[i] = scf_value_create(handle)) == NULL) || ((entry[i] = scf_entry_create(handle)) == NULL)) { syslog(LOG_ERR, "scf alloc resource failed - %s", scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } } i = 0; /* * Create the View Entry property group */ if (scf_service_add_pg(svc, viewEntryPgName, SCF_GROUP_APPLICATION, 0, pg) == -1) { if (scf_error() == SCF_ERROR_EXISTS) { ret = STMF_PS_ERROR_EXISTS; } else { syslog(LOG_ERR, "add pg %s failed - %s", viewEntryPgName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; } goto out; } createdVePg = B_TRUE; /* * Add the view entry as properties on the view entry group */ /* * Begin property update transaction */ if (scf_transaction_start(tran, pg) == -1) { syslog(LOG_ERR, "start transaction for add %s failed - %s", viewEntryPgName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* * Add allHosts property */ if (scf_transaction_property_new(tran, entry[i], STMF_VE_ALLHOSTS, SCF_TYPE_BOOLEAN) == -1) { if (scf_error() == SCF_ERROR_EXISTS) { ret = STMF_PS_ERROR_EXISTS; } else { syslog(LOG_ERR, "transaction property new %s/%s " "failed - %s", viewEntryPgName, STMF_VE_ALLHOSTS, scf_strerror(scf_error())); ret = STMF_PS_ERROR; } goto out; } /* Set the allHosts value */ scfBool = viewEntry->allHosts; scf_value_set_boolean(value[i], scfBool); /* * Add the allHosts value to the transaction */ if (scf_entry_add_value(entry[i], value[i]) == -1) { syslog(LOG_ERR, "add value %s/%s failed - %s", viewEntryPgName, STMF_VE_ALLHOSTS, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } i++; /* * Create hostGroup property */ if (scf_transaction_property_new(tran, entry[i], STMF_VE_HOSTGROUP, SCF_TYPE_USTRING) == -1) { if (scf_error() == SCF_ERROR_EXISTS) { ret = STMF_PS_ERROR_EXISTS; } else { syslog(LOG_ERR, "transaction property new %s/%s " "failed - %s", viewEntryPgName, STMF_VE_HOSTGROUP, scf_strerror(scf_error())); ret = STMF_PS_ERROR; } goto out; } /* * Set the value for hostGroup */ if (scf_value_set_ustring(value[i], viewEntry->hostGroup) == -1) { syslog(LOG_ERR, "set value %s/%s failed - %s", viewEntryPgName, STMF_VE_HOSTGROUP, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* * Add the hostGroup value to the transaction entry */ if (scf_entry_add_value(entry[i], value[i]) == -1) { syslog(LOG_ERR, "add value %s/%s failed - %s", viewEntryPgName, STMF_VE_HOSTGROUP, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } i++; /* * Create the allTargets property */ if (scf_transaction_property_new(tran, entry[i], STMF_VE_ALLTARGETS, SCF_TYPE_BOOLEAN) == -1) { if (scf_error() == SCF_ERROR_EXISTS) { ret = STMF_PS_ERROR_EXISTS; } else { syslog(LOG_ERR, "transaction property new %s/%s " "failed - %s", viewEntryPgName, STMF_VE_ALLTARGETS, scf_strerror(scf_error())); ret = STMF_PS_ERROR; } goto out; } /* * Set the allTargets value */ scfBool = viewEntry->allTargets; scf_value_set_boolean(value[i], scfBool); /* * Add the allTargets value to the transaction */ if (scf_entry_add_value(entry[i], value[i]) == -1) { syslog(LOG_ERR, "add value %s/%s failed - %s", viewEntryPgName, STMF_VE_ALLTARGETS, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } i++; /* * Create targetGroup property */ if (scf_transaction_property_new(tran, entry[i], STMF_VE_TARGETGROUP, SCF_TYPE_USTRING) == -1) { if (scf_error() == SCF_ERROR_EXISTS) { ret = STMF_PS_ERROR_EXISTS; } else { syslog(LOG_ERR, "transaction property new %s/%s " "failed - %s", viewEntryPgName, STMF_VE_TARGETGROUP, scf_strerror(scf_error())); ret = STMF_PS_ERROR; } goto out; } /* * Set the value for targetGroup */ if (scf_value_set_ustring(value[i], viewEntry->targetGroup) == -1) { syslog(LOG_ERR, "set value %s/%s failed - %s", viewEntryPgName, STMF_VE_TARGETGROUP, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* * Add targetGroup value to the transaction */ if (scf_entry_add_value(entry[i], value[i]) == -1) { syslog(LOG_ERR, "add value %s/%s failed - %s", viewEntryPgName, STMF_VE_TARGETGROUP, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } i++; /* * Create the luNbr property */ if (scf_transaction_property_new(tran, entry[i], STMF_VE_LUNBR, SCF_TYPE_OPAQUE) == -1) { if (scf_error() == SCF_ERROR_EXISTS) { ret = STMF_PS_ERROR_EXISTS; } else { syslog(LOG_ERR, "transaction property new %s/%s " "failed - %s", viewEntryPgName, STMF_VE_LUNBR, scf_strerror(scf_error())); ret = STMF_PS_ERROR; } goto out; } /* * Set the luNbr */ if (scf_value_set_opaque(value[i], (char *)viewEntry->luNbr, sizeof (viewEntry->luNbr)) == -1) { syslog(LOG_ERR, "set value %s/%s failed - %s", viewEntryPgName, STMF_VE_LUNBR, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* * Add luNbr to the transaction entry */ if (scf_entry_add_value(entry[i], value[i]) == -1) { syslog(LOG_ERR, "add value %s/%s failed - %s", viewEntryPgName, STMF_VE_LUNBR, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* * Now that we've successfully added the view entry, * update the logical unit property group or create * it if it does not exist */ ret = iPsAddRemoveLuViewEntry(luPgName, viewEntryPgName, ADD); /* * If we did not add the view entry name to the logical unit, * make sure we do not commit the transaction */ if (ret != STMF_PS_SUCCESS) { goto out; } /* * Commit property transaction */ if ((commitRet = scf_transaction_commit(tran)) != 1) { syslog(LOG_ERR, "transaction commit for add %s failed - %s", viewEntryPgName, scf_strerror(scf_error())); if (commitRet == 0) { ret = STMF_PS_ERROR_BUSY; } else { ret = STMF_PS_ERROR; } } if (ret != STMF_PS_SUCCESS) { /* * If we did not commit, try to remove the view entry name * from the logical unit. * If that fails, we're now inconsistent. */ backoutRet = iPsAddRemoveLuViewEntry(luPgName, viewEntryPgName, REMOVE); if (backoutRet != STMF_PS_SUCCESS) { syslog(LOG_ERR, "remove lu view entry %s failed" "possible inconsistency - %s", luPgName, scf_strerror(scf_error())); } /* * We are still in an error scenario even though the remove * lu view entry succeeded. */ goto out; } out: /* * Free resources */ if (handle != NULL) { scf_handle_destroy(handle); } if (svc != NULL) { scf_service_destroy(svc); } /* if there was an error, delete the created pg if one was created */ if ((ret != STMF_PS_SUCCESS) && createdVePg) { if (scf_pg_delete(pg) == -1) { syslog(LOG_ERR, "delete VE pg %s failed - %s", viewEntryPgName, scf_strerror(scf_error())); } } if (pg != NULL) { scf_pg_destroy(pg); } if (tran != NULL) { scf_transaction_destroy(tran); } /* * Free value and entry scf resources */ if (i > 0) { for (j = 0; j < VIEW_ENTRY_STRUCT_CNT; j++) { if (value[j] != NULL) scf_value_destroy(value[j]); if (entry[j] != NULL) scf_entry_destroy(entry[j]); } } return (ret); } /* * psClearProviderData * * providerName - name of provider data to clear */ int psClearProviderData(char *providerName, int providerType) { scf_handle_t *handle = NULL; scf_service_t *svc = NULL; scf_propertygroup_t *pg = NULL; char pgName[MAXPATHLEN]; int ret = STMF_PS_SUCCESS; boolean_t pgNotFound = B_FALSE; if (providerName == NULL || (providerType != STMF_LU_PROVIDER_TYPE && providerType != STMF_PORT_PROVIDER_TYPE)) { ret = STMF_PS_ERROR_INVALID_ARG; goto out; } ret = iPsInit(&handle, &svc); if (ret != STMF_PS_SUCCESS) { goto out; } /* * Allocate scf resources */ if ((pg = scf_pg_create(handle)) == NULL) { syslog(LOG_ERR, "scf alloc resource failed - %s", scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* * create the property group name */ (void) snprintf(pgName, sizeof (pgName), "%s%s", STMF_PROVIDER_DATA_PREFIX, providerName); /* * delete provider property group */ if (scf_service_get_pg(svc, pgName, pg) == -1) { if (scf_error() != SCF_ERROR_NOT_FOUND) { syslog(LOG_ERR, "get pg %s failed - %s", pgName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } else { pgNotFound = B_TRUE; } } if (!pgNotFound && (scf_pg_delete(pg) == -1)) { syslog(LOG_ERR, "delete pg %s failed - %s", pgName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } if (pgNotFound) { ret = STMF_PS_ERROR_NOT_FOUND; } out: /* * Free resources */ if (handle != NULL) { scf_handle_destroy(handle); } if (svc != NULL) { scf_service_destroy(svc); } if (pg != NULL) { scf_pg_destroy(pg); } return (ret); } /* * iPsCreateDeleteGroup * * Creates or deletes a group (target or host) * * When creating a group, two properties are created. One to hold the group * name and the other to hold the group members. * * pgName - Property group name * groupName - group name to create * addRemoveFlag - ADD_GROUP/REMOVE_GROUP * * returns: * STMF_PS_SUCCESS on success * STMF_PS_ERROR_* on failure */ static int iPsCreateDeleteGroup(char *pgRefName, char *groupName, int addRemoveFlag) { scf_handle_t *handle = NULL; scf_service_t *svc = NULL; scf_propertygroup_t *pg = NULL; scf_property_t *prop = NULL; scf_iter_t *propIter = NULL; scf_transaction_t *tran = NULL; scf_transaction_entry_t *entry1 = NULL; scf_transaction_entry_t *entry2 = NULL; scf_value_t *value = NULL; uint64_t groupIdx; char buf1[MAXNAMELEN]; char buf2[MAXNAMELEN]; char tmpbuf[MAXNAMELEN]; boolean_t found = B_FALSE; int ret = STMF_PS_SUCCESS; int commitRet; assert(groupName != NULL); ret = iPsInit(&handle, &svc); if (ret != STMF_PS_SUCCESS) { goto out; } /* * Allocate scf resources */ if (((pg = scf_pg_create(handle)) == NULL) || ((tran = scf_transaction_create(handle)) == NULL) || ((entry1 = scf_entry_create(handle)) == NULL) || ((entry2 = scf_entry_create(handle)) == NULL) || ((prop = scf_property_create(handle)) == NULL) || ((propIter = scf_iter_create(handle)) == NULL) || ((value = scf_value_create(handle)) == NULL)) { syslog(LOG_ERR, "scf alloc resource failed - %s", scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* * Get the property group being modified */ if (scf_service_get_pg(svc, pgRefName, pg) == -1) { if (scf_error() == SCF_ERROR_NOT_FOUND && addRemoveFlag == ADD) { if (scf_service_add_pg(svc, pgRefName, SCF_GROUP_APPLICATION, 0, pg) == -1) { syslog(LOG_ERR, "add pg %s failed - %s", pgRefName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; } } else if (scf_error() == SCF_ERROR_NOT_FOUND) { syslog(LOG_ERR, "get pg %s failed - %s", pgRefName, scf_strerror(scf_error())); ret = STMF_PS_ERROR_NOT_FOUND; } else { syslog(LOG_ERR, "get pg %s failed - %s", pgRefName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; } if (ret != STMF_PS_SUCCESS) { goto out; } } /* * propIter is the iterator handle */ if (scf_iter_pg_properties(propIter, pg) == -1) { syslog(LOG_ERR, "iter properties for %s failed - %s", pgRefName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* * Iterate through the group names. * If we find it in the list, it's an error when addRemoveFlag == ADD. */ while (scf_iter_next_property(propIter, prop) == 1) { if (scf_property_get_name(prop, buf1, sizeof (buf1)) == -1) { syslog(LOG_ERR, "get name from %s iter failed - %s", pgRefName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; break; } /* * Skip over member list properties */ if (strstr(buf1, STMF_MEMBER_LIST_SUFFIX)) { continue; } if (scf_property_get_value(prop, value) == -1) { syslog(LOG_ERR, "get property value %s/%s failed - %s", pgRefName, buf1, scf_strerror(scf_error())); ret = STMF_PS_ERROR; break; } if (scf_value_get_ustring(value, tmpbuf, sizeof (tmpbuf)) == -1) { syslog(LOG_ERR, "get ustring %s/%s failed - %s", pgRefName, buf1, scf_strerror(scf_error())); ret = STMF_PS_ERROR; break; } if ((strlen(tmpbuf) == strlen(groupName)) && bcmp(tmpbuf, groupName, strlen(tmpbuf)) == 0) { if (addRemoveFlag == ADD) { ret = STMF_PS_ERROR_EXISTS; } found = B_TRUE; /* * buf1 contains the name for REMOVE */ break; } } if (ret != STMF_PS_SUCCESS) { goto out; } scf_value_reset(value); if (!found && addRemoveFlag == REMOVE) { ret = STMF_PS_ERROR_NOT_FOUND; goto out; } /* * If we're adding, we need to create a new property name for the * new group */ if (addRemoveFlag == ADD) { for (groupIdx = 0; groupIdx < GROUP_MAX; groupIdx++) { if (snprintf(buf1, sizeof (buf1), "%s-%lld", STMF_GROUP_PREFIX, groupIdx) > sizeof (buf1)) { syslog(LOG_ERR, "buffer overflow on property name %s", buf1); ret = STMF_PS_ERROR; break; } if (scf_pg_get_property(pg, buf1, prop) == -1) { if (scf_error() != SCF_ERROR_NOT_FOUND) { syslog(LOG_ERR, "get property %s/%s " "failed - %s", pgRefName, buf1, scf_strerror(scf_error())); ret = STMF_PS_ERROR; } break; } } } /* * Now create the new member list property for the new group */ if (snprintf(buf2, sizeof (buf2), "%s-%s", buf1, STMF_MEMBER_LIST_SUFFIX) > sizeof (buf2)) { syslog(LOG_ERR, "buffer overflow on property name %s", buf1); ret = STMF_PS_ERROR; goto out; } /* * buf1 now contains the name of the property if it was found in the * list in the case of delete or the next available property name * in the case of create * * buf2 now contains the member list property name */ if (scf_transaction_start(tran, pg) == -1) { syslog(LOG_ERR, "start transaction for %s failed - %s", pgRefName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } if (addRemoveFlag == ADD) { /* * Create the property 'group name' * This is the container for the group name */ if (scf_transaction_property_new(tran, entry1, buf1, SCF_TYPE_USTRING) == -1) { syslog(LOG_ERR, "transaction property new %s/%s " "failed - %s", pgRefName, buf1, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } if (scf_value_set_ustring(value, groupName) == -1) { syslog(LOG_ERR, "set ustring %s/%s failed - %s", pgRefName, buf1, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } if (scf_entry_add_value(entry1, value) == -1) { syslog(LOG_ERR, "add value %s/%s failed - %s", pgRefName, buf1, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* * Create the property 'group list' * This is the container for the group members */ if (scf_transaction_property_new(tran, entry2, buf2, SCF_TYPE_USTRING) == -1) { syslog(LOG_ERR, "transaction property new %s/%s " "failed - %s", pgRefName, buf2, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } } else { /* * Delete the property 'group name' */ if (scf_transaction_property_delete(tran, entry1, buf1) == -1) { syslog(LOG_ERR, "transaction property delete %s/%s failed - %s", pgRefName, buf1, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* * Delete the property 'group list' */ if (scf_transaction_property_delete(tran, entry2, buf2) == -1) { syslog(LOG_ERR, "transaction property delete %s/%s " "failed - %s", pgRefName, buf2, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } } if (ret != STMF_PS_SUCCESS) { goto out; } if ((commitRet = scf_transaction_commit(tran)) != 1) { syslog(LOG_ERR, "transaction commit for %s failed - %s", pgRefName, scf_strerror(scf_error())); if (commitRet == 0) { ret = STMF_PS_ERROR_BUSY; } else { ret = STMF_PS_ERROR; } } out: /* * Free resources */ if (handle != NULL) { scf_handle_destroy(handle); } if (svc != NULL) { scf_service_destroy(svc); } if (pg != NULL) { scf_pg_destroy(pg); } if (tran != NULL) { scf_transaction_destroy(tran); } if (entry1 != NULL) { scf_entry_destroy(entry1); } if (entry2 != NULL) { scf_entry_destroy(entry2); } if (prop != NULL) { scf_property_destroy(prop); } if (propIter != NULL) { scf_iter_destroy(propIter); } if (value != NULL) { scf_value_destroy(value); } return (ret); } /* * iPsGetGroupList * * pgName - Property group name * groupList - pointer to pointer to stmfGroupList structure. On success, * contains the list of groups * * returns: * STMF_PS_SUCCESS on success * STMF_PS_ERROR_* on failure */ static int iPsGetGroupList(char *pgName, stmfGroupList **groupList) { scf_handle_t *handle = NULL; scf_service_t *svc = NULL; scf_propertygroup_t *pg = NULL; scf_property_t *prop = NULL; scf_iter_t *propIter = NULL; scf_value_t *value = NULL; char buf[MAXNAMELEN]; int memberCnt = 0; int i = 0; int ret = STMF_PS_SUCCESS; assert(groupList != NULL); ret = iPsInit(&handle, &svc); if (ret != STMF_PS_SUCCESS) { goto out; } /* * Allocate scf resources */ if (((pg = scf_pg_create(handle)) == NULL) || ((prop = scf_property_create(handle)) == NULL) || ((propIter = scf_iter_create(handle)) == NULL) || ((value = scf_value_create(handle)) == NULL)) { syslog(LOG_ERR, "scf alloc resource failed - %s", scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } if (scf_service_get_pg(svc, pgName, pg) == -1) { if (scf_error() == SCF_ERROR_NOT_FOUND) { syslog(LOG_ERR, "get pg %s failed - %s", pgName, scf_strerror(scf_error())); ret = STMF_PS_ERROR_NOT_FOUND; } else { syslog(LOG_ERR, "get pg %s failed - %s", pgName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; } goto out; } /* * propIter is the iterator handle */ if (scf_iter_pg_properties(propIter, pg) == -1) { syslog(LOG_ERR, "iter properties for %s failed - %s", pgName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } while (scf_iter_next_property(propIter, prop) == 1) { if (scf_property_get_name(prop, buf, sizeof (buf)) == -1) { syslog(LOG_ERR, "get name from %s iter failed - %s", pgName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; break; } /* * Skip over member list properties */ if (strstr(buf, STMF_MEMBER_LIST_SUFFIX)) { continue; } memberCnt++; } /* * propIter is the iterator handle */ if (scf_iter_pg_properties(propIter, pg) == -1) { syslog(LOG_ERR, "iter properties for %s failed - %s", pgName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } *groupList = (stmfGroupList *)calloc(1, sizeof (stmfGroupList) + memberCnt * sizeof (stmfGroupName)); if (*groupList == NULL) { ret = STMF_PS_ERROR_NOMEM; goto out; } /* * In order to get a list of groups, simply get all of the * properties that are not member list properties, i.e. the group * name properties. * It's possible for this list to grow beyond what was originally * read so just ensure we're not writing beyond our allocated buffer * by ensuring i < memberCnt */ while ((scf_iter_next_property(propIter, prop) == 1) && (i < memberCnt)) { if (scf_property_get_name(prop, buf, sizeof (buf)) == -1) { syslog(LOG_ERR, "get name from %s iter failed - %s", pgName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; break; } /* * Skip over member list properties */ if (strstr(buf, STMF_MEMBER_LIST_SUFFIX)) { continue; } if (scf_property_get_value(prop, value) == -1) { syslog(LOG_ERR, "get property value %s/%s failed - %s", pgName, buf, scf_strerror(scf_error())); ret = STMF_PS_ERROR; break; } if (scf_value_get_ustring(value, buf, sizeof (buf)) == -1) { syslog(LOG_ERR, "get ustring %s/%s failed - %s", pgName, buf, scf_strerror(scf_error())); ret = STMF_PS_ERROR; break; } bcopy(buf, (*groupList)->name[i++], strlen(buf)); (*groupList)->cnt++; } if (ret != STMF_PS_SUCCESS) { free(*groupList); goto out; } out: /* * Free resources */ if (handle != NULL) { scf_handle_destroy(handle); } if (svc != NULL) { scf_service_destroy(svc); } if (pg != NULL) { scf_pg_destroy(pg); } if (propIter != NULL) { scf_iter_destroy(propIter); } if (prop != NULL) { scf_property_destroy(prop); } if (value != NULL) { scf_value_destroy(value); } return (ret); } /* * iPsGetGroupMemberList * * pgName - Property group name * groupName - group name (host group or target group) * groupMemberList - pointer to pointer to stmfGroupProperties structure. On * success, contains the list of group members * * returns: * STMF_PS_SUCCESS on success * STMF_PS_ERROR_* on failure */ static int iPsGetGroupMemberList(char *pgName, char *groupName, stmfGroupProperties **groupMemberList) { scf_handle_t *handle = NULL; scf_service_t *svc = NULL; scf_propertygroup_t *pg = NULL; scf_property_t *prop = NULL; scf_value_t *valueLookup = NULL; scf_iter_t *valueIter = NULL; int i = 0; int memberCnt; int len; int ret = STMF_PS_SUCCESS; char buf[MAXNAMELEN]; assert(pgName != NULL && groupName != NULL); /* * init the service handle */ ret = iPsInit(&handle, &svc); if (ret != STMF_PS_SUCCESS) { goto out; } /* * Allocate scf resources */ if (((pg = scf_pg_create(handle)) == NULL) || ((prop = scf_property_create(handle)) == NULL) || ((valueIter = scf_iter_create(handle)) == NULL) || ((valueLookup = scf_value_create(handle)) == NULL)) { syslog(LOG_ERR, "scf alloc resource failed - %s", scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* * get the service property group handle */ if (scf_service_get_pg(svc, pgName, pg) == -1) { if (scf_error() == SCF_ERROR_NOT_FOUND) { ret = STMF_PS_ERROR_NOT_FOUND; } else { ret = STMF_PS_ERROR; } syslog(LOG_ERR, "get pg %s failed - %s", pgName, scf_strerror(scf_error())); goto out; } /* * Get the property handle * based on the target or host group name */ if (scf_pg_get_property(pg, groupName, prop) == -1) { syslog(LOG_ERR, "get property %s/%s failed - %s", pgName, groupName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* * valueIter is the iterator handle */ if (scf_iter_property_values(valueIter, prop) == -1) { syslog(LOG_ERR, "iter value %s/%s failed - %s", pgName, groupName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } while (scf_iter_next_value(valueIter, valueLookup) == 1) { if (scf_value_get_ustring(valueLookup, buf, MAXNAMELEN) == -1) { syslog(LOG_ERR, "iter value %s/%s failed - %s", pgName, groupName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; break; } i++; } /* * valueIter is the iterator handle */ if (scf_iter_property_values(valueIter, prop) == -1) { syslog(LOG_ERR, "iter value %s/%s failed - %s", pgName, groupName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } memberCnt = i; *groupMemberList = (stmfGroupProperties *)calloc(1, sizeof (stmfGroupProperties) + memberCnt * sizeof (stmfDevid)); if (*groupMemberList == NULL) { ret = STMF_PS_ERROR_NOMEM; goto out; } i = 0; while ((scf_iter_next_value(valueIter, valueLookup) == 1) && (i < memberCnt)) { if ((len = scf_value_get_ustring(valueLookup, buf, MAXNAMELEN)) == -1) { syslog(LOG_ERR, "iter value %s/%s failed - %s", pgName, groupName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; break; } if (len < sizeof (stmfDevid) - 1) { (*groupMemberList)->name[i].identLength = len; bcopy(buf, (*groupMemberList)->name[i++].ident, len); (*groupMemberList)->cnt++; } else { ret = STMF_PS_ERROR; break; } } if (ret != STMF_PS_SUCCESS) { free(*groupMemberList); goto out; } out: /* * Free resources */ if (handle != NULL) { scf_handle_destroy(handle); } if (svc != NULL) { scf_service_destroy(svc); } if (pg != NULL) { scf_pg_destroy(pg); } if (prop != NULL) { scf_property_destroy(prop); } if (valueLookup != NULL) { scf_value_destroy(valueLookup); } if (valueIter != NULL) { scf_iter_destroy(valueIter); } return (ret); } int psGetServicePersist(uint8_t *persistType) { scf_handle_t *handle = NULL; scf_service_t *svc = NULL; int ret; ret = iPsInit(&handle, &svc); if (ret != STMF_PS_SUCCESS) { return (STMF_PS_ERROR); } ret = iPsGetSetPersistType(persistType, handle, svc, GET); /* * Free resources */ if (handle != NULL) { scf_handle_destroy(handle); } if (svc != NULL) { scf_service_destroy(svc); } return (ret); } int psSetServicePersist(uint8_t persistType) { scf_handle_t *handle = NULL; scf_service_t *svc = NULL; int ret; ret = iPsInit(&handle, &svc); if (ret != STMF_PS_SUCCESS) { return (STMF_PS_ERROR); } ret = iPsGetSetPersistType(&persistType, handle, svc, SET); /* * Free resources */ if (handle != NULL) { scf_handle_destroy(handle); } if (svc != NULL) { scf_service_destroy(svc); } return (ret); } static int iPsGetSetPersistType(uint8_t *persistType, scf_handle_t *handle, scf_service_t *svc, int getSet) { scf_propertygroup_t *pg = NULL; scf_property_t *prop = NULL; scf_value_t *value = NULL; scf_transaction_t *tran = NULL; scf_transaction_entry_t *entry = NULL; char iPersistTypeGet[MAXNAMELEN] = {0}; char *iPersistType; int ret = STMF_PS_SUCCESS; int commitRet; if (((pg = scf_pg_create(handle)) == NULL) || ((prop = scf_property_create(handle)) == NULL) || ((entry = scf_entry_create(handle)) == NULL) || ((tran = scf_transaction_create(handle)) == NULL) || ((value = scf_value_create(handle)) == NULL)) { syslog(LOG_ERR, "scf alloc resource failed - %s", scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } if (getSet == GET) { /* set to default */ *persistType = STMF_PERSIST_SMF; iPersistType = STMF_PS_PERSIST_SMF; } if (getSet == SET) { if (*persistType == STMF_PERSIST_SMF) { iPersistType = STMF_PS_PERSIST_SMF; } else if (*persistType == STMF_PERSIST_NONE) { iPersistType = STMF_PS_PERSIST_NONE; } else { ret = STMF_PS_ERROR; goto out; } } /* * get stmf data property group */ if (scf_service_get_pg(svc, STMF_DATA_GROUP, pg) == -1) { if (scf_error() == SCF_ERROR_NOT_FOUND) { ret = STMF_PS_ERROR_NOT_FOUND; } else { ret = STMF_PS_ERROR; } syslog(LOG_ERR, "get pg %s failed - %s", STMF_DATA_GROUP, scf_strerror(scf_error())); goto out; } /* find persistence property */ /* * Get the persistence property */ if (scf_pg_get_property(pg, STMF_PERSIST_TYPE, prop) == -1) { if (scf_error() == SCF_ERROR_NOT_FOUND) { ret = STMF_PS_ERROR_NOT_FOUND; } else { syslog(LOG_ERR, "get property %s/%s failed - %s", STMF_DATA_GROUP, STMF_PERSIST_TYPE, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } } /* no persist property found */ if (ret == STMF_PS_ERROR_NOT_FOUND || getSet == SET) { /* * If we have no persistType property, go ahead * and create it with the user specified value or * the default value. */ /* * Begin the transaction */ if (scf_transaction_start(tran, pg) == -1) { syslog(LOG_ERR, "start transaction for %s failed - %s", STMF_DATA_GROUP, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* is this a SET or GET w/error? */ if (ret) { if (scf_transaction_property_new(tran, entry, STMF_PERSIST_TYPE, SCF_TYPE_ASTRING) == -1) { syslog(LOG_ERR, "transaction property new " "%s/%s failed - %s", STMF_DATA_GROUP, STMF_PERSIST_TYPE, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } } else { if (scf_transaction_property_change(tran, entry, STMF_PERSIST_TYPE, SCF_TYPE_ASTRING) == -1) { syslog(LOG_ERR, "transaction property change " "%s/%s failed - %s", STMF_DATA_GROUP, STMF_PERSIST_TYPE, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } } /* * set the persist type */ if (scf_value_set_astring(value, iPersistType) == -1) { syslog(LOG_ERR, "set value %s/%s failed - %s", STMF_DATA_GROUP, STMF_PERSIST_TYPE, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* * add the value to the transaction */ if (scf_entry_add_value(entry, value) == -1) { syslog(LOG_ERR, "add value %s/%s failed - %s", STMF_DATA_GROUP, STMF_PERSIST_TYPE, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } if ((commitRet = scf_transaction_commit(tran)) != 1) { syslog(LOG_ERR, "transaction commit for %s failed - %s", STMF_DATA_GROUP, scf_strerror(scf_error())); if (commitRet == 0) { ret = STMF_PS_ERROR_BUSY; } else { ret = STMF_PS_ERROR; } goto out; } /* reset return value */ ret = STMF_PS_SUCCESS; } else if (getSet == GET) { /* get the persist property */ if (scf_property_get_value(prop, value) == -1) { syslog(LOG_ERR, "get property value %s/%s failed - %s", STMF_DATA_GROUP, STMF_PERSIST_TYPE, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* * Get the value of the persist property */ if (scf_value_get_astring(value, iPersistTypeGet, MAXNAMELEN) == -1) { syslog(LOG_ERR, "get string value %s/%s failed - %s", STMF_DATA_GROUP, STMF_PERSIST_TYPE, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } } if (getSet == GET) { if (strcmp(iPersistTypeGet, STMF_PS_PERSIST_NONE) == 0) { *persistType = STMF_PERSIST_NONE; } else if (strcmp(iPersistTypeGet, STMF_PS_PERSIST_SMF) == 0) { *persistType = STMF_PERSIST_SMF; } else { ret = STMF_PS_ERROR; goto out; } } out: /* * Free resources. * handle and svc should not be free'd here. They're * free'd elsewhere */ if (pg != NULL) { scf_pg_destroy(pg); } if (prop != NULL) { scf_property_destroy(prop); } if (entry != NULL) { scf_entry_destroy(entry); } if (tran != NULL) { scf_transaction_destroy(tran); } if (value != NULL) { scf_value_destroy(value); } return (ret); } int psSetStmfProp(int propType, char *propVal) { return (iPsGetSetStmfProp(propType, propVal, SET)); } int psGetStmfProp(int propType, char *propVal) { return (iPsGetSetStmfProp(propType, propVal, GET)); } static int iPsGetSetStmfProp(int propType, char *propVal, int getSet) { scf_handle_t *handle = NULL; scf_service_t *svc = NULL; scf_property_t *prop = NULL; scf_propertygroup_t *pg = NULL; scf_transaction_t *tran = NULL; scf_transaction_entry_t *entry = NULL; scf_value_t *value = NULL; char *psStmfPropVal = NULL; char *psStmfProp = NULL; char stmfPropGet[MAXNAMELEN] = {0}; int ret = STMF_PS_SUCCESS; int commitRet; if (propVal == NULL || (getSet != GET && getSet != SET)) { ret = STMF_PS_ERROR; goto out; } /* * Init the service handle */ ret = iPsInit(&handle, &svc); if (ret != STMF_PS_SUCCESS) { goto out; } /* * Allocate scf resources */ if (((pg = scf_pg_create(handle)) == NULL) || ((prop = scf_property_create(handle)) == NULL) || ((entry = scf_entry_create(handle)) == NULL) || ((tran = scf_transaction_create(handle)) == NULL) || ((value = scf_value_create(handle)) == NULL)) { syslog(LOG_ERR, "scf alloc resource failed - %s", scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } if (getSet == GET) { switch (propType) { case STMF_DEFAULT_LU_STATE : psStmfProp = DEFAULT_LU_STATE; psStmfPropVal = STMF_PS_LU_ONLINE; (void) strcpy(stmfPropGet, psStmfPropVal); break; case STMF_DEFAULT_TARGET_PORT_STATE : psStmfProp = DEFAULT_TARGET_PORT_STATE; psStmfPropVal = STMF_PS_TARGET_PORT_ONLINE; (void) strcpy(stmfPropGet, psStmfPropVal); break; default : ret = STMF_PS_ERROR; goto out; } } if (getSet == SET) { switch (propType) { case STMF_DEFAULT_LU_STATE : psStmfProp = DEFAULT_LU_STATE; if (strcasecmp(propVal, "online") == 0) { psStmfPropVal = STMF_PS_LU_ONLINE; } else if (strcasecmp(propVal, "offline") == 0) { psStmfPropVal = STMF_PS_LU_OFFLINE; } else { ret = STMF_PS_ERROR; goto out; } break; case STMF_DEFAULT_TARGET_PORT_STATE : psStmfProp = DEFAULT_TARGET_PORT_STATE; if (strcasecmp(propVal, "online") == 0) { psStmfPropVal = STMF_PS_TARGET_PORT_ONLINE; } else if (strcasecmp(propVal, "offline") == 0) { psStmfPropVal = STMF_PS_TARGET_PORT_OFFLINE; } else { ret = STMF_PS_ERROR; goto out; } break; default : ret = STMF_PS_ERROR; goto out; } } /* * get stmf data property group */ if (scf_service_get_pg(svc, STMF_DATA_GROUP, pg) == -1) { if (scf_error() == SCF_ERROR_NOT_FOUND) { ret = STMF_PS_ERROR_NOT_FOUND; } else { ret = STMF_PS_ERROR; } syslog(LOG_ERR, "get pg %s failed - %s", STMF_DATA_GROUP, scf_strerror(scf_error())); goto out; } /* * get the stmf props property, if exists */ if (scf_pg_get_property(pg, psStmfProp, prop) == -1) { if (scf_error() == SCF_ERROR_NOT_FOUND) { ret = STMF_PS_ERROR_NOT_FOUND; } else { syslog(LOG_ERR, "start transaction for %s/%s " "failed - %s", STMF_DATA_GROUP, psStmfProp, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } } /* if stmf prop is not found or while setting the prop */ if (ret == STMF_PS_ERROR_NOT_FOUND || getSet == SET) { /* * Begin the transaction */ if (scf_transaction_start(tran, pg) == -1) { syslog(LOG_ERR, "start transaction for %s failed - %s", STMF_DATA_GROUP, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } if (ret) { if (scf_transaction_property_new(tran, entry, psStmfProp, SCF_TYPE_ASTRING) == -1) { syslog(LOG_ERR, "transaction property new " "%s/%s failed - %s", STMF_DATA_GROUP, psStmfProp, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } } else { if (scf_transaction_property_change(tran, entry, psStmfProp, SCF_TYPE_ASTRING) == -1) { syslog(LOG_ERR, "transaction property change " "%s/%s failed - %s", STMF_DATA_GROUP, psStmfProp, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } } /* * set stmf prop value */ if (scf_value_set_astring(value, psStmfPropVal) == -1) { syslog(LOG_ERR, "set value %s/%s failed - %s", STMF_DATA_GROUP, psStmfProp, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* * add the value to the transaction */ if (scf_entry_add_value(entry, value) == -1) { syslog(LOG_ERR, "add value %s/%s failed - %s", STMF_DATA_GROUP, psStmfProp, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } if ((commitRet = scf_transaction_commit(tran)) != 1) { syslog(LOG_ERR, "transaction commit for %s" "failed - %s", STMF_DATA_GROUP, scf_strerror(scf_error())); if (commitRet == 0) { ret = STMF_PS_ERROR_BUSY; } else { ret = STMF_PS_ERROR; } goto out; } ret = STMF_PS_SUCCESS; } else if (getSet == GET) { if (scf_property_get_value(prop, value) == -1) { syslog(LOG_ERR, "get property value " "%s/%s failed - %s", STMF_DATA_GROUP, psStmfProp, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* get stmfProp */ if (scf_value_get_astring(value, stmfPropGet, MAXNAMELEN) == -1) { syslog(LOG_ERR, "get string value %s/%s failed - %s", STMF_DATA_GROUP, psStmfProp, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } } if (getSet == GET) { if (strcmp(stmfPropGet, STMF_PS_LU_ONLINE) == 0) { (void) strcpy(propVal, "online"); } else if (strcmp(stmfPropGet, STMF_PS_LU_OFFLINE) == 0) { (void) strcpy(propVal, "offline"); } else if (strcmp(stmfPropGet, STMF_PS_TARGET_PORT_ONLINE) == 0) { (void) strcpy(propVal, "online"); } else if (strcmp(stmfPropGet, STMF_PS_TARGET_PORT_OFFLINE) == 0) { (void) strcpy(propVal, "offline"); } else { ret = STMF_PS_ERROR; goto out; } } out: /* * Free resources. */ if (handle != NULL) { scf_handle_destroy(handle); } if (svc != NULL) { scf_service_destroy(svc); } if (pg != NULL) { scf_pg_destroy(pg); } if (prop != NULL) { scf_property_destroy(prop); } if (entry != NULL) { scf_entry_destroy(entry); } if (tran != NULL) { scf_transaction_destroy(tran); } if (value != NULL) { scf_value_destroy(value); } return (ret); } /* * Initialize scf stmf service access * handle - returned handle * service - returned service handle * * Both handle and service must be destroyed by the caller */ static int iPsInit(scf_handle_t **handle, scf_service_t **service) { scf_scope_t *scope = NULL; uint64_t version; int ret; assert(handle != NULL && service != NULL); if ((*handle = scf_handle_create(SCF_VERSION)) == NULL) { syslog(LOG_ERR, "scf_handle_create failed - %s", scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto err; } if (scf_handle_bind(*handle) == -1) { syslog(LOG_ERR, "scf_handle_bind failed - %s", scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto err; } if ((*service = scf_service_create(*handle)) == NULL) { syslog(LOG_ERR, "scf_service_create failed - %s", scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto err; } if ((scope = scf_scope_create(*handle)) == NULL) { syslog(LOG_ERR, "scf_scope_create failed - %s", scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto err; } if (scf_handle_get_scope(*handle, SCF_SCOPE_LOCAL, scope) == -1) { syslog(LOG_ERR, "scf_handle_get_scope failed - %s", scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto err; } if (scf_scope_get_service(scope, STMF_SERVICE, *service) == -1) { syslog(LOG_ERR, "scf_scope_get_service failed - %s", scf_strerror(scf_error())); ret = STMF_PS_ERROR_SERVICE_NOT_FOUND; goto err; } /* * Get and check the version number */ ret = iPsGetServiceVersion(&version, *handle, *service); if (ret != STMF_PS_SUCCESS) { goto err; } if (version != STMF_SMF_VERSION) { ret = STMF_PS_ERROR_VERSION_MISMATCH; goto err; } /* we only need destroy the scope here */ scf_scope_destroy(scope); return (STMF_PS_SUCCESS); err: if (*handle != NULL) { scf_handle_destroy(*handle); } if (*service != NULL) { scf_service_destroy(*service); *service = NULL; } if (scope != NULL) { scf_scope_destroy(scope); } return (ret); } /* * called by iPsInit only * iPsGetServiceVersion */ static int iPsGetServiceVersion(uint64_t *version, scf_handle_t *handle, scf_service_t *svc) { scf_propertygroup_t *pg = NULL; scf_property_t *prop = NULL; scf_value_t *value = NULL; scf_transaction_t *tran = NULL; scf_transaction_entry_t *entry = NULL; int ret = STMF_PS_SUCCESS; int commitRet; if (((pg = scf_pg_create(handle)) == NULL) || ((prop = scf_property_create(handle)) == NULL) || ((entry = scf_entry_create(handle)) == NULL) || ((tran = scf_transaction_create(handle)) == NULL) || ((value = scf_value_create(handle)) == NULL)) { syslog(LOG_ERR, "scf alloc resource failed - %s", scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } *version = STMF_SMF_VERSION; /* * get stmf data property group */ if (scf_service_get_pg(svc, STMF_DATA_GROUP, pg) == -1) { if (scf_error() == SCF_ERROR_NOT_FOUND) { ret = STMF_PS_ERROR_NOT_FOUND; } else { syslog(LOG_ERR, "get pg %s failed - %s", STMF_DATA_GROUP, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } } /* create the group */ if (ret == STMF_PS_ERROR_NOT_FOUND) { /* * create the property group. */ if (scf_service_add_pg(svc, STMF_DATA_GROUP, SCF_GROUP_APPLICATION, 0, pg) == -1) { syslog(LOG_ERR, "add pg %s failed - %s", STMF_DATA_GROUP, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* reset return value */ ret = STMF_PS_SUCCESS; } /* find version property */ /* * Get the version property */ if (scf_pg_get_property(pg, STMF_VERSION_NAME, prop) == -1) { if (scf_error() == SCF_ERROR_NOT_FOUND) { ret = STMF_PS_ERROR_NOT_FOUND; } else { syslog(LOG_ERR, "get property %s/%s failed - %s", STMF_DATA_GROUP, STMF_VERSION_NAME, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } } /* no version property found */ if (ret == STMF_PS_ERROR_NOT_FOUND) { /* * If we have no version property, go ahead * and create it. We're obviously making an assumption * here that someone did not delete the existing property * and that this is the initial set and the initial call * to iPsInit. * If they did delete it, this will simply plant this * library's version on this service. That may or may not be * correct and we have no way of determining that. */ /* * Begin the transaction */ if (scf_transaction_start(tran, pg) == -1) { syslog(LOG_ERR, "start transaction for %s failed - %s", STMF_DATA_GROUP, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } if (scf_transaction_property_new(tran, entry, STMF_VERSION_NAME, SCF_TYPE_COUNT) == -1) { syslog(LOG_ERR, "transaction property new %s/%s failed - %s", STMF_DATA_GROUP, STMF_VERSION_NAME, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* * set the version number */ scf_value_set_count(value, *version); /* * add the value to the transaction */ if (scf_entry_add_value(entry, value) == -1) { syslog(LOG_ERR, "add value %s/%s failed - %s", STMF_DATA_GROUP, STMF_VERSION_NAME, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } if ((commitRet = scf_transaction_commit(tran)) != 1) { syslog(LOG_ERR, "transaction commit for %s failed - %s", STMF_DATA_GROUP, scf_strerror(scf_error())); if (commitRet == 0) { ret = STMF_PS_ERROR_BUSY; } else { ret = STMF_PS_ERROR; } goto out; } /* reset return value */ ret = STMF_PS_SUCCESS; } else { /* get the version property */ if (scf_pg_get_property(pg, STMF_VERSION_NAME, prop) == -1) { syslog(LOG_ERR, "get property %s/%s failed - %s", STMF_DATA_GROUP, STMF_VERSION_NAME, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } if (scf_property_get_value(prop, value) == -1) { syslog(LOG_ERR, "get property value %s/%s failed - %s", STMF_DATA_GROUP, STMF_VERSION_NAME, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* * Get the actual value of the view entry count property */ if (scf_value_get_count(value, version) == -1) { syslog(LOG_ERR, "get count value %s/%s failed - %s", STMF_DATA_GROUP, STMF_VERSION_NAME, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } } out: /* * Free resources. * handle and svc should not be free'd here. They're * free'd elsewhere */ if (pg != NULL) { scf_pg_destroy(pg); } if (prop != NULL) { scf_property_destroy(prop); } if (entry != NULL) { scf_entry_destroy(entry); } if (tran != NULL) { scf_transaction_destroy(tran); } if (value != NULL) { scf_value_destroy(value); } return (ret); } /* * iPsGetActualGroupName * * pgName - Property group name * groupName - requested group name * actualName - actual group name to reference (len must be >= MAXNAMELEN) * * returns: * STMF_PS_SUCCESS on success * STMF_PS_ERROR_* on failure */ static int iPsGetActualGroupName(char *pgName, char *groupName, char *actualName) { scf_handle_t *handle = NULL; scf_service_t *svc = NULL; scf_propertygroup_t *pg = NULL; scf_property_t *prop = NULL; scf_iter_t *propIter = NULL; scf_value_t *value = NULL; char buf[MAXNAMELEN]; int ret; ret = iPsInit(&handle, &svc); if (ret != STMF_PS_SUCCESS) { goto out; } /* * Allocate scf resources */ if (((pg = scf_pg_create(handle)) == NULL) || ((prop = scf_property_create(handle)) == NULL) || ((propIter = scf_iter_create(handle)) == NULL) || ((value = scf_value_create(handle)) == NULL)) { syslog(LOG_ERR, "scf alloc resource failed - %s", scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* * get group list property group */ if (scf_service_get_pg(svc, pgName, pg) == -1) { if (scf_error() == SCF_ERROR_NOT_FOUND) { ret = STMF_PS_ERROR_GROUP_NOT_FOUND; } else { syslog(LOG_ERR, "get pg %s failed - %s", pgName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; } goto out; } /* * propIter is the iterator handle */ if (scf_iter_pg_properties(propIter, pg) == -1) { syslog(LOG_ERR, "iter properties for %s failed - %s", pgName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* * Iterate through group properties searching for the requested * group name. When we find it, we need to get the property name * since it refers to the actual group name. */ /* initialize to not found */ ret = STMF_PS_ERROR_GROUP_NOT_FOUND; while (scf_iter_next_property(propIter, prop) == 1) { if (scf_property_get_name(prop, actualName, MAXNAMELEN) == -1) { syslog(LOG_ERR, "get name from %s iter failed - %s", pgName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; break; } /* * Skip over non-member list properties */ if (strstr(actualName, STMF_MEMBER_LIST_SUFFIX)) { continue; } if (scf_property_get_value(prop, value) == -1) { syslog(LOG_ERR, "get property value %s/%s failed - %s", pgName, actualName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; break; } if (scf_value_get_ustring(value, buf, sizeof (buf)) == -1) { syslog(LOG_ERR, "get ustring %s/%s failed - %s", pgName, actualName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; break; } /* * When we find a match, set success and break */ if ((strlen(buf) == strlen(groupName)) && bcmp(buf, groupName, strlen(buf)) == 0) { ret = STMF_PS_SUCCESS; break; } } /* * if we didn't find it, ret is set to STMF_PS_ERROR_GROUP_NOT_FOUND */ out: /* * Free resources */ if (handle != NULL) { scf_handle_destroy(handle); } if (svc != NULL) { scf_service_destroy(svc); } if (pg != NULL) { scf_pg_destroy(pg); } if (propIter != NULL) { scf_iter_destroy(propIter); } if (prop != NULL) { scf_property_destroy(prop); } if (value != NULL) { scf_value_destroy(value); } return (ret); } /* * psAddHostGroupMember * * Add a host group member to a host group, * * Input: groupName - name of group to which the member is added * memberName - name of group member to add */ int psAddHostGroupMember(char *groupName, char *memberName) { int ret; char groupPropListName[MAXNAMELEN]; char groupPropName[MAXNAMELEN]; ret = iPsGetActualGroupName(STMF_HOST_GROUPS, groupName, groupPropName); if (ret != STMF_PS_SUCCESS) { return (ret); } if (snprintf(groupPropListName, sizeof (groupPropListName), "%s-%s", groupPropName, STMF_MEMBER_LIST_SUFFIX) > sizeof (groupPropListName)) { syslog(LOG_ERR, "buffer overflow on property name %s", groupPropName); return (STMF_PS_ERROR); } return (iPsAddRemoveGroupMember(STMF_HOST_GROUPS, groupPropListName, memberName, ADD)); } /* * psAddTargetGroupMember * * Add a target port group member to a target group * * Input: groupName - name of group to which the member is added * memberName - name of group member to add. Must be nul terminated. */ int psAddTargetGroupMember(char *groupName, char *memberName) { int ret; char groupPropListName[MAXNAMELEN]; char groupPropName[MAXNAMELEN]; ret = iPsGetActualGroupName(STMF_TARGET_GROUPS, groupName, groupPropName); if (ret != STMF_PS_SUCCESS) { return (ret); } if (snprintf(groupPropListName, sizeof (groupPropListName), "%s-%s", groupPropName, STMF_MEMBER_LIST_SUFFIX) > sizeof (groupPropListName)) { syslog(LOG_ERR, "buffer overflow on property name %s", groupPropName); return (STMF_PS_ERROR); } return (iPsAddRemoveGroupMember(STMF_TARGET_GROUPS, groupPropListName, memberName, ADD)); } /* * psAddViewEntry * * luGuid - logical unit identifier * viewEntry - pointer to viewEntry allocated by the caller that contains * the values to set for this view entry * * returns: * STMF_PS_SUCCESS on success * STMF_PS_ERROR_* on failure */ int psAddViewEntry(stmfGuid *lu, stmfViewEntry *viewEntry) { scf_handle_t *handle = NULL; scf_service_t *svc = NULL; scf_propertygroup_t *pg = NULL; char guidAsciiBuf[33]; /* size of ascii hex 16 byte guid with NULL */ char viewEntryPgName[VIEW_ENTRY_PG_SIZE]; char scfLuPgName[LOGICAL_UNIT_PG_SIZE]; int ret = STMF_PS_SUCCESS; sigset_t sigmaskRestore; /* grab the signal hold lock */ (void) pthread_mutex_lock(&sigSetLock); /* * hold signals until we're done */ if (holdSignal(&sigmaskRestore) != 0) { (void) pthread_mutex_unlock(&sigSetLock); return (STMF_PS_ERROR); } ret = iPsInit(&handle, &svc); if (ret != STMF_PS_SUCCESS) { goto out; } pg = scf_pg_create(handle); if (pg == NULL) { syslog(LOG_ERR, "scf pg alloc failed - %s", scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* Convert to ASCII uppercase hexadecimal string */ (void) snprintf(guidAsciiBuf, sizeof (guidAsciiBuf), "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", lu->guid[0], lu->guid[1], lu->guid[2], lu->guid[3], lu->guid[4], lu->guid[5], lu->guid[6], lu->guid[7], lu->guid[8], lu->guid[9], lu->guid[10], lu->guid[11], lu->guid[12], lu->guid[13], lu->guid[14], lu->guid[15]); (void) snprintf(scfLuPgName, sizeof (scfLuPgName), "%s-%s", STMF_LU_PREFIX, guidAsciiBuf); bzero(viewEntryPgName, sizeof (viewEntryPgName)); /* * Format of view entry property group name: * VE-- */ (void) snprintf(viewEntryPgName, sizeof (viewEntryPgName), "%s-%d-%s", STMF_VE_PREFIX, viewEntry->veIndex, guidAsciiBuf); ret = iPsAddViewEntry(scfLuPgName, viewEntryPgName, viewEntry); out: /* * Okay, we're done. Release the signals */ if (releaseSignal(&sigmaskRestore) != 0) { /* * Don't set this as an STMF_PS_ERROR_*. We succeeded * the requested operation. But we do need to log it. */ syslog(LOG_ERR, "Unable to release one or more signals - %s", strerror(errno)); } /* * Free resources */ if (handle != NULL) { scf_handle_destroy(handle); } if (svc != NULL) { scf_service_destroy(svc); } if (pg != NULL) { scf_pg_destroy(pg); } /* release the signal hold lock */ (void) pthread_mutex_unlock(&sigSetLock); return (ret); } /* * psCheckService * * Purpose: Checks whether service exists * */ int psCheckService() { int ret; scf_handle_t *handle = NULL; scf_service_t *svc = NULL; ret = iPsInit(&handle, &svc); /* * Free resources */ if (handle != NULL) { scf_handle_destroy(handle); } if (svc != NULL) { scf_service_destroy(svc); } return (ret); } /* * psCreateHostGroup * * groupName - name of group to create * * returns: * STMF_PS_SUCCESS on success * STMF_PS_ERROR_* on failure */ int psCreateHostGroup(char *groupName) { return (iPsCreateDeleteGroup(STMF_HOST_GROUPS, groupName, ADD)); } /* * psCreateTargetGroup * * groupName - name of group to create * * returns: * STMF_PS_SUCCESS on success * STMF_PS_ERROR_* on failure */ int psCreateTargetGroup(char *groupName) { return (iPsCreateDeleteGroup(STMF_TARGET_GROUPS, groupName, ADD)); } /* * psDeleteHostGroup * * groupName - name of group to delete * * returns: * STMF_PS_SUCCESS on success * STMF_PS_ERROR_* on failure */ int psDeleteHostGroup(char *groupName) { return (iPsCreateDeleteGroup(STMF_HOST_GROUPS, groupName, REMOVE)); } /* * psDeleteTargetGroup * * groupName - name of group to delete * * returns: * STMF_PS_SUCCESS on success * STMF_PS_ERROR_* on failure */ int psDeleteTargetGroup(char *groupName) { return (iPsCreateDeleteGroup(STMF_TARGET_GROUPS, groupName, REMOVE)); } /* * psGetHostGroupList * * groupList - pointer to pointer to stmfGroupList. Contains the list * of host groups on successful return. * * returns: * STMF_PS_SUCCESS on success * STMF_PS_ERROR_* on failure */ int psGetHostGroupList(stmfGroupList **groupList) { return (iPsGetGroupList(STMF_HOST_GROUPS, groupList)); } /* * psGetLogicalUnitList * * */ int psGetLogicalUnitList(stmfGuidList **guidList) { scf_handle_t *handle = NULL; scf_service_t *svc = NULL; scf_propertygroup_t *pg = NULL; scf_iter_t *pgIter = NULL; char buf[MAXNAMELEN]; int guidCnt = 0; int i = 0, j; int ret = STMF_PS_SUCCESS; unsigned int guid[sizeof (stmfGuid)]; stmfGuid outGuid; assert(guidList != NULL); ret = iPsInit(&handle, &svc); if (ret != STMF_PS_SUCCESS) { goto out; } /* * Allocate scf resources */ if (((pg = scf_pg_create(handle)) == NULL) || ((pgIter = scf_iter_create(handle)) == NULL)) { syslog(LOG_ERR, "scf alloc resource failed - %s", scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* * pgIter is the iterator handle */ if (scf_iter_service_pgs(pgIter, svc) == -1) { syslog(LOG_ERR, "iter property groups failed - %s", scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } while (scf_iter_next_pg(pgIter, pg) == 1) { if (scf_pg_get_name(pg, buf, sizeof (buf)) == -1) { syslog(LOG_ERR, "get pg name failed - %s", scf_strerror(scf_error())); ret = STMF_PS_ERROR; break; } /* * Only count LU property groups */ if (strncmp(buf, STMF_LU_PREFIX, strlen(STMF_LU_PREFIX)) == 0) { guidCnt++; } } /* * pgIter is the iterator handle */ if (scf_iter_service_pgs(pgIter, svc) == -1) { syslog(LOG_ERR, "iter property groups failed - %s", scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } *guidList = (stmfGuidList *)calloc(1, sizeof (stmfGuidList) + guidCnt * sizeof (stmfGuid)); if (*guidList == NULL) { ret = STMF_PS_ERROR_NOMEM; goto out; } /* * it's possible for entries to be added/removed while we're retrieving * the property groups. Just make sure we don't write beyond our * allocated buffer by checking to ensure i < guidCnt. */ while ((scf_iter_next_pg(pgIter, pg) == 1) && (i < guidCnt)) { if (scf_pg_get_name(pg, buf, sizeof (buf)) == -1) { syslog(LOG_ERR, "get pg name failed - %s", scf_strerror(scf_error())); ret = STMF_PS_ERROR; break; } /* * Only use LU property groups */ if (strncmp(buf, STMF_LU_PREFIX, strlen(STMF_LU_PREFIX)) != 0) { continue; } j = strlen(STMF_LU_PREFIX) + strlen("-"); (void) sscanf(buf + j, "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x", &guid[0], &guid[1], &guid[2], &guid[3], &guid[4], &guid[5], &guid[6], &guid[7], &guid[8], &guid[9], &guid[10], &guid[11], &guid[12], &guid[13], &guid[14], &guid[15]); for (j = 0; j < sizeof (stmfGuid); j++) { outGuid.guid[j] = guid[j]; } bcopy(&outGuid, (*guidList)->guid[i++].guid, sizeof (stmfGuid)); (*guidList)->cnt++; } if (ret != STMF_PS_SUCCESS) { free(*guidList); goto out; } out: /* * Free resources */ if (handle != NULL) { scf_handle_destroy(handle); } if (svc != NULL) { scf_service_destroy(svc); } if (pg != NULL) { scf_pg_destroy(pg); } if (pgIter != NULL) { scf_iter_destroy(pgIter); } return (ret); } /* * psGetTargetGroupList * * groupList - pointer to pointer to stmfGroupList. Contains the list * of target groups on successful return. * * returns: * STMF_PS_SUCCESS on success * STMF_PS_ERROR_* on failure */ int psGetTargetGroupList(stmfGroupList **groupList) { return (iPsGetGroupList(STMF_TARGET_GROUPS, groupList)); } /* * psGetHostGroupMemberList * * groupName - group name for which to retrieve a member list * groupMemberList - pointer to pointer to stmfGroupProperties list * * returns: * STMF_PS_SUCCESS on success * STMF_PS_ERROR_* on failure */ int psGetHostGroupMemberList(char *groupName, stmfGroupProperties **groupMemberList) { int ret; char groupPropListName[MAXNAMELEN]; char groupPropName[MAXNAMELEN]; ret = iPsGetActualGroupName(STMF_HOST_GROUPS, groupName, groupPropName); if (ret != STMF_PS_SUCCESS) { return (ret); } if (snprintf(groupPropListName, sizeof (groupPropListName), "%s-%s", groupPropName, STMF_MEMBER_LIST_SUFFIX) > sizeof (groupPropListName)) { syslog(LOG_ERR, "buffer overflow on property name %s", groupPropName); return (STMF_PS_ERROR); } return (iPsGetGroupMemberList(STMF_HOST_GROUPS, groupPropListName, groupMemberList)); } /* * psGetTargetGroupMemberList * * groupName - group name for which to retrieve a member list * groupMemberList - pointer to pointer to stmfGroupProperties list * * returns: * STMF_PS_SUCCESS on success * STMF_PS_ERROR_* on failure */ int psGetTargetGroupMemberList(char *groupName, stmfGroupProperties **groupMemberList) { int ret; char groupPropListName[MAXNAMELEN]; char groupPropName[MAXNAMELEN]; ret = iPsGetActualGroupName(STMF_TARGET_GROUPS, groupName, groupPropName); if (ret != STMF_PS_SUCCESS) { return (ret); } if (snprintf(groupPropListName, sizeof (groupPropListName), "%s-%s", groupPropName, STMF_MEMBER_LIST_SUFFIX) > sizeof (groupPropListName)) { syslog(LOG_ERR, "buffer overflow on property name %s", groupPropName); return (STMF_PS_ERROR); } return (iPsGetGroupMemberList(STMF_TARGET_GROUPS, groupPropListName, groupMemberList)); } /* * qsort function * sort on veIndex */ static int viewEntryCompare(const void *p1, const void *p2) { stmfViewEntry *v1 = (stmfViewEntry *)p1, *v2 = (stmfViewEntry *)p2; if (v1->veIndex > v2->veIndex) return (1); if (v1->veIndex < v2->veIndex) return (-1); return (0); } /* * psGetViewEntryList * * luGuid - identifier of logical unit for which to retrieve a view entry list * viewEntryList - pointer to pointer to stmfViewEntryList. It will be allocated * on successful return. * * returns: * STMF_PS_SUCCESS on success * STMF_PS_ERROR_* on failure */ int psGetViewEntryList(stmfGuid *lu, stmfViewEntryList **viewEntryList) { scf_handle_t *handle = NULL; scf_service_t *svc = NULL; scf_propertygroup_t *pg = NULL; scf_property_t *prop = NULL; scf_value_t *value = NULL; scf_iter_t *propIter = NULL; char guidAsciiBuf[33]; /* size of ascii hex 16 byte guid with NULL */ char viewEntryPgName[VIEW_ENTRY_PG_SIZE]; char luPgName[LOGICAL_UNIT_PG_SIZE]; int ret = STMF_PS_SUCCESS; uint64_t i = 0; uint64_t veCnt; ret = iPsInit(&handle, &svc); if (ret != STMF_PS_SUCCESS) { goto out; } /* * Allocate scf resources */ if (((pg = scf_pg_create(handle)) == NULL) || ((prop = scf_property_create(handle)) == NULL) || ((propIter = scf_iter_create(handle)) == NULL) || ((value = scf_value_create(handle)) == NULL)) { syslog(LOG_ERR, "scf alloc resource failed - %s", scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* Convert to ASCII uppercase hexadecimal string */ (void) snprintf(guidAsciiBuf, sizeof (guidAsciiBuf), "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", lu->guid[0], lu->guid[1], lu->guid[2], lu->guid[3], lu->guid[4], lu->guid[5], lu->guid[6], lu->guid[7], lu->guid[8], lu->guid[9], lu->guid[10], lu->guid[11], lu->guid[12], lu->guid[13], lu->guid[14], lu->guid[15]); /* form the LU property group name (LU-) */ (void) snprintf(luPgName, sizeof (luPgName), "%s-%s", STMF_LU_PREFIX, guidAsciiBuf); /* get the property group associated with this LU */ if (scf_service_get_pg(svc, luPgName, pg) == -1) { if (scf_error() == SCF_ERROR_NOT_FOUND) { ret = STMF_PS_ERROR_NOT_FOUND; } else { syslog(LOG_ERR, "get pg %s failed - %s", luPgName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; } goto out; } /* get the view entry count property */ if (scf_pg_get_property(pg, STMF_VE_CNT, prop) == -1) { syslog(LOG_ERR, "get property %s/%s failed - %s", luPgName, STMF_VE_CNT, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } if (scf_property_get_value(prop, value) == -1) { syslog(LOG_ERR, "get property value %s/%s failed - %s", luPgName, STMF_VE_CNT, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* * Get the actual value of the view entry count property */ if (scf_value_get_count(value, &veCnt) == -1) { syslog(LOG_ERR, "get integer value %s/%s failed - %s", luPgName, STMF_VE_CNT, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* * propIter is the iterator handle */ if (scf_iter_pg_properties(propIter, pg) == -1) { syslog(LOG_ERR, "iter properties for %s failed - %s", luPgName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* * alloc the list based on the view entry count */ *viewEntryList = (stmfViewEntryList *)calloc(1, sizeof (stmfViewEntryList) + veCnt * sizeof (stmfViewEntry)); if (*viewEntryList == NULL) { ret = STMF_PS_ERROR_NOMEM; goto out; } i = 0; /* * iterate through the view entry properties to find the * view entries */ while (scf_iter_next_property(propIter, prop) == 1) { /* find match for view entry property */ if (scf_property_get_name(prop, viewEntryPgName, sizeof (viewEntryPgName)) != -1) { if (strncmp(viewEntryPgName, STMF_VE_PREFIX, strlen(STMF_VE_PREFIX)) != 0) { continue; } /* * We've exceeded our alloc limit * break with error */ if (i == veCnt) { ret = STMF_PS_ERROR; break; } if ((ret = iPsGetViewEntry(viewEntryPgName, &((*viewEntryList)->ve[i]))) != STMF_PS_SUCCESS) { break; } i++; /* set the list count */ (*viewEntryList)->cnt++; } else { syslog(LOG_ERR, "scf iter %s properties failed - %s", luPgName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; break; } } if (ret != STMF_PS_SUCCESS) { free(*viewEntryList); goto out; } /* * We're sorting the final list here based on the veIndex * If we don't, the caller is going to have to do it to reap * some intelligent output. */ qsort((void *)&((*viewEntryList)->ve[0]), (*viewEntryList)->cnt, sizeof (stmfViewEntry), viewEntryCompare); out: /* * Free resources */ if (handle != NULL) { scf_handle_destroy(handle); } if (svc != NULL) { scf_service_destroy(svc); } if (pg != NULL) { scf_pg_destroy(pg); } if (prop != NULL) { scf_property_destroy(prop); } if (value != NULL) { scf_value_destroy(value); } if (propIter != NULL) { scf_iter_destroy(propIter); } return (ret); } /* * iPsGetViewEntry * * viewEntryPgName - view entry property group name to retrieve * viewEntry - pointer to stmfViewEntry structure allocated by the caller * * returns: * STMF_PS_SUCCESS on success * STMF_PS_ERROR_* on failure */ static int iPsGetViewEntry(char *viewEntryPgName, stmfViewEntry *viewEntry) { scf_handle_t *handle = NULL; scf_service_t *svc = NULL; scf_propertygroup_t *pg = NULL; scf_property_t *prop = NULL; scf_value_t *value = NULL; uint8_t scfBool; char *indexPtr; char groupName[sizeof (stmfGroupName)]; int ret = STMF_PS_SUCCESS; ret = iPsInit(&handle, &svc); if (ret != STMF_PS_SUCCESS) { goto out; } /* * Allocate scf resources */ if (((pg = scf_pg_create(handle)) == NULL) || ((prop = scf_property_create(handle)) == NULL) || ((value = scf_value_create(handle)) == NULL)) { syslog(LOG_ERR, "scf alloc resource failed - %s", scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } bzero(viewEntry, sizeof (stmfViewEntry)); /* * get the service property group view entry handle */ if (scf_service_get_pg(svc, viewEntryPgName, pg) == -1) { if (scf_error() == SCF_ERROR_NOT_FOUND) { ret = STMF_PS_ERROR_NOT_FOUND; } else { syslog(LOG_ERR, "get pg %s failed - %s", viewEntryPgName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; } goto out; } /* * get index * format is: VE--GUID */ indexPtr = strchr(viewEntryPgName, '-'); if (!indexPtr) { ret = STMF_PS_ERROR; goto out; } /* Set the index */ viewEntry->veIndex = atoi(strtok(++indexPtr, "-")); viewEntry->veIndexValid = B_TRUE; /* get allHosts property */ if (scf_pg_get_property(pg, STMF_VE_ALLHOSTS, prop) == -1) { syslog(LOG_ERR, "get property %s/%s failed - %s", viewEntryPgName, STMF_VE_ALLHOSTS, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } if (scf_property_get_value(prop, value) == -1) { syslog(LOG_ERR, "get property %s/%s failed - %s", viewEntryPgName, STMF_VE_ALLHOSTS, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* set allHosts */ if (scf_value_get_boolean(value, (uint8_t *)&scfBool) == -1) { syslog(LOG_ERR, "get property %s/%s failed - %s", viewEntryPgName, STMF_VE_ALLHOSTS, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } viewEntry->allHosts = scfBool; /* get hostGroup property */ if (scf_pg_get_property(pg, STMF_VE_HOSTGROUP, prop) == -1) { syslog(LOG_ERR, "get property %s/%s failed - %s", viewEntryPgName, STMF_VE_HOSTGROUP, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } if (scf_property_get_value(prop, value) == -1) { syslog(LOG_ERR, "get property %s/%s failed - %s", viewEntryPgName, STMF_VE_HOSTGROUP, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } if (scf_value_get_ustring(value, groupName, sizeof (groupName)) == -1) { syslog(LOG_ERR, "get value %s/%s failed - %s", viewEntryPgName, STMF_VE_HOSTGROUP, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* set hostGroup */ bcopy(groupName, viewEntry->hostGroup, strlen(groupName)); /* get allTargets property */ if (scf_pg_get_property(pg, STMF_VE_ALLTARGETS, prop) == -1) { syslog(LOG_ERR, "get property %s/%s failed - %s", viewEntryPgName, STMF_VE_ALLTARGETS, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } if (scf_property_get_value(prop, value) == -1) { syslog(LOG_ERR, "get property value %s/%s failed - %s", viewEntryPgName, STMF_VE_ALLTARGETS, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* set allTargets */ if (scf_value_get_boolean(value, (uint8_t *)&scfBool) == -1) { syslog(LOG_ERR, "get value %s/%s failed - %s", viewEntryPgName, STMF_VE_ALLTARGETS, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } viewEntry->allTargets = scfBool; /* get targetGroup property */ if (scf_pg_get_property(pg, STMF_VE_TARGETGROUP, prop) == -1) { syslog(LOG_ERR, "get property %s/%s failed - %s", viewEntryPgName, STMF_VE_TARGETGROUP, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } if (scf_property_get_value(prop, value) == -1) { syslog(LOG_ERR, "get property value %s/%s failed - %s", viewEntryPgName, STMF_VE_TARGETGROUP, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } if (scf_value_get_ustring(value, groupName, sizeof (groupName)) == -1) { syslog(LOG_ERR, "get value %s/%s failed - %s", viewEntryPgName, STMF_VE_TARGETGROUP, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* set targetGroup */ bcopy(groupName, viewEntry->targetGroup, strlen(groupName)); /* get luNbr property */ if (scf_pg_get_property(pg, STMF_VE_LUNBR, prop) == -1) { syslog(LOG_ERR, "get property %s/%s failed - %s", viewEntryPgName, STMF_VE_LUNBR, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } if (scf_property_get_value(prop, value) == -1) { syslog(LOG_ERR, "get property value %s/%s failed - %s", viewEntryPgName, STMF_VE_LUNBR, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* set luNbr */ if (scf_value_get_opaque(value, (char *)viewEntry->luNbr, sizeof (viewEntry->luNbr)) == -1) { syslog(LOG_ERR, "get opaque value %s/%s failed - %s", viewEntryPgName, STMF_VE_LUNBR, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* set luNbrValid to true since we just got it */ viewEntry->luNbrValid = B_TRUE; out: /* * Free resources */ if (handle != NULL) { scf_handle_destroy(handle); } if (svc != NULL) { scf_service_destroy(svc); } if (pg != NULL) { scf_pg_destroy(pg); } if (value != NULL) { scf_value_destroy(value); } if (prop != NULL) { scf_property_destroy(prop); } return (ret); } /* * psRemoveHostGroupMember * * Remove a host group member from a host group, * * groupName - name of group from which the member is removed * memberName - name of group member to remove * * returns: * STMF_PS_SUCCESS on success * STMF_PS_ERROR_* on failure */ int psRemoveHostGroupMember(char *groupName, char *memberName) { int ret; char groupPropListName[MAXNAMELEN]; char groupPropName[MAXNAMELEN]; ret = iPsGetActualGroupName(STMF_HOST_GROUPS, groupName, groupPropName); if (ret != STMF_PS_SUCCESS) { return (ret); } if (snprintf(groupPropListName, sizeof (groupPropListName), "%s-%s", groupPropName, STMF_MEMBER_LIST_SUFFIX) > sizeof (groupPropListName)) { syslog(LOG_ERR, "buffer overflow on property name %s", groupPropName); return (STMF_PS_ERROR); } return (iPsAddRemoveGroupMember(STMF_HOST_GROUPS, groupPropListName, memberName, REMOVE)); } /* * psRemoveTargetGroupMember * * Remove a target port group member from an target port group, * * groupName - name of group from which the member is removed * memberName - name of group member to remove * * returns: * STMF_PS_SUCCESS on success * STMF_PS_ERROR_* on failure */ int psRemoveTargetGroupMember(char *groupName, char *memberName) { int ret; char groupPropListName[MAXNAMELEN]; char groupPropName[MAXNAMELEN]; ret = iPsGetActualGroupName(STMF_TARGET_GROUPS, groupName, groupPropName); if (ret != STMF_PS_SUCCESS) { return (ret); } if (snprintf(groupPropListName, sizeof (groupPropListName), "%s-%s", groupPropName, STMF_MEMBER_LIST_SUFFIX) > sizeof (groupPropListName)) { syslog(LOG_ERR, "buffer overflow on property name %s", groupPropName); return (STMF_PS_ERROR); } return (iPsAddRemoveGroupMember(STMF_TARGET_GROUPS, groupPropListName, memberName, REMOVE)); } /* * psGetProviderData * * Retrieves an nvlist on a per provider basis * * providerName - property group name to use * nvl - nvlist to retrieve * */ int psGetProviderData(char *providerName, nvlist_t **nvl, int providerType, uint64_t *setToken) { scf_handle_t *handle = NULL; scf_service_t *svc = NULL; scf_propertygroup_t *pg = NULL; scf_property_t *prop = NULL; scf_value_t *value = NULL; uint64_t blockCnt = 0; ssize_t blockOffset = 0; ssize_t actualBlockSize = 0; char pgName[MAXPATHLEN]; char dataPropertyName[STMF_PROVIDER_DATA_PROP_NAME_SIZE]; char *nvlistEncoded = NULL; ssize_t nvlistEncodedSize = 0; boolean_t foundSetCnt = B_TRUE; int i; int ret = STMF_PS_SUCCESS; if (providerName == NULL || (providerType != STMF_LU_PROVIDER_TYPE && providerType != STMF_PORT_PROVIDER_TYPE)) { ret = STMF_PS_ERROR_INVALID_ARG; goto out; } ret = iPsInit(&handle, &svc); if (ret != STMF_PS_SUCCESS) { goto out; } /* * create the property group name */ (void) snprintf(pgName, sizeof (pgName), "%s%s", STMF_PROVIDER_DATA_PREFIX, providerName); /* * Allocate scf resources */ if (((pg = scf_pg_create(handle)) == NULL) || ((value = scf_value_create(handle)) == NULL) || ((prop = scf_property_create(handle)) == NULL)) { syslog(LOG_ERR, "scf alloc resource failed - %s", scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* * Retrieve the existing property group. */ if (scf_service_get_pg(svc, pgName, pg) == -1) { if (scf_error() != SCF_ERROR_NOT_FOUND) { syslog(LOG_ERR, "get pg %s failed - %s", pgName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } else { ret = STMF_PS_ERROR_NOT_FOUND; goto out; } } /* * Get the STMF_PROVIDER_DATA_PROP_COUNT property */ if (scf_pg_get_property(pg, STMF_PROVIDER_DATA_PROP_COUNT, prop) == -1) { syslog(LOG_ERR, "get property %s/%s failed - %s", pgName, STMF_PROVIDER_DATA_PROP_COUNT, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* * Get the STMF_PROVIDER_DATA_PROP_COUNT value */ if (scf_property_get_value(prop, value) == -1) { syslog(LOG_ERR, "get property value %s/%s failed - %s", pgName, STMF_PROVIDER_DATA_PROP_COUNT, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* * Now get the actual value from the value handle */ if (scf_value_get_count(value, &blockCnt) == -1) { syslog(LOG_ERR, "get integer value %s/%s failed - %s", pgName, STMF_PROVIDER_DATA_PROP_COUNT, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* Has the caller requested the token to be set? */ if (setToken) { /* * Get the STMF_PROVIDER_DATA_PROP_SET_COUNT property * If it doesn't exist, we assume it to be zero. */ *setToken = 0; if (scf_pg_get_property(pg, STMF_PROVIDER_DATA_PROP_SET_COUNT, prop) == -1) { if (scf_error() == SCF_ERROR_NOT_FOUND) { foundSetCnt = B_FALSE; } else { syslog(LOG_ERR, "get property %s/%s " "failed - %s", pgName, STMF_PROVIDER_DATA_PROP_SET_COUNT, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } } if (foundSetCnt) { /* * Get the STMF_PROVIDER_DATA_PROP_SET_COUNT value */ if (scf_property_get_value(prop, value) == -1) { syslog(LOG_ERR, "get property value %s/%s failed - %s", pgName, STMF_PROVIDER_DATA_PROP_SET_COUNT, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* * Now get the actual value from the value handle * and set the caller's token */ if (scf_value_get_count(value, setToken) == -1) { syslog(LOG_ERR, "get integer value %s/%s failed - %s", pgName, STMF_PROVIDER_DATA_PROP_SET_COUNT, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } } } nvlistEncoded = (char *)calloc(1, blockCnt * STMF_PROVIDER_DATA_PROP_SIZE); if (nvlistEncoded == NULL) { syslog(LOG_ERR, "nvlistEncoded alloc failed"); ret = STMF_PS_ERROR_NOMEM; goto out; } for (i = 0; i < blockCnt; i++) { bzero(dataPropertyName, sizeof (dataPropertyName)); /* * create the name to use for the property */ (void) snprintf(dataPropertyName, sizeof (dataPropertyName), "%s-%d", STMF_PROVIDER_DATA_PROP_PREFIX, i); if (scf_pg_get_property(pg, dataPropertyName, prop) == -1) { syslog(LOG_ERR, "get property %s/%s failed - %s", pgName, dataPropertyName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } if (scf_property_get_value(prop, value) == -1) { syslog(LOG_ERR, "get property value %s/%s failed - %s", pgName, dataPropertyName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* * Set the data block offset */ blockOffset = STMF_PROVIDER_DATA_PROP_SIZE * i; actualBlockSize = scf_value_get_opaque(value, &nvlistEncoded[blockOffset], STMF_PROVIDER_DATA_PROP_SIZE); if (actualBlockSize == -1) { syslog(LOG_ERR, "get opaque property value %s/%s " "failed - %s", pgName, dataPropertyName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } nvlistEncodedSize += actualBlockSize; } if (nvlist_unpack(nvlistEncoded, nvlistEncodedSize, nvl, 0) != 0) { syslog(LOG_ERR, "unable to unpack nvlist"); ret = STMF_PS_ERROR; goto out; } out: /* * Free resources */ if (handle != NULL) { scf_handle_destroy(handle); } if (svc != NULL) { scf_service_destroy(svc); } if (pg != NULL) { scf_pg_destroy(pg); } if (prop != NULL) { scf_property_destroy(prop); } if (value != NULL) { scf_value_destroy(value); } if (nvlistEncoded != NULL) { free(nvlistEncoded); } return (ret); } /* * psGetProviderDataList * * Retrieves the list of providers that currently store persistent data * * providerList - pointer to a pointer to an stmfProviderList structure * On success, this will contain the list of providers * currently storing persistent data. */ int psGetProviderDataList(stmfProviderList **providerList) { scf_handle_t *handle = NULL; scf_service_t *svc = NULL; scf_propertygroup_t *pg = NULL; scf_property_t *prop = NULL; scf_value_t *value = NULL; scf_iter_t *pgIter = NULL; char buf[MAXNAMELEN]; int providerCnt = 0; int64_t providerType; int i = 0, j; int ret = STMF_PS_SUCCESS; ret = iPsInit(&handle, &svc); if (ret != STMF_PS_SUCCESS) { goto out; } *providerList = NULL; /* * Allocate scf resources */ if (((pg = scf_pg_create(handle)) == NULL) || ((value = scf_value_create(handle)) == NULL) || ((prop = scf_property_create(handle)) == NULL) || ((pgIter = scf_iter_create(handle)) == NULL)) { syslog(LOG_ERR, "scf alloc resource failed - %s", scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* * pgIter is the iterator handle */ if (scf_iter_service_pgs(pgIter, svc) == -1) { syslog(LOG_ERR, "iter property groups failed - %s", scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } while (scf_iter_next_pg(pgIter, pg) == 1) { if (scf_pg_get_name(pg, buf, sizeof (buf)) == -1) { syslog(LOG_ERR, "get name failed - %s", scf_strerror(scf_error())); ret = STMF_PS_ERROR; break; } /* * Only count LU property groups */ if (strncmp(buf, STMF_PROVIDER_DATA_PREFIX, strlen(STMF_PROVIDER_DATA_PREFIX)) == 0) { providerCnt++; } } /* * pgIter is the iterator handle */ if (scf_iter_service_pgs(pgIter, svc) == -1) { syslog(LOG_ERR, "iter property groups failed - %s", scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } *providerList = (stmfProviderList *)calloc(1, sizeof (stmfProviderList) + providerCnt * sizeof (stmfProvider)); if (*providerList == NULL) { ret = STMF_PS_ERROR_NOMEM; goto out; } /* * it's possible for entries to be added/removed while we're retrieving * the property groups. Just make sure we don't write beyond our * allocated buffer by checking to ensure i < providerCnt. */ while ((scf_iter_next_pg(pgIter, pg) == 1) && (i < providerCnt)) { if (scf_pg_get_name(pg, buf, sizeof (buf)) == -1) { syslog(LOG_ERR, "get name failed - %s", scf_strerror(scf_error())); ret = STMF_PS_ERROR; break; } /* * Only use provider data property groups */ if (strncmp(buf, STMF_PROVIDER_DATA_PREFIX, strlen(STMF_PROVIDER_DATA_PREFIX)) != 0) { continue; } /* * Get the STMF_PROVIDER_DATA_PROP_TYPE property */ if (scf_pg_get_property(pg, STMF_PROVIDER_DATA_PROP_TYPE, prop) == -1) { syslog(LOG_ERR, "get property %s/%s failed - %s", buf, STMF_PROVIDER_DATA_PROP_TYPE, scf_strerror(scf_error())); ret = STMF_PS_ERROR; break; } /* * Get the STMF_PROVIDER_DATA_PROP_TYPE value */ if (scf_property_get_value(prop, value) == -1) { syslog(LOG_ERR, "get property value %s/%s failed - %s", buf, STMF_PROVIDER_DATA_PROP_TYPE, scf_strerror(scf_error())); ret = STMF_PS_ERROR; break; } /* * Now get the actual value from the value handle */ if (scf_value_get_integer(value, &providerType) == -1) { syslog(LOG_ERR, "get integer value %s/%s failed - %s", buf, STMF_PROVIDER_DATA_PROP_TYPE, scf_strerror(scf_error())); ret = STMF_PS_ERROR; break; } (*providerList)->provider[i].providerType = providerType; /* determine offset for copy of provider name */ j = strlen(STMF_PROVIDER_DATA_PREFIX); /* copy provider name to caller's list */ (void) strncpy((*providerList)->provider[i].name, buf + j, sizeof ((*providerList)->provider[i].name)); i++; (*providerList)->cnt++; } if (ret != STMF_PS_SUCCESS) { free(*providerList); goto out; } out: /* * Free resources */ if (handle != NULL) { scf_handle_destroy(handle); } if (svc != NULL) { scf_service_destroy(svc); } if (pg != NULL) { scf_pg_destroy(pg); } if (value != NULL) { scf_value_destroy(value); } if (prop != NULL) { scf_property_destroy(prop); } if (pgIter != NULL) { scf_iter_destroy(pgIter); } return (ret); } /* * psSetProviderData * * Stores a packed nvlist on a per provider basis * * providerName - property group name to use * nvl - nvlist to store * providerType - type of provider (logical unit or port) * */ int psSetProviderData(char *providerName, nvlist_t *nvl, int providerType, uint64_t *setToken) { scf_handle_t *handle = NULL; scf_service_t *svc = NULL; scf_propertygroup_t *pg = NULL; scf_property_t *prop = NULL; scf_transaction_t *tran = NULL; /* represents arrays of entry and value pointers for scf */ scf_transaction_entry_t **addEntry = NULL; scf_transaction_entry_t **deleteEntry = NULL; scf_value_t **addValue = NULL; /* * These declarations are for known entry and value set/get * operations */ scf_transaction_entry_t *entry1 = NULL; scf_transaction_entry_t *entry2 = NULL; scf_transaction_entry_t *entry3 = NULL; scf_transaction_entry_t *entry5 = NULL; scf_value_t *value1 = NULL; scf_value_t *value2 = NULL; scf_value_t *value3 = NULL; scf_value_t *value4 = NULL; scf_value_t *value5 = NULL; boolean_t newPg = B_FALSE; char pgName[MAXPATHLEN]; char dataPropertyName[STMF_PROVIDER_DATA_PROP_NAME_SIZE]; char *nvlistEncoded = NULL; size_t nvlistEncodedSize; size_t blockSize; int i, j = 0; int addEntryAlloc = 0, deleteEntryAlloc = 0, addValueAlloc = 0; int blockOffset; uint64_t oldBlockCnt = 0; uint64_t blockCnt = 0; uint64_t setCnt = 0; boolean_t foundSetCnt = B_TRUE; int ret = STMF_PS_SUCCESS; int commitRet; if (providerName == NULL || (providerType != STMF_LU_PROVIDER_TYPE && providerType != STMF_PORT_PROVIDER_TYPE)) { ret = STMF_PS_ERROR_INVALID_ARG; goto out; } ret = iPsInit(&handle, &svc); if (ret != STMF_PS_SUCCESS) { goto out; } bzero(pgName, sizeof (pgName)); /* * create the property group name */ (void) snprintf(pgName, sizeof (pgName), "%s%s", STMF_PROVIDER_DATA_PREFIX, providerName); /* * Allocate scf resources */ if (((pg = scf_pg_create(handle)) == NULL) || ((entry1 = scf_entry_create(handle)) == NULL) || ((entry2 = scf_entry_create(handle)) == NULL) || ((entry3 = scf_entry_create(handle)) == NULL) || ((entry5 = scf_entry_create(handle)) == NULL) || ((value1 = scf_value_create(handle)) == NULL) || ((value2 = scf_value_create(handle)) == NULL) || ((value3 = scf_value_create(handle)) == NULL) || ((value4 = scf_value_create(handle)) == NULL) || ((value5 = scf_value_create(handle)) == NULL) || ((prop = scf_property_create(handle)) == NULL) || ((tran = scf_transaction_create(handle)) == NULL)) { syslog(LOG_ERR, "scf alloc resource failed - %s", scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* * Get the existing property group */ if (scf_service_get_pg(svc, pgName, pg) == -1) { if (scf_error() != SCF_ERROR_NOT_FOUND) { syslog(LOG_ERR, "get pg %s failed - %s", pgName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } else { /* * create the property group. */ if (scf_service_add_pg(svc, pgName, SCF_GROUP_APPLICATION, 0, pg) == -1) { syslog(LOG_ERR, "add pg %s failed - %s", pgName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } newPg = B_TRUE; } } /* * Begin the transaction */ if (scf_transaction_start(tran, pg) == -1) { syslog(LOG_ERR, "start transaction for %s failed - %s", pgName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } if (!newPg) { /* * Get the STMF_PROVIDER_DATA_PROP_COUNT property */ if (scf_pg_get_property(pg, STMF_PROVIDER_DATA_PROP_COUNT, prop) == -1) { syslog(LOG_ERR, "get property %s/%s failed - %s", pgName, STMF_PROVIDER_DATA_PROP_COUNT, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* * Get the STMF_PROVIDER_DATA_PROP_COUNT value */ if (scf_property_get_value(prop, value4) == -1) { syslog(LOG_ERR, "get property value %s/%s failed - %s", pgName, STMF_PROVIDER_DATA_PROP_COUNT, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* * Now get the actual value from the value handle */ if (scf_value_get_count(value4, &oldBlockCnt) == -1) { syslog(LOG_ERR, "get integer value %s/%s failed - %s", pgName, STMF_PROVIDER_DATA_PROP_COUNT, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } } /* * Get the STMF_PROVIDER_DATA_PROP_SET_COUNT property * If it doesn't exist, we'll create it later after successfully * setting the data. */ if (scf_pg_get_property(pg, STMF_PROVIDER_DATA_PROP_SET_COUNT, prop) == -1) { if (scf_error() == SCF_ERROR_NOT_FOUND) { foundSetCnt = B_FALSE; } else { syslog(LOG_ERR, "get property %s/%s failed - %s", pgName, STMF_PROVIDER_DATA_PROP_SET_COUNT, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } } if (foundSetCnt) { /* * Get the STMF_PROVIDER_DATA_PROP_SET_COUNT value */ if (scf_property_get_value(prop, value5) == -1) { syslog(LOG_ERR, "get property value %s/%s failed - %s", pgName, STMF_PROVIDER_DATA_PROP_SET_COUNT, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* * Now get the actual value from the value handle */ if (scf_value_get_count(value5, &setCnt) == -1) { syslog(LOG_ERR, "get integer value %s/%s failed - %s", pgName, STMF_PROVIDER_DATA_PROP_SET_COUNT, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* * Compare the setCnt prop to the caller's. */ if (setToken && (*setToken != setCnt)) { ret = STMF_PS_ERROR_PROV_DATA_STALE; goto out; } } setCnt++; /* * prepare the list for writing */ if (nvlist_pack(nvl, &nvlistEncoded, &nvlistEncodedSize, NV_ENCODE_XDR, 0) != 0) { syslog(LOG_ERR, "nvlist_pack for %s failed", pgName); ret = STMF_PS_ERROR_NOMEM; goto out; } /* Determine how many chunks we need to write */ blockCnt = nvlistEncodedSize/STMF_PROVIDER_DATA_PROP_SIZE; if (nvlistEncodedSize % STMF_PROVIDER_DATA_PROP_SIZE) blockCnt++; /* allocate entry and value resources for writing those chunks */ addEntry = (scf_transaction_entry_t **)calloc(1, sizeof (*addEntry) * blockCnt); if (addEntry == NULL) { syslog(LOG_ERR, "addEntry alloc for %s failed", pgName); ret = STMF_PS_ERROR_NOMEM; goto out; } addValue = (scf_value_t **)calloc(1, sizeof (*addValue) * blockCnt); if (addValue == NULL) { syslog(LOG_ERR, "value alloc for %s failed", pgName); ret = STMF_PS_ERROR_NOMEM; goto out; } /* * allocate entry delete resources for deleting anything existing * that is more than the new block count. We could leave them around * without suffering any ill effects but it will be cleaner to look at * in smf tools if they are deleted. */ if (oldBlockCnt > blockCnt) { deleteEntry = (scf_transaction_entry_t **)calloc(1, sizeof (*deleteEntry) * (oldBlockCnt - blockCnt)); if (deleteEntry == NULL) { syslog(LOG_ERR, "deleteEntry alloc for %s failed", pgName); ret = STMF_PS_ERROR_NOMEM; goto out; } deleteEntryAlloc = oldBlockCnt - blockCnt; } for (i = 0; i < blockCnt; i++) { /* * Create the entry resource for the prop */ addEntry[i] = scf_entry_create(handle); if (addEntry[i] == NULL) { syslog(LOG_ERR, "scf value alloc for %s failed - %s", pgName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* bump alloc count for addEntry allocation */ addEntryAlloc++; /* * create the name to use for the property */ (void) snprintf(dataPropertyName, sizeof (dataPropertyName), "%s-%d", STMF_PROVIDER_DATA_PROP_PREFIX, i); /* * Create the new property */ if (scf_transaction_property_new(tran, addEntry[i], dataPropertyName, SCF_TYPE_OPAQUE) == -1) { if (scf_error() == SCF_ERROR_EXISTS) { if (scf_transaction_property_change(tran, addEntry[i], dataPropertyName, SCF_TYPE_OPAQUE) == -1) { syslog(LOG_ERR, "transaction property " "change %s/%s failed - %s", pgName, dataPropertyName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } } else { syslog(LOG_ERR, "transaction property new %s/%s " "failed - %s", pgName, dataPropertyName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } } /* * Create the value resource for the prop */ addValue[i] = scf_value_create(handle); if (addValue[i] == NULL) { syslog(LOG_ERR, "scf value alloc for %s failed - %s", pgName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* bump alloc count for addValue allocation */ addValueAlloc++; /* * Set the data block offset and size */ if ((STMF_PROVIDER_DATA_PROP_SIZE * (i + 1)) > nvlistEncodedSize) { blockSize = nvlistEncodedSize - STMF_PROVIDER_DATA_PROP_SIZE * i; } else { blockSize = STMF_PROVIDER_DATA_PROP_SIZE; } blockOffset = STMF_PROVIDER_DATA_PROP_SIZE * i; if (scf_value_set_opaque(addValue[i], &nvlistEncoded[blockOffset], blockSize) == -1) { syslog(LOG_ERR, "set value for %s failed - %s", pgName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* * Add the data block to the transaction entry */ if (scf_entry_add_value(addEntry[i], addValue[i]) == -1) { syslog(LOG_ERR, "add value for %s failed - %s", pgName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } } /* * Now we need to delete any chunks (properties) that are no longer * needed. Iterate through the rest of the chunks deleting each. */ for (i = blockCnt; i < oldBlockCnt; i++) { /* * Create the entry resource for the prop */ deleteEntry[j] = scf_entry_create(handle); if (deleteEntry[j] == NULL) { syslog(LOG_ERR, "scf value alloc for %s failed - %s", pgName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* * create the name to use for the property */ (void) snprintf(dataPropertyName, sizeof (dataPropertyName), "%s-%d", STMF_PROVIDER_DATA_PROP_PREFIX, i); /* * Delete the existing property */ if (scf_transaction_property_delete(tran, deleteEntry[j++], dataPropertyName) == -1) { syslog(LOG_ERR, "delete property %s/%s failed - %s", pgName, dataPropertyName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } } if (newPg) { /* * Ensure the read_authorization property is set * for the group */ if (scf_transaction_property_new(tran, entry1, "read_authorization", SCF_TYPE_ASTRING) == -1) { syslog(LOG_ERR, "transaction property %s/%s new " "failed - %s", pgName, "read_authorization", scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } if (scf_value_set_astring(value1, STMF_SMF_READ_ATTR) == -1) { syslog(LOG_ERR, "set value %s/%s failed - %s", pgName, "read_authorization", scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } if (scf_entry_add_value(entry1, value1) == -1) { syslog(LOG_ERR, "add value %s/%s failed - %s", pgName, "read_authorization", scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } } /* create or change the count property */ if (scf_transaction_property_new(tran, entry2, STMF_PROVIDER_DATA_PROP_COUNT, SCF_TYPE_COUNT) == -1) { if (scf_error() == SCF_ERROR_EXISTS) { if (scf_transaction_property_change(tran, entry2, STMF_PROVIDER_DATA_PROP_COUNT, SCF_TYPE_COUNT) == -1) { syslog(LOG_ERR, "transaction property change " "%s/%s failed - %s", pgName, STMF_PROVIDER_DATA_PROP_COUNT, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } } else { syslog(LOG_ERR, "transaction property %s/%s new " "failed - %s", pgName, STMF_PROVIDER_DATA_PROP_COUNT, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } } scf_value_set_count(value2, blockCnt); if (scf_entry_add_value(entry2, value2) == -1) { syslog(LOG_ERR, "add value %s/%s failed - %s", pgName, STMF_PROVIDER_DATA_PROP_COUNT, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* create or change the set count property */ if (scf_transaction_property_new(tran, entry5, STMF_PROVIDER_DATA_PROP_SET_COUNT, SCF_TYPE_COUNT) == -1) { if (scf_error() == SCF_ERROR_EXISTS) { if (scf_transaction_property_change(tran, entry5, STMF_PROVIDER_DATA_PROP_SET_COUNT, SCF_TYPE_COUNT) == -1) { syslog(LOG_ERR, "transaction property change %s/%s " "failed - %s", pgName, STMF_PROVIDER_DATA_PROP_SET_COUNT, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } } else { syslog(LOG_ERR, "transaction property new %s/%s " "failed - %s", pgName, STMF_PROVIDER_DATA_PROP_SET_COUNT, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } } scf_value_set_count(value5, setCnt); if (scf_entry_add_value(entry5, value5) == -1) { syslog(LOG_ERR, "add value %s/%s failed - %s", pgName, STMF_PROVIDER_DATA_PROP_SET_COUNT, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* create or change the provider type property */ if (scf_transaction_property_new(tran, entry3, STMF_PROVIDER_DATA_PROP_TYPE, SCF_TYPE_INTEGER) == -1) { if (scf_error() == SCF_ERROR_EXISTS) { if (scf_transaction_property_change(tran, entry3, STMF_PROVIDER_DATA_PROP_TYPE, SCF_TYPE_INTEGER) == -1) { syslog(LOG_ERR, "transaction property change %s/%s " "failed - %s", pgName, STMF_PROVIDER_DATA_PROP_TYPE, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } } else { syslog(LOG_ERR, "transaction property new %s/%s " "failed - %s", pgName, STMF_PROVIDER_DATA_PROP_TYPE, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } } switch (providerType) { case STMF_PORT_PROVIDER_TYPE: case STMF_LU_PROVIDER_TYPE: scf_value_set_integer(value3, providerType); break; default: ret = STMF_PS_ERROR; goto out; } if (scf_entry_add_value(entry3, value3) == -1) { syslog(LOG_ERR, "add value %s/%s failed - %s", pgName, STMF_PROVIDER_DATA_PROP_TYPE, scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } if ((commitRet = scf_transaction_commit(tran)) != 1) { syslog(LOG_ERR, "transaction commit for %s failed - %s", pgName, scf_strerror(scf_error())); if (commitRet == 0) { ret = STMF_PS_ERROR_BUSY; } else { ret = STMF_PS_ERROR; } goto out; } /* pass the new token back to the caller if requested */ if (ret == STMF_PS_SUCCESS && setToken) { *setToken = setCnt; } out: /* * Free resources */ if (handle != NULL) { scf_handle_destroy(handle); } if (svc != NULL) { scf_service_destroy(svc); } if (pg != NULL) { scf_pg_destroy(pg); } if (prop != NULL) { scf_property_destroy(prop); } if (tran != NULL) { scf_transaction_destroy(tran); } for (i = 0; i < addEntryAlloc; i++) { scf_entry_destroy(addEntry[i]); } for (i = 0; i < addValueAlloc; i++) { scf_value_destroy(addValue[i]); } free(addValue); free(addEntry); for (i = 0; i < deleteEntryAlloc; i++) { scf_entry_destroy(deleteEntry[i]); } free(deleteEntry); if (entry1 != NULL) { scf_entry_destroy(entry1); } if (entry2 != NULL) { scf_entry_destroy(entry2); } if (entry3 != NULL) { scf_entry_destroy(entry3); } if (entry5 != NULL) { scf_entry_destroy(entry5); } if (value1 != NULL) { scf_value_destroy(value1); } if (value2 != NULL) { scf_value_destroy(value2); } if (value3 != NULL) { scf_value_destroy(value3); } if (value4 != NULL) { scf_value_destroy(value4); } if (value5 != NULL) { scf_value_destroy(value5); } if (nvlistEncoded != NULL) { free(nvlistEncoded); } return (ret); } /* * psGetViewEntry * * Purpose: Get a single view entry based on the logical unit identifier and * view entry index * * lu - logical unit identifier * viewEntryIndex - index of view entry * ve - caller allocated stmfViewEntry structure. On success, this will * contain the retrieved view entry */ int psGetViewEntry(stmfGuid *lu, uint32_t viewEntryIndex, stmfViewEntry *ve) { scf_handle_t *handle = NULL; scf_service_t *svc = NULL; scf_propertygroup_t *pg = NULL; char guidAsciiBuf[33]; /* size of ascii hex 16 byte guid with NULL */ char viewEntryPgName[VIEW_ENTRY_PG_SIZE]; char luPgName[LOGICAL_UNIT_PG_SIZE]; int ret = STMF_PS_SUCCESS; ret = iPsInit(&handle, &svc); if (ret != STMF_PS_SUCCESS) { goto out; } pg = scf_pg_create(handle); if (pg == NULL) { syslog(LOG_ERR, "scf pg alloc failed - %s", scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* Convert to ASCII uppercase hexadecimal string */ (void) snprintf(guidAsciiBuf, sizeof (guidAsciiBuf), "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", lu->guid[0], lu->guid[1], lu->guid[2], lu->guid[3], lu->guid[4], lu->guid[5], lu->guid[6], lu->guid[7], lu->guid[8], lu->guid[9], lu->guid[10], lu->guid[11], lu->guid[12], lu->guid[13], lu->guid[14], lu->guid[15]); (void) snprintf(luPgName, sizeof (luPgName), "%s-%s", STMF_LU_PREFIX, guidAsciiBuf); /* * Format of view entry property group name: * VE-- */ (void) snprintf(viewEntryPgName, sizeof (viewEntryPgName), "%s-%d-%s", STMF_VE_PREFIX, viewEntryIndex, guidAsciiBuf); if (scf_service_get_pg(svc, viewEntryPgName, pg) == -1) { if (scf_error() == SCF_ERROR_NOT_FOUND) { ret = STMF_PS_ERROR_NOT_FOUND; } else { syslog(LOG_ERR, "get pg %s failed - %s", viewEntryPgName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; } goto out; } if ((ret = iPsGetViewEntry(viewEntryPgName, ve)) != STMF_PS_SUCCESS) { ret = STMF_PS_ERROR; goto out; } out: /* * Free resources */ if (handle != NULL) { scf_handle_destroy(handle); } if (svc != NULL) { scf_service_destroy(svc); } if (pg != NULL) { scf_pg_destroy(pg); } return (ret); } /* * psRemoveViewEntry * * Remove a view entry * * luGuid - identifier of logical unit from which to remove view entry * viewEntryIndex - view entry name to remove * * returns: * STMF_PS_SUCCESS on success * STMF_PS_ERROR_* on failure */ int psRemoveViewEntry(stmfGuid *lu, uint32_t viewEntryIndex) { scf_handle_t *handle = NULL; scf_service_t *svc = NULL; scf_propertygroup_t *pg = NULL; char guidAsciiBuf[33]; /* size of ascii hex 16 byte guid with NULL */ char viewEntryPgName[VIEW_ENTRY_PG_SIZE]; char luPgName[LOGICAL_UNIT_PG_SIZE]; int ret = STMF_PS_SUCCESS; sigset_t sigmaskRestore; /* grab the signal hold lock */ (void) pthread_mutex_lock(&sigSetLock); /* * hold signals until we're done */ if (holdSignal(&sigmaskRestore) != 0) { (void) pthread_mutex_unlock(&sigSetLock); return (STMF_PS_ERROR); } ret = iPsInit(&handle, &svc); if (ret != STMF_PS_SUCCESS) { goto out; } pg = scf_pg_create(handle); if (pg == NULL) { syslog(LOG_ERR, "scf pg alloc failed - %s", scf_strerror(scf_error())); ret = STMF_PS_ERROR; goto out; } /* Convert to ASCII uppercase hexadecimal string */ (void) snprintf(guidAsciiBuf, sizeof (guidAsciiBuf), "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", lu->guid[0], lu->guid[1], lu->guid[2], lu->guid[3], lu->guid[4], lu->guid[5], lu->guid[6], lu->guid[7], lu->guid[8], lu->guid[9], lu->guid[10], lu->guid[11], lu->guid[12], lu->guid[13], lu->guid[14], lu->guid[15]); (void) snprintf(luPgName, sizeof (luPgName), "%s-%s", STMF_LU_PREFIX, guidAsciiBuf); /* * Format of view entry property group name: * VE-- */ (void) snprintf(viewEntryPgName, sizeof (viewEntryPgName), "%s-%d-%s", STMF_VE_PREFIX, viewEntryIndex, guidAsciiBuf); if (scf_service_get_pg(svc, viewEntryPgName, pg) == -1) { if (scf_error() == SCF_ERROR_NOT_FOUND) { ret = STMF_PS_ERROR_NOT_FOUND; } else { syslog(LOG_ERR, "get pg %s failed - %s", viewEntryPgName, scf_strerror(scf_error())); ret = STMF_PS_ERROR; } goto out; } /* * update the logical unit property group to remove * the view entry and update the view entry count * If it fails, we won't delete the property group so that * we maintain consistency. */ if ((ret = iPsAddRemoveLuViewEntry(luPgName, viewEntryPgName, REMOVE)) != STMF_PS_SUCCESS) { goto out; } /* * Delete the view entry. If this fails, we should try to add * the logical unit view entry property group back otherwise * we're inconsistent. */ if (scf_pg_delete(pg) == -1) { syslog(LOG_ERR, "delete pg %s failed - %s", viewEntryPgName, scf_strerror(scf_error())); if ((ret = iPsAddRemoveLuViewEntry(luPgName, viewEntryPgName, ADD)) != STMF_PS_SUCCESS) { syslog(LOG_ERR, "add of view entry %s failed, possible" "inconsistency - %s", viewEntryPgName, scf_strerror(scf_error())); } ret = STMF_PS_ERROR; goto out; } out: /* * Okay, we're done. Release the signals */ if (releaseSignal(&sigmaskRestore) != 0) { /* * Don't set this as an STMF_PS_ERROR_*. We succeeded * the requested operation. But we do need to log it. */ syslog(LOG_ERR, "Unable to release one or more signals - %s", strerror(errno)); } /* * Free resources */ if (handle != NULL) { scf_handle_destroy(handle); } if (svc != NULL) { scf_service_destroy(svc); } if (pg != NULL) { scf_pg_destroy(pg); } /* release the signal hold lock */ (void) pthread_mutex_unlock(&sigSetLock); return (ret); } /* * holdSignal * * Hold SIGINT, SIGTERM, SIGQUIT until further notice. * * Saves old signal mask on a per thread basis * and saves action for the process. * * Installs action for above signals. * * locks held: sigSetLock * * returns: * 0 on success * non-zero otherwise */ static int holdSignal(sigset_t *sigmaskRestore) { struct sigaction act; sigset_t sigmask; /* * Return existing signal mask for this thread */ if (pthread_sigmask(0, NULL, sigmaskRestore) != 0) { return (1); } (void) sigemptyset(&act.sa_mask); act.sa_handler = sigHandler; act.sa_flags = 0; /* * Have we set the actions for the signals we want to catch? */ if (!actionSet) { if (sigaction(SIGQUIT, &act, ¤tActionQuit) != 0) { return (1); } if (sigaction(SIGINT, &act, ¤tActionInt) != 0) { return (1); } if (sigaction(SIGTERM, &act, ¤tActionTerm) != 0) { return (1); } actionSet = B_TRUE; } /* * We still need to change the mask for the current thread */ if (sigfillset(&sigmask) != 0) { return (1); } (void) sigdelset(&sigmask, SIGQUIT); (void) sigdelset(&sigmask, SIGINT); (void) sigdelset(&sigmask, SIGTERM); if (pthread_sigmask(SIG_SETMASK, &sigmask, NULL) != 0) { return (1); } return (0); } /* * releaseSignal * * Re-install the original signal mask and signal actions * * Also, raise any signals that were caught during the hold period and clear * the signal from the caught set (signalsCaught). * * locks held: sigSetLock * * Returns * 0 on success * non-zero otherwise */ static int releaseSignal(sigset_t *sigmaskRestore) { int ret = 0; if (sigaction(SIGQUIT, ¤tActionQuit, NULL) != 0) { ret = 1; } if (sigaction(SIGINT, ¤tActionInt, NULL) != 0) { ret = 1; } if (sigaction(SIGTERM, ¤tActionTerm, NULL) != 0) { ret = 1; } actionSet = B_FALSE; /* * Restore previous signal mask for this thread */ if (pthread_sigmask(SIG_SETMASK, sigmaskRestore, NULL) != 0) { syslog(LOG_ERR, "Unable to restore sigmask"); } /* * Now raise signals that were raised while we were held */ if (sigismember(&signalsCaught, SIGTERM)) { (void) sigdelset(&signalsCaught, SIGTERM); (void) raise(SIGTERM); } if (sigismember(&signalsCaught, SIGINT)) { (void) sigdelset(&signalsCaught, SIGINT); (void) raise(SIGINT); } if (sigismember(&signalsCaught, SIGQUIT)) { (void) sigdelset(&signalsCaught, SIGQUIT); (void) raise(SIGQUIT); } return (ret); }