#!/bin/ksh93
#  ALTRAN_PROLOG_BEGIN_TAG                                                    
#  This is an automatically generated prolog.                                  
#                                                                              
#  Copyright (C) Altran ACT S.A.S. 2017,2019,2021.  All rights reserved.  
#                                                                              
#  ALTRAN_PROLOG_END_TAG                                                      
#                                                                              
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
# 61haes_r714 src/43haes/lib/ksh93/hacmp/KLIB_HACMP_add_mirror_group.sh 1.20 
#  
# Licensed Materials - Property of IBM 
#  
# COPYRIGHT International Business Machines Corp. 2011 
# All Rights Reserved 
#  
# US Government Users Restricted Rights - Use, duplication or 
# disclosure restricted by GSA ADP Schedule Contract with IBM Corp. 
#  
# IBM_PROLOG_END_TAG 
# @(#)  7d4c34b 43haes/lib/ksh93/hacmp/KLIB_HACMP_add_mirror_group.sh, 726, 2147A_aha726, Feb 05 2021 09:50 PM

# Start of POD-formatted documentation. Viewing suggestions:
#      perldoc <FILENAME>
#      pod2text -c <FILENAME>
#      pod2text -c --code <FILENAME>
#      pod2html <FILENAME>
function devDoc {
    : <<'=cut' >/dev/null 2>&1

=head1 NAME

 KLIB_HACMP_add_mirror_group

=head1 SYNOPSIS

 clmgr add mirror_group <mirror_group_name> \
             TYPE=ds8k_inband_mm \
             MG_TYPE=user \
             VOLUME_GROUPS=<volume_group>[,<vg#2>,...] \
             DISKS=<raw_disk>[,<disk#2>,...] \
             [ HYPERSWAP_ENABLED={no|yes} ] \
             [ CONSISTENT={yes|no} ] \
             [ UNPLANNED_HS_TIMEOUT=## ] \
             [ HYPERSWAP_PRIORITY={medium|high} ] \
             [ RECOVERY={auto|manual} ] \
             [ RESYNC={auto|manual} ] \
             [ ATTRIBUTES=<NAME>@<VALUE>[,<NAME#2>@<VALUE#2>,...] ]

 clmgr add mirror_group <mirror_group_name> \
             TYPE=ds8k_inband_mm \
             MG_TYPE=system \
             VOLUME_GROUPS=<volume_group>[,<vg#2>,...] \
             DISKS=<raw_disk>[,<disk#2>,...] \
             NODE=<node> \
             HYPERSWAP_ENABLED={no|yes} \
             [ CONSISTENT={yes|no} ] \
             [ UNPLANNED_HS_TIMEOUT=## ] \
             [ HYPERSWAP_PRIORITY={medium|high} ] \
             [ ATTRIBUTES=<NAME>@<VALUE>[,<NAME#2>@<VALUE#2>,...] ]

 clmgr add mirror_group <mirror_group_name> \
             TYPE=ds8k_inband_mm \
             MG_TYPE=repository \
             SITE=<site> \
             NON_HS_DISK=<Non-HyperSwap_disk> \
             HS_DISK=<HyperSwap_disk> \
             [ HYPERSWAP_ENABLED={no|yes} ] \
             [ CONSISTENT={yes|no} ] \
             [ UNPLANNED_HS_TIMEOUT=## ] \
             [ HYPERSWAP_PRIORITY={medium|high} ] \
             [ RESYNC={auto|manual} ] \
             [ ATTRIBUTES=<NAME>@<VALUE>[,<NAME#2>@<VALUE#2>,...] ]

 clmgr add mirror_group <mirror_group_name> \
             TYPE=ds8k_gm \
             RECOVERY={auto|manual} \
             STORAGE_SYSTEMS=<storage_system>[,<ss#2>,...] \
             VENDOR_ID=<vendor_specific_identifier> \
             [ ATTRIBUTES=<NAME>@<VALUE>[,<NAME#2>@<VALUE#2>,...] ]

 clmgr add mirror_group <mirror_group_name> \
             TYPE=xiv_rm \
             MODE={sync|async} \
             RECOVERY={auto|manual} \
             STORAGE_SYSTEMS=<storage_system>[,<ss#2>,...] \
             VENDOR_ID=<vendor_specific_identifier> \
             [ ATTRIBUTES=<NAME>@<VALUE>[,<NAME#2>@<VALUE#2>,...] ]

 clmgr add mirror_group <mirror_group_name> \
             TYPE=svc \
             STORAGE_SYSTEMS=<MASTER_SVC>,<AUXILIARY_SVC> \
             [ MIRROR_PAIRS=<mirror_pair>[,<mirror_pair#2>,...] ] \
             [ MODE={sync|async} ] \
             [ RECOVERY={auto|manual} ]

 clmgr add mirror_group <mirror_group_name> \
             TYPE=hitachi \
             VENDOR_ID=<device_group> \
             HORCM_INSTANCE=<instance> \
             [ MODE={sync|async} ] \
             [ RECOVERY={auto|manual} ] \
             [ HORCM_TIMEOUT=### ] \
             [ PAIR_EVENT_TIMEOUT=### ]

 clmgr add mirror_group <mirror_group_name> \
             TYPE=emc \
             [ MG_TYPE={composite|device} ] \
             [ MODE={sync|async} ] \
             [ RECOVERY={auto|manual} ] \
             [ CONSISTENT={yes|no} ] \
             [ VENDOR_ID=<vendor_specific_identifier> ]

 NOTE: the alias for "mirror_group" is "mig".

=head1 DESCRIPTION

Attempts to create a new mirror group.

=head1 ARGUMENTS

 1. properties [REQUIRED] [hash ref]
    An associative array within which data about the
    created object can be returned to the caller.

 2. mirror_group [REQUIRED] [string]
    The label that is to be applied to this mirror group.

 3. type [REQUIRED] [set]
    The type of storage technology that this storage agent
    will be working with, from the set ds8k_gm, ds8k_inband_mm,
    emc, hitachi, svc, xiv_rm.

 4. mode [REQUIRED] [set]
    The mode of the mirroring: synchronous or asynchronous

 5. recovery [REQUIRED] [set]
    The recovery policy indicating the action to be taken
    in case of a site fallover.

    Valid values include:
       automatic:  No manual intervention required
       manual:     Manual Intervention required

 6. storage_systems [OPTIONAL] [string]
    Storage systems.

 7. mirror_pairs [OPTIONAL] [string]
    One or more mirror pairs to include.

 8. consistent [OPTIONAL] [boolean]

 9. vendor_id [OPTIONAL] [string]
    Vendor-specific identifier.

 10. horcm_instance [OPTIONAL] [string]

 11. horcm_timeout [OPTIONAL] [posint]

 12. pair_event_timeout [OPTIONAL] [posint]

 13. volume_groups [OPTIONAL] [string]
     Hyperswap-only. Required if raw disks are not specified.

 14. raw_disks [OPTIONAL] [string]
     Hyperswap-only. Required if volume are not specified.

 15. hs_enabled [OPTIONAL] [boolean]

 16. hs_priority [OPTIONAL] [set]
     Valid values: medium, high

 17. hs_unpl_timeout [OPTIONAL] [posint]

 18. mg_type [REQUIRED] [set]
     The type of HyperSwap or EMC mirror group to create.

     HyperSwap valid values: user, system, repository
     EMC valid values: composite, device

 19. node [OPTIONAL] [string]
     A node name. Required with ds8k_inband_mm, and type
     "system".

 20. site [OPTIONAL] [string]
     A site name. Required with ds8k_inband_mm, and type
     "repository".

 21. non_hs_disk [OPTIONAL] [string]
     A disk. Required with ds8k_inband_mm, and type
     "repository".

 22. hs_disk [OPTIONAL] [string]
     A disk. Required with ds8k_inband_mm, and type
     "repository".

 23. attributes [OPTIONAL] [string]
    Vendor-specific, opaque attributes.

 24. resync [REQUIRED] [set]
    In case replication volume or path recovers, the HyperSwap
    function makes sure to perform a re-sync automatically for
    'auto'. For 'manual', a user recommended action would be
    displayed in the errpt log for HyperSwap-enabled mirror
    groups, and in hacmp.out for HyperSwap-disabled mirror
    groups. A split and merge policy is recommended to be
    configured for using 'auto'.

    Valid values include:
       automatic
       manual

=head1 RETURN

 0: no errors were detected; the operation appears to have been successful
 1: a general error has occurred
 2: a specified resource does not exist, or could not be found
 3: some required input was missing
 4: some detected input was incorrect in some way
 5: a required dependency does not exist
 6: a specified search failed to match any data

=cut
} # End of POD-formatted documentation.


#============================================================================
#
# Name:        KLIB_HACMP_add_mirror_group
#
# Description: This is the main, FPATH function that is invoked by clmgr
#              to add a mirror group to the cluster configuration.
#
# Inputs:      See the "devDoc()" function, above.
#
# Outputs:     The properties hash is populated. The only other outputs are
#              any error messages that might be needed.
#
# Returns:     Zero if no errors are detected. Otherwise, an appropriate
#              non-zero value is returned. Refer to the "RETURN" section
#              of the "devDoc()" function, above, for the standard return
#              code values/meanings for clmgr.
#
#============================================================================
function KLIB_HACMP_add_mirror_group {
    . $HALIBROOT/log_entry "$0()" "$CL"
    : version=@(#)  7d4c34b 43haes/lib/ksh93/hacmp/KLIB_HACMP_add_mirror_group.sh, 726, 2147A_aha726, Feb 05 2021 09:50 PM
    : INPUTS: $*

    typeset -n properties=$1
    typeset    mirror_group=${2//\"/}
    typeset -l type=${3//\"/}
    typeset    mode=${4//\"/}
    typeset    recovery=${5//\"/}
    typeset    storage_systems=${6//\"/}
    typeset    mirror_pairs=${7//\"/}
    typeset    consistent=${8//\"/}
    typeset    vendor_id=${9//\"/}
    typeset    horcm_instance=${10//\"/}
    typeset    horcm_timeout=${11//\"/}
    typeset    pair_event_timeout=${12//\"/}
    typeset    volume_groups=${13//\"/}
    typeset    raw_disks=${14//\"/}
    typeset -l hs_enabled=${15//\"/}
    typeset    hs_priority=${16//\"/}
    typeset    hs_unpl_timeout=${17//\"/}
    typeset -l mg_type=${18//\"/}
    typeset    node=${19//\"/}
    typeset    site=${20//\"/}
    typeset    non_hs_disk=${21//\"/}
    typeset    hs_disk=${22//\"/}
    typeset    attributes=${23//\"/}
    typeset -l resync=${24//\"/}
 
    [[ $CLMGR_LOGGING == 'med' ]] && set +x  # Only trace param values

    #================================================================
    : Check for a defined cluster. No need to continue without one.
    #================================================================
    CL=$LINENO isClusterDefined
    if (( $? != RC_SUCCESS )); then
        log_return_msg "$RC_MISSING_DEPENDENCY" "$0()" "$LINENO"
        return $?
    fi

    CL=$LINENO isEnterprise
    if (( $? != 1 )); then
        CL=$LINENO cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 184 "\nERROR: this operation requires IBM PowerHA SystemMirror for AIX Enterprise Edition.\n\n" 1>&2
        log_return_msg "$RC_MISSING_DEPENDENCY" "$0()" "$LINENO"
        return $?
    fi

    #===================================
    : Declare and initialize variables
    #===================================
    typeset -i rc=$RC_UNKNOWN
    typeset pair="" attr="" value=""

    #=================
    : Validate input
    #=================
    if [[ $mirror_group == *([[:space:]]) ]]; then
        /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 100 "\nERROR: a name/label must be provided.\n\n" 1>&2
        rc=$RC_MISSING_INPUT

    else
        CL=$LINENO KLIB_HACMP_is_known_mirror_group $mirror_group
        if (( $? == RC_SUCCESS )); then
            /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 229 "\nERROR: the specified object already exists: \"%1\$s\"\n\n" "$mirror_group" 1>&2
            rc=$RC_INCORRECT_INPUT
        fi
    fi

    #============================
    : Check the required values
    #============================
    for pair in TYPE:$type
    do
        print -- "$pair" | IFS=: read attr value
        if [[ $value == *([[:space:]]) ]]; then
            /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 101 "\nERROR: this operation requires the \"%1\$s\" attribute.\n\n" "$attr" 1>&2
            rc=$RC_MISSING_INPUT
        fi
    done

    if [[ $type != *([[:space:]]) ]]; then
        case $type in
            *8*g*) type=ds8k_gm        ;;
            *8*i*) type=ds8k_inband_mm ;;
            e*)    type=emc            ;;
            h*)    type=hitachi        ;;
            s*)    type=svc            ;;
            x*)    type=xiv_rm         ;;
            *) /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 110 "\nERROR: invalid value specified for \"%1\$s\":  \"%2\$s\".\n" TYPE "$type" 1>&2
               /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 3 "Valid values: %1\$s\n\n" "ds8k_gm, ds8k_inband_mm, emc, hitachi, svc, xiv_rm" 1>&2
               rc=$RC_INCORRECT_INPUT
            ;;
        esac
    fi

    #======================================
    : Validate the specified mode, if any
    #======================================
    if [[ $mode != *([[:space:]]) ]]; then
        if [[ $type == @(xiv_rm|hitachi|emc|svc) ]]; then
            case $mode in
                @(a|A)*) [[ $type == "emc" ]] && mode="ASYNC" || mode="async" ;;
                @(s|S)*) [[ $type == "emc" ]] && mode="SYNC"  || mode="sync"  ;;
                *)  /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 110 "\nERROR: invalid value specified for \"%1\$s\":  \"%2\$s\".\n" MODE "$mode" 1>&2
                    /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 3 "Valid values: %1\$s\n\n" "sync, async" 1>&2
                    rc=$RC_INCORRECT_INPUT
                ;;
            esac

        elif [[ $type == "ds8k_inband_mm" ]]; then
            if [[ $mode != s* ]]; then
                CL=$LINENO cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 282 '\nERROR: invalid value specified for "%1$s" ("%2$s") with "%3$s".\n\n' MODE "$mode" "$type" 1>&2
                /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 3 "Valid values: %1\$s\n\n" "sync" 1>&2
                rc=$RC_INCORRECT_INPUT
            fi

        elif [[ -n $type ]]; then
            /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 283 '\nERROR: "%1$s" does not apply to "%2$s".\n\n' "MODE" "$type" 1>&2
            rc=$RC_INCORRECT_INPUT
        fi

    elif [[ $type == @(xiv_rm|hitachi) ]]; then
        mode="sync"  # Set a default value for these storage technologies
    fi

    if [[ $consistent != *([[:space:]]) ]]; then
        if [[ $type == @(ds8k_inband_mm|emc) ]]; then
            if [[ $consistent == @(y|Y|t|T)* ]]; then
                [[ $type == "emc" ]] && consistent="YES" || consistent="yes"
            elif [[ $consistent == @(n|N|f|F)* ]]; then
                [[ $type == "emc" ]] && consistent="NO"  || consistent="no"
            else
                /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 110 "\nERROR: invalid value specified for \"%1\$s\":  \"%2\$s\".\n" CONSISTENT "$consistent" 1>&2
                /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 3 "Valid values: %1\$s\n\n" "yes, no" 1>&2
                rc=$RC_INCORRECT_INPUT
            fi

        elif [[ -n $type ]]; then
            /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 283 '\nERROR: "%1$s" does not apply to "%2$s".\n\n' "CONSISTENT" "$type" 1>&2
            rc=$RC_INCORRECT_INPUT
        fi

    elif [[ $type == @(ds8k_inband_mm|emc) ]]; then # Set a default value
        [[ $type == "emc" ]] && consistent="YES" || consistent="yes"
    fi

    #==================================
    : XIV or Global Mirror validation
    #==================================
    if [[ $type == @(xiv_rm|ds8k_gm|svc) ]]; then
        if [[ -z $storage_systems ]]; then
            /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 101 "\nERROR: this operation requires the \"%1\$s\" attribute.\n\n" STORAGE_SYSTEMS 1>&2
            rc=$RC_MISSING_INPUT
        else
            for value in ${storage_systems//,/ }; do
                [[ $value == *([[:space:]]) ]] && continue
                CL=$LINENO KLIB_HACMP_is_known_storage_system "$value"
                if (( $? != RC_SUCCESS )); then
                    /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 102 "\nERROR: \"%1\$s\" does not appear to exist!\n\n" "$value" 1>&2
                    /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 164 "Available Storage Systems:\n\n" 1>&2

                    typeset available
                    CL=$LINENO KLIB_HACMP_list_storage_systems available
                    for (( i=0; i<${#available[*]}; i++ )); do
                        if [[ ${available[$i]} != *([[:space:]]) ]]; then
                            print -u2 "\t${available[$i]}"
                        fi
                    done
                    print -u2 ""

                    rc=$RC_INCORRECT_INPUT
                fi
            done
        fi

    elif [[ -n $type ]]; then
        if [[ -n $storage_systems ]]; then
            /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 45 '\nERROR: "%1$s" may only be used with "%2$s".\n\n' STORAGE_SYSTEMS "TYPE={xiv_rm|ds8k_gm}" 1>&2
            rc=$RC_INCORRECT_INPUT
        fi
    fi
    if [[ $type == @(xiv_rm|ds8k_gm) ]]; then
        if [[ -z $vendor_id ]]; then
            /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 101 "\nERROR: this operation requires the \"%1\$s\" attribute.\n\n" VENDOR_ID 1>&2
            rc=$RC_MISSING_INPUT
        fi
    fi

    #==========================
    : SVC-specific validation
    #==========================
    if [[ $type == "svc" ]]; then
        if [[ $mirror_pairs != *([[:space:]]) ]]; then
            typeset -i BAD_MIP=0
            for value in ${mirror_pairs//,/ }; do
                [[ $value == *([[:space:]]) ]] && continue
                CL=$LINENO KLIB_HACMP_is_known_mirror_pair "$value"
                if (( $? != RC_SUCCESS )); then
                    /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 102 "\nERROR: \"%1\$s\" does not appear to exist!\n\n" "$value" 1>&2
                    BAD_MIP=1
                fi
            done

            if (( BAD_MIP )); then
                /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 166 "Available Mirror Pairs:\n\n" 1>&2

                typeset available
                CL=$LINENO KLIB_HACMP_list_mirror_pairs available
                for (( i=0; i<${#available[*]}; i++ )); do
                    if [[ ${available[$i]} != *([[:space:]]) ]]; then
                        print -u2 "\t${available[$i]}"
                    fi
                done
                print -u2 ""

                rc=$RC_INCORRECT_INPUT
            fi

        fi

    elif [[ -n $type ]]; then
        if [[ -n $mirror_pairs ]]; then
            /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 45 '\nERROR: "%1$s" may only be used with "%2$s".\n\n' MIRROR_PAIRS TYPE=svc 1>&2
            rc=$RC_INCORRECT_INPUT
        fi
    fi

    #==========================
    : Check the MG_TYPE input
    #==========================
    if [[ -n $mg_type ]]; then
        if [[ $type == "ds8k_inband_mm" ]]; then
            if [[ -z $LANG || $LANG=@(C|en|En|EN)* ]]; then
                case $mg_type in
                    u*) mg_type="user"       ;;
                    s*) mg_type="system"     ;;
                    r*) mg_type="repository" ;;
                     *) /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 110 "\nERROR: invalid value specified for \"%1\$s\":  \"%2\$s\".\n" MG_TYPE "$mg_type" 1>&2
                        /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 3 "Valid values: %1\$s\n\n" "user, system, repository" 1>&2
                        rc=$RC_INCORRECT_INPUT
                    ;;
                esac
            else # Convert other languages to English, for internal processing
                typeset -l UTYPE=$(dspmsg -s 4 genxd.cat 56 "User")
                typeset -l STYPE=$(dspmsg -s 4 genxd.cat 57 "System")
                typeset -l RTYPE=$(dspmsg -s 4 genxd.cat 58 "Repositories")
                if [[ $UTYPE == $mg_type* ]]; then
                    mg_type="user"
                elif [[ $STYPE == $mg_type* ]]; then
                    mg_type="system"
                elif [[ $RTYPE == $mg_type* ]]; then
                    mg_type="repository"
                else
                    dspmsg -s $CLMGR_SET $CLMGR_MSGS 110 "\nERROR: invalid value specified for \"%1\$s\":  \"%2\$s\".\n" MG_TYPE "$mg_type" 1>&2
                    dspmsg -s $CLMGR_SET $CLMGR_MSGS 3 "Valid values: %1\$s\n\n" \
"$(dspmsg -s 4 genxd.cat 56 'User'),\
 $(dspmsg -s 4 genxd.cat 57 'System'),\
 $(dspmsg -s 4 genxd.cat 58 'Repositories')" 1>&2
                    rc=$RC_INCORRECT_INPUT
                fi
            fi

        elif [[ $type == "emc" ]]; then
            case $mg_type in
                c*) mg_type="CompGroup" ;;
                d*) mg_type="DevGroup"  ;;
                 *) /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 110 "\nERROR: invalid value specified for \"%1\$s\":  \"%2\$s\".\n" MG_TYPE "$mg_type" 1>&2
                    /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 3 "Valid values: %1\$s\n\n" "composite, device" 1>&2
                    rc=$RC_INCORRECT_INPUT
                ;;
            esac

        else
            /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 45 '\nERROR: "%1$s" may only be used with "%2$s".\n\n' MG_TYPE "TYPE={ds8k_inband_mm|emc}" 1>&2
            rc=$RC_INCORRECT_INPUT
        fi

    elif [[ $type == @(ds8k_inband_mm|emc) ]]; then
        /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 101 "\nERROR: this operation requires the \"%1\$s\" attribute.\n\n" "MG_TYPE" 1>&2
        rc=$RC_MISSING_INPUT
    fi

    #==========================================
    : Check the HyperSwap-specific attributes
    #==========================================
    if [[ $type == "ds8k_inband_mm" ]]; then

        if [[ $hs_enabled != *([[:space:]]) ]]; then
            if [[ $hs_enabled == @(e|y|t)* ]]; then
                hs_enabled="enabled"
            elif [[ $hs_enabled == @(d|n|f)* ]]; then
                hs_enabled="disabled"
            else
                /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 110 "\nERROR: invalid value specified for \"%1\$s\":  \"%2\$s\".\n" HYPERSWAP_ENABLED "$hs_enabled" 1>&2
                /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 3 "Valid values: %1\$s\n\n" "no, yes" 1>&2
                rc=$RC_INCORRECT_INPUT
            fi
        fi

        if [[ $hs_priority != *([[:space:]]) ]]; then
            case $hs_priority in
                @(m|M)*) hs_priority="Medium" ;;
                @(h|H)*) hs_priority="High"   ;;
                      *) /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 110 "\nERROR: invalid value specified for \"%1\$s\":  \"%2\$s\".\n" HYPERSWAP_PRIORITY "$hs_priority" 1>&2
                         /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 3 "Valid values: %1\$s\n\n" "medium, high" 1>&2
                         rc=$RC_INCORRECT_INPUT
                ;;
            esac
        fi

        if [[ $hs_unpl_timeout != *([[:space:]]) ]]; then
            CL=$LINENO verify_is_numeric "$hs_unpl_timeout" 2 UNPLANNED_HS_TIMEOUT
            (( $? != RC_SUCCESS )) && rc=$RC_INCORRECT_INPUT
        fi

        if [[ $mg_type == @(user|system) ]]; then
            if [[ -z $volume_groups && -z $raw_disks ]]; then
                CL=$LINENO cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 284 '\nERROR: "%1$s" requires one of the following options:\n\n' "MG_TYPE=$mg_type" 1>&2
                print -u2 "\t\tVOLUME_GROUPS, RAW_DISKS\n"
                rc=$RC_INCORRECT_INPUT
            fi
        elif [[ -n $volume_groups ]]; then
            /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 45 '\nERROR: "%1$s" may only be used with "%2$s".\n\n' VOLUME_GROUPS "MG_TYPE={user|system}" 1>&2
            rc=$RC_INCORRECT_INPUT
        elif [[ -n $raw_disks ]]; then
            /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 45 '\nERROR: "%1$s" may only be used with "%2$s".\n\n' RAW_DISKS "MG_TYPE={user|system}" 1>&2
            rc=$RC_INCORRECT_INPUT
        fi

        if [[ $mg_type == @(user|system) ]]; then
            if [[ -n $volume_groups ]]; then
                typeset vg=""
                typeset -i all_vgs_found=1
                for vg in ${volume_groups//,/ }; do
                    if [[ $vg == "rootvg" ]]; then
                        if [[ $mg_type != "system" ]]; then
                            dspmsg -s $CLMGR_SET $CLMGR_MSGS 45 '\nERROR: "%1$s" may only be used with "%2$s".\n\n' "$vg" "MG_TYPE=system" 1>&2
                            rc=$RC_INCORRECT_INPUT
                            all_vgs_found=0
                        fi
                        continue  # Special case; avoid validation
                    fi

                    CL=$LINENO KLIB_HACMP_is_known_volume_group "$vg" >/dev/null 2>&1
                    if (( $? != RC_SUCCESS )); then
                        /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 102 "\nERROR: \"%1\$s\" does not appear to exist!\n\n" "$vg" 1>&2
                        rc=$RC_INCORRECT_INPUT
                        all_vgs_found=0
                    fi
                done
                if (( ! all_vgs_found )); then
                    /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 160 "Available Volume Groups:\n\n" 1>&2
                    typeset available
                    CL=$LINENO KLIB_HACMP_list_volume_groups available
                    for (( i=0; i<${#available[*]}; i++ )); do
                        if [[ ${available[$i]} != *([[:space:]]) ]]; then
                            print -u2 "\t${available[$i]}"
                        fi
                    done
                    print -u2 ""
                fi
            fi
        fi

        if [[ $mg_type == @(user|system) ]]; then
            typeset new_disks=""
            if [[ -n $raw_disks ]]; then
                typeset -i all_disks_found=1
                typeset disk="" dname="" duuid="" rem=""
                typeset -A diskMap
                LC_ALL=C LANG=C $HAXDCLI/clxd_list_rdisk |\
                while read dname duuid rem; do
                    [[ $dname == "Device" ]] && continue
                    [[ $dname == *([[:space:]]) ]] && continue
                    diskMap[$dname]=$duuid
                done

                for disk in ${raw_disks//,/ }; do
                    if [[ " ${!diskMap[*]} " != *\ $disk\ * && \
                          " ${diskMap[*]} "  != *\ $disk\ * ]]
                    then
                        /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 285 '\nERROR: "%1$s" either does not exist, or is not a raw disk.\n\n' "$disk" 1>&2
                        rc=$RC_INCORRECT_INPUT
                        all_disks_found=0
                    else
                        typeset pv=""
                        for pv in ${!diskMap[*]}; do
                            if [[ $pv == $disk ]]; then
                                new_disks="$new_disks ${diskMap[$pv]}"
                                break
                            elif [[ ${diskMap[$pv]} == $disk ]]; then
                                new_disks="$new_disks ${diskMap[$pv]}"
                                break
                            fi
                        done
                    fi
                done
                if (( ! all_disks_found )); then
                    /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 153 "Available Physical Volumes:\n\n" 1>&2
                    $HAXDCLI/clxd_list_rdisk 1>&2
                    print -u2 ""
                else
                    raw_disks=${new_disks# }
                fi
            fi
        fi

        if [[ $mg_type == "system" ]]; then
            if [[ -n $node ]]; then
                CL=$LINENO KLIB_HACMP_is_known_node $node >/dev/null
                if (( $? != RC_SUCCESS )); then
                    rc=$RC_NOT_FOUND
                    /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 102 "\nERROR: \"%1\$s\" does not appear to exist!\n\n" "$node" 1>&2
                    /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 151 "Available Nodes:\n\n" 1>&2

                    typeset available
                    CL=$LINENO KLIB_HACMP_list_nodes available
                    for (( i=0; i<${#available[*]}; i++ )); do
                        if [[ ${available[$i]} != *([[:space:]]) ]]; then
                            print -u2 "\t${available[$i]}"
                        fi
                    done
                    print -u2 ""
                fi

            else
                CL=$LINENO cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 37 '\nERROR: option "%1$s" is required when any of the following option(s)\n       are used: %2$s\n\n' NODE "MG_TYPE=system" 1>&2
                rc=$RC_INCORRECT_INPUT
            fi

        elif [[ -n $node ]]; then
            /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 45 '\nERROR: "%1$s" may only be used with "%2$s".\n\n' NODE "MG_TYPE=system" 1>&2
            rc=$RC_INCORRECT_INPUT
        fi

        if [[ $mg_type == "repository" ]]; then
            if [[ -n $site ]]; then
                CL=$LINENO KLIB_HACMP_is_known_site $site >/dev/null
                if (( $? != RC_SUCCESS )); then
                    rc=$RC_NOT_FOUND
                    /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 102 "\nERROR: \"%1\$s\" does not appear to exist!\n\n" "$site" 1>&2
                    /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 157 "Available Sites:\n\n" 1>&2

                    typeset available
                    CL=$LINENO KLIB_HACMP_list_sites available
                    for (( i=0; i<${#available[*]}; i++ )); do
                        if [[ ${available[$i]} != *([[:space:]]) ]]; then
                            print -u2 "\t${available[$i]}"
                        fi
                    done
                    print -u2 ""
                fi

            else
                CL=$LINENO cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 37 '\nERROR: option "%1$s" is required when any of the following option(s)\n       are used: %2$s\n\n' SITE "MG_TYPE=repository" 1>&2
                rc=$RC_INCORRECT_INPUT
            fi

        elif [[ -n $site ]]; then
            /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 45 '\nERROR: "%1$s" may only be used with "%2$s".\n\n' SITE "MG_TYPE=repository" 1>&2
            rc=$RC_INCORRECT_INPUT
        fi

        if [[ $mg_type == "repository" ]]; then
            if [[ -n $non_hs_disk ]]; then
                typeset -i found=0
                typeset dname="" duuid="" rem=""
                LC_ALL=C LANG=C $HAXDCLI/clxd_list_rdisk |\
                while read dname duuid rem; do
                    [[ $dname == "Device" ]] && continue
                    [[ $dname == *([[:space:]]) ]] && continue
                    if [[ $dname == $non_hs_disk || \
                          $duuid == $non_hs_disk ]]
                    then
                        non_hs_disk="$duuid"  # Convert to UUID
                        found=1
                    fi
                done

                if (( ! found )); then
                    /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 285 '\nERROR: "%1$s" either does not exist, or is not a raw disk.\n\n' "$non_hs_disk" 1>&2
                    rc=$RC_INCORRECT_INPUT

                    /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 153 "Available Physical Volumes:\n\n" 1>&2
                    $HAXDCLI/clxd_list_rdisk 1>&2
                    print -u2 ""
                fi

            else
                CL=$LINENO cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 37 '\nERROR: option "%1$s" is required when any of the following option(s)\n       are used: %2$s\n\n' NON_HS_DISK "MG_TYPE=repository" 1>&2
                rc=$RC_INCORRECT_INPUT
            fi

        elif [[ -n $non_hs_disk ]]; then
            /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 45 '\nERROR: "%1$s" may only be used with "%2$s".\n\n' NON_HS_DISK "MG_TYPE=repository" 1>&2
            rc=$RC_INCORRECT_INPUT
        fi

        if [[ $mg_type == "repository" ]]; then
            if [[ -n $hs_disk ]]; then
                typeset -i found=0
                typeset dname="" duuid="" rem=""
                LC_ALL=C LANG=C $HAXDCLI/clxd_list_rdisk |\
                while read dname duuid rem; do
                    [[ $dname == "Device" ]] && continue
                    [[ $dname == *([[:space:]]) ]] && continue
                    if [[ $dname == $hs_disk || \
                          $duuid == $hs_disk ]]
                    then
                        hs_disk="$duuid"  # Convert to UUID
                        found=1
                    fi
                done

                if (( ! found )); then
                    /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 285 '\nERROR: "%1$s" either does not exist, or is not a raw disk.\n\n' "$hs_disk" 1>&2
                    rc=$RC_INCORRECT_INPUT

                    /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 153 "Available Physical Volumes:\n\n" 1>&2
                    $HAXDCLI/clxd_list_rdisk
                    print -u2 ""
                fi

            else
                CL=$LINENO cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 37 '\nERROR: option "%1$s" is required when any of the following option(s)\n       are used: %2$s\n\n' HS_DISK "MG_TYPE=repository" 1>&2
                rc=$RC_INCORRECT_INPUT
            fi

        elif [[ -n $hs_disk ]]; then
            /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 45 '\nERROR: "%1$s" may only be used with "%2$s".\n\n' HS_DISK "MG_TYPE=repository" 1>&2
            rc=$RC_INCORRECT_INPUT
        fi

        if [[ $mg_type != "repository" ]]; then
            typeset PAIR="" attr="" value=""
            for PAIR in "SITE:$site" \
                        "NON_HS_DISK:$non_hs_disk" \
                        "HS_DISK:$hs_disk"
            do
                attr=${PAIR%%:*}
                value=${PAIR#*:}
                if [[ -n $value ]]; then
                    /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 45 '\nERROR: "%1$s" may only be used with "%2$s".\n\n' "$attr" "MG_TYPE=repository" 1>&2
                    rc=$RC_INCORRECT_INPUT
                fi
            done
       fi

    elif [[ -n $type ]]; then
        typeset PAIR="" attr="" value=""
        for PAIR in "MG_TYPE:$mg_type" \
                    "HYPERSWAP_ENABLED:$hs_enabled" \
                    "HYPERSWAP_PRIORITY:$hs_priority" \
                    "UNPLANNED_HS_TIMEOUT:$hs_unpl_timeout" \
                    "NODE:$node" \
                    "SITE:$site" \
                    "NON_HS_DISK:$non_hs_disk" \
                    "HS_DISK:$hs_disk"
        do
            attr=${PAIR%%:*}
            value=${PAIR#*:}
            if [[ -n $value ]]; then
                if [[ $attr == "MG_TYPE" && $type == "emc" ]]; then
                    continue
                fi

                /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 45 '\nERROR: "%1$s" may only be used with "%2$s".\n\n' "$attr" TYPE=ds8k_inband_mm 1>&2
                rc=$RC_INCORRECT_INPUT
            fi
        done
    fi

    #========================================
    : Check the Hitachi-specific attributes
    #========================================
    if [[ -n $horcm_instance && $type != "hitachi" ]]; then
        /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 45 '\nERROR: "%1$s" may only be used with "%2$s".\n\n' HORCM_INSTANCE TYPE=hitachi 1>&2
        rc=$RC_INCORRECT_INPUT
    fi
    if [[ -n $horcm_timeout ]]; then
        if [[ $type != "hitachi" ]]; then
            /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 45 '\nERROR: "%1$s" may only be used with "%2$s".\n\n' HORCM_TIMEOUT TYPE=hitachi 1>&2
            rc=$RC_INCORRECT_INPUT
        else
            CL=$LINENO verify_is_numeric "$horcm_timeout" 2 HORCM_TIMEOUT
            (( $? != RC_SUCCESS )) && rc=$RC_INCORRECT_INPUT
        fi
    fi
    if [[ -n $pair_event_timeout ]]; then
        if [[ $type != "hitachi" ]]; then
            /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 45 '\nERROR: "%1$s" may only be used with "%2$s".\n\n' PAIR_EVENT_TIMEOUT TYPE=hitachi 1>&2
            rc=$RC_INCORRECT_INPUT
        else
            CL=$LINENO verify_is_numeric "$pair_event_timeout" 2 PAIR_EVENT_TIMEOUT
            (( $? != RC_SUCCESS )) && rc=$RC_INCORRECT_INPUT
        fi
    fi

    if [[ $recovery != *([[:space:]]) ]]; then
        if [[ $type == "ds8k_inband_mm" && \
              $mg_type != u* ]]
        then
            /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 45 '\nERROR: "%1$s" may only be used with "%2$s".\n\n' RECOVERY "MG_TYPE=user" 1>&2
            rc=$RC_INCORRECT_INPUT
        else
            case $recovery in
                @(a|A)*)
                    recovery="auto"
                    [[ $type == "emc" ]] && recovery="AUTO"
                ;;
                @(m|M)*)
                    recovery="manual"
                    [[ $type == "emc" ]] && recovery="MANUAL"
                ;;
                *)  /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 110 "\nERROR: invalid value specified for \"%1\$s\":  \"%2\$s\".\n" RECOVERY "$recovery" 1>&2
                    /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 3 "Valid values: %1\$s\n\n" "auto, manual" 1>&2
                    rc=$RC_INCORRECT_INPUT
                ;;
            esac
        fi
    fi

    if [[ $resync != *([[:space:]]) ]]; then
        if [[ $type == "ds8k_inband_mm" && \
              $mg_type != @(u|r)* ]]
        then
            /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 45 '\nERROR: "%1$s" may only be used with "%2$s".\n\n' RECOVERY "MG_TYPE={user|repository}" 1>&2
            rc=$RC_INCORRECT_INPUT
        else
            if [[ $resync != *([[:space:]]) ]]; then
                CL=$LINENO verify_in_set RESYNC "$resync" "manual, automatic" resync
                (( $? != RC_SUCCESS )) && rc=$RC_INCORRECT_INPUT
            fi
        fi
    fi

    #========================================================================
    : If no errors have been detected yet, set any defaults that are needed
    #========================================================================
    if (( $rc == RC_UNKNOWN )); then
        case $type in
            ds8k_inband_mm)
                [[ -z $mode ]] && mode="sync"
                [[ -z $hs_enabled      ]] && hs_enabled="disabled"
                [[ -z $consistent      ]] && consistent="yes"
                [[ -z $hs_unpl_timeout ]] && hs_unpl_timeout=60
                [[ -z $recovery        ]] && recovery="manual"
                [[ -z $resync          ]] && resync="manual"

                if [[ $mg_type == "user" ]]; then
                    [[ -z $hs_priority ]] && hs_priority="Medium"
                elif [[ $mg_type == @(system|repository) ]]; then
                    [[ -z $hs_priority ]] && hs_priority="High"
                fi
            ;;
            ds8k_gm)
                [[ -z $recovery   ]] && recovery="automatic"
                [[ -z $mode       ]] && mode="sync"
                [[ -z $consistent ]] && consistent="yes"
            ;;
            hitachi)
                [[ -z $horcm_timeout      ]] && horcm_timeout=300
                [[ -z $pair_event_timeout ]] && pair_event_timeout=3600
            ;;
            svc)
                [[ -z $recovery   ]] && recovery="AUTO"
                [[ -z $mode       ]] && mode="sync"
            ;;
            xiv*)
                [[ -z $recovery   ]] && recovery="automatic"
                [[ -z $mode       ]] && mode="sync"
                [[ -z $consistent ]] && consistent="yes"
            ;;
        esac
    fi

    #================================================================
    : Create the mirror group if no input errors have been detected
    #================================================================
    if (( $rc == RC_UNKNOWN )); then
        typeset value="" SOpts="" vOpt="" oOpts="" pOpts="" gOpt=""
        typeset IOpt="" HOpt="" POpt="" rOpt="" mOpt="" aOpts="" lOpts=""
        typeset xOpt="" tOpt="" pOpt="" eOpt="" yOpt="" iOpt="" wOpt="" dOpt=""
        typeset YOpt="" ROpt=""

        [[ -n $mode               ]] && mOpt=" -m $mode"
        [[ -n $recovery           ]] && rOpt=" -r $recovery"
        [[ -n $resync             ]] && ROpt=" -R $resync"
        if [[ -n $vendor_id ]]; then
            case $type in
                hitachi) vOpt=" -D $vendor_id" ;;
                emc)     vOpt=" -D $vendor_id" ;;
                *)       vOpt=" -v $vendor_id" ;;
            esac
        fi
        [[ -n $consistent         ]] && gOpt=" -g $consistent"
        [[ -n $horcm_instance     ]] && IOpt=" -I $horcm_instance"
        [[ -n $horcm_timeout      ]] && HOpt=" -H $horcm_timeout"
        [[ -n $pair_event_timeout ]] && POpt=" -P $pair_event_timeout"

        [[ -n $mg_type            ]] && yOpt=" -y $mg_type"
        [[ -n $hs_enabled         ]] && xOpt=" -x $hs_enabled"
        [[ -n $hs_unpl_timeout    ]] && tOpt=" -t $hs_unpl_timeout"
        [[ -n $hs_priority        ]] && YOpt=" -Y $hs_priority"
        [[ -n $node               ]] && eOpt=" -e $node"
        [[ -n $site               ]] && iOpt=" -i $site"
        [[ -n $non_hs_disk        ]] && wOpt=" -w $non_hs_disk"
        [[ -n $hs_disk            ]] && dOpt=" -d $hs_disk"

        if [[ -n $attributes ]]; then
            for value in ${attributes//,/ }; do
                oOpts="$oOpts -o${value//@/ }"
            done
        fi

        if [[ -n $storage_systems ]]; then
            for value in ${storage_systems//,/ }; do
                SOpts="$SOpts -S $value"
            done
        fi

        if [[ -n $mirror_pairs ]]; then
            for value in ${mirror_pairs//,/ }; do
                pOpts="$pOpts -p $value"
            done
        fi

        if [[ -n $raw_disks ]]; then
            for value in ${raw_disks//,/ }; do
                aOpts="$aOpts -a $value"
            done
        fi

        if [[ -n $volume_groups ]]; then
            for value in ${volume_groups//,/ }; do
                lOpts="$lOpts -l $value"
            done
        fi

        print -- "$0()[$LINENO]($SECONDS): $HAXDWIZ/clxd_create_mg_director -s $type -n $mirror_group$yOpt$lOpts$aOpts$mOpt$rOpt$ROpt$SOpts$vOpt$pOpts$IOpt$HOpt$POpt$iOpt$eOpt$wOpt$dOpt$xOpt$gOpt$tOpt$YOpt$oOpts" >>$CLMGR_TMPLOG
        $HAXDWIZ/clxd_create_mg_director -s $type -n $mirror_group$yOpt$lOpts$aOpts$mOpt$rOpt$ROpt$SOpts$vOpt$pOpts$IOpt$HOpt$POpt$iOpt$eOpt$wOpt$dOpt$xOpt$gOpt$tOpt$YOpt$oOpts
        rc=$?
        print "$0()[$LINENO]($SECONDS): clxd_create_mg_director RC: $rc" >>$CLMGR_TMPLOG

        if (( $rc != RC_SUCCESS )); then
            /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 201 "\nERROR: failed to create \"%1\$s\".\n\n" "$mirror_group" 1>&2
            rc=$RC_ERROR
        fi

        #===========================================================
        : If output from this operation was requested, retrieve it
        #===========================================================
        if (( $rc == RC_SUCCESS )); then
            if (( CLMGR_VERBOSE )) || [[ -n $CLMGR_ATTRS ]]; then
                CL=$LINENO KLIB_HACMP_get_mirror_group_attributes "$mirror_group" properties
            fi
        fi
    fi

    #=======================================================================
    : If a user input error was detected, provide some helpful suggestions
    #=======================================================================
    if (( $rc == RC_MISSING_INPUT || $rc == RC_INCORRECT_INPUT )) && \
       [[ $CLMGR_GUI == *([[:space:]]) ]]
    then
        CL=$LINENO cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 104 "For more information about available options and syntax, try\n\"$HAUTILS/clmgr %1\$s\". As an\nalternative, if the PowerHA SystemMirror man pages have been installed, invoke\n\"$HAUTILS/clmgr -hv\" (or \"/usr/bin/man clmgr\"),\nsearching for \"%2\$s\" in the displayed text.\n\n" \
        "add mirror_group -h" "MIRROR GROUP:" "$CLMGR_PROGNAME" 1>&2
    fi

    log_return_msg "$rc" "$0()" "$LINENO"
    return $?
} # End of "KLIB_HACMP_add_mirror_group()"
#================================================
# The following, commented line enforces coding
# standards when this file is edited via vim.
#================================================
# vim:tabstop=4:shiftwidth=4:expandtab:smarttab
#================================================
