#!/bin/sh

# Shell script to collect configuration data for SCC.
# Copyright (C) 2001-2004 Open Challenge B.V.
# Copyright (C) 2004-2005 OpenEyeT Professional Services.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; see the file COPYING.
# If not, write to the Free Software Foundation,
# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# Contact information: www.OpenEyeT.nl/scc/index.html 

# SCC-release:	1.6.26
# file-version:	$Revision: 1.180 $


ProgName=${0##*/};			export ProgName

uid=$(id | sed -e 's/(.*//' -e 's/.*=//')
if [ "${uid}" != "0" ]
then
	echo "${ProgName}: only root should run this program" >&2
	exit 2
fi

SYNTAX="Syntax error, use: ${ProgName} [ -a <arg> ] [ -e <module> ] [ -i ]" >&2

args=""
interactive=0
modules=""
while [ $# -gt 0 ]
do
	case "${1}" in
	-a)	args="${2}"
		shift 2;;
	-e)	if [ "${2}" ]
		then
			modules="${2}"
		fi
		shift 2;;
	-i)	interactive=1;
		shift 1;;
	*)	break;;
	esac
done

if [ $# -ne 0 ]
then
	echo "${SYNTAX}" >&2
	exit 1
fi
	
if [ ${interactive} -eq 0 ]
then
	if tty -s
	then
		echo "${ProgName}: use -i option to run interactive" >&2
		exit 2
	fi
fi

export SCC_BIN=/opt/scc/bin
export SCC_TOP=/var/opt/scc

export SCC_DATA=${SCC_TOP}/data
export SCC_TMP=${SCC_TOP}/tmp
export SCC_CONF=/etc/opt/scc/conf

umask 077

mkdir -p ${SCC_DATA} ${SCC_TMP} 2>/dev/null

. ${SCC_BIN}/scc_modules/scc_utils

[ -x ${SCC_CONF}/scc-localize ] && . ${SCC_CONF}/scc-localize

export TMPDIR=${SCC_TMP}
export TMP=${SCC_TMP}

export SHELL=/bin/sh
export LANG=C

cd ${SCC_TMP}

PATH=/sbin:/usr/sbin:/usr/bin:/bin:/usr/lib:${SCC_BIN};	export PATH

export TMP1_FILE=${SCC_TMP}/scc_collect1_$$
export TMP2_FILE=${SCC_TMP}/scc_collect2_$$
export TMP3_FILE=${SCC_TMP}/scc_collect3_$$
export PROC_FILE=${SCC_TMP}/scc_ps_$$

# Some commands adjust the width of their output according to COLUMNS, unset
# this variable to avoid differences in the snapshots.
export COLUMNS=300		# always use the same width.
unset LINES
unset DISPLAY

OS_NAME=$(uname -s)
hostname=$(hostname)
HOSTNAME=${hostname%%.*}
export OS_NAME HOSTNAME

scc_linux_distro		# Set SCC_LINUX_DISTRO to the proper value.

SCC_KEEP_CONFIG=${SCC_DATA}/scc.${HOSTNAME}.keep
SCC_KEEP_NEW=${SCC_TMP}/scc.keep_$$
rm -f ${SCC_KEEP_NEW}
touch ${SCC_KEEP_NEW} ${SCC_KEEP_CONFIG}
export SCC_KEEP_CONFIG SCC_KEEP_NEW

new_keep_version="keep_file_version:1.1"
keep_version=$(grep "^${new_keep_version}$" ${SCC_KEEP_CONFIG} 2>/dev/null)
if [ "${keep_version}" != "${new_keep_version}" ]
then
	# The version of the keep-file does not match with the version
	# used by scc-collect. This means that the file has been written
	# by an incompatible version of scc-collect. Erase the keep-file.
	>${SCC_KEEP_CONFIG}
fi
echo "${new_keep_version}" >>${SCC_KEEP_NEW}

trap "rm -f ${TMP1_FILE} ${TMP2_FILE} ${TMP3_FILE} ${PROC_FILE} ${SCC_KEEP_NEW}" 0
trap "exit 2" 1 2 3 15

# Store the current processes for later use.
# Reduce the length of the lines.
# On some systems java code is part of the output, resulting in lines exceeding 2KB and errors from grep.
# Indicated by Doug Probst and Mattijs de Ruijter.
case "${OS_NAME}" in
*BSD)	ps -axww -o user,pid,ppid,state,pri,%cpu,%mem,vsz,rss,tty,start,time,command	|
	cut -c1-300 >${PROC_FILE}
	;;

OSF1)	ps axww -o user,pid,ppid,state,pri,%cpu,%mem,vsz,rss,tty,start,time,command	|
	cut -c1-300 >${PROC_FILE}
	# TRU64
	;;

*)	# Try to collect the process hierarchy.
	UNIX95= ps -Hef 2>/dev/null		|
	cut -c1-300 >${PROC_FILE}
	if [ $(wc -l <$PROC_FILE) -lt 10 ]			# Not supported?
	then
		ps -ef 2>/dev/null			|
		cut -c1-300 >${PROC_FILE}
	fi
	;;
esac

IS_NIS_MASTER=0;		export IS_NIS_MASTER
NIS_DATA_DIR="";		export NIS_DATA_DIR
grep -l ypxfrd ${PROC_FILE} >/dev/null 2>/dev/null
if [ $? -eq 0 ]
then
	IS_NIS_MASTER=1
	NIS_DATA_DIR=$(grep "^[ 	]*DIR" /var/yp/Makefile 2>/dev/null	|
			tail -1							|
			sed -e 's/^[ 	]*DIR[ 	]*=[ 	]*//' -e 's/[ 	].*//')
	if [ ! -d "${NIS_DATA_DIR}" ]
	then
		NIS_DATA_DIR=/etc
	fi
fi

# Not part of scc-utils as it should not be called by the modules.
scc_crypt_init()
{
	# Get the crypt-key from the keep-config-file, otherwise initialize.

	scc_keep_crypt_tag="scc-crypt-key"

	crypt_key=$(sed -n -e "s@^${scc_keep_crypt_tag}:@@p" ${SCC_KEEP_CONFIG})
	if [ ! -n "${crypt_key}" ]
	then
		if [ -z "${RANDOM}" ]
		then
			# No ${RANDOM}, use the seconds, minutes and hours. Add 10 to avoid multiplying with 0.
			RANDOM="$(date '+%H:%M:%S' | awk -F: '{ print ( 10 + $1 ) * ( 10 + $2 ) * ( 10 + $3 ) }' )"
			export RANDOM
		fi
		crypt_key="${RANDOM}${RANDOM}"
	fi
	echo "${scc_keep_crypt_tag}:${crypt_key}" >>${SCC_KEEP_NEW}

	return 0;
}

# To record the timing of separate parts of scc-collect, give SCC_PROFILING a non-empty value.
# Usage: [ ${SCC_PROFILING} ] && scc_timing "end of: network"
#export SCC_PROFILING="yes"
now=$(date '+%M:%S')
min=${now%:*}
sec=${now#*:}
tick_prev=$(( ${sec#0} + ( 60 * ${min#0} ) ));		export tick_prev
total_time=0;						export total_time

# For several commands we need to know the name of the HP-UX kernel.
if [ -x /usr/sbin/kmpath ]
then
	# This is only available for HP-UX 11.*
	HPUX_KERNEL="$(/usr/sbin/kmpath 2>/dev/null)"
fi
HPUX_KERNEL=${HPUX_KERNEL:-/stand/vmunix}
export HPUX_KERNEL

# Edit scc-localize to change the default setting of this variable.
if [ -z "${MAX_SYS_ACCOUNT_ID}" ]
then
	MAX_SYS_ACCOUNT_ID=500
	if [ "${OS_NAME}" = "HP-UX" -o "${OS_NAME}" = "SunOS" ]
	then
		MAX_SYS_ACCOUNT_ID=100		# check logins(1)
	fi
fi
export MAX_SYS_ACCOUNT_ID

scc_crypt_init;

##	START: GENERAL
[ ${SCC_PROFILING} ] && scc_timing "start of run"

mkdir -p ${SCC_DATA}/plugin_data		# Just in case it was removed
SCC_MODULE="";					export SCC_MODULE
(
	cd ${SCC_BIN}/scc_modules
	for SCC_MODULE in scc_[0-9][0-9][0-9][0-9]_[su]_*
	do
		if [ -x "${SCC_MODULE}" ]
		then
			echo "moduleSTART:${SCC_MODULE}" >>${SCC_KEEP_NEW}
			module_has_run=0

			rm -f ${TMP1_FILE} ${TMP2_FILE} ${TMP3_FILE}

			if [ ${interactive} -eq 0 ]
			then
				[ ${SCC_PROFILING} ] && scc_timing "${SCC_MODULE}	start of module"
			fi

			case "${SCC_MODULE}" in
			scc_[0-9][0-9][0-9][0-9]_s_*)		# scc system module
				if [ ${interactive} -eq 0 ]	# All modules, no specific modules requested?
				then
					./"${SCC_MODULE}" 2>&1
					module_has_run=1
				else
					case "${SCC_MODULE}" in
					*${modules}*)
						./"${SCC_MODULE}" 2>&1	# run the matching system module
						module_has_run=1
					esac
				fi
				;;

			scc_[0-9][0-9][0-9][0-9]_u_*)		# scc user module
				if [ "${modules}" ]
				then
					# Check whether the module should be run;
					# Only user modules can have arguments.
					case "${SCC_MODULE}" in
					*${modules}*)	# run the user module
							checksum="$(sed -e '/^[ 	]*#/d'	\
									-e '/^[ 	]*$/d' ${SCC_MODULE}	| cksum)"
							if [ ${interactive} -eq 1 ]
							then
								echo "var:MoDuLe:start::${SCC_MODULE}:${checksum}"
								./"${SCC_MODULE}" ${args} 2>&1
								module_has_run=1
								echo "var:MoDuLe:end::${SCC_MODULE}:"
							else
								# Surround the data with these tags, when a module
								# is changed, scc-log detects this and removes the
								# data of the module from the current and new snapshot
								# before comparing them. This makes it possible to update
								# modules without changes reported in the logbook.
								{
									echo "var:MoDuLe:start::${SCC_MODULE}:${checksum}"
									./"${SCC_MODULE}" ${args} 2>&1
									module_has_run=1
									echo "var:MoDuLe:end::${SCC_MODULE}:"
								} >"${SCC_DATA}/plugin_data/${SCC_MODULE}"
							fi
							;;
					esac;
				fi

				if [ ${interactive} -eq 0 ]
				then
					# Send the plugin-data of new user-modules only when it exists.
					if [ -s ${SCC_DATA}/plugin_data/${SCC_MODULE} ]
					then
						# Incorporate the output of the user module.
						cat "${SCC_DATA}/plugin_data/${SCC_MODULE}"
					fi
				fi
				;;
			esac

			if [ ${interactive} -eq 0 ]
			then
				[ ${SCC_PROFILING} ] && scc_timing "${SCC_MODULE}	end of module"
			fi

			if [ ${module_has_run} -eq 0 ]
			then
				# The module has not run.
				# Preserve its data from the keep-file into the new keep-file.
				sed -n -e "/^moduleSTART:${SCC_MODULE}/,/^moduleEND:${SCC_MODULE}/p" ${SCC_KEEP_CONFIG}	|
				sed -e "/^module.*:${SCC_MODULE}/d" >>${SCC_KEEP_NEW}
			fi
			echo "moduleEND:${SCC_MODULE}" >>${SCC_KEEP_NEW}
		else
			echo "fix:messages::non-executable module: ${SCC_MODULE}"
		fi	# if [ -x "${SCC_MODULE}" ]
	done	# for SCC_MODULE in scc_[0-9][0-9][0-9][0-9]_[su]_*
)

##	END
[ ${SCC_PROFILING} ] && scc_timing "end of run"

if [ "${interactive}" -eq 0 ]
then
	# Changing a module will change the check_sum in the keep-file.
	# During the next (regular) run of scc we want the differences for an altered module to be ignored.
	# Do not preserver the keep-data running in interactive mode.
	mv ${SCC_KEEP_NEW} ${SCC_KEEP_CONFIG}
fi

exit 0
