#!/usr/bin/ksh93 ################################################################ function usagemsg_mapluns { print " Program: mapluns.sh The purpose of this script is to map the disks from a VIO server to their respective virtual SCSI slot numbers, virtual adapters, and LDEV numbers. IF THIS SCRIPT HANGS OR GETS A SEGMENTATION FAULT, DOWNLOAD KSH93 FROM WWW.KORNSHELL.COM AND USE IT AS THE INTERPRETER FOR THIS SCRIPT. This script is intended to be run on a VIO server in the "oem_setup_env" environment. The output from this script is a table of information containing the name of the VIO server, hdisk name, virtual adapter name, virtual slot number, the SAN LDEV ID, VTD, and associated partitions. Usage: ${1##*/} [-?vV] [-h HMCname -u HMCuser] [-n #] [-s SystemName1,...] Where: -v = Verbose mode - displays lsvioslot function info -V = Very Verbose Mode - debug output displayed -h = HMC machine name -u = HMC user name -n # = Prompt the user # times to select managed systems -s = List of managed system names from which to obtain slot information Author: Dana French (dfrench@mtxia.com) Copyright 2006, 2007, 2008 All Rights Reserved \"AutoContent\" enabled " } ################################################################ #### #### Description #### #### Assumptions: #### #### Dependencies: #### #### Products: #### #### Configured Usage: #### #### Details: ################################################################ function mapluns { typeset VERSION="2.1" typeset TRUE="1" typeset FALSE="0" typeset EXITCODE="0" typeset VERBOSE="${FALSE}" typeset VERYVERB="${FALSE}" typeset HMCLIST="${FALSE}" typeset USEMAP="${FALSE}" typeset USEMAPFILE="" typeset HMCUSER="" typeset HMCNAME="" typeset LPARNAME="" typeset SYSNAMES="" typeset SYSNAME="" typeset SYSNBR="0" typeset HDISK="" typeset VHOST="" typeset VSLOT="" typeset LDEV="" typeset TMPDISK="" typeset LSCFG="" typeset LINE="" typeset ICNT="0" #### #### Process the command line options and arguments, saving #### the values as appropriate. #### while getopts ":vVu:h:s:n#" OPTION do case "${OPTION}" in 'u') HMCUSER="${OPTARG}";; 'h') HMCNAME="${OPTARG}";; 's') IFS=$' \t,:/' SYSNAMES=( ${OPTARG} ) SYSNBR="${#SYSNAMES[*]}" IFS=$' \t\n';; 'n') SYSNBR="${OPTARG}";; 'L') USEMAP="${TRUE}" USEMAPFILE="${OPTARG}";; 'v') VERBOSE="${TRUE}";; 'V') VERYVERB="${TRUE}";; [?:#]) usagemsg_mapluns "${0}" && return 1 ;; esac done shift $(( ${OPTIND} - 1 )) trap "usagemsg_mapluns ${0}" EXIT if (( USEMAP == TRUE )) && [[ ! -s "${USEMAPFILE}" ]] then usagemsg_mapluns "Invalid LUN map file name" return 1 fi trap "-" EXIT unset VFLAG (( VERYVERB == TRUE )) && set -x (( VERBOSE == TRUE )) && typeset VFLAG="-v" (( VERBOSE == TRUE )) && print -u 2 "# Program........: ${0}" (( VERBOSE == TRUE )) && print -u 2 "# Version........: ${VERSION}" (( VERBOSE == TRUE )) && print -u 2 "# Author.........: Dana French, Mt Xia Inc." (( VERBOSE == TRUE )) && print -u 2 "# Email..........: dfrench@mtxia.com" (( VERBOSE == TRUE )) && print -u 2 "# Copyright......: 2006, 2007, 2008, All Rights Reserved" ################################################################ #### Retrieve Slot numbers from the multiple frames. #### if [[ "_${HMCNAME}" != "_" ]] && [[ "_${HMCUSER}" != "_" ]] then typeset -A LNAMES typeset -A NODISKS for (( IDX=0; IDX /tmp/tmp${$}.sh # . /tmp/tmp${$}.sh # rm -f /tmp/tmp${$}.sh eval $( lsvioslot -h ${HMCNAME} -u ${HMCUSER} -s ${SYSNAME} ${VFLAG} ) for NAME in "${!LPAR_NAME[@]}" do if [[ "_${LPAR_NAME[${NAME}]}" == "_aixlinux" ]] then LNAMES[${NAME}]="${LPAR_NAME[${NAME}]}" NODISKS[${NAME}]="${LPAR_NAME[${NAME}]}" # print "LNAMES[${NAME}]=${LNAMES[${NAME}]}" fi done done fi unset LPAR_NAME ################################################################ #### #### Retrieve a list of VHOST adapters and their #### associated SLOT numbers from the localhost VIO server. #### lscfg -l 'vhost*' | while read -r -- VHOST SLOT JUNK do ALLSLOTS[${SLOT##*-C}]="${VHOST}" done ################################################################ #### Retrieve a list of all disks and LUN ID numbers. typeset -A HDSN lscfg -vl 'hdisk*' | egrep 'hdisk|Serial Number' | while IFS=$' \t\n' read -r -- HDISK JUNK do read -r -- HDSERIAL HDSERIAL="${HDSERIAL##*.}" HDSN[${HDISK}]="${HDSERIAL}" done typeset -A ALLDISKS lscfg -vl 'hdisk*' | egrep 'hdisk|Z1' | while IFS=$' \t\n' read -r -- HDISK JUNK do IFS=')' read -r -- F1 LDEV LDEV="${LDEV//./}" LDEV="${LDEV%% *}" ALLDISKS[${HDISK}]="${LDEV}" done IFS=$' \t\n' typeset -A PVIDS lspv | while IFS=$' \t\n' read -r -- HDISK PVID JUNK do PVIDS[${HDISK}]="${PVID}" done IFS=$' \t\n' #### Retrieve a list of all VHOST information from the #### localhost VIO server. IFS=$'\n' LSMAP=( $( /usr/ios/cli/ioscli lsmap -all ) ) typeset HOSTID=$( hostname ) print -u 2 "# hostname:hdisk:hdsn:vadapter:vslot:ldev:pvid:vtd:lpars" #### Parse though the stored VHOST information, one line at a #### time, extracting specfic pieces of information. for MAPLN in "${LSMAP[@]//Backing device/BackingDevice}" do #### Determine if the line of VHOST information contains the #### VHOST ID, backing device name, or VTD name. If not, #### continue with the next iteration of the loop. [[ "_${MAPLN}" != _@(vhost|BackingDevice|VTD)* ]] && continue #### If the line of VHOST information contains the VHOST ID, #### extract the VHOST ID, and the SLOT number from this #### line and continue with the next iteration of the loop. if [[ "_${MAPLN}" = _vhost* ]] then VHOST=${MAPLN%%[$' \t']*} VHOST=${VHOST#*[$' \t']} VSLOT=${MAPLN##*-} VSLOT=${VSLOT%%[$' \t']*} continue fi #### If the line of VHOST information contains the VTD, #### extract the VTD from this line and continue with #### the next iteration of the loop. if [[ "_${MAPLN}" = _VTD* ]] then VTD=${MAPLN##*[$' \t']} [[ "_${VTD}" == _FOUND ]] && VTD="" continue fi HDISK=${MAPLN##*[$' \t']} TMPDISK="${HDISK}" #### Identify an hdisk associated with the HDLM disk #### device. if [[ "_${TMPDISK}" = _dlmfdrv* ]] then TMPDISK=$( /usr/DynamicLinkManager/bin/dlnkmgr view -drv | grep "${TMPDISK}" | awk '{ print $3 }' | head -1 ) fi #### Obtain the hdisk configuration settings from the #### ODM and store in an array. LSCFG=( $( lscfg -vl ${TMPDISK} ) ) #### Loop through the array and extract the LDEV number. LDEV="" HDSERIAL="" for LINE in "${LSCFG[@]}" do if [[ "_${LINE}" = *'Serial Number'* ]] then HDSERIAL="${LINE##*.}" HDSERIAL=${HDSERIAL%%[$' \t']*} fi if [[ "_${LINE}" = *\(Z1\)* ]] then LDEV=${LINE#*\(Z1\)} LDEV=${LDEV//./} LDEV=${LDEV%%[$' \t']*} fi done #### #### Read through a previously created DISKMAP file and #### extract the LABEL information from the last field #### typeset LABEL="" if (( USEMAP == TRUE )) && [[ -s "${USEMAPFILE}" ]] then while IFS=":" read -r -A -- PREV do [[ "_${PREV[4]}" == "_${LDEV}" ]] && LABEL="${PREV[5]//$'\t'/} ${PREV[6]//$'\t'/}" done < "${USEMAPFILE}" fi typeset LPARNAME="" typeset LNAME for LNAME in "${!LNAMES[@]}" do unset ARY typeset ARY typeset IDX LPARVAR="${LNAME//[!A-Za-z0-9]/}" eval ARY="( \${!SLOT_${LPARVAR}[@]} )" for IDX in "${ARY[@]}" do # print "SLOT_${LPARVAR}[${IDX}]" if (( ${IDX} == ${VSLOT//[!0-9]/} )) then LPARNAME="${LPARNAME},${LNAME}" unset NODISKS[${LNAME}] unset ALLSLOTS[${IDX}] fi done done LPARNAME="${LPARNAME#,}" PVID="${PVIDS[${HDISK}]}" print -u 2 "# ${HOSTID}:${HDISK}:${HDSERIAL}:${VHOST}:${VSLOT}:${LDEV}:${PVID}:${VTD}:${LPARNAME}:\t${LABEL}" DISK_ARY[ICNT]="${HDISK}" CMD_ARY[ICNT++]="/usr/ios/cli/ioscli mkvdev -vdev ${HDISK} -vadapter ${VHOST} -dev ${VTD}" # HDISK="" VHOST="" VSLOT="" LDEV="" HDISK="" LDEV="" VTD="" done #### List of HDISKs not associated with any virtual LPAR print -u 2 "# \n# List of HDISKs not associated with any virtual LPAR" print -u 2 "# hostname:hdisk:hdsn:vadapter:vslot:ldev:pvid:vtd:lpars" HDISK="" VHOST="" VSLOT="" LDEV="" VTD="" LPARNAME="" PVID="" IFS="," ADISK=",${DISK_ARY[*]}," IFS=$' \t\n' for HDISK in "${!ALLDISKS[@]}" do if [[ "_${ADISK}" != *,${HDISK},* ]] then HDSERIAL="${HDSN[${HDISK}]}" LDEV="${ALLDISKS[${HDISK}]}" PVID="${PVIDS[${HDISK}]}" print -u 2 "# ${HOSTID}:${HDISK}:${HDSERIAL}:${VHOST}:${VSLOT}:${LDEV}:${PVID}:${VTD}:${LPARNAME}" fi done LDEV="" PVID="" HDSERIAL="" #### List of LPAR's not associated with any virtual scsi adapters print -u 2 "# \n# List of LPAR's not associated with any virtual SCSI adapters" print -u 2 "# hostname:hdisk:hdsn:vadapter:vslot:ldev:pvid:vtd:lpars" HDISK="" for LNAME in "${!NODISKS[@]}" do print -u 2 "# ${HOSTID}:${HDISK}:${HDSERIAL}:${VHOST}:${VSLOT}:${LDEV}:${PVID}:${VTD}:${LNAME}" done #### List of virtual SCSI adapters and slots not associated with any LPAR print -u 2 "# \n# List of virtual SCSI adapters and slots not associated with any LPAR" print -u 2 "# hostname:hdisk:hdsn:vadapter:vslot:ldev:pvid:vtd:lpars" unset LNAME for VSLOT in "${!ALLSLOTS[@]}" do VHOST="${ALLSLOTS[${VSLOT}]}" print -u 2 "# ${HOSTID}:${HDISK}:${HDSERIAL}:${VHOST}:C${VSLOT}:${LDEV}:${PVID}:${VTD}:${LNAME}" done print #### Print the VIO command lines required to recreate the current #### VHOST adapter configuration. for LINE in "${CMD_ARY[@]}" do print "${LINE}" done return 0 } ################################################################ ################################################################ function usagemsg_lsvioslot { print " Program: lsvioslot List the slot adapters and associated slot numbers for one or more LPAR's from a VIO server. Usage: ${1##*/} [-?vV] -h HMCname [-l LPARname] [-u HMCuser] [-s SystemName] [-L] [-d] [-k] [-D X] Where: -v = Verbose mode - displays lsvioslot function info -V = Very Verbose Mode - debug output displayed -h = HMC machine name -u = HMC user name -l = List slots/slots for specific LPAR -s = System name from which to obtain slot information -L = Display a list of systems managed by the specified HMC -d = Output is formatted as colon (:) delimited data records -k = Output is coded as Korn Shell 93 arrays (Default) -D X = Specify a different delimiter to use in delimited data records Author: Dana French (dfrench@mtxia.com) Copyright 2006, 2007, 2008 All Rights Reserved \"AutoContent\" enabled " } ################################################################ #### #### Description: #### #### The lsvioslot function retrieves "slot" information for #### virtual SCSI adapters from an HMC and builds formatted #### output based upon user requirements. The formatted #### output can take the form of Korn Shell code containing #### arrays of information, or data records. #### #### Assumptions: #### #### This script assumes "ssh" connectivity to the HMC, but #### not necessarily "password-less" login. #### #### The HMC user is assumed to have the ability to retrieve #### HMC configuration information. #### #### Dependencies: #### #### Connectivity with the HMC using "ssh" is the only #### communication mechanism supported at this time. #### #### Products: #### #### Two output types are provided at this time, Korn Shell #### coded arrays of information, and colon (:) delimited #### data records. One or both types may be output from a #### single execution of the function. #### #### The two data types are generated on separate data #### streams. The Korn shell code is generated on the STDOUT #### steam, the data record formatted output is generated on #### the STDERR stream. #### #### #### Configured Usage: #### #### This function is expected to be called from a Korn Shell #### function library, but may be incorporated into a #### stand-alone script if necessary. #### #### An HMC managed system name must be provided by the user #### of this function. That name can be provided on the #### command line, or by selecting it from a menu. If a #### managed system name is not provided on the command line, #### a menu is generated on STDERR, and the user must select #### a system from the menu. #### #### Details: #### ################################################################ function lsvioslot { typeset VERSION="2.1" typeset TRUE="1" typeset FALSE="0" typeset EXITCODE="0" typeset VERBOSE="${FALSE}" typeset VERYVERB="${FALSE}" typeset HMCUSER="" typeset HMCNAME="" typeset LPARNAME="" typeset SYSNAME="" typeset LPAROUT="" typeset HMCLIST="${FALSE}" typeset KORNOUT="${FALSE}" typeset DATAOUT="${FALSE}" typeset -L1 D=":" #### #### Process the command line options and arguments, saving #### the values as appropriate. #### while getopts ":vVu:h:l:s:LkdD:" OPTION do case "${OPTION}" in 'u') HMCUSER="${OPTARG}";; 'h') HMCNAME="${OPTARG}";; 'l') LPARNAME="${OPTARG}";; 's') SYSNAME="${OPTARG}";; 'L') HMCLIST="${TRUE}";; 'k') KORNOUT="${TRUE}";; 'd') DATAOUT="${TRUE}";; 'D') D="${OPTARG}";; 'v') VERBOSE="${TRUE}";; 'V') VERYVERB="${TRUE}";; '?') usagemsg_lsvioslot "${0}" && return 1 ;; ':') usagemsg_lsvioslot "${0}" && return 1 ;; esac done shift $(( ${OPTIND} - 1 )) #### #### Verify the HMC machine name and LPAR name was specified, #### if not display an error message and return from this script. #### The HMC machine name and LPAR name are the only required #### command line parameters, all others are optional. #### trap "usagemsg_lsvioslot ${0}" EXIT if [[ "_${HMCNAME}" = "_" ]] then print -u 2 "ERROR: HMC machine name not specified" return 2 fi #### If neither 'Korn shell code output (-k)' or 'data record output (-d)' #### was selected on the command line, default to 'Korn shell code output #### (-k)'. if (( KORNOUT == FALSE )) && (( DATAOUT == FALSE )) then KORNOUT="${TRUE}" fi trap "-" EXIT #### #### Display some program info and the command line arguments specified #### if "VERBOSE" mode was specified. #### (( VERYVERB == TRUE )) && set -x (( VERBOSE == TRUE )) && print -u 2 "# Program........: ${0}" (( VERBOSE == TRUE )) && print -u 2 "# Version........: ${VERSION}" (( VERBOSE == TRUE )) && print -u 2 "# HMC Name.......: ${HMCNAME}" (( VERBOSE == TRUE )) && print -u 2 "# HMC User.......: ${HMCUSER:-}" (( VERBOSE == TRUE )) && print -u 2 "# System Name....: ${SYSNAME:-}" (( VERBOSE == TRUE )) && print -u 2 "# LPAR Name......: ${LPARNAME:-}" ################################################################ #### #### If the "-L" option was specified on the command line, display #### the list of managed system names and return from this function. #### if (( HMCLIST == TRUE )) then lsmanagedsys -L -u "${HMCUSER}" -h "${HMCNAME}" return 0 fi #### #### If the managed system name was not specified on the command line, #### display a selection menu of managed system names, using the #### array of names obtained earlier. Prompt the user to select #### a name. #### if [[ "_${SYSNAME}" = "_" ]] then SYSNAME=$( lsmanagedsys -u "${HMCUSER}" -h "${HMCNAME}" ) fi #### #### Create an array of LPAR names from which to obtain slot information #### IFS=$' \t\n' unset LPAR_NAMES if [[ "_${LPARNAME}" == "_" ]] then LPAR_NAMES=( $( exec ssh ${HMCUSER:-hscroot}@${HMCNAME} "lssyscfg -r lpar -m ${SYSNAME} -F name" ) ) else LPAR_NAMES=( ${LPARNAME} ) fi #### If the '-d' command line option was specified, indicating a desire for #### delimited data record formatted output, send a header line containing #### field names to the STDERR stream. if (( DATAOUT == TRUE )) then print -u 2 -- "# lpar_name${D}lpar_type${D}slot_number${D}slot_type${D}" fi #### If the '-k' command line option was specified, indicating a desire for #### korn shell code output, send a korn shell statement establishing an #### associative array to STDOUT for the purpose of containing the LPAR #### names. (( KORNOUT == TRUE )) && print "typeset -A LPAR_NAME;" #### Loop through the list of LPAR names obtained from the command line or #### returned from the HMC managed system for the purpose of reporting the #### virtual SCSI SLOT numbers and adapter types. for LPARNAME in "${LPAR_NAMES[@]}" do (( VERBOSE == TRUE )) && print -u 2 "# LPAR Name......: ${LPARNAME}" LPARVAR="${LPARNAME//[!A-Za-z0-9]/}" #### Begin the iteration of the loop by retrieving the LPAR names and their #### respective environments (vioserver or aixlinux) from the HMC. LPAROUT=$( exec ssh ${HMCUSER:-hscroot}@${HMCNAME} "lssyscfg -r lpar \ -m ${SYSNAME} \ --filter lpar_names=${LPARNAME} -F name,lpar_env" ) #### If the '-k' command line option was specified, output a korn shell #### statement defining an element of the LPAR name associative array. The #### array element will have the LPAR name as the index and the environment #### type (vioserver or aixlinux) as the element value. (( KORNOUT == TRUE )) && print "LPAR_NAME[${LPAROUT%,*}]=\"${LPAROUT#*,}\";" #### Retrieve all virtual SCSI adapter information for an LPAR from the HMC #### and store this information in a temporary array for later processing. #### This information will contain SLOT numbers, SLOT types, etc. unset ARY nameref ARY="SLOTS_${LPARVAR}" # DLF IFS=",\"" IFS=$',"\n' TMPARY[0]="" TMPARY=( $( exec ssh ${HMCUSER:-hscroot}@${HMCNAME} "lssyscfg -r prof \ -m ${SYSNAME} \ --filter lpar_names=${LPARNAME} \ -F virtual_scsi_adapters" ) ) unset TMPARY[0] #### Parse each virtual SCSI adapter record stored in the temporary array #### and extract the adapter SLOT number and SLOT type (client or server). typeset IDX typeset SLOT typeset TYPE for IDX in "${!TMPARY[@]}" do SLOT="${TMPARY[IDX]%%/*}" TYPE="${TMPARY[IDX]#*/}" TYPE="${TYPE%%/*}" [[ "_${SLOT}" == "_" ]] && continue [[ "_${TYPE}" == "_" ]] && continue #### If the '-k' command line option was specified, output a korn shell #### statement defining an element of the SLOT by LPAR name indexed array. #### The array element will have the SLOT number as the index and the slot #### type type (client or server) as the element value. The array will have #### a complex name consisting of the literal characters 'SLOT_' followed by #### the LPAR name. This means a separate array will be generated for each #### LPAR to contain it's SLOT information. if (( KORNOUT == TRUE )) then print "SLOT_${LPARVAR}[${SLOT}]=\"${TYPE}\";" fi #### If the '-d' command line option was specified, output a colon (:) #### delimited record containing the LPAR name, LPAR type (vioserver or #### aixlinux), SLOT number, and SLOT type. if (( DATAOUT == TRUE )) then print -u 2 -- "# ${LPARNAME}${D}${LPAROUT#*,}${D}${SLOT}${D}${TYPE}${D}" fi #### Continue with the next iteration of the loop which will use the next #### LPAR name in the list, or if none exist, exit the loop. done | sort -n unset ARY done return 0 } ################################################################ function usagemsg_lsmanagedsys { print " Program: lsmanagedsys List the managed systems associated with an HMC. Usage: ${1##*/} [-?vV] -h HMCname -u HMCuser [-L] Where: -v = Verbose mode - displays lsmanagedsys function info -V = Very Verbose Mode - debug output displayed -h = HMC machine name -u = HMC user name -L = Display a list of systems managed by the specified HMC Author: Dana French (dfrench@mtxia.com) Copyright 2006, 2007, 2008 All Rights Reserved \"AutoContent\" enabled " } ################################################################ #### #### Description: #### #### The purpose of this function is to retrieve a list of #### HMC managed systems from an HMC, generate a menu using #### the retrieved system names, prompt the user to select #### one of the system names, and return the selected system #### name as the result of this function. #### #### Assumptions: #### #### This script assumes "ssh" connectivity to the HMC, but #### not necessarily "password-less" login. #### #### The HMC user is assumed to have the ability to retrieve #### HMC configuration information. #### #### Dependencies: #### #### Connectivity with the HMC using "ssh" is the only #### communication mechanism supported at this time. #### #### Products: #### #### A menu of retrieved system names is generated on the #### STDERR stream, the user is expected to select an item #### from the displayed menu on the STDIN steam. The #### selected item, the managed system name, is sent to the #### STDOUT stream as the result of this function. #### #### Configured Usage: #### #### This function is expected to be called from a Korn Shell #### function library, but may be incorporated into a #### stand-alone script if necessary. #### #### An HMC managed system name must be provided by the user #### of this function. That name can be provided on the #### command line, or by selecting it from a menu. If a #### managed system name is not provided on the command line, #### a menu is generated on STDERR, and the user must select #### a system from the menu. #### #### Details: #### ################################################################ function lsmanagedsys { typeset VERSION="2.1" typeset TRUE="1" typeset FALSE="0" typeset VERBOSE="${FALSE}" typeset VERYVERB="${FALSE}" typeset HMCLIST="${FALSE}" typeset HMCUSER="" typeset HMCNAME="" typeset SYSLIST typeset SYSTMP #### #### Process the command line options and arguments, saving #### the values as appropriate. #### while getopts ":vVLu:h:" OPTION do case "${OPTION}" in 'u') HMCUSER="${OPTARG}";; 'h') HMCNAME="${OPTARG}";; 'L') HMCLIST="${TRUE}";; 'v') VERBOSE="${TRUE}";; 'V') VERYVERB="${TRUE}";; [?:#]) usagemsg_lsmanagedsys "${0}" && return 1 ;; esac done shift $(( ${OPTIND} - 1 )) ################################################################ #### #### Obtain a list of managed system names from the HMC #### SYSLIST=( $( exec ssh ${HMCUSER:-hscroot}@${HMCNAME} "lssyscfg -r sys -F name" ) ) #### #### If the "-L" option was specified on the command line, display #### the list of managed system names and return from this function. #### typeset SYSTMP if (( HMCLIST == TRUE )) then for SYSTMP in "${SYSLIST[@]}" do print -- "${SYSTMP}" done return 0 fi #### #### Display a selection menu of managed system names, using the #### array of system names obtained earlier. Prompt the user to #### select a name. #### PS3=$'\n'"Select a system by number: " print -u 2 -- "\nSelect a system managed by the HMC \"${HMCNAME}\".\n" select SYSNAME in "${SYSLIST[@]}" do if [[ "_${SYSNAME}" == "_" ]] then print -u 2 "\n# ERROR: Invalid selection\n" else break fi done >&2 #### Send the system name selected by the user to STDOUT, to be #### interpreted by the calling function as the result of this function. print -- "${SYSNAME}" return 0 } ################################################################ mapluns "${@}"