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

##  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 ${PATHETC}/innfeed-delayed.conf"
INNFEED=
if [ -f "${MOST_LOGS}/innfeed.log" ]; then
    INNFEED="${MOST_LOGS}/innfeed.log"
fi
INNFEEDPIDFILES=
if [ -f "${PATHRUN}/innfeed.pid" ]; then
    INNFEEDPIDFILES="${PATHRUN}/innfeed.pid"
fi
for F in ${INNFEEDCONF}; do
    if [ -f "${F}" ]; then
        INNFEEDLOG=$(${AWK} '{gsub(/:|#/, " & ")} \
                             {if ($1 == "log-file" && $2 == ":" \
                                  && $3 != "innfeed.log") \
                                  print $3}' ${F})
        INNFEEDPID=$(${AWK} '{gsub(/:|#/, " & ")} \
                             {if ($1 == "pid-file" && $2 == ":" \
                                  && $3 != "innfeed.pid") \
                                  print $3}' ${F})
    fi
    for L in ${INNFEEDLOG}; do
        if [ -f "${MOST_LOGS}/${L}" ]; then
            INNFEED="${INNFEED} ${MOST_LOGS}/${L}"
        fi
    done
    for P in ${INNFEEDPID}; do
        if [ -f "${PATHRUN}/${P}" ]; then
            INNFEEDPIDFILES="${INNFEEDPIDFILES} ${PATHRUN}/${P}"
        fi
    done
done
NNTPSEND=${MOST_LOGS}/nntpsend.log
PERLNOCEM=${MOST_LOGS}/perl-nocem.log
SENDIHAVE=${MOST_LOGS}/send-ihave.log
SENDUUCP=${MOST_LOGS}/send-uucp.log
LIVEFILES="${CONTROLBATCH} ${INNFEED} ${NNTPSEND} ${PERLNOCEM} \
    ${SENDIHAVE} ${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.
    for F in ${INNFEEDPIDFILES}; do
        INNFEEDPID=
        test -f "${F}" && INNFEEDPID=$(cat "${F}")
        ##  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
    done

    ${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} | ${PERLNOCEM})
            ##  Make a link that can be deleted (since if not rotating
            ##  we delete the copy that is made in ${TMPDIR}).
            if [ -f ${F}.old ]; then
                mv ${F}.old ${OLD}/${BASE}
                rm -f ${OLD}/${BASE}.0
                ln ${OLD}/${BASE} ${OLD}/${BASE}.0
            fi
            ;;
        ${ACTIVEFILE})
            mv ${BASE}.old ${OLD}/${BASE}
            ;;
        ${UNWANTED_LOG})
            ##  innreport assumes where unwanted.log exists, so leave it.
            ##  This log file is not reset because it keeps the count of
            ##  articles posted to newsgroups not present in the active file.
            ##  Just copy the current file without removing it.
            if [ -f ${F} ]; then
                cp ${F} ${OLD}/${BASE}
                chmod 0440 ${OLD}/${BASE}
            fi
            ;;
        *)
            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} \
        ${PERLNOCEM}; do
        BASE=$(basename ${F})
        rm -f ${OLD}/${BASE}.0
        test -f ${F} && 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

##  Also add possible logs from perl-nocem.log to the analysis.
BASE=$(basename ${PERLNOCEM})
OLD_PERLNOCEM=${OLD}/${BASE}.0
if [ -f ${OLD_PERLNOCEM} ]; then
    cat ${OLD_PERLNOCEM} >>${OLD_SYSLOG}
fi
rm -f ${OLD_PERLNOCEM}

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}

##  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 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
