#!/bin/sh
#
# Amanda, The Advanced Maryland Automatic Network Disk Archiver
# Copyright (c) 1991-1998 University of Maryland at College Park
# All Rights Reserved.
#
# Permission to use, copy, modify, distribute, and sell this software and its
# documentation for any purpose is hereby granted without fee, provided that
# the above copyright notice appear in all copies and that both that
# copyright notice and this permission notice appear in supporting
# documentation, and that the name of U.M. not be used in advertising or
# publicity pertaining to distribution of the software without specific,
# written prior permission.  U.M. makes no representations about the
# suitability of this software for any purpose.  It is provided "as is"
# without express or implied warranty.
#
# U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
# OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
# Author: James da Silva, Systems Design and Analysis Group
#			   Computer Science Department
#			   University of Maryland at College Park
#

#
# amcleanup.sh - clean up and generate a report after a crash.

# try to hit all the possibilities here
prefix=/usr
exec_prefix=${prefix}
libexecdir=/usr/lib/amanda
sbindir=${exec_prefix}/sbin

confdir=/etc/amanda

PATH=$sbindir:$libexecdir:/usr/bin:/bin:/usr/sbin:/sbin:/usr/ucb
export PATH

USE_VERSION_SUFFIXES="no"
if test "$USE_VERSION_SUFFIXES" = yes; then
	SUF=-2.5.1p1
else
	SUF=
fi

if test -h /proc/1/exe ; then
	if test $# -eq 1 ; then
		KILL_ENABLE=0
		conf=$1
		shift;
	elif test $# -eq 2 && test "$1" == "-k" ; then
		KILL_ENABLE=1
		conf=$2
		shift
		shift
	else
		echo "Usage: amcleanup [-k] conf"
		exit 1
	fi
else
	if test $# -ne 1 ; then
		echo "Usage: amcleanup conf"
		exit 1
	else
		conf=$1
		KILL_ENABLE=0
	fi
fi

if test ! -d $confdir/$conf ; then
	echo "amcleanup: could not cd into $confdir/$conf"
	exit 1
fi

cd $confdir/$conf

logdir=`amgetconf$SUF $conf logdir "$@"`
rc=$?
if test $rc -ne 0 ; then
	echo "amcleanup: 'amgetconf$SUF logdir' exited with status: $rc" 1>&2
	exit 1
fi
logfile=$logdir/log
errfile=$logdir/amdump
erramflush=$logdir/amflush
tapecycle=`amgetconf$SUF $conf tapecycle "$@"`
rc=$?
if test $rc -ne 0 ; then
	echo "amcleanup: 'amgetconf$SUF tapecycle' exited with status: $rc " 1>&2
	exit 1
fi
dumpuser=`amgetconf$SUF $conf dumpuser "$@"`
rc=$?
if test $rc -ne 0 ; then
	echo "amcleanup: 'amgetconf$SUF $conf dumpuser' exited with status: $rc" 1>&2
	exit 1
fi

# Check for running processes which should not be
# running right now.
if test ${KILL_ENABLE} -eq 1 ; then
	if test -h /proc/1/exe ; then
		USER_PROCESS_NAMES="\
			/usr/lib/amanda/amandad \
			/usr/lib/amanda/amcleanupdisk \
			/usr/lib/amanda/amidxtaped \
			/usr/lib/amanda/amindexd \
			/usr/lib/amanda/amlogroll \
			/usr/lib/amanda/amtrmidx \
			/usr/lib/amanda/amtrmlog \
			/usr/lib/amanda/chg-chio \
			/usr/lib/amanda/chg-chs \
			/usr/lib/amanda/chg-disk \
			/usr/lib/amanda/chg-iomega \
			/usr/lib/amanda/chg-juke \
			/usr/lib/amanda/chg-manual \
			/usr/lib/amanda/chg-mcutil \
			/usr/lib/amanda/chg-mtx \
			/usr/lib/amanda/chg-multi \
			/usr/lib/amanda/chg-null \
			/usr/lib/amanda/chg-rait \
			/usr/lib/amanda/chg-rth \
			/usr/lib/amanda/chg-scsi \
			/usr/lib/amanda/chg-zd-mtx \
			/usr/lib/amanda/chunker \
			/usr/lib/amanda/driver \
			/usr/lib/amanda/generic-dumper \
			/usr/lib/amanda/gnutar \
			/usr/lib/amanda/noop \
			/usr/lib/amanda/patch-system \
			/usr/lib/amanda/selfcheck \
			/usr/lib/amanda/sendbackup \
			/usr/lib/amanda/sendsize \
			/usr/lib/amanda/star \
			/usr/lib/amanda/taper \
			/usr/lib/amanda/versionsuffix \
			${exec_prefix}/sbin/amaddclient \
			${exec_prefix}/sbin/amadmin \
			${exec_prefix}/sbin/amaespipe \
			${exec_prefix}/sbin/amcheckdb \
			${exec_prefix}/sbin/amcrypt \
			${exec_prefix}/sbin/amcryptsimple \
			${exec_prefix}/sbin/amdd \
			${exec_prefix}/sbin/amdump \
			${exec_prefix}/sbin/amfetchdump \
			${exec_prefix}/sbin/amflush \
			${exec_prefix}/sbin/amgetconf \
			${exec_prefix}/sbin/amgpgcrypt \
			${exec_prefix}/sbin/amlabel \
			${exec_prefix}/sbin/ammt \
			${exec_prefix}/sbin/amoverview \
			${exec_prefix}/sbin/amplot \
			${exec_prefix}/sbin/amrecover \
			${exec_prefix}/sbin/amreport \
			${exec_prefix}/sbin/amrestore \
			${exec_prefix}/sbin/amrmtape \
			${exec_prefix}/sbin/amserverconfig \
			${exec_prefix}/sbin/amstatus \
			${exec_prefix}/sbin/amtape \
			${exec_prefix}/sbin/amtapetype \
			${exec_prefix}/sbin/amtoc \
			${exec_prefix}/sbin/amverify \
			${exec_prefix}/sbin/amverifyrun"

		ROOT_PROCESS_NAMES="\
			/usr/lib/amanda/calcsize \
			/usr/lib/amanda/killpgrp \
			/usr/lib/amanda/rundump \
			/usr/lib/amanda/runtar \
			/usr/lib/amanda/dumper \
			/usr/lib/amanda/planner \
			${exec_prefix}/sbin/amcheck"

		PREVIOUS_DIR="`pwd`"
		cd /proc
		PIDS_FOUND=0
		KEEP_CHECKING=1
		while test ${KEEP_CHECKING} -ne 0 ; do
			PIDS_THIS_PASS=0
			for search_user in ${dumpuser} root ; do
				if test "${search_user}" == "${dumpuser}" ; then
					PROCESS_NAMES=${USER_PROCESS_NAMES}
				elif test "${search_user}" == "root" ; then
					PROCESS_NAMES=${ROOT_PROCESS_NAMES}
				fi
				for search_pid in [0-9]* ; do
					for search_name in ${PROCESS_NAMES} ; do
						ls -l /proc/${search_pid}/exe 2>/dev/null | grep ${search_name} >/dev/null
						match_name=$?
						pid_uid="`cat /proc/${search_pid}/status 2>/dev/null | grep Uid | awk '//{split($_,i); print i[2]}'`"
						if test ${match_name} -eq 0  && test "${pid_uid}" == "${search_user}" ; then
							echo "amcleanup: Process ${search_name} found running at pid #${search_pid}."
							kill_pid=${search_pid}
							kill_name=${search_name}
							PIDS_FOUND=`expr ${PIDS} + 1`
							PIDS_THIS_PASS=1
							break
						else
							kill_pid=""
							continue
						fi
					done
					if test ! -z "${kill_pid}" ; then
						if test -d /proc/${kill_pid} ; then
							echo "amcleanup: Sending process ${kill_pid} the TERM signal."
							kill -15 -- ${kill_pid}
							sleep 5
							if test -d /proc/${kill_pid} ; then
								echo "amcleanup: Sending process  ${kill_pid} the KILL signal."
								kill -9 -- ${kill_pid}
							fi
							sleep 5
							if test -d /proc/${kill_pid} ; then
								echo "amcleanup: Process ${kill_pid} did not respond to the KILL signal (and may be hung)!" 1>&2
								KILL_FAILURES=`expr ${KILL_FAILURES} + 1`
							fi
						else
							echo "amcleanup: Process ${kill_pid} no longer running.  Skipping..."
						fi
					fi
				done
			done
			if test ${PIDS_THIS_PASS} -eq 0 ; then
				KEEP_CHECKING=0
			else
				KEEP_CHECKING=1
			fi
		done
		if test ${PIDS_FOUND} -gt 0 ; then
			echo "amcleanup: ${PIDS_FOUND} Amanda processes were found running."
			echo "amcleanup: ${KILL_FAILURES} processes failed to terminate."
		else
			echo "amcleanup: No Amanda processes were found running."
		fi
		cd "${PREVIOUS_DIR}"
	fi
fi

retstatus=0
if test -f $logfile ; then
	echo "amcleanup: processing outstanding log file."
	exec </dev/null >/dev/null 2>&1
	amreport$SUF $conf "$@"
	rc=$?
	if test $rc -ne 0 ; then
		echo "amcleanup: amreport exited with status: $rc" 1>&2
		retstatus=`expr $retstatus + 1`
	fi

	# Roll the log file to its datestamped name.
	amlogroll$SUF $conf "$@"
	rc=$?
	if test $rc -ne 0 ; then
		echo "acmleanup: amlogroll exited with status: $rc" 1>&2
		retstatus=`expr $retstatus + 2`
	fi

	# Trim the index file to those for dumps that still exist.
	amtrmidx$SUF $conf "$@"
	rc=$?
	if test $rc -ne 0 ; then
		echo "amcleanup: amtrmidx exited with status: $rc" 1>&2
		retstatus=`expr $retstatus + 4`
	fi

else
	echo "amcleanup: no unprocessed logfile to clean up."
fi

if test -f $errfile ; then
    # if log was found, this will have been directed to /dev/null,
    # which is fine.
    echo "amcleanup: $errfile exists, renaming it."

    # Keep debug log through the tapecycle plus a couple days
    maxdays=`expr $tapecycle + 2`

    days=1
    # First, find out the last existing errfile,
    # to avoid ``infinite'' loops if tapecycle is infinite
    while test $days -lt $maxdays  && test -f $errfile.$days ; do
	days=`expr $days + 1`
    done
    # Now, renumber the existing log files
    while test $days -ge 2 ; do
	ndays=`expr $days - 1`
	mv $errfile.$ndays $errfile.$days
	days=$ndays
    done
    mv $errfile $errfile.1
fi

if test -f $erramflush ; then
    # if log was found, this will have been directed to /dev/null,
    # which is fine.
    echo "amcleanup: $erramflush exists, renaming it."

    # Keep debug log through the tapecycle plus a couple days
    maxdays=`expr $tapecycle + 2`

    days=1
    # First, find out the last existing erramflush,
    # to avoid ``infinite'' loops if tapecycle is infinite
    while test $days -lt $maxdays  && test -f $erramflush.$days ; do
	days=`expr $days + 1`
    done
    # Now, renumber the existing log files
    while test $days -ge 2 ; do
	ndays=`expr $days - 1`
	mv $erramflush.$ndays $erramflush.$days
	days=$ndays
    done
    mv $erramflush $erramflush.1
fi

$libexecdir/amcleanupdisk $conf "$@"
rc=$?
if test $rc -ne 0 ; then
	echo "amcleanup: amcleanupdisk exited with status: $rc" 1>&2
	retstatus=`expr $retstatus + 8`
fi

exit $retstatus
