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