diff options
Diffstat (limited to 'usr/src/cmd')
-rw-r--r-- | usr/src/cmd/stmfadm/stmfadm.c | 3514 | ||||
-rw-r--r-- | usr/src/cmd/stmfadm/stmfadm.h | 73 | ||||
-rw-r--r-- | usr/src/cmd/stmfsvc/stmf.xml | 119 | ||||
-rw-r--r-- | usr/src/cmd/stmfsvc/stmfsvc.c | 307 |
4 files changed, 4013 insertions, 0 deletions
diff --git a/usr/src/cmd/stmfadm/stmfadm.c b/usr/src/cmd/stmfadm/stmfadm.c new file mode 100644 index 0000000..0c98614 --- /dev/null +++ b/usr/src/cmd/stmfadm/stmfadm.c @@ -0,0 +1,3514 @@ +/* + * 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 2010 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * Copyright 2012 Milan Jurik. All rights reserved. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <strings.h> +#include <sys/types.h> +#include <unistd.h> +#include <wchar.h> +#include <libintl.h> +#include <errno.h> +#include <time.h> +#include <string.h> +#include <assert.h> +#include <getopt.h> +#include <cmdparse.h> +#include <stmfadm.h> +#include <libstmf.h> +#include <signal.h> +#include <pthread.h> +#include <locale.h> + +static int addHostGroupMemberFunc(int, char **, cmdOptions_t *, void *); +static int addTargetGroupMemberFunc(int, char **, cmdOptions_t *, void *); +static int addViewFunc(int, char **, cmdOptions_t *, void *); +static int createHostGroupFunc(int, char **, cmdOptions_t *, void *); +static int createLuFunc(int, char **, cmdOptions_t *, void *); +static int modifyLuFunc(int, char **, cmdOptions_t *, void *); +static int importLuFunc(int, char **, cmdOptions_t *, void *); +static int deleteLuFunc(int, char **, cmdOptions_t *, void *); +static int createTargetGroupFunc(int, char **, cmdOptions_t *, void *); +static int deleteHostGroupFunc(int, char **, cmdOptions_t *, void *); +static int deleteTargetGroupFunc(int, char **, cmdOptions_t *, void *); +static int listLuFunc(int, char **, cmdOptions_t *, void *); +static int listTargetFunc(int, char **, cmdOptions_t *, void *); +static int listViewFunc(int, char **, cmdOptions_t *, void *); +static int listHostGroupFunc(int, char **, cmdOptions_t *, void *); +static int listStateFunc(int, char **, cmdOptions_t *, void *); +static int listTargetGroupFunc(int, char **, cmdOptions_t *, void *); +static int offlineTargetFunc(int, char **, cmdOptions_t *, void *); +static int offlineLuFunc(int, char **, cmdOptions_t *, void *); +static int onlineTargetFunc(int, char **, cmdOptions_t *, void *); +static int onlineLuFunc(int, char **, cmdOptions_t *, void *); +static int onlineOfflineTarget(char *, int); +static int onlineOfflineLu(char *, int); +static int removeHostGroupMemberFunc(int, char **, cmdOptions_t *, void *); +static int removeTargetGroupMemberFunc(int, char **, cmdOptions_t *, void *); +static int callModify(char *, stmfGuid *, uint32_t, const char *, const char *); +static int removeViewFunc(int, char **, cmdOptions_t *, void *); +static char *getExecBasename(char *); +static int parseDevid(char *input, stmfDevid *devid); +static void printGroupProps(stmfGroupProperties *groupProps); +static int checkScsiNameString(wchar_t *, stmfDevid *); +static int checkHexUpper(char *); +static int checkIscsiName(wchar_t *); +static void printLuProps(stmfLogicalUnitProperties *luProps); +static int printExtLuProps(stmfGuid *guid); +static void printGuid(stmfGuid *guid, FILE *printWhere); +static void printTargetProps(stmfTargetProperties *); +static void printSessionProps(stmfSessionList *); +static int setLuPropFromInput(luResource, char *); +static int convertCharToPropId(char *, uint32_t *); + + + +/* + * MAJOR - This should only change when there is an incompatible change made + * to the interfaces or the output. + * + * MINOR - This should change whenever there is a new command or new feature + * with no incompatible change. + */ +#define VERSION_STRING_MAJOR "1" +#define VERSION_STRING_MINOR "0" +#define MAX_DEVID_INPUT 256 +#define GUID_INPUT 32 +#define MAX_LU_NBR 16383 +#define ONLINE_LU 0 +#define OFFLINE_LU 1 +#define ONLINE_TARGET 2 +#define OFFLINE_TARGET 3 +#define PROPS_FORMAT " %-18s: " +#define VIEW_FORMAT " %-13s: " +#define LVL3_FORMAT " %s" +#define LVL4_FORMAT " %s" +#define DELAYED_EXEC_WAIT_INTERVAL 300 * 1000 * 1000 /* in nano sec */ +#define DELAYED_EXEC_WAIT_MAX 30 /* Maximum number of interval times */ + +/* SCSI Name String length definitions */ +#define SNS_EUI_16 16 +#define SNS_EUI_24 24 +#define SNS_EUI_32 32 +#define SNS_NAA_16 16 +#define SNS_NAA_32 32 +#define SNS_WWN_16 16 +#define SNS_IQN_223 223 + +/* LU Property strings */ +#define GUID "GUID" +#define ALIAS "ALIAS" +#define VID "VID" +#define PID "PID" +#define META_FILE "META" +#define WRITE_PROTECT "WP" +#define WRITEBACK_CACHE_DISABLE "WCD" +#define COMPANY_ID "OUI" +#define BLOCK_SIZE "BLK" +#define SERIAL_NUMBER "SERIAL" +#define MGMT_URL "MGMT-URL" +#define HOST_ID "HOST-ID" + +#define STMFADM_SUCCESS 0 +#define STMFADM_FAILURE 1 + +#define MODIFY_HELP "\n"\ +"Description: Modify properties of a logical unit. \n" \ +"Valid properties for -p, --lu-prop are: \n" \ +" alias - alias for logical unit (up to 255 chars)\n" \ +" mgmt-url - Management URL address\n" \ +" wcd - write cache disabled (true, false)\n" \ +" wp - write protect (true, false)\n\n" \ +"-f alters the meaning of the operand to be a file name\n" \ +"rather than a LU name. This allows for modification\n" \ +"of a logical unit that is not yet imported into stmf\n" + +#define CREATE_HELP "\n"\ +"Description: Create a logical unit. \n" \ +"Valid properties for -p, --lu-prop are: \n" \ +" alias - alias for logical unit (up to 255 chars)\n" \ +" blk - block size in bytes in 2^n\n" \ +" guid - 32 ascii hex characters in NAA format \n" \ +" host-id - host identifier to be used for GUID generation \n" \ +" 8 ascii hex characters\n" \ +" meta - separate meta data file name\n" \ +" mgmt-url - Management URL address\n" \ +" oui - organizational unique identifier\n" \ +" 6 ascii hex characters of valid format\n" \ +" pid - product identifier (up to 16 chars)\n" \ +" serial - serial number (up to 252 chars)\n" \ +" vid - vendor identifier (up to 8 chars)\n" \ +" wcd - write cache disabled (true, false)\n" \ +" wp - write protect (true, false)\n" +#define ADD_VIEW_HELP "\n"\ +"Description: Add a view entry to a logical unit. \n" \ +"A view entry is comprised of three elements; the \n" \ +"logical unit number, the target group name and the\n" \ +"host group name. These three elements combine together\n" \ +"to form a view for a given COMSTAR logical unit.\n" \ +"This view is realized by a client, a SCSI initiator,\n" \ +"via a REPORT LUNS command. \n" + + + +/* tables set up based on cmdparse instructions */ + +/* add new options here */ +optionTbl_t longOptions[] = { + {"all", no_arg, 'a', NULL}, + {"group-name", required_arg, 'g', "group-name"}, + {"keep-views", no_arg, 'k', NULL}, + {"lu-name", required_arg, 'l', "LU-Name"}, + {"lun", required_arg, 'n', "logical-unit-number"}, + {"lu-prop", required_arg, 'p', "logical-unit-property=value"}, + {"file", no_arg, 'f', "filename"}, + {"size", required_arg, 's', "size K/M/G/T/P"}, + {"target-group", required_arg, 't', "group-name"}, + {"host-group", required_arg, 'h', "group-name"}, + {"verbose", no_arg, 'v', NULL}, + {NULL, 0, 0, 0} +}; + +/* + * Add new subcommands here + */ +subCommandProps_t subcommands[] = { + {"add-hg-member", addHostGroupMemberFunc, "g", "g", NULL, + OPERAND_MANDATORY_MULTIPLE, OPERANDSTRING_GROUP_MEMBER, NULL}, + {"add-tg-member", addTargetGroupMemberFunc, "g", "g", NULL, + OPERAND_MANDATORY_MULTIPLE, OPERANDSTRING_GROUP_MEMBER, NULL}, + {"add-view", addViewFunc, "nth", NULL, NULL, + OPERAND_MANDATORY_SINGLE, OPERANDSTRING_LU, ADD_VIEW_HELP}, + {"create-hg", createHostGroupFunc, NULL, NULL, NULL, + OPERAND_MANDATORY_SINGLE, OPERANDSTRING_GROUP_NAME, NULL}, + {"create-tg", createTargetGroupFunc, NULL, NULL, NULL, + OPERAND_MANDATORY_SINGLE, OPERANDSTRING_GROUP_NAME, NULL}, + {"create-lu", createLuFunc, "ps", NULL, NULL, OPERAND_MANDATORY_SINGLE, + "lu file", CREATE_HELP}, + {"delete-hg", deleteHostGroupFunc, NULL, NULL, NULL, + OPERAND_MANDATORY_SINGLE, OPERANDSTRING_GROUP_NAME, NULL}, + {"modify-lu", modifyLuFunc, "psf", NULL, NULL, OPERAND_MANDATORY_SINGLE, + OPERANDSTRING_LU, MODIFY_HELP}, + {"delete-lu", deleteLuFunc, "k", NULL, NULL, + OPERAND_MANDATORY_MULTIPLE, OPERANDSTRING_LU, NULL}, + {"delete-tg", deleteTargetGroupFunc, NULL, NULL, NULL, + OPERAND_MANDATORY_SINGLE, OPERANDSTRING_GROUP_NAME, NULL}, + {"import-lu", importLuFunc, NULL, NULL, NULL, + OPERAND_MANDATORY_SINGLE, "file name", NULL}, + {"list-hg", listHostGroupFunc, "v", NULL, NULL, + OPERAND_OPTIONAL_MULTIPLE, OPERANDSTRING_GROUP_NAME, NULL}, + {"list-lu", listLuFunc, "v", NULL, NULL, OPERAND_OPTIONAL_MULTIPLE, + OPERANDSTRING_LU, NULL}, + {"list-state", listStateFunc, NULL, NULL, NULL, OPERAND_NONE, NULL}, + {"list-target", listTargetFunc, "v", NULL, NULL, + OPERAND_OPTIONAL_MULTIPLE, OPERANDSTRING_TARGET, NULL}, + {"list-tg", listTargetGroupFunc, "v", NULL, NULL, + OPERAND_OPTIONAL_MULTIPLE, OPERANDSTRING_GROUP_NAME, NULL}, + {"list-view", listViewFunc, "l", "l", NULL, + OPERAND_OPTIONAL_MULTIPLE, OPERANDSTRING_VIEW_ENTRY, NULL}, + {"online-lu", onlineLuFunc, NULL, NULL, NULL, + OPERAND_MANDATORY_SINGLE, OPERANDSTRING_LU, NULL}, + {"offline-lu", offlineLuFunc, NULL, NULL, NULL, + OPERAND_MANDATORY_SINGLE, OPERANDSTRING_LU, NULL}, + {"online-target", onlineTargetFunc, NULL, NULL, NULL, + OPERAND_MANDATORY_SINGLE, OPERANDSTRING_TARGET, NULL}, + {"offline-target", offlineTargetFunc, NULL, NULL, NULL, + OPERAND_MANDATORY_SINGLE, OPERANDSTRING_TARGET, NULL}, + {"remove-hg-member", removeHostGroupMemberFunc, "g", "g", NULL, + OPERAND_MANDATORY_MULTIPLE, OPERANDSTRING_GROUP_MEMBER, NULL}, + {"remove-tg-member", removeTargetGroupMemberFunc, "g", "g", NULL, + OPERAND_MANDATORY_MULTIPLE, OPERANDSTRING_GROUP_MEMBER, NULL}, + {"remove-view", removeViewFunc, "la", "l", NULL, + OPERAND_OPTIONAL_MULTIPLE, OPERANDSTRING_VIEW_ENTRY, NULL}, + {NULL, 0, NULL, NULL, 0, NULL, 0, NULL, NULL} +}; + +/* globals */ +char *cmdName; + +/* + * addHostGroupMemberFunc + * + * Add members to a host group + * + */ +/*ARGSUSED*/ +static int +addHostGroupMemberFunc(int operandLen, char *operands[], cmdOptions_t *options, + void *args) +{ + int i; + int ret = 0; + int stmfRet; + stmfGroupName groupName = {0}; + wchar_t groupNamePrint[sizeof (stmfGroupName)] = {0}; + stmfDevid devid; + + for (; options->optval; options++) { + switch (options->optval) { + /* host group name */ + case 'g': + (void) mbstowcs(groupNamePrint, options->optarg, + sizeof (stmfGroupName) - 1); + bcopy(options->optarg, groupName, + strlen(options->optarg)); + break; + default: + (void) fprintf(stderr, "%s: %c: %s\n", + cmdName, options->optval, + gettext("unknown option")); + return (1); + } + } + + for (i = 0; i < operandLen; i++) { + if (parseDevid(operands[i], &devid) != 0) { + (void) fprintf(stderr, "%s: %s: %s\n", + cmdName, operands[i], + gettext("unrecognized device id")); + ret++; + continue; + } + stmfRet = stmfAddToHostGroup(&groupName, &devid); + switch (stmfRet) { + case STMF_STATUS_SUCCESS: + break; + case STMF_ERROR_EXISTS: + (void) fprintf(stderr, "%s: %s: %s\n", cmdName, + operands[i], gettext("already exists")); + ret++; + break; + case STMF_ERROR_GROUP_NOT_FOUND: + (void) fprintf(stderr, "%s: %ws: %s\n", cmdName, + groupNamePrint, gettext("not found")); + ret++; + break; + case STMF_ERROR_PERM: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("permission denied")); + ret++; + break; + case STMF_ERROR_BUSY: + (void) fprintf(stderr, "%s: %s: %s\n", cmdName, + operands[i], gettext("resource busy")); + ret++; + break; + case STMF_ERROR_SERVICE_NOT_FOUND: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF service not found")); + ret++; + break; + case STMF_ERROR_SERVICE_DATA_VERSION: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF service version incorrect")); + ret++; + break; + default: + (void) fprintf(stderr, "%s: %s: %s\n", cmdName, + operands[i], gettext("unknown error")); + ret++; + break; + } + } + + return (ret); +} + +/* + * addTargetGroupMemberFunc + * + * Add members to a target group + * + */ +/*ARGSUSED*/ +static int +addTargetGroupMemberFunc(int operandLen, char *operands[], + cmdOptions_t *options, void *args) +{ + int i; + int ret = 0; + int stmfRet; + stmfGroupName groupName = {0}; + wchar_t groupNamePrint[sizeof (stmfGroupName)] = {0}; + stmfDevid devid; + + for (; options->optval; options++) { + switch (options->optval) { + /* target group name */ + case 'g': + (void) mbstowcs(groupNamePrint, options->optarg, + sizeof (stmfGroupName) - 1); + bcopy(options->optarg, groupName, + strlen(options->optarg)); + break; + default: + (void) fprintf(stderr, "%s: %c: %s\n", + cmdName, options->optval, + gettext("unknown option")); + return (1); + } + } + + for (i = 0; i < operandLen; i++) { + if (parseDevid(operands[i], &devid) != 0) { + (void) fprintf(stderr, "%s: %s: %s\n", + cmdName, operands[i], + gettext("unrecognized device id")); + ret++; + continue; + } + stmfRet = stmfAddToTargetGroup(&groupName, &devid); + switch (stmfRet) { + case STMF_STATUS_SUCCESS: + break; + case STMF_ERROR_EXISTS: + (void) fprintf(stderr, "%s: %s: %s\n", cmdName, + operands[i], gettext("already exists")); + ret++; + break; + case STMF_ERROR_GROUP_NOT_FOUND: + (void) fprintf(stderr, "%s: %ws: %s\n", cmdName, + groupNamePrint, gettext("not found")); + ret++; + break; + case STMF_ERROR_PERM: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("permission denied")); + ret++; + break; + case STMF_ERROR_BUSY: + (void) fprintf(stderr, "%s: %s: %s\n", cmdName, + operands[i], gettext("resource busy")); + ret++; + break; + case STMF_ERROR_SERVICE_NOT_FOUND: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF service not found")); + ret++; + break; + case STMF_ERROR_SERVICE_ONLINE: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF service must be offline")); + ret++; + break; + case STMF_ERROR_SERVICE_DATA_VERSION: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF service version incorrect")); + ret++; + break; + case STMF_ERROR_TG_ONLINE: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF target must be offline")); + ret++; + break; + default: + (void) fprintf(stderr, "%s: %s: %s\n", cmdName, + operands[i], gettext("unknown error")); + ret++; + break; + } + } + + return (ret); +} + +/* + * parseDevid + * + * Converts char * input to a stmfDevid + * + * input - this should be in the following format with either a + * wwn. iqn. or eui. representation. + * A name string of the format: + * wwn.<WWN> (FC/SAS address) + * iqn.<iSCSI name> (iSCSI iqn) + * eui.<WWN> (iSCSI eui name) + * + * devid - pointer to stmfDevid structure allocated by the caller. + * + * Returns: + * 0 on success + * non-zero on failure + */ +static int +parseDevid(char *input, stmfDevid *devid) +{ + wchar_t inputWc[MAX_DEVID_INPUT + 1] = {0}; + + /* convert to wcs */ + (void) mbstowcs(inputWc, input, MAX_DEVID_INPUT); + + /* + * Check for known scsi name string formats + * If one is found, we're done + * If not, then it's a failure to parse + */ + if (checkScsiNameString(inputWc, devid) == 0) { + return (0); + } + + return (-1); +} + +/* + * checkScsiNameString + * + * Validates known SCSI name string formats and converts to stmfDevid + * format + * + * input - input SCSI name string + * devid - pointer to stmfDevid structure allocated by the caller + * on successful return, contains the devid based on input + * + * returns: + * 0 on success + * -1 on failure + */ +static int +checkScsiNameString(wchar_t *input, stmfDevid *devid) +{ + char *mbString = NULL; + int mbStringLen; + int len; + int i; + + /* + * Convert to multi-byte string + * + * This is used for either eui or naa formats + */ + mbString = calloc(1, (mbStringLen = wcstombs(mbString, input, 0)) + 1); + if (mbString == NULL) { + (void) fprintf(stderr, "%s: %s\n", + cmdName, "Insufficient memory\n"); + return (-1); + } + if (wcstombs(mbString, input, mbStringLen) == (size_t)-1) { + return (-1); + } + + /* + * check for iqn format + */ + if (strncmp(mbString, "iqn.", 4) == 0) { + if ((len = strlen(mbString)) > (SNS_IQN_223)) { + return (-1); + } + for (i = 0; i < len; i++) { + mbString[i] = tolower(mbString[i]); + } + if (checkIscsiName(input + 4) != 0) { + return (-1); + } + } else if (strncmp(mbString, "wwn.", 4) == 0) { + if ((len = strlen(mbString + 4)) != SNS_WWN_16) { + return (-1); + } else if (checkHexUpper(mbString + 4) != 0) { + return (-1); + } + } else if (strncmp(mbString, "eui.", 4) == 0) { + if ((len = strlen(mbString + 4)) != SNS_EUI_16) { + return (-1); + } else if (checkHexUpper(mbString + 4) != 0) { + return (-1); + } + } else { + return (-1); + } + + /* + * We have a validated name string. + * Go ahead and set the length and copy it. + */ + devid->identLength = strlen(mbString); + bzero(devid->ident, STMF_IDENT_LENGTH); + bcopy(mbString, devid->ident, devid->identLength); + + return (0); +} + + +/* + * Checks whether the entire string is in hex and converts to upper + */ +static int +checkHexUpper(char *input) +{ + int i; + + for (i = 0; i < strlen(input); i++) { + if (isxdigit(input[i])) { + input[i] = toupper(input[i]); + continue; + } + return (-1); + } + + return (0); +} + +/* + * checkIscsiName + * + * Purpose: Basic string checking on name + */ +static int +checkIscsiName(wchar_t *input) +{ + int i; + + for (i = 0; input[i] != 0; i++) { + if (!iswalnum(input[i]) && input[i] != '-' && + input[i] != '.' && input[i] != ':') { + return (-1); + } + } + + return (0); +} + + +/* + * addViewFunc + * + * Adds a view entry to a logical unit + * + */ +/*ARGSUSED*/ +static int +addViewFunc(int operandLen, char *operands[], cmdOptions_t *options, + void *args) +{ + stmfViewEntry viewEntry; + stmfGuid inGuid; + unsigned int guid[sizeof (stmfGuid)]; + uint16_t inputLuNbr; + int ret = 0; + int stmfRet; + int i; + char sGuid[GUID_INPUT + 1]; + + bzero(&viewEntry, sizeof (viewEntry)); + /* init view entry structure */ + viewEntry.allHosts = B_TRUE; + viewEntry.allTargets = B_TRUE; + viewEntry.luNbrValid = B_FALSE; + + /* check input length */ + if (strlen(operands[0]) != GUID_INPUT) { + (void) fprintf(stderr, "%s: %s: %s%d%s\n", cmdName, operands[0], + gettext("must be "), GUID_INPUT, + gettext(" hexadecimal digits")); + return (1); + } + + for (; options->optval; options++) { + switch (options->optval) { + /* logical unit number */ + case 'n': + viewEntry.luNbrValid = B_TRUE; + inputLuNbr = atoi(options->optarg); + if (inputLuNbr > MAX_LU_NBR) { + (void) fprintf(stderr, "%s: %d: %s\n", + cmdName, inputLuNbr, + gettext("Logical unit number" + " must be less than 16384")); + return (1); + } + viewEntry.luNbr[0] = inputLuNbr >> 8; + viewEntry.luNbr[1] = inputLuNbr & 0xff; + break; + /* host group */ + case 'h': + viewEntry.allHosts = B_FALSE; + bcopy(options->optarg, viewEntry.hostGroup, + strlen(options->optarg)); + break; + /* target group */ + case 't': + viewEntry.allTargets = B_FALSE; + bcopy(options->optarg, viewEntry.targetGroup, + strlen(options->optarg)); + break; + default: + (void) fprintf(stderr, "%s: %c: %s\n", + cmdName, options->optval, + gettext("unknown option")); + return (1); + } + } + + /* convert to lower case for scan */ + for (i = 0; i < 32; i++) + sGuid[i] = tolower(operands[0][i]); + sGuid[i] = 0; + + (void) sscanf(sGuid, "%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 (i = 0; i < sizeof (stmfGuid); i++) { + inGuid.guid[i] = guid[i]; + } + + /* add the view entry */ + stmfRet = stmfAddViewEntry(&inGuid, &viewEntry); + switch (stmfRet) { + case STMF_STATUS_SUCCESS: + break; + case STMF_ERROR_EXISTS: + (void) fprintf(stderr, "%s: %s: %s\n", cmdName, + operands[0], gettext("already exists")); + ret++; + break; + case STMF_ERROR_BUSY: + (void) fprintf(stderr, "%s: %s: %s\n", cmdName, + operands[0], gettext("resource busy")); + ret++; + break; + case STMF_ERROR_SERVICE_NOT_FOUND: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF service not found")); + ret++; + break; + case STMF_ERROR_PERM: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("permission denied")); + ret++; + break; + case STMF_ERROR_LUN_IN_USE: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("LUN already in use")); + ret++; + break; + case STMF_ERROR_VE_CONFLICT: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("view entry exists")); + ret++; + break; + case STMF_ERROR_CONFIG_NONE: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF service is not initialized")); + ret++; + break; + case STMF_ERROR_SERVICE_DATA_VERSION: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF service version incorrect")); + ret++; + break; + case STMF_ERROR_INVALID_HG: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("invalid host group")); + ret++; + break; + case STMF_ERROR_INVALID_TG: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("invalid target group")); + ret++; + break; + default: + (void) fprintf(stderr, "%s: %s: %s\n", cmdName, + operands[0], gettext("unknown error")); + ret++; + break; + } + + return (ret); +} + +/* + * createHostGroupFunc + * + * Create a host group + * + */ +/*ARGSUSED*/ +static int +createHostGroupFunc(int operandLen, char *operands[], + cmdOptions_t *options, void *args) +{ + int ret = 0; + int stmfRet; + wchar_t groupNamePrint[sizeof (stmfGroupName)] = {0}; + stmfGroupName groupName = {0}; + + (void) strlcpy(groupName, operands[0], sizeof (groupName)); + (void) mbstowcs(groupNamePrint, (char *)groupName, + sizeof (stmfGroupName) - 1); + /* call create group */ + stmfRet = stmfCreateHostGroup(&groupName); + switch (stmfRet) { + case STMF_STATUS_SUCCESS: + break; + case STMF_ERROR_EXISTS: + (void) fprintf(stderr, "%s: %s: %s\n", cmdName, + operands[0], gettext("already exists")); + ret++; + break; + case STMF_ERROR_BUSY: + (void) fprintf(stderr, "%s: %s: %s\n", cmdName, + operands[0], gettext("resource busy")); + ret++; + break; + case STMF_ERROR_SERVICE_NOT_FOUND: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF service not found")); + ret++; + break; + case STMF_ERROR_PERM: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("permission denied")); + ret++; + break; + case STMF_ERROR_SERVICE_DATA_VERSION: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF service version incorrect")); + ret++; + break; + default: + (void) fprintf(stderr, "%s: %s: %s\n", cmdName, + operands[0], gettext("unknown error")); + ret++; + break; + } + + return (ret); +} + +/* + * createLuFunc + * + * Create a logical unit + * + */ +/*ARGSUSED*/ +static int +createLuFunc(int operandLen, char *operands[], cmdOptions_t *options, + void *args) +{ + luResource hdl = NULL; + int ret = 0; + int stmfRet = 0; + char guidAsciiBuf[33]; + stmfGuid createdGuid; + + stmfRet = stmfCreateLuResource(STMF_DISK, &hdl); + + if (stmfRet != STMF_STATUS_SUCCESS) { + (void) fprintf(stderr, "%s: %s\n", + cmdName, gettext("Failure to create lu resource\n")); + return (1); + } + + for (; options->optval; options++) { + switch (options->optval) { + case 'p': + ret = setLuPropFromInput(hdl, options->optarg); + if (ret != 0) { + (void) stmfFreeLuResource(hdl); + return (1); + } + break; + case 's': + stmfRet = stmfSetLuProp(hdl, STMF_LU_PROP_SIZE, + options->optarg); + if (stmfRet != STMF_STATUS_SUCCESS) { + (void) fprintf(stderr, "%s: %c: %s\n", + cmdName, options->optval, + gettext("size param invalid")); + (void) stmfFreeLuResource(hdl); + return (1); + } + break; + default: + (void) fprintf(stderr, "%s: %c: %s\n", + cmdName, options->optval, + gettext("unknown option")); + return (1); + } + } + + stmfRet = stmfSetLuProp(hdl, STMF_LU_PROP_FILENAME, operands[0]); + + if (stmfRet != STMF_STATUS_SUCCESS) { + (void) fprintf(stderr, "%s: %s\n", + cmdName, gettext("could not set filename")); + return (1); + } + + stmfRet = stmfCreateLu(hdl, &createdGuid); + switch (stmfRet) { + case STMF_STATUS_SUCCESS: + break; + case STMF_ERROR_BUSY: + case STMF_ERROR_LU_BUSY: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("resource busy")); + ret++; + break; + case STMF_ERROR_PERM: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("permission denied")); + ret++; + break; + case STMF_ERROR_FILE_IN_USE: + (void) fprintf(stderr, "%s: filename %s: %s\n", cmdName, + operands[0], gettext("in use")); + ret++; + break; + case STMF_ERROR_INVALID_BLKSIZE: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("invalid block size")); + ret++; + break; + case STMF_ERROR_GUID_IN_USE: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("guid in use")); + ret++; + break; + case STMF_ERROR_META_FILE_NAME: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("meta file error")); + ret++; + break; + case STMF_ERROR_DATA_FILE_NAME: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("data file error")); + ret++; + break; + case STMF_ERROR_FILE_SIZE_INVALID: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("file size invalid")); + ret++; + break; + case STMF_ERROR_SIZE_OUT_OF_RANGE: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("invalid size")); + ret++; + break; + case STMF_ERROR_META_CREATION: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("could not create meta file")); + ret++; + break; + case STMF_ERROR_WRITE_CACHE_SET: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("could not set write cache")); + ret++; + break; + default: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("unknown error")); + ret++; + break; + } + + if (ret != 0) { + goto done; + } + + (void) snprintf(guidAsciiBuf, sizeof (guidAsciiBuf), + "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X" + "%02X%02X%02X%02X%02X%02X", + createdGuid.guid[0], createdGuid.guid[1], createdGuid.guid[2], + createdGuid.guid[3], createdGuid.guid[4], createdGuid.guid[5], + createdGuid.guid[6], createdGuid.guid[7], createdGuid.guid[8], + createdGuid.guid[9], createdGuid.guid[10], createdGuid.guid[11], + createdGuid.guid[12], createdGuid.guid[13], createdGuid.guid[14], + createdGuid.guid[15]); + (void) printf("Logical unit created: %s\n", guidAsciiBuf); + +done: + (void) stmfFreeLuResource(hdl); + return (ret); +} + +/* + * createLuFunc + * + * Create a logical unit + * + */ +/*ARGSUSED*/ +static int +modifyLuFunc(int operandLen, char *operands[], cmdOptions_t *options, + void *args) +{ + stmfGuid inGuid; + unsigned int guid[sizeof (stmfGuid)]; + int ret = 0; + int i; + char *fname = NULL; + char *lasts = NULL; + char sGuid[GUID_INPUT + 1]; + char *prop = NULL; + char *propVal = NULL; + boolean_t fnameUsed = B_FALSE; + uint32_t propId; + cmdOptions_t *optionStart = options; + + + for (; options->optval; options++) { + switch (options->optval) { + case 'f': + fnameUsed = B_TRUE; + fname = operands[0]; + break; + } + } + options = optionStart; + + /* check input length */ + if (!fnameUsed && strlen(operands[0]) != GUID_INPUT) { + (void) fprintf(stderr, "%s: %s: %s%d%s\n", cmdName, operands[0], + gettext("must be "), GUID_INPUT, + gettext(" hexadecimal digits")); + return (1); + } + + if (!fnameUsed) { + /* convert to lower case for scan */ + for (i = 0; i < 32; i++) + sGuid[i] = tolower(operands[0][i]); + sGuid[i] = 0; + (void) sscanf(sGuid, + "%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 (i = 0; i < sizeof (stmfGuid); i++) { + inGuid.guid[i] = guid[i]; + } + } + + for (; options->optval; options++) { + switch (options->optval) { + case 'p': + prop = strtok_r(options->optarg, "=", &lasts); + propVal = strtok_r(NULL, "=", &lasts); + ret = convertCharToPropId(prop, &propId); + if (ret != 0) { + (void) fprintf(stderr, "%s: %s: %s\n", + cmdName, + gettext("invalid property specified"), + prop); + return (1); + } + if (propVal == NULL && + propId != STMF_LU_PROP_MGMT_URL) { + (void) fprintf(stderr, "%s: %s: %s\n", + cmdName, options->optarg, + gettext("invalid property specifier" + "- prop=val\n")); + return (1); + } + if (propVal == NULL) { + ret = callModify(fname, &inGuid, propId, + "", prop); + } else { + ret = callModify(fname, &inGuid, propId, + propVal, prop); + } + if (ret != 0) { + return (1); + } + break; + case 's': + if (callModify(fname, &inGuid, + STMF_LU_PROP_SIZE, options->optarg, + "size") != 0) { + return (1); + } + break; + case 'f': + break; + default: + (void) fprintf(stderr, "%s: %c: %s\n", + cmdName, options->optval, + gettext("unknown option")); + return (1); + } + } + return (ret); +} + +static int +callModify(char *fname, stmfGuid *luGuid, uint32_t prop, const char *propVal, + const char *propString) +{ + int ret = 0; + int stmfRet = 0; + + if (!fname) { + stmfRet = stmfModifyLu(luGuid, prop, propVal); + } else { + stmfRet = stmfModifyLuByFname(STMF_DISK, fname, prop, + propVal); + } + switch (stmfRet) { + case STMF_STATUS_SUCCESS: + break; + case STMF_ERROR_BUSY: + case STMF_ERROR_LU_BUSY: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("resource busy")); + ret++; + break; + case STMF_ERROR_PERM: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("permission denied")); + ret++; + break; + case STMF_ERROR_INVALID_BLKSIZE: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("invalid block size")); + ret++; + break; + case STMF_ERROR_GUID_IN_USE: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("guid in use")); + ret++; + break; + case STMF_ERROR_META_FILE_NAME: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("meta file error")); + ret++; + break; + case STMF_ERROR_DATA_FILE_NAME: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("data file error")); + ret++; + break; + case STMF_ERROR_FILE_SIZE_INVALID: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("file size invalid")); + ret++; + break; + case STMF_ERROR_SIZE_OUT_OF_RANGE: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("invalid size")); + ret++; + break; + case STMF_ERROR_META_CREATION: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("could not create meta file")); + ret++; + break; + case STMF_ERROR_INVALID_PROP: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("invalid property for modify")); + ret++; + break; + case STMF_ERROR_WRITE_CACHE_SET: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("could not set write cache")); + ret++; + break; + case STMF_ERROR_ACCESS_STATE_SET: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("cannot modify while in standby mode")); + ret++; + break; + default: + (void) fprintf(stderr, "%s: %s: %s: %d\n", cmdName, + gettext("could not set property"), propString, + stmfRet); + ret++; + break; + } + + return (ret); +} + + +/* + * importLuFunc + * + * Create a logical unit + * + */ +/*ARGSUSED*/ +static int +importLuFunc(int operandLen, char *operands[], cmdOptions_t *options, + void *args) +{ + int stmfRet = 0; + int ret = 0; + char guidAsciiBuf[33]; + stmfGuid createdGuid; + + stmfRet = stmfImportLu(STMF_DISK, operands[0], &createdGuid); + switch (stmfRet) { + case STMF_STATUS_SUCCESS: + break; + case STMF_ERROR_BUSY: + case STMF_ERROR_LU_BUSY: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("resource busy")); + ret++; + break; + case STMF_ERROR_PERM: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("permission denied")); + ret++; + break; + case STMF_ERROR_FILE_IN_USE: + (void) fprintf(stderr, "%s: filename %s: %s\n", cmdName, + operands[0], gettext("in use")); + ret++; + break; + case STMF_ERROR_GUID_IN_USE: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("guid in use")); + ret++; + break; + case STMF_ERROR_META_FILE_NAME: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("meta file error")); + ret++; + break; + case STMF_ERROR_DATA_FILE_NAME: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("data file error")); + ret++; + break; + case STMF_ERROR_META_CREATION: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("could not create meta file")); + ret++; + break; + case STMF_ERROR_WRITE_CACHE_SET: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("could not set write cache")); + ret++; + break; + default: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("unknown error")); + ret++; + break; + } + + if (ret != STMF_STATUS_SUCCESS) { + goto done; + } + + (void) snprintf(guidAsciiBuf, sizeof (guidAsciiBuf), + "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X" + "%02X%02X%02X%02X%02X%02X", + createdGuid.guid[0], createdGuid.guid[1], createdGuid.guid[2], + createdGuid.guid[3], createdGuid.guid[4], createdGuid.guid[5], + createdGuid.guid[6], createdGuid.guid[7], createdGuid.guid[8], + createdGuid.guid[9], createdGuid.guid[10], createdGuid.guid[11], + createdGuid.guid[12], createdGuid.guid[13], createdGuid.guid[14], + createdGuid.guid[15]); + (void) printf("Logical unit imported: %s\n", guidAsciiBuf); + +done: + return (ret); +} + +static int +setLuPropFromInput(luResource hdl, char *optarg) +{ + char *prop = NULL; + char *propVal = NULL; + char *lasts = NULL; + uint32_t propId; + int ret = 0; + + prop = strtok_r(optarg, "=", &lasts); + if ((propVal = strtok_r(NULL, "=", &lasts)) == NULL) { + (void) fprintf(stderr, "%s: %s: %s\n", + cmdName, optarg, + gettext("invalid property specifier - prop=val\n")); + return (1); + } + + ret = convertCharToPropId(prop, &propId); + if (ret != 0) { + (void) fprintf(stderr, "%s: %s: %s\n", + cmdName, gettext("invalid property specified"), prop); + return (1); + } + + ret = stmfSetLuProp(hdl, propId, propVal); + if (ret != STMF_STATUS_SUCCESS) { + (void) fprintf(stderr, "%s: %s %s: ", + cmdName, gettext("unable to set"), prop); + switch (ret) { + case STMF_ERROR_INVALID_PROPSIZE: + (void) fprintf(stderr, "invalid length\n"); + break; + case STMF_ERROR_INVALID_ARG: + (void) fprintf(stderr, "bad format\n"); + break; + default: + (void) fprintf(stderr, "\n"); + break; + } + return (1); + } + + return (0); +} + +static int +convertCharToPropId(char *prop, uint32_t *propId) +{ + if (strcasecmp(prop, GUID) == 0) { + *propId = STMF_LU_PROP_GUID; + } else if (strcasecmp(prop, ALIAS) == 0) { + *propId = STMF_LU_PROP_ALIAS; + } else if (strcasecmp(prop, VID) == 0) { + *propId = STMF_LU_PROP_VID; + } else if (strcasecmp(prop, PID) == 0) { + *propId = STMF_LU_PROP_PID; + } else if (strcasecmp(prop, WRITE_PROTECT) == 0) { + *propId = STMF_LU_PROP_WRITE_PROTECT; + } else if (strcasecmp(prop, WRITEBACK_CACHE_DISABLE) == 0) { + *propId = STMF_LU_PROP_WRITE_CACHE_DISABLE; + } else if (strcasecmp(prop, BLOCK_SIZE) == 0) { + *propId = STMF_LU_PROP_BLOCK_SIZE; + } else if (strcasecmp(prop, SERIAL_NUMBER) == 0) { + *propId = STMF_LU_PROP_SERIAL_NUM; + } else if (strcasecmp(prop, COMPANY_ID) == 0) { + *propId = STMF_LU_PROP_COMPANY_ID; + } else if (strcasecmp(prop, META_FILE) == 0) { + *propId = STMF_LU_PROP_META_FILENAME; + } else if (strcasecmp(prop, MGMT_URL) == 0) { + *propId = STMF_LU_PROP_MGMT_URL; + } else if (strcasecmp(prop, HOST_ID) == 0) { + *propId = STMF_LU_PROP_HOST_ID; + } else { + return (1); + } + return (0); +} + +/* + * deleteLuFunc + * + * Delete a logical unit + * + */ +/*ARGSUSED*/ +static int +deleteLuFunc(int operandLen, char *operands[], cmdOptions_t *options, + void *args) +{ + int i, j; + int ret = 0; + int stmfRet; + unsigned int inGuid[sizeof (stmfGuid)]; + stmfGuid delGuid; + boolean_t keepViews = B_FALSE; + boolean_t viewEntriesRemoved = B_FALSE; + boolean_t noLunFound = B_FALSE; + boolean_t views = B_FALSE; + boolean_t notValidHexNumber = B_FALSE; + char sGuid[GUID_INPUT + 1]; + stmfViewEntryList *viewEntryList = NULL; + + for (; options->optval; options++) { + switch (options->optval) { + /* Keep views for logical unit */ + case 'k': + keepViews = B_TRUE; + break; + default: + (void) fprintf(stderr, "%s: %c: %s\n", + cmdName, options->optval, + gettext("unknown option")); + return (1); + } + } + + + for (i = 0; i < operandLen; i++) { + for (j = 0; j < GUID_INPUT; j++) { + if (!isxdigit(operands[i][j])) { + notValidHexNumber = B_TRUE; + break; + } + sGuid[j] = tolower(operands[i][j]); + } + if ((notValidHexNumber == B_TRUE) || + (strlen(operands[i]) != GUID_INPUT)) { + (void) fprintf(stderr, "%s: %s: %s%d%s\n", + cmdName, operands[i], gettext("must be "), + GUID_INPUT, + gettext(" hexadecimal digits long")); + notValidHexNumber = B_FALSE; + ret++; + continue; + } + + sGuid[j] = 0; + + (void) sscanf(sGuid, + "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x", + &inGuid[0], &inGuid[1], &inGuid[2], &inGuid[3], + &inGuid[4], &inGuid[5], &inGuid[6], &inGuid[7], + &inGuid[8], &inGuid[9], &inGuid[10], &inGuid[11], + &inGuid[12], &inGuid[13], &inGuid[14], &inGuid[15]); + + for (j = 0; j < sizeof (stmfGuid); j++) { + delGuid.guid[j] = inGuid[j]; + } + + stmfRet = stmfDeleteLu(&delGuid); + switch (stmfRet) { + case STMF_STATUS_SUCCESS: + break; + case STMF_ERROR_NOT_FOUND: + noLunFound = B_TRUE; + break; + case STMF_ERROR_BUSY: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("resource busy")); + ret++; + break; + case STMF_ERROR_PERM: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("permission denied")); + ret++; + break; + default: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("unknown error")); + ret++; + break; + } + + if (!keepViews) { + stmfRet = stmfGetViewEntryList(&delGuid, + &viewEntryList); + if (stmfRet == STMF_STATUS_SUCCESS) { + for (j = 0; j < viewEntryList->cnt; j++) { + (void) stmfRemoveViewEntry(&delGuid, + viewEntryList->ve[j].veIndex); + } + /* check if viewEntryList is empty */ + if (viewEntryList->cnt != 0) + viewEntriesRemoved = B_TRUE; + stmfFreeMemory(viewEntryList); + } else { + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("unable to remove view entries\n")); + ret++; + } + + } + if (keepViews) { + stmfRet = stmfGetViewEntryList(&delGuid, + &viewEntryList); + if (stmfRet == STMF_STATUS_SUCCESS) { + views = B_TRUE; + stmfFreeMemory(viewEntryList); + } + } + + if ((!viewEntriesRemoved && noLunFound && !views) || + (!views && keepViews && noLunFound)) { + (void) fprintf(stderr, "%s: %s: %s\n", + cmdName, sGuid, + gettext("not found")); + ret++; + } + noLunFound = viewEntriesRemoved = views = B_FALSE; + } + return (ret); +} + + +/* + * createTargetGroupFunc + * + * Create a target group + * + */ +/*ARGSUSED*/ +static int +createTargetGroupFunc(int operandLen, char *operands[], cmdOptions_t *options, + void *args) +{ + int ret = 0; + int stmfRet; + wchar_t groupNamePrint[sizeof (stmfGroupName)] = {0}; + stmfGroupName groupName = {0}; + + (void) strlcpy(groupName, operands[0], sizeof (groupName)); + (void) mbstowcs(groupNamePrint, (char *)groupName, + sizeof (stmfGroupName) - 1); + /* call create group */ + stmfRet = stmfCreateTargetGroup(&groupName); + switch (stmfRet) { + case STMF_STATUS_SUCCESS: + break; + case STMF_ERROR_EXISTS: + (void) fprintf(stderr, "%s: %ws: %s\n", cmdName, + groupNamePrint, gettext("already exists")); + ret++; + break; + case STMF_ERROR_BUSY: + (void) fprintf(stderr, "%s: %ws: %s\n", cmdName, + groupNamePrint, gettext("resource busy")); + ret++; + break; + case STMF_ERROR_PERM: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("permission denied")); + ret++; + break; + case STMF_ERROR_SERVICE_NOT_FOUND: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF service not found")); + ret++; + break; + case STMF_ERROR_SERVICE_DATA_VERSION: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF service version incorrect")); + ret++; + break; + default: + (void) fprintf(stderr, "%s: %ws: %s\n", cmdName, + groupNamePrint, gettext("unknown error")); + ret++; + break; + } + + return (ret); +} + +/* + * deleteHostGroupFunc + * + * Delete a host group + * + */ +/*ARGSUSED*/ +static int +deleteHostGroupFunc(int operandLen, char *operands[], + cmdOptions_t *options, void *args) +{ + int ret = 0; + int stmfRet; + wchar_t groupNamePrint[sizeof (stmfGroupName)] = {0}; + stmfGroupName groupName = {0}; + + (void) strlcpy(groupName, operands[0], sizeof (groupName)); + (void) mbstowcs(groupNamePrint, (char *)groupName, + sizeof (stmfGroupName) - 1); + /* call delete group */ + stmfRet = stmfDeleteHostGroup(&groupName); + switch (stmfRet) { + case STMF_STATUS_SUCCESS: + break; + case STMF_ERROR_NOT_FOUND: + (void) fprintf(stderr, "%s: %ws: %s\n", cmdName, + groupNamePrint, gettext("not found")); + ret++; + break; + case STMF_ERROR_BUSY: + (void) fprintf(stderr, "%s: %ws: %s\n", cmdName, + groupNamePrint, gettext("resource busy")); + ret++; + break; + case STMF_ERROR_SERVICE_NOT_FOUND: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF service not found")); + ret++; + break; + case STMF_ERROR_PERM: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("permission denied")); + ret++; + break; + case STMF_ERROR_GROUP_IN_USE: + (void) fprintf(stderr, "%s: %ws: %s\n", cmdName, + groupNamePrint, + gettext("group is in use by existing view entry")); + ret++; + break; + case STMF_ERROR_SERVICE_DATA_VERSION: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF service version incorrect")); + ret++; + break; + default: + (void) fprintf(stderr, "%s: %ws: %s\n", cmdName, + groupNamePrint, gettext("unknown error")); + ret++; + break; + } + + return (ret); +} + +/* + * deleteTargetGroupFunc + * + * Delete a target group + * + */ +/*ARGSUSED*/ +static int +deleteTargetGroupFunc(int operandLen, char *operands[], cmdOptions_t *options, + void *args) +{ + int ret = 0; + int stmfRet; + wchar_t groupNamePrint[sizeof (stmfGroupName)] = {0}; + stmfGroupName groupName = {0}; + + (void) strlcpy(groupName, operands[0], sizeof (groupName)); + (void) mbstowcs(groupNamePrint, (char *)groupName, + sizeof (stmfGroupName) - 1); + /* call delete group */ + stmfRet = stmfDeleteTargetGroup(&groupName); + switch (stmfRet) { + case STMF_STATUS_SUCCESS: + break; + case STMF_ERROR_NOT_FOUND: + (void) fprintf(stderr, "%s: %ws: %s\n", cmdName, + groupNamePrint, gettext("not found")); + ret++; + break; + case STMF_ERROR_BUSY: + (void) fprintf(stderr, "%s: %ws: %s\n", cmdName, + groupNamePrint, gettext("resource busy")); + ret++; + break; + case STMF_ERROR_SERVICE_NOT_FOUND: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF service not found")); + ret++; + break; + case STMF_ERROR_PERM: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("permission denied")); + ret++; + break; + case STMF_ERROR_GROUP_IN_USE: + (void) fprintf(stderr, "%s: %ws: %s\n", cmdName, + groupNamePrint, + gettext("group is in use by existing view entry")); + ret++; + break; + case STMF_ERROR_SERVICE_DATA_VERSION: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF service version incorrect")); + ret++; + break; + default: + (void) fprintf(stderr, "%s: %ws: %s\n", cmdName, + groupNamePrint, gettext("unknown error")); + ret++; + break; + } + + return (ret); +} + +/* + * listHostGroupFunc + * + * Lists the specified host groups or all if none are specified + * + */ +/*ARGSUSED*/ +static int +listHostGroupFunc(int operandLen, char *operands[], cmdOptions_t *options, + void *args) +{ + int ret = 0; + int stmfRet; + int i, j, outerLoop; + boolean_t verbose = B_FALSE; + boolean_t found = B_TRUE; + boolean_t operandEntered; + stmfGroupList *groupList; + stmfGroupProperties *groupProps; + wchar_t operandName[sizeof (stmfGroupName)]; + wchar_t groupNamePrint[sizeof (stmfGroupName)]; + + for (; options->optval; options++) { + switch (options->optval) { + case 'v': + verbose = B_TRUE; + break; + default: + (void) fprintf(stderr, "%s: %c: %s\n", + cmdName, options->optval, + gettext("unknown option")); + return (1); + } + } + + if (operandLen > 0) { + outerLoop = operandLen; + operandEntered = B_TRUE; + } else { + outerLoop = 1; + operandEntered = B_FALSE; + } + + stmfRet = stmfGetHostGroupList(&groupList); + if (stmfRet != STMF_STATUS_SUCCESS) { + switch (stmfRet) { + case STMF_ERROR_BUSY: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("resource busy")); + break; + case STMF_ERROR_SERVICE_NOT_FOUND: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF service not found")); + break; + case STMF_ERROR_PERM: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("permission denied")); + break; + case STMF_ERROR_SERVICE_DATA_VERSION: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF service version incorrect")); + break; + default: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("unknown error")); + break; + } + return (1); + } + + for (i = 0; i < outerLoop; i++) { + for (found = B_FALSE, j = 0; j < groupList->cnt; j++) { + (void) mbstowcs(groupNamePrint, + (char *)groupList->name[j], + sizeof (stmfGroupName) - 1); + groupNamePrint[sizeof (stmfGroupName) - 1] = 0; + if (operandEntered) { + (void) mbstowcs(operandName, operands[i], + sizeof (stmfGroupName) - 1); + operandName[sizeof (stmfGroupName) - 1] = 0; + if (wcscmp(operandName, groupNamePrint) + == 0) { + found = B_TRUE; + } + } + if ((found && operandEntered) || !operandEntered) { + (void) printf("Host Group: %ws\n", + groupNamePrint); + if (verbose) { + stmfRet = stmfGetHostGroupMembers( + &(groupList->name[j]), &groupProps); + if (stmfRet != STMF_STATUS_SUCCESS) { + return (1); + } + printGroupProps(groupProps); + } + if (found && operandEntered) { + break; + } + } + + } + if (operandEntered && !found) { + (void) fprintf(stderr, "%s: %s: %s\n", cmdName, + operands[i], gettext("not found")); + ret = 1; + } + } + return (ret); +} + +/* + * printGroupProps + * + * Prints group members for target or host groups + * + */ +static void +printGroupProps(stmfGroupProperties *groupProps) +{ + int i; + wchar_t memberIdent[sizeof (groupProps->name[0].ident) + 1] = {0}; + + + for (i = 0; i < groupProps->cnt; i++) { + (void) mbstowcs(memberIdent, (char *)groupProps->name[i].ident, + sizeof (groupProps->name[0].ident)); + (void) printf("\tMember: %ws\n", memberIdent); + } +} + +/* + * listTargetGroupFunc + * + * Lists the specified target groups or all if none are specified + * + */ +/*ARGSUSED*/ +static int +listTargetGroupFunc(int operandLen, char *operands[], cmdOptions_t *options, + void *args) +{ + int ret = 0; + int stmfRet; + int i, j, outerLoop; + boolean_t verbose = B_FALSE; + boolean_t found = B_TRUE; + boolean_t operandEntered; + stmfGroupList *groupList; + stmfGroupProperties *groupProps; + wchar_t operandName[sizeof (stmfGroupName)]; + wchar_t groupNamePrint[sizeof (stmfGroupName)]; + + for (; options->optval; options++) { + switch (options->optval) { + case 'v': + verbose = B_TRUE; + break; + default: + (void) fprintf(stderr, "%s: %c: %s\n", + cmdName, options->optval, + gettext("unknown option")); + return (1); + } + } + + if (operandLen > 0) { + outerLoop = operandLen; + operandEntered = B_TRUE; + } else { + outerLoop = 1; + operandEntered = B_FALSE; + } + + stmfRet = stmfGetTargetGroupList(&groupList); + if (stmfRet != STMF_STATUS_SUCCESS) { + switch (stmfRet) { + case STMF_ERROR_BUSY: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("resource busy")); + break; + case STMF_ERROR_SERVICE_NOT_FOUND: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF service not found")); + break; + case STMF_ERROR_SERVICE_DATA_VERSION: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF service version incorrect")); + break; + case STMF_ERROR_PERM: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("permission denied")); + break; + default: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("unknown error")); + break; + } + return (1); + } + + for (i = 0; i < outerLoop; i++) { + for (found = B_FALSE, j = 0; j < groupList->cnt; j++) { + (void) mbstowcs(groupNamePrint, + (char *)groupList->name[j], + sizeof (stmfGroupName) - 1); + groupNamePrint[sizeof (stmfGroupName) - 1] = 0; + if (operandEntered) { + (void) mbstowcs(operandName, operands[i], + sizeof (stmfGroupName) - 1); + operandName[sizeof (stmfGroupName) - 1] = 0; + if (wcscmp(operandName, groupNamePrint) + == 0) { + found = B_TRUE; + } + } + if ((found && operandEntered) || !operandEntered) { + (void) printf("Target Group: %ws\n", + groupNamePrint); + if (verbose) { + stmfRet = stmfGetTargetGroupMembers( + &(groupList->name[j]), &groupProps); + if (stmfRet != STMF_STATUS_SUCCESS) { + return (1); + } + printGroupProps(groupProps); + } + if (found && operandEntered) { + break; + } + } + + } + if (operandEntered && !found) { + (void) fprintf(stderr, "%s: %s: %s\n", cmdName, + operands[i], gettext("not found")); + ret = 1; + } + } + return (ret); +} + +/* + * listLuFunc + * + * List the logical units and optionally the properties + * + */ +/*ARGSUSED*/ +static int +listLuFunc(int operandLen, char *operands[], cmdOptions_t *options, void *args) +{ + cmdOptions_t *optionList = options; + boolean_t operandEntered; + int i, j; + int ret = 0; + int stmfRet; + int outerLoop; + unsigned int inGuid[sizeof (stmfGuid)]; + stmfGuid cmpGuid; + boolean_t verbose = B_FALSE; + boolean_t found; + char sGuid[GUID_INPUT + 1]; + stmfGuidList *luList; + stmfLogicalUnitProperties luProps; + boolean_t invalidInput = B_FALSE; + stmfViewEntryList *viewEntryList; + + for (; optionList->optval; optionList++) { + switch (optionList->optval) { + case 'v': + verbose = B_TRUE; + break; + } + } + + if ((stmfRet = stmfGetLogicalUnitList(&luList)) + != STMF_STATUS_SUCCESS) { + switch (stmfRet) { + case STMF_ERROR_SERVICE_NOT_FOUND: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF service not found")); + break; + case STMF_ERROR_BUSY: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("resource busy")); + break; + case STMF_ERROR_PERM: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("permission denied")); + break; + case STMF_ERROR_SERVICE_DATA_VERSION: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF service version incorrect")); + break; + default: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("list failed")); + break; + } + return (1); + } + + if (operandLen > 0) { + operandEntered = B_TRUE; + outerLoop = operandLen; + } else { + operandEntered = B_FALSE; + outerLoop = 1; + } + + + for (invalidInput = B_FALSE, i = 0; i < outerLoop; i++) { + if (operandEntered) { + if (strlen(operands[i]) != GUID_INPUT) { + invalidInput = B_TRUE; + } else { + for (j = 0; j < GUID_INPUT; j++) { + if (!isxdigit(operands[i][j])) { + invalidInput = B_TRUE; + break; + } + } + } + if (invalidInput) { + (void) fprintf(stderr, "%s: %s: %s%d%s\n", + cmdName, operands[i], gettext("must be "), + GUID_INPUT, + gettext(" hexadecimal digits long")); + invalidInput = B_FALSE; + continue; + } + + for (j = 0; j < GUID_INPUT; j++) { + sGuid[j] = tolower(operands[i][j]); + } + sGuid[j] = 0; + + (void) sscanf(sGuid, + "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x", + &inGuid[0], &inGuid[1], &inGuid[2], &inGuid[3], + &inGuid[4], &inGuid[5], &inGuid[6], &inGuid[7], + &inGuid[8], &inGuid[9], &inGuid[10], &inGuid[11], + &inGuid[12], &inGuid[13], &inGuid[14], &inGuid[15]); + + for (j = 0; j < sizeof (stmfGuid); j++) { + cmpGuid.guid[j] = inGuid[j]; + } + } + + for (found = B_FALSE, j = 0; j < luList->cnt; j++) { + if (operandEntered) { + if (bcmp(luList->guid[j].guid, cmpGuid.guid, + sizeof (stmfGuid)) == 0) { + found = B_TRUE; + } + } + if ((found && operandEntered) || !operandEntered) { + (void) printf("LU Name: "); + printGuid(&luList->guid[j], stdout); + (void) printf("\n"); + + if (verbose) { + stmfRet = stmfGetLogicalUnitProperties( + &(luList->guid[j]), &luProps); + if (stmfRet == STMF_STATUS_SUCCESS) { + printLuProps(&luProps); + } else { + (void) fprintf(stderr, "%s:", + cmdName); + printGuid(&luList->guid[j], + stderr); + (void) fprintf(stderr, "%s\n", + gettext(" get properties " + "failed")); + } + stmfRet = stmfGetViewEntryList( + &(luList->guid[j]), + &viewEntryList); + (void) printf(PROPS_FORMAT, + "View Entry Count"); + if (stmfRet == STMF_STATUS_SUCCESS) { + (void) printf("%d", + viewEntryList->cnt); + } else { + (void) printf("unknown"); + } + (void) printf("\n"); + ret = printExtLuProps( + &(luList->guid[j])); + } + if (found && operandEntered) { + break; + } + } + + } + if (operandEntered && !found) { + (void) fprintf(stderr, "%s: %s: %s\n", cmdName, + operands[i], gettext("not found")); + ret = 1; + } + } + + return (ret); +} + +static void +printGuid(stmfGuid *guid, FILE *stream) +{ + int i; + for (i = 0; i < 16; i++) { + (void) fprintf(stream, "%02X", guid->guid[i]); + } +} + +static int +printExtLuProps(stmfGuid *guid) +{ + int stmfRet; + luResource hdl = NULL; + int ret = 0; + char propVal[MAXNAMELEN]; + size_t propValSize = sizeof (propVal); + + if ((stmfRet = stmfGetLuResource(guid, &hdl)) + != STMF_STATUS_SUCCESS) { + switch (stmfRet) { + case STMF_ERROR_BUSY: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("resource busy")); + break; + case STMF_ERROR_PERM: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("permission denied")); + break; + case STMF_ERROR_NOT_FOUND: + /* No error here */ + return (0); + default: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("get extended properties failed")); + break; + } + return (1); + } + + stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_FILENAME, propVal, + &propValSize); + (void) printf(PROPS_FORMAT, "Data File"); + if (stmfRet == STMF_STATUS_SUCCESS) { + (void) printf("%s\n", propVal); + } else if (stmfRet == STMF_ERROR_NO_PROP) { + (void) printf("not set\n"); + } else if (stmfRet == STMF_ERROR_NO_PROP_STANDBY) { + (void) printf("prop unavailable in standby\n"); + } else { + (void) printf("<error retrieving property>\n"); + ret++; + } + + stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_META_FILENAME, propVal, + &propValSize); + (void) printf(PROPS_FORMAT, "Meta File"); + if (stmfRet == STMF_STATUS_SUCCESS) { + (void) printf("%s\n", propVal); + } else if (stmfRet == STMF_ERROR_NO_PROP) { + (void) printf("not set\n"); + } else if (stmfRet == STMF_ERROR_NO_PROP_STANDBY) { + (void) printf("prop unavailable in standby\n"); + } else { + (void) printf("<error retrieving property>\n"); + ret++; + } + + stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_SIZE, propVal, + &propValSize); + (void) printf(PROPS_FORMAT, "Size"); + if (stmfRet == STMF_STATUS_SUCCESS) { + (void) printf("%s\n", propVal); + } else if (stmfRet == STMF_ERROR_NO_PROP) { + (void) printf("not set\n"); + } else if (stmfRet == STMF_ERROR_NO_PROP_STANDBY) { + (void) printf("prop unavailable in standby\n"); + } else { + (void) printf("<error retrieving property>\n"); + ret++; + } + + stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_BLOCK_SIZE, propVal, + &propValSize); + (void) printf(PROPS_FORMAT, "Block Size"); + if (stmfRet == STMF_STATUS_SUCCESS) { + (void) printf("%s\n", propVal); + } else if (stmfRet == STMF_ERROR_NO_PROP) { + (void) printf("not set\n"); + } else if (stmfRet == STMF_ERROR_NO_PROP_STANDBY) { + (void) printf("prop unavailable in standby\n"); + } else { + (void) printf("<error retrieving property>\n"); + ret++; + } + + stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_MGMT_URL, propVal, + &propValSize); + (void) printf(PROPS_FORMAT, "Management URL"); + if (stmfRet == STMF_STATUS_SUCCESS) { + (void) printf("%s\n", propVal); + } else if (stmfRet == STMF_ERROR_NO_PROP) { + (void) printf("not set\n"); + } else if (stmfRet == STMF_ERROR_NO_PROP_STANDBY) { + (void) printf("prop unavailable in standby\n"); + } else { + (void) printf("<error retrieving property>\n"); + ret++; + } + + stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_VID, propVal, + &propValSize); + (void) printf(PROPS_FORMAT, "Vendor ID"); + if (stmfRet == STMF_STATUS_SUCCESS) { + (void) printf("%s\n", propVal); + } else if (stmfRet == STMF_ERROR_NO_PROP) { + (void) printf("not set\n"); + } else if (stmfRet == STMF_ERROR_NO_PROP_STANDBY) { + (void) printf("prop unavailable in standby\n"); + } else { + (void) printf("<error retrieving property>\n"); + ret++; + } + + stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_PID, propVal, + &propValSize); + (void) printf(PROPS_FORMAT, "Product ID"); + if (stmfRet == STMF_STATUS_SUCCESS) { + (void) printf("%s\n", propVal); + } else if (stmfRet == STMF_ERROR_NO_PROP) { + (void) printf("not set\n"); + } else if (stmfRet == STMF_ERROR_NO_PROP_STANDBY) { + (void) printf("prop unavailable in standby\n"); + } else { + (void) printf("<error retrieving property>\n"); + ret++; + } + + stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_SERIAL_NUM, propVal, + &propValSize); + (void) printf(PROPS_FORMAT, "Serial Num"); + if (stmfRet == STMF_STATUS_SUCCESS) { + (void) printf("%s\n", propVal); + } else if (stmfRet == STMF_ERROR_NO_PROP) { + (void) printf("not set\n"); + } else if (stmfRet == STMF_ERROR_NO_PROP_STANDBY) { + (void) printf("prop unavailable in standby\n"); + } else { + (void) printf("<error retrieving property>\n"); + ret++; + } + + stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_WRITE_PROTECT, propVal, + &propValSize); + (void) printf(PROPS_FORMAT, "Write Protect"); + if (stmfRet == STMF_STATUS_SUCCESS) { + (void) printf("%s\n", + strcasecmp(propVal, "true") ? "Disabled" : "Enabled"); + } else if (stmfRet == STMF_ERROR_NO_PROP) { + (void) printf("not set\n"); + } else if (stmfRet == STMF_ERROR_NO_PROP_STANDBY) { + (void) printf("prop unavailable in standby\n"); + } else { + (void) printf("<error retrieving property>\n"); + ret++; + } + + stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_WRITE_CACHE_DISABLE, propVal, + &propValSize); + (void) printf(PROPS_FORMAT, "Writeback Cache"); + if (stmfRet == STMF_STATUS_SUCCESS) { + (void) printf("%s\n", + strcasecmp(propVal, "true") ? "Enabled" : "Disabled"); + } else if (stmfRet == STMF_ERROR_NO_PROP) { + (void) printf("not set\n"); + } else if (stmfRet == STMF_ERROR_NO_PROP_STANDBY) { + (void) printf("prop unavailable in standby\n"); + } else { + (void) printf("<error retrieving property>\n"); + ret++; + } + + stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_ACCESS_STATE, propVal, + &propValSize); + (void) printf(PROPS_FORMAT, "Access State"); + if (stmfRet == STMF_STATUS_SUCCESS) { + if (strcmp(propVal, STMF_ACCESS_ACTIVE) == 0) { + (void) printf("%s\n", "Active"); + } else if (strcmp(propVal, + STMF_ACCESS_ACTIVE_TO_STANDBY) == 0) { + (void) printf("%s\n", "Active->Standby"); + } else if (strcmp(propVal, STMF_ACCESS_STANDBY) == 0) { + (void) printf("%s\n", "Standby"); + } else if (strcmp(propVal, + STMF_ACCESS_STANDBY_TO_ACTIVE) == 0) { + (void) printf("%s\n", "Standby->Active"); + } else { + (void) printf("%s\n", "Unknown"); + } + } else if (stmfRet == STMF_ERROR_NO_PROP) { + (void) printf("not set\n"); + } else { + (void) printf("<error retrieving property>\n"); + ret++; + } + +done: + (void) stmfFreeLuResource(hdl); + return (ret); + +} + + +/* + * printLuProps + * + * Prints the properties for a logical unit + * + */ +static void +printLuProps(stmfLogicalUnitProperties *luProps) +{ + (void) printf(PROPS_FORMAT, "Operational Status"); + switch (luProps->status) { + case STMF_LOGICAL_UNIT_ONLINE: + (void) printf("Online"); + break; + case STMF_LOGICAL_UNIT_OFFLINE: + (void) printf("Offline"); + break; + case STMF_LOGICAL_UNIT_ONLINING: + (void) printf("Onlining"); + break; + case STMF_LOGICAL_UNIT_OFFLINING: + (void) printf("Offlining"); + break; + case STMF_LOGICAL_UNIT_UNREGISTERED: + (void) printf("unregistered"); + (void) strncpy(luProps->providerName, "unregistered", + sizeof (luProps->providerName)); + break; + default: + (void) printf("unknown"); + break; + } + (void) printf("\n"); + (void) printf(PROPS_FORMAT, "Provider Name"); + if (luProps->providerName[0] != 0) { + (void) printf("%s", luProps->providerName); + } else { + (void) printf("unknown"); + } + (void) printf("\n"); + (void) printf(PROPS_FORMAT, "Alias"); + if (luProps->alias[0] != 0) { + (void) printf("%s", luProps->alias); + } else { + (void) printf("-"); + } + (void) printf("\n"); +} + +/* + * printTargetProps + * + * Prints the properties for a target + * + */ +static void +printTargetProps(stmfTargetProperties *targetProps) +{ + (void) printf(PROPS_FORMAT, "Operational Status"); + switch (targetProps->status) { + case STMF_TARGET_PORT_ONLINE: + (void) printf("Online"); + break; + case STMF_TARGET_PORT_OFFLINE: + (void) printf("Offline"); + break; + case STMF_TARGET_PORT_ONLINING: + (void) printf("Onlining"); + break; + case STMF_TARGET_PORT_OFFLINING: + (void) printf("Offlining"); + break; + default: + (void) printf("unknown"); + break; + } + (void) printf("\n"); + (void) printf(PROPS_FORMAT, "Provider Name"); + if (targetProps->providerName[0] != 0) { + (void) printf("%s", targetProps->providerName); + } + (void) printf("\n"); + (void) printf(PROPS_FORMAT, "Alias"); + if (targetProps->alias[0] != 0) { + (void) printf("%s", targetProps->alias); + } else { + (void) printf("-"); + } + (void) printf("\n"); + (void) printf(PROPS_FORMAT, "Protocol"); + switch (targetProps->protocol) { + case STMF_PROTOCOL_FIBRE_CHANNEL: + (void) printf("%s", "Fibre Channel"); + break; + case STMF_PROTOCOL_ISCSI: + (void) printf("%s", "iSCSI"); + break; + case STMF_PROTOCOL_SRP: + (void) printf("%s", "SRP"); + break; + case STMF_PROTOCOL_SAS: + (void) printf("%s", "SAS"); + break; + default: + (void) printf("%s", "unknown"); + break; + } + + (void) printf("\n"); +} + +/* + * printSessionProps + * + * Prints the session data + * + */ +static void +printSessionProps(stmfSessionList *sessionList) +{ + int i; + char *cTime; + wchar_t initiator[STMF_IDENT_LENGTH + 1]; + + (void) printf(PROPS_FORMAT, "Sessions"); + (void) printf("%d\n", sessionList->cnt); + for (i = 0; i < sessionList->cnt; i++) { + (void) mbstowcs(initiator, + (char *)sessionList->session[i].initiator.ident, + STMF_IDENT_LENGTH); + initiator[STMF_IDENT_LENGTH] = 0; + (void) printf(LVL3_FORMAT, "Initiator: "); + (void) printf("%ws\n", initiator); + (void) printf(LVL4_FORMAT, "Alias: "); + if (sessionList->session[i].alias[0] != 0) { + (void) printf("%s", sessionList->session[i].alias); + } else { + (void) printf("-"); + } + (void) printf("\n"); + (void) printf(LVL4_FORMAT, "Logged in since: "); + cTime = ctime(&(sessionList->session[i].creationTime)); + if (cTime != NULL) { + (void) printf("%s", cTime); + } else { + (void) printf("unknown\n"); + } + } +} + +static int +getStmfState(stmfState *state) +{ + int ret; + + ret = stmfGetState(state); + switch (ret) { + case STMF_STATUS_SUCCESS: + break; + case STMF_ERROR_PERM: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("permission denied")); + break; + case STMF_ERROR_SERVICE_NOT_FOUND: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF service not found")); + break; + case STMF_ERROR_BUSY: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("resource busy")); + break; + case STMF_ERROR_SERVICE_DATA_VERSION: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF service version incorrect")); + break; + default: + (void) fprintf(stderr, "%s: %s: %d\n", cmdName, + gettext("unknown error"), ret); + break; + } + return (ret); +} + +/* + * listStateFunc + * + * List the operational and config state of the stmf service + * + */ +/*ARGSUSED*/ +static int +listStateFunc(int operandLen, char *operands[], cmdOptions_t *options, + void *args) +{ + int ret; + stmfState state; + boolean_t aluaEnabled; + uint32_t node; + + if ((ret = getStmfState(&state)) != STMF_STATUS_SUCCESS) + return (ret); + + (void) printf("%-18s: ", "Operational Status"); + switch (state.operationalState) { + case STMF_SERVICE_STATE_ONLINE: + (void) printf("online"); + break; + case STMF_SERVICE_STATE_OFFLINE: + (void) printf("offline"); + break; + case STMF_SERVICE_STATE_ONLINING: + (void) printf("onlining"); + break; + case STMF_SERVICE_STATE_OFFLINING: + (void) printf("offlining"); + break; + default: + (void) printf("unknown"); + break; + } + (void) printf("\n"); + (void) printf("%-18s: ", "Config Status"); + switch (state.configState) { + case STMF_CONFIG_STATE_NONE: + (void) printf("uninitialized"); + break; + case STMF_CONFIG_STATE_INIT: + (void) printf("initializing"); + break; + case STMF_CONFIG_STATE_INIT_DONE: + (void) printf("initialized"); + break; + default: + (void) printf("unknown"); + break; + } + (void) printf("\n"); + ret = stmfGetAluaState(&aluaEnabled, &node); + switch (ret) { + case STMF_STATUS_SUCCESS: + break; + case STMF_ERROR_PERM: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("permission denied")); + break; + case STMF_ERROR_BUSY: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("resource busy")); + break; + default: + (void) fprintf(stderr, "%s: %s: %d\n", cmdName, + gettext("unknown error"), ret); + break; + } + (void) printf("%-18s: ", "ALUA Status"); + if (ret == STMF_STATUS_SUCCESS) { + if (aluaEnabled == B_TRUE) { + (void) printf("enabled"); + } else { + (void) printf("disabled"); + } + } else { + (void) printf("unknown"); + } + + (void) printf("\n"); + (void) printf("%-18s: ", "ALUA Node"); + if (ret == STMF_STATUS_SUCCESS) { + (void) printf("%d", node); + } else { + (void) printf("unknown"); + } + (void) printf("\n"); + return (ret); +} + +/* + * listTargetFunc + * + * list the targets and optionally their properties + * + */ +/*ARGSUSED*/ +static int +listTargetFunc(int operandLen, char *operands[], cmdOptions_t *options, + void *args) +{ + cmdOptions_t *optionList = options; + int ret = 0; + int stmfRet; + int i, j; + int outerLoop; + stmfSessionList *sessionList; + stmfDevid devid; + boolean_t operandEntered, found, verbose = B_FALSE; + stmfDevidList *targetList; + wchar_t targetIdent[STMF_IDENT_LENGTH + 1]; + stmfTargetProperties targetProps; + + if ((stmfRet = stmfGetTargetList(&targetList)) != STMF_STATUS_SUCCESS) { + switch (stmfRet) { + case STMF_ERROR_NOT_FOUND: + ret = 0; + break; + case STMF_ERROR_SERVICE_OFFLINE: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF service offline")); + break; + case STMF_ERROR_BUSY: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("resource busy")); + break; + case STMF_ERROR_SERVICE_DATA_VERSION: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF service version incorrect")); + break; + case STMF_ERROR_PERM: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("permission denied")); + break; + default: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("unknown error")); + break; + } + return (1); + } + + for (; optionList->optval; optionList++) { + switch (optionList->optval) { + case 'v': + verbose = B_TRUE; + break; + } + } + + if (operandLen > 0) { + outerLoop = operandLen; + operandEntered = B_TRUE; + } else { + outerLoop = 1; + operandEntered = B_FALSE; + } + + for (i = 0; i < outerLoop; i++) { + if (operandEntered) { + bzero(&devid, sizeof (devid)); + (void) parseDevid(operands[i], &devid); + } + for (found = B_FALSE, j = 0; j < targetList->cnt; j++) { + if (operandEntered) { + if (bcmp(&devid, &(targetList->devid[j]), + sizeof (devid)) == 0) { + found = B_TRUE; + } + } + if ((found && operandEntered) || !operandEntered) { + (void) mbstowcs(targetIdent, + (char *)targetList->devid[j].ident, + STMF_IDENT_LENGTH); + targetIdent[STMF_IDENT_LENGTH] = 0; + (void) printf("Target: %ws\n", targetIdent); + if (verbose) { + stmfRet = stmfGetTargetProperties( + &(targetList->devid[j]), + &targetProps); + if (stmfRet == STMF_STATUS_SUCCESS) { + printTargetProps(&targetProps); + } else { + (void) fprintf(stderr, "%s:", + cmdName); + (void) fprintf(stderr, "%s\n", + gettext(" get properties" + " failed")); + } + stmfRet = stmfGetSessionList( + &(targetList->devid[j]), + &sessionList); + if (stmfRet == STMF_STATUS_SUCCESS) { + printSessionProps(sessionList); + } else { + (void) fprintf(stderr, "%s:", + cmdName); + (void) fprintf(stderr, "%s\n", + gettext(" get session info" + " failed")); + } + } + if (found && operandEntered) { + break; + } + } + + } + if (operandEntered && !found) { + (void) fprintf(stderr, "%s: %s: %s\n", cmdName, + operands[i], "not found"); + ret = 1; + } + } + return (ret); +} + +/* + * listViewFunc + * + * list the view entries for the specified logical unit + * + */ +/*ARGSUSED*/ +static int +listViewFunc(int operandLen, char *operands[], cmdOptions_t *options, + void *args) +{ + stmfViewEntryList *viewEntryList; + stmfGuid inGuid; + unsigned int guid[sizeof (stmfGuid)]; + int ret = 0; + int stmfRet; + int i, j, outerLoop; + boolean_t found = B_TRUE; + boolean_t operandEntered; + uint16_t outputLuNbr; + wchar_t groupName[sizeof (stmfGroupName)]; + char sGuid[GUID_INPUT + 1]; + + + for (; options->optval; options++) { + switch (options->optval) { + case 'l': + if (strlen(options->optarg) != GUID_INPUT) { + (void) fprintf(stderr, + "%s: %s: %s%d%s\n", + cmdName, options->optarg, + gettext("must be "), GUID_INPUT, + gettext(" hexadecimal digits" + " long")); + return (1); + } + bcopy(options->optarg, sGuid, GUID_INPUT); + break; + default: + (void) fprintf(stderr, "%s: %c: %s\n", + cmdName, options->optval, + gettext("unknown option")); + return (1); + } + } + + if (operandLen > 0) { + outerLoop = operandLen; + operandEntered = B_TRUE; + } else { + outerLoop = 1; + operandEntered = B_FALSE; + } + + for (i = 0; i < 32; i++) + sGuid[i] = tolower(sGuid[i]); + sGuid[i] = 0; + + (void) sscanf(sGuid, "%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 (i = 0; i < sizeof (stmfGuid); i++) { + inGuid.guid[i] = guid[i]; + } + + if ((stmfRet = stmfGetViewEntryList(&inGuid, &viewEntryList)) + != STMF_STATUS_SUCCESS) { + + switch (stmfRet) { + case STMF_ERROR_BUSY: + (void) fprintf(stderr, "%s: %s: %s\n", cmdName, + sGuid, gettext("resource busy")); + break; + case STMF_ERROR_SERVICE_NOT_FOUND: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF service not found")); + break; + case STMF_ERROR_SERVICE_DATA_VERSION: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF service version incorrect")); + break; + case STMF_ERROR_PERM: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("permission denied")); + break; + default: + (void) fprintf(stderr, "%s: %s: %s\n", cmdName, + sGuid, gettext("unknown error")); + break; + } + return (1); + } + + if (viewEntryList->cnt == 0) { + (void) fprintf(stderr, "%s: %s: %s\n", cmdName, + sGuid, gettext("no views found")); + return (1); + } + + for (i = 0; i < outerLoop; i++) { + for (found = B_FALSE, j = 0; j < viewEntryList->cnt; j++) { + if (operandEntered) { + if (atoi(operands[i]) == + viewEntryList->ve[j].veIndex) { + found = B_TRUE; + } + } + if ((found && operandEntered) || !operandEntered) { + (void) printf("View Entry: %d\n", + viewEntryList->ve[j].veIndex); + (void) printf(VIEW_FORMAT, "Host group"); + if (viewEntryList->ve[j].allHosts) { + (void) printf("All\n"); + } else { + (void) mbstowcs(groupName, + viewEntryList->ve[j].hostGroup, + sizeof (stmfGroupName) - 1); + groupName[sizeof (stmfGroupName) - 1] + = 0; + (void) printf("%ws\n", groupName); + } + (void) printf(VIEW_FORMAT, "Target group"); + if (viewEntryList->ve[j].allTargets) { + (void) printf("All\n"); + } else { + (void) mbstowcs(groupName, + viewEntryList->ve[j].targetGroup, + sizeof (stmfGroupName) - 1); + groupName[sizeof (stmfGroupName) - 1] + = 0; + (void) printf("%ws\n", groupName); + } + outputLuNbr = ((viewEntryList->ve[j].luNbr[0] & + 0x3F) << 8) | viewEntryList->ve[j].luNbr[1]; + (void) printf(VIEW_FORMAT, "LUN"); + (void) printf("%d\n", outputLuNbr); + if (found && operandEntered) { + break; + } + } + } + if (operandEntered && !found) { + (void) fprintf(stderr, "%s: %s, %s: %s\n", cmdName, + sGuid, operands[i], gettext("not found")); + ret = 1; + } + } + + return (ret); +} + + +/* + * onlineOfflineLu + * + * Purpose: Online or offline a logical unit + * + * lu - logical unit to online or offline + * + * state - ONLINE_LU + * OFFLINE_LU + */ +static int +onlineOfflineLu(char *lu, int state) +{ + char sGuid[GUID_INPUT + 1]; + stmfGuid inGuid; + unsigned int guid[sizeof (stmfGuid)]; + int i; + int ret = 0, stmfRet; + stmfLogicalUnitProperties luProps; + + if (strlen(lu) != GUID_INPUT) { + (void) fprintf(stderr, "%s: %s: %s %d %s\n", cmdName, lu, + gettext("must be"), GUID_INPUT, + gettext("hexadecimal digits long")); + return (1); + } + + bcopy(lu, sGuid, GUID_INPUT); + + for (i = 0; i < 32; i++) + sGuid[i] = tolower(sGuid[i]); + sGuid[i] = 0; + + (void) sscanf(sGuid, "%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 (i = 0; i < sizeof (stmfGuid); i++) { + inGuid.guid[i] = guid[i]; + } + + if (state == ONLINE_LU) { + ret = stmfOnlineLogicalUnit(&inGuid); + } else if (state == OFFLINE_LU) { + ret = stmfOfflineLogicalUnit(&inGuid); + } else { + return (STMFADM_FAILURE); + } + if (ret != STMF_STATUS_SUCCESS) { + switch (ret) { + case STMF_ERROR_PERM: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("permission denied")); + break; + case STMF_ERROR_SERVICE_NOT_FOUND: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF service not found")); + break; + case STMF_ERROR_BUSY: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("resource busy")); + break; + case STMF_ERROR_NOT_FOUND: + (void) fprintf(stderr, "%s: %s: %s\n", cmdName, + lu, gettext("not found")); + break; + case STMF_ERROR_SERVICE_DATA_VERSION: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF service version incorrect")); + break; + default: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("unknown error")); + break; + } + } else { + struct timespec ts = {0}; + unsigned int count = 0; + uint32_t ret_state; + + ret_state = (state == ONLINE_LU) ? + STMF_LOGICAL_UNIT_ONLINING : STMF_LOGICAL_UNIT_OFFLINING; + ts.tv_nsec = DELAYED_EXEC_WAIT_INTERVAL; + + /* CONSTCOND */ + while (1) { + stmfRet = stmfGetLogicalUnitProperties(&inGuid, + &luProps); + if (stmfRet == STMF_STATUS_SUCCESS) + ret_state = luProps.status; + + if ((state == ONLINE_LU && + ret_state == STMF_LOGICAL_UNIT_ONLINE) || + (state == OFFLINE_LU && + ret_state == STMF_LOGICAL_UNIT_OFFLINE)) + return (STMFADM_SUCCESS); + + if ((state == ONLINE_LU && + ret_state == STMF_LOGICAL_UNIT_OFFLINE) || + (state == OFFLINE_LU && + ret_state == STMF_LOGICAL_UNIT_ONLINE)) + return (STMFADM_FAILURE); + + if (++count == DELAYED_EXEC_WAIT_MAX) { + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("Logical Unit state change request " + "submitted. Waiting for completion " + "timed out")); + return (STMFADM_FAILURE); + } + (void) nanosleep(&ts, NULL); + } + } + return (STMFADM_FAILURE); +} + +/* + * onlineLuFunc + * + * Purpose: Online a logical unit + * + */ +/*ARGSUSED*/ +static int +onlineLuFunc(int operandLen, char *operands[], cmdOptions_t *options, + void *args) +{ + int ret; + stmfState state; + + ret = getStmfState(&state); + if (ret != STMF_STATUS_SUCCESS) + return (ret); + if (state.operationalState == STMF_SERVICE_STATE_OFFLINE || + state.operationalState == STMF_SERVICE_STATE_OFFLINING) { + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF service is offline")); + return (1); + } + return (onlineOfflineLu(operands[0], ONLINE_LU)); +} + +/* + * offlineLuFunc + * + * Purpose: Offline a logical unit + * + */ +/*ARGSUSED*/ +static int +offlineLuFunc(int operandLen, char *operands[], cmdOptions_t *options, + void *args) +{ + return (onlineOfflineLu(operands[0], OFFLINE_LU)); +} + +/* + * onlineOfflineTarget + * + * Purpose: Online or offline a target + * + * target - target to online or offline + * + * state - ONLINE_TARGET + * OFFLINE_TARGET + */ +static int +onlineOfflineTarget(char *target, int state) +{ + int ret = 0, stmfRet = 0; + stmfDevid devid; + stmfTargetProperties targetProps; + + if (parseDevid(target, &devid) != 0) { + (void) fprintf(stderr, "%s: %s: %s\n", + cmdName, target, gettext("unrecognized device id")); + return (1); + } + if (state == ONLINE_TARGET) { + ret = stmfOnlineTarget(&devid); + } else if (state == OFFLINE_TARGET) { + ret = stmfOfflineTarget(&devid); + } else { + return (STMFADM_FAILURE); + } + if (ret != STMF_STATUS_SUCCESS) { + switch (ret) { + case STMF_ERROR_PERM: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("permission denied")); + break; + case STMF_ERROR_SERVICE_NOT_FOUND: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF service not found")); + break; + case STMF_ERROR_BUSY: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("resource busy")); + break; + case STMF_ERROR_NOT_FOUND: + (void) fprintf(stderr, "%s: %s: %s\n", cmdName, + target, gettext("not found")); + break; + case STMF_ERROR_SERVICE_DATA_VERSION: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF service version incorrect")); + break; + default: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("unknown error")); + break; + } + } else { + struct timespec ts = {0}; + unsigned int count = 0; + uint32_t ret_state; + + ret_state = (state == ONLINE_TARGET) ? + STMF_TARGET_PORT_ONLINING : STMF_TARGET_PORT_OFFLINING; + ts.tv_nsec = DELAYED_EXEC_WAIT_INTERVAL; + + /* CONSTCOND */ + while (1) { + stmfRet = stmfGetTargetProperties(&devid, &targetProps); + if (stmfRet == STMF_STATUS_SUCCESS) + ret_state = targetProps.status; + + if ((state == ONLINE_TARGET && + ret_state == STMF_TARGET_PORT_ONLINE) || + (state == OFFLINE_TARGET && + ret_state == STMF_TARGET_PORT_OFFLINE)) { + return (STMFADM_SUCCESS); + } + + if ((state == ONLINE_TARGET && + ret_state == STMF_TARGET_PORT_OFFLINE) || + (state == OFFLINE_TARGET && + ret_state == STMF_TARGET_PORT_ONLINE)) { + return (STMFADM_FAILURE); + } + + if (++count == DELAYED_EXEC_WAIT_MAX) { + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("Target state change request " + "submitted. Waiting for completion " + "timed out.")); + return (STMFADM_FAILURE); + } + (void) nanosleep(&ts, NULL); + } + } + return (STMFADM_FAILURE); +} + +/* + * onlineTargetFunc + * + * Purpose: Online a target + * + */ +/*ARGSUSED*/ +static int +onlineTargetFunc(int operandLen, char *operands[], cmdOptions_t *options, + void *args) +{ + int ret; + stmfState state; + + ret = getStmfState(&state); + if (ret != STMF_STATUS_SUCCESS) + return (ret); + if (state.operationalState == STMF_SERVICE_STATE_OFFLINE || + state.operationalState == STMF_SERVICE_STATE_OFFLINING) { + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF service is offline")); + return (1); + } + return (onlineOfflineTarget(operands[0], ONLINE_TARGET)); +} + +/* + * offlineTargetFunc + * + * Purpose: Offline a target + * + */ +/*ARGSUSED*/ +static int +offlineTargetFunc(int operandLen, char *operands[], cmdOptions_t *options, + void *args) +{ + return (onlineOfflineTarget(operands[0], OFFLINE_TARGET)); +} + + +/*ARGSUSED*/ +static int +removeHostGroupMemberFunc(int operandLen, char *operands[], + cmdOptions_t *options, void *args) +{ + int i; + int ret = 0; + int stmfRet; + stmfGroupName groupName = {0}; + stmfDevid devid; + wchar_t groupNamePrint[sizeof (stmfGroupName)] = {0}; + + for (; options->optval; options++) { + switch (options->optval) { + case 'g': + (void) mbstowcs(groupNamePrint, options->optarg, + sizeof (stmfGroupName) - 1); + bcopy(options->optarg, groupName, + strlen(options->optarg)); + break; + default: + (void) fprintf(stderr, "%s: %c: %s\n", + cmdName, options->optval, + gettext("unknown option")); + return (1); + } + } + + for (i = 0; i < operandLen; i++) { + if (parseDevid(operands[i], &devid) != 0) { + (void) fprintf(stderr, "%s: %s: %s\n", + cmdName, operands[i], + gettext("unrecognized device id")); + ret++; + continue; + } + stmfRet = stmfRemoveFromHostGroup(&groupName, &devid); + switch (stmfRet) { + case STMF_STATUS_SUCCESS: + break; + case STMF_ERROR_MEMBER_NOT_FOUND: + (void) fprintf(stderr, "%s: %s: %s\n", cmdName, + operands[i], gettext("not found")); + ret++; + break; + case STMF_ERROR_GROUP_NOT_FOUND: + (void) fprintf(stderr, "%s: %ws: %s\n", cmdName, + groupNamePrint, gettext("not found")); + ret++; + break; + case STMF_ERROR_BUSY: + (void) fprintf(stderr, "%s: %s: %s\n", cmdName, + operands[i], "resource busy"); + ret++; + break; + case STMF_ERROR_SERVICE_NOT_FOUND: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF service not found")); + ret++; + break; + case STMF_ERROR_SERVICE_DATA_VERSION: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF service version incorrect")); + ret++; + break; + case STMF_ERROR_PERM: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("permission denied")); + ret++; + break; + default: + (void) fprintf(stderr, "%s: %s: %s\n", cmdName, + operands[i], gettext("unknown error")); + ret++; + break; + } + } + + return (ret); +} + +/* + * removeTargetGroupMemberFunc + * + * Removes one or more members from a target group + * + */ +/*ARGSUSED*/ +static int +removeTargetGroupMemberFunc(int operandLen, char *operands[], + cmdOptions_t *options, void *args) +{ + int i; + int ret = 0; + int stmfRet; + stmfGroupName groupName = {0}; + stmfDevid devid; + wchar_t groupNamePrint[sizeof (stmfGroupName)] = {0}; + + for (; options->optval; options++) { + switch (options->optval) { + case 'g': + (void) mbstowcs(groupNamePrint, options->optarg, + sizeof (stmfGroupName) - 1); + bcopy(options->optarg, groupName, + strlen(options->optarg)); + break; + default: + (void) fprintf(stderr, "%s: %c: %s\n", + cmdName, options->optval, + gettext("unknown option")); + return (1); + } + } + + for (i = 0; i < operandLen; i++) { + if (parseDevid(operands[i], &devid) != 0) { + (void) fprintf(stderr, "%s: %s: %s\n", + cmdName, operands[i], + gettext("unrecognized device id")); + ret++; + continue; + } + stmfRet = stmfRemoveFromTargetGroup(&groupName, &devid); + switch (stmfRet) { + case STMF_STATUS_SUCCESS: + break; + case STMF_ERROR_MEMBER_NOT_FOUND: + (void) fprintf(stderr, "%s: %s: %s\n", cmdName, + operands[i], gettext("not found")); + ret++; + break; + case STMF_ERROR_GROUP_NOT_FOUND: + (void) fprintf(stderr, "%s: %ws: %s\n", cmdName, + groupNamePrint, gettext("not found")); + ret++; + break; + case STMF_ERROR_BUSY: + (void) fprintf(stderr, "%s: %s: %s\n", cmdName, + operands[i], gettext("resource busy")); + ret++; + break; + case STMF_ERROR_SERVICE_NOT_FOUND: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF service not found")); + ret++; + break; + case STMF_ERROR_PERM: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("permission denied")); + ret++; + break; + case STMF_ERROR_SERVICE_DATA_VERSION: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF service version incorrect")); + ret++; + break; + case STMF_ERROR_TG_ONLINE: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF target must be offline")); + ret++; + break; + default: + (void) fprintf(stderr, "%s: %s: %s\n", cmdName, + operands[i], gettext("unknown error")); + ret++; + break; + } + } + + return (ret); +} + +/* + * removeViewFunc + * + * Removes one or more view entries from a logical unit + * + */ +/*ARGSUSED*/ +static int +removeViewFunc(int operandLen, char *operands[], cmdOptions_t *options, + void *args) +{ + char sGuid[GUID_INPUT + 1]; + stmfViewEntryList *viewEntryList; + stmfGuid inGuid; + uint32_t count; + unsigned int guid[sizeof (stmfGuid)]; + char *endPtr; + uint32_t veNbr; + int i; + boolean_t all = B_FALSE; + boolean_t luInput = B_FALSE; + int ret = 0; + int stmfRet; + + /* Note: 'l' is required */ + for (; options->optval; options++) { + switch (options->optval) { + case 'l': + if (strlen(options->optarg) != GUID_INPUT) { + (void) fprintf(stderr, + "%s: %s: %s %d %s\n", + cmdName, options->optarg, + gettext("must be"), GUID_INPUT, + gettext("hexadecimal digits long")); + return (1); + } + bcopy(options->optarg, sGuid, GUID_INPUT); + luInput = B_TRUE; + break; + case 'a': + /* removing all view entries for this GUID */ + all = B_TRUE; + break; + default: + (void) fprintf(stderr, "%s: %c: %s\n", + cmdName, options->optval, + "unknown option"); + return (1); + } + } + + if (!all && operandLen == 0) { + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("no view entries specified")); + return (1); + } + + if (!luInput) { + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("logical unit (-l) not specified")); + return (1); + } + + for (i = 0; i < 32; i++) + sGuid[i] = tolower(sGuid[i]); + sGuid[i] = 0; + + (void) sscanf(sGuid, "%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 (i = 0; i < sizeof (stmfGuid); i++) { + inGuid.guid[i] = guid[i]; + } + + if ((stmfRet = stmfGetViewEntryList(&inGuid, &viewEntryList)) + != STMF_STATUS_SUCCESS) { + + switch (stmfRet) { + case STMF_ERROR_BUSY: + (void) fprintf(stderr, "%s: %s: %s\n", cmdName, + sGuid, gettext("resource busy")); + break; + case STMF_ERROR_SERVICE_NOT_FOUND: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF service not found")); + break; + case STMF_ERROR_SERVICE_DATA_VERSION: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF service version incorrect")); + break; + case STMF_ERROR_PERM: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("permission denied")); + break; + default: + (void) fprintf(stderr, "%s: %s: %s\n", cmdName, + sGuid, gettext("unknown error")); + break; + } + return (1); + } + + if (viewEntryList->cnt == 0) { + (void) fprintf(stderr, "%s: %s: %s\n", cmdName, + sGuid, gettext("no views found")); + return (1); + } + + if (all) { + count = viewEntryList->cnt; + } else { + count = operandLen; + } + + for (i = 0; i < count; i++) { + if (all) { + veNbr = viewEntryList->ve[i].veIndex; + } else { + endPtr = NULL; + veNbr = strtol(operands[i], &endPtr, 10); + if (endPtr && *endPtr != 0) { + (void) fprintf(stderr, "%s: %s: %s\n", cmdName, + operands[i], gettext("invalid input")); + continue; + } + } + stmfRet = stmfRemoveViewEntry(&inGuid, veNbr); + switch (stmfRet) { + case STMF_STATUS_SUCCESS: + break; + case STMF_ERROR_NOT_FOUND: + (void) fprintf(stderr, "%s: %s: %d: %s\n", + cmdName, sGuid, veNbr, + gettext("not found")); + ret++; + break; + case STMF_ERROR_BUSY: + (void) fprintf(stderr, "%s: %s: %s\n", cmdName, + sGuid, gettext("resource busy")); + ret++; + break; + case STMF_ERROR_SERVICE_NOT_FOUND: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF service not found")); + ret++; + break; + case STMF_ERROR_CONFIG_NONE: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF service is not initialized")); + ret++; + break; + case STMF_ERROR_SERVICE_DATA_VERSION: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF service version incorrect")); + ret++; + break; + default: + (void) fprintf(stderr, "%s: %s, %d: %s", + cmdName, sGuid, veNbr, + gettext("unknown error")); + ret++; + break; + } + } + + return (ret); +} + +/* + * input: + * execFullName - exec name of program (argv[0]) + * + * copied from usr/src/cmd/zoneadm/zoneadm.c in OS/Net + * (changed name to lowerCamelCase to keep consistent with this file) + * + * Returns: + * command name portion of execFullName + */ +static char * +getExecBasename(char *execFullname) +{ + char *lastSlash, *execBasename; + + /* guard against '/' at end of command invocation */ + for (;;) { + lastSlash = strrchr(execFullname, '/'); + if (lastSlash == NULL) { + execBasename = execFullname; + break; + } else { + execBasename = lastSlash + 1; + if (*execBasename == '\0') { + *lastSlash = '\0'; + continue; + } + break; + } + } + return (execBasename); +} + +int +main(int argc, char *argv[]) +{ + synTables_t synTables; + char versionString[VERSION_STRING_MAX_LEN]; + int ret; + int funcRet; + void *subcommandArgs = NULL; + + (void) setlocale(LC_ALL, ""); + (void) textdomain(TEXT_DOMAIN); + /* set global command name */ + cmdName = getExecBasename(argv[0]); + + (void) snprintf(versionString, VERSION_STRING_MAX_LEN, "%s.%s", + VERSION_STRING_MAJOR, VERSION_STRING_MINOR); + synTables.versionString = versionString; + synTables.longOptionTbl = &longOptions[0]; + synTables.subCommandPropsTbl = &subcommands[0]; + + ret = cmdParse(argc, argv, synTables, subcommandArgs, &funcRet); + if (ret != 0) { + return (ret); + } + + return (funcRet); +} /* end main */ diff --git a/usr/src/cmd/stmfadm/stmfadm.h b/usr/src/cmd/stmfadm/stmfadm.h new file mode 100644 index 0000000..2224db9 --- /dev/null +++ b/usr/src/cmd/stmfadm/stmfadm.h @@ -0,0 +1,73 @@ +/* + * 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 _STMFADM_H +#define _STMFADM_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <libintl.h> +#include <unistd.h> +#include <sys/types.h> +#include <netinet/in.h> +#include <inttypes.h> +#include <cmdparse.h> + +/* DEFINES */ + +/* subcommands */ +#define ADD_MEMBER SUBCOMMAND(0) +#define ADD_VIEW SUBCOMMAND(1) +#define CREATE_I_GROUP SUBCOMMAND(2) +#define CREATE_T_GROUP SUBCOMMAND(3) +#define DELETE_GROUP SUBCOMMAND(4) +#define LIST_INIT SUBCOMMAND(5) +#define LIST_INIT_GROUP SUBCOMMAND(6) +#define LIST_TARGET_GROUP SUBCOMMAND(7) +#define LIST_VIEW SUBCOMMAND(8) +#define REMOVE_MEMBER SUBCOMMAND(9) +#define REMOVE_VIEW SUBCOMMAND(10) + + +#define OPERANDSTRING_INITIATOR "initiator-name" +#define OPERANDSTRING_LU "LU-name" +#define OPERANDSTRING_GROUP_MEMBER "group-member" +#define OPERANDSTRING_GROUP_NAME "group-name" +#define OPERANDSTRING_TARGET "target-name" +#define OPERANDSTRING_VIEW_ENTRY "ve-number" + +#define VERSION_STRING_MAX_LEN 10 + + +#ifdef __cplusplus +} +#endif + +#endif /* _STMFADM_H */ diff --git a/usr/src/cmd/stmfsvc/stmf.xml b/usr/src/cmd/stmfsvc/stmf.xml new file mode 100644 index 0000000..b3119da --- /dev/null +++ b/usr/src/cmd/stmfsvc/stmf.xml @@ -0,0 +1,119 @@ +<?xml version='1.0'?> +<!DOCTYPE service_bundle SYSTEM '/usr/share/lib/xml/dtd/service_bundle.dtd.1'> + +<!-- + +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. + + +Service manifests for SCSI Target Mode Framework +--> + +<!-- + +--> + +<service_bundle type='manifest' name='stmf'> + +<service + name='system/stmf' + type='service' + version='1'> + + <create_default_instance enabled='false' /> + + <single_instance/> + + <dependency name = 'filesystem_local' + grouping='require_all' + restart_on='none' + type='service'> + <service_fmri + value='svc:/system/filesystem/local:default'/> + </dependency> + + <exec_method + type='method' + name='start' + exec='/lib/svc/method/svc-stmf start' + timeout_seconds='600'> + <method_context> + <method_credential + user='root' + group='root' + privileges='basic,sys_devices' + /> + </method_context> + </exec_method> + + <exec_method + type='method' + name='stop' + exec='/lib/svc/method/svc-stmf stop' + timeout_seconds='600'> + <method_context> + <method_credential + user='root' + group='root' + privileges='basic,sys_devices' + /> + </method_context> + </exec_method> + + <property_group name='startd' type='framework'> + <propval name='duration' type='astring' + value='transient' /> + </property_group> + + <property_group name='general' type='framework'> + <!-- to start stop stmf --> + <propval name='action_authorization' type='astring' + value='solaris.smf.manage.stmf' /> + </property_group> + + <property_group name='host_groups' type='application'> + </property_group> + + <property_group name='target_groups' type='application'> + </property_group> + + + <stability value='Evolving' /> + + <template> + <common_name> + <loctext xml:lang='C'> + STMF + </loctext> + </common_name> + <documentation> + <manpage title='stmf' section='7D' + manpath='/usr/share/man' /> + <manpage title='stmfadm' section='1M' + manpath='/usr/share /man' /> + </documentation> + </template> + +</service> + +</service_bundle> diff --git a/usr/src/cmd/stmfsvc/stmfsvc.c b/usr/src/cmd/stmfsvc/stmfsvc.c new file mode 100644 index 0000000..814ebc2 --- /dev/null +++ b/usr/src/cmd/stmfsvc/stmfsvc.c @@ -0,0 +1,307 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <strings.h> +#include <sys/types.h> +#include <unistd.h> +#include <libintl.h> +#include <errno.h> +#include <time.h> +#include <string.h> +#include <assert.h> +#include <getopt.h> +#include <cmdparse.h> +#include <libstmf.h> +#include <signal.h> +#include <pthread.h> +#include <locale.h> + +static int svcStart(int, char **, cmdOptions_t *, void *); +static int svcStop(int, char **, cmdOptions_t *, void *); +static int online(); + +/* + * MAJOR - This should only change when there is an incompatible change made + * to the interfaces or the output. + * + * MINOR - This should change whenever there is a new command or new feature + * with no incompatible change. + */ +#define VERSION_STRING_MAJOR "1" +#define VERSION_STRING_MINOR "0" +#define VERSION_STRING_MAX_LEN 10 + +/* 10 ms sleep in nanoseconds */ +#define TEN_MS_NANOSLEEP 10000000 + +/* tables set up based on cmdparse instructions */ + +/* add new options here */ +optionTbl_t longOptions[] = { + {NULL, 0, 0, 0} +}; + +/* + * Add new subcommands here + */ +subCommandProps_t subcommands[] = { + {"start", svcStart, NULL, NULL, NULL, OPERAND_NONE, NULL}, + {"stop", svcStop, NULL, NULL, NULL, OPERAND_NONE, NULL}, + {NULL, 0, NULL, NULL, 0, NULL, 0, NULL} +}; + +/* globals */ +char *cmdName; + +/* + * svcStop + * + * Offlines the stmf service + * + */ +/*ARGSUSED*/ +static int +svcStop(int operandLen, char *operands[], cmdOptions_t *options, + void *args) +{ + int stmfRet; + int ret = 0; + stmfState state; + boolean_t serviceOffline = B_FALSE; + struct timespec rqtp; + + bzero(&rqtp, sizeof (rqtp)); + + rqtp.tv_nsec = TEN_MS_NANOSLEEP; + + if ((stmfRet = stmfOffline()) != STMF_STATUS_SUCCESS) { + switch (stmfRet) { + case STMF_ERROR_PERM: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("permission denied")); + break; + case STMF_ERROR_SERVICE_NOT_FOUND: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF service not found")); + break; + case STMF_ERROR_SERVICE_OFFLINE: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF service already offline")); + break; + default: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("unable to offline service")); + break; + } + return (1); + } + + /* wait for service offline */ + while (!serviceOffline) { + stmfRet = stmfGetState(&state); + if (stmfRet != STMF_STATUS_SUCCESS) { + ret = 1; + break; + } + if (state.operationalState == STMF_SERVICE_STATE_OFFLINE) { + serviceOffline = B_TRUE; + } else { + (void) nanosleep(&rqtp, NULL); + } + } + + return (ret); +} + +/* + * loadConfig + * + * Loads the stmf config from the SMF repository + * + */ +/*ARGSUSED*/ +static int +svcStart(int operandLen, char *operands[], cmdOptions_t *options, + void *args) +{ + int stmfRet; + int ret = 0; + (void) stmfLoadStmfProps(); + if ((stmfRet = stmfLoadConfig()) != STMF_STATUS_SUCCESS) { + switch (stmfRet) { + case STMF_ERROR_PERM: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("permission denied")); + break; + case STMF_ERROR_SERVICE_NOT_FOUND: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF service not found")); + break; + case STMF_ERROR_SERVICE_ONLINE: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF service must be offline")); + break; + default: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("Unable to load the configuration. " + "See /var/adm/messages for details")); + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("For information on reverting the " + "stmf:default instance to a previously " + "running configuration see the man page " + "for svccfg(1M)")); + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("After reverting the instance " + "you must clear the service maintenance " + "state. See the man page for svcadm(1M)")); + break; + } + return (1); + } + ret = online(); + return (ret); + +} + +/* + * online + * + * Onlines the stmf service + * + */ +/*ARGSUSED*/ +static int +online() +{ + int stmfRet; + int ret = 0; + stmfState state; + boolean_t serviceOnline = B_FALSE; + struct timespec rqtp; + + bzero(&rqtp, sizeof (rqtp)); + + rqtp.tv_nsec = TEN_MS_NANOSLEEP; + + if ((stmfRet = stmfOnline()) != STMF_STATUS_SUCCESS) { + switch (stmfRet) { + case STMF_ERROR_PERM: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("permission denied")); + break; + case STMF_ERROR_SERVICE_NOT_FOUND: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF service not found")); + break; + case STMF_ERROR_SERVICE_ONLINE: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("STMF service already online")); + break; + default: + (void) fprintf(stderr, "%s: %s\n", cmdName, + gettext("unable to online service")); + break; + } + return (1); + } + + /* wait for service online */ + while (!serviceOnline) { + stmfRet = stmfGetState(&state); + if (stmfRet != STMF_STATUS_SUCCESS) { + ret = 1; + break; + } + if (state.operationalState == STMF_SERVICE_STATE_ONLINE) { + serviceOnline = B_TRUE; + } else { + (void) nanosleep(&rqtp, NULL); + } + } + + return (ret); +} + + +/* + * input: + * execFullName - exec name of program (argv[0]) + * + * copied from usr/src/cmd/zoneadm/zoneadm.c in OS/Net + * (changed name to lowerCamelCase to keep consistent with this file) + * + * Returns: + * command name portion of execFullName + */ +static char * +getExecBasename(char *execFullname) +{ + char *lastSlash, *execBasename; + + /* guard against '/' at end of command invocation */ + for (;;) { + lastSlash = strrchr(execFullname, '/'); + if (lastSlash == NULL) { + execBasename = execFullname; + break; + } else { + execBasename = lastSlash + 1; + if (*execBasename == '\0') { + *lastSlash = '\0'; + continue; + } + break; + } + } + return (execBasename); +} + +int +main(int argc, char *argv[]) +{ + synTables_t synTables; + char versionString[VERSION_STRING_MAX_LEN]; + int ret; + int funcRet; + void *subcommandArgs = NULL; + + (void) setlocale(LC_ALL, ""); + /* set global command name */ + cmdName = getExecBasename(argv[0]); + + (void) snprintf(versionString, VERSION_STRING_MAX_LEN, "%s.%s", + VERSION_STRING_MAJOR, VERSION_STRING_MINOR); + synTables.versionString = versionString; + synTables.longOptionTbl = &longOptions[0]; + synTables.subCommandPropsTbl = &subcommands[0]; + + ret = cmdParse(argc, argv, synTables, subcommandArgs, &funcRet); + if (ret != 0) { + return (ret); + } + + return (funcRet); +} /* end main */ |