/* * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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. (FC/SAS address) * iqn. (iSCSI iqn) * eui. (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("\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("\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("\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("\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("\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("\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("\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("\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("\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("\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("\n"); ret++; } done: (void) stmfFreeLuResource(hdl); return (ret); } /* * printLuProps * * Prints the properties for a logical unit * */ static void printLuProps(stmfLogicalUnitProperties *luProps) { (void) printf(PROPS_FORMAT, "Operational Status"); switch (luProps->status) { case STMF_LOGICAL_UNIT_ONLINE: (void) printf("Online"); break; case STMF_LOGICAL_UNIT_OFFLINE: (void) printf("Offline"); break; case STMF_LOGICAL_UNIT_ONLINING: (void) printf("Onlining"); break; case STMF_LOGICAL_UNIT_OFFLINING: (void) printf("Offlining"); break; case STMF_LOGICAL_UNIT_UNREGISTERED: (void) printf("unregistered"); (void) strncpy(luProps->providerName, "unregistered", sizeof (luProps->providerName)); break; default: (void) printf("unknown"); break; } (void) printf("\n"); (void) printf(PROPS_FORMAT, "Provider Name"); if (luProps->providerName[0] != 0) { (void) printf("%s", luProps->providerName); } else { (void) printf("unknown"); } (void) printf("\n"); (void) printf(PROPS_FORMAT, "Alias"); if (luProps->alias[0] != 0) { (void) printf("%s", luProps->alias); } else { (void) printf("-"); } (void) printf("\n"); } /* * printTargetProps * * Prints the properties for a target * */ static void printTargetProps(stmfTargetProperties *targetProps) { (void) printf(PROPS_FORMAT, "Operational Status"); switch (targetProps->status) { case STMF_TARGET_PORT_ONLINE: (void) printf("Online"); break; case STMF_TARGET_PORT_OFFLINE: (void) printf("Offline"); break; case STMF_TARGET_PORT_ONLINING: (void) printf("Onlining"); break; case STMF_TARGET_PORT_OFFLINING: (void) printf("Offlining"); break; default: (void) printf("unknown"); break; } (void) printf("\n"); (void) printf(PROPS_FORMAT, "Provider Name"); if (targetProps->providerName[0] != 0) { (void) printf("%s", targetProps->providerName); } (void) printf("\n"); (void) printf(PROPS_FORMAT, "Alias"); if (targetProps->alias[0] != 0) { (void) printf("%s", targetProps->alias); } else { (void) printf("-"); } (void) printf("\n"); (void) printf(PROPS_FORMAT, "Protocol"); switch (targetProps->protocol) { case STMF_PROTOCOL_FIBRE_CHANNEL: (void) printf("%s", "Fibre Channel"); break; case STMF_PROTOCOL_ISCSI: (void) printf("%s", "iSCSI"); break; case STMF_PROTOCOL_SRP: (void) printf("%s", "SRP"); break; case STMF_PROTOCOL_SAS: (void) printf("%s", "SAS"); break; default: (void) printf("%s", "unknown"); break; } (void) printf("\n"); } /* * printSessionProps * * Prints the session data * */ static void printSessionProps(stmfSessionList *sessionList) { int i; char *cTime; wchar_t initiator[STMF_IDENT_LENGTH + 1]; (void) printf(PROPS_FORMAT, "Sessions"); (void) printf("%d\n", sessionList->cnt); for (i = 0; i < sessionList->cnt; i++) { (void) mbstowcs(initiator, (char *)sessionList->session[i].initiator.ident, STMF_IDENT_LENGTH); initiator[STMF_IDENT_LENGTH] = 0; (void) printf(LVL3_FORMAT, "Initiator: "); (void) printf("%ws\n", initiator); (void) printf(LVL4_FORMAT, "Alias: "); if (sessionList->session[i].alias[0] != 0) { (void) printf("%s", sessionList->session[i].alias); } else { (void) printf("-"); } (void) printf("\n"); (void) printf(LVL4_FORMAT, "Logged in since: "); cTime = ctime(&(sessionList->session[i].creationTime)); if (cTime != NULL) { (void) printf("%s", cTime); } else { (void) printf("unknown\n"); } } } static int getStmfState(stmfState *state) { int ret; ret = stmfGetState(state); switch (ret) { case STMF_STATUS_SUCCESS: break; case STMF_ERROR_PERM: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("permission denied")); break; case STMF_ERROR_SERVICE_NOT_FOUND: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("STMF service not found")); break; case STMF_ERROR_BUSY: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("resource busy")); break; case STMF_ERROR_SERVICE_DATA_VERSION: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("STMF service version incorrect")); break; default: (void) fprintf(stderr, "%s: %s: %d\n", cmdName, gettext("unknown error"), ret); break; } return (ret); } /* * listStateFunc * * List the operational and config state of the stmf service * */ /*ARGSUSED*/ static int listStateFunc(int operandLen, char *operands[], cmdOptions_t *options, void *args) { int ret; stmfState state; boolean_t aluaEnabled; uint32_t node; if ((ret = getStmfState(&state)) != STMF_STATUS_SUCCESS) return (ret); (void) printf("%-18s: ", "Operational Status"); switch (state.operationalState) { case STMF_SERVICE_STATE_ONLINE: (void) printf("online"); break; case STMF_SERVICE_STATE_OFFLINE: (void) printf("offline"); break; case STMF_SERVICE_STATE_ONLINING: (void) printf("onlining"); break; case STMF_SERVICE_STATE_OFFLINING: (void) printf("offlining"); break; default: (void) printf("unknown"); break; } (void) printf("\n"); (void) printf("%-18s: ", "Config Status"); switch (state.configState) { case STMF_CONFIG_STATE_NONE: (void) printf("uninitialized"); break; case STMF_CONFIG_STATE_INIT: (void) printf("initializing"); break; case STMF_CONFIG_STATE_INIT_DONE: (void) printf("initialized"); break; default: (void) printf("unknown"); break; } (void) printf("\n"); ret = stmfGetAluaState(&aluaEnabled, &node); switch (ret) { case STMF_STATUS_SUCCESS: break; case STMF_ERROR_PERM: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("permission denied")); break; case STMF_ERROR_BUSY: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("resource busy")); break; default: (void) fprintf(stderr, "%s: %s: %d\n", cmdName, gettext("unknown error"), ret); break; } (void) printf("%-18s: ", "ALUA Status"); if (ret == STMF_STATUS_SUCCESS) { if (aluaEnabled == B_TRUE) { (void) printf("enabled"); } else { (void) printf("disabled"); } } else { (void) printf("unknown"); } (void) printf("\n"); (void) printf("%-18s: ", "ALUA Node"); if (ret == STMF_STATUS_SUCCESS) { (void) printf("%d", node); } else { (void) printf("unknown"); } (void) printf("\n"); return (ret); } /* * listTargetFunc * * list the targets and optionally their properties * */ /*ARGSUSED*/ static int listTargetFunc(int operandLen, char *operands[], cmdOptions_t *options, void *args) { cmdOptions_t *optionList = options; int ret = 0; int stmfRet; int i, j; int outerLoop; stmfSessionList *sessionList; stmfDevid devid; boolean_t operandEntered, found, verbose = B_FALSE; stmfDevidList *targetList; wchar_t targetIdent[STMF_IDENT_LENGTH + 1]; stmfTargetProperties targetProps; if ((stmfRet = stmfGetTargetList(&targetList)) != STMF_STATUS_SUCCESS) { switch (stmfRet) { case STMF_ERROR_NOT_FOUND: ret = 0; break; case STMF_ERROR_SERVICE_OFFLINE: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("STMF service offline")); break; case STMF_ERROR_BUSY: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("resource busy")); break; case STMF_ERROR_SERVICE_DATA_VERSION: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("STMF service version incorrect")); break; case STMF_ERROR_PERM: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("permission denied")); break; default: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("unknown error")); break; } return (1); } for (; optionList->optval; optionList++) { switch (optionList->optval) { case 'v': verbose = B_TRUE; break; } } if (operandLen > 0) { outerLoop = operandLen; operandEntered = B_TRUE; } else { outerLoop = 1; operandEntered = B_FALSE; } for (i = 0; i < outerLoop; i++) { if (operandEntered) { bzero(&devid, sizeof (devid)); (void) parseDevid(operands[i], &devid); } for (found = B_FALSE, j = 0; j < targetList->cnt; j++) { if (operandEntered) { if (bcmp(&devid, &(targetList->devid[j]), sizeof (devid)) == 0) { found = B_TRUE; } } if ((found && operandEntered) || !operandEntered) { (void) mbstowcs(targetIdent, (char *)targetList->devid[j].ident, STMF_IDENT_LENGTH); targetIdent[STMF_IDENT_LENGTH] = 0; (void) printf("Target: %ws\n", targetIdent); if (verbose) { stmfRet = stmfGetTargetProperties( &(targetList->devid[j]), &targetProps); if (stmfRet == STMF_STATUS_SUCCESS) { printTargetProps(&targetProps); } else { (void) fprintf(stderr, "%s:", cmdName); (void) fprintf(stderr, "%s\n", gettext(" get properties" " failed")); } stmfRet = stmfGetSessionList( &(targetList->devid[j]), &sessionList); if (stmfRet == STMF_STATUS_SUCCESS) { printSessionProps(sessionList); } else { (void) fprintf(stderr, "%s:", cmdName); (void) fprintf(stderr, "%s\n", gettext(" get session info" " failed")); } } if (found && operandEntered) { break; } } } if (operandEntered && !found) { (void) fprintf(stderr, "%s: %s: %s\n", cmdName, operands[i], "not found"); ret = 1; } } return (ret); } /* * listViewFunc * * list the view entries for the specified logical unit * */ /*ARGSUSED*/ static int listViewFunc(int operandLen, char *operands[], cmdOptions_t *options, void *args) { stmfViewEntryList *viewEntryList; stmfGuid inGuid; unsigned int guid[sizeof (stmfGuid)]; int ret = 0; int stmfRet; int i, j, outerLoop; boolean_t found = B_TRUE; boolean_t operandEntered; uint16_t outputLuNbr; wchar_t groupName[sizeof (stmfGroupName)]; char sGuid[GUID_INPUT + 1]; for (; options->optval; options++) { switch (options->optval) { case 'l': if (strlen(options->optarg) != GUID_INPUT) { (void) fprintf(stderr, "%s: %s: %s%d%s\n", cmdName, options->optarg, gettext("must be "), GUID_INPUT, gettext(" hexadecimal digits" " long")); return (1); } bcopy(options->optarg, sGuid, GUID_INPUT); break; default: (void) fprintf(stderr, "%s: %c: %s\n", cmdName, options->optval, gettext("unknown option")); return (1); } } if (operandLen > 0) { outerLoop = operandLen; operandEntered = B_TRUE; } else { outerLoop = 1; operandEntered = B_FALSE; } for (i = 0; i < 32; i++) sGuid[i] = tolower(sGuid[i]); sGuid[i] = 0; (void) sscanf(sGuid, "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x", &guid[0], &guid[1], &guid[2], &guid[3], &guid[4], &guid[5], &guid[6], &guid[7], &guid[8], &guid[9], &guid[10], &guid[11], &guid[12], &guid[13], &guid[14], &guid[15]); for (i = 0; i < sizeof (stmfGuid); i++) { inGuid.guid[i] = guid[i]; } if ((stmfRet = stmfGetViewEntryList(&inGuid, &viewEntryList)) != STMF_STATUS_SUCCESS) { switch (stmfRet) { case STMF_ERROR_BUSY: (void) fprintf(stderr, "%s: %s: %s\n", cmdName, sGuid, gettext("resource busy")); break; case STMF_ERROR_SERVICE_NOT_FOUND: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("STMF service not found")); break; case STMF_ERROR_SERVICE_DATA_VERSION: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("STMF service version incorrect")); break; case STMF_ERROR_PERM: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("permission denied")); break; default: (void) fprintf(stderr, "%s: %s: %s\n", cmdName, sGuid, gettext("unknown error")); break; } return (1); } if (viewEntryList->cnt == 0) { (void) fprintf(stderr, "%s: %s: %s\n", cmdName, sGuid, gettext("no views found")); return (1); } for (i = 0; i < outerLoop; i++) { for (found = B_FALSE, j = 0; j < viewEntryList->cnt; j++) { if (operandEntered) { if (atoi(operands[i]) == viewEntryList->ve[j].veIndex) { found = B_TRUE; } } if ((found && operandEntered) || !operandEntered) { (void) printf("View Entry: %d\n", viewEntryList->ve[j].veIndex); (void) printf(VIEW_FORMAT, "Host group"); if (viewEntryList->ve[j].allHosts) { (void) printf("All\n"); } else { (void) mbstowcs(groupName, viewEntryList->ve[j].hostGroup, sizeof (stmfGroupName) - 1); groupName[sizeof (stmfGroupName) - 1] = 0; (void) printf("%ws\n", groupName); } (void) printf(VIEW_FORMAT, "Target group"); if (viewEntryList->ve[j].allTargets) { (void) printf("All\n"); } else { (void) mbstowcs(groupName, viewEntryList->ve[j].targetGroup, sizeof (stmfGroupName) - 1); groupName[sizeof (stmfGroupName) - 1] = 0; (void) printf("%ws\n", groupName); } outputLuNbr = ((viewEntryList->ve[j].luNbr[0] & 0x3F) << 8) | viewEntryList->ve[j].luNbr[1]; (void) printf(VIEW_FORMAT, "LUN"); (void) printf("%d\n", outputLuNbr); if (found && operandEntered) { break; } } } if (operandEntered && !found) { (void) fprintf(stderr, "%s: %s, %s: %s\n", cmdName, sGuid, operands[i], gettext("not found")); ret = 1; } } return (ret); } /* * onlineOfflineLu * * Purpose: Online or offline a logical unit * * lu - logical unit to online or offline * * state - ONLINE_LU * OFFLINE_LU */ static int onlineOfflineLu(char *lu, int state) { char sGuid[GUID_INPUT + 1]; stmfGuid inGuid; unsigned int guid[sizeof (stmfGuid)]; int i; int ret = 0, stmfRet; stmfLogicalUnitProperties luProps; if (strlen(lu) != GUID_INPUT) { (void) fprintf(stderr, "%s: %s: %s %d %s\n", cmdName, lu, gettext("must be"), GUID_INPUT, gettext("hexadecimal digits long")); return (1); } bcopy(lu, sGuid, GUID_INPUT); for (i = 0; i < 32; i++) sGuid[i] = tolower(sGuid[i]); sGuid[i] = 0; (void) sscanf(sGuid, "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x", &guid[0], &guid[1], &guid[2], &guid[3], &guid[4], &guid[5], &guid[6], &guid[7], &guid[8], &guid[9], &guid[10], &guid[11], &guid[12], &guid[13], &guid[14], &guid[15]); for (i = 0; i < sizeof (stmfGuid); i++) { inGuid.guid[i] = guid[i]; } if (state == ONLINE_LU) { ret = stmfOnlineLogicalUnit(&inGuid); } else if (state == OFFLINE_LU) { ret = stmfOfflineLogicalUnit(&inGuid); } else { return (STMFADM_FAILURE); } if (ret != STMF_STATUS_SUCCESS) { switch (ret) { case STMF_ERROR_PERM: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("permission denied")); break; case STMF_ERROR_SERVICE_NOT_FOUND: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("STMF service not found")); break; case STMF_ERROR_BUSY: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("resource busy")); break; case STMF_ERROR_NOT_FOUND: (void) fprintf(stderr, "%s: %s: %s\n", cmdName, lu, gettext("not found")); break; case STMF_ERROR_SERVICE_DATA_VERSION: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("STMF service version incorrect")); break; default: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("unknown error")); break; } } else { struct timespec ts = {0}; unsigned int count = 0; uint32_t ret_state; ret_state = (state == ONLINE_LU) ? STMF_LOGICAL_UNIT_ONLINING : STMF_LOGICAL_UNIT_OFFLINING; ts.tv_nsec = DELAYED_EXEC_WAIT_INTERVAL; /* CONSTCOND */ while (1) { stmfRet = stmfGetLogicalUnitProperties(&inGuid, &luProps); if (stmfRet == STMF_STATUS_SUCCESS) ret_state = luProps.status; if ((state == ONLINE_LU && ret_state == STMF_LOGICAL_UNIT_ONLINE) || (state == OFFLINE_LU && ret_state == STMF_LOGICAL_UNIT_OFFLINE)) return (STMFADM_SUCCESS); if ((state == ONLINE_LU && ret_state == STMF_LOGICAL_UNIT_OFFLINE) || (state == OFFLINE_LU && ret_state == STMF_LOGICAL_UNIT_ONLINE)) return (STMFADM_FAILURE); if (++count == DELAYED_EXEC_WAIT_MAX) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("Logical Unit state change request " "submitted. Waiting for completion " "timed out")); return (STMFADM_FAILURE); } (void) nanosleep(&ts, NULL); } } return (STMFADM_FAILURE); } /* * onlineLuFunc * * Purpose: Online a logical unit * */ /*ARGSUSED*/ static int onlineLuFunc(int operandLen, char *operands[], cmdOptions_t *options, void *args) { int ret; stmfState state; ret = getStmfState(&state); if (ret != STMF_STATUS_SUCCESS) return (ret); if (state.operationalState == STMF_SERVICE_STATE_OFFLINE || state.operationalState == STMF_SERVICE_STATE_OFFLINING) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("STMF service is offline")); return (1); } return (onlineOfflineLu(operands[0], ONLINE_LU)); } /* * offlineLuFunc * * Purpose: Offline a logical unit * */ /*ARGSUSED*/ static int offlineLuFunc(int operandLen, char *operands[], cmdOptions_t *options, void *args) { return (onlineOfflineLu(operands[0], OFFLINE_LU)); } /* * onlineOfflineTarget * * Purpose: Online or offline a target * * target - target to online or offline * * state - ONLINE_TARGET * OFFLINE_TARGET */ static int onlineOfflineTarget(char *target, int state) { int ret = 0, stmfRet = 0; stmfDevid devid; stmfTargetProperties targetProps; if (parseDevid(target, &devid) != 0) { (void) fprintf(stderr, "%s: %s: %s\n", cmdName, target, gettext("unrecognized device id")); return (1); } if (state == ONLINE_TARGET) { ret = stmfOnlineTarget(&devid); } else if (state == OFFLINE_TARGET) { ret = stmfOfflineTarget(&devid); } else { return (STMFADM_FAILURE); } if (ret != STMF_STATUS_SUCCESS) { switch (ret) { case STMF_ERROR_PERM: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("permission denied")); break; case STMF_ERROR_SERVICE_NOT_FOUND: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("STMF service not found")); break; case STMF_ERROR_BUSY: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("resource busy")); break; case STMF_ERROR_NOT_FOUND: (void) fprintf(stderr, "%s: %s: %s\n", cmdName, target, gettext("not found")); break; case STMF_ERROR_SERVICE_DATA_VERSION: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("STMF service version incorrect")); break; default: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("unknown error")); break; } } else { struct timespec ts = {0}; unsigned int count = 0; uint32_t ret_state; ret_state = (state == ONLINE_TARGET) ? STMF_TARGET_PORT_ONLINING : STMF_TARGET_PORT_OFFLINING; ts.tv_nsec = DELAYED_EXEC_WAIT_INTERVAL; /* CONSTCOND */ while (1) { stmfRet = stmfGetTargetProperties(&devid, &targetProps); if (stmfRet == STMF_STATUS_SUCCESS) ret_state = targetProps.status; if ((state == ONLINE_TARGET && ret_state == STMF_TARGET_PORT_ONLINE) || (state == OFFLINE_TARGET && ret_state == STMF_TARGET_PORT_OFFLINE)) { return (STMFADM_SUCCESS); } if ((state == ONLINE_TARGET && ret_state == STMF_TARGET_PORT_OFFLINE) || (state == OFFLINE_TARGET && ret_state == STMF_TARGET_PORT_ONLINE)) { return (STMFADM_FAILURE); } if (++count == DELAYED_EXEC_WAIT_MAX) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("Target state change request " "submitted. Waiting for completion " "timed out.")); return (STMFADM_FAILURE); } (void) nanosleep(&ts, NULL); } } return (STMFADM_FAILURE); } /* * onlineTargetFunc * * Purpose: Online a target * */ /*ARGSUSED*/ static int onlineTargetFunc(int operandLen, char *operands[], cmdOptions_t *options, void *args) { int ret; stmfState state; ret = getStmfState(&state); if (ret != STMF_STATUS_SUCCESS) return (ret); if (state.operationalState == STMF_SERVICE_STATE_OFFLINE || state.operationalState == STMF_SERVICE_STATE_OFFLINING) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("STMF service is offline")); return (1); } return (onlineOfflineTarget(operands[0], ONLINE_TARGET)); } /* * offlineTargetFunc * * Purpose: Offline a target * */ /*ARGSUSED*/ static int offlineTargetFunc(int operandLen, char *operands[], cmdOptions_t *options, void *args) { return (onlineOfflineTarget(operands[0], OFFLINE_TARGET)); } /*ARGSUSED*/ static int removeHostGroupMemberFunc(int operandLen, char *operands[], cmdOptions_t *options, void *args) { int i; int ret = 0; int stmfRet; stmfGroupName groupName = {0}; stmfDevid devid; wchar_t groupNamePrint[sizeof (stmfGroupName)] = {0}; for (; options->optval; options++) { switch (options->optval) { case 'g': (void) mbstowcs(groupNamePrint, options->optarg, sizeof (stmfGroupName) - 1); bcopy(options->optarg, groupName, strlen(options->optarg)); break; default: (void) fprintf(stderr, "%s: %c: %s\n", cmdName, options->optval, gettext("unknown option")); return (1); } } for (i = 0; i < operandLen; i++) { if (parseDevid(operands[i], &devid) != 0) { (void) fprintf(stderr, "%s: %s: %s\n", cmdName, operands[i], gettext("unrecognized device id")); ret++; continue; } stmfRet = stmfRemoveFromHostGroup(&groupName, &devid); switch (stmfRet) { case STMF_STATUS_SUCCESS: break; case STMF_ERROR_MEMBER_NOT_FOUND: (void) fprintf(stderr, "%s: %s: %s\n", cmdName, operands[i], gettext("not found")); ret++; break; case STMF_ERROR_GROUP_NOT_FOUND: (void) fprintf(stderr, "%s: %ws: %s\n", cmdName, groupNamePrint, gettext("not found")); ret++; break; case STMF_ERROR_BUSY: (void) fprintf(stderr, "%s: %s: %s\n", cmdName, operands[i], "resource busy"); ret++; break; case STMF_ERROR_SERVICE_NOT_FOUND: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("STMF service not found")); ret++; break; case STMF_ERROR_SERVICE_DATA_VERSION: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("STMF service version incorrect")); ret++; break; case STMF_ERROR_PERM: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("permission denied")); ret++; break; default: (void) fprintf(stderr, "%s: %s: %s\n", cmdName, operands[i], gettext("unknown error")); ret++; break; } } return (ret); } /* * removeTargetGroupMemberFunc * * Removes one or more members from a target group * */ /*ARGSUSED*/ static int removeTargetGroupMemberFunc(int operandLen, char *operands[], cmdOptions_t *options, void *args) { int i; int ret = 0; int stmfRet; stmfGroupName groupName = {0}; stmfDevid devid; wchar_t groupNamePrint[sizeof (stmfGroupName)] = {0}; for (; options->optval; options++) { switch (options->optval) { case 'g': (void) mbstowcs(groupNamePrint, options->optarg, sizeof (stmfGroupName) - 1); bcopy(options->optarg, groupName, strlen(options->optarg)); break; default: (void) fprintf(stderr, "%s: %c: %s\n", cmdName, options->optval, gettext("unknown option")); return (1); } } for (i = 0; i < operandLen; i++) { if (parseDevid(operands[i], &devid) != 0) { (void) fprintf(stderr, "%s: %s: %s\n", cmdName, operands[i], gettext("unrecognized device id")); ret++; continue; } stmfRet = stmfRemoveFromTargetGroup(&groupName, &devid); switch (stmfRet) { case STMF_STATUS_SUCCESS: break; case STMF_ERROR_MEMBER_NOT_FOUND: (void) fprintf(stderr, "%s: %s: %s\n", cmdName, operands[i], gettext("not found")); ret++; break; case STMF_ERROR_GROUP_NOT_FOUND: (void) fprintf(stderr, "%s: %ws: %s\n", cmdName, groupNamePrint, gettext("not found")); ret++; break; case STMF_ERROR_BUSY: (void) fprintf(stderr, "%s: %s: %s\n", cmdName, operands[i], gettext("resource busy")); ret++; break; case STMF_ERROR_SERVICE_NOT_FOUND: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("STMF service not found")); ret++; break; case STMF_ERROR_PERM: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("permission denied")); ret++; break; case STMF_ERROR_SERVICE_DATA_VERSION: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("STMF service version incorrect")); ret++; break; case STMF_ERROR_TG_ONLINE: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("STMF target must be offline")); ret++; break; default: (void) fprintf(stderr, "%s: %s: %s\n", cmdName, operands[i], gettext("unknown error")); ret++; break; } } return (ret); } /* * removeViewFunc * * Removes one or more view entries from a logical unit * */ /*ARGSUSED*/ static int removeViewFunc(int operandLen, char *operands[], cmdOptions_t *options, void *args) { char sGuid[GUID_INPUT + 1]; stmfViewEntryList *viewEntryList; stmfGuid inGuid; uint32_t count; unsigned int guid[sizeof (stmfGuid)]; char *endPtr; uint32_t veNbr; int i; boolean_t all = B_FALSE; boolean_t luInput = B_FALSE; int ret = 0; int stmfRet; /* Note: 'l' is required */ for (; options->optval; options++) { switch (options->optval) { case 'l': if (strlen(options->optarg) != GUID_INPUT) { (void) fprintf(stderr, "%s: %s: %s %d %s\n", cmdName, options->optarg, gettext("must be"), GUID_INPUT, gettext("hexadecimal digits long")); return (1); } bcopy(options->optarg, sGuid, GUID_INPUT); luInput = B_TRUE; break; case 'a': /* removing all view entries for this GUID */ all = B_TRUE; break; default: (void) fprintf(stderr, "%s: %c: %s\n", cmdName, options->optval, "unknown option"); return (1); } } if (!all && operandLen == 0) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("no view entries specified")); return (1); } if (!luInput) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("logical unit (-l) not specified")); return (1); } for (i = 0; i < 32; i++) sGuid[i] = tolower(sGuid[i]); sGuid[i] = 0; (void) sscanf(sGuid, "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x", &guid[0], &guid[1], &guid[2], &guid[3], &guid[4], &guid[5], &guid[6], &guid[7], &guid[8], &guid[9], &guid[10], &guid[11], &guid[12], &guid[13], &guid[14], &guid[15]); for (i = 0; i < sizeof (stmfGuid); i++) { inGuid.guid[i] = guid[i]; } if ((stmfRet = stmfGetViewEntryList(&inGuid, &viewEntryList)) != STMF_STATUS_SUCCESS) { switch (stmfRet) { case STMF_ERROR_BUSY: (void) fprintf(stderr, "%s: %s: %s\n", cmdName, sGuid, gettext("resource busy")); break; case STMF_ERROR_SERVICE_NOT_FOUND: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("STMF service not found")); break; case STMF_ERROR_SERVICE_DATA_VERSION: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("STMF service version incorrect")); break; case STMF_ERROR_PERM: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("permission denied")); break; default: (void) fprintf(stderr, "%s: %s: %s\n", cmdName, sGuid, gettext("unknown error")); break; } return (1); } if (viewEntryList->cnt == 0) { (void) fprintf(stderr, "%s: %s: %s\n", cmdName, sGuid, gettext("no views found")); return (1); } if (all) { count = viewEntryList->cnt; } else { count = operandLen; } for (i = 0; i < count; i++) { if (all) { veNbr = viewEntryList->ve[i].veIndex; } else { endPtr = NULL; veNbr = strtol(operands[i], &endPtr, 10); if (endPtr && *endPtr != 0) { (void) fprintf(stderr, "%s: %s: %s\n", cmdName, operands[i], gettext("invalid input")); continue; } } stmfRet = stmfRemoveViewEntry(&inGuid, veNbr); switch (stmfRet) { case STMF_STATUS_SUCCESS: break; case STMF_ERROR_NOT_FOUND: (void) fprintf(stderr, "%s: %s: %d: %s\n", cmdName, sGuid, veNbr, gettext("not found")); ret++; break; case STMF_ERROR_BUSY: (void) fprintf(stderr, "%s: %s: %s\n", cmdName, sGuid, gettext("resource busy")); ret++; break; case STMF_ERROR_SERVICE_NOT_FOUND: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("STMF service not found")); ret++; break; case STMF_ERROR_CONFIG_NONE: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("STMF service is not initialized")); ret++; break; case STMF_ERROR_SERVICE_DATA_VERSION: (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("STMF service version incorrect")); ret++; break; default: (void) fprintf(stderr, "%s: %s, %d: %s", cmdName, sGuid, veNbr, gettext("unknown error")); ret++; break; } } return (ret); } /* * input: * execFullName - exec name of program (argv[0]) * * copied from usr/src/cmd/zoneadm/zoneadm.c in OS/Net * (changed name to lowerCamelCase to keep consistent with this file) * * Returns: * command name portion of execFullName */ static char * getExecBasename(char *execFullname) { char *lastSlash, *execBasename; /* guard against '/' at end of command invocation */ for (;;) { lastSlash = strrchr(execFullname, '/'); if (lastSlash == NULL) { execBasename = execFullname; break; } else { execBasename = lastSlash + 1; if (*execBasename == '\0') { *lastSlash = '\0'; continue; } break; } } return (execBasename); } int main(int argc, char *argv[]) { synTables_t synTables; char versionString[VERSION_STRING_MAX_LEN]; int ret; int funcRet; void *subcommandArgs = NULL; (void) setlocale(LC_ALL, ""); (void) textdomain(TEXT_DOMAIN); /* set global command name */ cmdName = getExecBasename(argv[0]); (void) snprintf(versionString, VERSION_STRING_MAX_LEN, "%s.%s", VERSION_STRING_MAJOR, VERSION_STRING_MINOR); synTables.versionString = versionString; synTables.longOptionTbl = &longOptions[0]; synTables.subCommandPropsTbl = &subcommands[0]; ret = cmdParse(argc, argv, synTables, subcommandArgs, &funcRet); if (ret != 0) { return (ret); } return (funcRet); } /* end main */