1#!/bin/sh -
2#
3#
4# Run nightly periodic scripts
5#
6# usage: periodic { daily | weekly | monthly | security } - run standard scripts
7#        periodic /absolute/path/to/directory  - run periodic scripts in dir
8#
9
10usage () {
11    echo "usage: $0 <directory of files to execute>" 1>&2
12    echo "or     $0 { daily | weekly | monthly | security }"    1>&2
13    exit 1
14}
15
16output_pipe()
17{
18    # Where's our output going ?
19    eval output=\$${1##*/}_output
20    case "$output" in
21    /*) pipe="cat >>$output";;
22    "") pipe=cat;;
23    *)  pipe="mail -E -s '$host ${2}${2:+ }${1##*/} run output' $output";;
24    esac
25    eval $pipe
26}
27
28if [ $# -lt 1 ] ; then
29    usage
30fi
31
32_localbase=`/sbin/sysctl -n user.localbase 2> /dev/null`
33# Set default value of _localbase if not previously set
34: ${_localbase:="/usr/local"}
35
36# Use a deterministic path to match the preset from /etc/crontab in case
37# periodic is run interactively.
38export PATH=/sbin:/bin:/usr/sbin:/usr/bin:${_localbase}/sbin:${_localbase}/bin
39
40# If possible, check the global system configuration file,
41# to see if there are additional dirs to check
42if [ -r /etc/defaults/periodic.conf ]; then
43    . /etc/defaults/periodic.conf
44    source_periodic_confs
45fi
46
47host=`hostname`
48export host
49
50# If we were called normally, then create a lock file for each argument
51# in turn and reinvoke ourselves with the LOCKED argument.  This prevents
52# very long running jobs from being overlapped by another run as this is
53# will lead the system running progressively slower and more and more jobs
54# are run at once.
55if [ $1 != "LOCKED" ]; then
56    ret=0
57    for arg; do
58        lockfile=/var/run/periodic.${arg##*/}.lock
59        lockf -s -t 0 "${lockfile}" /bin/sh $0 LOCKED "$arg"
60        case $? in
61        0) ;;
62        73) #EX_CANTCREATE
63            echo "can't create ${lockfile}" | \
64                output_pipe $arg "$PERIODIC"
65            ret=1
66            ;;
67        75) #EX_TEMPFAIL
68            echo "$host ${arg##*/} prior run still in progress" | \
69                output_pipe $arg "$PERIODIC"
70            ret=1
71            ;;
72        *)
73            ret=1
74            ;;
75        esac
76    done
77    exit $ret
78fi
79
80if [ $# -ne 2 ]; then
81    usage
82fi
83shift
84arg=$1
85
86if [ -z "$PERIODIC_ANTICONGESTION_FILE" ] ; then
87	export PERIODIC_ANTICONGESTION_FILE=`mktemp ${TMPDIR:-/tmp}/periodic.anticongestion.XXXXXXXXXX`
88	remove_periodic_anticongestion_file=yes
89else
90	# We might be in a recursive invocation; let the top-level invocation
91	# remove the file.
92	remove_periodic_anticongestion_file=no
93fi
94if [ -t 0 ]; then
95	export PERIODIC_IS_INTERACTIVE=1
96fi
97tmp_output=`mktemp ${TMPDIR:-/tmp}/periodic.XXXXXXXXXX`
98context="$PERIODIC"
99export PERIODIC="$arg${PERIODIC:+ }${PERIODIC}"
100
101# Execute each executable file in the directory list.  If the x bit is not
102# set, assume the user didn't really want us to muck with it (it's a
103# README file or has been disabled).
104
105success=YES info=YES badconfig=NO empty_output=YES	# Defaults when ${run}_* aren't YES/NO
106for var in success info badconfig empty_output; do
107    case $(eval echo "\$${arg##*/}_show_$var") in
108    [Yy][Ee][Ss]) eval $var=YES;;
109    [Nn][Oo])     eval $var=NO;;
110    esac
111done
112
113case $arg in
114/*) if [ -d "$arg" ]; then
115        dirlist="$arg"
116    else
117        echo "$0: $arg not found" >&2
118        exit 1
119    fi
120    ;;
121*)  dirlist=
122    for top in /etc/periodic ${local_periodic}; do
123        [ -d $top/$arg ] && dirlist="$dirlist $top/$arg"
124    done
125    ;;
126esac
127
128{
129    empty=TRUE
130    processed=0
131    for dir in $dirlist; do
132        for file in $dir/*; do
133            if [ -x $file -a ! -d $file ]; then
134                output=TRUE
135                processed=$(($processed + 1))
136                $file </dev/null >$tmp_output 2>&1
137                rc=$?
138                if [ -s $tmp_output ]; then
139                    case $rc in
140                    0)  [ $success = NO ] && output=FALSE;;
141                    1)  [ $info = NO ] && output=FALSE;;
142                    2)  [ $badconfig = NO ] && output=FALSE;;
143                    esac
144                    [ $output = TRUE ] && { cat $tmp_output; empty=FALSE; }
145                fi
146                cp /dev/null $tmp_output
147            fi
148        done
149    done
150    if [ $empty = TRUE ]; then
151        if [ $empty_output = TRUE ]; then
152            [ $processed = 1 ] && plural= || plural=s
153            echo "No output from the $processed file$plural processed"
154        fi
155    else
156        echo ""
157        echo "-- End of $arg output --"
158    fi
159} | output_pipe $arg "$context"
160
161rm -f $tmp_output
162if [ $remove_periodic_anticongestion_file = "yes" ] ; then
163	rm -f $PERIODIC_ANTICONGESTION_FILE
164fi
165