#!/bin/sh

# Shell script to collect and compare 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.104 $


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

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

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

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

export SHELL=/bin/sh
export LANG=C

umask 077

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

cd ${SCC_TMP}

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

# Use the following utilities for SunOS.
if [ -x /usr/ccs/bin/what ]
then
	alias what=/usr/ccs/bin/what
fi
if [ -x /usr/xpg4/bin/awk ]
then
	alias awk=/usr/xpg4/bin/awk
fi
if [ -x /usr/xpg4/bin/grep ]
then
	alias grep=/usr/xpg4/bin/grep
fi
if [ -x /usr/xpg4/bin/tr ]
then
	alias tr=/usr/xpg4/bin/tr
fi

name=$(hostname)
name=${name%%.*}

index=${SCC_DATA}/index.html
lock_cfg=${SCC_DATA}/scc.${name}.lock
ito_log=${SCC_DATA}/cfg.log

split_file=${SCC_CONF}/scc-split.conf

export TMP1_FILE=${SCC_TMP}/scc_log1_$$
export TMP2_FILE=${SCC_TMP}/scc_log2_$$
export TMP3_FILE=${SCC_TMP}/scc_log3_$$

export PROC_FILE=${SCC_TMP}/scc_log_ps_$$

# File, used in release 1.1.30, no longer needed
rm -f ${SCC_DATA}/scc_rpm_keep

scc_check_snapshot()
{
	awk '/^fix:messages:/	{
					# When a module signals an error, the syntax of the message-line is correct
					visited[ "fix:messages::" ] = 1;
					compare[ ":messages:" ] = 1;
			}
		/^fix:|^var:|^hlp:/	{
				class=$0;
				sub( /::.*/, "::", class );
				cnt=split( class, part, ":" );

				if ( visited[ class ] )			# Each visited class already has been checked.
				{
					print $0;			# print, but do not check again.
					next;
				}

				# line with classification with minimal number of elements:
				#	fix:general::			# cnt is 4
				# line with classification with maximal number of elements:
				#	fix:1:2:3:4:5:6:7:8:9:10::	# cnt is 13
				if ( cnt < 4 )
				{
					print "fix:messages::not enough fields in classification:", $0;
				}
				else if ( cnt > 13 )
				{
					print "fix:messages::too many fields in classification:", $0;
				}
				else if ( ( class == $0 ) && ( class !~ "::$" ) )
				{
					print "fix:messages::no end of classification:", $0;
				}
				else
				{
					visited[ class ]=1;

					# A class conflict occurs in the following case:
					# fix:a:b::data
					# fix:a:b:c::data
					# Either a:b is the classification of configuration data,
					# or it is the entry-point for a sub-menu.
					# Help-info can be available for a sub-menu.
					# Therefore no class conflicts for help-info.
					if ( class !~ "^hlp:" )
					{
						sub( /^.../, "", class );	# erase fix or var or hlp
						sub( /::$/, ":", class );	# map :a:: to :a: to check for :a:b:
						for ( c in compare )
						{
							if ( c == class )
							{
								break;
							}
							if ( index( c, class ) == 1 )
							{
								print "fix:messages::class conflict for \"" class "\" and \"" c "\"";
								break;
							}
							if ( index( class, c ) == 1 )
							{
								print "fix:messages::class conflict for \"" c "\" and \"" class "\"";
								break;
							}
						}
						compare[ class ]=1;
					}
					print $0;
				}
				next;
			}
			{
				print "fix:messages::unknown prefix:" $0;
			}'
	return 0;
}

# Check for the conditions in a split-file.
# ARGUMENTS
#	<condition>	"absent" or "present"
#	<arg>		possible formats are:
#			<file>
#			<user>|<process>
check_split_condition()
{
	if [ "${2}" != "${2#*|}" ]
	then
		# This is a very simple process checker.
		user="${2%|*}"		# Split $2 into <user> and <proc>
		proc="${2#*|}"
		awk	'{
				if ( $1 != u )
				{
					next;
				}
				if ( $0 ~ p )
				{
					exit 2;
				}
			}' u="${user}" p="${proc}" ${PROC_FILE}
		ret=$?
		if [ "${1}" = "present" -a "${ret}" -eq 2 ]
		then
			return 1;
		fi
		if [ "${1}" = "absent" -a "${ret}" -ne 2 ]
		then
			return 1;
		fi
	else
		if [ "${1}" = "present" -a -f "${2}" ]
		then
			return 1;
		fi
		if [ "${1}" = "absent" -a ! -f "${2}" ]
		then
			return 1;
		fi
	fi

	return 0
}

# Some commands might "hang", use a lock-file to avoid that more and more
# invocations of Scc start and swamp the system.
if [ -f ${lock_cfg} ]
then
	running=1
	pid=$(<${lock_cfg})
	if [ -n "${pid}" ]
	then
		# Check in a non-destructive way whether the process is still running.
		kill -0 ${pid} 2>/dev/null
		if [ $? -ne 0 ]
		then
			# Unable to signal the process: it is no longer active.
			# Maybe hard-killed during a shutdown.
			running=0
		fi
	fi
	if [ ${running} -eq 1 ]
	then
		echo "${ProgName}: another instance is active, check process ID in ${lock_cfg}" >&2
		exit 2
	fi

	rm -f ${lock_cfg}
fi

# Do not install the traps earlier, as the above exit will remove the
# lock file from the other, running invocation of this program.
trap "rm -f ${TMP1_FILE} ${TMP2_FILE} ${TMP3_FILE} ${lock_cfg} ${PROC_FILE}" 0
trap "exit 2" 1 2 3 15

# Record our PID in the lock-file
echo "$$" > ${lock_cfg}
remark=""
max_months=0			# No limit
mods=""
restart=0
uninstall=0
virtual_host=0
while [ $# -gt 0 ]
do
	case ${1} in
	-c)	remark=$(echo "${2}" | tr -d "\012")	# be sure that the remark is single-line
		shift 2;;

	-e)	mods="${2}";
		shift 2;;

	-m)	case "${2}" in
		[0-9]*)	max_months=${2};;
		*)	echo "${ProgName}: non-numeric argument for -m option: ${2}" >&2
			exit 1;;
		esac
		shift 2;;

	-r)	restart=1
		shift 1;;

	-u)	uninstall=1
		shift 1;;

	-v)	interactive=" -i "
		virtual_host=1
		name="${2}"		# Act as data is originating from virtual host.
		shift 2;;

	*)	echo "Syntax error, use ${ProgName} [ -c <remark> ] [ -e <mod> ] [ -m <max> ] [ -r | -u ] [ -v <host>" >&2
		exit 1;;
	esac
done

if [ ${virtual_host} -eq 1 -a -z "${mods}" ]
then
	echo "${ProgName}: use -e option with -v option" >&2
	exit 1
fi

log_cfg=${SCC_DATA}/scc.${name}.log
keep=${SCC_DATA}/scc.${name}.keep

split_hosts=""
if [ -s "${split_file}" -a ${virtual_host} -eq 0 ]
then
	split_hosts="$(awk -F"|" '/^host\|/ { print $2 }' ${split_file} | sort -u)"
fi

if [ ${restart} -eq 1 ]
then
	# Erase the current snapshot(s) to indicate the restart.
	rm -f ${SCC_DATA}/scc.${name}.cur
	if [ ${virtual_host} -eq 0 ]
	then
		for h in ${split_hosts}
		do
			rm -f ${SCC_DATA}/scc.${h}.cur
		done
	fi
fi

if [ ${uninstall} -eq 1 ]
then
	for h in ${name} ${split_hosts}
	do
		rm -f ${SCC_DATA}/scc.${h}.*
	done
	rm -f ${ito_log} ${lock_cfg} ${keep}
	exit 0
fi

if [ ${virtual_host} -eq 0 ]
then
	# For some programs that inspect the logbook, "fixed" filenames are easier. 
	# Use a symbolic link to save disk-space.
	if [ -h ${ito_log} ]
	then
		# Check whether the target of the symlink corresponds to ${log_cfg}.
		# When this is not the case, the hostname of the system changed.
		prev_host="$(ls -l ${ito_log}	|
			awk '{ sub( /.*scc\./, "", $NF ); sub( /\.log$/, "", $NF ); print $NF }')"
		if [ "${prev_host}" != "${name}" ]
		then
			# We have to move the files to reflect the new hostname.
			for suffix in cur html log log.html keep old
			do
				mv ${SCC_DATA}/scc.${prev_host}.${suffix} ${SCC_DATA}/scc.${name}.${suffix} 2>/dev/null
			done

			if [ -z "${remark}" ]		# Do not change remark supplied with -c option.
			then
				remark="Hostname changed from ${prev_host} to ${name}"
			fi
		fi
	fi
	rm -f ${ito_log}
	touch ${log_cfg}
	ln -s ${log_cfg} ${ito_log}
fi

# Reduce the log file to the specified number of months.
if [ ${max_months} -gt 0 ]
then
	limit=$(( ( $(date '+%Y') * 12 ) + $(date '+%m') - ${max_months} ))

	for h in ${name} ${split_hosts}
	do
		echo "${SCC_DATA}/scc.${h}.log"
	done				|
	sort -u				|
	while read logfile
	do
		first=$(head -1 ${logfile} | awk -F- '{ print ( ( $1 * 12 ) + $2 ) }' )
		if [ -n "${first}" -a ${first} -lt ${limit} ]
		then
			# Some of the log-entries are too old.
			awk -F- '{
					if ( ( ( $1 * 12 ) + $2 ) >= l )
					{
						print;
					}
			}' l="${limit}" ${logfile} >${TMP1_FILE}

			# The html-version of the log file is generated from scratch out of the shorter log file.
			mv ${TMP1_FILE} ${logfile}
		fi
	done
fi	# if [ ${max_months} -gt 0 ]

# Record the start of collecting.
d_n=$(date '+%Y-%m-%d')
t_n_b=$(date '+%H.%M.%S')
s=${t_n_b#*.*.}		# seconds
s=${s#0}		# strip leading "0"
h=${t_n_b%.*.*}		# hours
h=${h#0}		# strip leading "0"
m=${t_n_b#*.}		# minutes and seconds
m=${m%.*}		# minutes
m=${m#0}		# strip leading "0"
tick_start=$(( ${s} + ( 60 * ${m} ) + ( 3600 * ${h} ) ))

# Run scc-collect in a "clean" environment.
# It needs TZ to use the correct time-settings.
# It uses SCC_PROFILING to determine whether to add performance data to the snapshot.
# It uses SCC_IGNORE_STM to determine whether to run stm or not.
# It uses SCC_INSTALL_PHASE to determine whether SCC is called during installation.
env -i	TZ="${TZ}"					\
	SCC_PROFILING="${SCC_PROFILING}"		\
	SCC_IGNORE_STM="${SCC_IGNORE_STM}"		\
	SCC_INSTALL_PHASE="${SCC_INSTALL_PHASE}"	\
	SCC_INSTALL_METHOD="${SCC_INSTALL_METHOD}"	\
	LOGNAME="root"					\
		nice ${SCC_BIN}/scc-collect -e "${mods}" ${interactive} </dev/null >${TMP3_FILE} 2>&1 

# Record the end of collecting.
t_n_e=$(date '+%H.%M.%S')

s=${t_n_e#*.*.}		# seconds
s=${s#0}		# strip leading "0"
h=${t_n_e%.*.*}		# hours
h=${h#0}		# strip leading "0"
m=${t_n_e#*.}		# minutes and seconds
m=${m%.*}		# minutes
m=${m#0}		# strip leading "0"
tick_end=$(( ${s} + ( 60 * ${m} ) + ( 3600 * ${h} ) ))
if [ ${tick_end} -lt ${tick_start} ]
then
	tick_end=$(( ${tick_end} + ( 24 * 3600 ) ))
fi
runtime="$(( ${tick_end} - ${tick_start} ))"

# Check the syntax of the new snapshot.
rm -f ${TMP1_FILE}
sed	-e 's/[ 	][ 	]*$//'	\
	-e '/^$/d' ${TMP3_FILE}				|
scc_check_snapshot >${TMP2_FILE}

rm -f ${TMP1_FILE} ${TMP3_FILE}

# Do not use the split-file when -v option is used.
if [ -s ${split_file} -a ${virtual_host} -eq 0 ]
then
	# The file ${PROC_FILE} only exists during the collection of data.
	# Extract its contents from the new snapshot.
	sed -n -e "s/^var:system:processes:://p" <${TMP2_FILE} >${PROC_FILE}

	# Split the new snapshot according to the split-file.
	# Produce the new snapshots for all pseudo hosts in the splitfile.
	# ${TMP2_FILE} contains the collected data.
	for host in ${split_hosts}
	do
		rm -f ${SCC_DATA}/scc.${host}.new

		# Check whether pseudo host is active/present.
		check="$(sed -n -e "s/^host|${host}|present|//p" ${split_file})"
		if [ -n "${check}" ]
		then
			check_split_condition present "${check}"
			if [ $? -eq 0 ]
			then
				continue
			fi
		fi
		check="$(sed -n -e "s/^host|${host}|absent|//p" ${split_file})"
		if [ -n "${check}" ]
		then
			check_split_condition absent "${check}"
			if [ $? -eq 0 ]
			then
				continue
			fi
		fi

		# Collect all the classifications that have to be moved/copied.
		cp_file=${SCC_TMP}/${host}.cp.$$
		del_file=${SCC_TMP}/${host}.del.$$
		rm -f ${cp_file} ${del_file}

		awk -F"|"	'/^[ 	]*#/	{ next }
				/^[ 	]*$/	{ next }
						{
							if ( $2 != h )
							{
								next;
							}
							data = "";
							n_class = "";
							del = 0;
							new = 0;
						}
				/^class\|.*\|rm\|/	{
							data = $4;
							del = 1;
						}
				/^class\|.*\|cp\|/	{
							data = $4;
							n_class = $4;
							if ( NF == 5 )
							{
								n_class = $5;
							}
							new = 1;
						}
				/^class\|.*\|mv\|/	{
							data = $4;
							n_class = $4;
							if ( NF == 5 )
							{
								n_class = $5;
							}
							del = 1;
							new = 1;
						}
						{
							if ( new == 0 && del == 0 )
							{
								next;
							}

							if ( length( n_class ) == 0 )
							{
								n_class = ":"
							}

							if ( data ~ "^fix:" || data ~ "^var:" )
							{
								# Do not extend.
								if ( new )
								{
									# n_class should also start with "fix:" or "var:"
									printf( "s%s^%s%s%s%sp\n",	\
										sep, data, sep,		\
										n_class, sep ) >>cp_file
								}
								if ( del )
								{
									print data >>del_file;
								}
							}
							else
							{
								# Extend optional with fix, var and hlp.
								col = ":"
								if ( data ~ "^:" )
								{
									col = "";
								}
								if ( new )
								{
									printf( "s%s^fix%s%s%sfix%s%s%sp\n",	\
										sep, col, data, sep,		\
										col, n_class, sep ) >>cp_file
									printf( "s%s^var%s%s%svar%s%s%sp\n",	\
										sep, col, data, sep,		\
										col, n_class, sep ) >>cp_file
									printf( "s%s^hlp%s%s%shlp%s%s%sp\n",	\
										sep, col, data, sep,		\
										col, n_class, sep ) >>cp_file
								}

								if ( del )
								{
									print "fix" col data >>del_file;
									print "var" col data >>del_file;
									print "hlp" col data >>del_file;
								}
							}
							next;
						}'					\
							cp_file="${cp_file}"		\
							del_file="${del_file}"		\
							h="${host}"			\
							sep='\001'			\
								${split_file}

		if [ -s ${cp_file} ]		# Something to copy?
		then
			sed -n -f ${cp_file} ${TMP2_FILE}		|
			scc_check_snapshot >${TMP1_FILE}

			{
				grep -l "^fix:messages::" ${TMP1_FILE} >/dev/null 2>/dev/null
				if [ $? -eq 0 ]
				then
					echo "fix:messages::inspect scc.${host}.cur to determine cause of messages in system/user-modules"
				fi
				echo "var:general::date:${d_n}"
				echo "var:general::start time:${t_n_b}"
				echo "var:general::stop time :${t_n_e}"
				echo "var:general::runtime:${runtime}"
				echo "fix:general::hostname:${host}"
				echo "var:general::remark:${remark}"
				if [ ${restart} -eq 1 ]
				then
					echo "var:general::restart:true"
				fi

				# Record the split-file specifications for this pseudo host
				sed -n -e "s/^\(.*|${host}|\)/var:general::splitfile:\1/p" ${split_file}

				cat ${TMP1_FILE}
				rm -f ${TMP1_FILE}
			} >${SCC_DATA}/scc.${host}.new
		fi
		if [ -s ${del_file} ]		# Something to remove?
		then
			grep -v -f ${del_file} ${TMP2_FILE} >${TMP2_FILE}.tmp
			mv ${TMP2_FILE}.tmp ${TMP2_FILE}
		fi

		rm -f ${cp_file} ${del_file}

	done	# while read host
fi	# if [ -s ${split_file} ]

# The data of the pseudo hosts has been split off from the entire scc-data of the host.
# Now we can generate the new snapshot for the local host.
{
	grep -l "^fix:messages::" ${TMP2_FILE} >/dev/null 2>/dev/null
	if [ $? -eq 0 ]
	then
		echo "fix:messages::inspect scc.${name}.cur to determine cause of messages in system/user-modules"
	fi
	echo "var:general::date:${d_n}"
	echo "var:general::start time:${t_n_b}"
	echo "var:general::stop time :${t_n_e}"
	echo "var:general::runtime:${runtime}"
	cat ${TMP2_FILE}
	rm -f ${TMP2_FILE}
} >${SCC_DATA}/scc.${name}.new

# Compare with previous snapshot and generate html-files.
{
	echo "${name} local"
	if [ -s ${split_file} -a ${virtual_host} -eq 0 ]
	then
		awk -F"|" '/^host\|/ { if ( $3 == "local" || $3 == "remote" ) print $2, $3 }' ${split_file}
	fi
}				|
sort -u				|
while read host compare
do
	new_snapshot=${SCC_DATA}/scc.${host}.new
	prev_snapshot=${SCC_DATA}/scc.${host}.cur
	old_snapshot=${SCC_DATA}/scc.${host}.old
	logfile=${SCC_DATA}/scc.${host}.log

	if [ ! -f ${SCC_DATA}/scc.${host}.new ]
	then
		# No data split off.
		if [ "${compare}" = "local" ]
		then
			# No new data available, do nothing. Previous data will be send to server.
			:
		else
			# Remove all files, to avoid that anything is send to the server.
			rm -f	${SCC_DATA}/scc.${host}.cur	\
				${SCC_DATA}/scc.${host}.log	\
				${SCC_DATA}/scc.${host}.html	\
				${SCC_DATA}/scc.${host}.log.html
		fi
		continue
	fi

	if [ -f ${prev_snapshot} -a "${compare}" = "local" ]
	then
		# Data present from previous run and we have to compare locally.

		>${TMP1_FILE}

		# The software system module of scc records the checksums of all modules.
		# scc-collect "surrounds" the data of a user-module with the following tags:
		#
		#	var:MoDuLe:start::<module>:<checksum>
		#	...
		#	var:MoDuLe:end::<module>:
		#
		# These tags are used to ignore changes when a user-modules has been changed.

		# Suppose you run scc daily and the user modules weekly (on sunday).
		# When you change a user-module on wednesday, the change of the checksum
		# recorded by the software system module will be reported on the next run of scc.
		# On the first run of the changed user-module, the changed checksum in the plugin-data
		# causes that all changes of that user-module are ignored.
		#
		# The "proper" procedure to change a user-module is:
		#	- run all system modules and the user-module: scc -e "<user-module>"
		#	- change the user-module
		#	- test the user-module: scc-collect -i -e "<user-module>"
		#	- rerun the system modules and the user-module: scc -e "<user-module>"
		# The last run will signal the change in the checksum of the user-module,
		# but ignores all changes in the output of the user-module. On the next,
		# weekly activation of the user-module, all (regular) changes will be
		# reported.
		grep "^var:MoDuLe:start::scc_[0-9][0-9][0-9][0-9]_u_" ${prev_snapshot} >${TMP2_FILE}
		grep "^var:MoDuLe:start::scc_[0-9][0-9][0-9][0-9]_u_" ${new_snapshot} >${TMP3_FILE}
		diff ${TMP2_FILE} ${TMP3_FILE}			|
		sed -n -e 's/.*var:MoDuLe:start:://p'		|
		sed -e 's/:.*//'				|
		sort -u						|
		while read module remainder
		do
			# This module is reported, erase all the data of this module.
			echo "/^var:MoDuLe:start::${module}:/,/^var:MoDuLe:end::${module}:/d" >>${TMP1_FILE}
		done

		# Sometimes "fixed" lines between "variable" lines are also reported.
		# Avoid this by limiting the comparison to "fixed" lines.
		if [ -s ${TMP1_FILE} ]
		then
			sed -f ${TMP1_FILE} ${prev_snapshot}		|
			grep "^fix:" >${TMP2_FILE}

			sed -f ${TMP1_FILE} ${new_snapshot}		|
			grep "^fix:" >${TMP3_FILE}

			if [ -z "${remark}" ]		# Do not change remark supplied with -c option.
			then
				remark="changes in modules $(awk -F: '{ printf( "%s ", $(NF - 1) ) }' ${TMP1_FILE}), differences ignored"
			fi
			>${TMP1_FILE}
		else
			grep "^fix:" ${prev_snapshot} >${TMP2_FILE}
			grep "^fix:" ${new_snapshot} >${TMP3_FILE}
		fi

		# During install, the RPM-database is locked and cannot return
		# the installed rpm's. After the installation, the new snapshot
		# contains rpm-data, but the old snapshot does not contain
		# rpm-data. Avoid messages in the log file, by ignoring all
		# rpm-data when the old (current) snapshot does not contain
		# any rpm-data. 
		ignore_rpm=""
		if [ -x /bin/rpm ]
		then
			grep -l "^fix:software:installed-rpms:" ${TMP2_FILE} >/dev/null 2>/dev/null
			if [ $? -ne 0 ]
			then
				# No rpm-data in current (previous) snapshot.
				ignore_rpm="-e /^new::software:installed-rpms:/d "
			fi
		fi

		# Moving data from the main-snapshot through the split-file should not
		# add to the differences when the split-file is created or extended.
		# Only appplicable for the "main"-snapshot.
		ignore_split_moves=""
		if [ "${host}" = "${name}" -a -f ${split_file} ]
		then
			ignore_split_moves="$(sed	-n						\
							-e 's/|$//'					\
							-e 's@^class|.*|mv|\(.*\)|.*@-e /\1/d@p'	\
							-e 's@^class|.*|mv|\(.*\)@-e /\1/d@p'		\
								<${split_file})"
		fi

		# Compare     old          new
		diff ${TMP2_FILE} ${TMP3_FILE}		|
		sed 	-e "/^[0-9]/d"		\
			-e "/^--/d"		\
			-e "s/^< fix:/old::/"	\
			-e "s/^> fix:/new::/" ${ignore_rpm} ${ignore_split_moves} >${TMP1_FILE}

		if [ -s ${TMP1_FILE} ]
		then
			# Get the date and time of the old (current) snapshot.
			d_o=$(head ${prev_snapshot} | sed -n -e "s/.*::date://p")
			t_o=$(head ${prev_snapshot} | sed -n -e "s/.*::start time://p" | sed -e 's/:/./g')

			echo "${d_n}:${t_n_b}:result::different"
			echo "${d_n}:${t_n_b}:remark::${remark}"
			echo "${d_n}:${t_n_b}:runtime::${runtime}"
			echo "${d_n}:${t_n_b}:count::$(wc -l <${TMP1_FILE} | sed -e 's/^ *//')"
			echo "${d_n}:${t_n_b}:previous date::${d_o}"
			echo "${d_n}:${t_n_b}:previous time::${t_o}"

			sed -e "s/^/${d_n}:${t_n_b}:data::/" ${TMP1_FILE}
		else
			echo "${d_n}:${t_n_b}:result::identical"
			echo "${d_n}:${t_n_b}:remark::${remark}"
			echo "${d_n}:${t_n_b}:runtime::${runtime}"
		fi >>${logfile}
		rm -f ${TMP1_FILE}
	else	# if [ -f ${prev_snapshot} -a "${compare}" = "local" ]
		# No previous snapshot available.
		if [ "${compare}" = "local" ]
		then
			# Indicate a restart for this local (re)start.
			{
				echo "${d_n}:${t_n_b}:result::(re)start"
				echo "${d_n}:${t_n_b}:remark::${remark}"
				echo "${d_n}:${t_n_b}:runtime::${runtime}"
			} >>${logfile}
		else
			# Just empty the logfile to indicate to the server a remote compare.
			>${logfile};
		fi
	fi
	if [ -f ${prev_snapshot} ]
	then
		rm -f ${old_snapshot}
		mv -f ${prev_snapshot} ${old_snapshot}
	fi
	mv -f ${new_snapshot} ${prev_snapshot}

	if [ -s ${logfile} ]
	then
		nice ${SCC_BIN}/scc-log2html ${host} <${logfile} >${logfile}.html
	else
		> ${logfile}.html
	fi

	# The file with the previous snapshot has been replaced by the new (current) snapshot.
	nice ${SCC_BIN}/scc-snap2html ${host} <${prev_snapshot} >${SCC_DATA}/scc.${host}.html
done

if [ ${virtual_host} -eq 0 ]
then
	# To ease navigation on the server, the html-file of the snapshot contains a reference
	# to index.html (the main file for a realm). To avoid an 404 error when browsing on the client,
	# we create a simple index.html on the client.
	cat <<-_X_ >${index}
		<HTML>
		<HEAD>
			<TITLE>Index for ${name}</TITLE>
		</HEAD>
		<BODY>
			<A HREF=scc.${name}.html>snapshot of ${name}</A>
			<BR>
			<A HREF=scc.${name}.log.html>logbook of ${name}</A>
			<BR>
			<A HREF=/opt/scc/man/man5/scc-5.html>manual pages</A>
		</BODY>
		</HTML>
	_X_
fi

exit 0
