diff options
| author | John Forte <John.Forte@Sun.COM> | 2008-10-14 15:09:13 -0700 |
|---|---|---|
| committer | John Forte <John.Forte@Sun.COM> | 2008-10-14 15:09:13 -0700 |
| commit | fcf3ce441efd61da9bb2884968af01cb7c1452cc (patch) | |
| tree | 0e80d59ad41702571586195bf099ccc14222ce02 /usr/src/lib/libstmf/common | |
| parent | 247b82a1f1cb5ebd2d163bd9afdb1a3065611962 (diff) | |
| download | illumos-joyent-fcf3ce441efd61da9bb2884968af01cb7c1452cc.tar.gz | |
6745433 Merge NWS consolidation into OS/Net consolidation
Diffstat (limited to 'usr/src/lib/libstmf/common')
| -rw-r--r-- | usr/src/lib/libstmf/common/libstmf.h | 300 | ||||
| -rw-r--r-- | usr/src/lib/libstmf/common/llib-lstmf | 30 | ||||
| -rw-r--r-- | usr/src/lib/libstmf/common/mapfile-vers | 72 | ||||
| -rw-r--r-- | usr/src/lib/libstmf/common/stmf.c | 3376 | ||||
| -rw-r--r-- | usr/src/lib/libstmf/common/store.c | 4747 | ||||
| -rw-r--r-- | usr/src/lib/libstmf/common/store.h | 81 |
6 files changed, 8606 insertions, 0 deletions
diff --git a/usr/src/lib/libstmf/common/libstmf.h b/usr/src/lib/libstmf/common/libstmf.h new file mode 100644 index 0000000000..99d27a705b --- /dev/null +++ b/usr/src/lib/libstmf/common/libstmf.h @@ -0,0 +1,300 @@ +/* + * 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 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _LIBSTMF_H +#define _LIBSTMF_H + +#include <time.h> +#include <sys/param.h> +#include <libnvpair.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* Constants and Types */ + +/* LU and Local Port states */ +#define STMF_LOGICAL_UNIT_OFFLINE 0 +#define STMF_LOGICAL_UNIT_OFFLINING 1 +#define STMF_LOGICAL_UNIT_ONLINE 2 +#define STMF_LOGICAL_UNIT_ONLINING 3 +#define STMF_LOGICAL_UNIT_UNREGISTERED 4 +#define STMF_TARGET_PORT_OFFLINE 5 +#define STMF_TARGET_PORT_OFFLINING 6 +#define STMF_TARGET_PORT_ONLINE 7 +#define STMF_TARGET_PORT_ONLINING 8 +#define STMF_SERVICE_STATE_ONLINE 9 +#define STMF_SERVICE_STATE_OFFLINE 10 +#define STMF_SERVICE_STATE_ONLINING 11 +#define STMF_SERVICE_STATE_OFFLINING 12 +#define STMF_SERVICE_STATE_UNKNOWN 13 +#define STMF_CONFIG_STATE_NONE 14 +#define STMF_CONFIG_STATE_INIT 15 +#define STMF_CONFIG_STATE_INIT_DONE 16 +#define STMF_CONFIG_STATE_UNKNOWN 17 + +#define STMF_IDENT_LENGTH 255 + +/* API status return values */ +#define STMF_STATUS_SUCCESS 0x0000 +#define STMF_STATUS_ERROR 0x8000 +#define STMF_ERROR_BUSY (STMF_STATUS_ERROR | 0x01) +#define STMF_ERROR_NOT_FOUND (STMF_STATUS_ERROR | 0x02) +#define STMF_ERROR_MEMBER_NOT_FOUND (STMF_STATUS_ERROR | 0x03) +#define STMF_ERROR_GROUP_NOT_FOUND (STMF_STATUS_ERROR | 0x04) +#define STMF_ERROR_PERM (STMF_STATUS_ERROR | 0x05) +#define STMF_ERROR_NOMEM (STMF_STATUS_ERROR | 0x06) +#define STMF_ERROR_INVALID_ARG (STMF_STATUS_ERROR | 0x07) +#define STMF_ERROR_EXISTS (STMF_STATUS_ERROR | 0x08) +#define STMF_ERROR_SERVICE_NOT_FOUND (STMF_STATUS_ERROR | 0x09) +#define STMF_ERROR_SERVICE_ONLINE (STMF_STATUS_ERROR | 0x0a) +#define STMF_ERROR_SERVICE_OFFLINE (STMF_STATUS_ERROR | 0x0b) +#define STMF_ERROR_GROUP_IN_USE (STMF_STATUS_ERROR | 0x0c) +#define STMF_ERROR_LUN_IN_USE (STMF_STATUS_ERROR | 0x0d) +#define STMF_ERROR_VE_CONFLICT (STMF_STATUS_ERROR | 0x0e) +#define STMF_ERROR_CONFIG_NONE (STMF_STATUS_ERROR | 0x0f) +#define STMF_ERROR_SERVICE_DATA_VERSION (STMF_STATUS_ERROR | 0x10) +#define STMF_ERROR_INVALID_HG (STMF_STATUS_ERROR | 0x11) +#define STMF_ERROR_INVALID_TG (STMF_STATUS_ERROR | 0x12) +#define STMF_ERROR_PROV_DATA_STALE (STMF_STATUS_ERROR | 0x13) + +/* Initiator Name Types */ +#define STMF_FC_PORT_WWN 1 +#define STMF_ISCSI_NAME 2 + +/* protected data flag for provider store */ +#define STMF_PROTECTED_DATA 0x0001 + +/* provider types */ +#define STMF_LU_PROVIDER_TYPE 1 +#define STMF_PORT_PROVIDER_TYPE 2 + + +/* devid code set and name types */ +#define EUI_64_TYPE 2 +#define NAA_TYPE 3 +#define SCSI_NAME_TYPE 8 + +#define BINARY_CODE_SET 1 +#define ASCII_CODE_SET 2 +#define UTF_8_CODE_SET 3 + +typedef enum _stmfProtocol +{ + STMF_PROTOCOL_FIBRE_CHANNEL = 0, + STMF_PROTOCOL_ISCSI = 1, + STMF_PROTOCOL_SAS = 2 +} stmfProtocol; + + +typedef struct _stmfGuid +{ + uchar_t guid[16]; +} stmfGuid; + +typedef struct _stmfGuidList +{ + uint32_t cnt; + stmfGuid guid[1]; +} stmfGuidList; + +typedef struct _stmfState +{ + int operationalState; + int configState; +} stmfState; + +typedef struct _stmfDevid +{ + uint8_t identLength; /* length of ident */ + uint8_t ident[STMF_IDENT_LENGTH]; /* SCSI name string ident */ +} stmfDevid; + +typedef struct _stmfDevidList +{ + uint32_t cnt; + stmfDevid devid[1]; +} stmfDevidList; + +typedef char stmfGroupName[256]; +typedef char stmfProviderName[256]; + +typedef struct _stmfGroupList +{ + uint32_t cnt; + stmfGroupName name[1]; +} stmfGroupList; + +typedef struct _stmfProvider +{ + int providerType; + stmfProviderName name; +} stmfProvider; + +typedef struct _stmfProviderList +{ + uint32_t cnt; + stmfProvider provider[1]; +} stmfProviderList; + +typedef struct _stmfSession +{ + stmfDevid initiator; + char alias[256]; + time_t creationTime; +} stmfSession; + +typedef struct _stmfSessionList +{ + uint32_t cnt; + stmfSession session[1]; +} stmfSessionList; + + +typedef struct _stmfViewEntry +{ + boolean_t veIndexValid; /* if B_TRUE, veIndex is valid value */ + uint32_t veIndex; /* View Entry index */ + boolean_t allHosts; /* all initiator ports */ + stmfGroupName hostGroup; /* Host Group Name */ + boolean_t allTargets; /* B_TRUE = targetGroup is invalid */ + stmfGroupName targetGroup; /* Target Group Name */ + boolean_t luNbrValid; /* if B_TRUE, luNbr is a valid value */ + uchar_t luNbr[8]; /* LU number for this view entry */ +} stmfViewEntry; + +typedef struct _stmfViewEntryList +{ + uint32_t cnt; + stmfViewEntry ve[1]; +} stmfViewEntryList; + +typedef struct _stmfViewEntryProperties +{ + stmfGuid associatedLogicalUnitGuid; + stmfViewEntry viewEntry; +} stmfViewEntryProperties; + +typedef struct _stmfGroupProperties +{ + uint32_t cnt; + stmfDevid name[1]; +} stmfGroupProperties; + +typedef struct _stmfTargetProperties +{ + stmfProviderName providerName; + char alias[256]; + uint16_t status; + stmfProtocol protocol; + stmfDevid devid; +} stmfTargetProperties; + +typedef struct _stmfLogicalUnitProperties +{ + char alias[256]; + uchar_t vendor[8]; + uchar_t product[16]; + uchar_t revision[4]; + uint32_t status; + char providerName[256]; + stmfGuid luid; +} stmfLogicalUnitProperties; + +typedef struct _stmfLogicalUnitProviderProperties +{ + char providerName[MAXPATHLEN]; + uint32_t instance; + uint32_t status; + uchar_t rsvd[64]; +} stmfLogicalUnitProviderProperties; + +typedef struct _stmfLocalPortProviderProperties +{ + char providerName[MAXPATHLEN]; + uint32_t instance; + uint32_t status; + uchar_t rsvd[64]; +} stmfLocalPortProviderProperties; + + +/* API prototypes */ +int stmfAddToHostGroup(stmfGroupName *hostGroupName, stmfDevid *name); +int stmfAddToTargetGroup(stmfGroupName *targetGroupName, stmfDevid *targetName); +int stmfAddViewEntry(stmfGuid *lu, stmfViewEntry *viewEntry); +int stmfClearProviderData(char *providerName, int providerType); +int stmfCreateHostGroup(stmfGroupName *hostGroupName); +int stmfCreateTargetGroup(stmfGroupName *targetGroupName); +int stmfDeleteHostGroup(stmfGroupName *hostGroupName); +int stmfDeleteTargetGroup(stmfGroupName *targetGroupName); +int stmfDevidFromIscsiName(char *iscsiName, stmfDevid *devid); +int stmfDevidFromWwn(uchar_t wwn[8], stmfDevid *devid); +void stmfFreeMemory(void *); +int stmfGetHostGroupList(stmfGroupList **initiatorGroupList); +int stmfGetHostGroupMembers(stmfGroupName *hostGroupName, + stmfGroupProperties **groupProperties); +int stmfGetLocalPortProviderList(stmfProviderList **localPortProviderList); +int stmfGetLocalPortProviderProperties(stmfProviderName *providerName, + stmfLocalPortProviderProperties *providerProperties); +int stmfGetLogicalUnitList(stmfGuidList **logicalUnitList); +int stmfGetLogicalUnitProperties(stmfGuid *logicalUnit, + stmfLogicalUnitProperties *logicalUnitProps); +int stmfGetLogicalUnitProviderList(stmfProviderList **logicalUnitProviderList); +int stmfGetLogicalUnitProviderProperties(stmfProviderName *providerName, + stmfLogicalUnitProviderProperties *providerProperties); +int stmfGetProviderData(char *providerName, nvlist_t **nvl, int providerType); +int stmfGetProviderDataProt(char *providerName, nvlist_t **nvl, + int providerType, uint64_t *setToken); +int stmfGetSessionList(stmfDevid *target, stmfSessionList **sessionList); +int stmfGetState(stmfState *); +int stmfGetTargetGroupList(stmfGroupList **targetGroupList); +int stmfGetTargetGroupMembers(stmfGroupName *targetGroupName, + stmfGroupProperties **groupProperties); +int stmfGetTargetList(stmfDevidList **targetList); +int stmfGetTargetProperties(stmfDevid *target, + stmfTargetProperties *targetProps); +int stmfGetViewEntryList(stmfGuid *lu, stmfViewEntryList **viewEntryList); +int stmfLoadConfig(void); +int stmfOffline(void); +int stmfOfflineTarget(stmfDevid *devid); +int stmfOfflineLogicalUnit(stmfGuid *logicalUnit); +int stmfOnline(void); +int stmfOnlineTarget(stmfDevid *devid); +int stmfOnlineLogicalUnit(stmfGuid *logicalUnit); +int stmfRemoveFromHostGroup(stmfGroupName *hostGroupName, + stmfDevid *initiatorName); +int stmfRemoveFromTargetGroup(stmfGroupName *targetGroupName, + stmfDevid *targetName); +int stmfRemoveViewEntry(stmfGuid *lu, uint32_t viewEntryIndex); +int stmfSetProviderData(char *providerName, nvlist_t *nvl, int providerType); +int stmfSetProviderDataProt(char *providerName, nvlist_t *nvl, + int providerType, uint64_t *setToken); + +#ifdef __cplusplus +} +#endif + +#endif /* _LIBSTMF_H */ diff --git a/usr/src/lib/libstmf/common/llib-lstmf b/usr/src/lib/libstmf/common/llib-lstmf new file mode 100644 index 0000000000..73d658b7ff --- /dev/null +++ b/usr/src/lib/libstmf/common/llib-lstmf @@ -0,0 +1,30 @@ +/* + * 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 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/*LINTLIBRARY*/ +/*PROTOLIB1*/ + +#include <libstmf.h> +#include <store.h> diff --git a/usr/src/lib/libstmf/common/mapfile-vers b/usr/src/lib/libstmf/common/mapfile-vers new file mode 100644 index 0000000000..b98f3acbd8 --- /dev/null +++ b/usr/src/lib/libstmf/common/mapfile-vers @@ -0,0 +1,72 @@ +# +# 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 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +SUNW_1.1 { + global: + stmfAddToHostGroup; + stmfAddToTargetGroup; + stmfAddViewEntry; + stmfClearProviderData; + stmfCreateHostGroup; + stmfCreateTargetGroup; + stmfDeleteHostGroup; + stmfDeleteTargetGroup; + stmfDevidFromIscsiName; + stmfDevidFromWwn; + stmfFreeMemory; + stmfGetHostGroupList; + stmfGetHostGroupMembers; + stmfGetTargetGroupList; + stmfGetTargetGroupMembers; + stmfGetTargetList; + stmfGetTargetProperties; + stmfGetLogicalUnitList; + stmfGetLogicalUnitProperties; + stmfGetProviderData; + stmfGetProviderDataList; + stmfGetProviderDataProt; + stmfGetSessionList; + stmfGetState; + stmfGetViewEntryList; + stmfOfflineTarget; + stmfOfflineLogicalUnit; + stmfOnlineTarget; + stmfOnlineLogicalUnit; + stmfRemoveFromHostGroup; + stmfRemoveFromTargetGroup; + stmfRemoveViewEntry; + stmfSetProviderData; + stmfSetProviderDataProt; + local: + *; +}; + +SUNWprivate { + global: + stmfLoadConfig; + stmfOffline; + stmfOnline; + local: + *; +}; + diff --git a/usr/src/lib/libstmf/common/stmf.c b/usr/src/lib/libstmf/common/stmf.c new file mode 100644 index 0000000000..08a457c78c --- /dev/null +++ b/usr/src/lib/libstmf/common/stmf.c @@ -0,0 +1,3376 @@ +/* + * 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 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <wchar.h> +#include <strings.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <libintl.h> +#include <errno.h> +#include <string.h> +#include <assert.h> +#include <libnvpair.h> +#include <pthread.h> +#include <syslog.h> +#include <libstmf.h> +#include <netinet/in.h> +#include <inttypes.h> +#include <store.h> +#include <locale.h> +#include <sys/stmf_ioctl.h> + +#define STMF_PATH "/devices/pseudo/stmf@0:admin" + +#define EUI "eui." +#define WWN "wwn." +#define IQN "iqn." +#define WWN_ASCII_SIZE 16 +#define IDENT_LENGTH_BYTE 3 + +#define MAX_LU 2<<16 - 1 +#define MAX_TARGET_PORT 1024 +#define MAX_PROVIDER 1024 +#define MAX_GROUP 1024 +#define MAX_SESSION 1024 +#define MAX_ISCSI_NAME 223 + +#define OPEN_STMF 0 +#define OPEN_EXCL_STMF O_EXCL + +#define LOGICAL_UNIT_TYPE 0 +#define TARGET_TYPE 1 +#define STMF_SERVICE_TYPE 2 + +static int openStmf(int, int *fd); +static int groupIoctl(int fd, int cmd, stmfGroupName *); +static int loadStore(int fd); +static int initializeConfig(); +static int groupMemberIoctl(int fd, int cmd, stmfGroupName *, stmfDevid *); +static int guidCompare(const void *, const void *); +static int addViewEntryIoctl(int fd, stmfGuid *, stmfViewEntry *); +static int loadHostGroups(int fd, stmfGroupList *); +static int loadTargetGroups(int fd, stmfGroupList *); +static int getStmfState(stmf_state_desc_t *); +static int setStmfState(int fd, stmf_state_desc_t *, int); +static int setProviderData(int fd, char *, nvlist_t *, int); + +/* + * Open for stmf module + * + * flag - open flag (OPEN_STMF, OPEN_EXCL_STMF) + * fd - pointer to integer. On success, contains the stmf file descriptor + */ +static int +openStmf(int flag, int *fd) +{ + int ret = STMF_STATUS_ERROR; + + if ((*fd = open(STMF_PATH, O_NDELAY | O_RDONLY | flag)) != -1) { + ret = STMF_STATUS_SUCCESS; + } else { + if (errno == EBUSY) { + ret = STMF_ERROR_BUSY; + } else { + ret = STMF_STATUS_ERROR; + } + syslog(LOG_DEBUG, "openStmf:open failure:%s:errno(%d)", + STMF_PATH, errno); + } + + return (ret); +} + +/* + * initializeConfig + * + * This routine should be called before any ioctl requiring initialization + * which is basically everything except stmfGetState(), setStmfState() and + * stmfLoadConfig(). + */ +static int +initializeConfig() +{ + int ret; + stmfState state; + + + ret = stmfGetState(&state); + if (ret != STMF_STATUS_SUCCESS) { + return (ret); + } + + /* if we've already initialized or in the process, return success */ + if (state.configState == STMF_CONFIG_STATE_INIT_DONE || + state.configState == STMF_CONFIG_STATE_INIT) { + return (STMF_STATUS_SUCCESS); + } + + ret = stmfLoadConfig(); + if (ret != STMF_STATUS_SUCCESS) { + syslog(LOG_DEBUG, + "initializeConfig:stmfLoadConfig:error(%d)", ret); + return (ret); + } + + ret = stmfGetState(&state); + if (ret != STMF_STATUS_SUCCESS) { + syslog(LOG_DEBUG, + "initializeConfig:stmfGetState:error(%d)", ret); + return (ret); + } + + if (state.configState != STMF_CONFIG_STATE_INIT_DONE) { + syslog(LOG_DEBUG, "initializeConfig:state.configState(%d)", + state.configState); + ret = STMF_STATUS_ERROR; + } + + return (ret); +} + + +/* + * groupIoctl + * + * Purpose: issue ioctl for create/delete on group + * + * cmd - valid STMF ioctl group cmd + * groupName - groupName to create or delete + */ +static int +groupIoctl(int fd, int cmd, stmfGroupName *groupName) +{ + int ret = STMF_STATUS_SUCCESS; + int ioctlRet; + stmf_iocdata_t stmfIoctl; + stmf_group_name_t iGroupName; + + bzero(&iGroupName, sizeof (iGroupName)); + + bcopy(groupName, &iGroupName.name, strlen((char *)groupName)); + + iGroupName.name_size = strlen((char *)groupName); + + bzero(&stmfIoctl, sizeof (stmfIoctl)); + /* + * Issue ioctl to create the host group + */ + stmfIoctl.stmf_version = STMF_VERSION_1; + stmfIoctl.stmf_ibuf_size = sizeof (iGroupName); + stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&iGroupName; + ioctlRet = ioctl(fd, cmd, &stmfIoctl); + if (ioctlRet != 0) { + switch (errno) { + case EACCES: + ret = STMF_ERROR_PERM; + break; + default: + switch (stmfIoctl.stmf_error) { + case STMF_IOCERR_TG_EXISTS: + case STMF_IOCERR_HG_EXISTS: + ret = STMF_ERROR_EXISTS; + break; + case STMF_IOCERR_TG_IN_USE: + case STMF_IOCERR_HG_IN_USE: + ret = STMF_ERROR_GROUP_IN_USE; + break; + case STMF_IOCERR_INVALID_HG: + case STMF_IOCERR_INVALID_TG: + ret = STMF_ERROR_NOT_FOUND; + break; + default: + syslog(LOG_DEBUG, + "groupIoctl:error(%d)", + stmfIoctl.stmf_error); + ret = STMF_STATUS_ERROR; + break; + } + break; + } + } +done: + return (ret); +} + +/* + * groupIoctl + * + * Purpose: issue ioctl for add/remove member on group + * + * cmd - valid STMF ioctl group member cmd + * groupName - groupName to add to or remove from + * devid - group member to add or remove + */ +static int +groupMemberIoctl(int fd, int cmd, stmfGroupName *groupName, stmfDevid *devid) +{ + int ret = STMF_STATUS_SUCCESS; + int ioctlRet; + stmf_iocdata_t stmfIoctl; + stmf_group_op_data_t stmfGroupData; + + bzero(&stmfGroupData, sizeof (stmfGroupData)); + + bcopy(groupName, &stmfGroupData.group.name, strlen((char *)groupName)); + + stmfGroupData.group.name_size = strlen((char *)groupName); + stmfGroupData.ident[IDENT_LENGTH_BYTE] = devid->identLength; + bcopy(&(devid->ident), &stmfGroupData.ident[IDENT_LENGTH_BYTE + 1], + devid->identLength); + + bzero(&stmfIoctl, sizeof (stmfIoctl)); + /* + * Issue ioctl to add to the host group + */ + stmfIoctl.stmf_version = STMF_VERSION_1; + stmfIoctl.stmf_ibuf_size = sizeof (stmfGroupData); + stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&stmfGroupData; + ioctlRet = ioctl(fd, cmd, &stmfIoctl); + if (ioctlRet != 0) { + switch (errno) { + case EBUSY: + ret = STMF_ERROR_BUSY; + break; + case EACCES: + ret = STMF_ERROR_PERM; + break; + default: + switch (stmfIoctl.stmf_error) { + case STMF_IOCERR_TG_ENTRY_EXISTS: + case STMF_IOCERR_HG_ENTRY_EXISTS: + ret = STMF_ERROR_EXISTS; + break; + case STMF_IOCERR_INVALID_TG_ENTRY: + case STMF_IOCERR_INVALID_HG_ENTRY: + ret = + STMF_ERROR_MEMBER_NOT_FOUND; + break; + case STMF_IOCERR_INVALID_TG: + case STMF_IOCERR_INVALID_HG: + ret = + STMF_ERROR_GROUP_NOT_FOUND; + break; + default: + syslog(LOG_DEBUG, + "groupMemberIoctl:error" + "(%d)", + stmfIoctl.stmf_error); + ret = STMF_STATUS_ERROR; + break; + } + break; + } + } +done: + return (ret); +} + +/* + * guidCompare + * + * qsort function + * sort on guid + */ +static int +guidCompare(const void *p1, const void *p2) +{ + + stmfGuid *g1 = (stmfGuid *)p1, *g2 = (stmfGuid *)p2; + int i; + + for (i = 0; i < sizeof (stmfGuid); i++) { + if (g1->guid[i] > g2->guid[i]) + return (1); + if (g1->guid[i] < g2->guid[i]) + return (-1); + } + + return (0); +} + +/* + * stmfAddToHostGroup + * + * Purpose: Adds an initiator to an existing host group + * + * hostGroupName - name of an existing host group + * hostName - name of initiator to add + */ +int +stmfAddToHostGroup(stmfGroupName *hostGroupName, stmfDevid *hostName) +{ + int ret; + int fd; + + if (hostGroupName == NULL || + (strnlen((char *)hostGroupName, sizeof (stmfGroupName)) + == sizeof (stmfGroupName)) || hostName == NULL) { + return (STMF_ERROR_INVALID_ARG); + } + + /* call init */ + ret = initializeConfig(); + if (ret != STMF_STATUS_SUCCESS) { + return (ret); + } + + /* + * Open control node for stmf + */ + if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS) + return (ret); + + if ((ret = groupMemberIoctl(fd, STMF_IOCTL_ADD_HG_ENTRY, hostGroupName, + hostName)) != STMF_STATUS_SUCCESS) { + goto done; + } + + ret = psAddHostGroupMember((char *)hostGroupName, + (char *)hostName->ident); + switch (ret) { + case STMF_PS_SUCCESS: + ret = STMF_STATUS_SUCCESS; + break; + case STMF_PS_ERROR_EXISTS: + ret = STMF_ERROR_EXISTS; + break; + case STMF_PS_ERROR_GROUP_NOT_FOUND: + ret = STMF_ERROR_GROUP_NOT_FOUND; + break; + case STMF_PS_ERROR_BUSY: + ret = STMF_ERROR_BUSY; + break; + case STMF_PS_ERROR_SERVICE_NOT_FOUND: + ret = STMF_ERROR_SERVICE_NOT_FOUND; + break; + case STMF_PS_ERROR_VERSION_MISMATCH: + ret = STMF_ERROR_SERVICE_DATA_VERSION; + break; + default: + syslog(LOG_DEBUG, + "stmfAddToHostGroup:psAddHostGroupMember:error(%d)", + ret); + ret = STMF_STATUS_ERROR; + break; + } + +done: + (void) close(fd); + return (ret); +} + +/* + * stmfAddToTargetGroup + * + * Purpose: Adds a local port to an existing target group + * + * targetGroupName - name of an existing target group + * targetName - name of target to add + */ +int +stmfAddToTargetGroup(stmfGroupName *targetGroupName, stmfDevid *targetName) +{ + int ret; + int fd; + stmfState state; + + if (targetGroupName == NULL || + (strnlen((char *)targetGroupName, sizeof (stmfGroupName)) + == sizeof (stmfGroupName)) || targetName == NULL) { + return (STMF_ERROR_INVALID_ARG); + } + + ret = stmfGetState(&state); + if (ret == STMF_STATUS_SUCCESS) { + if (state.operationalState != STMF_SERVICE_STATE_OFFLINE) { + return (STMF_ERROR_SERVICE_ONLINE); + } + } else { + return (STMF_STATUS_ERROR); + } + + /* call init */ + ret = initializeConfig(); + if (ret != STMF_STATUS_SUCCESS) { + return (ret); + } + + /* + * Open control node for stmf + */ + if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS) + return (ret); + + if ((ret = groupMemberIoctl(fd, STMF_IOCTL_ADD_TG_ENTRY, + targetGroupName, targetName)) != STMF_STATUS_SUCCESS) { + goto done; + } + + ret = psAddTargetGroupMember((char *)targetGroupName, + (char *)targetName->ident); + switch (ret) { + case STMF_PS_SUCCESS: + ret = STMF_STATUS_SUCCESS; + break; + case STMF_PS_ERROR_EXISTS: + ret = STMF_ERROR_EXISTS; + break; + case STMF_PS_ERROR_GROUP_NOT_FOUND: + ret = STMF_ERROR_GROUP_NOT_FOUND; + break; + case STMF_PS_ERROR_BUSY: + ret = STMF_ERROR_BUSY; + break; + case STMF_PS_ERROR_SERVICE_NOT_FOUND: + ret = STMF_ERROR_SERVICE_NOT_FOUND; + break; + case STMF_PS_ERROR_VERSION_MISMATCH: + ret = STMF_ERROR_SERVICE_DATA_VERSION; + break; + default: + syslog(LOG_DEBUG, + "stmfAddToTargetGroup:psAddTargetGroupMember:" + "error(%d)", ret); + ret = STMF_STATUS_ERROR; + break; + } + +done: + (void) close(fd); + return (ret); +} + +/* + * addViewEntryIoctl + * + * Purpose: Issues ioctl to add a view entry + * + * lu - Logical Unit identifier to which the view entry is added + * viewEntry - view entry to add + * init - When set to B_TRUE, we are in the init state, i.e. don't call open + */ +static int +addViewEntryIoctl(int fd, stmfGuid *lu, stmfViewEntry *viewEntry) +{ + int ret = STMF_STATUS_SUCCESS; + int ioctlRet; + stmf_iocdata_t stmfIoctl; + stmf_view_op_entry_t ioctlViewEntry; + + bzero(&ioctlViewEntry, sizeof (ioctlViewEntry)); + /* + * don't set ve_ndx or ve_ndx_valid as ve_ndx_valid should be + * false on input + */ + ioctlViewEntry.ve_lu_number_valid = viewEntry->luNbrValid; + ioctlViewEntry.ve_all_hosts = viewEntry->allHosts; + ioctlViewEntry.ve_all_targets = viewEntry->allTargets; + + if (viewEntry->allHosts == B_FALSE) { + bcopy(viewEntry->hostGroup, &ioctlViewEntry.ve_host_group.name, + sizeof (stmfGroupName)); + ioctlViewEntry.ve_host_group.name_size = + strlen((char *)viewEntry->hostGroup); + } + if (viewEntry->allTargets == B_FALSE) { + bcopy(viewEntry->targetGroup, + &ioctlViewEntry.ve_target_group.name, + sizeof (stmfGroupName)); + ioctlViewEntry.ve_target_group.name_size = + strlen((char *)viewEntry->targetGroup); + } + if (viewEntry->luNbrValid) { + bcopy(viewEntry->luNbr, &ioctlViewEntry.ve_lu_nbr, + sizeof (ioctlViewEntry.ve_lu_nbr)); + } + bcopy(lu, &ioctlViewEntry.ve_guid, sizeof (stmfGuid)); + + bzero(&stmfIoctl, sizeof (stmfIoctl)); + /* + * Issue ioctl to add to the view entry + */ + stmfIoctl.stmf_version = STMF_VERSION_1; + stmfIoctl.stmf_ibuf_size = sizeof (ioctlViewEntry); + stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&ioctlViewEntry; + stmfIoctl.stmf_obuf_size = sizeof (ioctlViewEntry); + stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)&ioctlViewEntry; + ioctlRet = ioctl(fd, STMF_IOCTL_ADD_VIEW_ENTRY, &stmfIoctl); + if (ioctlRet != 0) { + switch (errno) { + case EBUSY: + ret = STMF_ERROR_BUSY; + break; + case EACCES: + switch (stmfIoctl.stmf_error) { + case STMF_IOCERR_UPDATE_NEED_CFG_INIT: + ret = STMF_ERROR_CONFIG_NONE; + break; + default: + ret = STMF_ERROR_PERM; + break; + } + break; + default: + switch (stmfIoctl.stmf_error) { + case STMF_IOCERR_LU_NUMBER_IN_USE: + ret = STMF_ERROR_LUN_IN_USE; + break; + case STMF_IOCERR_VIEW_ENTRY_CONFLICT: + ret = STMF_ERROR_VE_CONFLICT; + break; + case STMF_IOCERR_UPDATE_NEED_CFG_INIT: + ret = STMF_ERROR_CONFIG_NONE; + break; + case STMF_IOCERR_INVALID_HG: + ret = STMF_ERROR_INVALID_HG; + break; + case STMF_IOCERR_INVALID_TG: + ret = STMF_ERROR_INVALID_TG; + break; + default: + syslog(LOG_DEBUG, + "addViewEntryIoctl" + ":error(%d)", + stmfIoctl.stmf_error); + ret = STMF_STATUS_ERROR; + break; + } + break; + } + goto done; + } + + /* copy lu nbr back to caller's view entry on success */ + viewEntry->veIndex = ioctlViewEntry.ve_ndx; + if (ioctlViewEntry.ve_lu_number_valid) { + bcopy(&ioctlViewEntry.ve_lu_nbr, viewEntry->luNbr, + sizeof (ioctlViewEntry.ve_lu_nbr)); + } + viewEntry->luNbrValid = B_TRUE; + +done: + return (ret); +} + +/* + * stmfAddViewEntry + * + * Purpose: Adds a view entry to a logical unit + * + * lu - guid of the logical unit to which the view entry is added + * viewEntry - view entry structure to add + */ +int +stmfAddViewEntry(stmfGuid *lu, stmfViewEntry *viewEntry) +{ + int ret; + int fd; + stmfViewEntry iViewEntry; + + if (lu == NULL || viewEntry == NULL) { + return (STMF_ERROR_INVALID_ARG); + } + + /* initialize and set internal view entry */ + bzero(&iViewEntry, sizeof (iViewEntry)); + + if (!viewEntry->allHosts) { + bcopy(viewEntry->hostGroup, iViewEntry.hostGroup, + sizeof (iViewEntry.hostGroup)); + } else { + iViewEntry.allHosts = B_TRUE; + } + + if (!viewEntry->allTargets) { + bcopy(viewEntry->targetGroup, iViewEntry.targetGroup, + sizeof (iViewEntry.targetGroup)); + } else { + iViewEntry.allTargets = B_TRUE; + } + + if (viewEntry->luNbrValid) { + iViewEntry.luNbrValid = B_TRUE; + bcopy(viewEntry->luNbr, iViewEntry.luNbr, + sizeof (iViewEntry.luNbr)); + } + + /* + * set users return view entry index valid flag to false + * in case of failure + */ + viewEntry->veIndexValid = B_FALSE; + + /* Check to ensure service exists */ + if (psCheckService() != STMF_STATUS_SUCCESS) { + return (STMF_ERROR_SERVICE_NOT_FOUND); + } + + /* call init */ + ret = initializeConfig(); + if (ret != STMF_STATUS_SUCCESS) { + return (ret); + } + + /* + * Open control node for stmf + */ + if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS) + return (ret); + + /* + * First add the view entry to the driver + */ + ret = addViewEntryIoctl(fd, lu, &iViewEntry); + if (ret != STMF_STATUS_SUCCESS) { + goto done; + } + + /* + * If the add to driver was successful, add it to the persistent + * store. + */ + ret = psAddViewEntry(lu, &iViewEntry); + switch (ret) { + case STMF_PS_SUCCESS: + ret = STMF_STATUS_SUCCESS; + break; + case STMF_PS_ERROR_NOT_FOUND: + ret = STMF_ERROR_NOT_FOUND; + break; + case STMF_PS_ERROR_BUSY: + ret = STMF_ERROR_BUSY; + break; + case STMF_PS_ERROR_SERVICE_NOT_FOUND: + ret = STMF_ERROR_SERVICE_NOT_FOUND; + break; + case STMF_PS_ERROR_VERSION_MISMATCH: + ret = STMF_ERROR_SERVICE_DATA_VERSION; + break; + default: + syslog(LOG_DEBUG, + "stmfAddViewEntry:psAddViewEntry:error(%d)", ret); + ret = STMF_STATUS_ERROR; + break; + } + +done: + (void) close(fd); + + if (ret == STMF_STATUS_SUCCESS) { + /* set caller's view entry on success */ + viewEntry->veIndexValid = iViewEntry.veIndexValid; + viewEntry->veIndex = iViewEntry.veIndex; + viewEntry->luNbrValid = B_TRUE; + bcopy(iViewEntry.luNbr, viewEntry->luNbr, + sizeof (iViewEntry.luNbr)); + } + return (ret); +} + +/* + * stmfClearProviderData + * + * Purpose: delete all provider data for specified provider + * + * providerName - name of provider for which data should be deleted + */ +int +stmfClearProviderData(char *providerName, int providerType) +{ + int ret; + int fd; + int ioctlRet; + int savedErrno; + stmf_iocdata_t stmfIoctl; + stmf_ppioctl_data_t ppi; + + /* call init */ + ret = initializeConfig(); + if (ret != STMF_STATUS_SUCCESS) { + return (ret); + } + + if (providerName == NULL) { + return (STMF_ERROR_INVALID_ARG); + } + + if (providerType != STMF_LU_PROVIDER_TYPE && + providerType != STMF_PORT_PROVIDER_TYPE) { + return (STMF_ERROR_INVALID_ARG); + } + + /* + * Open control node for stmf + */ + if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS) + return (ret); + + bzero(&ppi, sizeof (ppi)); + + (void) strncpy(ppi.ppi_name, providerName, sizeof (ppi.ppi_name)); + + switch (providerType) { + case STMF_LU_PROVIDER_TYPE: + ppi.ppi_lu_provider = 1; + break; + case STMF_PORT_PROVIDER_TYPE: + ppi.ppi_port_provider = 1; + break; + default: + ret = STMF_ERROR_INVALID_ARG; + goto done; + } + + bzero(&stmfIoctl, sizeof (stmfIoctl)); + + stmfIoctl.stmf_version = STMF_VERSION_1; + stmfIoctl.stmf_ibuf_size = sizeof (stmf_ppioctl_data_t); + stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&ppi; + + ioctlRet = ioctl(fd, STMF_IOCTL_CLEAR_PP_DATA, &stmfIoctl); + if (ioctlRet != 0) { + savedErrno = errno; + switch (savedErrno) { + case EBUSY: + ret = STMF_ERROR_BUSY; + break; + case EACCES: + ret = STMF_ERROR_PERM; + break; + default: + syslog(LOG_DEBUG, + "stmfClearProviderData:ioctl error(%d)", + ioctlRet); + ret = STMF_STATUS_ERROR; + break; + } + if (savedErrno != ENOENT) { + goto done; + } + } + + ret = psClearProviderData(providerName, providerType); + switch (ret) { + case STMF_PS_SUCCESS: + ret = STMF_STATUS_SUCCESS; + break; + case STMF_PS_ERROR_NOT_FOUND: + ret = STMF_ERROR_NOT_FOUND; + break; + case STMF_PS_ERROR_BUSY: + ret = STMF_ERROR_BUSY; + break; + case STMF_PS_ERROR_SERVICE_NOT_FOUND: + ret = STMF_ERROR_SERVICE_NOT_FOUND; + break; + case STMF_PS_ERROR_VERSION_MISMATCH: + ret = STMF_ERROR_SERVICE_DATA_VERSION; + break; + default: + syslog(LOG_DEBUG, + "stmfClearProviderData:psClearProviderData" + ":error(%d)", ret); + ret = STMF_STATUS_ERROR; + break; + } + +done: + (void) close(fd); + return (ret); +} + +/* + * stmfCreateHostGroup + * + * Purpose: Create a new initiator group + * + * hostGroupName - name of host group to create + */ +int +stmfCreateHostGroup(stmfGroupName *hostGroupName) +{ + int ret; + int fd; + + if (hostGroupName == NULL || + (strnlen((char *)hostGroupName, sizeof (stmfGroupName)) + == sizeof (stmfGroupName))) { + return (STMF_ERROR_INVALID_ARG); + } + + /* Check to ensure service exists */ + if (psCheckService() != STMF_STATUS_SUCCESS) { + return (STMF_ERROR_SERVICE_NOT_FOUND); + } + + /* call init */ + ret = initializeConfig(); + if (ret != STMF_STATUS_SUCCESS) { + return (ret); + } + + /* + * Open control node for stmf + */ + if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS) + return (ret); + + if ((ret = groupIoctl(fd, STMF_IOCTL_CREATE_HOST_GROUP, + hostGroupName)) != STMF_STATUS_SUCCESS) { + goto done; + } + + ret = psCreateHostGroup((char *)hostGroupName); + switch (ret) { + case STMF_PS_SUCCESS: + ret = STMF_STATUS_SUCCESS; + break; + case STMF_PS_ERROR_EXISTS: + ret = STMF_ERROR_EXISTS; + break; + case STMF_PS_ERROR_BUSY: + ret = STMF_ERROR_BUSY; + break; + case STMF_PS_ERROR_SERVICE_NOT_FOUND: + ret = STMF_ERROR_SERVICE_NOT_FOUND; + break; + case STMF_PS_ERROR_VERSION_MISMATCH: + ret = STMF_ERROR_SERVICE_DATA_VERSION; + break; + default: + syslog(LOG_DEBUG, + "stmfCreateHostGroup:psCreateHostGroup:error(%d)", + ret); + ret = STMF_STATUS_ERROR; + break; + } + +done: + (void) close(fd); + return (ret); +} + +/* + * stmfCreateTargetGroup + * + * Purpose: Create a local port group + * + * targetGroupName - name of local port group to create + */ +int +stmfCreateTargetGroup(stmfGroupName *targetGroupName) +{ + int ret; + int fd; + + if (targetGroupName == NULL || + (strnlen((char *)targetGroupName, sizeof (stmfGroupName)) + == sizeof (stmfGroupName))) { + return (STMF_ERROR_INVALID_ARG); + } + + /* Check to ensure service exists */ + if (psCheckService() != STMF_STATUS_SUCCESS) { + return (STMF_ERROR_SERVICE_NOT_FOUND); + } + + /* call init */ + ret = initializeConfig(); + if (ret != STMF_STATUS_SUCCESS) { + return (ret); + } + + /* + * Open control node for stmf + */ + if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS) + return (ret); + + /* + * Add the group to the driver + */ + if ((ret = groupIoctl(fd, STMF_IOCTL_CREATE_TARGET_GROUP, + targetGroupName)) != STMF_STATUS_SUCCESS) { + goto done; + } + + /* + * If the add to the driver was successful, add it to the persistent + * store. + */ + ret = psCreateTargetGroup((char *)targetGroupName); + switch (ret) { + case STMF_PS_SUCCESS: + ret = STMF_STATUS_SUCCESS; + break; + case STMF_PS_ERROR_EXISTS: + ret = STMF_ERROR_EXISTS; + break; + case STMF_PS_ERROR_BUSY: + ret = STMF_ERROR_BUSY; + break; + case STMF_PS_ERROR_SERVICE_NOT_FOUND: + ret = STMF_ERROR_SERVICE_NOT_FOUND; + break; + case STMF_PS_ERROR_VERSION_MISMATCH: + ret = STMF_ERROR_SERVICE_DATA_VERSION; + break; + default: + syslog(LOG_DEBUG, + "stmfCreateTargetGroup:psCreateTargetGroup" + ":error(%d)", ret); + ret = STMF_STATUS_ERROR; + break; + } + +done: + (void) close(fd); + return (ret); +} + +/* + * stmfDeleteHostGroup + * + * Purpose: Delete an initiator or local port group + * + * hostGroupName - group to delete + */ +int +stmfDeleteHostGroup(stmfGroupName *hostGroupName) +{ + int ret; + int fd; + + if (hostGroupName == NULL) { + return (STMF_ERROR_INVALID_ARG); + } + + /* Check to ensure service exists */ + if (psCheckService() != STMF_STATUS_SUCCESS) { + return (STMF_ERROR_SERVICE_NOT_FOUND); + } + + /* call init */ + ret = initializeConfig(); + if (ret != STMF_STATUS_SUCCESS) { + return (ret); + } + + /* + * Open control node for stmf + */ + if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS) + return (ret); + + /* + * Remove the group from the driver + */ + if ((ret = groupIoctl(fd, STMF_IOCTL_REMOVE_HOST_GROUP, + hostGroupName)) != STMF_STATUS_SUCCESS) { + goto done; + } + + /* + * If the remove from the driver was successful, remove it from the + * persistent store. + */ + ret = psDeleteHostGroup((char *)hostGroupName); + switch (ret) { + case STMF_PS_SUCCESS: + ret = STMF_STATUS_SUCCESS; + break; + case STMF_PS_ERROR_NOT_FOUND: + ret = STMF_ERROR_NOT_FOUND; + break; + case STMF_PS_ERROR_BUSY: + ret = STMF_ERROR_BUSY; + break; + case STMF_PS_ERROR_SERVICE_NOT_FOUND: + ret = STMF_ERROR_SERVICE_NOT_FOUND; + break; + case STMF_PS_ERROR_VERSION_MISMATCH: + ret = STMF_ERROR_SERVICE_DATA_VERSION; + break; + default: + syslog(LOG_DEBUG, + "stmfDeleteHostGroup:psDeleteHostGroup:error(%d)", + ret); + ret = STMF_STATUS_ERROR; + break; + } + +done: + (void) close(fd); + return (ret); +} + +/* + * stmfDeleteTargetGroup + * + * Purpose: Delete an initiator or local port group + * + * targetGroupName - group to delete + */ +int +stmfDeleteTargetGroup(stmfGroupName *targetGroupName) +{ + int ret = STMF_STATUS_SUCCESS; + int fd; + + if (targetGroupName == NULL) { + return (STMF_ERROR_INVALID_ARG); + } + + /* Check to ensure service exists */ + if (psCheckService() != STMF_STATUS_SUCCESS) { + return (STMF_ERROR_SERVICE_NOT_FOUND); + } + + /* call init */ + ret = initializeConfig(); + if (ret != STMF_STATUS_SUCCESS) { + return (ret); + } + + /* + * Open control node for stmf + */ + if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS) + return (ret); + + /* + * Remove the group from the driver + */ + if ((ret = groupIoctl(fd, STMF_IOCTL_REMOVE_TARGET_GROUP, + targetGroupName)) != STMF_STATUS_SUCCESS) { + goto done; + } + + /* + * If the remove from the driver was successful, remove it from the + * persistent store. + */ + ret = psDeleteTargetGroup((char *)targetGroupName); + switch (ret) { + case STMF_PS_SUCCESS: + ret = STMF_STATUS_SUCCESS; + break; + case STMF_PS_ERROR_NOT_FOUND: + ret = STMF_ERROR_NOT_FOUND; + break; + case STMF_PS_ERROR_BUSY: + ret = STMF_ERROR_BUSY; + break; + case STMF_PS_ERROR_SERVICE_NOT_FOUND: + ret = STMF_ERROR_SERVICE_NOT_FOUND; + break; + case STMF_PS_ERROR_VERSION_MISMATCH: + ret = STMF_ERROR_SERVICE_DATA_VERSION; + break; + default: + syslog(LOG_DEBUG, + "stmfDeleteTargetGroup:psDeleteTargetGroup" + ":error(%d)", ret); + ret = STMF_STATUS_ERROR; + break; + } + +done: + (void) close(fd); + return (ret); +} + +/* + * stmfDevidFromIscsiName + * + * Purpose: convert an iSCSI name to an stmf devid + * + * iscsiName - unicode nul terminated utf-8 encoded iSCSI name + * devid - on success, contains the converted iscsi name + */ +int +stmfDevidFromIscsiName(char *iscsiName, stmfDevid *devid) +{ + if (devid == NULL || iscsiName == NULL) + return (STMF_ERROR_INVALID_ARG); + + bzero(devid, sizeof (stmfDevid)); + + /* Validate size of target */ + if ((devid->identLength = strlen(iscsiName)) > MAX_ISCSI_NAME || + devid->identLength < strlen(EUI) || + devid->identLength < strlen(IQN)) { + return (STMF_ERROR_INVALID_ARG); + } + + if ((strncmp(iscsiName, EUI, strlen(EUI)) != 0) && + strncmp(iscsiName, IQN, strlen(IQN)) != 0) { + return (STMF_ERROR_INVALID_ARG); + } + + /* copy UTF-8 bytes to ident */ + bcopy(iscsiName, devid->ident, devid->identLength); + + return (STMF_STATUS_SUCCESS); +} + +/* + * stmfDevidFromWwn + * + * Purpose: convert a WWN to an stmf devid + * + * wwn - 8-byte wwn identifier + * devid - on success, contains the converted wwn + */ +int +stmfDevidFromWwn(uchar_t *wwn, stmfDevid *devid) +{ + if (wwn == NULL || devid == NULL) + return (STMF_ERROR_INVALID_ARG); + + bzero(devid, sizeof (stmfDevid)); + + /* Copy eui prefix */ + (void) bcopy(WWN, devid->ident, strlen(WWN)); + + /* Convert to ASCII uppercase hexadecimal string */ + (void) snprintf((char *)&devid->ident[strlen(WWN)], + sizeof (devid->ident), "%02X%02X%02X%02X%02X%02X%02X%02X", + wwn[0], wwn[1], wwn[2], wwn[3], wwn[4], wwn[5], wwn[6], wwn[7]); + + devid->identLength = strlen((char *)devid->ident); + + return (STMF_STATUS_SUCCESS); +} + +/* + * stmfFreeMemory + * + * Purpose: Free memory allocated by this library + * + * memory - previously allocated pointer of memory managed by library + */ +void +stmfFreeMemory(void *memory) +{ + free(memory); +} + +/* + * stmfGetHostGroupList + * + * Purpose: Retrieves the list of initiator group oids + * + * hostGroupList - pointer to pointer to hostGroupList structure + * on success, this contains the host group list. + */ +int +stmfGetHostGroupList(stmfGroupList **hostGroupList) +{ + int ret; + + if (hostGroupList == NULL) { + return (STMF_ERROR_INVALID_ARG); + } + + ret = psGetHostGroupList(hostGroupList); + switch (ret) { + case STMF_PS_SUCCESS: + ret = STMF_STATUS_SUCCESS; + break; + case STMF_PS_ERROR_NOT_FOUND: + ret = STMF_ERROR_NOT_FOUND; + break; + case STMF_PS_ERROR_BUSY: + ret = STMF_ERROR_BUSY; + break; + case STMF_PS_ERROR_SERVICE_NOT_FOUND: + ret = STMF_ERROR_SERVICE_NOT_FOUND; + break; + case STMF_PS_ERROR_VERSION_MISMATCH: + ret = STMF_ERROR_SERVICE_DATA_VERSION; + break; + default: + syslog(LOG_DEBUG, + "stmfGetHostGroupList:psGetHostGroupList:error(%d)", + ret); + ret = STMF_STATUS_ERROR; + break; + } + + return (ret); +} + +/* + * stmfGetHostGroupMembers + * + * Purpose: Retrieves the group properties for a host group + * + * groupName - name of group for which to retrieve host group members. + * groupProp - pointer to pointer to stmfGroupProperties structure + * on success, this contains the list of group members. + */ +int +stmfGetHostGroupMembers(stmfGroupName *groupName, + stmfGroupProperties **groupProp) +{ + int ret; + + if (groupName == NULL || groupProp == NULL) { + return (STMF_ERROR_INVALID_ARG); + } + + ret = psGetHostGroupMemberList((char *)groupName, groupProp); + switch (ret) { + case STMF_PS_SUCCESS: + ret = STMF_STATUS_SUCCESS; + break; + case STMF_PS_ERROR_NOT_FOUND: + ret = STMF_ERROR_NOT_FOUND; + break; + case STMF_PS_ERROR_BUSY: + ret = STMF_ERROR_BUSY; + break; + case STMF_PS_ERROR_SERVICE_NOT_FOUND: + ret = STMF_ERROR_SERVICE_NOT_FOUND; + break; + case STMF_PS_ERROR_VERSION_MISMATCH: + ret = STMF_ERROR_SERVICE_DATA_VERSION; + break; + default: + syslog(LOG_DEBUG, + "stmfGetHostGroupMembers:psGetHostGroupMembers" + ":error(%d)", ret); + ret = STMF_STATUS_ERROR; + break; + } + + return (ret); +} + +/* + * stmfGetProviderData + * + * Purpose: Get provider data list + * + * providerName - name of provider for which to retrieve the data + * nvl - pointer to nvlist_t pointer which will contain the nvlist data + * retrieved. + * providerType - type of provider for which to retrieve data. + * STMF_LU_PROVIDER_TYPE + * STMF_PORT_PROVIDER_TYPE + */ +int +stmfGetProviderData(char *providerName, nvlist_t **nvl, int providerType) +{ + return (stmfGetProviderDataProt(providerName, nvl, providerType, + NULL)); +} + +/* + * stmfGetProviderDataProt + * + * Purpose: Get provider data list with token + * + * providerName - name of provider for which to retrieve the data + * nvl - pointer to nvlist_t pointer which will contain the nvlist data + * retrieved. + * providerType - type of provider for which to retrieve data. + * STMF_LU_PROVIDER_TYPE + * STMF_PORT_PROVIDER_TYPE + * setToken - Returns the stale data token + */ +int +stmfGetProviderDataProt(char *providerName, nvlist_t **nvl, int providerType, + uint64_t *setToken) +{ + int ret; + + if (providerName == NULL || nvl == NULL) { + return (STMF_ERROR_INVALID_ARG); + } + + if (providerType != STMF_LU_PROVIDER_TYPE && + providerType != STMF_PORT_PROVIDER_TYPE) { + return (STMF_ERROR_INVALID_ARG); + } + + /* call init */ + ret = initializeConfig(); + if (ret != STMF_STATUS_SUCCESS) { + return (ret); + } + + ret = psGetProviderData(providerName, nvl, providerType, setToken); + switch (ret) { + case STMF_PS_SUCCESS: + ret = STMF_STATUS_SUCCESS; + break; + case STMF_PS_ERROR_BUSY: + ret = STMF_ERROR_BUSY; + break; + case STMF_PS_ERROR_NOT_FOUND: + ret = STMF_ERROR_NOT_FOUND; + break; + case STMF_PS_ERROR_SERVICE_NOT_FOUND: + ret = STMF_ERROR_SERVICE_NOT_FOUND; + break; + case STMF_PS_ERROR_VERSION_MISMATCH: + ret = STMF_ERROR_SERVICE_DATA_VERSION; + break; + default: + syslog(LOG_DEBUG, + "stmfGetProviderData:psGetProviderData:error(%d)", + ret); + ret = STMF_STATUS_ERROR; + break; + } + + return (ret); +} + +/* + * stmfGetProviderDataList + * + * Purpose: Get the list of providers currently persisting data + * + * providerList - pointer to pointer to an stmfProviderList structure allocated + * by the caller. Will contain the list of providers on success. + */ +int +stmfGetProviderDataList(stmfProviderList **providerList) +{ + int ret; + + ret = psGetProviderDataList(providerList); + switch (ret) { + case STMF_PS_SUCCESS: + ret = STMF_STATUS_SUCCESS; + break; + case STMF_PS_ERROR_BUSY: + ret = STMF_ERROR_BUSY; + break; + case STMF_PS_ERROR_SERVICE_NOT_FOUND: + ret = STMF_ERROR_SERVICE_NOT_FOUND; + break; + case STMF_PS_ERROR_VERSION_MISMATCH: + ret = STMF_ERROR_SERVICE_DATA_VERSION; + break; + default: + syslog(LOG_DEBUG, + "stmfGetProviderDataList:psGetProviderDataList" + ":error(%d)", ret); + ret = STMF_STATUS_ERROR; + break; + } + + return (ret); +} + + +/* + * stmfGetSessionList + * + * Purpose: Retrieves the session list for a target (devid) + * + * devid - devid of target for which to retrieve session information. + * sessionList - pointer to pointer to stmfSessionList structure + * on success, this contains the list of initiator sessions. + */ +int +stmfGetSessionList(stmfDevid *devid, stmfSessionList **sessionList) +{ + int ret = STMF_STATUS_SUCCESS; + int fd; + int ioctlRet; + int cmd = STMF_IOCTL_SESSION_LIST; + int i; + stmf_iocdata_t stmfIoctl; + slist_scsi_session_t *fSessionList; + uint8_t ident[260]; + uint32_t fSessionListSize; + + if (sessionList == NULL || devid == NULL) { + ret = STMF_ERROR_INVALID_ARG; + } + + /* call init */ + ret = initializeConfig(); + if (ret != STMF_STATUS_SUCCESS) { + return (ret); + } + + /* + * Open control node for stmf + */ + if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS) + return (ret); + + /* + * Allocate ioctl input buffer + */ + fSessionListSize = MAX_SESSION; + fSessionListSize = fSessionListSize * (sizeof (slist_scsi_session_t)); + fSessionList = (slist_scsi_session_t *)calloc(1, fSessionListSize); + if (fSessionList == NULL) { + return (STMF_ERROR_NOMEM); + } + + ident[IDENT_LENGTH_BYTE] = devid->identLength; + bcopy(&(devid->ident), &ident[IDENT_LENGTH_BYTE + 1], + devid->identLength); + + bzero(&stmfIoctl, sizeof (stmfIoctl)); + /* + * Issue ioctl to get the session list + */ + stmfIoctl.stmf_version = STMF_VERSION_1; + stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&ident; + stmfIoctl.stmf_ibuf_size = sizeof (ident); + stmfIoctl.stmf_obuf_size = fSessionListSize; + stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fSessionList; + ioctlRet = ioctl(fd, cmd, &stmfIoctl); + if (ioctlRet != 0) { + switch (errno) { + case EBUSY: + ret = STMF_ERROR_BUSY; + break; + case EACCES: + ret = STMF_ERROR_PERM; + break; + default: + syslog(LOG_DEBUG, + "stmfGetSessionList:ioctl errno(%d)", + errno); + ret = STMF_STATUS_ERROR; + break; + } + goto done; + } + /* + * Check whether input buffer was large enough + */ + if (stmfIoctl.stmf_obuf_max_nentries > MAX_SESSION) { + fSessionListSize = stmfIoctl.stmf_obuf_max_nentries * + sizeof (slist_scsi_session_t); + fSessionList = realloc(fSessionList, fSessionListSize); + if (fSessionList == NULL) { + return (STMF_ERROR_NOMEM); + } + stmfIoctl.stmf_obuf_size = fSessionListSize; + stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fSessionList; + ioctlRet = ioctl(fd, cmd, &stmfIoctl); + if (ioctlRet != 0) { + switch (errno) { + case EBUSY: + ret = STMF_ERROR_BUSY; + break; + case EACCES: + ret = STMF_ERROR_PERM; + break; + default: + syslog(LOG_DEBUG, + "stmfGetSessionList:ioctl " + "errno(%d)", errno); + ret = STMF_STATUS_ERROR; + break; + } + goto done; + } + } + + /* + * allocate caller's buffer with the final size + */ + *sessionList = (stmfSessionList *)calloc(1, sizeof (stmfSessionList) + + stmfIoctl.stmf_obuf_max_nentries * sizeof (stmfSession)); + if (*sessionList == NULL) { + ret = STMF_ERROR_NOMEM; + free(sessionList); + goto done; + } + + (*sessionList)->cnt = stmfIoctl.stmf_obuf_max_nentries; + + /* + * copy session info to caller's buffer + */ + for (i = 0; i < (*sessionList)->cnt; i++) { + (*sessionList)->session[i].initiator.identLength = + fSessionList->initiator[IDENT_LENGTH_BYTE]; + bcopy(&(fSessionList->initiator[IDENT_LENGTH_BYTE + 1]), + (*sessionList)->session[i].initiator.ident, + STMF_IDENT_LENGTH); + bcopy(&(fSessionList->alias), + &((*sessionList)->session[i].alias), + sizeof ((*sessionList)->session[i].alias)); + bcopy(&(fSessionList++->creation_time), + &((*sessionList)->session[i].creationTime), + sizeof (time_t)); + } +done: + (void) close(fd); + return (ret); +} + +/* + * stmfGetTargetGroupList + * + * Purpose: Retrieves the list of target groups + * + * targetGroupList - pointer to a pointer to an stmfGroupList structure. On + * success, it contains the list of target groups. + */ +int +stmfGetTargetGroupList(stmfGroupList **targetGroupList) +{ + int ret; + + if (targetGroupList == NULL) { + return (STMF_ERROR_INVALID_ARG); + } + + ret = psGetTargetGroupList(targetGroupList); + switch (ret) { + case STMF_PS_SUCCESS: + ret = STMF_STATUS_SUCCESS; + break; + case STMF_PS_ERROR_NOT_FOUND: + ret = STMF_ERROR_NOT_FOUND; + break; + case STMF_PS_ERROR_BUSY: + ret = STMF_ERROR_BUSY; + break; + case STMF_PS_ERROR_SERVICE_NOT_FOUND: + ret = STMF_ERROR_SERVICE_NOT_FOUND; + break; + case STMF_PS_ERROR_VERSION_MISMATCH: + ret = STMF_ERROR_SERVICE_DATA_VERSION; + break; + default: + syslog(LOG_DEBUG, + "stmfGetTargetGroupList:psGetTargetGroupList:" + "error(%d)", ret); + ret = STMF_STATUS_ERROR; + break; + } + + return (ret); +} + +/* + * stmfGetTargetGroupMembers + * + * Purpose: Retrieves the group members for a target group + * + * groupName - name of target group for which to retrieve members. + * groupProp - pointer to pointer to stmfGroupProperties structure + * on success, this contains the list of group members. + */ +int +stmfGetTargetGroupMembers(stmfGroupName *groupName, + stmfGroupProperties **groupProp) +{ + int ret; + + if (groupName == NULL || groupProp == NULL) { + return (STMF_ERROR_INVALID_ARG); + } + + ret = psGetTargetGroupMemberList((char *)groupName, groupProp); + switch (ret) { + case STMF_PS_SUCCESS: + ret = STMF_STATUS_SUCCESS; + break; + case STMF_PS_ERROR_NOT_FOUND: + ret = STMF_ERROR_NOT_FOUND; + break; + case STMF_PS_ERROR_BUSY: + ret = STMF_ERROR_BUSY; + break; + case STMF_PS_ERROR_SERVICE_NOT_FOUND: + ret = STMF_ERROR_SERVICE_NOT_FOUND; + break; + case STMF_PS_ERROR_VERSION_MISMATCH: + ret = STMF_ERROR_SERVICE_DATA_VERSION; + break; + default: + syslog(LOG_DEBUG, + "stmfGetTargetGroupMembers:psGetTargetGroupMembers:" + "error(%d)", ret); + ret = STMF_STATUS_ERROR; + break; + } + + return (ret); +} + +/* + * stmfGetTargetList + * + * Purpose: Retrieves the list of target ports + * + * targetList - pointer to a pointer to an stmfDevidList structure. + * On success, it contains the list of local ports (target). + */ +int +stmfGetTargetList(stmfDevidList **targetList) +{ + int ret; + int fd; + int ioctlRet; + int i; + stmf_iocdata_t stmfIoctl; + /* framework target port list */ + slist_target_port_t *fTargetList; + uint32_t fTargetListSize; + + if (targetList == NULL) { + return (STMF_ERROR_INVALID_ARG); + } + + /* call init */ + ret = initializeConfig(); + if (ret != STMF_STATUS_SUCCESS) { + return (ret); + } + + /* + * Open control node for stmf + */ + if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS) + return (ret); + + /* + * Allocate ioctl input buffer + */ + fTargetListSize = MAX_TARGET_PORT * sizeof (slist_target_port_t); + fTargetList = (slist_target_port_t *)calloc(1, fTargetListSize); + if (fTargetList == NULL) { + goto done; + } + + bzero(&stmfIoctl, sizeof (stmfIoctl)); + /* + * Issue ioctl to add to the host group + */ + stmfIoctl.stmf_version = STMF_VERSION_1; + stmfIoctl.stmf_obuf_size = fTargetListSize; + stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fTargetList; + ioctlRet = ioctl(fd, STMF_IOCTL_TARGET_PORT_LIST, &stmfIoctl); + if (ioctlRet != 0) { + switch (errno) { + case EBUSY: + ret = STMF_ERROR_BUSY; + break; + case EACCES: + ret = STMF_ERROR_PERM; + break; + default: + syslog(LOG_DEBUG, + "stmfGetTargetList:ioctl errno(%d)", errno); + ret = STMF_STATUS_ERROR; + break; + } + goto done; + } + /* + * Check whether input buffer was large enough + */ + if (stmfIoctl.stmf_obuf_max_nentries > MAX_TARGET_PORT) { + fTargetListSize = stmfIoctl.stmf_obuf_max_nentries * + sizeof (slist_lu_t); + fTargetList = realloc(fTargetList, fTargetListSize); + if (fTargetList == NULL) { + return (STMF_ERROR_NOMEM); + } + stmfIoctl.stmf_obuf_size = fTargetListSize; + stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fTargetList; + ioctlRet = ioctl(fd, STMF_IOCTL_TARGET_PORT_LIST, + &stmfIoctl); + if (ioctlRet != 0) { + switch (errno) { + case EBUSY: + ret = STMF_ERROR_BUSY; + break; + case EACCES: + ret = STMF_ERROR_PERM; + break; + default: + syslog(LOG_DEBUG, + "stmfGetTargetList:ioctl errno(%d)", + errno); + ret = STMF_STATUS_ERROR; + break; + } + goto done; + } + } + + *targetList = (stmfDevidList *)calloc(1, + stmfIoctl.stmf_obuf_max_nentries * sizeof (stmfDevid) + + sizeof (stmfDevidList)); + + (*targetList)->cnt = stmfIoctl.stmf_obuf_max_nentries; + for (i = 0; i < stmfIoctl.stmf_obuf_max_nentries; i++, fTargetList++) { + (*targetList)->devid[i].identLength = + fTargetList->target[IDENT_LENGTH_BYTE]; + bcopy(&fTargetList->target[IDENT_LENGTH_BYTE + 1], + &(*targetList)->devid[i].ident, + fTargetList->target[IDENT_LENGTH_BYTE]); + } + +done: + (void) close(fd); + free(fTargetList); + return (ret); +} + +/* + * stmfGetTargetProperties + * + * Purpose: Retrieves the properties for a logical unit + * + * devid - devid of the target for which to retrieve properties + * targetProps - pointer to an stmfTargetProperties structure. + * On success, it contains the target properties for + * the specified devid. + */ +int +stmfGetTargetProperties(stmfDevid *devid, stmfTargetProperties *targetProps) +{ + int ret = STMF_STATUS_SUCCESS; + int fd; + int ioctlRet; + stmf_iocdata_t stmfIoctl; + sioc_target_port_props_t targetProperties; + + if (devid == NULL || targetProps == NULL) { + return (STMF_ERROR_INVALID_ARG); + } + + /* call init */ + ret = initializeConfig(); + if (ret != STMF_STATUS_SUCCESS) { + return (ret); + } + + /* + * Open control node for stmf + */ + if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS) + return (ret); + + targetProperties.tgt_id[IDENT_LENGTH_BYTE] = devid->identLength; + bcopy(&(devid->ident), &targetProperties.tgt_id[IDENT_LENGTH_BYTE + 1], + devid->identLength); + + bzero(&stmfIoctl, sizeof (stmfIoctl)); + /* + * Issue ioctl to add to the host group + */ + stmfIoctl.stmf_version = STMF_VERSION_1; + stmfIoctl.stmf_ibuf_size = sizeof (targetProperties.tgt_id); + stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&targetProperties.tgt_id; + stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)&targetProperties; + stmfIoctl.stmf_obuf_size = sizeof (targetProperties); + ioctlRet = ioctl(fd, STMF_IOCTL_GET_TARGET_PORT_PROPERTIES, + &stmfIoctl); + if (ioctlRet != 0) { + switch (errno) { + case EBUSY: + ret = STMF_ERROR_BUSY; + break; + case EACCES: + ret = STMF_ERROR_PERM; + break; + case ENOENT: + ret = STMF_ERROR_NOT_FOUND; + break; + default: + syslog(LOG_DEBUG, + "stmfGetTargetProperties:ioctl errno(%d)", + errno); + ret = STMF_STATUS_ERROR; + break; + } + goto done; + } + + bcopy(targetProperties.tgt_provider_name, targetProps->providerName, + sizeof (targetProperties.tgt_provider_name)); + if (targetProperties.tgt_state == STMF_STATE_ONLINE) { + targetProps->status = STMF_TARGET_PORT_ONLINE; + } else if (targetProperties.tgt_state == STMF_STATE_OFFLINE) { + targetProps->status = STMF_TARGET_PORT_OFFLINE; + } else if (targetProperties.tgt_state == STMF_STATE_ONLINING) { + targetProps->status = STMF_TARGET_PORT_ONLINING; + } else if (targetProperties.tgt_state == STMF_STATE_OFFLINING) { + targetProps->status = STMF_TARGET_PORT_OFFLINING; + } + bcopy(targetProperties.tgt_alias, targetProps->alias, + sizeof (targetProps->alias)); +done: + (void) close(fd); + return (ret); +} + +/* + * stmfGetLogicalUnitList + * + * Purpose: Retrieves list of logical unit Object IDs + * + * luList - pointer to a pointer to a stmfGuidList structure. On success, + * it contains the list of logical unit guids. + * + */ +int +stmfGetLogicalUnitList(stmfGuidList **luList) +{ + int ret; + int fd; + int ioctlRet; + int cmd = STMF_IOCTL_LU_LIST; + int i, k; + stmf_iocdata_t stmfIoctl; + /* framework lu list */ + slist_lu_t *fLuList; + /* persistent store lu list */ + stmfGuidList *sLuList = NULL; + int finalListSize = 0; + int newAllocSize; + uint32_t fLuListSize; + uint32_t endList; + + if (luList == NULL) { + return (STMF_ERROR_INVALID_ARG); + } + + /* call init */ + ret = initializeConfig(); + if (ret != STMF_STATUS_SUCCESS) { + return (ret); + } + + /* + * Open control node for stmf + */ + if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS) + return (ret); + + /* + * Allocate ioctl input buffer + */ + fLuListSize = MAX_LU; + fLuListSize = fLuListSize * (sizeof (slist_lu_t)); + fLuList = (slist_lu_t *)calloc(1, fLuListSize); + if (fLuList == NULL) { + return (STMF_ERROR_NOMEM); + } + + bzero(&stmfIoctl, sizeof (stmfIoctl)); + /* + * Issue ioctl to get the LU list + */ + stmfIoctl.stmf_version = STMF_VERSION_1; + stmfIoctl.stmf_obuf_size = fLuListSize; + stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fLuList; + ioctlRet = ioctl(fd, cmd, &stmfIoctl); + if (ioctlRet != 0) { + switch (errno) { + case EBUSY: + ret = STMF_ERROR_BUSY; + break; + case EACCES: + ret = STMF_ERROR_PERM; + break; + default: + syslog(LOG_DEBUG, + "stmfGetLogicalUnitList:ioctl errno(%d)", + errno); + ret = STMF_STATUS_ERROR; + break; + } + goto done; + } + /* + * Check whether input buffer was large enough + */ + if (stmfIoctl.stmf_obuf_max_nentries > MAX_LU) { + fLuListSize = stmfIoctl.stmf_obuf_max_nentries * + sizeof (slist_lu_t); + fLuList = realloc(fLuList, fLuListSize); + if (fLuList == NULL) { + return (STMF_ERROR_NOMEM); + } + stmfIoctl.stmf_obuf_size = fLuListSize; + stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fLuList; + ioctlRet = ioctl(fd, cmd, &stmfIoctl); + if (ioctlRet != 0) { + switch (errno) { + case EBUSY: + ret = STMF_ERROR_BUSY; + break; + case EACCES: + ret = STMF_ERROR_PERM; + break; + default: + syslog(LOG_DEBUG, + "stmfGetLogicalUnitList:" + "ioctl errno(%d)", errno); + ret = STMF_STATUS_ERROR; + break; + } + goto done; + } + } + + ret = psGetLogicalUnitList(&sLuList); + switch (ret) { + case STMF_PS_SUCCESS: + ret = STMF_STATUS_SUCCESS; + break; + case STMF_PS_ERROR_BUSY: + ret = STMF_ERROR_BUSY; + break; + case STMF_PS_ERROR_SERVICE_NOT_FOUND: + ret = STMF_ERROR_SERVICE_NOT_FOUND; + break; + case STMF_PS_ERROR_VERSION_MISMATCH: + ret = STMF_ERROR_SERVICE_DATA_VERSION; + break; + default: + syslog(LOG_DEBUG, + "stmfGetLogicalUnitList:psGetLogicalUnitList" + ":error(%d)", ret); + ret = STMF_STATUS_ERROR; + break; + } + if (ret != STMF_STATUS_SUCCESS) { + goto done; + } + + /* + * 2 lists must be merged + * reallocate the store list to add the list from the + * framework + */ + newAllocSize = sLuList->cnt * sizeof (stmfGuid) + sizeof (stmfGuidList) + + stmfIoctl.stmf_obuf_nentries * sizeof (stmfGuid); + + sLuList = realloc(sLuList, newAllocSize); + if (sLuList == NULL) { + ret = STMF_ERROR_NOMEM; + goto done; + } + + /* + * add list from ioctl. Start from end of list retrieved from store. + */ + endList = sLuList->cnt + stmfIoctl.stmf_obuf_nentries; + for (k = 0, i = sLuList->cnt; i < endList; i++, k++) { + bcopy(&fLuList[k].lu_guid, sLuList->guid[i].guid, + sizeof (stmfGuid)); + } + sLuList->cnt = endList; + + /* + * sort the list for merging + */ + qsort((void *)&(sLuList->guid[0]), sLuList->cnt, + sizeof (stmfGuid), guidCompare); + + /* + * get final list count + */ + for (i = 0; i < sLuList->cnt; i++) { + if ((i + 1) <= sLuList->cnt) { + if (bcmp(sLuList->guid[i].guid, sLuList->guid[i+1].guid, + sizeof (stmfGuid)) == 0) { + continue; + } + } + finalListSize++; + } + + /* + * allocate caller's buffer with the final size + */ + *luList = (stmfGuidList *)calloc(1, sizeof (stmfGuidList) + + finalListSize * sizeof (stmfGuid)); + if (*luList == NULL) { + ret = STMF_ERROR_NOMEM; + goto done; + } + + /* + * copy guids to caller's buffer + */ + for (k = 0, i = 0; i < sLuList->cnt; i++) { + if ((i + 1) <= sLuList->cnt) { + if (bcmp(sLuList->guid[i].guid, sLuList->guid[i+1].guid, + sizeof (stmfGuid)) == 0) { + continue; + } + } + bcopy(&(sLuList->guid[i].guid), (*luList)->guid[k++].guid, + sizeof (stmfGuid)); + } + + (*luList)->cnt = finalListSize; + +done: + (void) close(fd); + /* + * free internal buffers + */ + free(fLuList); + free(sLuList); + return (ret); +} + +/* + * stmfGetLogicalUnitProperties + * + * Purpose: Retrieves the properties for a logical unit + * + * lu - guid of the logical unit for which to retrieve properties + * stmfLuProps - pointer to an stmfLogicalUnitProperties structure. On success, + * it contains the logical unit properties for the specified guid. + */ +int +stmfGetLogicalUnitProperties(stmfGuid *lu, stmfLogicalUnitProperties *luProps) +{ + int ret = STMF_STATUS_SUCCESS; + int stmfRet; + int fd; + int ioctlRet; + int cmd = STMF_IOCTL_GET_LU_PROPERTIES; + stmfViewEntryList *viewEntryList = NULL; + stmf_iocdata_t stmfIoctl; + sioc_lu_props_t fLuProps; + + if (luProps == NULL || luProps == NULL) { + ret = STMF_ERROR_INVALID_ARG; + } + + bzero(luProps, sizeof (stmfLogicalUnitProperties)); + + /* call init */ + ret = initializeConfig(); + if (ret != STMF_STATUS_SUCCESS) { + return (ret); + } + + /* + * Open control node for stmf + */ + if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS) + return (ret); + + bzero(&stmfIoctl, sizeof (stmfIoctl)); + /* + * Issue ioctl to add to the host group + */ + stmfIoctl.stmf_version = STMF_VERSION_1; + stmfIoctl.stmf_ibuf_size = sizeof (stmfGuid); + stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)lu; + stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)&fLuProps; + stmfIoctl.stmf_obuf_size = sizeof (fLuProps); + ioctlRet = ioctl(fd, cmd, &stmfIoctl); + if (ioctlRet != 0) { + switch (errno) { + case EBUSY: + ret = STMF_ERROR_BUSY; + break; + case EACCES: + ret = STMF_ERROR_PERM; + break; + case ENOENT: + stmfRet = stmfGetViewEntryList(lu, + &viewEntryList); + if (stmfRet == STMF_STATUS_SUCCESS) { + luProps->status = + STMF_LOGICAL_UNIT_UNREGISTERED; + if (viewEntryList->cnt > 0) { + ret = STMF_STATUS_SUCCESS; + } else { + ret = STMF_ERROR_NOT_FOUND; + } + } else { + ret = STMF_ERROR_NOT_FOUND; + } + stmfFreeMemory(viewEntryList); + break; + default: + syslog(LOG_DEBUG, + "stmfGetLogicalUnit:ioctl errno(%d)", + errno); + ret = STMF_STATUS_ERROR; + break; + } + goto done; + } + + bcopy(fLuProps.lu_provider_name, luProps->providerName, + sizeof (fLuProps.lu_provider_name)); + if (fLuProps.lu_state == STMF_STATE_ONLINE) { + luProps->status = STMF_LOGICAL_UNIT_ONLINE; + } else if (fLuProps.lu_state == STMF_STATE_OFFLINE) { + luProps->status = STMF_LOGICAL_UNIT_OFFLINE; + } else if (fLuProps.lu_state == STMF_STATE_ONLINING) { + luProps->status = STMF_LOGICAL_UNIT_ONLINING; + } else if (fLuProps.lu_state == STMF_STATE_OFFLINING) { + luProps->status = STMF_LOGICAL_UNIT_OFFLINING; + } + bcopy(fLuProps.lu_alias, luProps->alias, sizeof (luProps->alias)); +done: + (void) close(fd); + return (ret); +} + +/* + * stmfGetState + * + * Purpose: retrieve the current state of the stmf module + * + * state - pointer to stmfState structure allocated by the caller + * On success, contains the state of stmf + */ +int +stmfGetState(stmfState *state) +{ + int ret; + stmf_state_desc_t iState; + + if (state == NULL) { + return (STMF_ERROR_INVALID_ARG); + } + + ret = getStmfState(&iState); + if (ret != STMF_STATUS_SUCCESS) { + return (ret); + } + switch (iState.state) { + case STMF_STATE_ONLINE: + state->operationalState = + STMF_SERVICE_STATE_ONLINE; + break; + case STMF_STATE_OFFLINE: + state->operationalState = + STMF_SERVICE_STATE_OFFLINE; + break; + case STMF_STATE_ONLINING: + state->operationalState = + STMF_SERVICE_STATE_ONLINING; + break; + case STMF_STATE_OFFLINING: + state->operationalState = + STMF_SERVICE_STATE_OFFLINING; + break; + default: + state->operationalState = + STMF_SERVICE_STATE_UNKNOWN; + break; + } + switch (iState.config_state) { + case STMF_CONFIG_NONE: + state->configState = STMF_CONFIG_STATE_NONE; + break; + case STMF_CONFIG_INIT: + state->configState = STMF_CONFIG_STATE_INIT; + break; + case STMF_CONFIG_INIT_DONE: + state->configState = + STMF_CONFIG_STATE_INIT_DONE; + break; + default: + state->configState = + STMF_CONFIG_STATE_UNKNOWN; + break; + } + return (STMF_STATUS_SUCCESS); +} + +/* + * stmfGetViewEntryList + * + * Purpose: Retrieves the list of view entries for the specified + * logical unit. + * + * lu - the guid of the logical unit for which to retrieve the view entry list + * viewEntryList - a pointer to a pointer to a stmfViewEntryList structure. On + * success, contains the list of view entries. + */ +int +stmfGetViewEntryList(stmfGuid *lu, stmfViewEntryList **viewEntryList) +{ + int ret; + + if (lu == NULL || viewEntryList == NULL) { + return (STMF_ERROR_INVALID_ARG); + } + + ret = psGetViewEntryList(lu, viewEntryList); + switch (ret) { + case STMF_PS_SUCCESS: + ret = STMF_STATUS_SUCCESS; + break; + case STMF_PS_ERROR_NOT_FOUND: + ret = STMF_ERROR_NOT_FOUND; + break; + case STMF_PS_ERROR_BUSY: + ret = STMF_ERROR_BUSY; + break; + case STMF_PS_ERROR_SERVICE_NOT_FOUND: + ret = STMF_ERROR_SERVICE_NOT_FOUND; + break; + case STMF_PS_ERROR_VERSION_MISMATCH: + ret = STMF_ERROR_SERVICE_DATA_VERSION; + break; + default: + syslog(LOG_DEBUG, + "stmfGetViewEntryList:error(%d)", ret); + ret = STMF_STATUS_ERROR; + break; + } + + return (ret); +} + +/* + * loadHostGroups + * + * Purpose - issues the ioctl to load the host groups into stmf + * + * fd - file descriptor for the control node of stmf. + * groupList - populated host group list + */ +static int +loadHostGroups(int fd, stmfGroupList *groupList) +{ + int i, j; + int ret = STMF_STATUS_SUCCESS; + stmfGroupProperties *groupProps = NULL; + + for (i = 0; i < groupList->cnt; i++) { + if ((ret = groupIoctl(fd, STMF_IOCTL_CREATE_HOST_GROUP, + &(groupList->name[i]))) != STMF_STATUS_SUCCESS) { + goto out; + } + ret = stmfGetHostGroupMembers(&(groupList->name[i]), + &groupProps); + for (j = 0; j < groupProps->cnt; j++) { + if ((ret = groupMemberIoctl(fd, STMF_IOCTL_ADD_HG_ENTRY, + &(groupList->name[i]), &(groupProps->name[j]))) + != STMF_STATUS_SUCCESS) { + goto out; + } + } + } + + +out: + stmfFreeMemory(groupProps); + return (ret); +} + +/* + * loadTargetGroups + * + * Purpose - issues the ioctl to load the target groups into stmf + * + * fd - file descriptor for the control node of stmf. + * groupList - populated target group list. + */ +static int +loadTargetGroups(int fd, stmfGroupList *groupList) +{ + int i, j; + int ret = STMF_STATUS_SUCCESS; + stmfGroupProperties *groupProps = NULL; + + for (i = 0; i < groupList->cnt; i++) { + if ((ret = groupIoctl(fd, STMF_IOCTL_CREATE_TARGET_GROUP, + &(groupList->name[i]))) != STMF_STATUS_SUCCESS) { + goto out; + } + ret = stmfGetTargetGroupMembers(&(groupList->name[i]), + &groupProps); + for (j = 0; j < groupProps->cnt; j++) { + if ((ret = groupMemberIoctl(fd, STMF_IOCTL_ADD_TG_ENTRY, + &(groupList->name[i]), &(groupProps->name[j]))) + != STMF_STATUS_SUCCESS) { + goto out; + } + } + } + + +out: + stmfFreeMemory(groupProps); + return (ret); +} + + +/* + * loadStore + * + * Purpose: Load the configuration data from the store + * + * First load the host groups and target groups, then the view entries + * and finally the provider data + * + * fd - file descriptor of control node for stmf. + */ +static int +loadStore(int fd) +{ + int ret; + int i, j; + stmfGroupList *groupList = NULL; + stmfGuidList *guidList = NULL; + stmfViewEntryList *viewEntryList = NULL; + stmfProviderList *providerList = NULL; + int providerType; + nvlist_t *nvl = NULL; + + + + /* load host groups */ + ret = stmfGetHostGroupList(&groupList); + if (ret != STMF_STATUS_SUCCESS) { + return (ret); + } + ret = loadHostGroups(fd, groupList); + if (ret != STMF_STATUS_SUCCESS) { + goto out; + } + + stmfFreeMemory(groupList); + groupList = NULL; + + /* load target groups */ + ret = stmfGetTargetGroupList(&groupList); + if (ret != STMF_STATUS_SUCCESS) { + goto out; + } + ret = loadTargetGroups(fd, groupList); + if (ret != STMF_STATUS_SUCCESS) { + goto out; + } + + stmfFreeMemory(groupList); + groupList = NULL; + + /* Get the guid list */ + ret = psGetLogicalUnitList(&guidList); + switch (ret) { + case STMF_PS_SUCCESS: + ret = STMF_STATUS_SUCCESS; + break; + case STMF_PS_ERROR_NOT_FOUND: + ret = STMF_ERROR_NOT_FOUND; + break; + case STMF_PS_ERROR_BUSY: + ret = STMF_ERROR_BUSY; + break; + case STMF_PS_ERROR_SERVICE_NOT_FOUND: + ret = STMF_ERROR_SERVICE_NOT_FOUND; + break; + case STMF_PS_ERROR_VERSION_MISMATCH: + ret = STMF_ERROR_SERVICE_DATA_VERSION; + break; + default: + ret = STMF_STATUS_ERROR; + break; + } + + if (ret != STMF_STATUS_SUCCESS) { + goto out; + } + + /* + * We have the guid list, now get the corresponding + * view entries for each guid + */ + for (i = 0; i < guidList->cnt; i++) { + ret = psGetViewEntryList(&guidList->guid[i], &viewEntryList); + switch (ret) { + case STMF_PS_SUCCESS: + ret = STMF_STATUS_SUCCESS; + break; + case STMF_PS_ERROR_NOT_FOUND: + ret = STMF_ERROR_NOT_FOUND; + break; + case STMF_PS_ERROR_BUSY: + ret = STMF_ERROR_BUSY; + break; + case STMF_PS_ERROR_SERVICE_NOT_FOUND: + ret = STMF_ERROR_SERVICE_NOT_FOUND; + break; + case STMF_PS_ERROR_VERSION_MISMATCH: + ret = STMF_ERROR_SERVICE_DATA_VERSION; + break; + default: + ret = STMF_STATUS_ERROR; + break; + } + if (ret != STMF_STATUS_SUCCESS) { + goto out; + } + for (j = 0; j < viewEntryList->cnt; j++) { + ret = addViewEntryIoctl(fd, &guidList->guid[i], + &viewEntryList->ve[j]); + if (ret != STMF_STATUS_SUCCESS) { + goto out; + } + } + } + + /* get the list of providers that have data */ + ret = psGetProviderDataList(&providerList); + switch (ret) { + case STMF_PS_SUCCESS: + ret = STMF_STATUS_SUCCESS; + break; + case STMF_PS_ERROR_NOT_FOUND: + ret = STMF_ERROR_NOT_FOUND; + break; + case STMF_PS_ERROR_BUSY: + ret = STMF_ERROR_BUSY; + break; + case STMF_PS_ERROR_SERVICE_NOT_FOUND: + ret = STMF_ERROR_SERVICE_NOT_FOUND; + break; + case STMF_PS_ERROR_VERSION_MISMATCH: + ret = STMF_ERROR_SERVICE_DATA_VERSION; + break; + default: + ret = STMF_STATUS_ERROR; + break; + } + if (ret != STMF_STATUS_SUCCESS) { + goto out; + } + + for (i = 0; i < providerList->cnt; i++) { + providerType = providerList->provider[i].providerType; + ret = psGetProviderData(providerList->provider[i].name, + &nvl, providerType, NULL); + switch (ret) { + case STMF_PS_SUCCESS: + ret = STMF_STATUS_SUCCESS; + break; + case STMF_PS_ERROR_NOT_FOUND: + ret = STMF_ERROR_NOT_FOUND; + break; + case STMF_PS_ERROR_BUSY: + ret = STMF_ERROR_BUSY; + break; + case STMF_PS_ERROR_SERVICE_NOT_FOUND: + ret = STMF_ERROR_SERVICE_NOT_FOUND; + break; + case STMF_PS_ERROR_VERSION_MISMATCH: + ret = STMF_ERROR_SERVICE_DATA_VERSION; + break; + default: + ret = STMF_STATUS_ERROR; + break; + } + if (ret != STMF_STATUS_SUCCESS) { + goto out; + } + + /* call setProviderData */ + ret = setProviderData(fd, providerList->provider[i].name, nvl, + providerType); + switch (ret) { + case STMF_PS_SUCCESS: + ret = STMF_STATUS_SUCCESS; + break; + case STMF_PS_ERROR_NOT_FOUND: + ret = STMF_ERROR_NOT_FOUND; + break; + case STMF_PS_ERROR_BUSY: + ret = STMF_ERROR_BUSY; + break; + case STMF_PS_ERROR_SERVICE_NOT_FOUND: + ret = STMF_ERROR_SERVICE_NOT_FOUND; + break; + case STMF_PS_ERROR_VERSION_MISMATCH: + ret = STMF_ERROR_SERVICE_DATA_VERSION; + break; + default: + ret = STMF_STATUS_ERROR; + break; + } + if (ret != STMF_STATUS_SUCCESS) { + goto out; + } + + nvlist_free(nvl); + nvl = NULL; + } +out: + if (groupList != NULL) { + free(groupList); + } + if (guidList != NULL) { + free(guidList); + } + if (viewEntryList != NULL) { + free(viewEntryList); + } + if (nvl != NULL) { + nvlist_free(nvl); + } + return (ret); +} + +/* + * stmfLoadConfig + * + * Purpose - load the configuration data from smf into stmf + * + */ +int +stmfLoadConfig(void) +{ + int ret; + int fd; + stmf_state_desc_t stmfStateSet; + stmfState state; + + + /* Check to ensure service exists */ + if (psCheckService() != STMF_STATUS_SUCCESS) { + return (STMF_ERROR_SERVICE_NOT_FOUND); + } + + ret = stmfGetState(&state); + if (ret == STMF_STATUS_SUCCESS) { + if (state.operationalState != STMF_SERVICE_STATE_OFFLINE) { + return (STMF_ERROR_SERVICE_ONLINE); + } + } else { + return (STMF_STATUS_ERROR); + } + + + stmfStateSet.state = STMF_STATE_OFFLINE; + stmfStateSet.config_state = STMF_CONFIG_INIT; + + /* + * Open control node for stmf + */ + if ((ret = openStmf(OPEN_EXCL_STMF, &fd)) != STMF_STATUS_SUCCESS) + return (ret); + + ret = setStmfState(fd, &stmfStateSet, STMF_SERVICE_TYPE); + if (ret != STMF_STATUS_SUCCESS) { + goto done; + } + + /* Load the persistent configuration data */ + ret = loadStore(fd); + if (ret != 0) { + goto done; + } + + stmfStateSet.state = STMF_STATE_OFFLINE; + stmfStateSet.config_state = STMF_CONFIG_INIT_DONE; + +done: + if (ret == STMF_STATUS_SUCCESS) { + ret = setStmfState(fd, &stmfStateSet, STMF_SERVICE_TYPE); + } + (void) close(fd); + return (ret); +} + +/* + * getStmfState + * + * stmfState - pointer to stmf_state_desc_t structure. Will contain the state + * information of the stmf service on success. + */ +static int +getStmfState(stmf_state_desc_t *stmfState) +{ + int ret = STMF_STATUS_SUCCESS; + int fd; + int ioctlRet; + stmf_iocdata_t stmfIoctl; + + /* + * Open control node for stmf + */ + if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS) + return (ret); + + bzero(&stmfIoctl, sizeof (stmfIoctl)); + /* + * Issue ioctl to get the stmf state + */ + stmfIoctl.stmf_version = STMF_VERSION_1; + stmfIoctl.stmf_ibuf_size = sizeof (stmf_state_desc_t); + stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)stmfState; + stmfIoctl.stmf_obuf_size = sizeof (stmf_state_desc_t); + stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)stmfState; + ioctlRet = ioctl(fd, STMF_IOCTL_GET_STMF_STATE, &stmfIoctl); + + (void) close(fd); + + if (ioctlRet != 0) { + switch (errno) { + case EBUSY: + ret = STMF_ERROR_BUSY; + break; + case EPERM: + case EACCES: + ret = STMF_ERROR_PERM; + break; + default: + syslog(LOG_DEBUG, + "getStmfState:ioctl errno(%d)", errno); + ret = STMF_STATUS_ERROR; + break; + } + } + return (ret); +} + + +/* + * setStmfState + * + * stmfState - pointer to caller set state structure + * objectType - one of: + * LOGICAL_UNIT_TYPE + * TARGET_TYPE + * STMF_SERVICE_TYPE + */ +static int +setStmfState(int fd, stmf_state_desc_t *stmfState, int objectType) +{ + int ret = STMF_STATUS_SUCCESS; + int ioctlRet; + int cmd; + stmf_iocdata_t stmfIoctl; + + switch (objectType) { + case LOGICAL_UNIT_TYPE: + cmd = STMF_IOCTL_SET_LU_STATE; + break; + case TARGET_TYPE: + cmd = STMF_IOCTL_SET_TARGET_PORT_STATE; + break; + case STMF_SERVICE_TYPE: + cmd = STMF_IOCTL_SET_STMF_STATE; + break; + default: + ret = STMF_STATUS_ERROR; + goto done; + } + + bzero(&stmfIoctl, sizeof (stmfIoctl)); + /* + * Issue ioctl to set the stmf state + */ + stmfIoctl.stmf_version = STMF_VERSION_1; + stmfIoctl.stmf_ibuf_size = sizeof (stmf_state_desc_t); + stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)stmfState; + ioctlRet = ioctl(fd, cmd, &stmfIoctl); + if (ioctlRet != 0) { + switch (errno) { + case EBUSY: + ret = STMF_ERROR_BUSY; + break; + case EACCES: + ret = STMF_ERROR_PERM; + break; + case ENOENT: + ret = STMF_ERROR_NOT_FOUND; + break; + default: + syslog(LOG_DEBUG, + "setStmfState:ioctl errno(%d)", errno); + ret = STMF_STATUS_ERROR; + break; + } + } +done: + return (ret); +} + +/* + * stmfOnline + * + * Purpose: Online stmf service + * + */ +int +stmfOnline(void) +{ + int ret; + int fd; + stmfState state; + stmf_state_desc_t iState; + + ret = stmfGetState(&state); + if (ret == STMF_STATUS_SUCCESS) { + if (state.operationalState == STMF_SERVICE_STATE_ONLINE) { + return (STMF_ERROR_SERVICE_ONLINE); + } + } else { + return (STMF_STATUS_ERROR); + } + iState.state = STMF_STATE_ONLINE; + iState.config_state = STMF_CONFIG_NONE; + /* + * Open control node for stmf + * to make call to setStmfState() + */ + if ((ret = openStmf(OPEN_EXCL_STMF, &fd)) != STMF_STATUS_SUCCESS) + return (ret); + ret = setStmfState(fd, &iState, STMF_SERVICE_TYPE); + (void) close(fd); + return (ret); +} + +/* + * stmfOffline + * + * Purpose: Offline stmf service + * + */ +int +stmfOffline(void) +{ + int ret; + int fd; + stmfState state; + stmf_state_desc_t iState; + + ret = stmfGetState(&state); + if (ret == STMF_STATUS_SUCCESS) { + if (state.operationalState == STMF_SERVICE_STATE_OFFLINE) { + return (STMF_ERROR_SERVICE_OFFLINE); + } + } else { + return (STMF_STATUS_ERROR); + } + iState.state = STMF_STATE_OFFLINE; + iState.config_state = STMF_CONFIG_NONE; + + /* + * Open control node for stmf + * to make call to setStmfState() + */ + if ((ret = openStmf(OPEN_EXCL_STMF, &fd)) != STMF_STATUS_SUCCESS) + return (ret); + ret = setStmfState(fd, &iState, STMF_SERVICE_TYPE); + (void) close(fd); + return (ret); +} + + +/* + * stmfOfflineTarget + * + * Purpose: Change state of target to offline + * + * devid - devid of the target to offline + */ +int +stmfOfflineTarget(stmfDevid *devid) +{ + stmf_state_desc_t targetState; + int ret = STMF_STATUS_SUCCESS; + int fd; + + if (devid == NULL) { + return (STMF_ERROR_INVALID_ARG); + } + bzero(&targetState, sizeof (targetState)); + + targetState.state = STMF_STATE_OFFLINE; + targetState.ident[IDENT_LENGTH_BYTE] = devid->identLength; + bcopy(&(devid->ident), &targetState.ident[IDENT_LENGTH_BYTE + 1], + devid->identLength); + /* + * Open control node for stmf + * to make call to setStmfState() + */ + if ((ret = openStmf(OPEN_EXCL_STMF, &fd)) != STMF_STATUS_SUCCESS) + return (ret); + ret = setStmfState(fd, &targetState, TARGET_TYPE); + (void) close(fd); + return (ret); +} + +/* + * stmfOfflineLogicalUnit + * + * Purpose: Change state of logical unit to offline + * + * lu - guid of the logical unit to offline + */ +int +stmfOfflineLogicalUnit(stmfGuid *lu) +{ + stmf_state_desc_t luState; + int ret = STMF_STATUS_SUCCESS; + int fd; + + if (lu == NULL) { + return (STMF_ERROR_INVALID_ARG); + } + + bzero(&luState, sizeof (luState)); + + luState.state = STMF_STATE_OFFLINE; + bcopy(lu, &luState.ident, sizeof (stmfGuid)); + /* + * Open control node for stmf + * to make call to setStmfState() + */ + if ((ret = openStmf(OPEN_EXCL_STMF, &fd)) != STMF_STATUS_SUCCESS) + return (ret); + ret = setStmfState(fd, &luState, LOGICAL_UNIT_TYPE); + (void) close(fd); + return (ret); +} + +/* + * stmfOnlineTarget + * + * Purpose: Change state of target to online + * + * devid - devid of the target to online + */ +int +stmfOnlineTarget(stmfDevid *devid) +{ + stmf_state_desc_t targetState; + int ret = STMF_STATUS_SUCCESS; + int fd; + + if (devid == NULL) { + return (STMF_ERROR_INVALID_ARG); + } + bzero(&targetState, sizeof (targetState)); + + targetState.state = STMF_STATE_ONLINE; + targetState.ident[IDENT_LENGTH_BYTE] = devid->identLength; + bcopy(&(devid->ident), &targetState.ident[IDENT_LENGTH_BYTE + 1], + devid->identLength); + /* + * Open control node for stmf + * to make call to setStmfState() + */ + if ((ret = openStmf(OPEN_EXCL_STMF, &fd)) != STMF_STATUS_SUCCESS) + return (ret); + ret = setStmfState(fd, &targetState, TARGET_TYPE); + (void) close(fd); + return (ret); +} + +/* + * stmfOnlineLogicalUnit + * + * Purpose: Change state of logical unit to online + * + * lu - guid of the logical unit to online + */ +int +stmfOnlineLogicalUnit(stmfGuid *lu) +{ + stmf_state_desc_t luState; + int ret = STMF_STATUS_SUCCESS; + int fd; + + if (lu == NULL) { + return (STMF_ERROR_INVALID_ARG); + } + + bzero(&luState, sizeof (luState)); + + luState.state = STMF_STATE_ONLINE; + bcopy(lu, &luState.ident, sizeof (stmfGuid)); + /* + * Open control node for stmf + * to make call to setStmfState() + */ + if ((ret = openStmf(OPEN_EXCL_STMF, &fd)) != STMF_STATUS_SUCCESS) + return (ret); + ret = setStmfState(fd, &luState, LOGICAL_UNIT_TYPE); + (void) close(fd); + return (ret); +} + +/* + * stmfRemoveFromHostGroup + * + * Purpose: Removes an initiator from an initiator group + * + * hostGroupName - name of an initiator group + * hostName - name of host group member to remove + */ +int +stmfRemoveFromHostGroup(stmfGroupName *hostGroupName, stmfDevid *hostName) +{ + int ret; + int fd; + + if (hostGroupName == NULL || + (strnlen((char *)hostGroupName, sizeof (stmfGroupName)) + == sizeof (stmfGroupName)) || hostName == NULL) { + return (STMF_ERROR_INVALID_ARG); + } + + /* call init */ + ret = initializeConfig(); + if (ret != STMF_STATUS_SUCCESS) { + return (ret); + } + + /* + * Open control node for stmf + */ + if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS) + return (ret); + + if ((ret = groupMemberIoctl(fd, STMF_IOCTL_REMOVE_HG_ENTRY, + hostGroupName, hostName)) != STMF_STATUS_SUCCESS) { + goto done; + } + + ret = psRemoveHostGroupMember((char *)hostGroupName, + (char *)hostName->ident); + switch (ret) { + case STMF_PS_SUCCESS: + ret = STMF_STATUS_SUCCESS; + break; + case STMF_PS_ERROR_MEMBER_NOT_FOUND: + ret = STMF_ERROR_MEMBER_NOT_FOUND; + break; + case STMF_PS_ERROR_GROUP_NOT_FOUND: + ret = STMF_ERROR_GROUP_NOT_FOUND; + break; + case STMF_PS_ERROR_BUSY: + ret = STMF_ERROR_BUSY; + break; + case STMF_PS_ERROR_SERVICE_NOT_FOUND: + ret = STMF_ERROR_SERVICE_NOT_FOUND; + break; + case STMF_PS_ERROR_VERSION_MISMATCH: + ret = STMF_ERROR_SERVICE_DATA_VERSION; + break; + default: + syslog(LOG_DEBUG, + "stmfRemoveFromHostGroup" + "psRemoveHostGroupMember:error(%d)", ret); + ret = STMF_STATUS_ERROR; + break; + } + +done: + (void) close(fd); + return (ret); +} + +/* + * stmfRemoveFromTargetGroup + * + * Purpose: Removes a local port from a local port group + * + * targetGroupName - name of a target group + * targetName - name of target to remove + */ +int +stmfRemoveFromTargetGroup(stmfGroupName *targetGroupName, stmfDevid *targetName) +{ + int ret; + int fd; + + if (targetGroupName == NULL || + (strnlen((char *)targetGroupName, sizeof (stmfGroupName)) + == sizeof (stmfGroupName)) || targetName == NULL) { + return (STMF_ERROR_INVALID_ARG); + } + + /* call init */ + ret = initializeConfig(); + if (ret != STMF_STATUS_SUCCESS) { + return (ret); + } + + /* + * Open control node for stmf + */ + if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS) + return (ret); + + if ((ret = groupMemberIoctl(fd, STMF_IOCTL_REMOVE_TG_ENTRY, + targetGroupName, targetName)) != STMF_STATUS_SUCCESS) { + goto done; + } + + ret = psRemoveTargetGroupMember((char *)targetGroupName, + (char *)targetName->ident); + switch (ret) { + case STMF_PS_SUCCESS: + ret = STMF_STATUS_SUCCESS; + break; + case STMF_PS_ERROR_MEMBER_NOT_FOUND: + ret = STMF_ERROR_MEMBER_NOT_FOUND; + break; + case STMF_PS_ERROR_GROUP_NOT_FOUND: + ret = STMF_ERROR_GROUP_NOT_FOUND; + break; + case STMF_PS_ERROR_BUSY: + ret = STMF_ERROR_BUSY; + break; + case STMF_PS_ERROR_SERVICE_NOT_FOUND: + ret = STMF_ERROR_SERVICE_NOT_FOUND; + break; + case STMF_PS_ERROR_VERSION_MISMATCH: + ret = STMF_ERROR_SERVICE_DATA_VERSION; + break; + default: + syslog(LOG_DEBUG, + "stmfRemoveFromTargetGroup" + "psRemoveTargetGroupMember:error(%d)", ret); + ret = STMF_STATUS_ERROR; + break; + } + +done: + (void) close(fd); + return (ret); +} + +/* + * stmfRemoveViewEntry + * + * Purpose: Removes a view entry from a logical unit + * + * lu - guid of lu for which view entry is being removed + * viewEntryIndex - index of view entry to remove + * + */ +int +stmfRemoveViewEntry(stmfGuid *lu, uint32_t viewEntryIndex) +{ + int ret = STMF_STATUS_SUCCESS; + int fd; + int ioctlRet; + stmf_iocdata_t stmfIoctl; + stmf_view_op_entry_t ioctlViewEntry; + + if (lu == NULL) { + return (STMF_ERROR_INVALID_ARG); + } + + /* call init */ + ret = initializeConfig(); + if (ret != STMF_STATUS_SUCCESS) { + return (ret); + } + + /* + * Open control node for stmf + */ + if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS) + return (ret); + + bzero(&ioctlViewEntry, sizeof (ioctlViewEntry)); + ioctlViewEntry.ve_ndx_valid = B_TRUE; + ioctlViewEntry.ve_ndx = viewEntryIndex; + bcopy(lu, &ioctlViewEntry.ve_guid, sizeof (stmfGuid)); + + bzero(&stmfIoctl, sizeof (stmfIoctl)); + /* + * Issue ioctl to add to the view entry + */ + stmfIoctl.stmf_version = STMF_VERSION_1; + stmfIoctl.stmf_ibuf_size = sizeof (ioctlViewEntry); + stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&ioctlViewEntry; + ioctlRet = ioctl(fd, STMF_IOCTL_REMOVE_VIEW_ENTRY, &stmfIoctl); + if (ioctlRet != 0) { + switch (errno) { + case EBUSY: + ret = STMF_ERROR_BUSY; + break; + case EACCES: + switch (stmfIoctl.stmf_error) { + case STMF_IOCERR_UPDATE_NEED_CFG_INIT: + ret = STMF_ERROR_CONFIG_NONE; + break; + default: + ret = STMF_ERROR_PERM; + break; + } + break; + case ENODEV: + case ENOENT: + ret = STMF_ERROR_NOT_FOUND; + break; + default: + syslog(LOG_DEBUG, + "stmfRemoveViewEntry:ioctl errno(%d)", + errno); + ret = STMF_STATUS_ERROR; + break; + } + goto done; + } + + ret = psRemoveViewEntry(lu, viewEntryIndex); + switch (ret) { + case STMF_PS_SUCCESS: + ret = STMF_STATUS_SUCCESS; + break; + case STMF_PS_ERROR_NOT_FOUND: + ret = STMF_ERROR_NOT_FOUND; + break; + case STMF_PS_ERROR_BUSY: + ret = STMF_ERROR_BUSY; + break; + case STMF_PS_ERROR_SERVICE_NOT_FOUND: + ret = STMF_ERROR_SERVICE_NOT_FOUND; + break; + case STMF_PS_ERROR_VERSION_MISMATCH: + ret = STMF_ERROR_SERVICE_DATA_VERSION; + break; + default: + syslog(LOG_DEBUG, + "stmfRemoveViewEntry" "psRemoveViewEntry:error(%d)", + ret); + ret = STMF_STATUS_ERROR; + break; + } + +done: + (void) close(fd); + return (ret); +} + +/* + * stmfSetProviderData + * + * Purpose: set the provider data + * + * providerName - unique name of provider + * nvl - nvlist to set + * providerType - type of provider for which to set data + * STMF_LU_PROVIDER_TYPE + * STMF_PORT_PROVIDER_TYPE + */ +int +stmfSetProviderData(char *providerName, nvlist_t *nvl, int providerType) +{ + return (stmfSetProviderDataProt(providerName, nvl, providerType, + NULL)); +} + +/* + * stmfSetProviderDataProt + * + * Purpose: set the provider data + * + * providerName - unique name of provider + * nvl - nvlist to set + * providerType - type of provider for which to set data + * STMF_LU_PROVIDER_TYPE + * STMF_PORT_PROVIDER_TYPE + * setToken - Stale data token returned in the stmfGetProviderDataProt() + * call or NULL. + */ +int +stmfSetProviderDataProt(char *providerName, nvlist_t *nvl, int providerType, + uint64_t *setToken) +{ + int ret; + int fd; + + if (providerName == NULL || nvl == NULL) { + return (STMF_ERROR_INVALID_ARG); + } + + if (providerType != STMF_LU_PROVIDER_TYPE && + providerType != STMF_PORT_PROVIDER_TYPE) { + return (STMF_ERROR_INVALID_ARG); + } + + /* call init */ + ret = initializeConfig(); + if (ret != STMF_STATUS_SUCCESS) { + return (ret); + } + + /* + * Open control node for stmf + */ + if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS) + return (ret); + + ret = setProviderData(fd, providerName, nvl, providerType); + + (void) close(fd); + + if (ret != STMF_STATUS_SUCCESS) { + goto done; + } + + /* setting driver provider data successful. Now persist it */ + ret = psSetProviderData(providerName, nvl, providerType, setToken); + switch (ret) { + case STMF_PS_SUCCESS: + ret = STMF_STATUS_SUCCESS; + break; + case STMF_PS_ERROR_EXISTS: + ret = STMF_ERROR_EXISTS; + break; + case STMF_PS_ERROR_BUSY: + ret = STMF_ERROR_BUSY; + break; + case STMF_PS_ERROR_SERVICE_NOT_FOUND: + ret = STMF_ERROR_SERVICE_NOT_FOUND; + break; + case STMF_PS_ERROR_VERSION_MISMATCH: + ret = STMF_ERROR_SERVICE_DATA_VERSION; + break; + case STMF_PS_ERROR_PROV_DATA_STALE: + ret = STMF_ERROR_PROV_DATA_STALE; + break; + default: + syslog(LOG_DEBUG, + "stmfSetProviderData" + "psSetProviderData:error(%d)", ret); + ret = STMF_STATUS_ERROR; + break; + } + +done: + return (ret); +} + +/* + * setProviderData + * + * Purpose: set the provider data + * + * providerName - unique name of provider + * nvl - nvlist to set + * providerType - logical unit or port provider + */ +static int +setProviderData(int fd, char *providerName, nvlist_t *nvl, int providerType) +{ + int ret = STMF_STATUS_SUCCESS; + int ioctlRet; + size_t nvlistEncodedSize; + stmf_ppioctl_data_t *ppi = NULL; + char *allocatedNvBuffer; + stmf_iocdata_t stmfIoctl; + + if (providerName == NULL) { + return (STMF_ERROR_INVALID_ARG); + } + + /* get size of encoded nvlist */ + if (nvlist_size(nvl, &nvlistEncodedSize, NV_ENCODE_XDR) != 0) { + return (STMF_STATUS_ERROR); + } + + /* allocate memory for ioctl */ + ppi = (stmf_ppioctl_data_t *)calloc(1, nvlistEncodedSize + + sizeof (stmf_ppioctl_data_t)); + if (ppi == NULL) { + return (STMF_ERROR_NOMEM); + } + + allocatedNvBuffer = (char *)&ppi->ppi_data; + if (nvlist_pack(nvl, &allocatedNvBuffer, &nvlistEncodedSize, + NV_ENCODE_XDR, 0) != 0) { + return (STMF_STATUS_ERROR); + } + + /* set provider name and provider type */ + (void) strncpy(ppi->ppi_name, providerName, sizeof (ppi->ppi_name)); + switch (providerType) { + case STMF_LU_PROVIDER_TYPE: + ppi->ppi_lu_provider = 1; + break; + case STMF_PORT_PROVIDER_TYPE: + ppi->ppi_port_provider = 1; + break; + default: + return (STMF_ERROR_INVALID_ARG); + } + + /* set the size of the ioctl data to packed data size */ + ppi->ppi_data_size = nvlistEncodedSize; + + bzero(&stmfIoctl, sizeof (stmfIoctl)); + + stmfIoctl.stmf_version = STMF_VERSION_1; + /* + * Subtracting 8 from the size as that is the size of the last member + * of the structure where the packed data resides + */ + stmfIoctl.stmf_ibuf_size = nvlistEncodedSize + + sizeof (stmf_ppioctl_data_t) - 8; + stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)ppi; + ioctlRet = ioctl(fd, STMF_IOCTL_LOAD_PP_DATA, &stmfIoctl); + if (ioctlRet != 0) { + switch (errno) { + case EBUSY: + ret = STMF_ERROR_BUSY; + break; + case EACCES: + ret = STMF_ERROR_PERM; + break; + default: + syslog(LOG_DEBUG, + "setProviderData:ioctl errno(%d)", errno); + ret = STMF_STATUS_ERROR; + break; + } + if (ret != STMF_STATUS_SUCCESS) + goto done; + } + +done: + free(ppi); + return (ret); +} diff --git a/usr/src/lib/libstmf/common/store.c b/usr/src/lib/libstmf/common/store.c new file mode 100644 index 0000000000..9e20376233 --- /dev/null +++ b/usr/src/lib/libstmf/common/store.c @@ -0,0 +1,4747 @@ +/* + * 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 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#include <libscf.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <assert.h> +#include <strings.h> +#include <libstmf.h> +#include <store.h> +#include <syslog.h> +#include <signal.h> +#include <pthread.h> +#include <libnvpair.h> +#include <limits.h> +#include <unistd.h> + +/* + * 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-<N> where <N> is an unsigned integer + * type: ustring + * contains: group name + * group_name-<N>-member_list where <N> is an unsigned + * integer matching a group_name-<N> 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-<N> where <N> is an unsigned integer + * type: ustring + * contains: group name + * group_name-<N>-member_list where <N> is an unsigned + * integer matching a group_name-<N> 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-<GUID> + * where <GUID> is a 32 character hexadecimal string. + * Properties: ve_cnt + * type: count + * contains: the number of current view entries + * view-entry-<N>-<GUID> where <N> 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-<GUID> + * 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-<N>-<GUID> (matches property in lu-<GUID> + * 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-<N>-<GUID>" property group will exist for each + * view entry in the system. This property group name maps + * directly to the "lu-<GUID>" property group with a matching + * <GUID>. + * + * 5. Property Group: provider_data_pg_<provider-name> + * where <provider-name> is the name of the provider + * registered with stmf. + * Properties: provider_data_prop-<N> + * where <N> 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 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 + +/* + * 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" + +/* + * 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" +/* + * This is the data chunk size. The current value limit for scf is 4096. + * This is defined by REP_PROTOCOL_VALUE_LEN in + * OS/Net: usr/src/common/svc/repcache_protocol.h + * + * Larger data property size = better performance + */ +#define STMF_PROVIDER_DATA_PROP_SIZE 4000 + +#define STMF_SMF_READ_ATTR "solaris.smf.read.stmf" + + +/* 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 + +/* + * 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 { + syslog(LOG_ERR, "get pg failed - %s", + scf_strerror(scf_error())); + ret = STMF_PS_ERROR; + } + goto out; + } + + /* + * Begin the transaction + */ + if (scf_transaction_start(tran, pg) == -1) { + syslog(LOG_ERR, "start transaction failed - %s", + 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 failed - %s", + scf_strerror(scf_error())); + } + goto out; + } + + /* + * Get the property handle + */ + if (scf_pg_get_property(pg, groupName, prop) == -1) { + syslog(LOG_ERR, "get property failed - %s", + 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 failed - %s", + 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 value failed - %s", + 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 value failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 pg failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 new failed - %s", + 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 failed - %s", + 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 value failed - %s", + 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 integer value failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed" + "possible inconsistency - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + scf_strerror(scf_error())); + ret = STMF_PS_ERROR; + } + } else if (scf_error() == SCF_ERROR_NOT_FOUND) { + ret = STMF_PS_ERROR_NOT_FOUND; + } else { + syslog(LOG_ERR, "get pg failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + scf_strerror(scf_error())); + ret = STMF_PS_ERROR; + break; + } + if (scf_value_get_ustring(value, tmpbuf, + sizeof (tmpbuf)) == -1) { + syslog(LOG_ERR, "get ustring failed - %s", + 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 pg failed - %s", + 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 failed - %s", + 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 failed - %s", + scf_strerror(scf_error())); + ret = STMF_PS_ERROR; + goto out; + } + if (scf_value_set_ustring(value, groupName) == -1) { + syslog(LOG_ERR, "set ustring failed - %s", + scf_strerror(scf_error())); + ret = STMF_PS_ERROR; + goto out; + } + if (scf_entry_add_value(entry1, value) == -1) { + syslog(LOG_ERR, "add value failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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) { + ret = STMF_PS_ERROR_NOT_FOUND; + } else { + syslog(LOG_ERR, "get pg failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + scf_strerror(scf_error())); + ret = STMF_PS_ERROR; + break; + } + if (scf_value_get_ustring(value, buf, sizeof (buf)) == -1) { + syslog(LOG_ERR, "get ustring failed - %s", + 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 { + syslog(LOG_ERR, "get pg failed - %s", + scf_strerror(scf_error())); + ret = STMF_PS_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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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); +} + +/* + * 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + scf_strerror(scf_error())); + ret = STMF_PS_ERROR; + goto out; + } + if ((commitRet = scf_transaction_commit(tran)) != 1) { + syslog(LOG_ERR, "transaction commit failed - %s", + 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 failed - %s", + scf_strerror(scf_error())); + ret = STMF_PS_ERROR; + goto out; + } + + if (scf_property_get_value(prop, value) == -1) { + syslog(LOG_ERR, "get property value failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + scf_strerror(scf_error())); + ret = STMF_PS_ERROR; + break; + } + if (scf_value_get_ustring(value, buf, sizeof (buf)) == -1) { + syslog(LOG_ERR, "get ustring failed - %s", + 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-<view_entry_name>-<lu_name> + */ + (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 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 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-<guid>) */ + (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 failed - %s", + 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 failed - %s", + scf_strerror(scf_error())); + ret = STMF_PS_ERROR; + goto out; + } + + if (scf_property_get_value(prop, value) == -1) { + syslog(LOG_ERR, "get property value failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 pg iter service failed - %s", + 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 failed - %s", + scf_strerror(scf_error())); + ret = STMF_PS_ERROR; + } + goto out; + } + + + /* + * get index + * format is: VE-<veIndex>-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 failed - %s", + scf_strerror(scf_error())); + ret = STMF_PS_ERROR; + goto out; + } + + if (scf_property_get_value(prop, value) == -1) { + syslog(LOG_ERR, "get property failed - %s", + 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 failed - %s", + 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 failed - %s", + scf_strerror(scf_error())); + ret = STMF_PS_ERROR; + goto out; + } + + if (scf_property_get_value(prop, value) == -1) { + syslog(LOG_ERR, "get property failed - %s", + scf_strerror(scf_error())); + ret = STMF_PS_ERROR; + goto out; + } + + if (scf_value_get_ustring(value, groupName, + sizeof (groupName)) == -1) { + syslog(LOG_ERR, "set value failed - %s", + 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 failed - %s", + scf_strerror(scf_error())); + ret = STMF_PS_ERROR; + goto out; + } + + if (scf_property_get_value(prop, value) == -1) { + syslog(LOG_ERR, "get property failed - %s", + 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 property failed - %s", + 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 failed - %s", + scf_strerror(scf_error())); + ret = STMF_PS_ERROR; + goto out; + } + + if (scf_property_get_value(prop, value) == -1) { + syslog(LOG_ERR, "get property failed - %s", + scf_strerror(scf_error())); + ret = STMF_PS_ERROR; + goto out; + } + + if (scf_value_get_ustring(value, groupName, + sizeof (groupName)) == -1) { + syslog(LOG_ERR, "set value failed - %s", + 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 failed - %s", + scf_strerror(scf_error())); + ret = STMF_PS_ERROR; + goto out; + } + + if (scf_property_get_value(prop, value) == -1) { + syslog(LOG_ERR, "get property value failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + scf_strerror(scf_error())); + ret = STMF_PS_ERROR; + goto out; + } + + if (scf_property_get_value(prop, value) == -1) { + syslog(LOG_ERR, "get property value failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed"); + 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 failed"); + ret = STMF_PS_ERROR_NOMEM; + goto out; + } + + addValue = (scf_value_t **)calloc(1, sizeof (*addValue) + * blockCnt); + if (addValue == NULL) { + syslog(LOG_ERR, "value alloc failed"); + 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 failed"); + 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 failed - %s", + 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 failed - %s", + scf_strerror(scf_error())); + ret = STMF_PS_ERROR; + goto out; + } + } else { + syslog(LOG_ERR, + "transaction property new failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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 failed - %s", + 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, "get property failed - %s", + 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 new failed - %s", + 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 failed - %s", + scf_strerror(scf_error())); + ret = STMF_PS_ERROR; + goto out; + } + + if (scf_entry_add_value(entry1, value1) == -1) { + syslog(LOG_ERR, "add value failed - %s", + 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 failed - %s", + scf_strerror(scf_error())); + ret = STMF_PS_ERROR; + goto out; + } + } else { + syslog(LOG_ERR, "transaction property new failed - %s", + 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 failed - %s", + 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 failed - %s", + scf_strerror(scf_error())); + ret = STMF_PS_ERROR; + goto out; + } + } else { + syslog(LOG_ERR, "transaction property new failed - %s", + 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 failed - %s", + 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 failed - %s", + scf_strerror(scf_error())); + ret = STMF_PS_ERROR; + goto out; + } + } else { + syslog(LOG_ERR, "transaction property new failed - %s", + 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 failed - %s", + scf_strerror(scf_error())); + ret = STMF_PS_ERROR; + goto out; + } + + + if ((commitRet = scf_transaction_commit(tran)) != 1) { + syslog(LOG_ERR, "transaction commit failed - %s", + 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-<view_entry_index>-<lu_name> + */ + (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 failed - %s", + 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-<view_entry_index>-<lu_name> + */ + (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 failed - %s", + 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 failed - %s", + scf_strerror(scf_error())); + if ((ret = iPsAddRemoveLuViewEntry(luPgName, viewEntryPgName, + ADD)) != STMF_PS_SUCCESS) { + syslog(LOG_ERR, "add of view entry failed, possible" + "inconsistency - %s", 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); +} diff --git a/usr/src/lib/libstmf/common/store.h b/usr/src/lib/libstmf/common/store.h new file mode 100644 index 0000000000..2f19963755 --- /dev/null +++ b/usr/src/lib/libstmf/common/store.h @@ -0,0 +1,81 @@ +/* + * 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 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +#ifndef _STORE_H +#define _STORE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <libnvpair.h> + +/* + * Error defines + */ +#define STMF_PS_SUCCESS 0 +#define STMF_PS_ERROR 1 +#define STMF_PS_ERROR_MEMBER_NOT_FOUND 2 +#define STMF_PS_ERROR_GROUP_NOT_FOUND 3 +#define STMF_PS_ERROR_NOT_FOUND 4 +#define STMF_PS_ERROR_EXISTS 5 +#define STMF_PS_ERROR_NOMEM 6 +#define STMF_PS_ERROR_RETRY 7 +#define STMF_PS_ERROR_BUSY 8 +#define STMF_PS_ERROR_SERVICE_NOT_FOUND 9 +#define STMF_PS_ERROR_INVALID_ARG 10 +#define STMF_PS_ERROR_VERSION_MISMATCH 11 +#define STMF_PS_ERROR_PROV_DATA_STALE 12 + +int psAddHostGroupMember(char *groupName, char *memberName); +int psAddTargetGroupMember(char *groupName, char *memberName); +int psAddViewEntry(stmfGuid *lu, stmfViewEntry *viewEntry); +int psCreateHostGroup(char *groupName); +int psDeleteHostGroup(char *groupName); +int psCreateTargetGroup(char *groupName); +int psDeleteTargetGroup(char *groupName); +int psGetViewEntry(stmfGuid *lu, uint32_t viewEntryIndex, stmfViewEntry *ve); +int psGetLogicalUnitList(stmfGuidList **guidList); +int psRemoveHostGroupMember(char *groupName, char *memberName); +int psRemoveTargetGroupMember(char *groupName, char *memberName); +int psRemoveViewEntry(stmfGuid *lu, uint32_t viewEntryIndex); +int psGetHostGroupList(stmfGroupList **groupList); +int psGetTargetGroupList(stmfGroupList **groupList); +int psGetHostGroupMemberList(char *groupName, stmfGroupProperties **groupList); +int psGetTargetGroupMemberList(char *groupName, + stmfGroupProperties **groupList); +int psGetViewEntryList(stmfGuid *lu, stmfViewEntryList **viewEntryList); +int psCheckService(); +int psSetProviderData(char *providerName, nvlist_t *nvl, int providerType, + uint64_t *setHandle); +int psGetProviderData(char *providerName, nvlist_t **nvl, int providerType, + uint64_t *setHandle); +int psGetProviderDataList(stmfProviderList **providerList); +int psClearProviderData(char *providerName, int providerType); + +#ifdef __cplusplus +} +#endif + +#endif /* _STORE_H */ |
