#! /usr/bin/ksh
#
# ident	"@(#)sccheck_common.ksh	1.15	04/09/02 SMI"
#
# Copyright 2003-2004 Sun Microsystems, Inc.  All rights reserved.
# Use is subject to license terms.
#


#
# functions and global variables
# common to sccheck.ksh and sccheckd.ksh
#


export LC_COLLATE=C

PATH=/usr/cluster/bin:${PWD}:/bin:/usr/bin:/sbin:/usr/sbin:${PATH}; export PATH

#
#	Definitions and functions common
#	to both sccheck and sccheckd.
#


#
#	Configuration file.
#
# In a non-inetd environment the user would just export variables from their
# environment and run sccheck. However, sccheckd also needs access to
# 'user overrides' which inetd cannot pass along.
# Therefore, 'user environment overrides' may be set in this file which
# is accessible to both sccheck and sccheckd.
#
# The most common use of this file will be to override default locations
# of utilities like explorer, java, and gunzip.
#
# This file also holds various properties used by the java code and
# is expected to be present,although its absence will not be fatal.
#
typeset SCCHECK_CONF=/etc/default/sccheck

if [[ -e ${SCCHECK_CONF} ]]; then
    . ${SCCHECK_CONF}
fi


#
#	definitions common to client & server
#


integer -r SC_TRUE=1
integer -r SC_FALSE=0
typeset -r TRUE="true"   # no I18N
typeset -r FALSE="false" # no I18N

typeset -r CLINFO=/usr/sbin/clinfo
typeset -r SCHA_CLGET="/usr/cluster/bin/scha_cluster_get -O"
typeset -r SCCONF="/usr/cluster/bin/scconf -p"

# user can override via /etc/default/sccheck config file
typeset EXPLORER_HOME=${EXPLORER_HOME:-/opt/SUNWexplo}
typeset -r EXPLORER=${EXPLORER_HOME}/bin/explorer

# user can override via /etc/default/sccheck config file
#   default #1
typeset GUNZIP=${GUNZIP:-/usr/bin/gunzip}
if [[ ! -x ${GUNZIP} ]]; then
    #   default #2
    GUNZIP=/opt/SUNWexplo/bin/gzip.`/usr/bin/uname -p`
fi

typeset TAR=${TAR:-/usr/bin/tar}

# minimum java version:
# defined in /etc/default/sccheck config file
typeset -r MIN_JAVA_VER=${MIN_JAVA_MAJOR_VER}.${MIN_JAVA_MINOR_VER}

typeset MYNAME=$(uname -n)

# user can override via /etc/default/sccheck config file
typeset JAVA_HOME=${JAVA_HOME:-/usr/java}	

# user can override via /etc/default/sccheck config file
typeset JAVA=${JAVA:-${JAVA_HOME}/bin/java}


typeset -r SCCHECK_LIB=/usr/cluster/lib/sccheck
typeset -r SCCHECK_JAR=${SCCHECK_LIB}/sccheck.jar
typeset -r CLIENT_XSLBASEDIR=/var/cluster/sccheck/tmp/client # client num appended later
typeset -r SERVER_XSLDIR=/var/cluster/sccheck/tmp/server

#
# KE:  Knowledge Engine
#   aka
# KAE: Knowledge Automation Engine
#   aka
# EKE: Embedded Knowledge Engine
#
typeset -r KE_HOME=${SCCHECK_LIB}/kae


# having SCCHECK_LIB in the path with SCCHECK_JAR
# allows finding I18N resource bundles outside the jar

typeset CLASSPATH=${SCCHECK_LIB}:${SCCHECK_JAR}

# add KE jars to classpath
set -A KE_RESOURCES "\
	kae.jar \
	kae-libs.jar \
	eras-common.jar \
	common-libs.jar \
	eras-parsers.jar \
	explorer-input-source.jar \
	resources \
"

for resource in ${KE_RESOURCES}
do
	CLASSPATH=${CLASSPATH}:${KE_HOME}/${resource}
done


# suffix for default output directory name
typeset -r TIMESTAMP="$(date +%Y-%m-%d.%T)"


#
# space in MB required for one copy of explorer results compressed
# _and_ uncompressed
# small systems won't generate this much; big systems may generate more
# user can override from environment
#
typeset -i SCCHECK_DISKSPACEMB=${SCCHECK_DISKSPACEMB:-25} 

#
#	exit code definitions
#
#	not documented to users
#	these specific codes used by testing
#

integer -r ERR_UNSPECIFIED=201
integer -r ERR_TRAP=202
integer -r ERR_USAGE=203
integer -r ERR_NOT_ROOT=204
integer -r ERR_DISK_SPACE=205
integer -r ERR_FAILED_DIRS=206
integer -r ERR_PREREQS=207
integer -r ERR_EXPL_PARENT=208
integer -r ERR_INVALID_FILE=209
integer -r ERR_INVALID_EKE=210

#
#	filename definitions
#

typeset -r SCCHECK_LOGDIR="/var/cluster/logs/sccheck"
typeset -r KESERVERLOG=ke-server.log
typeset -r KECLIENTLOG=ke-client.log

typeset -r SCCHECK_REPORTSDIR_SERVER="/var/cluster/sccheck/tmp/server"
typeset -r SCCHECK_REPORTSDIR_CLIENT="/var/cluster/sccheck/reports."${TIMESTAMP}

typeset -r SCCHECK_PIDFILES_BASE=${SCCHECK_LOGDIR}


#
#	java defines supporting Knowledge Engine
#


set -A KE_JDEFINES " \
  -Dcom.sun.eras.common.logging4.config.file=/usr/cluster/lib/sccheck/sccheck.logging4.properties \
"


#
#	function definitions
#
#


###################################
#
#  common_check_prereqs
#
#	input:		nothing
#	output:		error messages
#	returns:	0 success or 1 failure
#
#	action: 
#
#	Check for prerequisite utilities and data
#	files.
#
###################################

common_check_prereqs()
{
    typeset -i prereq=0

    typeset -r ewrapper=${SCCHECK_LIB}/explorer_wrapper
    

    set -A exec_files "\
	${EXPLORER} \
	${GUNZIP} \
	${TAR} \
	${JAVA} \
	${ewrapper} \
    "

    

    for f in ${exec_files}
    do
	if [[ ! -x ${f} ]]; then
	    printf "$(gettext '%s: %s not found or not executable.')\n" ${PROG} "${f}"
	    prereq=1
	fi
    done

    #if there are file to check defined 

    if [ -n "${exist_files}" ]; then
	for f in ${exist_files}
	do
	    common_checkFile ${f}
	    if [ $? -ne 0 ]; then
		printf "$(gettext '%s: %s not found or empty size.')\n" ${PROG} "${f}"
		prereq=1
	    fi
	done
    fi

    return ${prereq}
} # common_check_prereqs

##############################
#
#  common_get_explorer_version
#
#	Return version string from explorer(1m).
#
#	input:		nothing
#	output:		print version string from explorer(1m)
#	returns:	nothing
#
#	action:
#
#	Ask explorer for its version string.
#	First use new-style flag, if it fails
#	try old-style flag.
#
#	no I18N: use C locale no make sure
#
##############################

common_get_explorer_version ()
{
    typeset lc_save=${LC_ALL}
    export LC_ALL=C

    typeset exv=$(${EXPLORER} -version 2>&1)
    typeset expl_version=

    # expr chokes on the output of this version call to explorer
    #	expr $("${exv}") : "Explorer version"
    # so we're left with echo | grep
    echo "$exv" | /usr/bin/grep "Explorer version" > /dev/null
    if [[ $? -eq 0 ]]; then
	expl_version=$(echo "$exv" | /usr/bin/grep "Explorer version")
    else
	exv=$(${EXPLORER} -V 2>&1)
	echo "$exv" | /usr/bin/grep "Explorer version" > /dev/null
	if [[ $? -eq 0 ]]; then
	    expl_version=$(echo "$exv" | /usr/bin/grep "Explorer version")
	else
	    expl_version="undetermined"	# no I18N
	fi
    fi

    # strip off the leading "Explorer version: " & convert spaces to _
    echo ${expl_version##*: } | /usr/bin/tr "[:blank:]" "_"

    export LC_ALL=${lc_save}
} # common_get_explorer_version

##############################
#
#  common_get_java_version
#
#	Obtain version string from java
#
#	input:		nothing
#	output:		Version string from JVM
#	returns:	nothing
#
#	action: 
#
#	Ask JVM for its version; translate
#	double quotes into <space>.
#
#	no I18N: use C locale
#
##############################
common_get_java_version ()
{

    typeset lc_save=${LC_ALL}
    export LC_ALL=C

    # get version string and replace double
    # quotes with <space>
    typeset jver=$($JAVA -version 2>&1 | /usr/bin/tr "\"" " " )

    echo ${jver}

    export LC_ALL=${lc_save}
} # common_get_java_version

##############################
#
#  common_test_java_version
#
#	Determine if appropriate version of java
#
#	input:		nothing
#	output:		error message
#	returns:	0 if appropriate version or 1 if not
#
#	action: 
#
#	Ask JVM for version (forced it to stdout)
#       parse out 'major' and 'minor' values
#       and test against defined requirements
#
#       Major & minor defined in /etc/default/sccheck
#       'dot-dot' not considered
#
#       java version "1.2.2" -> 1 and 2
#       java version "1.4.1_02a" -> 1 and 4
#
##############################
common_test_java_version()
{

	jver=`${JAVA} -version 2> /dev/stdout`
	# jver="java version 1.4.2_b03 blah blah blah"

	vernum=`echo $jver | tr -d \"   | awk '{ print $3}'`
	jmajor=`echo $vernum | awk -F. '{print $1}'`
	jminor=`echo $vernum | awk -F. '{print $2}'`

	# two failure cases:
	#    major is less than required
	# or
	#    major is equal to required but minor is less than required
	# all other cases are success

	if [ "$jmajor" -lt ${MIN_JAVA_MAJOR_VER} -o \( "$jmajor" -eq ${MIN_JAVA_MAJOR_VER} -a "$jminor" -lt ${MIN_JAVA_MINOR_VER} \) ]
	then
		printf "$(gettext '%s: java version found: %s. Must be %s or newer.')\n" ${PROG} ${vernum} ${MIN_JAVA_VER}
		return 1
	else
		return 0
	fi

} # common_test_java_version




##############################
#
#  common_test_eke_version
#
#	Determine if appropriate version of Embedded Knowledge Engine
#
#	input:		nothing
#	output:		error message
#	returns:	0 if appropriate version or 1 if not
#
#	action: 
#
#	Read string from version file & test against minimum aceptable eke version
#
##############################
common_test_eke_version()
{
    typeset min_ver=3

    # get version string
    typeset ver=$(/usr/bin/cat ${KE_HOME}/version)

    if [[ $min_ver < $ver ]]; then
	return 0 # acceptable
    else
	printf "$(gettext '%s:  downrev Knowledge Engine: %s. Package SUNWscsck must be updated.')\n" ${PROG} ${ver}
	return 1 # not acceptable
    fi
} # common_test_eke_version

##############################
#
# common_get_clustermode
#
#	input:		nothing
#	output:		prints ${TRUE} | ${FALSE}
#	returns:	nothing
#
#	action: 
#
#	Use clinfo to see if we're in clustermode.
#
##############################

common_get_clustermode()
{ 
    if [[ -x ${CLINFO} ]]; then
	${CLINFO} > /dev/null 2>&1
	if [[ $? -eq 0 ]]; then
	    echo ${TRUE}
	else
	    echo ${FALSE}
	fi
    else
	echo ${FALSE}
    fi
} # common_get_clustermode

###############################################
#
# common_get_clustername
#
#	input:		nothing
#	output:		prints:
#		clustername if in clustermode,
#		nothing if not in clustermode
#		or ifscha command not found
#
#	returns:	nothing
#
#	action: 
#
#	Use scha_clget() to fetch clustername.
#
###############################################
common_get_clustername()
{
    echo $(${SCHA_CLGET} CLUSTERNAME 2> /dev/null)
}

###############################################
#
# common_mkdir()
#
#	input:		name of directory to create
#	output:		prints error message
#	returns:	0 success || 1 failure
#
#	action: 
#
#	Attempt to mkdir -p the target directory.
#
######################################################
common_mkdir()
{
    typeset target=$1

    /usr/bin/mkdir -p ${target} 2> /dev/null
    integer status=$?
    if [[ ${status} -ne 0 ]]; then
	printf "$(gettext '%s:  Could not create directory: %s')\n" ${PROG} "${target}"
	return 1
    fi

    return 0
} # common_mkdir

########################################################
#
# common_mkdirs
#
#	input:		nothing
#	output:		prints error message	
#	returns:	0 success || 1 failure
#
#	action: 
#
#	Make directories needed on both client
#	and server.
#
########################################################

common_mkdirs()
{
    common_mkdir ${SCCHECK_REPORTSDIR_SERVER}	|| return 1
    common_mkdir ${SCCHECK_LOGDIR}		|| return 1

    return 0
} # common_mkdirs


#####################################################
#
# common_test_diskspace
#
#	Determine if enough disk space is available to
#	store explorer results. This is a total estimate
#	since explorer results sizes can vary widely from
#	machine to machine.
#
#	This is why env var $SCCHECK_DISKSPACEMB may be
#	overridden in the user's environment.
#
#	A server machine need only hold one explorer results
#	set, but client machine needs to hold number of
#	participating nodes plus one explorer results.
#
#	input:		N: multiple of space required
#			defaults to 1
#
#	output:		error message
#	returns:	0 if sufficient space or 1 if not
#
#	action: 
#
#	Get available space in / filesystem in KB. Convert to bytes.
#	Convert $SCCHECK_DISKSPACEMB to bytes, then multiply by
#	'N' to get total space required.
#	Compare total bytes required against bytes available.
#
#####################################################

common_test_diskspace()
{
    typeset -i factor=1
    typeset -i availkb=0
    typeset -i avail=0
    typeset -i min_node_diskspace=0
    typeset -i totrqd=0

    if [[ $# -gt 0 ]]; then
	factor=$1
    fi

    availkb=$(/usr/bin/df -k / | /bin/tail -1 | /usr/bin/awk '{print $4}')
    ((avail=$availkb * 1024))

    ((min_node_diskspace=$SCCHECK_DISKSPACEMB * 1024 * 1024))

    ((totrqd=$min_node_diskspace * $factor))

    if (( $avail >= $totrqd )); then
	return 0
    else
	printf "$(gettext '%s:  Insufficient disk space.')\n" ${PROG}
	return 1
    fi
} # common_test_diskspace

########################################################
#
# common_clean_pidfiles
#
#	Validate that there is an active sccheck(d)
#	process corresponding to each pidfile.
#
#	Both sccheck.ksh and sccheckd.ksh create
#	a 'pidfile' holding their process ID before
#	they invoke their java code and remove it on exit.
#
#	This validation function is extra insurance
#	against a stale pidfile remaining to confuse
#	the logic that depends upon the presence/absence
#	of pidfiles.
#
#	input:		pidfile 'base' name 
#	output:		nothing
#	returns:	nothing
#
#	action:
#
#	For all pidfiles matching pidfile 'base' name, read
#	the contained pid and test the environment to see
#	if that process exists and has a name that includes
#	the string 'sccheck.' This  will match both 'sccheck'
#	and 'sccheckd.'
#
#	Any pidfile containg an 'invalid' pid is removed.
#	
########################################################

common_clean_pidfiles()
{
    typeset lc_save=${LC_ALL}
    export LC_ALL=C

    typeset target=$1
    typeset pidfiles=$(/usr/bin/ls -1 ${target}* 2>/dev/null)
    typeset pidf=
    for pidf in $(echo $pidfiles)
    do
	typeset contentpid=$(/usr/bin/cat $pidf)

	# the typeset of and assignment to $pss must be separate
	# operations in order to evaluate the success of the grep
	typeset pss=

	# see if ${contentpid} matches an existing sccheck or
	# sccheckd process
	pss=$(/usr/bin/pgrep "sccheck" | /usr/bin/grep -w ${contentpid})
	typeset status=$?
	if [ $status -ne 0 ]; then
	    /usr/bin/rm $pidf 2> /dev/null
	fi
    done   
    export LC_ALL=${lc_save}
} # common_clean_pidfiles


#####################################################
#
# common_verify_isroot()
#
#	Print an error message and return non-zero
#	if the user is not root.
#
#####################################################

common_verify_isroot()
{
	typeset -r uid=$(expr "$(id)" : 'uid=\([0-9]*\)*')

	# make sure uid was set
	if [[ -z "${uid}" ]]; then
		printf "$(gettext '%s:  Cannot get uid')\n" ${PROG}
		return 1
	fi

	# check for root
	if [[ ${uid} -ne 0 ]]; then
		printf "$(gettext '%s:  Must be root')\n" "${PROG}"
		return 1
	fi

	return 0
} # common_verify_isroot

#####################################################
#
# common_verify_isauthorized()
#
#       Print an error message and return non-zero
#       if the user is not authorized.
#
#####################################################

common_verify_isauthorized()
{
        /usr/bin/auths 2>&1 | /usr/bin/egrep "solaris\.cluster\.system\.admin|solaris\.cluster\.system\.\*|solaris\.cluster\.\*|solaris\.\*" > /dev/null

        if [ $? -ne 0 ] ; then
                printf "$(gettext '%s:  Not authorized to use this command.')\n" ${PROG}
                return 1
        fi

        return 0
} # common_verify_isauthorized

#####################################################
#
# common_verify_iseuidroot()
#
#	Print an error message and return non-zero
#	if the euid of the process is not 0.
#
#####################################################

common_verify_iseuidroot()
{
	typeset -r euid=`/usr/xpg4/bin/id -u`

	# make sure euid was set
	if [[ -z "${euid}" ]]; then
		printf "$(gettext '%s:  Cannot get euid')\n" ${PROG}
		return 1
	fi

	# check for root
	if [[ ${euid} -ne 0 ]]; then
		printf "$(gettext '%s:  Must be root')\n" "${PROG}"
		return 1
	fi

	return 0
} # common_verify_iseuidroot

#####################################################
#
# common_checkFile ()
#
#	checks validity of a file
#       for now: only existence and useful size
#       return 0 on success
#
#####################################################

common_checkFile()
{
    if [ -r "$1" ] && [ -s "$1" ]
    then
	return 0
    else
	return 1
    fi
} # common_checkFile
