#! /bin/sh
. /usr/lib/innshellvars

##  $Id: scanlogs.in 9903 2015-06-20 17:20:46Z iulius $
##
##  Summarize INN log files and rotate them.
##  Used by news.daily.
##
##  Optional arguments:
##	norotate	Do not rotate logfiles.

##  Directory where old log files are kept.
OLD=${MOST_LOGS}/OLD

##  Files defined in innshellvars.  We repeat them for clarity.
ERRLOG=${MOST_LOGS}/errlog
LOG=${MOST_LOGS}/news

##  If you want to archive the active file, enable this line.
ACTIVEFILE=${ACTIVE}

##  Maximum number of lines to show from error log files.
MAXERRLINES=50

##  Where these programs, if used, write their logs.
##  We also have to find innfeed's log file.
CONTROLBATCH=${MOST_LOGS}/controlbatch.log
INNFEEDCONF=${PATHETC}/innfeed.conf
if [ -f "${INNFEEDCONF}" ]; then
    INNFEEDLOG=`${AWK} '{gsub(/:|#/, " & ")} {if ($1 == "log-file" && $2 == ":") print $3}' ${INNFEEDCONF}`
    INNFEEDPIDFILE=`${AWK} '{gsub(/:|#/, " & ")} {if ($1 == "pid-file" && $2 == ":") print $3}' ${INNFEEDCONF}`
fi
INNFEED=
for F in "${INNFEEDLOG}" ; do
    test -f "${MOST_LOGS}/${F}" && INNFEED="${INNFEED} ${MOST_LOGS}/${F}"
done
test -z "${INNFEED}" && test -f "${MOST_LOGS}/innfeed.log" && INNFEED="${MOST_LOGS}/innfeed.log"
NNTPSEND=${MOST_LOGS}/nntpsend.log
PERLNOCEM=${MOST_LOGS}/perl-nocem.log
SENDIHAVE=${MOST_LOGS}/send-ihave.log
SENDNNTP=${MOST_LOGS}/send-nntp.log
SENDUUCP=${MOST_LOGS}/send-uucp.log
LIVEFILES="${CONTROLBATCH} ${INNFEED} ${NNTPSEND} ${PERLNOCEM} ${SENDIHAVE} ${SENDNNTP} ${SENDUUCP}"

##  Where news.daily places expire output, unless noexplog was used.
EXPLOG=${MOST_LOGS}/expire.log

##  If you divide your news syslog into separate files, list them here.
SYSLOG_CRIT=${MOST_LOGS}/news.crit
SYSLOG_ERR=${MOST_LOGS}/news.err
SYSLOG_NOTICE=${MOST_LOGS}/news.notice
SYSLOGS="${SYSLOG_CRIT} ${SYSLOG_ERR} ${SYSLOG_NOTICE}"

##  Where tally control processor is found.
TALLY_CONTROL=${PATHBIN}/tally.control
UNWANTED_LOG=${MOST_LOGS}/unwanted.log
CONTROL_LOG=${MOST_LOGS}/control.log
CONTROL_DATA=
test -f ${MOST_LOGS}/newgroup.log && CONTROL_DATA=${MOST_LOGS}/newgroup.log
test -f ${MOST_LOGS}/rmgroup.log \
	&& CONTROL_DATA="${CONTROL_DATA} ${MOST_LOGS}/rmgroup.log"

##  Build up the list of log files to process.
LOGS="${ERRLOG} ${LOG} ${ACTIVEFILE} ${EXPLOG} ${SYSLOGS} ${UNWANTED_LOG}"

for F in ${LIVEFILES} ; do
    test -n "${F}" -a -f "${F}" && LOGS="${LOGS} ${F}"
done

test -n "${CONTROL_DATA}" && LOGS="${LOGS} ${CONTROL_LOG}"

for F in checkgroups default ihave newgroup rmgroup sendme sendsys \
	senduuname version miscctl badcontrol failedpgp badpgp; do
    test -f ${MOST_LOGS}/${F}.log && LOGS="${LOGS} ${MOST_LOGS}/${F}.log"
done

PROGNAME=scanlogs
LOCK=${LOCKS}/LOCK.${PROGNAME}

##  Set defaults.
ROTATE=true

##  Parse JCL.
for I
do
    case "X${I}" in
    Xnorotate)
	ROTATE=false
	;;
    *)
	echo "Unknown flag ${I}" 1>&2
	exit 1
	;;
    esac
done

##  Make sure every log exists.
for F in ${LOGS} ; do
    test ! -f ${F} && touch ${F}
done

##  Rotate the logs?
if ${ROTATE} ; then
    ##  Lock out others.
    shlock -p $$ -f ${LOCK} || {
	echo "$0: Locked by `cat ${LOCK}`"
	exit 1
    }
    trap "rm -f ${LOCK}; exit 0" 1 2 3 15

    HERE=`pwd`
    cd ${MOST_LOGS}
    test ! -d ${OLD} && mkdir ${OLD}

    ctlinnd -s logmode
    PAUSED=false
    ctlinnd -s pause "Flushing log and syslog files" 2>&1 && PAUSED=true

    ##  First, flush log files to be sure everything has been recorded
    ##  before rotating them.
    OUTPUT=`ctlinnd flushlogs 2>&1`
    if [ "$OUTPUT" != "Ok" -a "$OUTPUT" != "In debug mode" ]; then
	echo "$OUTPUT"
	echo 'Cannot flush logs.'
	rm -f ${LOCK}
	exit 1
    fi

    ##  Make sure these .old files exist, in case innd is down.
    for F in ${LOG} ${ERRLOG} ; do
	if [ ! -f ${F}.old ]; then
	    rm -f ${F}.old
	    cp ${F} ${F}.old
	    cat /dev/null >${F}
	fi
    done

    ##  Copy syslog files, truncating old inode since syslog has it open.
    for F in ${SYSLOGS}; do
	rm -f ${F}.old
	cp ${F} ${F}.old
	cat /dev/null >${F}
    done
    ctlinnd -s logmode

    ##  Make a copy of the active file.
    if [ -n ${ACTIVEFILE} ] ; then
	BASE=`basename ${ACTIVEFILE}`
	rm -f ${OLD}/${BASE}.old
	cp ${ACTIVEFILE} ${OLD}/${BASE}.old
    fi

    ##  These are live files, so use link rather than copy.
    for F in ${LIVEFILES} ; do
	if [ -f ${F} ]; then
	    rm -f ${F}.old ${F}.new
	    ln ${F} ${F}.old
	    touch ${F}.new
	    chmod 0660 ${F}.new
	    mv ${F}.new ${F}
	fi
    done

    ##  Tally control messages if we logged them.
    test -n "${CONTROL_DATA}" && cat ${CONTROL_DATA} | ${TALLY_CONTROL}

    ##  Find out the PID of innfeed now and not at the beginning of scanlogs
    ##  because it is restarted when running ctlinnd flushlogs.
    INNFEEDPID=
    for F in "${INNFEEDPIDFILE}" ; do
        test -f "${PATHRUN}/${F}" && INNFEEDPID=`cat "${PATHRUN}/${F}"`
    done
    test -z "${INNFEEDPID}" && test -f "${PATHRUN}/innfeed.pid" && INNFEEDPID=`cat "${PATHRUN}/innfeed.pid"`

    ##  Send a HUP signal to innfeed so that it reopens its log files.
    if [ ! -z ${INNFEEDPID} ]; then
        kill -HUP ${INNFEEDPID} > /dev/null 2>&1
    fi

    ${PAUSED} && ctlinnd -s go "Flushing log and syslog files" 2>&1

    cd ${OLD}
    for F in ${LOGS}; do
	##  Process the current (just-flushed) log.
	BASE=`basename ${F}`
	rm -f ${OLD}/${BASE}
	case ${F} in
	${SYSLOG_CRIT}|${SYSLOG_ERR}|${ERRLOG}|${LOG}|${SYSLOG_NOTICE})
	    ##  Make a link that can be deleted (since if not rotating
	    ##  we delete the copy that is made in ${TMPDIR}).
	    mv ${F}.old ${OLD}/${BASE}
	    rm -f ${OLD}/${BASE}.0
	    ln ${OLD}/${BASE} ${OLD}/${BASE}.0
	    ;;
	${ACTIVEFILE})
	    mv ${BASE}.old ${OLD}/${BASE}
	    ;;
	${UNWANTED_LOG})
	    ##  Rotate and compress the file.
	    BASE=`basename ${F}`
	    if [ ! -f ${BASE} -a -f ../${BASE} ]; then
		cp ../${BASE} ${BASE}
		chmod 0440 ${BASE}
	    fi
	    if [ -f ${BASE} ]; then
		${LOG_COMPRESS} <${BASE} >${BASE}.0${Z} && rm -f ${BASE}
		chmod 0440 ${BASE}.0${Z}

		##  Do rotation.
		if [ X${LOGCYCLES} = X ]; then       
		    LOGCYCLES=3
		fi
		EXT=${LOGCYCLES}
		rm -f ${BASE}.${LOGCYCLES}${Z}
		while [ ${EXT} -gt 0 ] ; do
		    NEXT=${EXT}
		    EXT=`expr ${EXT} - 1`
		    test -f ${BASE}.${EXT}${Z} \
			&& rm -f ${BASE}.${NEXT}${Z} \
			&& mv ${BASE}.${EXT}${Z} ${BASE}.${NEXT}${Z}
		done
	    fi
	    ##  innreport assumes where unwanted.log exists, so leave it
	    ##  and process later.
	    ;;
	*)
	    if [ -f ${F}.old ]; then
		mv ${F}.old ${OLD}/${BASE}
	    else
		rm -f ${OLD}/${BASE} ${F}.new
		touch ${F}.new
		chmod 0660 ${F}.new
		ln ${F} ${F}.old
		mv ${F}.new ${F}
		mv ${F}.old ${OLD}/${BASE}
	    fi
	    ;;
	esac
    done
    cd ${HERE}

else
    ##  Don't use the real OLD directory, instead use TMPDIR.
    OLD=${TMPDIR}

    ##  Make a snapshot of what we need for below.
    ctlinnd -s pause "Snapshot log and syslog files" 2>&1
    for F in ${SYSLOG_CRIT} ${SYSLOG_ERR} ${ERRLOG} ${LOG} ${SYSLOG_NOTICE} ; do
	BASE=`basename ${F}`
	rm -f ${OLD}/${BASE}.0
	cp ${F} ${OLD}/${BASE}.0
    done
    ctlinnd -s go "Snapshot log and syslog files" 2>&1
fi

##
##  We now (finally!) have copies of the log files where we need them.
##

##  Display syslog critical messages.
BASE=`basename ${SYSLOG_CRIT}`
OLD_SYSLOG=${OLD}/${BASE}.0
if [ -s ${OLD_SYSLOG} ] ; then
    echo Syslog critical messages:
    cat ${OLD_SYSLOG} | head -n ${MAXERRLINES}
    echo ---------
    echo ''
fi
rm -f ${OLD_SYSLOG}

##  Display syslog error messages.
BASE=`basename ${SYSLOG_ERR}`
OLD_SYSLOG=${OLD}/${BASE}.0
if [ -s ${OLD_SYSLOG} ] ; then
    echo Syslog error messages:
    cat ${OLD_SYSLOG} | head -n ${MAXERRLINES}
    echo ---------
    echo ''
fi
rm -f ${OLD_SYSLOG}

##  Display error log.
BASE=`basename ${ERRLOG}`
OLD_ERRLOG=${OLD}/${BASE}.0
if [ -s ${OLD_ERRLOG} ] ; then
    echo Error log:
    cat ${OLD_ERRLOG} | head -n ${MAXERRLINES}
    echo ---------
    echo ''
fi
rm -f ${OLD_ERRLOG}

##  Scan for various problems in articles we were offered or sent...
BASE=`basename ${LOG}`
OLD_LOG=${OLD}/${BASE}.0

##  and summarize syslog information.
BASE=`basename ${SYSLOG_NOTICE}`
OLD_SYSLOG=${OLD}/${BASE}.0
INNREPORT=${TMPDIR}/innreport$$
if [ -s ${OLD_SYSLOG} -o -s ${OLD_LOG} ] ; then
    ${PATHBIN}/innreport -f ${PATHETC}/innreport.conf ${OLD_SYSLOG} ${OLD_LOG} > ${INNREPORT}
    if [ -s ${INNREPORT} ] ; then
        cat ${INNREPORT}
        echo ---------
        echo ''
    fi
fi
rm -f ${OLD_LOG} ${OLD_SYSLOG} ${INNREPORT}

##  Now that innreport has finished, we can move unwanted.log.  This
##  file is not reset because it keeps the count of unwanted newsgroups.
if ${ROTATE} ; then
    BASE=`basename ${UNWANTED_LOG}`
    if [ -f ${UNWANTED_LOG}.old ]; then
	mv ${UNWANTED_LOG}.old ${OLD}/${BASE}
    else
	rm -f ${OLD}/${BASE}
	cp ${UNWANTED_LOG} ${OLD}/${BASE}
	chmod 0660 ${OLD}/${BASE}
    fi
fi

##  Compress and rotate the logs.
if ${ROTATE} ; then
    cd ${OLD}
    if [ X${LOGCYCLES} = X ]; then       
        LOGCYCLES=3
    fi
    for F in ${LOGS} ; do
	##  Skip if it's unwanted.log, since it's already rotated.
	if [ ${F} = ${UNWANTED_LOG} ]; then
	    continue
	fi
	##  Skip if file doesn't exist.
	BASE=`basename ${F}`
	test -f ${BASE} || continue

	##  Compress the file.
	${LOG_COMPRESS} <${BASE} >${BASE}.0${Z} && rm -f ${BASE}
	chmod 0440 ${BASE}.0${Z}

	##  Do rotation.
	EXT=${LOGCYCLES}
	rm -f ${BASE}.${LOGCYCLES}${Z}
	while [ ${EXT} -gt 0 ] ; do
	    NEXT=${EXT}
	    EXT=`expr ${EXT} - 1`
	    test -f ${BASE}.${EXT}${Z} \
		&& rm -f ${BASE}.${NEXT}${Z} \
		&& mv ${BASE}.${EXT}${Z} ${BASE}.${NEXT}${Z}
	done
    done

    ##  Remove lock.
    rm -f ${LOCK}
fi

##  All done.
exit 0
