root/usr/src/cmd/stmfadm/stmfadm.c
/*
 * 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, 0, 0, NULL, 0}
};

/* 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++;
        }

        (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 */