Cron Isn’t Working?

    December 19, 2006

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:


# 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:

# 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
-rwxr-xr-x 1 root root  566 Dec 16 00:16
-rwxr-xr-x 1 root root 1320 Dec 16 00:16
-rwxr-xr-x 1 root root  371 Dec 16 00:16
-rwxr--r-- 1 root root 1196 Dec 16 00:16 suse-do_mandb
-rwxr-xr-x 1 root root 1875 Dec 16 00:16
-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

# 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 $)
* * * * *    /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

A.P. Lawrence provides SCO Unix and Linux consulting services