#!/bin/ksh -p
#  exp_tools: explorer API for data gathering modules
#  $Id: //depot/stable/explorer/lib/exp_tools#3 $
EXP_TOOLS_VERSION='$Revision: #3 $'
export EXP_TOOLS_VERSION

EXP_VERSION=4.0

if [ -n "${DO_VERSION}" ]
then
    LIB=${0##*/}
    echo "${LIB} version: ${EXP_TOOLS_VERSION}"
    exit
fi

# Source common functions
. ${EXP_LIB}/exp_common

#
# touch a file
#    First arg is the file to create
#
touch_file () {
    if [ "$#" -lt 1 ]
    then
        # logfile ERROR "Wrong number of args to touch_file: $*"
        TEXT=`gettext "Wrong number of args to touch_file: %s"`
        TEXT=`printf "${TEXT}" "$*"`
	logfile ERROR "${TEXT}"
	return 1
    fi

    FILE=${EXP_TARGET}/$1
    DIR=${FILE%/*}

    # Make sure the directory exists
    [ ! -d "${DIR}" ] && { mkdir -p ${DIR}; }
    touch ${FILE} >/dev/null 2>&1
}

#
#  echo to a file
#    First arg is the file to echo to
#    Optional second arg is the message to print
#
echo_file () {
    (
    if [ "$#" -lt 1 ]
    then
        # logfile ERROR "Wrong number of args to echo_file: $*"
        TEXT=`gettext "Wrong number of args to echo_file: %s"`
        TEXT=`printf "${TEXT}" "$*"`
	logfile ERROR
	return 1
    fi

    FILE=${EXP_TARGET}/$1
    DIR=${FILE%/*}
    shift

    # Check for writeability of file
    if [ ! -w "${FILE}" ]
    then
	# Make sure the directory exists
	[ ! -d "${DIR}" ] && { mkdir -p ${DIR}; }

	# Create the file
	touch ${FILE} >/dev/null 2>&1
    fi
    {
	if [ "$#" -gt 0 ]
	then
	    echo "$*"
	else
	    cat
	fi
    } >>${FILE} 2>&1
    )
}

#
# create a symlink in EXP_TARGET
#    First arg is the basedir
#    Second arg is the source
#    Third arg is the link
#
symlink () {
    if [ "$#" -lt 3 ]
    then
        # logfile ERROR "Wrong number of args to symlink: $*"
        TEXT=`gettext "Wrong number of args to symlink: %s"`
        TEXT=`printf "${TEXT}" "$*"`
	logfile ERROR "${TEXT}"
	return 1
    fi

    cd ${EXP_TARGET}/$1
    ln -s $2 $3
    logfile "link: $3 -> $2 in $1"
}

#
# get a file
#    First arg is file to copy
#    Optional second arg is directory to store it in
#
get_file () {
    FTP=""
    if [ "$#" -lt 1 ]
    then
        # logfile ERROR "Wrong number of args to get_file: $*"
        TEXT=`gettext "Wrong number of args to get_file: %s"`
        TEXT=`printf "${TEXT}" "$*"`
	logfile ERROR "${TEXT}"
	return 1
    fi

    FILES=$1

    # Get file via ftp?
    echo "$2" | egrep -s -e "^ftp:"
    if [ "$?" -eq 0 ]
    then
        HOST=`echo $2 | nawk -F: '{print $2}'`
        PASS=`echo $2 | nawk -F: '{print $3}'`
        CDIR=`echo $2 | nawk -F: '{print $4}'`
	FTP=notempty
	shift
    fi

    # Where does the file go
    if [ -n "$2" ]
    then
	DIR=${EXP_TARGET}/$2
    else
	DIR=${EXP_TARGET}/extra
    fi

    # ftp get
    if [ -n "${FTP}" ]
    then
	# Add to .netrc to allow auto ftp of files
	if [ -f "/.netrc" ]
	then
	    cp /.netrc /.netrc.${EXP_PID}
	    echo "machine ${HOST} login root password ${PASS}" >>/.netrc
	else
	    touch /.netrc
	    chmod 600 /.netrc
	    echo "machine ${HOST} login root password ${PASS}" >>/.netrc
	fi

	# Make sure destination DIR exists
	[ ! -d "${DIR}" ] && { mkdir -p ${DIR}; }
	cd ${DIR}

	# Ftp off certain files
	EXP_TMPFILE="${EXP_TMPDIR}/ftp.${EXP_PID}"
	ftp ${HOST} >${EXP_TMPFILE} 2>&1 <<EOF
bin
prompt
cd ${CDIR}
mget $FILES
quit
EOF
	logfile "file: $FILES (on ${HOST})"

	# Restore .netrc
	if [ -f "/.netrc.${EXP_PID}" ]
	then
	    mv /.netrc.${EXP_PID} /.netrc
	else
	    rm -f /.netrc
	fi

	# Clean up
	rm -f ${EXP_TMPFILE}

        return
    fi

    # standard get
    for FILE in $FILES
    do
	[ ! -f "${FILE}" ] && return 1

	# If trailing !, filename not destination directory
	echo "$2" | egrep -s -e "!$"
	if [ "$?" -eq 0 ]
	then
	    CDIR=${DIR%/*}
	    DIR=`echo $DIR | sed -e 's/!$//'`
	    [ ! -d "${CDIR}" ] && { mkdir -p ${CDIR}; }
	else
	    [ ! -d "${DIR}" ] && { mkdir -p ${DIR}; }
	fi

	# Handle links
	if [ -h ${FILE} ]
	then
	    CDIR=${FILE%/*}
	    LINK=`ls -l ${FILE} | awk '/->/ { print $NF }'`

	    # Absolute path, copy it
	    if echo $LINK | egrep -s -e "^\/"
	    then
		# Copy file
		cp -p "${FILE}" "${DIR}"
		logfile "file: ${FILE}"
		continue
	    fi

	    # Relative path
	    DEST=${FILE##*/}
	    LDIR=${LINK%/*}
	    LDIR=`echo $LDIR | sed -e "s~^~${DIR}/~"`
	    NEW=`echo $LINK  | sed -e "s~^~${CDIR}/~"`

	    # Make sure the directory exists
	    [ ! -d "${LDIR}" ] && { mkdir -p ${LDIR}; }

	    # Copy file linked to, then cd and link
	    cp -p "${NEW}" "${LDIR}"
	    (cd ${DIR} ; ln -s ${LINK} ${DEST})

	    logfile "file: ${NEW}"
	    logfile "file: ${FILE} linked to ${LINK}"
	else
	    # Copy file
	    cp -p "${FILE}" "${DIR}"
	    logfile "file: ${FILE}"
	fi
    done
    return 0
}

#
# get a directory's contents
#    First arg may be recursive, otherwise it is source dir
#    Optional second arg is directory to store files in
get_dir () {
    if [ "$#" -lt 1 ]
    then
        # logfile ERROR "Wrong number of args to get_dir: $*"
        TEXT=`gettext "Wrong number of args to get_dir: %s"`
        TEXT=`printf "${TEXT}" "$*"`
	logfile ERROR "${TEXT}"
	return 1
    fi
    RECURSE=0

    # Check for recursive
    if [ "$1" = "recursive" ]
    then
        RECURSE=1
	shift
    fi
    logfile "dir: $1"

    # Check for empty directories
    FILES=`ls -Al $1/* 2>/dev/null | wc -l`
    if [ "${FILES}" -eq 0 ]
    then
	if [ -n "$2" ]
	then
	    DIR="${EXP_TARGET}/$2"
	else
	    DIR="${EXP_TARGET}/extra/${1##*/}"
	fi

	# Make the dir even if it's empty
	[ ! -d "${DIR}" ] && { mkdir -p ${DIR}; }
    fi

    # Walk directory
    for FILE in $1/* $1/.??*
    do
        if [ -d "${FILE}" -a "${RECURSE}" -eq 1 ]
	then
	    # Preserve some directory info
	    if [ -n "$2" ]
	    then
		DIR="$2/${FILE##*/}"
	    else
		DIR="extra/${1##*/}/${FILE##*/}"
	    fi

	    get_dir recursive "${FILE}" "${DIR}"
	else
	    # Preserve some directory info
	    if [ -n "$2" ]
	    then
		TAR="$2"
	    else
		TAR="extra/${1##*/}"
	    fi

	    get_file "${FILE}" "${TAR}"
	fi
    done
}

#
# Get command output
#    First arg is command to run
#    Optional second arg is the 3.x filename or destination dir
#
get_cmd () {
    # Save current LC_ALL and run commands in 'C' locale
    LC_SAVE=${LC_ALL}
    export LC_ALL=C

    if [ "$#" -lt 1 ]
    then
	export LC_ALL=${LC_SAVE}
        # logfile ERROR "Wrong number of args to get_cmd: $*"
        TEXT=`gettext "Wrong number of args to get_cmd: %s"`
        TEXT=`printf "${TEXT}" "$*"`
	logfile ERROR "${TEXT}"
	return 1
    fi

    COMMAND=$1

    # Clean up what is printed
    echo "${COMMAND}" | egrep -s -e " "
    if [ "$?" -eq 0 ]
    then
	CMD=`echo "${COMMAND}" | nawk '{ print $1 }'`
	ARG=`echo "${COMMAND}" | sed -e "s~${CMD} ~~"`
	CDIR=${CMD%/*}
	TMP=`echo "${CMD}" | sed -e "s~${CDIR}/~~"`
	BIN="$TMP $ARG"
    else
	CMD="${COMMAND}"
	CDIR=${CMD%/*}
	BIN=`echo "${CMD}" | sed -e "s~${CDIR}/~~"`
    fi

    # ignore option to set SERR=/dev/null
    IGNORE=""
    if [ -n "$2" ]
    then
        if [ "$2" = "ignore" ]
	then
	    IGNORE=notempty
	    shift
	fi
    fi

    # get command via telnet
    TELNET=""
    echo "$2" | egrep -s -e "^telnet:"
    if [ "$?" -eq 0 ]
    then
	TELNET=notempty
	IGNORE=notempty
	TYPE=`echo $2 | nawk -F: '{ print $2 }'`
	HOST=`echo $2 | nawk -F: '{ print $3 }'`
	PASS=`echo $2 | nawk -F: '{ print $4 }'`
	TIME=`echo $2 | nawk -F: '{ print $5 }'`
	CDIR="/bin"

	if [ "${TYPE}" = "t3" ]
	then
	    LOGIN=root
	    LOGOUT=exit
	    PORT=23
	elif [ "${TYPE}" = "sc" ]
	then
	    LOGIN=
	    LOGOUT=disc
	    PORT=5000
	elif [ "${TYPE}" = "brocade" ]
	then
	    LOGIN=`echo $2 | nawk -F: '{ print $6 }'`
	    LOGOUT=exit
	    PORT=23
	else
	    export LC_ALL=${LC_SAVE}
	    # logfile ERROR "Unknown telnet type for get_cmd: $*"
	    TEXT=`gettext "Unknown telnet type for get_cmd: %s"`
	    TEXT=`printf "${TEXT}" "$*"`
	    logfile ERROR "${TEXT}"
	    return 1
	fi
        shift

	export LC_ALL=${LC_SAVE}
	logfile "cmd: ${BIN} (on ${HOST})"
	export LC_ALL=C
    else
	export LC_ALL=${LC_SAVE}
	logfile "cmd: ${BIN}"
	export LC_ALL=C
    fi

    # Run command as a different user?
    USER=""
    EX_SMSUSER=""
    if [ -n "$2" ]
    then
	if echo "$2" | egrep -s -e "user="
	then
	    USER=`echo $2 | nawk -F= '{ print $2 }'`
	    shift
	fi
    fi

    # Do we have a destination dir or explorer3 name
    if [ -n "$2" ]
    then
	echo "$2" | egrep -s -e "/$"

	if [ "$?" -eq 0 ]
	then
	    # Destination dir
	    FILE=`echo "${BIN}" | sed -e 's~/~@~g' -e 's~ ~_~g' -e "s~${CDIR}/~~g"`
	    DIR=`echo "$2" | sed -e "s~/$~~"`

	    # Construct SOUT/SERR
	    SOUT="${EXP_TARGET}/${DIR}/${FILE}.out"
	    SERR="${EXP_TARGET}/${DIR}/${FILE}.err"
	else
	    # explorer 3 name
	    echo "$2" | egrep -s -e "!$"

	    # Use exact name? (name!)
	    if [ "$?" -eq 0 ]
	    then
		# strip !
		FILE=`echo $2 | sed -e "s/!$//"`
		# Construct SOUT/SERR
		SOUT="${EXP_TARGET}/${FILE}"
		SERR="${EXP_TARGET}/${FILE}.err"
	    else
		# Construct SOUT/SERR
		SOUT="${EXP_TARGET}/$2.out"
		SERR="${EXP_TARGET}/$2.err"
	    fi
	fi
    else
	# Filename based removing full path to command
	# and translated '/'='@' and ' '='_'
	FILE=`echo "${BIN}" | sed -e 's~/~@~g' -e 's~ ~_~g' -e "s~${CDIR}/~~g"`

	# Construct SOUT/SERR
	SOUT="${EXP_TARGET}/extra/${FILE}.out"
	SERR="${EXP_TARGET}/extra/${FILE}.err"
    fi

    # Use /dev/null if IGNORE set
    if [ -n "${IGNORE}" ]
    then
        SERR="/dev/null"
    fi

    # Make sure the directory exists
    DIR=${SOUT%/*}
    [ ! -d "${DIR}" ] && { mkdir -p ${DIR}; }

    # Get command via telnet
    if [ -n "${TELNET}" ]
    then
	if [ "${EXP_HOME}" = "/" ]
	then
	    IN_FILE="${EXP_LIB}/cmd.txt"
	else
	    IN_FILE="${EXP_ETC}/cmd.txt"
	fi
	CMD_FILE="${EXP_TMPDIR}/cmd.${EXP_PID}"

	if [ -n "${LOGIN}" ]
	then
	    sed -e "s~HOST~${HOST}~" \
		-e "s~PORT~${PORT}~" \
		-e "s~LOGIN~${LOGIN}~" \
		-e "s~LOGOUT~${LOGOUT}~" \
		-e "s~PASS~${PASS}~" \
		-e "s~TIME~${TIME}~" \
		-e "s~TYPE~${TYPE}~" \
		-e "s~FILE~${SOUT}~" \
		-e "s~CMD~${COMMAND}~" ${IN_FILE} > ${CMD_FILE}
	else
	    sed -e "s~HOST~${HOST}~" \
		-e "s~PORT~${PORT}~" \
		-e "/LOGIN/d" \
		-e "/sleep 3/d" \
		-e "s~LOGOUT~${LOGOUT}~" \
		-e "s~PASS~${PASS}~" \
		-e "s~TIME~${TIME}~" \
		-e "s~TYPE~${TYPE}~" \
		-e "s~FILE~${SOUT}~" \
		-e "s~CMD~${COMMAND}~" ${IN_FILE} > ${CMD_FILE}
	fi
	
	# Make cmd file executeable
	chmod 700 ${CMD_FILE}

	# Execute command via telnet
	${CMD_FILE} | telnet >>${SOUT} 2>>${SERR}
	rc=$?

	# Clean up
	rm -f ${CMD_FILE}
	export LC_ALL=${LC_SAVE}
	if [ "${rc}" -eq 0 ]
	then
	    if egrep -s -e "ogin incorrect" ${SOUT}
	    then
		rc=1
	    fi
	fi
	return ${rc}
    fi

    # Force use of full path name on executable
    if [ ! -f "${CMD}" ]
    then
	export LC_ALL=${LC_SAVE}
        # logfile WARNING "${CMD} not found"
        TEXT=`gettext "%s not found"`
        TEXT=`printf "${TEXT}" "${CMD}"`
	logfile WARNING "${TEXT}"
	return 1
    fi

    # Make sure it's executeable
    if [ ! -x "${CMD}" ]
    then
	export LC_ALL=${LC_SAVE}
        # logfile WARNING "Unable to execute ${CMD}"
        TEXT=`gettext "Unable to execute %s"`
        TEXT=`printf "${TEXT}" "${CMD}"`
	logfile WARNING "${TEXT}"
	return 1
    fi

    # Execute command
    if [ -z "${USER}" ]
    then
	ksh -p -c "${COMMAND}" >>${SOUT} 2>>${SERR}
	rc=$?
    else
	su ${USER} -c "${COMMAND}" >>${SOUT} 2>>${SERR}
	rc=$?
    fi
    export LC_ALL=${LC_SAVE}
    logfile "cmd: exit status: $rc"
    return $rc
}

#
# which_gate foo bar
# return non-zero if neither foo nor bar is in the ${EXP_WHICH} directive
# order of arguments is important.  which_gate foo bar returns zero on
# "foo,!bar" but one on "!foo,bar".
#
which_gate () {
    for i in $*
    do
	test `expr "${EXP_WHICH}" : ".*!\<$i\>.*"` -ne 0 && return 1
	test `expr "${EXP_WHICH}" :  ".*\<$i\>.*"` -ne 0 && return 0
    done

    return 1
}

#
# returns non-zero if all of the components of the ${EXP_WHICH} variable
# are negative (start with a ! character).
#
which_negative_check () {
    for i in `echo ${EXP_WHICH} | sed -e 's/,/ /g'`
    do
	expr "$i" : "^!" >/dev/null || return 0
    done
    return 1
}

#
# used by scripts to determine if they are executed (-w)
#
which_gate_exit () {
    which_gate $*
    if [ "$?" -eq 0 ]
    then
	TEXT=`gettext "RUNNING"`
	logfile NOTNOISE "${TEXT}"
    else
	TEXT=`gettext "SKIPPING"`
	logfile "${TEXT}"
	exit 0
    fi
}
