summaryrefslogtreecommitdiff
blob: 305341ac31fa325e563501789f35a1111e1d4c81 (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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#!/bin/bash
#
# $Id$
#
# 12 Oct 2008; Thilo Bangert <bangert@gentoo.org> run-crons:
#     ignore emacs backup files (bug #237200)
#     include logging patch (bug #140869)
#
# 08 Mar 2005; Aaron Walker <ka0ttic@gentoo.org> run-crons:
#     Ignore the error messages from find caused by race conditions, since
#     we could care less about the error as long as the file has been removed.
#     See bug 8506.
#
# 06 May 2004; Aron Griffis <agriffis@gentoo.org> run-crons:
#     Make the locking actually work.  The old code was racy.
#     Thanks to Mathias Gumz in bug 45155 for some cleanups.
#
# 23 Jun 2002; Jon Nelson <jnelson@gentoo.org> run-crons:
#     fixed a race condition, where cron jobs and run-crons wanted to
#     delete touch files
#
# 20 Apr 2002; Thilo Bangert <bangert@gentoo.org> run-crons:
#     moved lastrun directory to /var/spool/cron/lastrun
#
# Author: Achim Gottinger <achim@gentoo.org>
#
# Mostly copied from SuSE
#
# 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}