Blob Blame History Raw
#!/bin/bash
verrel=1.1
# =============================================================================
#
# Bash script to provide access to z/VM System Management functions.
# Written by Leland Lucius one fun week in the snowy winter of 2011.
#
# Released under the Artistic License 2.0.  Full license text can be found at:
#
#   http://opensource.org/licenses/artistic-license-2.0
#
# Read below for requirements, but one of my goals when writing it was to try
# and use as few external programs as possible.  Not for any technical reasons,
# I just wanted to see if I could do it mostly with bash.
#
# You can use "smaclient smiucv" to build the embedded IUCV helper utility.  This
# will allow you to use IUCV instead of TCP/IP as the transport between smaclient
# and the SMAPI servers.  You must install gcc for the build, but do not need
# it once built.  The helper will be built in the same directory where smaclient
# is located.
#
# When using smaclient, you need to provide the destination host, authorized
# userid and password.  These values can be specified in four locations:
#
#   1)  /etc/smaclient.conf
#   2)  ~/.smaclient
#   3)  environment variables SMHOST, SMUSER, and SMPASS
#   4)  arguments to smaclient
#
# For /etc/smaclient.conf and ~/.smaclient, you can specify any or all of the
# following variables:
#
#   smhost
#       For TCP/IP, specify the SMAPI host and port number.  The format is:
#           hostname/portnumber
#       For IUCV, specify the literal "IUCV".
#
#   smuser
#       For TCP/IP, specify the userid authorized to use SMAPPI.
#       For IUCV, there's no need to specify this, but it doesn't hurt.
#
#   smpass
#       For TCP/IP, specify the corresponding password.
#       For IUCV, there's no need to specify this, but it doesn't hurt.
#
# An example ~/.smaclient:
#
#   smhost="myzvm/44444"
#   smuser="vsmuser"
#   smpass="secret"
#
# Every smaclient function requires the smhost, smuser, and smpass as described
# above.  In addition, the "target" option is also required and its value
# should be as decribed in the System Management manual.
#
# An example invocation:
#
#   smaclient Image_Active_Configuration_Query -T guestnm
#
# produces:
#
#   Memory size: 1
#   Memory units: 3 (GB)
#   Share type: 1 (Relative)
#   Share value: 100
#   CPU count: 1
#
#   CPUs:
#     Address: 0
#     ID: FF0D111120978000
#     Status: 1 (Base)
#
#   Devices:
#     Device 0009 is 1 (CONS)
#     Device 000C is 2 (RDR)
#     Device 000D is 3 (PUN)
#     Device 000E is 4 (PRT)
#     Device 1000 is 5 (DASD)
#     Device 1001 is 5 (DASD)
#     Device 1002 is 5 (DASD)
#     Device 1003 is 5 (DASD)
#     Device 1004 is 5 (DASD)
#     Device 2000 is 5 (DASD)
#
# To get a list of supported SMAPI functions, enter "smaclient" without any
# arguments.
#
# Notes and warnings:
#
#   I have not tested all of the functions completely as I simply don't use
#   them.  If you find something amiss, feel free to let me know and I'll see
#   about fixing it.
#
#   Use at your own risk.  I wrote it, but by using it, you have determined
#   that the risk is acceptable and I will not be held responsible.
#
#   This script doesn't attempt to validate option values.  That is left up to
#   the SMAPI routines.  So, you'll have to consult the "Systems Management
#   Application Programming" book (SC24-6234 or equivalent).  An example error
#   where the message isn't very friendly:
#
#     smaclient Virtual_Network_Vswitch_Delete -D -T smuser -s tswitch -u 1234
#     Syntax error in parameter 12: Numeric value greater than maximum
#
#   In this case, paramter 12 is the update_system_config_indicator as it is
#   the 12th paramter listed in the Input Paramters for this function.
#
# =============================================================================

# =============================================================================
#
# Requirements:
#
#   bash        built with support for "/dev/tcp" if using SMAPI TCP interface 
#   dd          from "coreutils" package
#   tr          from "coreutils" package
#   getopt      from "util-linux" package
#   xxd         from "vim" package
#   smiucv      if you want to use the SMAPI IUCV interface
#
#   Some SMAPI functions require OPTION DIAG88 in the VSMWORKn VMs directory
#   entries.
#
# Global variables used:
#
#   smfile      SMAPI file descriptor
#   smhost      SMAPI host name (or IP) and port number (host/port) or "IUCV"
#   smuser      SMAPI authorized userid
#   smpass      SMAPI authorized password
#   smfunc      SMAPI function name
#   smtarg      SMAPI target identifier (guest or auth list entry name)
#   resp        SMAPI response in hexadecimal representation
#   reqid1      SMAPI request id from immediate response
#   resplen     SMAPI response length
#   reqid2      SMAPI request id from response
#   retc        SMAPI return code from response
#   reas        SMAPI reason code from response
#   debug       Set to "yes" to enable debugging code
# 
# Parsing related:
#
#   desc        Description of function
#   required    Required options for usage display and parameter checking
#   optional    Optional options for usage display
#   opts        Short options for passing to "getopt"
#   optl        Long options for passing to "getopt"
#   usesparms   Set to "r" for required positional parms, "o" for optional
#               positional parms, and "n" for no positional parms
#
# =============================================================================

# =============================================================================
# Display a message based on the SMAPI return code, reason code, and function
#
# Note:  I copied the messages from SC24-6234-00.  If this is a problem, I will
#        remove them and just go with a generic type of message.
# =============================================================================
function showerror
{
    # Define local variables
    local m pp rr

    case "${retc}_${reas}_${smfunc}" in

        # RC_OK
        0_0_Query_API_Functional_Level) m="The API functional level is z/VM V5.3" ;;
        0_0_*) m="Request successful" ;;
        0_4_Image_CPU_Define) m="CPU defined, but CPU affinity suppressed" ;;
        0_4_Shared_Memory_Create) m="Segment was created, but specified userid could not be found to give RSTD access" ;;
        0_4_Shared_Memory_Replace) m="Segment was replaced, but specified userid could not be found to give RSTD access" ;;
        0_8_*) m="Request successful; object directory offline" ;;
        0_12_Name_List_Add) m="Request successful; new list created" ;;
        0_12_Shared_Memory_*) m="Request successful; NAMESAVE statement already exists in directory" ;;
        0_12_*) m="Image not active" ;;
        0_16_*) m="Request successful; no more entries, list destroyed" ;;
        0_20_Directory_Manager_Local_Tag_Set_DM) m="Use not allowed by exit routine." ;;
        0_20_*) m="No output; user(s) not authorized for specified segment" ;;
        0_24_*) m="Request successful; virtual network LAN removed" ;;
        0_28_Asynchronous_Notification_*) m="No matching entries found" ;;
        0_28_Image_SCSI_Characteristics_Query_DM) m="There are no SCSI characteristics for this image." ;;
        0_28_Shared_Memory_Query) m="Query request successful, but segment not found" ;;
        0_28_*) m="No matching entries found.  Return buffer is empty." ;;
        0_32_*) m="Name was not in list" ;;
        0_36_*) m="Name is already in list" ;;
        0_40_*) m="Request successful; new virtual switch created" ;;
        0_44_*) m="Request successful; virtual switch removed" ;;
        0_66_*) m="Multiple DEFINE or MODIFY statements are erased in system config" ;;
        0_100_*) m="Asynchronous operation succeeded" ;;
        0_104_*) m="Asynchronous operation in progress" ;;
        0_108_*) m="Asynchronous operation failed" ;;
        0_540_*) m="The API functional level is z/VM V5.4" ;;
        0_610_*) m="The API functional level is z/VM V6.1" ;;
        0_611_*) m="The API functional level is the updated z/VM V6.1 SPE release" ;;
        0_612_*) m="The API functional level is the updated z/VM V6.1 SPE release with APAR VM64917 applied" ;;
        0_620_*) m="The API functional level is z/VM V6.2" ;;
        0_621_*) m="The API functional level is z/VM V6.2 with added support for network monitoring metrics and HiperSockets Vswitch bridge" ;;

        # RC_WNG
        4_4_*) m="Request does not exist" ;;
        4_5_*) m="Unrestricted LAN" ;;
        4_6_*) m="No authorized users" ;;
        4_8_*) m="Device does not exist" ;;
        4_28_*) m="Return buffer is empty" ;;
        4_3000_*) m="VMRELOCATE TEST error" ;;
        4_3001_*) m="No active relocations found" ;;
        4_3008_*) m="System is not a member of an SSI cluster" ;;
        4_3009_*) m="System was IPLed with theREPAIR IPL parameter" ;;

        # RC_ERR
        8_2_*) m="Invalid access user" ;;
        8_3_*) m="Invalid op value" ;;
        8_4_Virtual_Network_LAN_Access) m="Invalid promiscuity value" ;;
        8_4_Image_Definition_Delete_DM) m="Directory entry to be deleted not found" ;;
        8_4_System_Performance_Threshold_Enable) m="Performance monitoring virtual server not found" ;;
        8_8_*) m="Device does not exist" ;;
        8_10_*) m="Device not available for attachment" ;;
        8_12_Page_or_Spool_Volume_Add) m="Device not a volume" ;;
        8_12_VMRELOCATE_Image_Attributes) m="target_identifier not logged on" ;;
        8_13_*) m="Match key length does not match the match key specified" ;;
        8_14_*) m="Free modes not available" ;;
        8_18_*) m="Volume does not exist" ;;
        8_19_*) m="Volume is CP owned and cannot be used" ;;
        8_20_Image_Volume_Share) m="Volume is CP system and cannot be used" ;;
        8_20_Page_or_Spool_Volume_Add) m="Volume label already CP_OWNED on this system or in this system's configuration" ;;
        8_24_Page_or_Spool_Volume_Add) m="Error linking parm disk" ;;
        8_24_Image_Definition_Async_Updates) m="Unable to write ASYNCH file" ;;
        8_28_*) m="Parm disk not RW" ;;
        8_32_*) m="System configuration not found on parm disk" ;;
        8_34_*) m="System configuration has bad data" ;;
        8_36_*) m="Specified length is not valid" ;;
        8_38_*) m="CP disk modes not available" ;;
        8_40_*) m="Parm disk is full" ;;
        8_42_*) m="Parm disk access not allowed" ;;
        8_44_*) m="No link password for parm disk was provided" ;;
        8_46_*) m="Parm disk password is incorrect" ;;
        8_48_*) m="Parm disk is not in server's user directory" ;;
        8_50_*) m="Error with CPRELEASE of parm disk" ;;
        8_52_*) m="Error in access of CPACCESS parm disk" ;;
        8_241_*) m="Internal communication error" ;;
        8_1821_*) m="Relocation domain domain_name does not exist" ;;
        8_1822_*) m="User target_identifier cannot be set to a new relocation domain domain_name without the FORCE ARCHITECTURE option" ;;
        8_1823_*) m="A multiconfiguration virtual machine cannot be relocated" ;;
        8_2783_*) m="Invalid LAN ID" ;;
        8_2795_*) m="Invalid LAN parameter" ;;
        8_3000_*) m="VMRELOCATE MOVE error" ;;
        8_3002_*) m="Invalid parameter name" ;;
        8_3003_*) m="Invalid parameter operand" ;;
        8_3004_*) m="Required parameter missing" ;;
        8_3006_*) m="SSI is not in a STABLE state" ;;
        8_3007_*) m="The volume ID or slot is not available on all systems in the SSI" ;;
        8_3008_*) m="System is not a member of an SSI cluster" ;;
        8_3010_*) m="VMRELOCATE modify error" ;;
        8_3011_*) m="No unique CP_OWNED slot available on system and in System Config" ;;
        8_3012_*) m="Volume does not exist" ;;
        8_3013_*) m="Volume is offline" ;;
        8_3014_*) m="Volume does not support sharing" ;;
        8_*) m="VMRELOCATE_Status returned an error. The RS nnnn represents the HCPnnnn message." ;;

        # RCERR_SYNTAX
        24_13_*) m="Metadata entry name value length exceeds allowable length (1024)" ;;
        24_19_*) m="Parameter value not recognized" ;;
        24_*)
            pp=$(( reas / 100 ))
            rr=$(( reas % 100 ))
            case "${rr}" in
                1) m="First character of listname is a colon \":\"" ;;
                10) m="Characters not \"0123456789\"" ;;
                11) m="Unsupported function" ;;
                13) m="Length is greater than maximum or exceeds total length" ;;
                14) m="Length is less than minimum" ;;
                15) m="Numeric value less than minimum or null value encountered" ;;
                16) m="Characters not \"0123456789ABCDEF\"" ;;
                17) m="Characters not \"0123456789ABCDEF-\"" ;;
                18) m="Numeric value greater than maximum" ;;
                19) m="Unrecognized value" ;;
                23) m="Conflicting parameter specified" ;;
                24) m="Unspecified required parameter" ;;
                25) m="Extraneous parameter specified" ;;
                26) m="Characters not \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\"" ;;
                36) m="Characters not \"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\"" ;;
                37) m="Characters not \"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-\"" ;;
                42) m="Characters not \"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@#$+-:\"" ;;
                43) m="Characters not \"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@#$+-:_\"" ;;
                44) m="Characters not \"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@#$+-:_=\"" ;;
                45) m="Invalid SFS syntax" ;;
                88) m="Unexpected end of data" ;;
                99) m="Non-breaking characters: non-blank, non-null, non-delete, non-line-end, non-carriage return, non-line-feed" ;;
                *) m="Unknown syntax error: ${rr}" ;;
            esac

            m="Syntax error in parameter ${pp}: ${m}"
        ;;

        # RCERR_FILE_NOT_FOUND
        28_0_*) m="Namelist file not found" ;;

        # RCERR_FILE_CANNOT_BE_UPDATED
        36_0_*) m="Namelist file cannot be updated" ;;

        # RCERR_AUTH
        100_0_*) m="Request is authorized" ;;
        100_4_*) m="Authorization deferred to directory manager" ;;
        100_8_*) m="Request not authorized by external security manager" ;;
        100_12_*) m="Request not authorized by directory manager" ;;
        100_16_*) m="Request not authorized by server" ;;
        100_20_*) m="Target image not authorized for function" ;;

        # RCERR_NO_AUTHFILE
        104_0_*) m="Authorization file not found" ;;

        # RCERR_AUTHFILE_RO
        106_0_*) m="Authorization file cannot be updated" ;;

        # RCERR_EXISTS
        108_0_*) m="Authorization file entry already exists" ;;

        # RCERR_NO_ENTRY
        112_0_*) m="Authorization file entry does not exist" ;;

        # RCERR_USER_PW_BAD
        120_0_*) m="Authentication error; userid or password not valid" ;;

        # RCERR_PW_EXPIRED
        128_0_*) m="Authentication error; password expired" ;;

        # RCERR_ESM
        188_*) m="Internal server error; ESM failure: ${reas}" ;;

        # RCERR_PW_CHECK
        192_*) m="Internal server error; cannot authenticate user/password: ${reas}" ;;

        # RCERR_IMAGEOP
        200_0_*) m="Image operation error" ;;
        200_4_*) m="Image not found" ;;
        200_8_*) m="Image already active" ;;
        200_12_*) m="Image not active" ;;
        200_16_*) m="Image being deactivated" ;;
        200_24_*) m="List not found" ;;
        200_28_*) m="Some images in list not activated" ;;
        200_32_*) m="Some images in list not deactivated" ;;
        200_36_Image_Recycle) m="Some images in list not recycled" ;;
        200_36_Image_Deactivate) m="Specified time results in interval greater than max allowed" ;;

        # RCERR_IMAGEDEVU
        204_0_*) m="Image device usage error" ;;
        204_2_*) m="Input image device number not valid" ;;
        204_4_*) m="Image device already exists" ;;
        204_8_*) m="Image device does not exist" ;;
        204_12_*) m="Image device is busy" ;;
        204_16_*) m="Image device is not available" ;;
        204_20_*) m="Image device already connected" ;;
        204_24_*) m="Image device is not a tape drive, or cannot be assigned/reset" ;;
        204_28_*) m="Image device is not a shared DASD" ;;
        204_28_Image_Device_Reset) m="Image device is not a shared DASD" ;;
        204_28_*) m="Image device already defined as type other than network adapter" ;;
        204_32_*) m="Image device is not a reserved DASD" ;;
        204_36_*) m="I/O error on image device" ;;
        204_40_*) m="Virtual Network Adapter not deleted" ;;
        204_44_*) m="DASD volume cannot be deleted" ;;
        204_48_*) m="Virtual network adapter is already disconnected" ;;

        # RCERR_IMAGEDISKU
        208_0_*) m="Image disk usage error" ;;
        208_4_*) m="Image disk already in use" ;;
        208_8_*) m="Image disk not in use" ;;
        208_12_*) m="Image disk not available" ;;
        208_16_*) m="Image disk cannot be shared as requested" ;;
        208_20_*) m="Image disk shared in different mode" ;;
        208_28_*) m="Image disk does not have" ;;
        208_32_*) m="Incorrect password specified for image disk" ;;
        208_36_*) m="Image disk does not exist" ;;
        208_1157_*) m="MDISK DEVNO parameter requires the device to be a free volume" ;;

        # RCERR_IMAGECONN
        212_0_*) m="Active image connectivity error" ;;
        212_4_*) m="Partner image not found" ;;
        212_8_Virtual_Network_Adapter_Query) m="Adapter does not exist" ;;
        212_8_*) m="Image not authorized to connect" ;;
        212_12_*) m="LAN does not exist" ;;
        212_16_*) m="LAN owner LAN name does not exist" ;;
        212_20_*) m="Requested LAN owner not active" ;;
        212_24_*) m="LAN name already exists with different attributes" ;;
        212_28_*) m="Image device not correct type for requested connection" ;;
        212_32_*) m="Image device not connected to LAN" ;;
        212_36_*) m="Virtual switch already exists" ;;
        212_40_*) m="Virtual switch does not exist" ;;
        212_44_*) m="Image already authorized" ;;
        212_48_*) m="VLAN does not exist" ;;
        212_52_*) m="Maximum number of connections reached" ;;
        212_96_*) m="Unknown reason" ;;

        # RCERR_IMAGECPU
        216_2_*) m="Input virtual CPU value out range" ;;
        216_4_*) m="Virtual CPU not found" ;;
        216_12_*) m="Image not active" ;;
        216_24_*) m="Virtual CPU already exists" ;;
        216_28_*) m="Virtual CPU address beyond allowable range defined in directory" ;;
        216_40_*) m="Processor type not supported on your system" ;;

        # RCERR_VOLUME
        300_0_*) m="Image volume operation successful" ;;
        300_8_*) m="Device not found" ;;
        300_10_*) m="Device not available for attachment" ;;
        300_12_*) m="Device not a volume" ;;
        300_14_*) m="Free modes not available" ;;
        300_16_*) m="Device vary online failed" ;;
        300_18_*) m="Volume label not found in system configuration" ;;
        300_20_*) m="Volume label already in system configuration" ;;
        300_22_*) m="Parm disks 1 and 2 are same" ;;
        300_24_*) m="Error linking parm disk (1 or 2)" ;;
        300_28_*) m="Parm disk (1 or 2) not RW" ;;
        300_32_*) m="System configuration not found on parm disk 1" ;;
        300_34_*) m="System configuration has bad data" ;;
        300_36_*) m="Syntax errors updating system configuration file" ;;
        300_38_*) m="CP disk modes not available" ;;
        300_40_*) m="Parm disk (1 or 2) is full" ;;
        300_42_*) m="Parm disk (1 or 2) access not allowed" ;;
        300_44_*) m="Parm disk (1 or 2) PW not supplied" ;;
        300_46_*) m="Parm disk (1 or 2) PW is incorrect" ;;
        300_48_*) m="Parm disk (1 or 2) is not in server's user directory" ;;
        300_50_*) m="Error in release of CPRELEASE parm disk (1 or 2)" ;;
        300_52_*) m="Error in access of CPACCESS parm disk (1 or 2)" ;;

        # RCERR_INTERNAL
        396_0_*) m="Internal system error" ;;
        396_*) m=$(printf "Internal system error - product-specific return code (try HELP HCP%03dE in CMS)\n" ${reas}) ;;

        # RCERR_IMAGEDEF
        400_0_*) m="Image or profile definition error" ;;
        400_4_*) m="Image or profile definition not found" ;;
        400_8_*) m="Image or profile name already defined" ;;
        400_12_*) m="Image or profile definition is locked" ;;
        400_16_*) m="Image or profile definition cannot be deleted" ;;
        400_20_*) m="Image prototype is not defined" ;;
        400_24_*) m="Image or profile definition is not locked" ;;
        400_40_*) m="Multiple user statements" ;;

        # RCERR_IMAGEDEVD
        404_0_*) m="Image device definition error" ;;
        404_4_*) m="Image device already defined" ;;
        404_8_*) m="Image device not defined" ;;
        404_12_*) m="Image device is locked" ;;
        404_24_Image_Disk_Copy_DM) m="Image device type not same as source" ;;
        404_24_*) m="Image device is not locked" ;;
        404_28_*) m="Image device size not same as source" ;;

        # RCERR_IMAGEDISKD
        408_0_*) m="Image disk definition error" ;;
        408_4_*) m="Image disk already defined" ;;
        408_8_*) m="Image disk not defined" ;;
        408_12_*) m="Image device is locked" ;;
        408_16_*) m="Image disk sharing not allowed by target image definition" ;;
        408_24_*) m="Requested image disk space not available" ;;
        408_28_*) m="Image disk does not have required password" ;;
        408_32_*) m="Incorrect password specified for image disk" ;;

        # RCERR_IMAGECONND
        412_0_*) m="Image connectivity definition error" ;;
        412_4_*) m="Partner image not found" ;;
        412_16_*) m="Parameters do not match existing directory statement" ;;
        412_28_*) m="Image device not correct type for requested connection" ;;

        # RCERR_PROTODEF
        416_0_*) m="Prototype definition error" ;;
        416_4_*) m="Prototype definition not found" ;;
        416_8_*) m="Prototype already exists" ;;

        # RC_DASD_DM
        420_4_*) m="Group, region, or volume name is already defined" ;;
        420_8_*) m="Group, region, or volume name is not defined" ;;
        420_12_*) m="Region name is not included in the group" ;;
        420_36_*) m="The requested volume is offline or is not a DASD device" ;;

        # RCERR_SEGMENT_DM
        424_4_*) m="Namesave statement already exists" ;;
        424_8_*) m="Segment name not found" ;;

        # RCERR_NOTIFY
        428_4_*) m="Duplicate subscription" ;;
        428_8_*) m="No matching entries" ;;

        # RCERR_TAG
        432_4_*) m="Tag name is already defined" ;;
        432_8_*) m="Tag name is not defined" ;;
        432_12_*) m="Tag ordinal is already defined" ;;
        432_16_*) m="Tag is in use in one or more directory entries, can not be revoked" ;;
        432_20_*) m="Use not allowed by exit routine" ;;

        # RCERR_PROFILED
        436_4_*) m="Profile included not found" ;;
        436_40_*) m="Multiple profiles included" ;;

        # RCERR_POLICY_PW
        444_0_*) m="Password policy error" ;;
        444_4_*) m="Password too long" ;;
        444_8_*) m="Password too short" ;;
        444_12_*) m="Password content does not match policy" ;;

        # RCERR_POLICY_ACCT
        448_0_*) m="Account policy error" ;;
        448_4_*) m="Account number too long" ;;
        448_8_*) m="Account number too short" ;;
        448_12_*) m="Account number content does not match policy" ;;

        # RCERR_TASK
        452_4_*) m="Task not found" ;;

        # RCERR_SCSI
        456_4_*) m="LOADDEV statement not found" ;;

        # RC_IPL_DM
        460_4_*) m="Image does not have an IPL statement" ;;

        # RCERR_DM
        500_0_*) m="Directory manager request could not be completed" ;;
        500_4_*) m="Directory manager is not accepting updates" ;;
        500_8_*) m="Directory manager is not available" ;;
        500_12_*) m="Directory manager has been disabled" ;;
        500_16_*) m="Directory manager was interrupted" ;;
        500_20_*) m="Password format not supported" ;;

        # RCERR_LIST_DM
        504_*) m="Target ID not added - product-specific return code: ${reas}" ;;

        # RCERR_CPU_DM
        520_24_*) m="Only one base CPU may be defined" ;;
        520_28_*) m="Input virtual CPU value out of range" ;;
        520_30_*) m="CPU not found" ;;
        520_32_*) m="Maximum allowable number of virtual CPUs is exceeded" ;;
        520_45_*) m="The Cryptographic Coprocessor Facility (CCF) is not installed on this system" ;;
        520_2826_*) m="SCPDATA contains invalid UTF-8 data" ;;

        # RCERR_ASYNC_DM
        592_0_*) m="Asynchronous operation started" ;;
        592_*) m="Asynchronous operation started - product-specific asynchronous operation ID: ${reas}" ;;

        # RCERR_INTERNAL_DM
        596_*) m="Internal directory manager error - product-specific return code: ${reas}" ;;

        # RCERR_SHSTOR
        600_8_*) m="Bad page range" ;;
        600_12_*) m="User not logged on" ;;
        600_16_*) m="Could not save segment" ;;
        600_20_*) m="Not authorized to issue internal system command or is not authorized for RSTD segment" ;;
        600_24_*) m="Conflicting parameters" ;;
        600_28_*) m="Segment not found or does not exist" ;;
        600_299_*) m="Class S (skeleton) segment file already exists" ;;

        # RCERR_VIRTUALNETWORKD
        620_14_*) m="Free modes not available" ;;
        620_22_*) m="System config parm disks 1 and 2 are same" ;;
        620_24_*) m="Error linking parm disk (1 or 2)" ;;
        620_28_*) m="Parm disk (1 or 2) not RW" ;;
        620_32_*) m="System config not found on parm disk 1" ;;
        620_34_*) m="System config has bad data" ;;
        620_36_*) m="Syntax errors updating system config" ;;
        620_38_*) m="CP disk modes not available" ;;
        620_40_*) m="Parm disk (1 or 2) is full" ;;
        620_42_*) m="Parm disk (1 or 2) access not allowed" ;;
        620_44_*) m="Parm disk (1 or 2) PW not supplied" ;;
        620_46_*) m="Parm disk (1 or 2) PW is incorrect" ;;
        620_48_*) m="Parm disk (1 or 2) is not in server's directory" ;;
        620_50_*) m="Error in release of CPRELEASE parm disk (1 or 2)" ;;
        620_52_*) m="Error in access of CPACCESS parm disk (1 or 2)" ;;
        620_54_*) m="DEFINE VSWITCH statement already exists in system config" ;;
        620_58_*) m="MODIFY VSWITCH statement to userid not found in system config" ;;
        620_60_*) m="DEFINE VSWITCH statement does not exist in system config" ;;
        620_62_*) m="DEFINE operands conflict, cannot be updated in the system config" ;;
        620_64_*) m="Multiple DEFINE or MODIFY statements found in system config" ;;

        # RCERR_VMRM
        800_8_*) m="No measurement data exists" ;;
        800_12_*) m="Error in update buffer or processing syntax check" ;;
        800_16_*) m="Not authorized to access file" ;;
        800_24_*) m="Error writing file(s) to directory" ;;
        800_28_*) m="Specified configuration file not found" ;;
        800_32_*) m="Internal error processing updates" ;;

        # RCERR_SERVER
        900_4_*) m="Custom exec not found" ;;
        900_8_*) m="Worker server was not found" ;;
        900_12_*) m="Specified function does not exist" ;;
        900_16_*) m="Internal server error - DMSSIPTS entry for function is invalid" ;;
        900_20_*) m="Total length does not match the specified input data" ;;
        900_24_*) m="Error accessing SFS directory" ;;
        900_28_*) m="Internal server error - error with format of function output" ;;
        900_32_*) m="Internal server error - response from worker server was not valid" ;;
        900_36_*) m="Specified length was not valid, out of valid server data range" ;;
        900_40_*) m="Internal server socket error" ;;
        900_68_*) m="Unable to access LOHCOST server" ;;
        900_99_*) m="A system change occurred during the API call - reissue the API call to obtain the data." ;;

        *) m="Unrecognized return code ${retc} and reason code ${reas} from ${smfunc}" ;;
    esac

    echo -e "${m}"
}

# =============================================================================
# Check for successful completion, show message if needed, and bail if error
# =============================================================================
function checkandfail
{
    if [ ${retc} -ne 0 -o ${reas} -ne 0 ]
    then
        showerror
        exit 1
    fi
}

# =============================================================================
# Remove embedded blanks
# =============================================================================
function removeblanks
{
    IFS=""
    echo "${*}"
}

# =============================================================================
# Retrieve an 8 byte int from the SMAPI response buffer
# =============================================================================
function get8
{
    # Make sure there's enough left in the response buffer
    if [ ${#resp} -lt 16 ]
    then
        echo "get8 called with insufficient data"
        exit 1
    fi

    # Grab the next 8 bytes (16 hex digits)
    eval ${1}=$(( 16#${resp:0:16} ))

    # And remove them from the response buffer
    resp="${resp:16}"
}

# =============================================================================
# Retrieve a 4 byte int from the SMAPI response buffer
# =============================================================================
function get4
{
    # Make sure there's enough left in the response buffer
    if [ ${#resp} -lt 8 ]
    then
        echo "get4 called with insufficient data"
        exit 1
    fi

    # Grab the next 4 bytes (8 hex digits)
    eval ${1}=$(( 16#${resp:0:8} ))

    # And remove them from the response buffer
    resp="${resp:8}"
}

# =============================================================================
# Retrieve a 1 byte value from the SMAPI response buffer
# =============================================================================
function get1
{
    # Make sure there's enough left in the response buffer
    if [ ${#resp} -lt 2 ]
    then
        echo "get1 called with insufficient data"
        exit 1
    fi

    # Grab the next byte (2 hex digits)
    eval ${1}=$(( 16#${resp:0:2} ))

    # And remove them from the response buffer
    resp="${resp:2}"
}

# =============================================================================
# Retrieve characters from the SMAPI response buffer
#
# The variable name that will receive the characters must be passed when
# calling this function.
# =============================================================================
function getchars
{
    # Define local variables
    local len

    # Convert length to hex length
    len=$(( $1 * 2 ))

    # Set the variable to an empty string if the length is zero
    if [ ${len} -eq 0 ]
    then
        eval ${2}=""
        return
    fi

    # Make sure there's enough left in the response buffer
    if [ ${#resp} -lt ${len} ]
    then
        echo "getchars called with insufficient data"
        exit 1
    fi

    # Grab the string and convert back to character
    eval ${2}='"$(echo -n ${resp:0:len} | xxd -r -p)"'

    # And remove it from the response buffer
    resp="${resp:len}"
}

# =============================================================================
# Retrieve a string from the SMAPI response buffer
#
# The variable name that will receive the string must be passed when calling
# this function.
# =============================================================================
function getstring
{
    # Define local variables
    local len

    # Grab the string length
    get4 len

    # Grab the string
    getchars ${len} ${1}
}

# =============================================================================
# Retrieve an array of strings from the SMAPI response buffer
#
# The variable name that will receive the array must be passed when calling
# this function.
# =============================================================================
function getstringarray
{
    # Define local variables
    local array_length array_offset entry_length entry_index

    # Get the entire array length and convert to hex length
    get4 array_length
    array_length=$(( array_length * 2 ))

    # Process all array entries
    array_offset=0
    entry_index=0
    while [ ${array_offset} -lt ${array_length} ]
    do
        # Make sure there's enough left in the response buffer
        if [ $(( array_length - array_offset )) -lt 8 ]
        then
            echo "Premature end in getstringarray"
            exit 1
        fi

        # Grab the next 4 bytes (8 hex digits)
        entry_length=$(( 16#${resp:array_offset:8} * 2 ))
        array_offset=$(( array_offset + 8 ))

        # Set the variable to an empty string if the length is zero
        if [ ${entry_length} -eq 0 ]
        then
            eval ${1}[${entry_index}]=""
        else
            # Make sure there's enough left in the response buffer
            if [ $(( array_length - array_offset )) -lt ${entry_length} ]
            then
                echo "Premanture end in getstringarray"
                exit 1
            fi

            # Grab the string and convert back to character
            eval ${1}[${entry_index}]='"$(echo -n ${resp:array_offset:entry_length} | xxd -r -p)"'

            # Bump to next input entry
            array_offset=$(( array_offset + entry_length ))
        fi

        # Bump to next output entry
        entry_index=$(( entry_index + 1 ))
    done

    # Remove it from the response buffer
    resp="${resp:array_offset}"
}

# =============================================================================
# Retrieve an null terminated (ASCIIZ) string from the SMAPI response buffer
#
# The variable name that will receive the string must be passed when calling
# this function.
# =============================================================================
function getasciiz
{
    # Define local variables
    local i

    # Preset variable
    eval ${1}=""

    # Find first null byte
    for (( i = 0; i < ${#resp}; i += 2 ))
    do
        if [ "${resp:i:2}" == "00" ]
        then
            # Grab the string and convert back to character
            eval ${1}='"$(echo -n ${resp:0:i} | xxd -r -p)"'
    
            # Remove it (and the null terminator) from the response buffer
            resp="${resp:$(( i + 2 ))}"
            break
        fi
    done
}

# =============================================================================
# Convert value to hex representation of 8 byte int
# =============================================================================
function int8
{
    printf "%016x" $(( ${1} & 0xffffffffffffffff ))
}

# =============================================================================
# Convert value to hex representation of 4 byte int
# =============================================================================
function int4
{
    printf "%08x" $(( ${1} & 0xffffffff ))
}

# =============================================================================
# Convert value to hex representation of 1 byte int
# =============================================================================
function int1
{
    printf "%02x" $(( ${1} & 0xff ))
}

# =============================================================================
# Convert string to hex representation for specified length
# =============================================================================
function chars
{
    echo -n "${2:0:$1}" | xxd -p
}

# =============================================================================
# Convert string to hex representation prepended with string length
# =============================================================================
function string
{
    local s="${*}"

    int4 ${#s}
    echo -n "${s}" | xxd -p
}

# =============================================================================
# Convert string to hex representation with ASCIIZ appended
# =============================================================================
function asciiz
{
    echo -e -n "${*}\x00" | xxd -p
}

# =============================================================================
# Convert array of strings to hex representation
# =============================================================================
function stringarray
{
    # Define local variables
    local s a

    # Build hex representation of array
    a=""
    while [ ${#} -gt 0 ]
    do
        # Grab the next entry
        s="${1}"
        shift

        # Do not allow null entries
        if [ ${#s} -eq 0 ]
        then
            s=" "
        fi

        # Append to output "array"
        a=${a}$(string "${s}")
    done

    # Get rid of any blanks (inserted by xxd)
    a=$(removeblanks ${a})

    # Calc length of entire array and output it along with the array itself
    int4 $(( ${#a} / 2 ))
    echo -n "${a}"
}

# =============================================================================
# Send request to the SMAPI server
# =============================================================================
function smapi
{
    # Define local variables
    local s iucv

    # Remember the actual function being requested
    smfunc=${1}
    shift

    # Prepend the general parameters and remove embedded blanks
    s=$(removeblanks \
        $(string "${smfunc}") \
        $(string "${smuser}") \
        $(string "${smpass}") \
        $(string "${smtarg}") \
        ${*})

    # For debugging
    if [ "${debug}" == "yes" ]
    then
        { int4 $(( ${#s} / 2 )) ; echo -n ${s} ; } | xxd -r -p >req
    fi

    # Connect to the SMAPI host
    if [ "${smhost}" != "IUCV" ]
    then
        exec 3<>/dev/tcp/"${smhost}"

        # Bail if we couldn't connect
        if [ $? -ne 0 ]
        then
            echo "Failed to connect to ${smhost}"
            exit 1
        fi

        # Calculate and prepend request length, convert from hex to
        # binary representation, send to the SMAPI server, and wait
        # for the response.
        resp=$({ int4 $(( ${#s} / 2 )) ; echo -n ${s} ; } | xxd -r -p >&3 && xxd -p <&3)
    else
        # Calculate and prepend request length, convert from hex to
        # binary representation, send to the SMAPI server, and wait
        # for the response.
        resp=$({ int4 $(( ${#s} / 2 )) ; echo -n ${s} ; } | xxd -r -p | smiucv | xxd -p)
    fi

    # Get rid of any blanks inserted by xxd (don't quote it)
    resp=$(removeblanks ${resp})

    # For debugging
    if [ "${debug}" == "yes" ]
    then
        echo "${resp}" | xxd -r -p >resp
    fi

    # Retrieve the common results sent with every response
    get4 reqid1

    # Retrieve secondary result if available
    resplen=0
    reqid2=0
    retc=0
    reas=0

    if [ ${#resp} -gt 0 ]
    then
        get4 resplen
        get4 reqid2
        get4 retc
        get4 reas
    fi

    # For debugging
    #echo "reqid1 $reqid1"
    #echo "resplen $resplen"
    #echo "reqid2 $reqid2"
    #echo "retc $retc"
    #echo "reas $reas"

    # Close SMAPI file descriptor ... I know, WAY too anal
    if [ "${smhost}" != "IUCV" ]
    then
        eval 3>&-
    fi
}

# =============================================================================
# Wait for a request that is being processed asynchronously
# =============================================================================
function waitforasync
{
    # Define local variables
    local opid secs

    opid=$(int4 "${1}")
    secs=1

    echo "Waiting for asynchronous request ${1}"
    while true
    do
        sleep ${secs}

        smapi "Query_Asynchronous_Operation_DM" ${opid}
        if [ ${retc} -ne 0 -o ${reas} -ne 104 ]
        then
            break
        fi

        #secs=$(( secs * 2 ))
    done

    if [ ${retc} -eq 0 -a ${reas} -eq 100 ]
    then
        reas=0
    fi
}

# =============================================================================
# Send the request to the SMAPI server and wait for async requests
# =============================================================================
function execute_and_wait
{
    # Define local variables
    local opid=""

    # Submit the request
    smapi ${@}

    # Handle async response
    if [ ${retc} -eq 592 ]
    then
        # The operation id will be part of the response buffer or
        # will be the reason code
        if [ ${reas} -eq 0 ]
        then
            # (Not precisely correct, but hopefully it'll cover all cases}
            if [ ${#resp} -ge 4 ]
            then
                get4 opid
            fi
        else
            opid=${reas}
        fi

        # Go wait for it to complete
        if [ -z "${opid}" ]
        then
            echo "Unable to determine operation ID"
            exit 1
        fi
            
        waitforasync ${opid}
    fi
}

# =============================================================================
# Send the request to the SMAPI server without checking for errors.
#
# This function can only be called by a SMAPI function handler since its name
# is used as part of the SMAPI request.
# =============================================================================
function execute_no_check
{
    # Define local variables
    local caller

    # Retrieve caller info
    eval caller=("$(caller 0)")

    # Execute request and wait for the response
    execute_and_wait "${caller[1]}" ${@}
}

# =============================================================================
# Send the request to the SMAPI server and check success.
#
# This function can only be called by a SMAPI function handler since its name
# is used as part of the SMAPI request.
# =============================================================================
function execute
{
    # Retrieve the caller's name
    local caller

    # Retrieve caller info
    eval caller=("$(caller 0)")

    # Execute request and wait for the response
    execute_and_wait "${caller[1]}" ${@}

    # Check for error
    checkandfail
}

# =============================================================================
# Execute using keyword arguments
# =============================================================================
function execute_keywords
{
    local caller

    # Retrieve caller info
    eval caller=("$(caller 0)")

    # Generic setup
    required=()
    optional=()
    opts=""
    optl=""
    usesparms="o"

    # Parse the command line
    parseopts

    # Execute request and wait for the response
    execute_and_wait "${caller[1]}" "${addparms}"

    # Check for error
    checkandfail
}

# =============================================================================
# Execute using keyword arguments...bypass error checking
# =============================================================================
function execute_keywords_no_check
{
    local caller

    # Retrieve caller info
    eval caller=("$(caller 0)")

    # Generic setup
    required=()
    optional=()
    opts=""
    optl=""
    usesparms="o"

    # Parse the command line
    parseopts

    # Execute request and wait for the response
    execute_and_wait "${caller[1]}" "${addparms}"
}

# =============================================================================
# Retrieve and display simple array from response buffer
# =============================================================================
function showstringarray
{
    # Define local variables
    local i array

    # Retrieve the array
    getstringarray array

    # Show all the entries
    for (( i = 0; i < ${#array[@]}; i++ ))
    do
        echo "${array[i]}"
    done
}

# =============================================================================
# Retrieve and display ASCIIZ array from response buffer
# =============================================================================
function showasciizarray
{
    # Define local variables
    local array len

    # Calculate response length
    len=$(( $1 * 2 ))

    # Retrieve and process array entries
    echo "${resp:0:len}" | xxd -r -p | tr '\000' '\n'

    # Remove it from the response buffer
    resp="${resp:len}"
}

# =============================================================================
# Load array of records from stdin
# =============================================================================
function loadarray
{
    # Define local variables
    local i record

    # Load array from stdin
    OIFS="${IFS}"
    IFS=$'\n'
    i=0
    eval ${1}="()"
    while read record
    do
        # Ensure records do not exceend max length
        if [ ${#record} -gt 72 ]
        then
            echo "Record #$(( i + 1 )) is ${#record} bytes which exceeds the maximum of 72"
            echo "'${record}'"
            exit 1
        fi

        # Add new record to array
        eval ${1}[${i}]="\${record}"
        i=$(( i + 1 ))
    done
    IFS="${OIFS}"
}

# =============================================================================
# Display function usage
# =============================================================================
function usage
{
    # Define local variables
    local f i

    # Use the function name passed in or get the name of the caller
    f="${1}"
    if [ -z "${f}" ]
    then
        set -- $(caller 1)
        f="${2}"
    fi

    # Give 'em a little helping hand
    echo
    echo "${desc}"
    echo 
    echo "Usage: $(basename ${0}) ${f} [OPTION]... [PARAMETER]..."
    echo
    echo "Required general options:"
    echo "    -T | --target          target image or authorization entry name"

    # Show function related required parameters
    if [ -n "${required}" ]
    then
        echo
        echo "Required ${f} options:"
        for (( i = 0; i < ${#required[@]}; i++ ))
        do
            echo "${required[i]}"
        done
    fi

    echo
    echo "Optional general options:"
    echo "    -H | --smhost          hostname/port of SMAPI server"
    echo "                           : specify IUCV if SMAPI IUCV is desired"
    echo "                           : the smiucv command must be available"
    echo "    -U | --smuser          authorized SMAPI userid"
    echo "    -P | --smpass          authorized SMAPI password"
    echo "    -? | --help            output (this) usage information"
    echo
    echo "    smhost, smuser, and/or smpass may also be specified in"
    echo "    /etc/smaclient.conf, ~/.smaclient, and/or environment variables."

    # Show function related optional parameters
    if [ -n "${optional}" ]
    then
        echo
        echo "Optional ${f} options:"
        for (( i = 0; i < ${#optional[@]}; i++ ))
        do
            echo "${optional[i]}"
        done
    fi

    exit 1
}

# =============================================================================
# Parse command line options
#
# Variables that must be set prior to calling this function:
#
#   desc        Description of function
#   required    Required options for usage display and parameter checking
#   optional    Optional options for usage display
#   opts        Short options for passing to "getopt"
#   optl        Long options for passing to "getopt"
#   usesparms   Set to "r" for required positional parms, "o" for optional
#               positional parms, and "n" for no positional parms
# 
# =============================================================================
function parseopts
{
    # Define local variables
    local reqopts caller t

    # Copy existing values and make local since they will be modified
    local opts="${opts}" optl="${optl}"

    # Build array used to determine if all required options were specified
    reqopts=("    -T | --target          target image or authorization entry name" \
             "${required[@]}")

    # Lines with ":" are informational...remove them
    reqopts=("${reqopts[@]/*: *}")

    # Retrieve the caller's name
    set -- $(caller 0)
    caller="${2}"

    # Add the general options
    opts="H:U:P:T:D?${opts}"
    if [ -n "${optl}" ]
    then
        optl=",${optl}"
    fi
    optl="smhost:,smuser:,smpass:,target:,help${optl}"

    # Parse the command line (quotes around argv are a must!)
    t=$(getopt -o "${opts}" -l "${optl}" -- "${argv[@]}")

    # Try to give the user a little help if parsing failed
    if [ ${?} -ne 0 ]
    then
        usage "${caller}"
    fi

    # Empty out the argv array as it is going to get rebuilt
    argv=()
    addparms=""

    # Break up parsing result and assign to positional parameters
    # ("eval" and quotes are required)
    eval set -- "${t}"

    # Process positional parameters
    while [ ${#} -gt 0 ]
    do
        # Locate and remove current option from required opts array
        reqopts=("${reqopts[@]/*${1} *}")

        # Handle the general options
        case "${1}" in
            -H | --smhost)
                shift
                smhost="${1}"
            ;;

            -U | --smuser)
                shift
                smuser="${1}"
            ;;

            -P | --smpass)
                shift
                smpass="${1}"
            ;;

            -T | --target)
                shift
                smtarg="${1}"
            ;;

            -D)
                debug="yes"
            ;;

            -\? | --help)
                usage "${caller}"
            ;;

            *)
                # If positional parameters were specified on the command
                # line and the SMAPI function handler doesn't expect any,
                # then complain and bail.
                if [ "${1}" == "--" -a ${usesparms} == "n" -a ${#} -gt 1 ]
                then
                    echo "Unexpected positional parameter(s)"
                    usage "${caller}"
                fi

                # Otherwise transfer option and/or positional to argv array
                argv[${#argv[@]}]="${1}"

                # And build 6.1+ additional input parameters
                if [ "${1}" != "--" ]
                then
                    addparms="${addparms}$(asciiz """${1}""")"
                fi
            ;;
        esac

        # Remove option from positionals
        shift
    done

    # Check to make sure all of the required options were specified
    reqopts="${reqopts[*]}"
    if [ -n "${reqopts// }" ]
    then
        echo "Required option not specified"
        usage "${caller}"
    fi

    # These required parameters must be checked specifically since
    # they may come from locations other than the command line.
    if [ -z "${smhost}" ]
    then
        echo "Host/port (smhost) not specified"
        usage "${caller}"
    fi

    if [ "${smhost}" != "IUCV" -a -z "${smuser}" ]
    then
        echo "Authorized userid (smuser) not specified"
        usage "${caller}"
    fi

    if [ "${smhost}" != "IUCV" -a -z "${smpass}" ]
    then
        echo "Authorized password (smpass) not specified"
        usage "${caller}"
    fi
}

# =============================================================================
# SMAPI Function: Asynchronous_Notification_Disable_DM
# =============================================================================
function Asynchronous_Notification_Disable_DM
{
    # Define local variables
    local i entity_type communication_type port_number ip_address
    local encoding subscriber_data

    # Define info for parser
    desc="Stop receiving notification updates for specified entities"
    required=("    -c | --comm            communication type" \
              "                           : 1 = TCP" \
              "                           : 2 = UDP" \
              "    -p | --port            port number" \
              "    -i | --ip              IP address")
    optional=("    -t | --type            entity type" \
              "                           : 1 = DIRECTORY" \
              "    -e | --encoding        encoding of notification" \
              "                           : 0 = Unspecified (defaults to 1)" \
              "                           : 1 = ASCII" \
              "                           : 2 = EBCDIC" \
              "    -d | --data            subscriber data")
              
    opts="c:p:i:t:e:d:"
    optl="comm:,port:,ip:,type:,encoding:,data:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Initialize optional fields
    entity_type="1"
    encoding="0"
    subscriber_data=""

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -c | --comm)
                i=$(( i + 1 ))
                communication_type="${argv[i]}"
            ;;

            -p | --port)
                i=$(( i + 1 ))
                port_number="${argv[i]}"
            ;;

            -i | --ip)
                i=$(( i + 1 ))
                ip_address="${argv[i]}"
            ;;

            -d | --data)
                i=$(( i + 1 ))
                subscriber_data="${argv[i]}"
            ;;

           -t | --type)
                i=$(( i + 1 ))
                entity_type="${argv[i]}"
            ;;

            -e | --encoding)
                i=$(( i + 1 ))
                encoding="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(int1 "${entity_type}") \
            $(int1 "${communication_type}") \
            $(int4 "${port_number}") \
            $(string "${ip_address}") \
            $(int1 "${encoding}") \
            $(string "${subscriber_data}")

    # Tell user it was successful
    echo "Subscription disabled"
}

# =============================================================================
# SMAPI Function: Asynchronous_Notification_Enable_DM
# =============================================================================
function Asynchronous_Notification_Enable_DM
{
    # Define local variables
    local i entity_type subscription_type communication_type port_number
    local ip_address encoding subscriber_data

    # Define info for parser
    desc="Receive notification when updates occur to specified entities"
    required=("    -s | --sub             subscription type" \
              "                           : 1 = INCLUDE" \
              "                           : 2 = EXCLUDE" \
              "    -c | --comm            communication type" \
              "                           : 1 = TCP" \
              "                           : 2 = UDP" \
              "    -p | --port            port number" \
              "    -i | --ip              IP address")
    optional=("    -t | --type            entity type" \
              "                           : 1 = DIRECTORY" \
              "    -e | --encoding        encoding of notification" \
              "                           : 0 = Unspecified (defaults to 1)" \
              "                           : 1 = ASCII" \
              "                           : 2 = EBCDIC" \
              "    -d | --data            subscriber data")
    opts="s:c:p:i:t:e:d:"
    optl="sub:,comm:,port:,ip:,type:,encoding:,data:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Initialize optional fields
    entity_type="1"
    encoding="1"
    subscriber_data=""

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
           -t | --type)
                i=$(( i + 1 ))
                entity_type="${argv[i]}"
            ;;

            -s | --sub)
                i=$(( i + 1 ))
                subscription_type="${argv[i]}"
            ;;


            -c | --comm)
                i=$(( i + 1 ))
                communication_type="${argv[i]}"
            ;;

            -p | --port)
                i=$(( i + 1 ))
                port_number="${argv[i]}"
            ;;

            -i | --ip)
                i=$(( i + 1 ))
                ip_address="${argv[i]}"
            ;;

            -e | --encoding)
                i=$(( i + 1 ))
                encoding="${argv[i]}"
            ;;

            -d | --data)
                i=$(( i + 1 ))
                subscriber_data="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(int1 "${entity_type}") \
            $(int1 "${subscription_type}") \
            $(int1 "${communication_type}") \
            $(int4 "${port_number}") \
            $(string "${ip_address}") \
            $(int1 "${encoding}") \
            $(string "${subscriber_data}")

    # Tell user it was successful
    echo "Subscription enabled"
}

# =============================================================================
# SMAPI Function: Asynchronous_Notification_Query_DM
# =============================================================================
function Asynchronous_Notification_Query_DM
{
    # Define local variables
    local i arraylen reclen req
    local entity_type communication_type port_number ip_address
    local encoding subscriber_data userid subscription_type
    local notification_array_length notification_structure_length

    # Define info for parser
    desc="Query current notification subscriptions"
    required=()
    optional=("    -t | --type            entity type" \
              "                           : 1 = DIRECTORY" \
              "    -c | --comm            communication type" \
              "                           : 1 = TCP" \
              "                           : 2 = UDP" \
              "    -p | --port            port number" \
              "    -i | --ip              IP address" \
              "    -e | --encoding        encoding of notification" \
              "                           : 0 = Unspecified (defaults to 1)" \
              "                           : 1 = ASCII" \
              "                           : 2 = EBCDIC" \
              "    -d | --data            subscriber data")
    opts="t:c:p:i:e:d:"
    optl="type:,comm:,port:,ip:,encoding:,data:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Initialize optional fields
    entity_type="1"
    communication_type="0"
    port_number="0"
    ip_address=""
    encoding="0"
    subscriber_data=""

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
           -t | --type)
                i=$(( i + 1 ))
                entity_type="${argv[i]}"
            ;;

            -c | --comm)
                i=$(( i + 1 ))
                communication_type="${argv[i]}"
            ;;

            -p | --port)
                i=$(( i + 1 ))
                port_number="${argv[i]}"
            ;;

            -i | --ip)
                i=$(( i + 1 ))
                ip_address="${argv[i]}"
            ;;

            -e | --encoding)
                i=$(( i + 1 ))
                encoding="${argv[i]}"
            ;;

            -d | --data)
                i=$(( i + 1 ))
                subscriber_data="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(int1 "${entity_type}") \
            $(int1 "${communication_type}") \
            $(int4 "${port_number}") \
            $(string "${ip_address}") \
            $(int1 "${encoding}") \
            $(string "${subscriber_data}")

    # Retrieve the length of the returned array
    get4 notification_array_length

    # Retrieve and process array entries
    while [ $notification_array_length -gt 0 ]
    do
        # Retrieve the entry length
        get4 notification_structure_length

        # Protect against empty entries
        if [ $notification_structure_length -gt 0 ]
        then
            # Retrieve entry fields
            getstring userid
            get1 subscription_type
            get1 communication_type
            get4 port_number
            getstring ip_address
            get1 encoding
            getstring subscriber_data

            # Convert subscription_type
            case "${subscription_type}" in
                1) subscription_type="${subscription_type} (INCLUDE)" ;;
                2) subscription_type="${subscription_type} (EXCLUDE)" ;;
                *) subscription_type="${subscription_type} (??)" ;;
            esac
        
            # Convert communication_type
            case "${communication_type}" in
                1) communication_type="${communication_type} (TCP)" ;;
                2) communication_type="${communication_type} (UDP)" ;;
                *) communication_type="${communication_type} (??)" ;;
            esac
        
            # Convert encoding
            case "${encoding}" in
                1) encoding="${encoding} (ASCII)" ;;
                2) encoding="${encoding} (EBCDIC)" ;;
                *) encoding="${encoding} (??)" ;;
            esac
        
            # Show it to the user
            echo "Subscription:"
            echo "  Userid: ${userid}"
            echo "  Subscrition type: ${subscription_type}"
            echo "  Communication type: ${communication_type}"
            echo "  Port number: ${port_number}"
            echo "  IP address: ${ip_address}"
            echo "  Encoding: ${encoding}"
            echo "  Subscriber data: ${subscriber_data}"
        fi

        # Calculate remaining length (+4 for the "notification_structure_length" itself)
        notification_array_length=$(( notification_array_length - 4 - notification_structure_length ))
    done
}

# =============================================================================
# SMAPI Function: Authorization_List_Add
# =============================================================================
function Authorization_List_Add
{
    # Define local variables
    local i for_id function_id

    # Define info for parser
    desc="Add an entry to the list of authorized users"
    required=("    -f | --for             image or list name for which target is authorized" \
              "    -u | --func            function or list name for which target is authorized")
    optional=()
    opts="f:u:"
    optl="for:,func:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -f | --for)
                i=$(( i + 1 ))
                for_id="${argv[i]}"
            ;;

            -u | --func)
                i=$(( i + 1 ))
                function_id="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${for_id}") \
            $(string "${function_id}")

    # Tell user it was successful
    echo "Authorization granted to ${smtarg} for ${for_id} and function ${function_id}"
}

# =============================================================================
# SMAPI Function: Authorization_List_Query
# =============================================================================
function Authorization_List_Query
{
    # Define local variables
    local i for_id function_id
    local auth_record_array_length auth_record_structure_length
    local requesting_userid requesting_list_indicator requesting_type
    local for_userid for_list_indicator for_type
    local function_name function_list_indicator function_type

    # Define info for parser
    desc="Query the list of authorized users"
    required=()
    optional=("    -f | --for             image or list name for which target is authorized" \
              "    -u | --func            function or list name for which target is authorized")
    opts="f:u:"
    optl="for:,func:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Initialize optional fields
    for_id=""
    function_id=""

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -f | --for)
                i=$(( i + 1 ))
                for_id="${argv[i]}"
            ;;

            -u | --func)
                i=$(( i + 1 ))
                function_id="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${for_id}") \
            $(string "${function_id}")

    # Retrieve the length of the returned array
    get4 auth_record_array_length

    # Retrieve and process array entries
    while [ $auth_record_array_length -gt 0 ]
    do
        # Retrieve the entry length
        get4 auth_record_structure_length

        # Protect against empty entries
        if [ $auth_record_structure_length -gt 0 ]
        then
            # Retrieve entry fields
            getstring requesting_userid
            get1 requesting_list_indicator
            getstring for_userid
            get1 for_list_indicator
            getstring function_name
            get1 function_list_indicator

            # Convert requesting_type
            requesting_type="userid"
            if [ ${requesting_list_indicator} -eq 1 ]
            then
                requesting_type="list"
            fi

            # Convert for_list_indicator
            for_type="userid"
            if [ ${for_list_indicator} -eq 1 ]
            then
                for_type="list"
            fi

            # Convert function_type
            function_type="name"
            if [ ${function_list_indicator} -eq 1 ]
            then
                function_type="list"
            fi

            # Show it to the user
            echo "Entry:"
            echo "  Requesting ${requesting_type}: ${requesting_userid}"
            echo "  For ${for_type}: ${for_userid}"
            echo "  Function ${function_type}: ${function_name}"
        fi

        # Calculate remaining length (+4 for the "auth_record_structure_length" itself)
        auth_record_array_length=$(( auth_record_array_length - 4 - auth_record_structure_length ))
    done
}

# =============================================================================
# SMAPI Function: Authorization_List_Remove
# =============================================================================
function Authorization_List_Remove
{
    # Define local variables
    local i for_id function_id

    # Define info for parser
    desc="Remove an entry from the list of authorized users"
    required=("    -f | --for             image or list name for which target is authorized" \
              "    -u | --func            function or list name for which target is authorized")
    optional=()
    opts="f:u:"
    optl="for:,func:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -f | --for)
                i=$(( i + 1 ))
                for_id="${argv[i]}"
            ;;

            -u | --func)
                i=$(( i + 1 ))
                function_id="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${for_id}") \
            $(string "${function_id}")

    # Tell user it was successful
    echo "Authorization revoked from ${smtarg} for ${for_id} and function ${function_id}"
}

# =============================================================================
# SMAPI Function: Delete_ABEND_Dump
# =============================================================================
function Delete_ABEND_Dump
{
    # Define local variables
    local 

    # Define info for parser
    desc="Request deletion of abend dump"

    # Build and send request
    execute_keywords 
    
    # Tell user it was successful
    echo "Dump deletion requested"
}

# =============================================================================
# SMAPI Function: Directory_Manager_Local_Tag_Define_DM
# =============================================================================
function Directory_Manager_Local_Tag_Define_DM
{
    # Define local variables
    local i tag_name tag_ordinal define_action

    # Define info for parser
    desc="Define a local tag for an image"
    required=("    -n | --name            tag name" \
              "    -o | --ordinal         tag ordinal")
    optional=("    -a | --action          define action" \
              "                           : 1 = DEFINE (default)" \
              "                           : 2 = CHANGE")
    opts="n:o:a:"
    optl="name:,ordinal:,action:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Initialize optional fields
    define_action="1"

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -n | --name)
                i=$(( i + 1 ))
                tag_name="${argv[i]}"
            ;;

            -o | --ordinal)
                i=$(( i + 1 ))
                tag_ordinal="${argv[i]}"
            ;;

            -a | --action)
                i=$(( i + 1 ))
                define_action="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${tag_name}") \
            $(int4 "${tag_ordinal}") \
            $(int1 "${define_action}")

    # Tell user it was successful
    echo "Tag ${tag_name} with ${tag_ordinal} defined/changed"
}

# =============================================================================
# SMAPI Function: Directory_Manager_Local_Tag_Delete_DM
# =============================================================================
function Directory_Manager_Local_Tag_Delete_DM
{
    # Define local variables
    local i tag_name

    # Define info for parser
    desc="Delete a local tag from an image"
    required=("    -n | --name            tag name")
    optional=()
    opts="n:"
    optl="name:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Initialize optional fields
    define_action="1"

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -n | --name)
                i=$(( i + 1 ))
                tag_name="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${tag_name}")

    # Tell user it was successful
    echo "Tag ${tag_name} deleted"
}

# =============================================================================
# SMAPI Function: Directory_Manager_Local_Tag_Query_DM
# =============================================================================
function Directory_Manager_Local_Tag_Query_DM
{
    # Define local variables
    local i tag_name tag_value

    # Define info for parser
    desc="Query the value of a local tag"
    required=("    -n | --name            tag name")
    optional=()
    opts="n:"
    optl="name:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -n | --name)
                i=$(( i + 1 ))
                tag_name="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${tag_name}")

    # Retrieve return values
    getstring tag_value
    
    # Show them to the user
    echo "Tag ${tag_name} has a value of ${tag_value}"
}

# =============================================================================
# SMAPI Function: Directory_Manager_Local_Tag_Set_DM
# =============================================================================
function Directory_Manager_Local_Tag_Set_DM
{
    # Define local variables
    local i tag_name tag_value

    # Define info for parser
    desc="Set the value of a local tag"
    required=("    -n | --name            tag name" \
              "    -v | --value           tag value" \
              "                           : use \"DELETE\" to remove tag")
    optional=()
    opts="n:v:"
    optl="name:,value:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -n | --name)
                i=$(( i + 1 ))
                tag_name="${argv[i]}"
            ;;

            -v | --value)
                i=$(( i + 1 ))
                tag_value="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${tag_name}") \
            $(string "${tag_value}")

    # Tell user it was successful
    echo "Tag ${tag_name} set to ${tag_value}"
}

# =============================================================================
# SMAPI Function: Directory_Manager_Search_DM
# =============================================================================
function Directory_Manager_Search_DM
{
    # Define local variables
    local i search_pattern statement_array_length target_id statement

    # Define info for parser
    desc="Search directory"
    required=("    -p | --pattern         search pattern")
    optional=()
    opts="p:"
    optl="pattern:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -p | --pattern)
                i=$(( i + 1 ))
                search_pattern="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${search_pattern}")

    # Retrieve the length of the returned array
#    get4 statement_array_length

    # Retrieve and process array entries
#    while [ ${#resp} -gt 0 ]
#    do
#        getstring target_id
#        getstring statement
#
#        printf "%-8s: %s\n" "${target_id}" "${statement}"
#    done
    getstringarray statement_array
    for (( i = 0; i < ${#statement_array[@]}; i += 2 ))
    do
        image_name=${statement_array[i]}
        statement=${statement_array[$(( i + 1 ))]}
        printf "%-8s: %s\n" "${image_name}" "${statement}"
    done
}

# =============================================================================
# SMAPI Function: Event_Stream_Add
# =============================================================================
function Event_Stream_Add
{
    # Define local variables
    local i operation_id

    # Define info for parser
    desc="Cancel asynchronous task"
    required=("    -o | --opid            operation id")
    optional=()
    opts="o:"
    optl="opid:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -o | --opid)
                i=$(( i + 1 ))
                operation_id="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(int4 "${operation_id}")

    # Tell user it was successful
    echo "Task ${operation_id} cancelled"
}

# =============================================================================
# SMAPI Function: Event_Subscribe
# =============================================================================
function Event_Subscribe
{
    # Define local variables
    local i match_key

    # Define info for parser
    desc="Request deletion of abend dump"
    required=()
    optional=("    -m | --match           exact or fuzzy key to match")
    opts="m:"
    optl="match:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Initialize optional fields
    match_key=""

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -m | --match)
                i=$(( i + 1 ))
                match_key="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(int4 "${match_key}")

    # Tell user it was successful
    echo "Subscribed to event"
}

# =============================================================================
# SMAPI Function: Event_Unsubscribe
# =============================================================================
function Event_Unsubscribe
{
    # Define local variables
    local 

    # Define info for parser
    desc="Unsubscribe from events"
    required=()
    optional=()
    opts=""
    optl=""
    usesparms="n"

    # Parse the command line
    parseopts

    # Build and send the request
    execute

    # Tell user it was successful
    echo "Unsubscribed from events"
}

# =============================================================================
# SMAPI Function: Directory_Manager_Task_Cancel_DM
# =============================================================================
function Directory_Manager_Task_Cancel_DM
{
    # Define local variables
    local i operation_id

    # Define info for parser
    desc="Cancel asynchronous task"
    required=("    -o | --opid            operation id")
    optional=()
    opts="o:"
    optl="opid:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -o | --opid)
                i=$(( i + 1 ))
                operation_id="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(int4 "${operation_id}")

    # Tell user it was successful
    echo "Task ${operation_id} cancelled"
}

# =============================================================================
# SMAPI Function: Image_Activate
# =============================================================================
function Image_Activate
{
    # Define local variables
    local activated not_activated image_name
    local failing_array_length failing_structure_length

    # Define info for parser
    desc="Activate image(s)"
    required=()
    optional=()
    opts=""
    optl=""
    usesparms="n"

    # Parse the command line
    parseopts

    # Build and send the request
    execute_no_check

    # It was partially successful...show user what didn't activate
    if [ ${retc} -eq 200 -a ${reas} -eq 28 ]
    then
        # Retrieve the return values
        get4 activated
        get4 not_activated

        # Show them to the user
        echo "Number of images activated: ${activated}"
        echo "Number of images not activated: ${not_activated}"
    
        # Retrieve the length of the returned array
        get4 failing_array_length

        # Retrieve and process array entries
        while [ $failing_array_length -gt 0 ]
        do
            # Retrieve the entry length
            get4 failing_structure_length
    
            # Protect against empty entries
            if [ $failing_structure_length -gt 0 ]
            then
                # Retrieve the entry fields
                getstring image_name
                get4 retr
                get4 reas

                # Tell the user why this one failed
                echo "Activation of ${image_name} failed due to: "
                showerror
                echo
            fi
    
            # Calculate remaining length (+4 for the "failing_structure_length" itself)
            failing_array_length=$(( failing_array_length - 4 - failing_structure_length ))
        done

        # Bail since we handled this error specifically
        return
    fi

    # Check for error
    checkandfail

    # Tell user it was successful
    echo "${smtarg} activated"
}

# =============================================================================
# SMAPI Function: Image_Active_Configuration_Query
# =============================================================================
function Image_Active_Configuration_Query
{
    # Define local variables
    local memory_size memory_unit share_type share_value number_CPUs
    local CPU_info_array_length CPU_info_structure_length
    local CPU_number CPU_id CPU_status
    local device_info_array_length device_info_array_length
    local device_type device_address

    # Define info for parser
    desc="Query active configuration for target"
    required=()
    optional=()
    opts=""
    optl=""
    usesparms="n"

    # Parse the command line
    parseopts

    # Build and send the request
    execute

    # Retrieve return values
    get4 memory_size
    get1 memory_unit
    get1 share_type
    getstring share_value
    get4 number_CPUs

    # Convert memory_unit
    case "${memory_unit}" in
        1) memory_unit="${memory_unit} (KB)" ;;
        2) memory_unit="${memory_unit} (MB)" ;;
        3) memory_unit="${memory_unit} (GB)" ;;
        *) memory_unit="${memory_unit} (??)" ;;
    esac

    # Convert share_type
    percent=""
    case "${share_type}" in
        1) share_type="${share_type} (Relative)" ;;
        2) share_type="${share_type} (Absolute)" ;;
        *) share_type="${share_type} (??)" ;;
    esac

    # Show the user
    echo "Memory size: ${memory_size}"
    echo "Memory units: ${memory_unit}"
    echo "Share type: ${share_type}"
    echo "Share value: ${share_value}"
    echo "CPU count: ${number_CPUs}"
    echo

    # Retrieve the length of the returned array
    get4 CPU_info_array_length

    # Retrieve and process array entries
    echo "CPUs:"
    while [ $CPU_info_array_length -gt 0 ]
    do
        # Retrieve the entry length
        get4 CPU_info_structure_length

        # Protect against empty entries
        if [ $CPU_info_structure_length -gt 0 ]
        then
            # Retrieve the entry fields
            get4 CPU_number
            getstring CPU_id
            get1 CPU_status

            # Convert CPU_status
            case "${CPU_status}" in
                1) CPU_status="${CPU_status} (Base)" ;;
                2) CPU_status="${CPU_status} (Stopped)" ;;
                3) CPU_status="${CPU_status} (Check-stopped)" ;;
                4) CPU_status="${CPU_status} (Non-base, active)" ;;
                *) CPU_status="${CPU_status} (??)" ;;
            esac

            # Show the user
            echo "  Address: ${CPU_number}"
            echo "  ID: ${CPU_id}"
            echo "  Status: ${CPU_status}"
            echo
        fi

        # Calculate remaining length (+4 for the "CPU_info_structure_length" itself)
        CPU_info_array_length=$(( CPU_info_array_length - 4 - CPU_info_structure_length ))
    done

    # Retrieve the length of the returned array
    get4 device_info_array_length

    # Retrieve and process array entries
    echo "Devices:"
    while [ $device_info_array_length -gt 0 ]
    do
        # Retrieve the entry length
        get4 device_info_structure_length

        # Protect against empty entries
        if [ $device_info_structure_length -gt 0 ]
        then
            # Retrieve the entry fields
            get1 device_type
            getstring device_address

            # Convert device_type
            case "${device_type}" in
                1) device_type="${device_type} (CONS)" ;;
                2) device_type="${device_type} (RDR)" ;;
                3) device_type="${device_type} (PUN)" ;;
                4) device_type="${device_type} (PRT)" ;;
                5) device_type="${device_type} (DASD)" ;;
                *) device_type="${device_type} (??)" ;;
            esac

            # Show the user
            echo "  Device ${device_address} is ${device_type}"
        fi

        # Calculate remaining length (+4 for the "device_info_structure_length" itself)
        device_info_array_length=$(( device_info_array_length - 4 - device_info_structure_length ))
    done
}

# =============================================================================
# SMAPI Function: Image_CPU_Define
# =============================================================================
function Image_CPU_Define
{
    # Define local variables
    local i cpu_address cpu_type

    # Define info for parser
    desc="Add a CPU to an active image"
    required=("    -a | --addr            CPU address")
    optional=("    -t | --type            CPU type" \
              "                           : 0 = Unspecifed (default)" \
              "                           : 1 = CP" \
              "                           : 2 = IFL" \
              "                           : 3 = ZAAP" \
              "                           : 4 = ZIIP")
    opts="a:t:"
    optl="addr:,type"
    usesparms="n"

    # Parse the command line
    parseopts

    # Initialize optional fields
    cpu_type="0"

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -a | --addr)
                i=$(( i + 1 ))
                cpu_address="${argv[i]}"
            ;;

            -t | --type)
                i=$(( i + 1 ))
                cpu_type="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${cpu_address}") \
            $(int1 "${cpu_type}")

    # Tell user it was successful
    echo "CPU ${cpu_address} added to active ${smtarg}"
}

# =============================================================================
# SMAPI Function: Image_CPU_Define_DM
# =============================================================================
function Image_CPU_Define_DM
{
    # Define local variables
    local i cpu_address base_cpu cpuid dedicate_cpu

    # Define info for parser
    desc="Add a CPU to image directory"
    required=("    -a | --addr            CPU address" \
              "    -c | --cpuid           CPU id number")
    optional=("    -b | --base            base CPU" \
              "                           : 0 = Unspecified (default)" \
              "                           : 1 = BASE" \
              "    -d | --dedicate        dedicate real proc" \
              "                           : 0 = Unspecified (default)" \
              "                           : 1 = NODEDICATE" \
              "                           : 2 = DEDICATE")
    opts="a:c:b:d:"
    optl="addr:,cpuid:,base:,dedicate:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Initialize optional fields
    base_cpu="0"
    dedicate_cpu="0"

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -a | --addr)
                i=$(( i + 1 ))
                cpu_address="${argv[i]}"
            ;;

            -c | --cpuid)
                i=$(( i + 1 ))
                cpuid="${argv[i]}"
            ;;

            -b | --base)
                i=$(( i + 1 ))
                base_cpu="${argv[i]}"
            ;;

            -d | --dedicate)
                i=$(( i + 1 ))
                dedicate_cpu="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${cpu_address}") \
            $(int1 "${base_cpu}") \
            $(string "${cpuid}") \
            $(int1 "${dedicate_cpu}") \
            $(int1 "0")
               
    # Tell user it was successful
    echo "CPU ${cpu_address} added to ${smtarg}"
}

# =============================================================================
# SMAPI Function: Image_CPU_Delete
# =============================================================================
function Image_CPU_Delete
{
    # Define local variables
    local i cpu_address

    # Define info for parser
    desc="Delete a CPU from active image"
    required=("    -a | --addr            CPU address")
    optional=()
    opts="a:"
    optl="addr:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -a | --addr)
                i=$(( i + 1 ))
                cpu_address="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${cpu_address}")

    # Tell user it was successful
    echo "CPU ${cpu_address} deleted from active ${smtarg}"
}

# =============================================================================
# SMAPI Function: Image_CPU_Delete_DM
# =============================================================================
function Image_CPU_Delete_DM
{
    # Define local variables
    local i cpu_address

    # Define info for parser
    desc="Delete a CPU from image directory"
    required=("    -a | --addr            CPU address")
    optional=()
    opts="a:"
    optl="addr:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -a | --addr)
                i=$(( i + 1 ))
                cpu_address="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${cpu_address}")

    # Tell user it was successful
    echo "CPU ${cpu_address} deleted from ${smtarg}"
}

# =============================================================================
# SMAPI Function: Image_CPU_Query
# =============================================================================
function Image_CPU_Query
{
    # Define local variables
    local CPU_info_array_length CPU_info_structure_length
    local number_CPUs CPU_address CPU_id CPU_base CPU_status CPU_type

    # Define info for parser
    desc="Query CPUs in active image"
    required=()
    optional=()
    opts=""
    optl=""
    usesparms="n"

    # Parse the command line
    parseopts

    # Build and send the request
    execute

    # Retrieve return values
    get4 number_CPUs

    # Show the user
    echo "CPU count: ${number_CPUs}"
    echo

    # Retrieve the length of the returned array
    get4 CPU_info_array_length

    # Retrieve and process array entries
    echo "CPUs:"
    while [ $CPU_info_array_length -gt 0 ]
    do
        # Retrieve the entry length
        get4 CPU_info_structure_length

        # Protect against empty entries
        if [ $CPU_info_structure_length -gt 0 ]
        then
            # Retrieve the entry fields
            get4 CPU_address
            getstring CPU_id
            get1 CPU_base
            get1 CPU_status
            get1 CPU_type

            # Convert CPU_base
            case "${CPU_base}" in
                0) CPU_base="${CPU_base} (Unspecified}" ;;
                1) CPU_base="${CPU_base} (BASE)" ;;
                2) CPU_base="${CPU_base} (non-BASE)" ;;
                *) CPU_base="${CPU_base} (??)" ;;
            esac

            # Convert CPU_status
            case "${CPU_status}" in
                1) CPU_status="${CPU_status} (Stopped)" ;;
                2) CPU_status="${CPU_status} (Check-stopped)" ;;
                3) CPU_status="${CPU_status} (Soft-stopped or active)" ;;
                *) CPU_status="${CPU_status} (??)" ;;
            esac

            # Convert CPU_type
            case "${CPU_type}" in
                1) CPU_type="${CPU_type} (CP)" ;;
                2) CPU_type="${CPU_type} (IFL)" ;;
                3) CPU_type="${CPU_type} (ZAAP)" ;;
                4) CPU_type="${CPU_type} (ZIIP)" ;;
                *) CPU_type="${CPU_type} (??)" ;;
            esac

            # Show the user
            echo "  Address: ${CPU_address}"
            echo "  ID: ${CPU_id}"
            echo "  Base: ${CPU_base}"
            echo "  Type: ${CPU_type}"
            echo "  Status: ${CPU_status}"
            echo
        fi

        # Calculate remaining length (+4 for the "CPU_info_structure_length" itself)
        CPU_info_array_length=$(( CPU_info_array_length - 4 - CPU_info_structure_length ))
    done
}

# =============================================================================
# SMAPI Function: Image_CPU_Query_DM
# =============================================================================
function Image_CPU_Query_DM
{
    # Define local variables
    local i cpu_address base_cpu cpuid dedicate_cpu crypto

    # Define info for parser
    desc="Query CPUs in image directory"
    required=("    -a | --addr            CPU address")
    optional=()
    opts="a:"
    optl="addr:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -a | --addr)
                i=$(( i + 1 ))
                cpu_address="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${cpu_address}")

    # Retrieve return values
    getstring cpu_address
    get1 base_cpu
    getstring cpuid
    get1 dedicate_cpu
    get1 crypto

    # Convert base_cpu
    case "${base_cpu}" in
        0) base_cpu="${base_cpu} (unspecified)" ;;
        1) base_cpu="${base_cpu} (BASE)" ;;
        *) base_cpu="${base_cpu} (??)" ;;
    esac

    # Convert dedicate_cpu
    case "${dedicate_cpu}" in
        0) dedicate_cpu="${dedicate_cpu} (unspecified)" ;;
        1) dedicate_cpu="${dedicate_cpu} (NODEDICATE)" ;;
        2) dedicate_cpu="${dedicate_cpu} (DEDICATE)" ;;
        *) dedicate_cpu="${dedicate_cpu} (??)" ;;
    esac

    # Show the user
    echo "  Address: ${cpu_address}"
    echo "  ID: ${cpuid}"
    echo "  Base: ${base_cpu}"
    echo "  Dedicate: ${dedicate_cpu}"
    echo
}

# =============================================================================
# SMAPI Function: Image_CPU_Set_Maximum_DM
# =============================================================================
function Image_CPU_Set_Maximum_DM
{
    # Define local variables
    local i max_cpu

    # Define info for parser
    desc="Set the maximum number of CPUs for an image"
    required=("    -m | --max             CPU address")
    optional=()
    opts="m:"
    optl="max:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -m | --max)
                i=$(( i + 1 ))
                max_cpu="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(int4 "${max_cpu}")

    # Tell user it was successful
    echo "Maximum CPU count set to ${max_cpu} for ${smtarg}"
}

# =============================================================================
# SMAPI Function: Image_Create_DM
# =============================================================================
function Image_Create_DM
{
    # Define local variables
    local i file type_name initial_password initial_account_number
    local image_record_array

    # Define info for parser
    desc="Create image"
    required=()
    optional=("    -n | --name            name of prototype used as model" \
              "    -p | --pass            the initial password" \
              "    -a | --acct            the initial account number")
    opts="n:p:a:"
    optl="name:,pass:,acct:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Initialize optional fields
    prototype_name=""
    initial_password=""
    initial_account_number=""

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -n | --name)
                i=$(( i + 1 ))
                prototype_name="${argv[i]}"
            ;;

            -p | --pass)
                i=$(( i + 1 ))
                initial_password="${argv[i]}"
            ;;

            -a | --acct)
                i=$(( i + 1 ))
                initial_account_number="${argv[i]}"
            ;;
        esac
    done

    # Load array from stdin
    loadarray image_record_array

    # Build and send the request
    execute $(string "${prototype_name}") \
            $(string "${initial_password}") \
            $(string "${initial_account_number}") \
            $(stringarray "${image_record_array[@]}")

    # Tell user it was successful
    echo "${smtarg} created"
}

# =============================================================================
# SMAPI Function: Image_Deactivate
# =============================================================================
function Image_Deactivate
{
    # Define local variables
    local i force_time deactivated not_deactivated image_name
    local failing_array_length failing_structure_length

    # Define info for parser
    desc="Deactivate image(s)"
    required=()
    optional=("    -t | --time            when deactivation should occur" \
              "                           : IMMED" \
              "                           : WITHIN seconds" \
              "                           : BY hh:mm" \
              "                           : BY hh:mm:ss")
              
    opts="t:"
    optl="time:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Initialize optional fields
    force_time=""

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -t | --time)
                i=$(( i + 1 ))
                force_time="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute_no_check $(string "${force_time}")

    # It was partially successful...show user what didn't deactivate
    if [ ${retc} -eq 200 -a ${reas} -eq 28 ]
    then
        # Retrieve the return values
        get4 deactivated
        get4 not_deactivated

        # Show them to the user
        echo "Number of images deactivated: ${deactivated}"
        echo "Number of images not deactivated: ${not_deactivated}"
    
        # Retrieve the length of the returned array
        get4 failing_array_length

        # Retrieve and process array entries
        while [ $failing_array_length -gt 0 ]
        do
            # Retrieve the entry length
            get4 failing_structure_length
    
            # Protect against empty entries
            if [ $failing_structure_length -gt 0 ]
            then
                # Retrieve the entry fields
                getstring image_name
                get4 retr
                get4 reas

                # Tell the user why this one failed
                echo "Activation of ${image_name} failed due to: "
                showerror
                echo
            fi
    
            # Calculate remaining length (+4 for the "failing_structure_length" itself)
            failing_array_length=$(( failing_array_length - 4 - failing_structure_length ))
        done

        # Bail since we handled this error specifically
        return
    # Suppress error message if deactived with N seconds
    elif [ ${retc} -ne 0 ]
    then
        # Check for error
        checkandfail
    fi

    # Tell user it was successful
    echo "${smtarg} deactivated"
}

# =============================================================================
# SMAPI Function: Image_Definition_Async_Updates
# =============================================================================
function Image_Definition_Async_Updates
{
    # Define local variables
    local

    # Define info for parser
    desc="Enable/disable async image updates"

    # Build and send the request
    execute_keywords

    # Tell user it was successful
    echo "Entry added for ${smtarg}"
}

# =============================================================================
# SMAPI Function: Image_Definition_Create_DM
# =============================================================================
function Image_Definition_Create_DM
{
    # Define local variables
    local 

    # Define info for parser
    desc="Create new virtual machine entry"
    required=()
    optional=()
    opts=""
    optl=""
    usesparms="o"

    # Parse the command line
    parseopts

    # Complain if no additional parms were specified
    if [ -z "${addparms}" ]
    then
        echo "Additional parameters not specified"
        exit 1
    fi

    # Build and send the request
    execute $(int4 $(( ${#addparms} / 2 ))) \
                   ${addparms}

    # Tell user it was successful
    echo "Entry added for ${smtarg}"
}

# =============================================================================
# SMAPI Function: Image_Definition_Delete_DM
# =============================================================================
function Image_Definition_Delete_DM
{
    # Define local variables
    local 

    # Define info for parser
    desc="Delete virtual machine info"
    required=()
    optional=()
    opts=""
    optl=""
    usesparms="o"

    # Parse the command line
    parseopts

    # Complain if no additional parms were specified
    if [ -z "${addparms}" ]
    then
        echo "Additional parameters not specified"
        exit 1
    fi

    # Build and send the request
    execute $(int4 $(( ${#addparms} / 2 ))) \
                   ${addparms}

    # Tell user it was successful
    echo "Info deleted from ${smtarg}"
}

# =============================================================================
# SMAPI Function: Image_Definition_Query_DM
# =============================================================================
function Image_Definition_Query_DM
{
    # Define local variables
    local

    # Define info for parser
    desc="Extract directory records"
    required=()
    optional=()
    opts=""
    optl=""
    usesparms="o"

    # Parse the command line
    parseopts

    # Complain if no additional parms were specified
    if [ -z "${addparms}" ]
    then
        echo "Additional parameters not specified"
        exit 1
    fi

    # Build and send the request
    execute_no_check $(int4 $(( ${#addparms} / 2 ))) \
                            ${addparms}

    # Retrieve return values
    if [ ${retc} -eq 0 -a ${reas} -eq 0 ]
    then
        get4 directory_information_length
        showasciizarray ${directory_information_length}
    elif [ ${retc} -eq 8 -a ${reas} -eq 3002 ]
    then
        getstring error_data
        echo "error:" ${error_data}
    else
        checkandfail
    fi
}

# =============================================================================
# SMAPI Function: Image_Definition_Update_DM
# =============================================================================
function Image_Definition_Update_DM
{
    # Define local variables
    local 

    # Define info for parser
    desc="Update virtual machine entry"
    required=()
    optional=()
    opts=""
    optl=""
    usesparms="o"

    # Parse the command line
    parseopts

    # Complain if no additional parms were specified
    if [ -z "${addparms}" ]
    then
        echo "Additional parameters not specified"
        exit 1
    fi

    # Build and send the request
    execute $(int4 $(( ${#addparms} / 2 ))) \
                   ${addparms}

    # Tell user it was successful
    echo "Entry updated for ${smtarg}"
}

# =============================================================================
# SMAPI Function: Image_Delete_DM
# =============================================================================
function Image_Delete_DM
{
    # Define local variables
    local i data_security_erase

    # Define info for parser
    desc="Delete image"
    required=()
    optional=("    -e | --erase           erase disks" \
              "                           : 0 = Unspecified (use system default)" \
              "                           : 1 = Do not erase" \
              "                           : 2 = Erase")
    opts="e:"
    optl="erase:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Initialize optional fields
    data_security_erase="0"

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -e | --erase)
                i=$(( i + 1 ))
                data_security_erase="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(int1 "${data_security_erase}")

    # Tell user it was successful
    echo "${smtarg} image deleted"
}

# =============================================================================
# SMAPI Function: Image_Device_Dedicate
# =============================================================================
function Image_Device_Dedicate
{
    # Define local variables
    local i image_device_number real_device_number readonly
    
    # Define info for parser
    desc="Add a dedicated device to active image"
    required=("    -a | --addr            virtual address of device" \
              "    -d | --dev             real address of device")
    optional=("    -r | --readonly        read-only mode" \
              "                           : 0 = not read-only" \
              "                           : 1 = read-only mode")
    opts="a:d:r:"
    optl="addr:,dev:,readonly"
    usesparms="n"

    # Parse the command line
    parseopts

    # Initialize optional fields
    readonly="0"

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -a | --addr)
                i=$(( i + 1 ))
                image_device_number="${argv[i]}"
            ;;

            -d | --dev)
                i=$(( i + 1 ))
                real_device_number="${argv[i]}"
            ;;

            -r | --readonly)
                i=$(( i + 1 ))
                readonly="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${image_device_number}") \
            $(string "${real_device_number}") \
            $(int1 "${readonly}")

    # Tell user it was successful
    echo "${real_device_number} dedicated to active ${smtarg} as ${image_device_number}"
}

# =============================================================================
# SMAPI Function: Image_Device_Dedicate_DM
# =============================================================================
function Image_Device_Dedicate_DM
{
    # Define local variables
    local i image_device_number real_device_number readonly
    
    # Define info for parser
    desc="Add a dedicated device to image"
    required=("    -a | --addr            virtual address of device" \
              "    -d | --dev             real address of device")
    optional=("    -r | --readonly        read-only mode" \
              "                           : 0 = not read-only" \
              "                           : 1 = read-only mode")
    opts="a:d:r:"
    optl="addr:,dev:,readonly"
    usesparms="n"

    # Parse the command line
    parseopts

    # Initialize optional fields
    readonly="0"

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -a | --addr)
                i=$(( i + 1 ))
                image_device_number="${argv[i]}"
            ;;

            -d | --dev)
                i=$(( i + 1 ))
                real_device_number="${argv[i]}"
            ;;

            -r | --readonly)
                i=$(( i + 1 ))
                readonly="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${image_device_number}") \
            $(string "${real_device_number}") \
            $(int1 "${readonly}")

    # Tell user it was successful
    echo "${real_device_number} dedicated to ${smtarg} as ${image_device_number}"
}

# =============================================================================
# SMAPI Function: Image_Device_Reset
# =============================================================================
function Image_Device_Reset
{
    # Define local variables
    local i image_device_number

    # Define info for parser
    desc="Clear pending interrupts from device dedicated to active image"
    required=("    -a | --addr            virtual address of device")
    optional=()
    opts="a:"
    optl="addr:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -a | --addr)
                i=$(( i + 1 ))
                image_device_number="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${image_device_number}")

    # Tell user it was successful
    echo "${smtarg}'s ${image_device_number} reset"
}

# =============================================================================
# SMAPI Function: Image_Device_Undedicate
# =============================================================================
function Image_Device_Undedicate
{
    # Define local variables
    local i image_device_number

    # Define info for parser
    desc="Remove a dedicated device from active image"
    required=("    -a | --addr            virtual address of device")
    optional=()
    opts="a:"
    optl="addr:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -a | --addr)
                i=$(( i + 1 ))
                image_device_number="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${image_device_number}")

    # Tell user it was successful
    echo "${image_device_number} undedicated from ${smtarg}"
}

# =============================================================================
# SMAPI Function: Image_Device_Undedicate_DM
# =============================================================================
function Image_Device_Undedicate_DM
{
    # Define local variables
    local i image_device_number

    # Define info for parser
    desc="Remove a dedicated device from image"
    required=("    -a | --addr            virtual address of device")
    optional=()
    opts="a:"
    optl="addr:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -a | --addr)
                i=$(( i + 1 ))
                image_device_number="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${image_device_number}")

    # Tell user it was successful
    echo "${image_device_number} undedicated from ${smtarg}"
}

# =============================================================================
# SMAPI Function: Image_Disk_Copy
# =============================================================================
function Image_Disk_Copy
{
    # Define local variables
    local i image_disk_number

    # Define info for parser
    desc="Clone a disk in active image"
    required=("    -a | --addr            address of disk")
    optional=()
    opts="a:"
    optl="addr:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -a | --addr)
                i=$(( i + 1 ))
                image_disk_number="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${image_disk_number}")

    # Tell user it was successful
    echo "${image_disk_number} disk cloned in active ${smtarg}"
}

# =============================================================================
# SMAPI Function: Image_Disk_Copy_DM
# =============================================================================
function Image_Disk_Copy_DM
{
    # Define local variables
    local i image_disk_number source_image_name source_image_disk_number
    local image_disk_allocation_type allocation_area_name_or_volser
    local image_disk_mode read_password write_password multi_password

    # Define info for parser
    desc="Clone a disk in image"
    required=("    -a | --addr            address of disk" \
              "    -s | --srcname         source image name" \
              "    -d | --srcdisk         source disk" \
              "    -t | --alctype         allocation type" \
              "                           : nnn = starting cylinder or block" \
              "                           : AUTOG = automatic group" \
              "                           : AUTOR = automatic region" \
              "                           : AUTOV = automatic volume" \
              "                           : DEVNO = full volume midisk" \
              "    -n | --name            allocation area name or volser" \
              "    -m | --mode            disk mode")
    optional=("    -r | --read            read password" \
              "    -w | --write           write password" \
              "    -i | --multi           multi password")
    opts="a:s:d:t:n:m:r:w:i:"
    optl="addr:,srcname:,srcdisk:,alctype:,name:,mode:,read:,write:,multi:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Initialize optional variables
    read_password=""
    write_password=""
    multi_password=""

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -a | --addr)
                i=$(( i + 1 ))
                image_disk_number="${argv[i]}"
            ;;

            -s | --srcname)
                i=$(( i + 1 ))
                source_image_name="${argv[i]}"
            ;;

            -d | --srcdisk)
                i=$(( i + 1 ))
                source_image_disk_number="${argv[i]}"
            ;;

            -t | --alctype)
                i=$(( i + 1 ))
                image_disk_allocation_type="${argv[i]}"
            ;;

            -n | --name)
                i=$(( i + 1 ))
                allocation_area_name_or_volser="${argv[i]}"
            ;;

            -m | --mode)
                i=$(( i + 1 ))
                image_disk_mode="${argv[i]}"
            ;;

            -r | --read)
                i=$(( i + 1 ))
                read_password="${argv[i]}"
            ;;

            -w | --write)
                i=$(( i + 1 ))
                write_password="${argv[i]}"
            ;;

            -i | --multi)
                i=$(( i + 1 ))
                multi_password="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${image_disk_number}") \
            $(string "${source_image_name}") \
            $(string "${source_image_disk_number}") \
            $(string "${image_disk_allocation_type}") \
            $(string "${allocation_area_name_or_volser}") \
            $(string "${image_disk_mode}") \
            $(string "${read_password}") \
            $(string "${write_password}") \
            $(string "${multi_password}")

    # Tell user it was successful
    echo "${source_image_name} ${source_image_disk_number} disk copied to ${smtarg} ${image_disk_number}"
}

# =============================================================================
# SMAPI Function: Image_Disk_Create
# =============================================================================
function Image_Disk_Create
{
    # Define local variables
    local i image_disk_number image_disk_mode

    # Define info for parser
    desc="Add a disk to an active image"
    required=("    -a | --addr            address of disk")
    optional=("    -m | --mode            access mode")
    opts="a:m:"
    optl="addr:,mode:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Initialize optional variables
    image_disk_mode=""

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -a | --addr)
                i=$(( i + 1 ))
                image_disk_number="${argv[i]}"
            ;;

            -m | --mode)
                i=$(( i + 1 ))
                image_disk_mode="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${image_disk_number}") \
            $(string "${image_disk_mode}")

    # Tell user it was successful
    echo "${image_disk_number} added to active ${smtarg}"
}

# =============================================================================
# SMAPI Function: Image_Disk_Create_DM
# =============================================================================
function Image_Disk_Create_DM
{
    # Define local variables
    local i image_disk_number image_disk_device_type image_disk_allocation_type
    local allocation_area_name_or_volser allocation_unit_size image_disk_size
    local image_disk_mode image_disk_formatting image_disk_label
    local read_password write_password multi_password

    # Define info for parser
    desc="Add a disk to image"
    required=("    -a | --addr            address of disk" \
              "    -d | --devtype         device type" \
              "    -t | --alctype         allocation type" \
              "                           : nnn = starting cylinder or block" \
              "                           : AUTOG = automatic group" \
              "                           : AUTOR = automatic region" \
              "                           : AUTOV = automatic volume" \
              "                           : DEVNO = full volume midisk" \
              "                           : T-DISK = automatic temporary disk" \
              "                           : V-DISK = automatic virtual disk" \
              "    -n | --name            allocation area name or volser" \
              "    -u | --units           allocation unit size" \
              "                           : 1 = cylinders" \
              "                           : 2 = BLK0512" \
              "                           : 3 = BLK1024" \
              "                           : 4 = BLK2048" \
              "                           : 5 = BLK4096" \
              "    -s | --size            disk size (use 0 for DEVNO type)" \
              "    -m | --mode            disk mode")
    optional=("    -f | --format          format disk after allocation" \
              "                           : 0 = Unspecified" \
              "                           :     (CMS if \"--label\" used else NONE)" \
              "                           : 1 = NONE" \
              "                           : 2 = CMS0512" \
              "                           : 3 = CMS1024" \
              "                           : 4 = CMS2048" \
              "                           : 5 = CMS4096" \
              "                           : 6 = CMS - default block size" \
              "    -l | --label           disk label" \
              "    -r | --read            read password" \
              "    -w | --write           write password" \
              "    -i | --multi           multi password")
    opts="a:d:t:n:u:s:m:f:l:r:w:i:"
    optl="addr:,devtype:,alctype:,name:,units:,size:,mode:,format:,label:,read:,write:,multi:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Initialize optional variables
    image_disk_formatting="0"
    image_disk_label=""
    read_password=""
    write_password=""
    multi_password=""

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -a | --addr)
                i=$(( i + 1 ))
                image_disk_number="${argv[i]}"
            ;;

            -d | --devtype)
                i=$(( i + 1 ))
                image_disk_device_type="${argv[i]}"
            ;;

            -t | --alctype)
                i=$(( i + 1 ))
                image_disk_allocation_type="${argv[i]}"
            ;;

            -n | --name)
                i=$(( i + 1 ))
                allocation_area_name_or_volser="${argv[i]}"
            ;;

            -u | --units)
                i=$(( i + 1 ))
                allocation_unit_size="${argv[i]}"
            ;;

            -s | --size)
                i=$(( i + 1 ))
                image_disk_size="${argv[i]}"
            ;;

            -m | --mode)
                i=$(( i + 1 ))
                image_disk_mode="${argv[i]}"
            ;;

            -f | --format)
                i=$(( i + 1 ))
                image_disk_formatting="${argv[i]}"
            ;;

            -l | --label)
                i=$(( i + 1 ))
                image_disk_label="${argv[i]}"
            ;;

            -r | --read)
                i=$(( i + 1 ))
                read_password="${argv[i]}"
            ;;

            -w | --write)
                i=$(( i + 1 ))
                write_password="${argv[i]}"
            ;;

            -i | --multi)
                i=$(( i + 1 ))
                multi_password="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${image_disk_number}") \
            $(string "${image_disk_device_type}") \
            $(string "${image_disk_allocation_type}") \
            $(string "${allocation_area_name_or_volser}") \
            $(int1 "${allocation_unit_size}") \
            $(int4 "${image_disk_size}") \
            $(string "${image_disk_mode}") \
            $(int1 "${image_disk_formatting}") \
            $(string "${image_disk_label}") \
            $(string "${read_password}") \
            $(string "${write_password}") \
            $(string "${multi_password}")

    # Tell user it was successful
    echo "${image_disk_number} added to ${smtarg}"
}

# =============================================================================
# SMAPI Function: Image_Disk_Delete
# =============================================================================
function Image_Disk_Delete
{
    # Define local variables
    local i image_disk_number

    # Define info for parser
    desc="Delete disk from active image"
    required=("    -a | --addr            address of disk")
    optional=()
    opts="a:"
    optl="addr:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -a | --addr)
                i=$(( i + 1 ))
                image_disk_number="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${image_disk_number}")

    # Tell user it was successful
    echo "${image_disk_number} deleted from active ${smtarg}"
}

# =============================================================================
# SMAPI Function: Image_Disk_Delete_DM
# =============================================================================
function Image_Disk_Delete_DM
{
    # Define local variables
    local i image_disk_number data_security_erase

    # Define info for parser
    desc="Delete disk from image"
    required=("    -a | --addr            address of disk")
    optional=("    -e | --erase           erase disks" \
              "                           : 0 = use installation default" \
              "                           : 1 = do not erase" \
              "                           : 2 = erase")
    opts="a:e:"
    optl="addr:,erase:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Initialize optional fields
    data_security_erase="0"

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -a | --addr)
                i=$(( i + 1 ))
                image_disk_number="${argv[i]}"
            ;;

            -e | --erase)
                i=$(( i + 1 ))
                data_security_erase="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${image_disk_number}") \
            $(int1 "${data_security_erase}")

    # Tell user it was successful
    echo "${image_disk_number} deleted from ${smtarg}"
}

# =============================================================================
# SMAPI Function: Image_Disk_Query
# =============================================================================
function Image_Disk_Query
{
    # Define local variables
    local

    # Define info for parser
    desc="Show all disks attached to target"

    # Build and send the request
    execute_keywords

    # Show each entry until nothing left
    while [ ${#resp} -gt 0 ]
    do
        getchars  4 vdasd_vdev
        getchars  4 vdasd_rdev
        get1      vdasd_access_type
        getchars  4 vdasd_devtype
        get8      vdasd_size
        get1      vdasd_unit
        getchars  6 vdasd_volid
        getchars  1 vdasd_z

        # Convert vdasd_access_type
        case "${vdasd_access_type}" in
            1) vdasd_access_type="${vdasd_access_type} (R/O)" ;;
            2) vdasd_access_type="${vdasd_access_type} (R/W)" ;;
            *) vdasd_access_type="${vdasd_access_type} (??)" ;;
        esac

        # Convert vdasd_unit_type
        case "${vdasd_unit}" in
            1) vdasd_unit="${vdasd_unit} (Cylinders)" ;;
            2) vdasd_unit="${vdasd_unit} (Blocks)" ;;
            *) vdasd_unit="${vdasd_unit} (??)" ;;
        esac

        # Show it to the user
        echo "Disk Info:"
        echo "  Virtual Address: ${vdasd_vdev}"
        echo "  Real Address: ${vdasd_rdev}"
        echo "  Access Type: ${vdasd_access_type}"
        echo "  Device Type: ${vdasd_devtype}"
        echo "  Size: ${vdasd_size}"
        echo "  Units: ${vdasd_unit}"
        echo "  Volume ID: ${vdasd_volid}"
        echo
    done
}

# =============================================================================
# SMAPI Function: Image_Disk_Share
# =============================================================================
function Image_Disk_Share
{
    # Define local variables
    local i image_disk_number target_image_name target_image_disk_number
    local read_write_mode optional_password

    # Define info for parser
    desc="Add link to active image"
    required=("    -a | --addr            device address" \
              "    -o | --owner           owner of target disk" \
              "    -d | --disk            address of target disk" \
              "    -m | --mode            link mode")
    optional=("    -p | --pass            link mode password")
    opts="a:o:d:m:p:"
    optl="addr:,owner:,disk:,mode:,pass:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Initialize optional variables
    optional_password=""

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -a | --addr)
                i=$(( i + 1 ))
                image_disk_number="${argv[i]}"
            ;;

            -o | --owner)
                i=$(( i + 1 ))
                target_image_name="${argv[i]}"
            ;;

            -d | --disk)
                i=$(( i + 1 ))
                target_image_disk_number="${argv[i]}"
            ;;

            -m | --mode)
                i=$(( i + 1 ))
                read_write_mode="${argv[i]}"
            ;;

            -p | --pass)
                i=$(( i + 1 ))
                optional_password="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${image_disk_number}") \
            $(string "${target_image_name}") \
            $(string "${target_image_disk_number}") \
            $(string "${read_write_mode}") \
            $(string "${optional_password}")

    # Tell user it was successful
    echo "Link to ${target_image_name} ${image_disk_number} added to active ${smtarg} as ${target_image_disk_number}"
}

# =============================================================================
# SMAPI Function: Image_Disk_Share_DM
# =============================================================================
function Image_Disk_Share_DM
{
    # Define local variables
    local i image_disk_number target_image_name target_image_disk_number
    local read_write_mode optional_password

    # Define info for parser
    desc="Add link to image"
    required=("    -a | --addr            device address" \
              "    -o | --owner           owner of target disk" \
              "    -d | --disk            address of target disk" \
              "    -m | --mode            link mode")
    optional=("    -p | --pass            link mode password")
    opts="a:o:d:m:p:"
    optl="addr:,owner:,disk:,mode:,pass:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Initialize optional variables
    optional_password=""

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -a | --addr)
                i=$(( i + 1 ))
                image_disk_number="${argv[i]}"
            ;;

            -o | --owner)
                i=$(( i + 1 ))
                target_image_name="${argv[i]}"
            ;;

            -d | --disk)
                i=$(( i + 1 ))
                target_image_disk_number="${argv[i]}"
            ;;

            -m | --mode)
                i=$(( i + 1 ))
                read_write_mode="${argv[i]}"
            ;;

            -p | --pass)
                i=$(( i + 1 ))
                optional_password="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${image_disk_number}") \
            $(string "${target_image_name}") \
            $(string "${target_image_disk_number}") \
            $(string "${read_write_mode}") \
            $(string "${optional_password}")

    # Tell user it was successful
    echo "Link to ${target_image_name} ${image_disk_number} added to ${smtarg} as ${target_image_disk_number}"
}

# =============================================================================
# SMAPI Function: Image_Disk_Unshare
# =============================================================================
function Image_Disk_Unshare
{
    # Define local variables
    local i image_disk_number

    # Define info for parser
    desc="Remove link from active image"
    required=("    -a | --addr            device address")
    optional=()
    opts="a:"
    optl="addr:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -a | --addr)
                i=$(( i + 1 ))
                image_disk_number="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${image_disk_number}")

    # Tell user it was successful
    echo "${image_disk_number} disk detached from ${smtarg}"
}

# =============================================================================
# SMAPI Function: Image_Disk_Unshare_DM
# =============================================================================
function Image_Disk_Unshare_DM
{
    # Define local variables
    local i image_disk_number target_image_name target_image_disk_number

    # Define info for parser
    desc="Remove link from image"
    required=("    -a | --addr            device address" \
              "    -o | --owner           owner of target disk" \
              "    -d | --disk            address of target disk")
    optional=()
    opts="a:o:d:"
    optl="addr:,owner:,disk:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -a | --addr)
                i=$(( i + 1 ))
                image_disk_number="${argv[i]}"
            ;;

            -o | --owner)
                i=$(( i + 1 ))
                target_image_name="${argv[i]}"
            ;;

            -d | --disk)
                i=$(( i + 1 ))
                target_image_disk_number="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${image_disk_number}") \
            $(string "${target_image_name}") \
            $(string "${target_image_disk_number}")

    # Tell user it was successful
    echo "${target_image_disk_number} removed from ${smtarg}"
}

# =============================================================================
# SMAPI Function: Image_IPL_Delete_DM
# =============================================================================
function Image_IPL_Delete_DM
{
    # Define info for parser
    desc="Delete IPL statement from image"
    required=()
    optional=()
    opts=""
    optl=""
    usesparms="n"

    # Parse the command line
    parseopts

    # Build and send the request
    execute

    # Tell user it was successful
    echo "IPL statement deleted from ${smtarg}"
}

# =============================================================================
# SMAPI Function: Image_IPL_Query_DM
# =============================================================================
function Image_IPL_Query_DM
{
    # Define local variables
    local saved_system load_parameter parameter_string

    # Define info for parser
    desc="Query IPL statement in image"
    required=()
    optional=()
    opts=""
    optl=""
    usesparms="n"

    # Parse the command line
    parseopts

    # Build and send the request
    execute

    # Retrieve return values
    getstring saved_system
    getstring load_parameter
    getstring parameter_string
    
    # Show them to the user
    echo "System or address: ${saved_system}"
    echo "Load parameter: ${load_parameter}"
    echo "IPL parameters: ${parameter_string}"
}

# =============================================================================
# SMAPI Function: Image_IPL_Set_DM
# =============================================================================
function Image_IPL_Set_DM
{
    # Define local variables
    local i saved_system load_parameter parameter_string

    # Define info for parser
    desc="Lock image's directory or one of image's devices"
    required=("    -n | --name            saved segment name or device address")
    optional=("    -l | --load            load parameters" \
              "    -p | --parm            IPL parameters")
    opts="n:l:p:"
    optl="name:,load:,parm:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Initialize optional fields
    load_parameter=""
    parameter_string=""

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -n | --name)
                i=$(( i + 1 ))
                saved_system="${argv[i]}"
            ;;

            -l | --load)
                i=$(( i + 1 ))
                load_parameter="${argv[i]}"
            ;;

            -p | --parm)
                i=$(( i + 1 ))
                parameter_string="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${saved_system}") \
            $(string "${load_parameter}") \
            $(string "${parameter_string}")

    # Tell user it was successful
    echo "IPL statement set in ${smtarg}"
}

# =============================================================================
# SMAPI Function: Image_Lock_DM
# =============================================================================
function Image_Lock_DM
{
    # Define local variables
    local i device_address

    # Define info for parser
    desc="Lock image or one of its devices"
    required=()
    optional=("    -a | --addr            device address")
    opts="a:"
    optl="addr:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Initialize optional fields
    device_address=""

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -a | --addr)
                i=$(( i + 1 ))
                device_address="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${device_address}")

    # Tell user it was successful
    if [ -z "${device_address}" ]
    then
        echo "${smtarg}'s locked"
    else
        echo "${smtarg}'s ${device_address} disk locked"
    fi
}

# =============================================================================
# SMAPI Function: Image_Name_Query_DM
# =============================================================================
function Image_Name_Query_DM
{
    # Define local variables
    local

    # Define info for parser
    desc="Retrieve list of defined virtual images"
    required=()
    optional=()
    opts=""
    optl=""
    usesparms="n"

    # Parse the command line
    parseopts

    # Build and send the request
    execute

    # Retrieve and show the returned array
    showstringarray
}

# =============================================================================
# SMAPI Function: Image_Password_Set_DM
# =============================================================================
function Image_Password_Set_DM
{
    # Define local variables
    local i image_password

    # Define info for parser
    desc="Set password/passphrase for image"
    required=("    -p | --pass            image password/passphrase")
    optional=()
    opts="p:"
    optl="pass:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -p | --pass)
                i=$(( i + 1 ))
                image_password="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${image_password}")

    # Tell user it was successful
    echo "Password/passphrase changed for ${smtarg}"
}

# =============================================================================
# SMAPI Function: Image_Query_Activate_Time
# =============================================================================
function Image_Query_Activate_Time
{
    # Define local variables
    local i date_format_indicator
    local  image_name activation_date activation_time

    # Define info for parser
    desc="Query date/time when image was activated"
    required=()
    optional=("    -f | --format          date format" \
              "                           : 1 = mm/dd/yy" \
              "                           : 2 = mm/dd/yyyy" \
              "                           : 3 = yy-mm-dd" \
              "                           : 4 = yyyy-mm-dd" \
              "                           : 5 = dd/mm/yy" \
              "                           : 6 = dd/mm/yyyy")
    opts="f:"
    optl="format:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Initialize optional fields
    date_format_indicator="1"

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -f | --format)
                i=$(( i + 1 ))
                date_format_indicator="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(int1 "${date_format_indicator}")

    # Retrieve returned values
    getstring image_name
    getstring activation_date
    getstring activation_time

    # Show them to the user
    echo "${image_name} was activated on ${activation_date} at ${activation_time}"
}

# =============================================================================
# SMAPI Function: Image_Query_DM
# =============================================================================
function Image_Query_DM
{
    # Define local variables
    local

    # Define info for parser
    desc="Retrieve image's directory entry"
    required=()
    optional=()
    opts=""
    optl=""
    usesparms="n"

    # Parse the command line
    parseopts

    # Build and send the request
    execute

    # Retrieve and show the returned array
    showstringarray
}

# =============================================================================
# SMAPI Function: Image_Recycle
# =============================================================================
function Image_Recycle
{
    # Define local variables
    local recycled not_recycled image_name
    local failing_array_length failing_structure_length

    # Define info for parser
    desc="Activate image(s)"
    required=()
    optional=()
    opts=""
    optl=""
    usesparms="n"

    # Parse the command line
    parseopts

    # Build and send the request
    execute_no_check

    # It was partially successful...show user what didn't recycle
    if [ ${retc} -eq 200 -a ${reas} -eq 28 ]
    then
        # Retrieve the return values
        get4 recycled
        get4 not_recycled

        # Show them to the user
        echo "Number of images recycled: ${recycled}"
        echo "Number of images not recycled: ${not_recycled}"
    
        # Retrieve the length of the returned array
        get4 failing_array_length

        # Retrieve and process array entries
        while [ $failing_array_length -gt 0 ]
        do
            # Retrieve the entry length
            get4 failing_structure_length
    
            # Protect against empty entries
            if [ $failing_structure_length -gt 0 ]
            then
                # Retrieve the entry fields
                getstring image_name
                get4 retr
                get4 reas

                # Tell the user why this one failed
                echo "Activation of ${image_name} failed due to: "
                showerror
                echo
            fi
    
            # Calculate remaining length (+4 for the "failing_structure_length" itself)
            failing_array_length=$(( failing_array_length - 4 - failing_structure_length ))
        done

        # Bail since we handled this error specifically
        return
    fi

    # Check for error
    checkandfail

    # Tell user it was successful
    echo "${smtarg} recycled"
}

# =============================================================================
# SMAPI Function: Image_Replace_DM
# =============================================================================
function Image_Replace_DM
{
    # Define local variables
    local image_record_array

    # Define info for parser
    desc="Replace image's directory entry"
    required=()
    optional=()
    opts=""
    optl=""
    usesparms="n"

    # Parse the command line
    parseopts

    # Load array from stdin
    loadarray image_record_array

    # Build and send the request
    execute $(stringarray "${image_record_array[@]}")

    # Tell user it was successful
    echo "${smtarg}'s directory entry replaced"
}

# =============================================================================
# SMAPI Function: Image_SCSI_Characteristics_Define_DM
# =============================================================================
function Image_SCSI_Characteristics_Define_DM
{
    # Define local variables
    local i boot_program BR_LBA LUN port_name SCP_data_type SCP_data

    # Define info for parser
    desc="Define SCSI boot characteristics for image"
    required=()
    optional=("    -b | --boot            boot program number or \"DELETE\"" \
              "    -a | --addr            logical block address of boot record or \"DELETE\"" \
              "    -l | --lun             logical unit number or \"DELETE\"" \
              "    -p | --port            port name or \"DELETE\"" \
              "    -t | --type            SCP data type, 0 - 3" \
              "    -d | --data            SCP data (format based on --type)")
    opts="b:a:l:p:t:d:"
    optl="boot:,addr:,lun:,port:,type:,data:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Initialize optional fields
    boot_program=""
    BR_LBA=""
    LUN=""
    port_name=""
    SCP_data_type="0"
    SCP_data=""

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -b | --boot)
                i=$(( i + 1 ))
                boot_program="${argv[i]}"
            ;;

            -a | --addr)
                i=$(( i + 1 ))
                BR_LBA="${argv[i]}"
            ;;

            -l | --lun)
                i=$(( i + 1 ))
                LUN="${argv[i]}"
            ;;

            -p | --port)
                i=$(( i + 1 ))
                port_name="${argv[i]}"
            ;;

            -t | --type)
                i=$(( i + 1 ))
                SCP_data_type="${argv[i]}"
            ;;

            -d | --data)
                i=$(( i + 1 ))
                SCP_data="${argv[i]}"
            ;;
        esac
    done

    # Convert SCP_data to EBCDIC if necessary
    if [ "${SCP_data_type}" == "2" ]
    then
        SCP_data=$(echo -n "${SCP_data}" | dd conv=ebcdic)
    fi

    # Build and send the request
    execute $(string "${boot_program}") \
            $(string "${BR_LBA}") \
            $(string "${LUN}") \
            $(string "${port_name}") \
            $(int1 "${SCP_data_type}") \
            $(string "${SCP_data}")

    # Tell user it was successful
    echo "${smtarg}'s SCSI characteristics updated"
}

# =============================================================================
# SMAPI Function: Image_SCSI_Characteristics_Query_DM
# =============================================================================
function Image_SCSI_Characteristics_Query_DM
{
    # Define local variables
    local boot_program BR_LBA LUN port_name SCP_data_type SCP_data

    # Define info for parser
    desc="Query SCSI boot characteristics for image"
    required=()
    optional=()
    opts=""
    optl=""
    usesparms="n"

    # Parse the command line
    parseopts

    # Build and send the request
    execute

    # Retrieve the length of the returned array
    getstring boot_program
    getstring BR_LBA
    getstring LUN
    getstring port_name
    get1 SCP_data_type
    getstring SCP_data

    # Convert SCP_data to ASCII if necessary
    if [ "${SCP_data_type}" == "2" ]
    then
        SCP_data=$(echo -n "${SCP_data}" | dd conv=ascii)
    fi

    # Show them to the user
    echo "Boot program number: ${boot_program}"
    echo "LBA of boot record: ${BR_LBA}"
    echo "Logical unit number: ${LUN}"
    echo "Port name: ${port_name}"
    echo "SCP data type: ${SCP_data_type}"
    echo "SCP data: ${SCP_data}"
}

# =============================================================================
# SMAPI Function: Image_Status_Query
# =============================================================================
function Image_Status_Query
{
    # Define local variables
    local

    # Define info for parser
    desc="Determine active state of image(s)"
    required=()
    optional=()
    opts=""
    optl=""
    usesparms="n"

    # Parse the command line
    parseopts

    # Build and send the request
    execute

    # Retrieve and show the returned array
    showstringarray
}

# =============================================================================
# SMAPI Function: Image_Unlock_DM
# =============================================================================
function Image_Unlock_DM
{
    # Define local variables
    local i device_address

    # Define info for parser
    desc="Unlock image or one of its devices"
    required=()
    optional=("    -a | --addr            device address")
    opts="a:"
    optl="addr:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Initialize optional fields
    device_address=""

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -a | --addr)
                i=$(( i + 1 ))
                device_address="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${device_address}")

    # Tell user it was successful
    if [ -z "${device_address}" ]
    then
        echo "${smtarg}'s directory unlocked"
    else
        echo "${smtarg}'s ${device_address} disk unlocked"
    fi
}

# =============================================================================
# SMAPI Function: Image_Volume_Add
# =============================================================================
function Image_Volume_Add
{
    # Define local variables
    local i
    local image_device_number image_vol_id
    local system_config_name system_config_type
    local parm_disk_owner parm_disk_number parm_disk_password
    local alt_system_config_name alt_system_config_type
    local alt_parm_disk_owner alt_parm_disk_number alt_parm_disk_password

    # Define info for parser
    desc="Add a DASD volume to system configuration file"
    required=("    -a | --addr            device address" \
              "    -l | --label           volume label")
    optional=("         --confname        system config name (default SYSTEM)" \
              "         --conftype        system config type (default CONFIG)" \
              "         --parmowner       parm disk owner (default MAINT)" \
              "         --parmaddr        parm disk address (default CF1)" \
              "         --parmpass        parm disk password (default \",\")" \
              "         --altname         alternate system config name (default SYSTEM)" \
              "         --alttype         alternate system config type (default CONFIG)" \
              "         --altowner        alternate parm disk owner (default MAINT)" \
              "         --altaddr         alternate parm disk address (default CF2)" \
              "         --altpass         alternate parm disk password (default \",\")")
    opts="a:l:"
    optl="addr:,label:"
    optl="${optl},confname:,conftype:,parmowner:,parmaddr:,parmpass:"
    optl="${optl},altname:,alttype:,altowner:,altaddr:,altpass:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Initialize optional variables
    system_config_name=""
    system_config_type=""
    parm_disk_owner=""
    parm_disk_number=""
    parm_disk_password=""
    alt_system_config_name=""
    alt_system_config_type=""
    alt_parm_disk_owner=""
    alt_parm_disk_number=""
    alt_parm_disk_password=""
    
    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -a | --addr)
                i=$(( i + 1 ))
                image_device_number="${argv[i]}"
            ;;

            -l | --label)
                i=$(( i + 1 ))
                image_vol_id="${argv[i]}"
            ;;

            --confname)
                i=$(( i + 1 ))
                system_config_name="${argv[i]}"
            ;;

            --conftype)
                i=$(( i + 1 ))
                system_config_type="${argv[i]}"
            ;;

            --parmowner)
                i=$(( i + 1 ))
                parm_disk_owner="${argv[i]}"
            ;;

            --parmaddr)
                i=$(( i + 1 ))
                parm_disk_number="${argv[i]}"
            ;;

            --parmpass)
                i=$(( i + 1 ))
                parm_disk_password="${argv[i]}"
            ;;

            --altname)
                i=$(( i + 1 ))
                alt_system_config_name="${argv[i]}"
            ;;

            --alttype)
                i=$(( i + 1 ))
                alt_system_config_type="${argv[i]}"
            ;;

            --altowner)
                i=$(( i + 1 ))
                alt_parm_disk_owner="${argv[i]}"
            ;;

            --altaddr)
                i=$(( i + 1 ))
                alt_parm_disk_number="${argv[i]}"
            ;;

            --altpass)
                i=$(( i + 1 ))
                alt_parm_disk_password="${argv[i]}"
            ;;
       esac
    done

    # Build and send the request
    execute $(string "${image_device_number}") \
            $(string "${image_vol_id}") \
            $(string "${system_config_name}") \
            $(string "${system_config_type}") \
            $(string "${parm_disk_owner}") \
            $(string "${parm_disk_number}") \
            $(string "${parm_disk_password}") \
            $(string "${alt_system_config_name}") \
            $(string "${alt_system_config_type}") \
            $(string "${alt_parm_disk_owner}") \
            $(string "${alt_parm_disk_number}") \
            $(string "${alt_parm_disk_password}")

    # Tell user it was successful
    echo "${image_device_number} with label of ${image_vol_id} added to system configuration"
}

# =============================================================================
# SMAPI Function: Image_Volume_Delete
# =============================================================================
function Image_Volume_Delete
{
    # Define local variables
    local i
    local image_device_number image_vol_id
    local system_config_name system_config_type
    local parm_disk_owner parm_disk_number parm_disk_password
    local alt_system_config_name alt_system_config_type
    local alt_parm_disk_owner alt_parm_disk_number alt_parm_disk_password

    # Define info for parser
    desc="Delete a DASD volume from system configuration file"
    required=("    -a | --addr            device address" \
              "    -l | --label           volume label")
    optional=("         --confname        system config name (default SYSTEM)" \
              "         --conftype        system config type (default CONFIG)" \
              "         --parmowner       parm disk owner (default MAINT)" \
              "         --parmaddr        parm disk address (default CF1)" \
              "         --parmpass        parm disk password (default \",\")" \
              "         --altname         alternate system config name (default SYSTEM)" \
              "         --alttype         alternate system config type (default CONFIG)" \
              "         --altowner        alternate parm disk owner (default MAINT)" \
              "         --altaddr         alternate parm disk address (default CF2)" \
              "         --altpass         alternate parm disk password (default \",\")")
    opts="a:l:"
    optl="addr:,label:"
    optl="${optl},confname:,conftype:,parmowner:,parmaddr:,parmpass:"
    optl="${optl},altname:,alttype:,altowner:,altaddr:,altpass:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Initialize optional variables
    system_config_name=""
    system_config_type=""
    parm_disk_owner=""
    parm_disk_number=""
    parm_disk_password=""
    alt_system_config_name=""
    alt_system_config_type=""
    alt_parm_disk_owner=""
    alt_parm_disk_number=""
    alt_parm_disk_password=""
    
    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -a | --addr)
                i=$(( i + 1 ))
                image_device_number="${argv[i]}"
            ;;

            -l | --label)
                i=$(( i + 1 ))
                image_vol_id="${argv[i]}"
            ;;

            --confname)
                i=$(( i + 1 ))
                system_config_name="${argv[i]}"
            ;;

            --conftype)
                i=$(( i + 1 ))
                system_config_type="${argv[i]}"
            ;;

            --parmowner)
                i=$(( i + 1 ))
                parm_disk_owner="${argv[i]}"
            ;;

            --parmaddr)
                i=$(( i + 1 ))
                parm_disk_number="${argv[i]}"
            ;;

            --parmpass)
                i=$(( i + 1 ))
                parm_disk_password="${argv[i]}"
            ;;

            --altname)
                i=$(( i + 1 ))
                alt_system_config_name="${argv[i]}"
            ;;

            --alttype)
                i=$(( i + 1 ))
                alt_system_config_type="${argv[i]}"
            ;;

            --altowner)
                i=$(( i + 1 ))
                alt_parm_disk_owner="${argv[i]}"
            ;;

            --altaddr)
                i=$(( i + 1 ))
                alt_parm_disk_number="${argv[i]}"
            ;;

            --altpass)
                i=$(( i + 1 ))
                alt_parm_disk_password="${argv[i]}"
            ;;
       esac
    done

    # Build and send the request
    execute $(string "${image_device_number}") \
            $(string "${image_vol_id}") \
            $(string "${system_config_name}") \
            $(string "${system_config_type}") \
            $(string "${parm_disk_owner}") \
            $(string "${parm_disk_number}") \
            $(string "${parm_disk_password}") \
            $(string "${alt_system_config_name}") \
            $(string "${alt_system_config_type}") \
            $(string "${alt_parm_disk_owner}") \
            $(string "${alt_parm_disk_number}") \
            $(string "${alt_parm_disk_password}")

    # Tell user it was successful
    echo "${image_device_number} with label of ${image_vol_id} deleted from system configuration"
}

# =============================================================================
# SMAPI Function: Image_Volume_Share
# =============================================================================
function Image_Volume_Share
{
    # Define local variables
    local 

    # Define info for parser
    desc="Share full-pack minidisk"

    # Build and send request
    execute_keywords 
    
    # Tell user it was successful
    echo "Volume shared"
}

# =============================================================================
# SMAPI Function: Image_Volume_Space_Define_DM
# =============================================================================
function Image_Volume_Space_Define_DM
{
    # Define local variables
    local i
    local function_type region_name image_vol_id
    local start_cylinder size group_name device_type

    # Define info for parser
    desc="Make DASD space available for use by images"
    required=("    -f | --func            function type" \
              "                           : 1 = define region" \
              "                           : 2 = define region, add to group" \
              "                           : 3 = define region as full volume" \
              "                           : 4 = define region as full volume, add to group" \
              "                           : 5 = add existing region to group" \
              "    -r | --region          region name")
    optional=("    -v | --vol             volume label (funcs: 1, 2, 3, 4)" \
              "    -s | --start           starting cylinder (funcs: 1, 2)" \
              "    -c | --cyls            number of cylinders (funcs: 1, 2)" \
              "    -g | --group           group name (funcs: 2, 4, 5)" \
              "    -t | --type            device type (funcs: 1, 2)" \
              "                           : 0 = Unspecified" \
              "                           : 1 = 3390" \
              "                           : 2 = 9336" \
              "                           : 3 = 3380" \
              "                           : 4 = FB-512")
    opts="f:r:v:s:c:g:t:"
    optl="func:,region:,vol:,start:,cyls:,group:,type:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Initialize optional variables
    image_vol_id=""
    start_cylinder="-1"
    size="-1"
    group_name=""
    device_type="0"
    
    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -f | --func)
                i=$(( i + 1 ))
                function_type="${argv[i]}"
            ;;

            -r | --region)
                i=$(( i + 1 ))
                region_name="${argv[i]}"
            ;;

            -v | --vol)
                i=$(( i + 1 ))
                image_vol_id="${argv[i]}"
            ;;

            -s | --start)
                i=$(( i + 1 ))
                start_cylinder="${argv[i]}"
            ;;

            -c | --cyls)
                i=$(( i + 1 ))
                size="${argv[i]}"
            ;;

            -g | --group)
                i=$(( i + 1 ))
                group_name="${argv[i]}"
            ;;

            -t | --type)
                i=$(( i + 1 ))
                device_type="${argv[i]}"
            ;;
       esac
    done

    # Build and send the request
    execute $(int1 "${function_type}") \
            $(string "${region_name}") \
            $(string "${image_vol_id}") \
            $(int4 "${start_cylinder}") \
            $(int4 "${size}") \
            $(string "${group_name}") \
            $(int1 "${device_type}")

    # Tell user it was successful
    echo "Region ${region_name} made available for allocation"
}

# =============================================================================
# SMAPI Function: Image_Volume_Space_Define_Extended_DM
# =============================================================================
function Image_Volume_Space_Define_Extended_DM
{
    # Define local variables
    local

    # Define info for parser
    desc="Define space on DASD volume"
    required=()
    optional=()
    opts=""
    optl=""
    usesparms="o"

    # Parse the command line
    parseopts

    # Build and send the request
    execute $(int4 $(( ${#addparms} / 2 ))) \
                   $addparms}

    # Tell user it was successful
    echo "Space defined"
}

# =============================================================================
# SMAPI Function: Image_Volume_Space_Query_DM
# =============================================================================
function Image_Volume_Space_Query_DM
{
    # Define local variables
    local i
    local query_type entry_type entry_names

    # Define info for parser
    desc="Query space allocations for images"
    required=("    -q | --query           query type" \
              "                           : 1 = volume definition" \
              "                           : 2 = free space" \
              "                           : 3 = used space" \
              "    -e | --entity          entity type" \
              "                           : 1 = query specified volume" \
              "                           : 2 = query specified region" \
              "                           : 3 = query specified group")
    optional=("    -n | --names           entry names")
    opts="q:e:n:"
    optl="query:,entity:,names:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Initialize optional variables
    entry_names=""
    
    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -q | --query)
                i=$(( i + 1 ))
                query_type="${argv[i]}"
            ;;

            -e | --entity)
                i=$(( i + 1 ))
                entity_type="${argv[i]}"
            ;;

            -n | --names)
                i=$(( i + 1 ))
                entry_names="${argv[i]}"
            ;;
       esac
    done

    # Build and send the request
    execute $(int1 "${query_type}") \
            $(int1 "${entity_type}") \
            $(string "${entry_names}")

    # Retrieve and show the returned array
    showstringarray
}

# =============================================================================
# SMAPI Function: Image_Volume_Space_Query_Extended_DM
# =============================================================================
function Image_Volume_Space_Query_Extended_DM
{
    # Define local variables
    local

    # Define info for parser
    desc="Define space on DASD volume"
    required=()
    optional=()
    opts=""
    optl=""
    usesparms="o"

    # Parse the command line
    parseopts

    # Set defaults
    query_type=""
    entry_type=""

    # First option must be positional indicator
    if [ "${argv[0]}" == "--" ]
    then
        # Process options
        for (( i = 1; i < ${#argv[@]}; i++ ))
        do
            arg=$(tr <<<"${argv[i]}" "[:upper:]" "[:lower:]")
            case "${arg%=*}" in
                query_type) query_type="${arg#*=}" ;;
                entry_type) entry_type="${arg#*=}" ;;
            esac
        done
    fi

    # Complain if no additional parms were specified
    if [ -z "${addparms}" ]
    then
        echo "Additional parameters not specified"
        exit 1
    fi

    # Build and send the request
    execute $(int4 $(( ${#addparms} / 2 ))) \
                   $addparms}

    # Show each entry until nothing left
    while [ ${#resp} -gt 0 ]
    do
        getasciiz record_structure
        set -o noglob
        set -- ${record_structure}
        set +o noglob

        if [ "${query_type}" == "1" -a "${entry_type}" == "1" ]
        then
            echo "  Volume ID: ${1}"
            echo "  Device Type: ${2}"
            echo "  Size: ${3}"
            shift 3
            echo "  Regions: ${*}"
        elif [ "${query_type}" == "1" -a "${entry_type}" == "2" ]
        then
            echo "  Region Name: ${1}"
            echo "  Volume ID: ${2}"
            echo "  Start Cylinder: ${3}"
            echo "  Device Type: ${4}"
            echo "  Size: ${5}"
            shift 5
            echo "  Groups: ${*}"
        elif [ "${query_type}" == "1" -a "${entry_type}" == "3" ]
        then
            echo "  Group Name: ${1}"
            echo "  Allocation Method: ${2}"
            shift 2
            echo "  Regions: ${*}"
        elif [ "${query_type}" == "2" ]
        then
            echo "  Volume ID: ${1}"
            echo "  Device Type: ${2}"
            echo "  Start Cylinder: ${3}"
            echo "  Size: ${4}"
            echo "  Group Name: ${5}"
            echo "  Region Name: ${6}"
        elif [ "${query_type}" == "3" ]
        then
            echo "  Volume ID: ${1}"
            echo "  Device Type: ${2}"
            echo "  Start Cylinder: ${3}"
            echo "  Size: ${4}"
            echo "  Owner: ${5}"
            echo "  VADDR: ${6}"
            echo "  Group Name: ${7}"
            echo "  Region Name: ${8}"
            echo "  SSI Node: ${9}"
            shift 9
            echo "  System Affinity: ${*}"
        fi
        echo

    done
}

# =============================================================================
# SMAPI Function: Image_Volume_Space_Remove_DM
# =============================================================================
function Image_Volume_Space_Remove_DM
{
    # Define local variables
    local i
    local function_type region_name image_vol_id group_name

    # Define info for parser
    desc="Remove DASD regions/groups from space pool"
    required=("    -f | --func            function type" \
              "                           : 1 = remove region" \
              "                           : 2 = remove region from group" \
              "                           : 3 = remove region from all groups" \
              "                           : 4 = remove all regions from volume" \
              "                           : 5 = remove all regions from volume and group" \
              "                           : 6 = remove all regions from volume and all groups" \
              "                           : 7 = remove entire group")
    optional=("    -r | --region          region name (funcs: 1, 2, 3)" \
              "    -v | --vol             volume label (funcs: 4, 5, 6)" \
              "    -g | --group           group name (funcs: 2, 5, 7)")
    opts="f:r:v:g:"
    optl="func:,region:,vol:,group:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Initialize optional variables
    region_name=""
    image_vol_id=""
    group_name=""
    
    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -f | --func)
                i=$(( i + 1 ))
                function_type="${argv[i]}"
            ;;

            -r | --region)
                i=$(( i + 1 ))
                region_name="${argv[i]}"
            ;;

            -v | --vol)
                i=$(( i + 1 ))
                image_vol_id="${argv[i]}"
            ;;

            -g | --group)
                i=$(( i + 1 ))
                group_name="${argv[i]}"
            ;;
       esac
    done

    # Build and send the request
    execute $(int1 "${function_type}") \
            $(string "${region_name}") \
            $(string "${image_vol_id}") \
            $(string "${group_name}")

    # Tell user it was successful
    echo "Space allocation pool updated"
}

# =============================================================================
# SMAPI Function: Metadata_Delete
# =============================================================================
function Metadata_Delete
{
    # Define local variables
    local i names

    # Define info for parser
    desc="Delete metadata"
    required=()
    optional=()
    opts=""
    optl=""
    usesparms="r"

    # Parse the command line
    parseopts

    # First option must be positional indicator
    if [ "${argv[0]}" != "--" ]
    then
        echo "Missing name list"
        exit 1
    fi
    
    # Process names
    names=""
    for (( i = 1; i < ${#argv[@]}; i++ ))
    do
        names="${names} ${argv[i]}"
    done

    # Build and send the request
    execute $(asciiz "${names}")

    # Retrieve and show the returned array
    echo "Metadata deleted"
}

# =============================================================================
# SMAPI Function: Metadata_Get
# =============================================================================
function Metadata_Get
{
    # Define local variables
    local i names

    # Define info for parser
    desc="Get metadata"
    required=()
    optional=()
    opts=""
    optl=""
    usesparms="r"

    # Parse the command line
    parseopts

    # First option must be positional indicator
    if [ "${argv[0]}" != "--" ]
    then
        echo "Missing name list"
        exit 1
    fi
    
    # Process names
    names=""
    for (( i = 1; i < ${#argv[@]}; i++ ))
    do
        names="${names} ${argv[i]}"
    done

    # Build and send the request
    execute $(asciiz "${names}")

    # Retrieve the array length
    get4 metadata_entry_array_length

    # Retrieve and process array entries
    while [ ${metadata_entry_array_length} -gt 0 ]
    do
        # Retrieve the entry length
        get4 metadata_entry_structure_length

        # Protect against empty entries
        if [ ${metadata_entry_structure_length} -gt 0 ]
        then
            # Retrieve the entry fields
            get4 metadata_entry_name_length
            getchars ${metadata_entry_name_length} metadata_entry_name
            get4 metadata_length
            getchars ${metadata_length} metadata

            # Show it
            echo "Metadata Entry:"
            echo "  Name: ${metadata_entry_name}"
            echo "  Data: ${metadata}"
        fi
        
        # Calculate remaining length (+4 for the "CPU_info_structure_length" itself)
        metadata_entry_array_length=$(( metadata_entry_array_length - 4 - metadata_entry_structure_length ))
    done
}

# =============================================================================
# SMAPI Function: Metadata_Set
# =============================================================================
function Metadata_Set
{
    # Define local variables
    local i names

    # Define info for parser
    desc="Get metadata"
    required=()
    optional=()
    opts=""
    optl=""
    usesparms="r"

    # Parse the command line
    parseopts

    # First option must be positional indicator
    if [ "${argv[0]}" != "--" ]
    then
        echo "Missing name/value pairs"
        exit 1
    fi
    
    # Ensure we have an even number of arguments
    if [[ "${#argv[@]}" =~ .*[0248] ]]
    then
        echo "Incomplete name/value pairs"
        exit 1
    fi
    
    # Process name/value pairs
    names=""
    for (( i = 1; i < ${#argv[@]}; i += 2 ))
    do
        pair="$(string ${argv[i]})$(string ${argv[i + 1]})"
        pairs="${pairs}$(int4 ${#pair})${pair}"
    done

    # Build and send the request
    execute "$(int4 ${#pairs})${pairs}"

    # Tell user it was successful
    echo "Metadata set"
}

# =============================================================================
# SMAPI Function: Name_List_Add
# =============================================================================
function Name_List_Add
{
    # Define local variables
    local i name

    # Define info for parser
    desc="Add a userid or function name to a list"
    required=("    -n | --name            name to add")
    optional=()
    opts="n:"
    optl="name:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -n | --name)
                i=$(( i + 1 ))
                name="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${name}")

    # Tell user it was successful
    echo "${name} added to the ${smtarg} list"
}

# =============================================================================
# SMAPI Function: Name_List_Destroy
# =============================================================================
function Name_List_Destroy
{
    # Define local variables
    local

    # Define info for parser
    desc="Destroy an entire list"
    required=()
    optional=()
    opts=""
    optl=""
    usesparms="n"

    # Parse the command line
    parseopts

    # Build and send the request
    execute

    # Tell user it was successful
    echo "${smtarg} destroyed"
}

# =============================================================================
# SMAPI Function: Name_List_Query
# =============================================================================
function Name_List_Query
{
    # Define local variables
    local

    # Define info for parser
    desc="Query names in a list or names of the available lists"
    required=()
    optional=()
    opts=""
    optl=""
    usesparms="n"

    # Parse the command line
    parseopts

    # Build and send the request
    execute

    # Retrieve and show the returned array
    showstringarray
}

# =============================================================================
# SMAPI Function: Name_List_Remove
# =============================================================================
function Name_List_Remove
{
    # Define local variables
    local i name

    # Define info for parser
    desc="Remove a userid or function name from a list"
    required=("    -n | --name            name to remove")
    optional=()
    opts="n:"
    optl="name:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -n | --name)
                i=$(( i + 1 ))
                name="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${name}")

    # Tell user it was successful
    echo "${name} removed from the ${smtarg} list"
}

# =============================================================================
# SMAPI Function: Page_or_Spool_Volume_Add
# =============================================================================
function Page_or_Spool_Volume_Add
{
    # Define local variables
    local

    # Define info for parser
    desc="Add a page or spool volume to the system"

    # Build and send the request
    execute_keywords

    # Tell user it was successful
    echo "Volume added"
}

# =============================================================================
# SMAPI Function: Process_ABEND_Dump
# =============================================================================
function Process_ABEND_Dump
{
    # Define local variables
    local 

    # Define info for parser
    desc="Process and abend dump"

    # Build and send request
    execute_keywords 
    
    # Tell user it was successful
    echo "Dump processed"
}

# =============================================================================
# SMAPI Function: Profile_Create_DM
# =============================================================================
function Profile_Create_DM
{
    # Define local variables
    local profile_record_array

    # Define info for parser
    desc="Create a profile"
    required=()
    optional=()
    opts=""
    optl=""
    usesparms="n"

    # Parse the command line
    parseopts

    # Load array from stdin
    loadarray profile_record_array

    # Build and send the request
    execute $(stringarray "${profile_record_array[@]}")

    # Tell user it was successful
    echo "${smtarg} profile created"
}

# =============================================================================
# SMAPI Function: Profile_Delete_DM
# =============================================================================
function Profile_Delete_DM
{
    # Define local variables
    local

    # Define info for parser
    desc="Delete a profile"
    required=()
    optional=()
    opts=""
    optl=""
    usesparms="n"

    # Parse the command line
    parseopts

    # Build and send the request
    execute

    # Tell user it was successful
    echo "${smtarg} profile deleted"
}

# =============================================================================
# SMAPI Function: Profile_Lock_DM
# =============================================================================
function Profile_Lock_DM
{
    # Define local variables
    local

    # Define info for parser
    desc="Lock a profile"
    required=()
    optional=()
    opts=""
    optl=""
    usesparms="n"

    # Parse the command line
    parseopts

    # Build and send the request
    execute

    # Tell user it was successful
    echo "${smtarg} profile locked"
}

# =============================================================================
# SMAPI Function: Profile_Query_DM
# =============================================================================
function Profile_Query_DM
{
    # Define local variables
    local

    # Define info for parser
    desc="Retrieve a profile"
    required=()
    optional=()
    opts=""
    optl=""
    usesparms="n"

    # Parse the command line
    parseopts

    # Build and send the request
    execute

    # Retrieve and show the returned array
    showstringarray
}

# =============================================================================
# SMAPI Function: Profile_Replace_DM
# =============================================================================
function Profile_Replace_DM
{
    # Define local variables
    local profile_record_array

    # Define info for parser
    desc="Replace a profile"
    required=()
    optional=()
    opts=""
    optl=""
    usesparms="n"

    # Parse the command line
    parseopts

    # Load array from stdin
    loadarray profile_record_array

    # Build and send the request
    execute $(stringarray "${profile_record_array[@]}")

    # Tell user it was successful
    echo "${smtarg} profile replaced"
}

# =============================================================================
# SMAPI Function: Profile_Unlock_DM
# =============================================================================
function Profile_Unlock_DM
{
    # Define local variables
    local

    # Define info for parser
    desc="Unlock a profile"
    required=()
    optional=()
    opts=""
    optl=""
    usesparms="n"

    # Parse the command line
    parseopts

    # Build and send the request
    execute

    # Tell user it was successful
    echo "${smtarg} profile unlocked"
}

# =============================================================================
# SMAPI Function: Prototype_Create_DM
# =============================================================================
function Prototype_Create_DM
{
    # Define local variables
    local prototype_record_array

    # Define info for parser
    desc="Create prototype"
    required=()
    optional=()
    opts=""
    optl=""
    usesparms="n"

    # Parse the command line
    parseopts

    # Load array from stdin
    loadarray prototype_record_array

    # Build and send the request
    execute $(stringarray "${prototype_record_array[@]}")

    # Tell user it was successful
    echo "${smtarg} prototype created"
}

# =============================================================================
# SMAPI Function: Prototype_Delete_DM
# =============================================================================
function Prototype_Delete_DM
{
    # Define local variables
    local

    # Define info for parser
    desc="Delete prototype"
    required=()
    optional=()
    opts=""
    optl=""
    usesparms="n"

    # Parse the command line
    parseopts

    # Build and send the request
    execute

    # Tell user it was successful
    echo "${smtarg} prototype deleted"
}

# =============================================================================
# SMAPI Function: Prototype_Name_Query_DM
# =============================================================================
function Prototype_Name_Query_DM
{
    # Define local variables
    local

    # Define info for parser
    desc="Retrieve list of defined prototypes"
    required=()
    optional=()
    opts=""
    optl=""
    usesparms="n"

    # Parse the command line
    parseopts

    # Build and send the request
    execute

    # Retrieve and show the returned array
    showstringarray
}

# =============================================================================
# SMAPI Function: Prototype_Query_DM
# =============================================================================
function Prototype_Query_DM
{
    # Define local variables
    local

    # Define info for parser
    desc="Retrieve prototype"
    required=()
    optional=()
    opts=""
    optl=""
    usesparms="n"

    # Parse the command line
    parseopts

    # Build and send the request
    execute

    # Retrieve and show the returned array
    showstringarray
}

# =============================================================================
# SMAPI Function: Prototype_Replace_DM
# =============================================================================
function Prototype_Replace_DM
{
    # Define local variables
    local prototype_record_array

    # Define info for parser
    desc="Replace prototype"
    required=()
    optional=()
    opts=""
    optl=""
    usesparms="n"

    # Parse the command line
    parseopts

    # Load array from stdin
    loadarray prototype_record_array

    # Build and send the request
    execute $(stringarray "${prototype_record_array[@]}")

    # Tell user it was successful
    echo "${smtarg} prototype replaced"
}

# =============================================================================
# SMAPI Function: Query_ABEND_Dump
# =============================================================================
function Query_ABEND_Dump
{
    # Define local variables
    local 

    # Define info for parser
    desc="Display current dump information"

    # Build and send request
    execute_keywords 
    
    # Tell user it was successful
    echo "Dump deletion requested"
}

# =============================================================================
# SMAPI Function: Query_All_DM
# =============================================================================
function Query_All_DM
{
    # Define local variables
    local i format

    # Define info for parser
    desc="Create new virtual machine entry"
    required=()
    optional=()
    opts=""
    optl=""
    usesparms="o"

    # Parse the command line
    parseopts

    # Set to API default
    format="yes"

    # First option must be positional indicator
    if [ "${argv[0]}" == "--" ]
    then
        # Process options
        for (( i = 1; i < ${#argv[@]}; i++ ))
        do
            if [[ "${argv[i]}" =~ [Ff][Oo][Rr][Mm][Aa][Tt]=[Nn].* ]]
            then
                format="no"
            fi
        done
    fi

    # Complain if no additional parms were specified
    if [ -z "${addparms}" ]
    then
        echo "Additional parameters not specified"
        exit 1
    fi

    # Build and send the request
    execute $(int4 $(( ${#addparms} / 2 ))) \
                   ${addparms}

    # Retrieve the array length
    get4 directory_entries_array_length

    # Retrieve and process array entries
    while [ ${directory_entries_array_length} -gt 0 ]
    do
        # Retrieve the entry length
        get4 directory_entry_structure_length

        # Protect against empty entries
        if [ ${directory_entry_structure_length} -gt 0 ]
        then
            # Retrieve the entry fields
            get4 directory_entry_type
            getstring directory_entry_id

            # Convert directory_entry_type
            case "${directory_entry_type}" in
                0) directory_entry_type="${directory_entry_type} (USER)" ;;
                1) directory_entry_type="${directory_entry_type} (PROFILE)" ;;
                2) directory_entry_type="${directory_entry_type} (USER)" ;;
                3) directory_entry_type="${directory_entry_type} (POOL)" ;;
                4) directory_entry_type="${directory_entry_type} (DIRECTORY)" ;;
                5) directory_entry_type="${directory_entry_type} (GLOBAL)" ;;
                6) directory_entry_type="${directory_entry_type} (IDENTITY)" ;;
                7) directory_entry_type="${directory_entry_type} (SUBCONFIG)" ;;
                8) directory_entry_type="${directory_entry_type} (OTHER)" ;;
                *) directory_entry_type="${directory_entry_type} (?)" ;;
            esac

            # Show it to the user
            echo "Type:  ${directory_entry_type}"
            echo "ID:    ${directory_entry_id}"

            if [ "${format}" = "yes" ]
            then
                get4 directory_entry_data_length
                showasciizarray ${directory_entry_data_length}
            else
                showstringarray
            fi
        fi
        
        # Calculate remaining length (+4 for the "CPU_info_structure_length" itself)
        directory_entries_array_length=$(( directory_entries_array_length - 4 - directory_entry_structure_length ))
    done
}

# =============================================================================
# SMAPI Function: Query_API_Functional_Level
# =============================================================================
function Query_API_Functional_Level
{
    # Define local variables
    local

    # Define info for parser
    desc="Query level of API"
    required=()
    optional=()
    opts=""
    optl=""
    usesparms="n"

    # Parse the command line
    parseopts

    # Build and send the request
    execute_no_check
    
    # Show the level to the user
    showerror

    # Bail if unsuccessful
    if [ ${retc} -ne 0 ]
    then
        exit 1
    fi
}

# =============================================================================
# SMAPI Function: Query_Asynchronous_Operation_DM
# =============================================================================
function Query_Asynchronous_Operation_DM
{
    # Define local variables
    local i operation_id

    # Define info for parser
    desc="Query status of an asynchronous operation"
    required=("    -o | --opid            operationl id")
    optional=()
    opts="o:"
    optl="opid:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -o | --opid)
                i=$(( i + 1 ))
                operation_id="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute_no_check $(int4 "${operation_id}")

    # Show the user the status
    showerror

    # Bail if unsuccessful
    if [ ${retc} -ne 0 ]
    then
        exit 1
    fi
}

# =============================================================================
# SMAPI Function: Query_Directory_Manager_Level_DM
# =============================================================================
function Query_Directory_Manager_Level_DM
{
    # Define local variables
    local directory_manager_level

    # Define info for parser
    desc="Query directory manager level"
    required=()
    optional=()
    opts=""
    optl=""
    usesparms="n"

    # Parse the command line
    parseopts

    # Build and send the request
    execute

    # Retrieve return values
    getstring directory_manager_level
    
    # Tell user it was successful
    echo "${directory_manager_level}"
}

# =============================================================================
# SMAPI Function: Response_Recovery
# =============================================================================
function Response_Recovery
{
    # Define local variables
    local i request_id

    # Define info for parser
    desc="Recover previosly failed response data"
    required=("    -r | --reqid           request id")
    optional=()
    opts="r:"
    optl="reqid:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -r | --reqid)
                i=$(( i + 1 ))
                request_id="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(int4 "${request_id}")

    # Show the user the status
    showerror

    # Bail if unsuccessful
    if [ ${retc} -ne 0 ]
    then
        exit 1
    fi
}

# =============================================================================
# SMAPI Function: Shared_Memory_Access_Add_DM
# =============================================================================
function Shared_Memory_Access_Add_DM
{
    # Define local variables
    local i memory_segment_name

    # Define info for parser
    desc="Add restricted access to a memory segment"
    required=("    -n | --name            name of memory segment")
    optional=()
    opts="n:"
    optl="name:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -n | --name)
                i=$(( i + 1 ))
                memory_segment_name="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${memory_segment_name}")

    # Tell user it was successful
    echo "${smtarg} access added to memory segment ${memory_segment_name}"
}

# =============================================================================
# SMAPI Function: Shared_Memory_Access_Query_DM
# =============================================================================
function Shared_Memory_Access_Query_DM
{
    # Define local variables
    local i memory_segment_name

    # Define info for parser
    desc="Query restricted access to a memory segment"
    required=("    -n | --name            name of memory segment")
    optional=()
    opts="n:"
    optl="name:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -n | --name)
                i=$(( i + 1 ))
                memory_segment_name="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${memory_segment_name}")

    # Retrieve and show the returned array
    showstringarray
}

# =============================================================================
# SMAPI Function: Shared_Memory_Access_Remove_DM
# =============================================================================
function Shared_Memory_Access_Remove_DM
{
    # Define local variables
    local i memory_segment_name

    # Define info for parser
    desc="Remove restricted access to a memory segment"
    required=("    -n | --name            name of memory segment")
    optional=()
    opts="n:"
    optl="name:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -n | --name)
                i=$(( i + 1 ))
                memory_segment_name="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${memory_segment_name}")

    # Tell user it was successful
    echo "${smtarg} access removed to memory segment ${memory_segment_name}"
}

# =============================================================================
# SMAPI Function: Shared_Memory_Create
# =============================================================================
function Shared_Memory_Create
{
    # Define local variables
    local i memory_segment_name begin_page end_page
    local page_access_descriptor memory_attributes
    local memory_access_identifier

    # Define info for parser
    desc="Create a shared memory segment"
    required=("    -n | --name            name of memory segment" \
              "    -b | --begin           beginning page (hex)" \
              "    -e | --end             ending page (hex)" \
              "    -d | --desc            page access descriptor" \
              "                           : 1 = SW" \
              "                           : 2 = EW" \
              "                           : 3 = SR" \
              "                           : 4 = ER" \
              "                           : 5 = SN" \
              "                           : 6 = EN" \
              "                           : 7 = SC")
    optional=("    -a | --attr            memory attributes" \
              "                           : 0 = Unspecified" \
              "                           : 1 = RSTD" \
              "                           : 2 = UNRSTD" \
              "    -i | --id              memory access ID")
    opts="n:b:e:d:a:i:"
    optl="name:,begin:,end:,desc:,attr:,id:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Initialize optional variables
    memory_attributes="0"
    memory_access_identifier=""

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -n | --name)
                i=$(( i + 1 ))
                memory_segment_name="${argv[i]}"
            ;;

            -b | --begin)
                i=$(( i + 1 ))
                eval begin_page="\$((16#${argv[i]}))"
            ;;

            -e | --end)
                i=$(( i + 1 ))
                eval end_page="\$((16#${argv[i]}))"
            ;;

            -d | --desc)
                i=$(( i + 1 ))
                page_access_descriptor="${argv[i]}"
            ;;

            -a | --attr)
                i=$(( i + 1 ))
                memory_attributes="${argv[i]}"
            ;;

            -i | --id)
                i=$(( i + 1 ))
                memory_access_identifier="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${memory_segment_name}") \
            $(int8 "${begin_page}") \
            $(int8 "${end_page}") \
            $(int1 "${page_access_descriptor}") \
            $(int1 "${memory_attributes}") \
            $(string "${memory_access_identifier}")

    # Tell user it was successful
    echo "${smtarg} memory saved to ${memory_segment_name}"
}

# =============================================================================
# SMAPI Function: Shared_Memory_Delete
# =============================================================================
function Shared_Memory_Delete
{
    # Define local variables
    local i memory_segment_name

    # Define info for parser
    desc="Delete a shared memory segment"
    required=("    -n | --name            name of memory segment")
    optional=()
    opts="n:"
    optl="name:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -n | --name)
                i=$(( i + 1 ))
                memory_segment_name="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${memory_segment_name}")

    # Tell user it was successful
    echo "Memory segment ${memory_segment_name} deleted"
}

# =============================================================================
# SMAPI Function: Shared_Memory_Query
# =============================================================================
function Shared_Memory_Query
{
    # Define local variables
    local i
    local memory_segment_array_length memory_segment_structure_length
    local memory_segment_name memory_segment_status
    local page_range_array_length page_range_structure_length
    local begin_page end_page page_access_descriptor

    # Define info for parser
    desc="Query shared memory segment characteristics"
    required=("    -n | --name            name of memory segment")
    optional=()
    opts="n:"
    optl="name:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -n | --name)
                i=$(( i + 1 ))
                memory_segment_name="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${memory_segment_name}")

    # Retrieve the array length
    get4 memory_segment_array_length

    # Retrieve and process array entries
    while [ ${memory_segment_array_length} -gt 0 ]
    do
        # Retrieve the entry length
        get4 memory_segment_structure_length

        # Protect against empty entries
        if [ ${memory_segment_structure_length} -gt 0 ]
        then
            # Retrieve the entry fields
            getstring memory_segment_name
            get1 memory_segment_status

            # Convert memory_segment_status
            case "${memory_segment_status}" in
                1) memory_segment_status="${memory_segment_status} (S)" ;;
                2) memory_segment_status="${memory_segment_status} (A)" ;;
                3) memory_segment_status="${memory_segment_status} (R)" ;;
                *) memory_segment_status="${memory_segment_status} (?)" ;;
            esac

            # Show it to the user
            echo "Segment: ${memory_segment_name}"
            echo "Status:  ${memory_segment_status}"

            # Retrieve the array length
            get4 page_range_array_length

            # Retrieve and process array entries
            while [ ${page_range_array_length} -gt 0 ]
            do
                # Retrieve the entry length
                get4 page_range_structure_length
        
                # Protect against empty entries
                if [ ${page_range_structure_length} -gt 0 ]
                then
                    # Retrieve the entry fields
                    get8 begin_page
                    get8 end_page
                    get1 page_access_descriptor

                    # Convert page_access_descriptor
                    case "${page_access_descriptor}" in
                        1) page_access_descriptor="${page_access_descriptor} (SW)" ;;
                        2) page_access_descriptor="${page_access_descriptor} (EW)" ;;
                        3) page_access_descriptor="${page_access_descriptor} (SR)" ;;
                        4) page_access_descriptor="${page_access_descriptor} (ER)" ;;
                        5) page_access_descriptor="${page_access_descriptor} (SN)" ;;
                        6) page_access_descriptor="${page_access_descriptor} (EN)" ;;
                        7) page_access_descriptor="${page_access_descriptor} (SC)" ;;
                        *) page_access_descriptor="${page_access_descriptor} (??)" ;;
                    esac
                
                    # Show it to the user
                    printf "Range:   %08x-%08x %s\n" "${begin_page}" "${end_page}" "${page_access_descriptor}"
                fi

                # Calculate remaining length (+4 for the "CPU_info_structure_length" itself)
                page_range_array_length=$(( page_range_array_length - 4 - page_range_structure_length ))
            done

            echo
        fi

        # Calculate remaining length (+4 for the "CPU_info_structure_length" itself)
        memory_segment_array_length=$(( memory_segment_array_length - 4 - memory_segment_structure_length ))
    done
}

# =============================================================================
# SMAPI Function: Shared_Memory_Replace
# =============================================================================
function Shared_Memory_Replace
{
    # Define local variables
    local i memory_segment_name memory_access_identifier

    # Define info for parser
    desc="Replace a shared memory segment"
    required=("    -n | --name            name of memory segment")
    optional=("    -i | --id              memory access ID")
    opts="n:i:"
    optl="name:,id:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Initialize optional variables
    memory_access_identifier=""

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -n | --name)
                i=$(( i + 1 ))
                memory_segment_name="${argv[i]}"
            ;;

            -i | --id)
                i=$(( i + 1 ))
                memory_access_identifier="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${memory_segment_name}") \
            $(string "${memory_access_identifier}")

    # Tell user it was successful
    echo "Memory segment ${memory_segment_name} replaced"
}

# =============================================================================
# SMAPI Function: SSI_Query
# =============================================================================
function SSI_Query
{
    # Define local variables
    local

    # Define info for parser
    desc="Get SSI and system status"

    # Build and send the request
    execute_keywords

    # Extract info
    getasciiz ssi_name
    getasciiz ssi_mode
    getasciiz cross_system_timeouts
    getasciiz ssi_pdr
    
    # Show it
    echo "Name: ${ssi_name}"
    echo "Mode: ${ssi_mode}"
    echo "Cross System Timeouts: ${cross_system_timeouts}"
    echo "PDR: ${ssi_pdr}"

    # Show each entry until nothing left
    while [ ${#resp} -gt 0 ]
    do
        getasciiz info_structure
        set -o noglob
        set -- ${info_structure}
        set +o noglob

        echo "Info:"
        echo

        echo "  Member Slot: ${1}"
        echo "  Member System ID: ${2}"
        echo "  Member State: ${3}"
        echo "  Member PDR Heartbeat: ${4}"
        echo "  Member Received Heartbeat: ${5}"
        echo
    done
}

# =============================================================================
# SMAPI Function: Static_Image_Changes_Activate_DM
# =============================================================================
function Static_Image_Changes_Activate_DM
{
    # Define local variables
    local

    # Define info for parser
    desc="Enable automatic activattion of directory changes"
    required=()
    optional=()
    opts=""
    optl=""
    usesparms="n"

    # Parse the command line
    parseopts

    # Build and send the request
    execute

    # Tell user it was successful
    echo "Directory changes will be activated automatically"
}

# =============================================================================
# SMAPI Function: Static_Image_Changes_Deactivate_DM
# =============================================================================
function Static_Image_Changes_Deactivate_DM
{
    # Define local variables
    local

    # Define info for parser
    desc="Disable automatic activation of directory changes"
    required=()
    optional=()
    opts=""
    optl=""
    usesparms="n"

    # Parse the command line
    parseopts

    # Build and send the request
    execute

    # Tell user it was successful
    echo "Directory changes will not be activated automatically"
}

# =============================================================================
# SMAPI Function: Static_Image_Changes_Immediate_DM
# =============================================================================
function Static_Image_Changes_Immediate_DM
{
    # Define local variables
    local

    # Define info for parser
    desc="Force activattion pending changes to source directory"
    required=()
    optional=()
    opts=""
    optl=""
    usesparms="n"

    # Parse the command line
    parseopts

    # Build and send the request
    execute

    # Tell user it was successful
    echo "Changes to directory (if any) have been activated"
}

# =============================================================================
# SMAPI Function: System_Config_Syntax_Check
# =============================================================================
function System_Config_Syntax_Check
{
    # Define local variables
    local

    # Define info for parser
    desc="Check the syntax of a system config file"

    # Build and send the request
    execute_keywords

    # Tell user it was successful
    echo "Syntax check successful"
}

# =============================================================================
# SMAPI Function: System_Disk_Accessibility
# =============================================================================
function System_Disk_Accessibility
{
    # Define local variables
    local

    # Define info for parser
    desc="Verify accessibility of device"

    # Build and send the request
    execute_keywords

    # Tell user it was successful
    echo "Disk can be attached to system"
}

# =============================================================================
# SMAPI Function: System_Disk_Add
# =============================================================================
function System_Disk_Add
{
    # Define local variables
    local

    # Define info for parser
    desc="Add disk to system"

    # Build and send the request
    execute_keywords

    # Tell user it was successful
    echo "Disk added to system"
}

# =============================================================================
# SMAPI Function: System_Disk_Query
# =============================================================================
function System_Disk_Query
{
    # Define local variables
    local

    # Define info for parser
    desc="Query system disks"

    # Build and send the request
    execute_keywords

    # Show each entry until nothing left
    while [ ${#resp} -gt 0 ]
    do
        getasciiz disk_info_structure
        set -- ${disk_info_structure}

        # Show it to the user
        echo "Disk Info:"
        echo "  Device Number: ${1}"
        echo "  Device Type: ${2}"
        echo "  Device Status: ${3}"
        echo "  Device Volser: ${4}"
        echo
    done
}

# =============================================================================
# SMAPI Function: System_FCP_FreE_Query
# =============================================================================
function System_FCP_Free_Query
{
    # Define local variables
    local fcp_array

    # Define info for parser
    desc="Query free FCP devices"

    # Build and send the request
    execute_keywords

    # Show each entry until nothing left
    while [ ${#resp} -gt 0 ]
    do
        getasciiz fcp_structure
        OIFS="${IFS}"
        IFS=';'
        set -- ${fcp_structure}
        IFS="${OIFS}"

        # Show it to the user
        echo "FCP Info:"
        echo "  Device Number: ${1}"
        echo "  WWPN: ${2}"
        echo "  LUN: ${3}"
        echo "  UUID: ${4}"
        echo "  Vendor Name: ${5}"
        echo "  Product Number: ${6}"
        echo "  Model Number: ${7}"
        echo "  Serial Number: ${8}"
        echo "  Device Code: ${9}"
        shift 9
        echo "  Block Size: ${1}"
        echo "  Disk Blocks: ${2}"
        echo "  LUN Size: ${3}"
        echo
    done
}

# =============================================================================
# SMAPI Function: System_Performance_Threshold_Disable
# =============================================================================
function System_Performance_Threshold_Disable
{
    # Define local variables
    local i event_type

    # Define info for parser
    desc="Disable async threshold events"
    required=()
    optional=()
    opts=""
    optl=""
    usesparms="r"

    # Parse the command line
    parseopts

    # First option must be positional indicator
    if [ "${argv[0]}" != "--" ]
    then
        echo "Missing event type"
        exit 1
    fi
    
    # Reconstruct event type
    event_type=""
    for (( i = 1; i < ${#argv[@]}; i++ ))
    do
        event_type="${event_type} ${argv[i]}"
    done

    # Build and send the request
    execute $(asciiz "${event_type}")

    # Tell user it was successful
    echo "Performance threshold events disabled"
}

# =============================================================================
# SMAPI Function: System_Performance_Threshold_Enable
# =============================================================================
function System_Performance_Threshold_Enable
{
    # Define local variables
    local i event_type

    # Define info for parser
    desc="Enable async threshold events"
    required=()
    optional=()
    opts=""
    optl=""
    usesparms="r"

    # Parse the command line
    parseopts

    # First option must be positional indicator
    if [ "${argv[0]}" != "--" ]
    then
        echo "Missing event type"
        exit 1
    fi
    
    # Reconstruct event type
    event_type=""
    for (( i = 1; i < ${#argv[@]}; i++ ))
    do
        event_type="${event_type} ${argv[i]}"
    done

    # Build and send the request
    execute $(asciiz "${event_type}")

    # Tell user it was successful
    echo "Performance threshold events enabled"
}

# =============================================================================
# SMAPI Function: System_SCSI_Disk_Add
# =============================================================================
function System_SCSI_Disk_Add
{
    # Define local variables
    local

    # Define info for parser
    desc="Add SCSI disk to system"

    # Build and send the request
    execute_keywords

    # Tell user it was successful
    echo "SCSI disk added to system"
}

# =============================================================================
# SMAPI Function: System_SCSI_Disk_Delete
# =============================================================================
function System_SCSI_Disk_Delete
{
    # Define local variables
    local

    # Define info for parser
    desc="Delete SCSI disk from system"

    # Build and send the request
    execute_keywords

    # Tell user it was successful
    echo "SCSI disk deleted from system"
}

# =============================================================================
# SMAPI Function: System_SCSI_Disk_Query
# =============================================================================
function System_SCSI_Disk_Query
{
    # Define local variables
    local fcp_array

    # Define info for parser
    desc="Query SCSI system disks"

    # Build and send the request
    execute_keywords

    # Show each entry until nothing left
    while [ ${#resp} -gt 0 ]
    do
        getasciiz scsi_info_structure
        set -- ${scsi_info_structure}

        # Show it to the user
        echo "SCSI Info:"
        echo "  Device Number: ${1}"
        echo "  Device Type: ${2}"
        echo "  Device Attr: ${3}"
        echo "  Device Size: ${4}"
        echo "  FCP Devices:"

        fcp_array = "${5}"
        while [ ${#fcp_array} -gt 0 ]
        do
            echo "    FCP Device number: ${fcp_array:0:4}"
            echo "    WWPN: ${fcp_array:4:16}"
            echo "    LUN: ${fcp_array:20:16}"

            fcp_array="${fcp_array:36}"
        done
            
        echo
    done
}

# =============================================================================
# SMAPI Function: System_WWPN_Query
# =============================================================================
function System_WWPN_Query
{
    # Define local variables
    local fcp_array

    # Define info for parser
    desc="Query FCP devices"

    # Build and send the request
    execute_keywords

    # Show each entry until nothing left
    while [ ${#resp} -gt 0 ]
    do
        getasciiz wwpn_structure
        set -- ${wwpn_structure}

        # Show it to the user
        echo "WWPN Info:"
        echo "  Device Number: ${1}"
        echo "  NPIV Port Number: ${2}"
        echo "  CHPID: ${3}"
        echo "  Physical WWPN: ${4}"

        case "${5}" in
            1) echo "  ${5} (Active)" ;;
            2) echo "  ${5} (Free)" ;;
            3) echo "  ${5} (Offline)" ;;
            *) echo "  ${5} (?)" ;;
        esac

        echo
    done
}

# =============================================================================
# SMAPI Function: Virtual_Channel_Connection_Create
# =============================================================================
function Virtual_Channel_Connection_Create
{
    # Define local variables
    local i image_device_number coupled_image_name coupled_image_device_number

    # Define info for parser
    desc="Create virtual network connection (CTCA) between active images"
    required=("    -a | --addr            address of device in target" \
              "    -n | --name            name of partner image" \
              "    -d | --dev             address of device in partner")
    optional=()
    opts="a:n:d:"
    optl="addr:,name:,dev:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -a | --addr)
                i=$(( i + 1 ))
                image_device_number="${argv[i]}"
            ;;

            -n | --name)
                i=$(( i + 1 ))
                coupled_image_name="${argv[i]}"
            ;;

            -d | --dev)
                i=$(( i + 1 ))
                coupled_image_device_number="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${image_device_number}") \
            $(string "${coupled_image_name}") \
            $(string "${coupled_image_device_number}")

    # Tell user it was successful
    echo "${image_device_number} connected to active ${coupled_image_name}'s ${coupled_image_device_number} device"
}

# =============================================================================
# SMAPI Function: Virtual_Channel_Connection_Create_DM
# =============================================================================
function Virtual_Channel_Connection_Create_DM
{
    # Define local variables
    local i image_device_number coupled_image_name

    # Define info for parser
    desc="Create virtual network connection (CTCA) between images"
    required=("    -a | --addr            address of device" \
              "    -n | --name            name of partner image")
    optional=()
    opts="a:n:"
    optl="addr:,name:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -a | --addr)
                i=$(( i + 1 ))
                image_device_number="${argv[i]}"
            ;;

            -n | --name)
                i=$(( i + 1 ))
                coupled_image_name="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${image_device_number}") \
            $(string "${coupled_image_name}")

    # Tell user it was successful
    echo "${image_device_number} created and connected to ${coupled_image_name}"
}

# =============================================================================
# SMAPI Function: Virtual_Channel_Connection_Delete
# =============================================================================
function Virtual_Channel_Connection_Delete
{
    # Define local variables
    local i image_device_number

    # Define info for parser
    desc="Delete virtual network connection (CTCA) from active image"
    required=("    -a | --addr            address of device")
    optional=()
    opts="a:"
    optl="addr:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -a | --addr)
                i=$(( i + 1 ))
                image_device_number="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${image_device_number}")

    # Tell user it was successful
    echo "${image_device_number} CTCA deleted from active ${smtarg}"
}

# =============================================================================
# SMAPI Function: Virtual_Channel_Connection_Delete_DM
# =============================================================================
function Virtual_Channel_Connection_Delete_DM
{
    # Define local variables
    local i image_device_number

    # Define info for parser
    desc="Delete virtual network connection (CTCA) from image directory"
    required=("    -a | --addr            address of device")
    optional=()
    opts="a:"
    optl="addr:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -a | --addr)
                i=$(( i + 1 ))
                image_device_number="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${image_device_number}")

    # Tell user it was successful
    echo "${image_device_number} CTCA deleted from ${smtarg}"
}

# =============================================================================
# SMAPI Function: Virtual_Network_Adapter_Connect_LAN
# =============================================================================
function Virtual_Network_Adapter_Connect_LAN
{
    # Define local variables
    local i image_device_number lan_name lan_owner

    # Define info for parser
    desc="Connect an active image's network adapter to LAN"
    required=("    -a | --addr            address of device" \
              "    -n | --name            LAN name" \
              "    -o | --owner           LAN owner")
    optional=()
    opts="a:n:o:"
    optl="addr:,name:,owner:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -a | --addr)
                i=$(( i + 1 ))
                image_device_number="${argv[i]}"
            ;;

            -n | --name)
                i=$(( i + 1 ))
                lan_name="${argv[i]}"
            ;;

            -o | --owner)
                i=$(( i + 1 ))
                lan_owner="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${image_device_number}") \
            $(string "${lan_name}") \
            $(string "${lan_owner}")

    # Tell user it was successful
    echo "${image_device_number} connected to active ${lan_owner} ${lan_name}"
}

# =============================================================================
# SMAPI Function: Virtual_Network_Adapter_Connect_LAN_DM
# =============================================================================
function Virtual_Network_Adapter_Connect_LAN_DM
{
    # Define local variables
    local i image_device_number lan_name lan_owner

    # Define info for parser
    desc="Connect an active image's network adapter to LAN"
    required=("    -a | --addr            address of device" \
              "    -n | --name            LAN name" \
              "    -o | --owner           LAN owner")
    optional=()
    opts="a:n:o:"
    optl="addr:,name:,owner:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -a | --addr)
                i=$(( i + 1 ))
                image_device_number="${argv[i]}"
            ;;

            -n | --name)
                i=$(( i + 1 ))
                lan_name="${argv[i]}"
            ;;

            -o | --owner)
                i=$(( i + 1 ))
                lan_owner="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${image_device_number}") \
            $(string "${lan_name}") \
            $(string "${lan_owner}")

    # Tell user it was successful
    echo "${image_device_number} connected to ${lan_owner} ${lan_name}"
}

# =============================================================================
# SMAPI Function: Virtual_Network_Adapter_Connect_Vswitch
# =============================================================================
function Virtual_Network_Adapter_Connect_Vswitch
{
    # Define local variables
    local i image_device_number vswitch_name

    # Define info for parser
    desc="Connect an active image's network adapter to a virtual switch"
    required=("    -a | --addr            address of device" \
              "    -n | --name            Vswitch name")
    optional=()
    opts="a:n:"
    optl="addr:,name:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -a | --addr)
                i=$(( i + 1 ))
                image_device_number="${argv[i]}"
            ;;

            -n | --name)
                i=$(( i + 1 ))
                vswitch_name="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${image_device_number}") \
            $(string "${vswitch_name}")

    # Tell user it was successful
    echo "${image_device_number} connected to active ${vswitch_name}"
}

# =============================================================================
# SMAPI Function: Virtual_Network_Adapter_Connect_Vswitch_DM
# =============================================================================
function Virtual_Network_Adapter_Connect_Vswitch_DM
{
    # Define local variables
    local i image_device_number vswitch_name

    # Define info for parser
    desc="Connect an active image's network adapter to a virtual switch"
    required=("    -a | --addr            address of device" \
              "    -n | --name            Vswitch name")
    optional=()
    opts="a:n:"
    optl="addr:,name:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -a | --addr)
                i=$(( i + 1 ))
                image_device_number="${argv[i]}"
            ;;

            -n | --name)
                i=$(( i + 1 ))
                vswitch_name="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${image_device_number}") \
            $(string "${vswitch_name}")

    # Tell user it was successful
    echo "${image_device_number} connected to ${vswitch_name}"
}

# =============================================================================
# SMAPI Function: Virtual_Network_Adapter_Connect_Vswitch__Extended
# =============================================================================
function Virtual_Network_Adapter_Connect_Vswitch_Extended
{
    # Define local variables
    local

    # Define info for parser
    desc="Connect active adapter to existing switch"

    # Build and send the request
    execute_keywords

    # Tell user it was successful
    echo "Adapter connected to active ${smtarg}"
}

# =============================================================================
# SMAPI Function: Virtual_Network_Adapter_Create
# =============================================================================
function Virtual_Network_Adapter_Create
{
    # Define local variables
    local i image_device_number adapter_type network_adapter_devices
    local channel_path_id

    # Define info for parser
    desc="Add a network adapter to an active image"
    required=("    -a | --addr            address of device" \
              "    -t | --type            adapter type" \
              "                           : 1 = hipersocket NIC" \
              "                           : 2 = QDIO NIC" \
              "    -d | --devices         number of devices")
    optional=("    -p | --path            channel path ID")
    opts="a:t:d:p:"
    optl="addr:,type:,devices:,path:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Initialize optional variables
    channel_path_id=""

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -a | --addr)
                i=$(( i + 1 ))
                image_device_number="${argv[i]}"
            ;;

            -t | --type)
                i=$(( i + 1 ))
                adapter_type="${argv[i]}"
            ;;

            -d | --devices)
                i=$(( i + 1 ))
                network_adapter_devices="${argv[i]}"
            ;;

            -p | --path)
                i=$(( i + 1 ))
                channel_path_id="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${image_device_number}") \
            $(int1 "${adapter_type}") \
            $(int4 "${network_adapter_devices}") \
            $(string "${channel_path_id}")

    # Tell user it was successful
    echo "${image_device_number} added to active ${smtarg}"
}

# =============================================================================
# SMAPI Function: Virtual_Network_Adapter_Create_DM
# =============================================================================
function Virtual_Network_Adapter_Create_DM
{
    # Define local variables
    local i image_device_number adapter_type network_adapter_devices
    local channel_path_id mac_id

    # Define info for parser
    desc="Add a network adapter to an image"
    required=("    -a | --addr            address of device" \
              "    -t | --type            adapter type" \
              "                           : 1 = hipersocket NIC" \
              "                           : 2 = QDIO NIC" \
              "    -d | --devices         number of devices")
    optional=("    -p | --path            channel path ID" \
              "    -m | --mac             mac ID")
    opts="a:t:d:p:m:"
    optl="addr:,type:,devices:,path:,mac:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Initialize optional variables
    channel_path_id=""
    mac_id=""

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -a | --addr)
                i=$(( i + 1 ))
                image_device_number="${argv[i]}"
            ;;

            -t | --type)
                i=$(( i + 1 ))
                adapter_type="${argv[i]}"
            ;;

            -d | --devices)
                i=$(( i + 1 ))
                network_adapter_devices="${argv[i]}"
            ;;

            -p | --path)
                i=$(( i + 1 ))
                channel_path_id="${argv[i]}"
            ;;

            -m | --mac)
                i=$(( i + 1 ))
                mac_id="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${image_device_number}") \
            $(int1 "${adapter_type}") \
            $(int4 "${network_adapter_devices}") \
            $(string "${channel_path_id}") \
            $(string "${mac_id}")

    # Tell user it was successful
    echo "${image_device_number} added to ${smtarg}"
}

# =============================================================================
# SMAPI Function: Virtual_Network_Adapter_Create_Extended
# =============================================================================
function Virtual_Network_Adapter_Create_Extended
{
    # Define local variables
    local

    # Define info for parser
    desc="Add a network adapter to an active image"

    # Build and send the request
    execute_keywords

    # Tell user it was successful
    echo "Adapter added to active ${smtarg}"
}

# =============================================================================
# SMAPI Function: Virtual_Network_Adapter_Create_Extended_DM
# =============================================================================
function Virtual_Network_Adapter_Create_Extended_DM
{
    # Define local variables
    local

    # Define info for parser
    desc="Add a network adapter to an image"
    required=()
    optional=()
    opts=""
    optl=""
    usesparms="o"

    # Parse the command line
    parseopts

    # Build and send the request
    execute $(int4 $(( ${#addparms} / 2 ))) \
                   $addparms}

    # Tell user it was successful
    echo "Adapter added to ${smtarg}"
}

# =============================================================================
# SMAPI Function: Virtual_Network_Adapter_Delete
# =============================================================================
function Virtual_Network_Adapter_Delete
{
    # Define local variables
    local i image_device_number

    # Define info for parser
    desc="Delete a network adapter from an active image"
    required=("    -a | --addr            address of device")
    optional=()
    opts="a:"
    optl="addr:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -a | --addr)
                i=$(( i + 1 ))
                image_device_number="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${image_device_number}")

    # Tell user it was successful
    echo "${image_device_number} deleted from active ${smtarg}"
}

# =============================================================================
# SMAPI Function: Virtual_Network_Adapter_Delete_DM
# =============================================================================
function Virtual_Network_Adapter_Delete_DM
{
    # Define local variables
    local i image_device_number

    # Define info for parser
    desc="Delete a network adapter from an image"
    required=("    -a | --addr            address of device")
    optional=()
    opts="a:"
    optl="addr:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -a | --addr)
                i=$(( i + 1 ))
                image_device_number="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${image_device_number}")

    # Tell user it was successful
    echo "${image_device_number} deleted from ${smtarg}"
}

# =============================================================================
# SMAPI Function: Virtual_Network_Adapter_Disconnect
# =============================================================================
function Virtual_Network_Adapter_Disconnect
{
    # Define local variables
    local i image_device_number

    # Define info for parser
    desc="Disconnect network adapter in an active image"
    required=("    -a | --addr            address of device")
    optional=()
    opts="a:"
    optl="addr:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -a | --addr)
                i=$(( i + 1 ))
                image_device_number="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${image_device_number}")

    # Tell user it was successful
    echo "${image_device_number} disconnected in ${smtarg}"
}

# =============================================================================
# SMAPI Function: Virtual_Network_Adapter_Disconnect_DM
# =============================================================================
function Virtual_Network_Adapter_Disconnect_DM
{
    # Define local variables
    local i image_device_number

    # Define info for parser
    desc="Disconnect a network adapter in an image"
    required=("    -a | --addr            address of device")
    optional=()
    opts="a:"
    optl="addr:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -a | --addr)
                i=$(( i + 1 ))
                image_device_number="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${image_device_number}")

    # Tell user it was successful
    echo "${image_device_number} disconnected in ${smtarg}"
}

# =============================================================================
# SMAPI Function: Virtual_Network_Adapter_Query
# =============================================================================
function Virtual_Network_Adapter_Query
{
    # Define local variables
    local i image_device_number
    local adapter_array_length adapter_structure_length
    local image_device_number adapter_type network_adapter_devices
    local adapter_status lan_owner lan_name

    # Define info for parser
    desc="Query network adapter(s) in an active image"
    required=("    -a | --addr            address of device")
    optional=()
    opts="a:"
    optl="addr:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -a | --addr)
                i=$(( i + 1 ))
                image_device_number="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${image_device_number}")

    # Retrieve the length of the returned array
    get4 adapter_array_length

    # Retrieve and process array entries
    while [ $adapter_array_length -gt 0 ]
    do
        # Retrieve the entry length
        get4 adapter_structure_length

        # Protect against empty entries
        if [ $adapter_structure_length -gt 0 ]
        then
            # Retrieve entry fields
            getstring image_device_number
            get1 adapter_type
            get4 network_adapter_devices
            get1 adapter_status
            getstring lan_owner
            getstring lan_name

            # Convert adapter_type
            case "${adapter_type}" in
                1) adapter_type="${adapter_type} (Hipersocket)" ;;
                2) adapter_type="${adapter_type} (QDIO)" ;;
                *) adapter_type="${adapter_type} (??)" ;;
            esac

            # Convert adapter_status
            case "${adapter_status}" in
                0) adapter_status="${adapter_status} (not coupled)" ;;
                1) adapter_status="${adapter_status} (coupled, not active)" ;;
                2) adapter_status="${adapter_status} (coupled, active)" ;;
                *) adapter_status="${adapter_status} (??)" ;;
            esac
            
            # Show it to the user
            echo "Adapter:"
            echo "  Address: ${image_device_number}"
            echo "  Device count: ${network_adapter_devices}"
            echo "  Adapter type: ${adapter_type}"
            echo "  Adapter status: ${adapter_status}"
            echo "  Lan owner: ${lan_owner}"
            echo "  Lan name: ${lan_name}"
            echo
        fi

        # Calculate remaining length (+4 for the "adapter_structure_length" itself)
        adapter_array_length=$(( adapter_array_length - 4 - adapter_structure_length ))
    done
}

# =============================================================================
# SMAPI Function: Virtual_Network_LAN_Access
# =============================================================================
function Virtual_Network_LAN_Access
{
    # Define local variables
    local i lan_name lan_owner access_op access_user promiscuity

    # Define info for parser
    desc="Grant access to LAN"
    required=("    -n | --name            LAN name" \
              "    -o | --owner           LAN owner" \
              "    -a | --access          access operationr" \
              "                           : GRANT" \
              "                           : REVOKE" \
              "    -i | --image           target image")
    optional=("    -p | --promis          promiscuity" \
              "                           : NONPROMISCUOUS (default)" \
              "                           : PROMISCUOUS")
    optional=()
    opts="n:o:a:i:p:"
    optl="name:,owner:,access:,image:,promis:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Initialize optional variables
    promiscuity="NONPROMISCUOUS"

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -n | --name)
                i=$(( i + 1 ))
                lan_name="${argv[i]}"
            ;;

            -o | --owner)
                i=$(( i + 1 ))
                lan_owner="${argv[i]}"
            ;;

            -a | --access)
                i=$(( i + 1 ))
                access_op="${argv[i]}"
            ;;

            -i | --image)
                i=$(( i + 1 ))
                access_user="${argv[i]}"
            ;;

            -p | --promis)
                i=$(( i + 1 ))
                promiscuity="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(asciiz "${lan_name}") \
            $(asciiz "${lan_owner}") \
            $(asciiz "${access_op}") \
            $(asciiz "${access_user}") \
            $(asciiz "${promiscuity}")

    # Tell user it was successful
    echo "${access_user}'s access to ${lan_owner} ${lan_name} updated"
}

# =============================================================================
# SMAPI Function: Virtual_Network_LAN_Access_Query
# =============================================================================
function Virtual_Network_LAN_Access_Query
{
    # Define local variables
    local i lan_name lan_owner

    # Define info for parser
    desc="Query access to LAN"
    required=("    -n | --name            LAN name" \
              "    -o | --owner           LAN owner")
    optional=()
    opts="n:o:"
    optl="name:,owner:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -n | --name)
                i=$(( i + 1 ))
                lan_name="${argv[i]}"
            ;;

            -o | --owner)
                i=$(( i + 1 ))
                lan_owner="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(asciiz "${lan_name}") \
            $(asciiz "${lan_owner}")

    # Retrieve and show the returned array
    showasciizarray ${#resp}
}

# =============================================================================
# SMAPI Function: Virtual_Network_LAN_Create
# =============================================================================
function Virtual_Network_LAN_Create
{
    # Define local variables
    local i lan_name lan_owner lan_type transport_type

    # Define info for parser
    desc="Create a virtual LAN"
    required=("    -n | --name            lan name" \
              "    -o | --owner           lan owner" \
              "    -t | --type            lan type" \
              "                           : 1 = unrestricted Hipersocket LAN" \
              "                           : 2 = unrestricted QDIO LAN" \
              "                           : 3 = restricted Hipersocket LAN" \
              "                           : 4 = restricted QDIO LAN")
    optional=("    -m | --mech            transport mechanism" \
              "                           : 0 = Unspecified (IP assumed)" \
              "                           : 1 = IP" \
              "                           : 2 = Ethernet")
    opts="n:o:t:m:"
    optl="name:,owner:,type:,mech:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Initialize optional variables
    transport_type="0"

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -n | --name)
                i=$(( i + 1 ))
                lan_name="${argv[i]}"
            ;;

            -o | --owner)
                i=$(( i + 1 ))
                lan_owner="${argv[i]}"
            ;;

            -t | --type)
                i=$(( i + 1 ))
                lan_type="${argv[i]}"
            ;;

            -m | --mech)
                i=$(( i + 1 ))
                transport_type="${argv[i]}"
            ;;

            -p | --path)
                i=$(( i + 1 ))
                channel_path_id="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${lan_name}") \
            $(string "${lan_owner}") \
            $(int1 "${lan_type}") \
            $(int1 "${transport_type}")

    # Tell user it was successful
    echo "${lan_owner} ${lan_name} created"
}

# =============================================================================
# SMAPI Function: Virtual_Network_LAN_Delete
# =============================================================================
function Virtual_Network_LAN_Delete
{
    # Define local variables
    local i lan_name lan_owner

    # Define info for parser
    desc="Delete a virtual LAN"
    required=("    -n | --name            lan name" \
              "    -o | --owner           lan owner")
    optional=()
    opts="n:o:"
    optl="name:,owner:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -n | --name)
                i=$(( i + 1 ))
                lan_name="${argv[i]}"
            ;;

            -o | --owner)
                i=$(( i + 1 ))
                lan_owner="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${lan_name}") \
            $(string "${lan_owner}")

    # Tell user it was successful
    echo "${lan_owner} ${lan_name} deleted"
}

# =============================================================================
# SMAPI Function: Virtual_Network_LAN_Query
# =============================================================================
function Virtual_Network_LAN_Query
{
    # Define local variables
    local i lan_name lan_owner lan_type
    local lan_array_length lan_structure_length
    local connected_adapter_array_length connected_adapter_structure_length
    local adapter_owner image_device_number
                
    # Define info for parser
    desc="Query a virtual LAN"
    required=("    -n | --name            lan name" \
              "    -o | --owner           lan owner")
    optional=()
    opts="n:o:"
    optl="name:,owner:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -n | --name)
                i=$(( i + 1 ))
                lan_name="${argv[i]}"
            ;;

            -o | --owner)
                i=$(( i + 1 ))
                lan_owner="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${lan_name}") \
            $(string "${lan_owner}")

    # Retrieve the array length
    get4 lan_array_length

    # Retrieve and process array entries
    while [ ${lan_array_length} -gt 0 ]
    do
        # Retrieve the entry length
        get4 lan_structure_length

        # Protect against empty entries
        if [ ${lan_structure_length} -gt 0 ]
        then
            # Retrieve the entry fields
            getstring lan_name
            getstring lan_owner
            get1 lan_type

            # Convert lan_type
            case "${lan_type}" in
                1) lan_type="${lan_type} (Hipersocket)" ;;
                2) lan_type="${lan_type} (QDIO)" ;;
                *) lan_type="${lan_type} (??)" ;;
            esac

            # Show it to the user
            echo "LAN:"
            echo "  Name: ${lan_name}"
            echo "  Owner: ${lan_owner}"

            # Retrieve the array length
            get4 connected_adapter_array_length

            # Retrieve and process array entries
            echo "  Connections:"
            while [ ${connected_adapter_array_length} -gt 0 ]
            do
                # Retrieve the entry length
                get4 connected_adapter_structure_length
        
                # Protect against empty entries
                if [ ${connected_adapter_structure_length} -gt 0 ]
                then
                    # Retrieve the entry fields
                    getstring adapter_owner
                    getstring image_device_number

                    # Show it to the user
                    printf "    Adapter Owner: %-8s  Address: %s\n" ${adapter_owner} ${image_device_number}
                fi

                # Calculate remaining length (+4 for the "CPU_info_structure_length" itself)
                connected_adapter_array_length=$(( connected_adapter_array_length - 4 - connected_adapter_structure_length ))
            done

            echo
        fi

        # Calculate remaining length (+4 for the "CPU_info_structure_length" itself)
        lan_array_length=$(( lan_array_length - 4 - lan_structure_length ))
    done
}

# =============================================================================
# SMAPI Function: Virtual_Network_OSA_Query
# =============================================================================
function Virtual_Network_OSA_Query
{
    # Define local variables
    local i keyword_parms

    # Define info for parser
    desc="Queury real OSA devices"
    required=()
    optional=()
    opts=""
    optl=""
    usesparms="n"

    # Parse the command line
    parseopts

    # Build and send the request
    execute

    # Show each entry until nothing left
    while [ ${#resp} -gt 0 ]
    do
        getasciiz osa_info_structure
        set -- ${osa_info_structure}
               
        # Show it to the user
        echo "OSA Info:"
        echo "  Address: ${1}"
        echo "  Status: ${2}"
        echo "  Type: ${3}"
        echo "  Chpid: ${4}"
        echo "  Agent: ${5}"
        echo
    done
}

# =============================================================================
# SMAPI Function: Virtual_Network_VLAN_Query_Stats
# =============================================================================
function Virtual_Network_VLAN_Query_Stats
{
    # Define local variables
    local

    # Define info for parser
    desc="Query virtual LAN statistics"

    # Build and send the request
    execute_keywords

    # Retrieve the length of the returned array
    getasciiz port_array_length

    # Retrieve and process array entries
    while [ ${#resp} -gt 0 ]
    do
        # Retrieve entry fields
        getasciiz port_name
        getasciiz port_num

        echo "Port Info:"
        echo "  Port Name: ${port_name}"
        echo "  Port Number: ${port_num}"
        echo "  Segment Info:"

        getasciiz pseg_array_length
        i=$(( ${#resp} - pseg_array_length * 2 ))
        while [ ${#resp} -gt ${i} ]
        do
            getasciiz pseg_structure
            set -- ${pseg_structure}

            echo "    VLAN ID: ${1}"
            echo "    Received Frames: ${2}"
            echo "    Received Frames Discarded: ${3}"
            echo "    Transmitted Frames: ${4}"
            echo "    Transmitted Frames Discarded: ${5}"
            echo
        done
    done

    # Retrieve the length of the returned array
    getasciiz nic_array_length

    # Retrieve and process array entries
    while [ ${#resp} -gt 0 ]
    do
        # Retrieve entry fields
        getasciiz nic_name
        getasciiz nic_num

        echo "NIC Info:"
        echo "  NIC Name: ${nic_name}"
        echo "  NIC Number: ${nic_num}"
        echo "  Segment Info:"

        getasciiz nseg_array_length
        i=$(( ${#resp} - nseg_array_length * 2 ))
        while [ ${#resp} -gt ${i} ]
        do
            getasciiz nseg_structure
            set -- ${nseg_structure}

            echo "    VLAN ID: ${1}"
            echo "    Received Frames: ${2}"
            echo "    Received Frames Discarded: ${3}"
            echo "    Transmitted Frames: ${4}"
            echo "    Transmitted Frames Discarded: ${5}"
            echo
        done
    done
}

# =============================================================================
# SMAPI Function: Virtual_Network_Vswitch_Create
# =============================================================================
function Virtual_Network_Vswitch_Create
{
    # Define local variables
    local i switch_name real_device_address port_name
    local controller_name connection_value queue_memory_limit
    local routing_value transport_type vlan_id port_type
    local update_system_config_indicator gvrp_value native_vlanid
    local system_config_name system_config_type
    local parm_disk_owner parm_disk_number parm_disk_password
    local alt_system_config_name alt_system_config_type
    local alt_parm_disk_owner alt_parm_disk_number alt_parm_disk_password

    # Define info for parser
    desc="Create a virtual switch"
    required=("    -s | --switch          switch name")
    optional=("    -a | --addr            real device address" \
              "    -p | --portname        port name" \
              "    -c | --ctlrname        controller name" \
              "    -v | --connval         connection value" \
              "                           : 0 = Unspecified (defaults to 1)" \
              "                           : 1 = Activate" \
              "                           : 2 = Do not activate" \
              "    -q | --queue           queue memory limit" \
              "    -r | --routing         routing value" \
              "                           : 0 = Unspecified" \
              "                           : 1 = NONROUTER" \
              "                           : 2 = PRIROUTER" \
              "    -t | --trans           transport type" \
              "                           : 0 = Unspecified" \
              "                           : 1 = IP" \
              "                           : 2 = ETHERNET" \
              "    -i | --id              vlan id" \
              "                           : -1 = Unspecified" \
              "                           : 0 = UNAWARE" \
              "                           : 1-4096 = VLAN ID" \
              "    -o | --port            port type" \
              "                           : 0 = Unspecified" \
              "                           : 1 = ACCESS" \
              "                           : 2 = TRUNK"
              "    -u | --update          update system config" \
              "                           : 0 = Unspecified (defaults to 1)" \
              "                           : 1 = Create only" \
              "                           : 2 = Create and add to system config" \
              "                           : 3 = Add to system config only" \
              "    -g | --gvrp            GVRP value" \
              "                           : 0 = Unspecified" \
              "                           : 1 = GVRP" \
              "                           : 2 = NOGVRP" \
              "    -n | --native          native VLAN ID"
              "                           : -1 = Unspecified" \
              "                           : 1-4096 = VLAN ID" \
              "         --confname        system config name (default SYSTEM)" \
              "         --conftype        system config type (default CONFIG)" \
              "         --parmowner       parm disk owner (default MAINT)" \
              "         --parmaddr        parm disk address (default CF1)" \
              "         --parmpass        parm disk password (default \",\")" \
              "         --altname         alternate system config name (default SYSTEM)" \
              "         --alttype         alternate system config type (default CONFIG)" \
              "         --altowner        alternate parm disk owner (default MAINT)" \
              "         --altaddr         alternate parm disk address (default CF2)" \
              "         --altpass         alternate parm disk password (default \",\")")
    opts="s:a:p:c:v:q:r:t:i:o:u:g:n:"
    optl="switch:,addr:,portname:,ctlrname:,connval:,queue:,routing:,trans:,id:,port:,update:,gvrp:,native:"
    optl="${optl},confname:,conftype:,parmowner:,parmaddr:,parmpass:"
    optl="${optl},altname:,alttype:,altowner:,altaddr:,altpass:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Initialize optional variables
    real_device_address=""
    port_name=""
    controller_name=""
    connection_value="0"
    queue_memory_limit="-1"
    routing_value="0"
    transport_type="0"
    vlan_id="-1"
    port_type="0"
    update_system_config_indicator="0"
    gvrp_value="0"
    native_vlanid="-1"
    system_config_name=""
    system_config_type=""
    parm_disk_owner=""
    parm_disk_number=""
    parm_disk_password=""
    alt_system_config_name=""
    alt_system_config_type=""
    alt_parm_disk_owner=""
    alt_parm_disk_number=""
    alt_parm_disk_password=""
    
    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -s | --switch)
                i=$(( i + 1 ))
                switch_name="${argv[i]}"
            ;;

            -a | --addr)
                i=$(( i + 1 ))
                real_device_address="${argv[i]}"
            ;;

            -p | --portname)
                i=$(( i + 1 ))
                port_name="${argv[i]}"
            ;;

            -c | --ctlrname)
                i=$(( i + 1 ))
                controller_name="${argv[i]}"
            ;;

            -v | --connval)
                i=$(( i + 1 ))
                connection_value="${argv[i]}"
            ;;

            -q | --queue)
                i=$(( i + 1 ))
                queue_memory_limit="${argv[i]}"
            ;;

            -r | --routing)
                i=$(( i + 1 ))
                routing_value="${argv[i]}"
            ;;

            -t | --trans)
                i=$(( i + 1 ))
                transport_type="${argv[i]}"
            ;;

            -i | --id)
                i=$(( i + 1 ))
                vlan_id="${argv[i]}"
            ;;

            -o | --port_type)
                i=$(( i + 1 ))
                port_type="${argv[i]}"
            ;;

            -u | --update)
                i=$(( i + 1 ))
                update_system_config_indicator="${argv[i]}"
            ;;

            --confname)
                i=$(( i + 1 ))
                system_config_name="${argv[i]}"
            ;;

            --conftype)
                i=$(( i + 1 ))
                system_config_type="${argv[i]}"
            ;;

            --parmowner)
                i=$(( i + 1 ))
                parm_disk_owner="${argv[i]}"
            ;;

            --parmaddr)
                i=$(( i + 1 ))
                parm_disk_number="${argv[i]}"
            ;;

            --parmpass)
                i=$(( i + 1 ))
                parm_disk_password="${argv[i]}"
            ;;

            --altname)
                i=$(( i + 1 ))
                alt_system_config_name="${argv[i]}"
            ;;

            --alttype)
                i=$(( i + 1 ))
                alt_system_config_type="${argv[i]}"
            ;;

            --altowner)
                i=$(( i + 1 ))
                alt_parm_disk_owner="${argv[i]}"
            ;;

            --altaddr)
                i=$(( i + 1 ))
                alt_parm_disk_number="${argv[i]}"
            ;;

            --altpass)
                i=$(( i + 1 ))
                alt_parm_disk_password="${argv[i]}"
            ;;

            -g | --gvrp)
                i=$(( i + 1 ))
                gvrp_value="${argv[i]}"
            ;;

            -n | --native)
                i=$(( i + 1 ))
                native_vlanid="${argv[i]}"
            ;;
       esac
    done

    # Build and send the request
    execute $(string "${switch_name}") \
            $(string "${real_device_address}") \
            $(string "${port_name}") \
            $(string "${controller_name}") \
            $(int1 "${connection_value}") \
            $(int4 "${queue_memory_limit}") \
            $(int1 "${routing_value}") \
            $(int1 "${transport_type}") \
            $(int4 "${vlan_id}") \
            $(int1 "${port_type}") \
            $(int1 "${update_system_config_indicator}") \
            $(string "${system_config_name}") \
            $(string "${system_config_type}") \
            $(string "${parm_disk_owner}") \
            $(string "${parm_disk_number}") \
            $(string "${parm_disk_password}") \
            $(string "${alt_system_config_name}") \
            $(string "${alt_system_config_type}") \
            $(string "${alt_parm_disk_owner}") \
            $(string "${alt_parm_disk_number}") \
            $(string "${alt_parm_disk_password}") \
            $(int1 "${gvrp_value}") \
            $(int4 "${native_vlanid}")

    # Tell user it was successful
    echo "${switch_name} created"
}

# =============================================================================
# SMAPI Function: Virtual_Network_Vswitch_Create_Extended
# =============================================================================
function Virtual_Network_Vswitch_Create_Extended
{
    # Define local variables
    local

    # Define info for parser
    desc="Create a virtual switch"

    # Build and send the request
    execute_keywords

    # Tell user it was successful
    echo "Virtual switch created"
}

# =============================================================================
# SMAPI Function: Virtual_Network_Vswitch_Delete
# =============================================================================
function Virtual_Network_Vswitch_Delete
{
    # Define local variables
    local i switch_name update_system_config_indicator
    local system_config_name system_config_type
    local parm_disk_owner parm_disk_number parm_disk_password
    local alt_system_config_name alt_system_config_type
    local alt_parm_disk_owner alt_parm_disk_number alt_parm_disk_password

    # Define info for parser
    desc="Delete a virtual switch"
    required=("    -s | --switch          switch name")
    optional=("    -u | --update          update system config" \
              "                           : 0 = Unspecified (defaults to 1)" \
              "                           : 1 = Delete only" \
              "                           : 2 = Delete and remove from system config" \
              "                           : 3 = Remove from system config only" \
              "         --confname        system config name (default SYSTEM)" \
              "         --conftype        system config type (default CONFIG)" \
              "         --parmowner       parm disk owner (default MAINT)" \
              "         --parmaddr        parm disk address (default CF1)" \
              "         --parmpass        parm disk password (default \",\")" \
              "         --altname         alternate system config name (default SYSTEM)" \
              "         --alttype         alternate system config type (default CONFIG)" \
              "         --altowner        alternate parm disk owner (default MAINT)" \
              "         --altaddr         alternate parm disk address (default CF2)" \
              "         --altpass         alternate parm disk password (default \",\")")
    opts="s:u:"
    optl="switch:,update:"
    optl="${optl},confname:,conftype:,parmowner:,parmaddr:,parmpass:"
    optl="${optl},altname:,alttype:,altowner:,altaddr:,altpass:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Initialize optional variables
    update_system_config_indicator=0
    system_config_name=""
    system_config_type=""
    parm_disk_owner=""
    parm_disk_number=""
    parm_disk_password=""
    alt_system_config_name=""
    alt_system_config_type=""
    alt_parm_disk_owner=""
    alt_parm_disk_number=""
    alt_parm_disk_password=""
    
    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -s | --switch)
                i=$(( i + 1 ))
                switch_name="${argv[i]}"
            ;;

            -u | --update)
                i=$(( i + 1 ))
                update_system_config_indicator="${argv[i]}"
            ;;

            --confname)
                i=$(( i + 1 ))
                system_config_name="${argv[i]}"
            ;;

            --conftype)
                i=$(( i + 1 ))
                system_config_type="${argv[i]}"
            ;;

            --parmowner)
                i=$(( i + 1 ))
                parm_disk_owner="${argv[i]}"
            ;;

            --parmaddr)
                i=$(( i + 1 ))
                parm_disk_number="${argv[i]}"
            ;;

            --parmpass)
                i=$(( i + 1 ))
                parm_disk_password="${argv[i]}"
            ;;

            --altname)
                i=$(( i + 1 ))
                alt_system_config_name="${argv[i]}"
            ;;

            --alttype)
                i=$(( i + 1 ))
                alt_system_config_type="${argv[i]}"
            ;;

            --altowner)
                i=$(( i + 1 ))
                alt_parm_disk_owner="${argv[i]}"
            ;;

            --altaddr)
                i=$(( i + 1 ))
                alt_parm_disk_number="${argv[i]}"
            ;;

            --altpass)
                i=$(( i + 1 ))
                alt_parm_disk_password="${argv[i]}"
            ;;
       esac
    done

    # Build and send the request
    execute $(string "${switch_name}") \
            $(int1 "${update_system_config_indicator}") \
            $(string "${system_config_name}") \
            $(string "${system_config_type}") \
            $(string "${parm_disk_owner}") \
            $(string "${parm_disk_number}") \
            $(string "${parm_disk_password}") \
            $(string "${alt_system_config_name}") \
            $(string "${alt_system_config_type}") \
            $(string "${alt_parm_disk_owner}") \
            $(string "${alt_parm_disk_number}") \
            $(string "${alt_parm_disk_password}")

    # Tell user it was successful
    echo "${switch_name} deleted"
}

# =============================================================================
# SMAPI Function: Virtual_Network_Vswitch_Delete_Extended
# =============================================================================
function Virtual_Network_Vswitch_Delete_Extended
{
    # Define local variables
    local

    # Define info for parser
    desc="Delete a virtual switch"

    # Build and send the request
    execute_keywords

    # Tell user it was successful
    echo "Virtual switch deleted"
}

# =============================================================================
# SMAPI Function: Virtual_Network_Vswitch_Query
# =============================================================================
function Virtual_Network_Vswitch_Query
{
    # Define local variables
    local i
    local vswitch_array_length vswitch_structure_length
    local switch_name transport_type port_type switch_status
    local queue_memory_limit vlan_id native_vlan_id mac_id
    local gvrp_request_attribute gvrp_enabled_attribute
    local real_device_array_length real_device_structure_length
    local real_device_address controller_name port_name
    local device_status device_error_status
    local authorized_user_array_length authorized_user_structure_length
    local grant_userid
    local vlan_array_length vlan_structure_length
    local user_vlan_id vlan_ids
    local connected_adapter_array_length connected_adapter_structure_length
    local adapter_owner image_device_number

    # Define info for parser
    desc="Query a virtual switch"
    required=("    -s | --switch          switch name")
    optional=()
    opts="s:"
    optl="switch:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -s | --switch)
                i=$(( i + 1 ))
                switch_name="${argv[i]}"
            ;;
        esac
    done

    # Build and send the request
    execute $(string "${switch_name}")

    # Retrieve the array length
    get4 vswitch_array_length

    # Retrieve and process array entries
    while [ ${vswitch_array_length} -gt 0 ]
    do
        # Retrieve the entry length
        get4 vswitch_structure_length

        # Protect against empty entries
        if [ ${vswitch_structure_length} -gt 0 ]
        then
            # Retrieve the entry fields
            getstring switch_name
            get1 transport_type
            get1 port_type
            get4 queue_memory_limit
            get1 routing_value
            get4 vlan_id
            get4 native_vlan_id
            get8 mac_id
            get1 gvrp_request_attribute
            get1 gvrp_enabled_attribute
            get1 switch_status

            # Convert transport_type
            case "${transport_type}" in
                1) transport_type="${transport_type} (IP)" ;;
                2) transport_type="${transport_type} (Ethernet)" ;;
                *) transport_type="${transport_type} (??)" ;;
            esac

            # Convert port_type
            case "${port_type}" in
                1) port_type="${port_type} (Access)" ;;
                2) port_type="${port_type} (Trunk)" ;;
                *) port_type="${port_type} (??)" ;;
            esac

            # Convert routing_value
            case "${routing_value}" in
                1) routing_value="${routing_value} (NONROUTER)" ;;
                2) routing_value="${routing_value} (PRIROUTER)" ;;
                *) routing_value="${routing_value} (??)" ;;
            esac

            # Convert gvrp_request_attribute
            case "${gvrp_request_attribute}" in
                1) gvrp_request_attribute="${gvrp_request_attribute} (Requested)" ;;
                2) gvrp_request_attribute="${gvrp_request_attribute} (Not requested)" ;;
                *) gvrp_request_attribute="${gvrp_request_attribute} (??)" ;;
            esac

            # Convert gvrp_enabled_attribute
            case "${gvrp_enabled_attribute}" in
                1) gvrp_enabled_attribute="${gvrp_enabled_attribute} (Enabled)" ;;
                2) gvrp_enabled_attribute="${gvrp_enabled_attribute} (Not enabled)" ;;
                *) gvrp_enabled_attribute="${gvrp_enabled_attribute} (??)" ;;
            esac

            # Convert switch_status
            case "${switch_status}" in
                1) switch_status="${switch_status} (Virtual switch defined)" ;;
                2) switch_status="${switch_status} (Controller not available)" ;;
                3) switch_status="${switch_status} (Operator intervention required)" ;;
                4) switch_status="${switch_status} (Disconnected)" ;;
                5) switch_status="${switch_status} (Virtual devices attached to controller)" ;;
                6) switch_status="${switch_status} (OSA initialization in progress)" ;;
                7) switch_status="${switch_status} (OSA device not ready)" ;;
                8) switch_status="${switch_status} (OSA device ready)" ;;
                9) switch_status="${switch_status} (OSA devices being detached)" ;;
                10) switch_status="${switch_status} (Virtual switch delete pending)" ;;
                11) switch_status="${switch_status} (Virtual switch failover recovering)" ;;
                12) switch_status="${switch_status} (Autorestart in progress)" ;;
                *) switch_status="${switch_status} (??)" ;;
            esac

            # Show it to the user
            echo "VSWITCH:"
            echo "  Name: ${switch_name}"
            echo "  Transport type: ${transport_type}"
            echo "  Port type: ${port_type}"
            echo "  Queue memory limit: ${queue_memory_limit}"
            echo "  Routing value: ${routing_value}"
            echo "  VLAN ID: ${vlan_id}"
            echo "  Native VLAN ID: ${native_vlan_id}"
            printf "  Mac ID: %016x\n" "${mac_id}"
            echo "  GVRP request attributes: ${gvrp_request_attribute}"
            echo "  GVRP enabled attributes: ${gvrp_enabled_attribute}"
            echo "  Switch status: ${switch_status}"

            # Retrieve the array length
            get4 real_device_array_length

            # Retrieve and process array entries
            if [ ${real_device_array_length} -gt 0 ]
            then 
                echo "  Devices:"
            fi

            while [ ${real_device_array_length} -gt 0 ]
            do
                # Retrieve the entry length
                get4 real_device_structure_length
        
                # Protect against empty entries
                if [ ${real_device_structure_length} -gt 0 ]
                then
                    # Retrieve the entry fields
                    get4 real_device_address
                    getstring controller_name
                    getstring port_name
                    get1 device_status
                    get1 device_error_status
                    
                    # Convert device_status
                    case "${device_status}" in
                        0) device_status="${device_status} (Device is not active)" ;;
                        1) device_status="${device_status} (Device is active)" ;;
                        2) device_status="${device_status} (Device is a backup device)" ;;
                        *) device_status="${device_status} (??)" ;;
                    esac
                    
                    # Convert device_error_status
                    case "${device_error_status}" in
                        0) device_error_status="${device_error_status} (No error)" ;;
                        1) device_error_status="${device_error_status} (Port name conflict)" ;;
                        2) device_error_status="${device_error_status} (No layer 2 support)" ;;
                        3) device_error_status="${device_error_status} (Real device does not exist)" ;;
                        4) device_error_status="${device_error_status} (Real device is attached elsewhere)" ;;
                        5) device_error_status="${device_error_status} (Real device is not QDIO OSA-E)" ;;
                        6) device_error_status="${device_error_status} (Initialization error)" ;;
                        7) device_error_status="${device_error_status} (Stalled OSA)" ;;
                        8) device_error_status="${device_error_status} (Stalled controller)" ;;
                        9) device_error_status="${device_error_status} (Controller connection severed)" ;;
                        10) device_error_status="${device_error_status} (Primary or secondary routing conflict)" ;;
                        11) device_error_status="${device_error_status} (Device is offline)" ;;
                        12) device_error_status="${device_error_status} (Device was detached)" ;;
                        13) device_error_status="${device_error_status} (IP/Ethernet type mismatch)" ;;
                        14) device_error_status="${device_error_status} (Insufficient memory in controller virtual machine)" ;;
                        15) device_error_status="${device_error_status} (TCP/IP configuration conflict)" ;;
                        *) device_error_status="${device_error_status} (??)" ;;
                    esac

                    # Show it to the user
                    printf "    Read device: %04x\n" "${real_device_address}"
                    echo "    Controller name: ${controller_name}"
                    echo "    Port name: ${port_name}"
                    echo "    Device Status: ${device_status}"
                    echo "    Device error status: ${device_error_status}"
                fi
                echo

                # Calculate remaining length (+4 for the "CPU_info_structure_length" itself)
                real_device_array_length=$(( real_device_array_length - 4 - real_device_structure_length ))
            done

            # Retrieve the array length
            get4 authorized_user_array_length

            # Retrieve and process array entries
            if [ ${authorized_user_array_length} -gt 0 ]
            then 
                echo "  Authorized users:"
            fi

            while [ ${authorized_user_array_length} -gt 0 ]
            do
                # Retrieve the entry length
                get4 authorized_user_structure_length
        
                # Protect against empty entries
                if [ ${authorized_user_structure_length} -gt 0 ]
                then
                    # Retrieve the entry fields
                    getstring grant_userid

                    # Retrieve the array length
                    get4 vlan_array_length
        
                    # Retrieve and process array entries
                    vlan_ids=""
                    while [ ${vlan_array_length} -gt 0 ]
                    do
                        # Retrieve the entry length
                        get4 vlan_structure_length
                
                        # Protect against empty entries
                        if [ ${vlan_structure_length} -gt 0 ]
                        then
                            # Retrieve the entry fields
                            get4 user_vlan_id
                            
                            # Remember it
                            vlan_ids="${vlan_ids} ${user_vlan_id}"
                        fi
        
                        # Calculate remaining length (+4 for the "CPU_info_structure_length" itself)
                        vlan_array_length=$(( vlan_array_length - 4 - vlan_structure_length ))
                    done

                    # Show it to the user
                    printf "    User: %-8s - VLAN IDs:%s\n" "${grant_userid}" "${vlan_ids}"
                fi

                # Calculate remaining length (+4 for the "CPU_info_structure_length" itself)
                authorized_user_array_length=$(( authorized_user_array_length - 4 - authorized_user_structure_length ))
            done

            # Retrieve the array length
            get4 connected_adapter_array_length

            # Retrieve and process array entries
            if [ ${connected_adapter_array_length} -gt 0 ]
            then 
                echo "  Connections:"
            fi

            while [ ${connected_adapter_array_length} -gt 0 ]
            do
                # Retrieve the entry length
                get4 connected_adapter_structure_length
        
                # Protect against empty entries
                if [ ${connected_adapter_structure_length} -gt 0 ]
                then
                    # Retrieve the entry fields
                    getstring adapter_owner
                    getstring image_device_number

                    # Show it to the user
                    printf "    Adapter owner: %-8s - Device number: %s\n" "${adapter_owner}" "${image_device_number}"
                fi

                # Calculate remaining length (+4 for the "CPU_info_structure_length" itself)
                connected_adapter_array_length=$(( connected_adapter_array_length - 4 - connected_adapter_structure_length ))
            done

            echo
        fi

        # Calculate remaining length (+4 for the "CPU_info_structure_length" itself)
        vswitch_array_length=$(( vswitch_array_length - 4 - vswitch_structure_length ))
    done
}

# =============================================================================
# SMAPI Function: Virtual_Network_Vswitch_Query_Extended
# =============================================================================
function Virtual_Network_Vswitch_Query_Extended
{
    # Define local variables
    local

    # Define info for parser
    desc="Query virtual switch information"

    # Build and send the request
    execute_keywords

    # Retrieve vswitch count
    getasciiz vswitch_count

    for (( i = 0; i < vswitch_count; i++ ))
    do
        getasciiz vswitch_structure_length
        getasciiz vswitch_attr_count

        echo "VSWITCH Info:"
        echo

        getasciiz switch_name
        getasciiz transport_type
        getasciiz port_type
        getasciiz queue_memory_limit
        getasciiz routing_value
        getasciiz vlan_awareness
        getasciiz vlan_id
        getasciiz native_vlan_id
        getasciiz mac_id
        getasciiz gvrp_request_attribute
        getasciiz gvrp_enabled_attribute
        getasciiz switch_status
        getasciiz link_ag
        getasciiz lag_interval
        getasciiz lag_group
        getasciiz ip_timeout
        getasciiz switch_type
        getasciiz isolation_status
        getasciiz mac_protect
        getasciiz user_port_based
        if [ ${vswitch_attr_count} -gt 20 ]
        then
            getasciiz vlan_counters
        fi


        # Convert switch_status
        case "${switch_status}" in
            1) switch_status="${switch_status} (Virtual switch defined)" ;;
            2) switch_status="${switch_status} (Controller not available)" ;;
            3) switch_status="${switch_status} (Operator intervention required)" ;;
            4) switch_status="${switch_status} (Disconnected)" ;;
            5) switch_status="${switch_status} (Virtual devices attached to controller)" ;;
            6) switch_status="${switch_status} (OSA initialization in progress)" ;;
            7) switch_status="${switch_status} (OSA device not ready)" ;;
            8) switch_status="${switch_status} (OSA device ready)" ;;
            9) switch_status="${switch_status} (OSA devices being detached)" ;;
            10) switch_status="${switch_status} (Virtual switch delete pending)" ;;
            11) switch_status="${switch_status} (Virtual switch failover recovering)" ;;
            12) switch_status="${switch_status} (Autorestart in progress)" ;;
            *) switch_status="${switch_status} (??)" ;;
        esac

        echo "  Attributes:"
        echo
        echo "    Switch Name: ${switch_name}"
        echo "    Transport Type: ${transport_type}"
        echo "    Port Type: ${port_type}"
        echo "    Queue Memory Limit: ${queue_memory_limit}"
        echo "    Routing Value: ${routing_value}"
        echo "    VLAN Awareness: ${vlan_awareness}"
        echo "    VLAN ID: ${vlan_id}"
        echo "    Native VLAN ID: ${native_vlan_id}"
        echo "    MAC ID: ${mac_id}"
        echo "    GVRP Request Attribute: ${gvrp_request_attribute}"
        echo "    GVRP Enabled Attribute: ${gvrp_enabled_attribute}"
        echo "    Switch Status: ${switch_status}"
        echo "    Link Aggregation: ${link_ag}"
        echo "    Link Aggregation Interval: ${lag_interval}"
        echo "    IP Timeout: ${ip_timeout}"
        echo "    Switch Type: ${switch_type}"
        echo "    Isolation Status: ${isolation_status}"
        echo "    MAC Protect: ${mac_protect}"
        echo "    User Port Based: ${user_port_based}"
        echo "    VLAN Counters: ${vlan_counters}"
        echo
    
        getasciiz real_device_count

        echo "  Device Info:"
        echo
        
        for (( j = 0; j < real_device_count; j++ ))
        do
            getasciiz real_device_info_structure
            set -- ${real_device_info_structure}

            device_status="${5}"
            device_error_status="${6}"

            # Convert device_status
            case "${device_status}" in
                0) device_status="${device_status} (Device is not active)" ;;
                1) device_status="${device_status} (Device is active)" ;;
                2) device_status="${device_status} (Device is a backup device)" ;;
                *) device_status="${device_status} (??)" ;;
            esac

            # Convert device_error_status
            case "${device_error_status}" in
                0) device_error_status="${device_error_status} (No error)" ;;
                1) device_error_status="${device_error_status} (Port name conflict)" ;;
                2) device_error_status="${device_error_status} (No layer 2 support)" ;;
                3) device_error_status="${device_error_status} (Real device does not exist)" ;;
                4) device_error_status="${device_error_status} (Real device is attached elsewhere)" ;;
                5) device_error_status="${device_error_status} (Real device is not QDIO OSA-E)" ;;
                6) device_error_status="${device_error_status} (Initialization error)" ;;
                7) device_error_status="${device_error_status} (Stalled OSA)" ;;
                8) device_error_status="${device_error_status} (Stalled controller)" ;;
                9) device_error_status="${device_error_status} (Controller connection severed)" ;;
                10) device_error_status="${device_error_status} (Primary or secondary routing conflict)" ;;
                11) device_error_status="${device_error_status} (Device is offline)" ;;
                12) device_error_status="${device_error_status} (Device was detached)" ;;
                13) device_error_status="${device_error_status} (IP/Ethernet type mismatch)" ;;
                14) device_error_status="${device_error_status} (Insufficient memory in controller machine)" ;;
                15) device_error_status="${device_error_status} (TCP/IP configuration conflict)" ;;
                16) device_error_status="${device_error_status} (No link aggregation support)" ;;
                17) device_error_status="${device_error_status} (OSA-E attribute mismatch)" ;;
                18) device_error_status="${device_error_status} (Reserved for future use)" ;;
                19) device_error_status="${device_error_status} (OSA-E is not ready)" ;;
                20) device_error_status="${device_error_status} (Reserved for future use)" ;;
                21) device_error_status="${device_error_status} (Attempting restart for device)" ;;
                22) device_error_status="${device_error_status} (Error dedicating device)" ;;
                23) device_error_status="${device_error_status} (Device state is invalid)" ;;
                24) device_error_status="${device_error_status} (Port number is invalid for device)" ;;
                25) device_error_status="${device_error_status} (No OSA connection isolation)" ;;
                26) device_error_status="${device_error_status} (Reserved for future use)" ;;
                27) device_error_status="${device_error_status} (Reserved for future use)" ;;
                *) device_error_status="${device_error_status} (??)" ;;
            esac

            echo "    RDEV: ${1}"
            echo "    VDEV: ${2}"
            echo "    Controller Name: ${3}"
            echo "    Port Name: ${4}"
            echo "    Status: ${device_status}"
            echo "    Error Status: ${device_error_status}"
            echo
        done
        
        getasciiz authorized_user_count

        echo "  Authorized User Info:"
        echo

        for (( j = 0; j < authorized_user_count; j++ ))
        do
            getasciiz authorized_user_structure
            set -- ${authorized_user_structure}

            echo "    Port Number: ${1}"
            echo "    Userid: ${2}"
            echo "    Promiscuous Mode: ${3}"
            echo "    OSD Simulation: ${4}"

            getasciiz vlan_count

            echo "    VLAN Info:"
            echo

            for (( k = 0; k < vlan_count; k++ ))
            do
                getasciiz user_vlan_id
                echo "      VLAN ID: ${user_vlan_id}"
            done
            echo
        done

        getasciiz connected_adapter_count

        echo "  Connected Adapter Info:"
        echo

        for (( j = 0; j < connected_adapter_count; j++ ))
        do
            getasciiz connected_adapter_structure
            set -- ${connected_adapter_structure}

            echo "    Adapter Owner: ${1}"
            echo "    Virtual Device: ${2}"
            echo "    MAC Address: ${3}"
            echo "    Adapter Type: ${4}"
            echo
        done

        getasciiz uplink_nic_count

        echo "  Uplink Nic Info:"
        echo

        for (( j = 0; j < uplink_nic_count; j++ ))
        do
            getasciiz uplink_nic_structure
            set -- ${uplink_nic_structure}

            uplink_nic_error_status="${3}"

            # Convert uplink_nic_error_status
            case "${uplink_nic_error_status}" in
                0) uplink_nic_error_status="${uplink_nic_error_status} (No error)" ;;
                1) uplink_nic_error_status="${uplink_nic_error_status} (Userid not logged on)" ;;
                2) uplink_nic_error_status="${uplink_nic_error_status} (Not authorized)" ;;
                3) uplink_nic_error_status="${uplink_nic_error_status} (VDEV does not exist)" ;;
                4) uplink_nic_error_status="${uplink_nic_error_status} (VDEV is attached elsewhere)" ;;
                5) uplink_nic_error_status="${uplink_nic_error_status} (VDEV not compatible type)" ;;
                6) uplink_nic_error_status="${uplink_nic_error_status} (VLAN conflict)" ;;
                7) uplink_nic_error_status="${uplink_nic_error_status} (No MAC address)" ;;
                8) uplink_nic_error_status="${uplink_nic_error_status} (Not managed)" ;;
                9) uplink_nic_error_status="${uplink_nic_error_status} (Port error)" ;;
                13) uplink_nic_error_status="${uplink_nic_error_status} (Type mismatch)" ;;
                255) uplink_nic_error_status="${uplink_nic_error_status} (unknown error)" ;;
                *) uplink_nic_error_status="${uplink_nic_error_status} (??)" ;;
            esac

            echo "    Userid: ${1}"
            echo "    VDEV: ${2}"
            echo "    Error Status: ${uplink_nic_error_status}"
            echo
        done
    done
}

# =============================================================================
# SMAPI Function: Virtual_Network_Vswitch_Query_Stats
# =============================================================================
function Virtual_Network_Vswitch_Query_Stats
{
    # Define local variables
    local

    # Define info for parser
    desc="Query virtual switch stats"

    # Build and send the request
    execute_keywords

    # Retrieve the length of the returned array
    getasciiz vswitch_array_length

    # Retrieve and process array entries
    while [ ${#resp} -gt 0 ]
    do
        # Retrieve entry fields
        getasciiz switch_name

        echo "Port Info:"
        echo

        echo "  Switch Name: ${switch_name}"
        echo

        echo "  Segment Info:"
        echo

        getasciiz segment_array_length

        i=$(( ${#resp} - segment_array_length * 2 ))
        while [ ${#resp} -gt ${i} ]
        do
            getasciiz segment_structure
            set -o noglob
            set -- ${segment_structure}
            set +o noglob

            echo "    VLAN ID: ${1}"
            echo "    Received Frames: ${2}"
            echo "    Received Frames Discarded: ${3}"
            echo "    Transmitted Frames: ${4}"
            echo "    Transmitted Frames Discarded: ${5}"
            echo "    Activated TOD: ${6}"
            echo "    Config Update TOD: ${7}"
            echo "    VLAN Interfaces: ${8}"
            echo "    VLAN Deletes: ${9}"
            shift 9
            echo "    Device Type: ${1}"
            echo "    Device Address: ${2}"
            echo "    Device Status: ${3}"
            echo
        done
    done
}

# =============================================================================
# SMAPI Function: Virtual_Network_Vswitch_Set
# =============================================================================
function Virtual_Network_Vswitch_Set
{
    # Define local variables
    local i switch_name real_device_address port_name

    local i switch_name grant_userid user_vlan_id revoke_userid
    local real_device_address port_name controller_name
    local connection_value queue_memory_limit routing_value
    local port_type update_system_config_indicator
    local gvrp_value mac_id
    local system_config_name system_config_type
    local parm_disk_owner parm_disk_number parm_disk_password
    local alt_system_config_name alt_system_config_type
    local alt_parm_disk_owner alt_parm_disk_number alt_parm_disk_password

    # Define info for parser
    desc="Change configuration of a virtual switch"
    required=("    -s | --switch          switch name")
    optional=("    -g | --grant           userid to add to the access list" \
              "    -i | --id              VLAN ID(s)" \
              "                           : up to 4 singles \"100 200 300\"" \
              "                           : and/or ranges \"100-300 400\"" \
              "    -k | --revoke          userid to remove from the access list" \
              "    -a | --addr            real device address" \
              "    -p | --portname        port name" \
              "    -c | --ctlrname        controller name" \
              "    -v | --connval         connection value" \
              "                           : 0 = Unspecified (defaults to 1)" \
              "                           : 1 = Activate" \
              "                           : 2 = Do not activate" \
              "    -q | --queue           queue memory limit" \
              "    -r | --routing         routing value" \
              "                           : 0 = Unspecified" \
              "                           : 1 = NONROUTER" \
              "                           : 2 = PRIROUTER" \
              "    -o | --port            port type" \
              "                           : 0 = Unspecified" \
              "                           : 1 = ACCESS" \
              "                           : 2 = TRUNK"
              "    -u | --update          update system config" \
              "                           : 0 = Unspecified (defaults to 1)" \
              "                           : 1 = Update only" \
              "                           : 2 = Update active and system config" \
              "                           : 3 = Update system config only" \
              "    -g | --gvrp            GVRP value" \
              "                           : 0 = Unspecified" \
              "                           : 1 = GVRP" \
              "                           : 2 = NOGVRP" \
              "    -m | --mac             MAC ID" \
              "         --confname        system config name (default SYSTEM)" \
              "         --conftype        system config type (default CONFIG)" \
              "         --parmowner       parm disk owner (default MAINT)" \
              "         --parmaddr        parm disk address (default CF1)" \
              "         --parmpass        parm disk password (default \",\")" \
              "         --altname         alternate system config name (default SYSTEM)" \
              "         --alttype         alternate system config type (default CONFIG)" \
              "         --altowner        alternate parm disk owner (default MAINT)" \
              "         --altaddr         alternate parm disk address (default CF2)" \
              "         --altpass         alternate parm disk password (default \",\")")
    opts="s:g:i:k:a:p:c:v:q:r:o:u:g:m:"
    optl="switch:,grant:,id:,revoke:,addr:,portname:,ctlrname:,connval:,queue:,routing:,port:,update:,gvrp:,native:"
    optl="${optl},confname:,conftype:,parmowner:,parmaddr:,parmpass:"
    optl="${optl},altname:,alttype:,altowner:,altaddr:,altpass:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Initialize optional variables
    grant_userid=""
    user_vlan_id=""
    revoke_userid=""
    real_device_address=""
    port_name=""
    controller_name=""
    connection_value="0"
    queue_memory_limit="-1"
    routing_value="0"
    port_type="0"
    update_system_config_indicator="0"
    gvrp_value="0"
    mac_id=""
    system_config_name=""
    system_config_type=""
    parm_disk_owner=""
    parm_disk_number=""
    parm_disk_password=""
    alt_system_config_name=""
    alt_system_config_type=""
    alt_parm_disk_owner=""
    alt_parm_disk_number=""
    alt_parm_disk_password=""
    
    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -s | --switch)
                i=$(( i + 1 ))
                switch_name="${argv[i]}"
            ;;

            -g | --grant)
                i=$(( i + 1 ))
                grant_userid="${argv[i]}"
            ;;

            -i | --id)
                i=$(( i + 1 ))
                user_vlan_id="${argv[i]}"
            ;;

            -k| --revoke)
                i=$(( i + 1 ))
                revoke_userid="${argv[i]}"
            ;;

            -a | --addr)
                i=$(( i + 1 ))
                real_device_address="${argv[i]}"
            ;;

            -p | --portname)
                i=$(( i + 1 ))
                port_name="${argv[i]}"
            ;;

            -c | --ctlrname)
                i=$(( i + 1 ))
                controller_name="${argv[i]}"
            ;;

            -v | --connval)
                i=$(( i + 1 ))
                connection_value="${argv[i]}"
            ;;

            -q | --queue)
                i=$(( i + 1 ))
                queue_memory_limit="${argv[i]}"
            ;;

            -r | --routing)
                i=$(( i + 1 ))
                routing_value="${argv[i]}"
            ;;

            -o | --port_type)
                i=$(( i + 1 ))
                port_type="${argv[i]}"
            ;;

            -u | --update)
                i=$(( i + 1 ))
                update_system_config_indicator="${argv[i]}"
            ;;

            --confname)
                i=$(( i + 1 ))
                system_config_name="${argv[i]}"
            ;;

            --conftype)
                i=$(( i + 1 ))
                system_config_type="${argv[i]}"
            ;;

            --parmowner)
                i=$(( i + 1 ))
                parm_disk_owner="${argv[i]}"
            ;;

            --parmaddr)
                i=$(( i + 1 ))
                parm_disk_number="${argv[i]}"
            ;;

            --parmpass)
                i=$(( i + 1 ))
                parm_disk_password="${argv[i]}"
            ;;

            --altname)
                i=$(( i + 1 ))
                alt_system_config_name="${argv[i]}"
            ;;

            --alttype)
                i=$(( i + 1 ))
                alt_system_config_type="${argv[i]}"
            ;;

            --altowner)
                i=$(( i + 1 ))
                alt_parm_disk_owner="${argv[i]}"
            ;;

            --altaddr)
                i=$(( i + 1 ))
                alt_parm_disk_number="${argv[i]}"
            ;;

            --altpass)
                i=$(( i + 1 ))
                alt_parm_disk_password="${argv[i]}"
            ;;

            -g | --gvrp)
                i=$(( i + 1 ))
                gvrp_value="${argv[i]}"
            ;;

            -m | --mac)
                i=$(( i + 1 ))
                mac_id="${argv[i]}"
            ;;
       esac
    done

    # Build and send the request
    execute $(string "${switch_name}") \
            $(string "${grant_userid}") \
            $(string "${user_vlan_id}") \
            $(string "${revoke_userid}") \
            $(string "${real_device_address}") \
            $(string "${port_name}") \
            $(string "${controller_name}") \
            $(int1 "${connection_value}") \
            $(int4 "${queue_memory_limit}") \
            $(int1 "${routing_value}") \
            $(int1 "${port_type}") \
            $(int1 "${update_system_config_indicator}") \
            $(string "${system_config_name}") \
            $(string "${system_config_type}") \
            $(string "${parm_disk_owner}") \
            $(string "${parm_disk_number}") \
            $(string "${parm_disk_password}") \
            $(string "${alt_system_config_name}") \
            $(string "${alt_system_config_type}") \
            $(string "${alt_parm_disk_owner}") \
            $(string "${alt_parm_disk_number}") \
            $(string "${alt_parm_disk_password}") \
            $(int1 "${gvrp_value}") \
            $(string "${mac_id}")

    # Tell user it was successful
    echo "${switch_name} updated"
}

# =============================================================================
# SMAPI Function: Virtual_Network_Vswitch_Set_Extended
# =============================================================================
function Virtual_Network_Vswitch_Set_Extended
{
    # Define local variables
    local

    # Define info for parser
    desc="Updated a virtual switch"

    # Build and send the request
    execute_keywords

    # Tell user it was successful
    echo "Virtual switch updated"
}

# =============================================================================
# SMAPI Function: VMRELOCATE 
# =============================================================================
function VMRELOCATE
{
    # Define local variables
    local

    # Define info for parser
    desc="Relocate a virtual machine"

    # Build and send the request
    execute_keywords_no_check

    # Check for relocation failure
    if [ ${reas} -eq 3000 ]
    then
        if [ ${retc} -eq 4 ]
        then
            getasciiz error_record
            echo "VMRELOCATE TEST failed, error codes are:"
            echo "${error_record}"
            exit 1
        fi
        
        if [ ${retc} -eq 8 ]
        then
            getasciiz error_record
            echo "VMRELOCATE MOVE failed, error codes are:"
            echo "${error_record}"
            exit 1
        fi
    fi

    # Check for other errors
    checkandfail

    # Tell user it was successful
    echo "VMRELOCATE command sent"
}

# =============================================================================
# SMAPI Function: VMRELOCATE_Image_Attributes
# =============================================================================
function VMRELOCATE_Image_Attributes
{
    # Define local variables
    local

    # Define info for parser
    desc="Modify relocation settings for image"

    # Build and send the request
    execute_keywords

    # Tell user it was successful
    echo "Settings updated"
}

# =============================================================================
# SMAPI Function: VMRELOCATE_Modify
# =============================================================================
function VMRELOCATE_Modify
{
    # Define local variables
    local

    # Define info for parser
    desc="Modify relocation settings for image"

    # Build and send the request
    execute_keywords_no_check

    # Check for relocation failure
    if [ ${reas} -eq 3010 ]
    then
        if [ ${retc} -eq 8 ]
        then
            getasciiz error_record
            echo "VMRELOCATE MODIFY failed, error codes are:"
            echo "${error_record}"
            exit 1
        fi
    fi

    # Check for other errors
    checkandfail

    # Tell user it was successful
    echo "Relocation modified"
}

# =============================================================================
# SMAPI Function: VMRELOCATE_Status
# =============================================================================
function VMRELOCATE_Status
{
    # Define local variables
    local

    # Define info for parser
    desc="Get status of in progress relocations"

    # Build and send the request
    execute_keywords

    # Show each entry until nothing left
    while [ ${#resp} -gt 0 ]
    do
        getasciiz status_structure
        set -o noglob
        set -- ${status_structure}
        set +o noglob

        echo "Status:"
        echo

        echo "  Image: ${1}"
        echo "  Source System: ${2}"
        echo "  Destination System: ${3}"
        echo "  By: ${4}"
        echo "  Elapsed: ${5}"
        echo "  Status: ${6}"
        echo
    done
}

# =============================================================================
# SMAPI Function: VMRM_Configuration_Query
# =============================================================================
function VMRM_Configuration_Query
{
    # Define local variables
    local l configuration_file_name configuration_file_type
    local configuration_dir_name
    local configuration_file_length

    # Define info for parser
    desc="Query VMRM configuration"
    required=("    -n | --name            file name" \
              "    -t | --type            file type" \
              "    -d | --dir             SFS directory name")
    optional=()
    opts="n:t:d:"
    optl="name:,type:,dir:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -n | --name)
                i=$(( i + 1 ))
                configuration_file_name="${argv[i]}"
            ;;

            -t | --type)
                i=$(( i + 1 ))
                configuration_file_type="${argv[i]}"
            ;;

            -d | --dir)
                i=$(( i + 1 ))
                configuration_dir_name="${argv[i]}"
            ;;
       esac
    done

    # Build and send the request
    execute $(string "${configuration_file_name}") \
            $(string "${configuration_file_type}") \
            $(string "${configuration_dir_name}")

    # Retrieve length
    get4 configuration_file_length

    # Retrieve and show the returned array
    showasciizarray ${configuration_file_length}
}

# =============================================================================
# SMAPI Function: VMRM_Configuration_Update
# =============================================================================
function VMRM_Configuration_Update
{
    # Define local variables
    local l configuration_file_name configuration_file_type
    local configuration_dir_name configuration_file syncheck_only
    local update_file

    # Define info for parser
    desc="Update VMRM configuration"
    required=("    -n | --name            file name" \
              "    -t | --type            file type" \
              "    -d | --dir             SFS directory name")
    optional=("    -c | --check           syntax check only" \
              "                           : 0 = check and update" \
              "                           : 1 = check only")
    opts="n:t:d:c:"
    optl="name:,type:,dir:,check:"
    usesparms="n"

    # Parse the command line
    parseopts

    # Initialize optional variables
    syncheck_only="0"

    # Process options
    for (( i = 0; i < ${#argv[@]}; i++ ))
    do
        case "${argv[i]}" in
            -n | --name)
                i=$(( i + 1 ))
                configuration_file_name="${argv[i]}"
            ;;

            -t | --type)
                i=$(( i + 1 ))
                configuration_file_type="${argv[i]}"
            ;;

            -d | --dir)
                i=$(( i + 1 ))
                configuration_dir_name="${argv[i]}"
            ;;

            -c | --check)
                i=$(( i + 1 ))
                syncheck_only="${argv[i]}"
            ;;
       esac
    done

    # Build update file from stdin
    OIFS="${IFS}"
    IFS=$'\n'
    update_file=""
    while read log_record
    do
        update_file="${update_file}$(asciiz """${log_record}""")"
    done
    IFS="${OIFS}"

    # Build and send the request
    execute $(string "${configuration_file_name}") \
            $(string "${configuration_file_type}") \
            $(string "${configuration_dir_name}") \
            $(int1 "${syncheck_only}") \
            $(int4 ${#update_file}) \
            ${update_file}

    # Retrieve and show the returned array
    showstringarray
}

# =============================================================================
# SMAPI Function: VMRM_Measurement_Query
# =============================================================================
function VMRM_Measurement_Query
{
    # Define local variables
    local query_timestamp file_spec le_timestamp

    # Define info for parser
    desc="Query VMRM measurement values"
    required=()
    optional=()
    opts=""
    optl=""
    usesparms="n"

    # Parse the command line
    parseopts

    # Build and send the request
    execute

    # Retrieve return values
    getstring query_timestamp
    getstring file_spec
    getstring file_timestamp

    # Show them to the user
    echo "Query timestamp: ${query_timestamp}"
    echo "File spec: ${file_spec}"
    echo "File timestamp: ${file_timestamp}"
    echo

    # Retrieve and show the returned array
    showstringarray
}

# =============================================================================
# SMAPI Function: Build_SMIUCV_helper
# =============================================================================
function Build_SMIUCV_Helper
{
    # Define local variables
    local opath

    which gcc >/dev/null 2>&1
    if [ "${?}" -ne 0 ]
    then
        echo "Unable to build smiucv helper ... can't find gcc"
        exit 1
    fi

    opath=$(dirname "${0}")
    gcc -O3 -Wl,-s -o "${opath}/smiucv" -x c - <<END_OF_SMIUCV
/*
||=======================================================================
|| smiucv - Helper utility that provides an IUCV interface to the z/VM
||          System Management API (SMAPI).
||
|| This utility reads requests from stdin, sends them to the SMAPI server
|| via IUCV and writes the response to stdout.  It's intended for use by
|| the smaclient shell command.
||
|| Usage:
||
||   smiucv [user] [name] <request >response
||
||   User and name are optional and will default to VSMREQIU and DMSRSRQU.
||
|| Written by Leland Lucius
||=======================================================================
*/

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netiucv/iucv.h>
#include <sys/socket.h>

/*
|| Default remote IUCV user and name
*/
#define IUCV_USER "VSMREQIU"
#define IUCV_NAME "DMSRSRQU"

/*
|| Read data from the SMAPI server and write it to stdout
*/
int
readwrite( int fd, void *ptr, int len )
{
    unsigned char *buffer = (unsigned char *) ptr;
    struct timeval timeout;
    fd_set readfds;
    int i;
    int rc;

    /*
    || Initialize timeout
    */
    timeout.tv_sec = 30;
    timeout.tv_usec = 0;

    /*
    || Large responses will arrive in chunks
    */
    for( i = 0; i < len; i += rc )
    {
        /*
        || Wait for timeout or data
        */
        FD_ZERO( &readfds);
        FD_SET( fd, &readfds );
        if( ( rc = select( fd + 1, &readfds, NULL, NULL, &timeout ) ) < 0 )
        {
            fprintf( stderr, "select() failed: %d - %s\n", errno, strerror( errno ) );
            return 1;
        }
        else if( rc == 0 )
        {
            fprintf( stderr, "Timeout waiting for response from remote\n" );
            return 1;
        }

        /*
        || Read it
        */
        if( ( rc = recv( fd, &buffer[i], len - i, 0 ) ) < 0 )
        {
            fprintf( stderr, "Error reading from socket: %d - %s\n", errno, strerror( errno ) );
            return 1;
        }
        else if( rc == 0 )
        {
            fprintf( stderr, "Connection closed by remote\n" );
            return 1;
        }
    }

    /*
    || Write to stdout
    */
    if( write( fileno( stdout ), buffer, len ) != len )
    {
        fprintf( stderr, "Error writing to stdout: %d - %s\n", errno, strerror( errno ) );
        return 1;
    }

    return 0;
}

int
main( int argc, char *argv[] )
{
    struct sockaddr_iucv siu;
    unsigned char *buffer = NULL;
    char *user;
    char *name;
    int used = 0;
    int bufsize = 0;
    int fd = -1;
    int rc = 0;
    int len;
    int reqid;

    /*
    || Initialize sockaddr
    */
    memset( &siu, 0, sizeof( siu ) );
    siu.siucv_family = AF_IUCV;
    memset( &siu.siucv_nodeid, ' ', 8 );
    memset( &siu.siucv_user_id, ' ', 8 );
    memset( &siu.siucv_name, ' ', 8 );

    /*
    || Set userid...default or first command line argument
    */
    user = IUCV_USER;
    if( argc > 1 && argv[ 1 ] )
    {
        user = argv[ 1 ];
    }
    len = strlen( user );
    memcpy( &siu.siucv_user_id, user, ( len > 8 ? 8 : len ) );

    /*
    || Set name...default or second command line argument
    */
    name = IUCV_NAME;
    if( argc > 2 && argv[ 2 ] )
    {
        name = argv[ 2 ];
    }
    len = strlen( name );
    memcpy( &siu.siucv_name, name, ( len > 8 ? 8 : len ) );

    /*
    || Allocate an IUCV socket
    */
    fd = socket( AF_IUCV, SOCK_STREAM, IPPROTO_IP );
    if( fd == -1 )
    {
        fprintf( stderr, "Unable to create socket: %d - %s", errno, strerror( errno ) );
        rc = 1;
        goto die;
    }

    /*
    || Bind it
    */
    rc = bind( fd, (struct sockaddr *) &siu, sizeof( siu ) );
    if( rc < 0 )
    {
        fprintf( stderr, "Unable to bind: %d - %s", errno, strerror( errno ) );
        rc = 1;
        goto die;
    }
                                                     
    /*
    || Connect to partner
    */
    rc = connect( fd, (struct sockaddr *) &siu, sizeof( siu ) );
    if( rc == -1 )
    {
        fprintf( stderr, "Unable to connect: %d - %s", errno, strerror( errno ) );
        rc = 1;
        goto die;
    }

    /*
    || Read request into buffer
    */
    do
    {
        if( used == bufsize )
        {
            bufsize += 8192;
            buffer = realloc( buffer, bufsize );
            if( buffer == NULL )
            {
                fprintf( stderr, "Unable to alloc buffer: %d - %s\n", errno, strerror( errno ) );
                rc = 1;
                goto die;
            }
        }
    } while( read( fileno( stdin ), &buffer[ used++ ], 1 ) == 1 );

    /*
    || Send it to the server
    */
    if( write( fd, buffer, --used ) != used )
    {
        fprintf( stderr, "Error writing to socket: %d - %s\n", errno, strerror( errno ) );
        rc = 1;
        goto die;
    }

    /*
    || Get the first request ID
    */
    if( ( rc = readwrite( fd, &reqid, sizeof( reqid ) ) ) != 0 )
    {
        goto die;
    }

    /*
    || Get the response length
    */
    if( ( rc = readwrite( fd, &len, sizeof( len ) ) ) != 0 )
    {
        goto die;
    }

    /*
    || Free original buffer and allocate a new one
    */
    free( buffer );
    buffer = malloc( len );
    if( buffer == NULL )
    {
        fprintf( stderr, "Unable to alloc buffer: %d - %s\n", errno, strerror( errno ) );
        rc = 1;
        goto die;
    }

    /*
    || Get the response
    */
    if( ( rc = readwrite( fd, buffer, len ) ) != 0 )
    {
        goto die;
    }

die:

    /*
    || Free the buffer
    */
    if( buffer )
    {
        free( buffer );
    }

    /*
    || Kill the socket
    */
    if( fd != -1 )
    {
        shutdown( fd, SHUT_RDWR );
        close( fd );    
    }

    return rc;
}
END_OF_SMIUCV

    if [ "${?}" -ne 0 ]
    then
        echo "Failed to build smiucv..."
        exit 1
    fi

    echo "smiucv built as ${opath}/smiucv"
    echo
    echo "Make sure \"${opath}\" is included in PATH."
}

# =============================================================================
# Main
# =============================================================================
function main
{
    # Define local variables
    local i funcs
    
    # Read the global config file
    [ -r /etc/smaclient.conf ] && . /etc/smaclient.conf
    
    # Override or supplement with personal config
    [ -r ~/.smaclient ] && . ~/.smaclient
    
    # Environment variables provide final override
    if [ ! -z "$SMHOST" ]
    then
        smhost="$SMHOST"
    fi
    
    if [ ! -z "$SMUSER" ]
    then
        smuser="$SMUSER"
    fi
    
    if [ ! -z "$SMPASS" ]
    then
        smpass="$SMPASS"
    fi
    
    # Get SMAPI function name (may be the abbrev at this point) and remove
    smfunc="${1}"
    shift

    # Remember command arguments
    argv=("${@}")
    
    # Define supported functions (long name MUST match SMAPI function name)
    funcs=("smiucv  Build_SMIUCV_Helper" \
           "andd    Asynchronous_Notification_Disable_DM" \
           "aned    Asynchronous_Notification_Enable_DM" \
           "anqd    Asynchronous_Notification_Query_DM" \
           "ala     Authorization_List_Add" \
           "alq     Authorization_List_Query" \
           "alr     Authorization_List_Remove" \
           #        Check_Authorization (does not follow API format) 
           "dabd    Delete_ABEND_Dump"
           "dmltdfd Directory_Manager_Local_Tag_Define_DM" \
           "dmltdld Directory_Manager_Local_Tag_Delete_DM" \
           "dmltqd  Directory_Manager_Local_Tag_Query_DM" \
           "dmltsd  Directory_Manager_Local_Tag_Set_DM" \
           "dmsd    Directory_Manager_Search_DM" \
           "dmtcd   Directory_Manager_Task_Cancel_DM" \
           "esa     Event_Stream_Add" \
           "es      Event_Subscribe" \
           "eu      Event_Unsubscribe" \
           "ia      Image_Activate" \
           "iacq    Image_Active_Configuration_Query" \
           "icdf    Image_CPU_Define" \
           "icdfd   Image_CPU_Define_DM" \
           "icdl    Image_CPU_Delete" \
           "icdld   Image_CPU_Delete_DM" \
           "icq     Image_CPU_Query" \
           "icqd    Image_CPU_Query_DM" \
           "icsmd   Image_CPU_Set_Maximum_DM" \
           "icd     Image_Create_DM" \
           "id      Image_Deactivate" \
           "idau    Image_Definition_Async_Updates" \
           "idcd    Image_Definition_Create_DM" \
           "iddd    Image_Definition_Delete_DM" \
           "idqd    Image_Definition_Query_DM" \
           "idud    Image_Definition_Update_DM" \
           "idd     Image_Delete_DM" \
           "ided    Image_Device_Dedicate" \
           "idedd   Image_Device_Dedicate_DM" \
           "ider    Image_Device_Reset" \
           "ideu    Image_Device_Undedicate" \
           "ideud   Image_Device_Undedicate_DM" \
           "idico   Image_Disk_Copy" \
           "idicod  Image_Disk_Copy_DM" \
           "idicr   Image_Disk_Create" \
           "idicrd  Image_Disk_Create_DM" \
           "idid    Image_Disk_Delete" \
           "ididd   Image_Disk_Delete_DM" \
           "idq     Image_Disk_Query" \
           "idis    Image_Disk_Share" \
           "idisd   Image_Disk_Share_DM" \
           "idiu    Image_Disk_Unshare" \
           "idiud   Image_Disk_Unshare_DM" \
           "iidd    Image_IPL_Delete_DM" \
           "iiqd    Image_IPL_Query_DM" \
           "iisd    Image_IPL_Set_DM" \
           "ild     Image_Lock_DM" \
           "inqd    Image_Name_Query_DM" \
           "ipsd    Image_Password_Set_DM" \
           "iqat    Image_Query_Activate_Time" \
           "iqd     Image_Query_DM" \
           "ir      Image_Recycle" \
           "ird     Image_Replace_DM" \
           "iscdd   Image_SCSI_Characteristics_Define_DM" \
           "iscqd   Image_SCSI_Characteristics_Query_DM" \
           "isq     Image_Status_Query" \
           "iud     Image_Unlock_DM" \
           "iva     Image_Volume_Add" \
           "ivd     Image_Volume_Delete" \
           "ivs     Image_Volume_Share" \
           "ivsdd   Image_Volume_Space_Define_DM" \
           "ivsded  Image_Volume_Space_Define_Extended_DM" \
           "ivsqd   Image_Volume_Space_Query_DM" \
           "ivsqed  Image_Volume_Space_Query_Extended_DM" \
           "ivsrd   Image_Volume_Space_Remove_DM" \
           "md      Metadata_Delete" \
           "mg      Metadata_Get" \
           "ms      Metadata_Set" \
           "nla     Name_List_Add" \
           "nld     Name_List_Destroy" \
           "nlq     Name_List_Query" \
           "nlr     Name_List_Remove" \
           "posva   Page_or_Spool_Volume_Add" \
           "pabd    Process_ABEND_Dump" \
           "pfcd    Profile_Create_DM" \
           "pfdd    Profile_Delete_DM" \
           "pfld    Profile_Lock_DM" \
           "pfqd    Profile_Query_DM" \
           "pfrd    Profile_Replace_DM" \
           "pfud    Profile_Unlock_DM" \
           "ptcd    Prototype_Create_DM" \
           "ptdd    Prototype_Delete_DM" \
           "ptnqd   Prototype_Name_Query_DM" \
           "ptqd    Prototype_Query_DM" \
           "ptrd    Prototype_Replace_DM" \
           "qabd    Query_ABEND_Dump" \
           "qad     Query_All_DM" \
           "qafl    Query_API_Functional_Level" \
           "qaod    Query_Asynchronous_Operation_DM" \
           "qdmld   Query_Directory_Manager_Level_DM" \
           "rr      Response_Recovery" \
           "smaad   Shared_Memory_Access_Add_DM" \
           "smaqd   Shared_Memory_Access_Query_DM" \
           "smard   Shared_Memory_Access_Remove_DM" \
           "smc     Shared_Memory_Create" \
           "smd     Shared_Memory_Delete" \
           "smq     Shared_Memory_Query" \
           "smr     Shared_Memory_Replace" \
           "sq      SSI_Query" \
           "sicad   Static_Image_Changes_Activate_DM" \
           "sicdd   Static_Image_Changes_Deactivate_DM" \
           "sicid   Static_Image_Changes_Immediate_DM" \
           "scsc    System_Config_Syntax_Check" \
           "sdac    System_Disk_Accessibility" \
           "sda     System_Disk_Add" \
           "sdq     System_Disk_Query" \
           "sffq    System_FCP_Free_Query" \
           "sptd    System_Performance_Threshold_Disable" \
           "spte    System_Performance_Threshold_Enable" \
           "ssda    System_SCSI_Disk_Add" \
           "ssdd    System_SCSI_Disk_Delete" \
           "ssdq    System_SCSI_Disk_Query" \
           "swq     System_WWPN_Query" \
           "vccc    Virtual_Channel_Connection_Create" \
           "vcccd   Virtual_Channel_Connection_Create_DM" \
           "vccd    Virtual_Channel_Connection_Delete" \
           "vccdd   Virtual_Channel_Connection_Delete_DM" \
           "vnacl   Virtual_Network_Adapter_Connect_LAN" \
           "vnacld  Virtual_Network_Adapter_Connect_LAN_DM" \
           "vnacv   Virtual_Network_Adapter_Connect_Vswitch" \
           "vnacvd  Virtual_Network_Adapter_Connect_Vswitch_DM" \
           "vnacve  Virtual_Network_Adapter_Connect_Vswitch_Extended" \
           "vnac    Virtual_Network_Adapter_Create" \
           "vnacd   Virtual_Network_Adapter_Create_DM" \
           "vnace   Virtual_Network_Adapter_Create_Extended" \
           "vnaced  Virtual_Network_Adapter_Create_Extended_DM" \
           "vnadl   Virtual_Network_Adapter_Delete" \
           "vnadld  Virtual_Network_Adapter_Delete_DM" \
           "vnadc   Virtual_Network_Adapter_Disconnect" \
           "vnadcd  Virtual_Network_Adapter_Disconnect_DM" \
           "vnaq    Virtual_Network_Adapter_Query" \
           "vnla    Virtual_Network_LAN_Access" \
           "vnlaq   Virtual_Network_LAN_Access_Query" \
           "vnlc    Virtual_Network_LAN_Create" \
           "vnld    Virtual_Network_LAN_Delete" \
           "vnlq    Virtual_Network_LAN_Query" \
           "vnoq    Virtual_Network_OSA_Query" \
           "vnvlqs  Virtual_Network_VLAN_Query_Stats" \
           "vnvc    Virtual_Network_Vswitch_Create" \
           "vnvce   Virtual_Network_Vswitch_Create_Extended" \
           "vnvd    Virtual_Network_Vswitch_Delete" \
           "vnvde   Virtual_Network_Vswitch_Delete_Extended" \
           "vnvq    Virtual_Network_Vswitch_Query" \
           "vnvqe   Virtual_Network_Vswitch_Query_Extended" \
           "vnvsqs  Virtual_Network_Vswitch_Query_Stats" \
           "vnvs    Virtual_Network_Vswitch_Set" \
           "vnvse   Virtual_Network_Vswitch_Set_Extended" \
           "v       VMRELOCATE" \
           "via     VMRELOCATE_Image_Attributes" \
           "vm      VMRELOCATE_Modify" \
           "vs      VMRELOCATE_Status" \
           "vcq     VMRM_Configuration_Query" \
           "vcu     VMRM_Configuration_Update" \
           "vmq     VMRM_Measurement_Query" \
           "")

    # Search function array and invoke handler if valid function specified
    for (( i = 0; i < ${#funcs[@]} - 1; i++ ))
    do
        set -- ${funcs[i]}

        if [ "${smfunc}" == "${1}" ]
        then
            smfunc="${2}"
        fi

        if [ "${smfunc}" == "${2}" ]
        then
            ${2}
            return
        fi    
    done

    # Introduce ourselves
    echo "smaclient: z/VM SMAPI client - v${verrel}"
    echo

    # Complain about missing or invalid function
    if [ -z "${smfunc}" ]
    then
        echo "Function not specified as first argument"
    else
        echo "Unrecognized function \"${smfunc}\""
    fi

    # Help out the user a little
    echo
    echo "Available functions:"
    echo
    printf "  %-50s %-8s %s\n" "Function name" "Abbrev"
    for (( i = 0; i < ${#funcs[@]}; i++ ))
    do
        set -- ${funcs[i]}
        printf "  %-50s %-8s %s\n" "${2}" "${1}"
    done

    exit 1
} 

# Invoke main function
main "${@}"

exit 0