Let’s just get this out of the way first: when someone says cron is not working, it almost always is, and they have just misunderstood something basic.
Usually that’s not understanding the environment that cron scripts run under or that the machine was physically shut off at the time cron was supposed to do something.
However, for the sake of completeness, we’ll run through everything you might check, including the rare case of cron itself not running at all.
You’ll find a “cron” script in /etc/init.d on most systems. I say “most” not because I’ve ever seen it anywhere else, but because it could be started elsewhere. For example, Mac OS X cron is handled by “launchd” (and is not used for anything by default). Ubuntu is going to be changing init soon (see Replacing init with Upstart), and Upstart will eventually replace cron entirely. I expect that soon enough “cron” will be replaced everywhere, if not by Upstart then by something very like it. But that’s still the future as I write this, so I’ll assume your cron starts from /etc/init.d. Therefore, the very first question is “Did that script run?”:
# ls -lut /etc/init.d/cron -rwxr--r-- 1 root root 4250 Dec 16 00:37 /etc/init.d/cron
The “ls -lut” shows the time the file was last “used” – executed or read. This system was booted just prior to that time, so this makes sense. Is cron still running?
# ps -el | grep cron 1 S 0 2862 1 0 76 0 - 454 2 ? 00:00:00 cron
OK so far. Next we’ll see if it has looked at its files:
# ls -lut /etc/crontab -rw-r--r-- 1 root root 255 Dec 16 00:37 /etc/crontab
Cron should read /etc/crontab when it starts up, so this matches. What /etc/crontab actually does depends on your system. For example, this is from an older RedHat system:
SHELL=/bin/bash PATH=/sbin:/bin:/usr/sbin:/usr/bin MAILTO=root HOME=/ # run-parts 11 * * * * root run-parts /etc/cron.hourly 02 4 * * * root run-parts /etc/cron.daily 22 4 * * 0 root run-parts /etc/cron.weekly 42 4 1 * * root run-parts /etc/cron.monthly
But a newer Suse system is entirely different:
SHELL=/bin/sh PATH=/usr/bin:/usr/sbin:/sbin:/bin:/usr/lib/news/bin MAILTO=root # # check scripts in cron.hourly, cron.daily, cron.weekly, and cron.monthly # -*/15 * * * * root test -x /usr/lib/cron/run-crons && /usr/lib/cron/run-crons >/dev/null 2>&1
The “run-crons” referred to there is a much more complex script that could easily take up an article by itself, so we’ll ignore the details of that and just say that it ends up running stuff in /etc/cron.{hourly,daily,weekly,monthly} (though the contents of those directories are much different than the RedHat system)
So the next place we’d look is /etc/cron.daily:
(Suse system) # ls -lut /etc/cron.daily total 36 -rwxr-xr-x 1 root root 2059 Dec 16 00:16 suse.de-backup-rpmdb -rwxr-xr-x 1 root root 566 Dec 16 00:16 suse.de-check-battery -rwxr-xr-x 1 root root 1320 Dec 16 00:16 suse.de-clean-tmp -rwxr-xr-x 1 root root 371 Dec 16 00:16 suse.de-cron-local -rwxr--r-- 1 root root 1196 Dec 16 00:16 suse-do_mandb -rwxr-xr-x 1 root root 1875 Dec 16 00:16 suse.de-backup-rc.config -rwxr-xr-x 1 root root 393 Dec 16 00:15 logrotate -rwxr--r-- 1 root root 948 Dec 16 00:15 suse-clean_catman -rwxr-xr-x 1 root root 2500 Dec 16 00:15 beagle-crawl-system (RedHat) # ls -lut /etc/cron.daily total 44 -rwxr-xr-x 1 root root 193 Dec 16 04:07 tmpwatch -rwxr-xr-x 1 root root 132 Dec 16 04:07 slocate.cron -rwxr-xr-x 1 root root 100 Dec 16 04:07 tetex.cron -rwxr-xr-x 1 root root 104 Dec 16 04:02 rpm -rwxr-xr-x 1 root root 418 Dec 16 04:02 makewhatis.cron -rwxr-xr-x 1 root root 1603 Dec 16 04:02 prelink -rwxr-xr-x 1 root root 180 Dec 16 04:02 logrotate -rwxr-xr-x 1 root root 800 Dec 16 04:02 certwatch -rwxr-xr-x 1 root root 739 Dec 16 04:02 kjunk -rwxr-xr-x 1 root root 135 Dec 16 04:02 00webalizer -rwxr-xr-x 1 root root 276 Dec 16 04:02 0anacron
These both make sense: the Suse run-crons script runs every fifteen minutes, so its first run is approximately fifteen minutes after startup. The RedHat /etc/crontab says to process cron.daily scripts at 4:02 in the morning, and that’s what it did. The “0anacron” script ran first, and “tmpwatch” ran last – and it took roughly five minutes to get from “0anacron” to “tmpwatch”.
By the way, if we were not powered on at 4:02, that “0anacron” would have made sure the rest of the scripts still ran; see “man anacron”. That wouldn’t happen immediately though, and that’s often a source of confusion.
Cron also looks for crontabs in /var/spool/cron. Again, the RedHat and Suse systems are slightly different; Suse looks in a “tabs” subdirectory, the older RedHat does not. But the concept is the same, and if you have any crontabs there, “ls -lut” should show that cron read them at startup.
So, if all this is true so far, why didn’t a particular job you added run? Let’s say I put “/root/bin/foo” in a crontab in /var/spool/cron. The foo script looks like this:
# cat /root/bin/foo date > /tmp/this
and the crontab is this:
# crontab -l # DO NOT EDIT THIS FILE - edit the master and reinstall. # (/tmp/crontab.XXXXDWuESu installed on Sat Dec 16 01:22:23 2006) # (Cron version V5.0 -- $Id: crontab.c,v 1.12 2004/01/23 18:56:42 vixie Exp $) SHELL=/bin/sh PATH=/usr/bin:/usr/sbin:/sbin:/bin:/usr/lib/news/bin MAILTO=root # # * * * * * /root/bin/foo
The “foo” file should show a new time stamp every minute:
# date;ls -lut /root/bin/foo Sat Dec 16 01:34:41 EST 2006 -rwxr-xr-x 1 root root 17 Dec 16 01:34 /root/bin/foo
If it does, but you aren’t getting the expected output, then your script is at fault: see Cron, Batch and At and UNIX Basics: JOB SCHEDULING. If it does not, then your crontab is probably wrong. The Suse man page warns:
In this version of cron, /etc/crontab must not be writable by any user other than root. No crontab files may be links, or linked to by any other file. No crontab files may be executable, or be writable by any user other than their owner.
Another common mistake is having incorrect fields:
# correct for /etc/crontab only * * * * * root /root/bin/foo
If you put that in a /var/spool/cron crontab, your command won’t get run because cron instead does what you told it: run a command called “root” and give it the arguments “/root/bin/foo”. The /var/log/messages file shows that happening:
Dec 16 01:49:01 suse /usr/sbin/cron[3764]: (root) CMD (root /root/bin/foo) Dec 16 01:50:01 suse /usr/sbin/cron[3768]: (root) CMD (root /root/bin/foo)
If we correct the crontab:
* * * * * /root/bin/foo
Cron notices the change and now everything works:
Dec 16 01:52:01 suse /usr/sbin/cron[2862]: (root) RELOAD (tabs/root) Dec 16 01:53:01 suse /usr/sbin/cron[3785]: (root) CMD (/root/bin/foo) Dec 16 01:54:01 suse /usr/sbin/cron[3788]: (root) CMD (/root/bin/foo)
Of course all of this began with cron starting. If cron fails to start, the “messages” log will probably give you a clue, as might running “/etc/init.d/crond start” manually. If that script never ran, was it supposed to?
# chkconfig --list | grep crond crond 0:off 1:off 2:on 3:on 4:on 5:on 6:off
If 3,4, and 5 did not say “on”, that would explain a non-starting crond.
*Originally published at APLawrence.com
A.P. Lawrence provides SCO Unix and Linux consulting services http://www.pcunix.com