summaryrefslogtreecommitdiff
blob: 18a6199eb4b415f0ca2da4f970d0926cad7c47d0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#!/bin/bash
# Copyright 1999-2015 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
#
# this script looks into /etc/cron.[hourly|daily|weekly|monthly]
# for scripts to be executed. The info about last run is stored in
# /var/spool/cron/lastrun

LOCKDIR=/var/spool/cron/lastrun
LOCKFILE=${LOCKDIR}/lock

# Usage: log <level> <args to logger>
# Log a message via syslog.
log() {
	local level=$1
	shift
	logger -i -p "cron.${level}" -t run-crons "$@"
}

mkdir -p ${LOCKDIR}

# Make sure we're not running multiple instances at once.
# Try twice to lock, otherwise give up.
for ((i = 0; i < 2; i = i + 1)); do
	ln -sn $$ ${LOCKFILE} 2>/dev/null && break

	# lock failed, check for a running process.
	# handle both old- and new-style locking.
	cronpid=$(readlink ${LOCKFILE} 2>/dev/null) ||
	cronpid=$(cat ${LOCKFILE} 2>/dev/null) ||
	continue	# lockfile disappeared? try again

	# better than kill -0 because we can verify that it's really
	# another run-crons process
	if [[ $(</proc/${cronpid}/cmdline) == $(</proc/$$/cmdline) ]] 2>/dev/null; then
		# whoa, another process is really running
		exit 0
	else
		rm -f ${LOCKFILE}
	fi
done

# Check to make sure locking was successful
if [[ ! -L ${LOCKFILE} ]]; then
	echo "Can't create or read existing ${LOCKFILE}, giving up"
	exit 1
fi

# Set a trap to remove the lockfile when we're finished
trap "rm -f ${LOCKFILE}" 0 1 2 3 15


EXIT_STATUS=0
for BASE in hourly daily weekly monthly ; do
	CRONDIR=/etc/cron.${BASE}

	test -d $CRONDIR || continue

	if [ -e ${LOCKDIR}/cron.$BASE ] ; then
		case $BASE in
		hourly)
			#>= 1 hour, 5 min -=> +65 min
			TIME="-cmin +65" ;;
		daily)
			#>= 1 day, 5 min -=> +1445 min
			TIME="-cmin +1445"  ;;
		weekly)
			#>= 1 week, 5 min -=> +10085 min
			TIME="-cmin +10085"  ;;
		monthly)
			#>= 31 days, 5 min -=> +44645 min
			TIME="-cmin +44645" ;;
		esac

		find ${LOCKDIR} -name cron.$BASE $TIME -exec rm {} \; &>/dev/null || true
	fi

	# if there is no touch file, make one then run the scripts
	if [ ! -e ${LOCKDIR}/cron.$BASE ] ; then
		touch ${LOCKDIR}/cron.$BASE

		set +e
		for SCRIPT in $CRONDIR/* ; do
			if [[ -x $SCRIPT && ! -d $SCRIPT ]]; then
				# Filter out files people do not expect to be executed.
				case ${SCRIPT} in
				.*|*~) continue ;;
				esac

				log info "($(whoami)) CMD (${SCRIPT})"
				$SCRIPT
				ret=$?
				if [ ${ret} -ne 0 ] ; then
					log err "CMD (${SCRIPT}) failed with exit status ${ret}"
					EXIT_STATUS=1
				fi
			fi
		done
	fi
done

# Clean out bogus cron.$BASE files with future times
touch ${LOCKDIR}
find ${LOCKDIR} -newer ${LOCKDIR} -exec /bin/rm -f {} \; &>/dev/null || true

exit ${EXIT_STATUS}