The crontab command is used to manage cron jobs. The -l option displays the current list of jobs for the user. The following example runs the report mentioned in this chapter's introduction:
[dave@sawnee dave]$ crontab -l # DO NOT EDIT THIS FILE - edit the master and reinstall. # (/tmp/crontab.9889 installed on Fri Oct 15 09:42:06 2004) # (Cron version -- $Id: crontab.c,v 2.13 1994/01/17 03:20:37 vixie Exp $) 0 20 * * fri /home/dave/acct_prod_rpt.sh
The crontab command is the only user command that cron provides. There is a cron daemon to run jobs, but only crontab is run from the command line by users. It is used to create, edit, or display the crontab configuration file, which is called a crontab file for a user. Switches available for the crontab command are shown in Table 10-1.
We recommend using crontab -l rather than crontab -e to make crontab changes. For example:
$ crontab -l >crontab.out # Saves the crontab file $ cp crontab.out crontab.bkup # Create backup $ vi crontab.out # Make desired changes $ crontab crontab.out # Activate the changes $ crontab l # Verify changes
It took us five commands to modify the crontab file, but we do have a backup of the original as well as a copy of the new crontab. We could have just run crontab -e to edit the crontab file. When you run crontab -e for the first time, an editor starts with an empty document. Add the job command lines and save the file, and a crontab file is created for the user. If you would rather not use the default editor, set the EDITOR environment variable first. For example, run export EDITOR=vim;crontab -e to edit the crontab file with the vim editor.
The crontab enTRies can be set using monthly, weekly, daily, and hourly time definitions. The crontab(5) man page shows the format of the crontab lines. The time and date fields from the man page are shown in Table 10-2.
Follow the scheduling fields with the command to be run. The following crontab enTRy runs a backup process every day at 11:00 p.m.:
00 23 * * * /prod_serv/scripts/prod_backup_2
This entry runs a report at 6:15 a.m. on the first of every month:
15 6 1 * * /prod_serv/scripts/monthly_reports
This one runs a report every weekday at 2 p.m.:
0 14 * * 1-5 /home/ted/daily_rpt.sh
The crontab command validates the formatting of the command lines. Look at the output from crontab -e when the minute and hour fields are reversed:
[ted@sawnee ted]$ crontab -e 9 50 * * * /home/ted/sweep.sh ~ ~ ~ ~ no crontab for ted - using an empty one crontab: installing new crontab "/tmp/crontab.1279":0: bad hour errors in crontab file, can't install. Do you want to retry the same edit?
Consider inserting this snippet from the crontab(5) man page as a comment block in your crontab files so that it is easy to understand the format of the job command lines:
######################################################################## # field allowed values # ------ -------------- # minute 059 # hour 023 # day of month 131 # month 112 (or names, see below) # day of week 07 (0 or 7 is Sun, or use names) # min hour day month wkday ########################################################################
crontab does not validate the paths of commands, however, as you can see here:
[ted@sawnee ted]$ crontab -l # DO NOT EDIT THIS FILE - edit the master and reinstall. # (/tmp/crontab.26370 installed on Mon Aug 30 08:57:28 2004) # (Cron version -- $Id: crontab.c,v 2.13 1994/01/17 03:20:37 vixie Exp $) DBHOME="/prod_serv" 03 09 * * * /home/ted/sweeper.sh
crontab accepted the file, but look at the email Ted receives when it is executed by cron:
From: firstname.lastname@example.org (Cron Daemon) To: email@example.com Subject: Cron <ted@sawnee> /home/ted/sweeper.sh X-Cron-Env: <DBHOME=/prod_serv> X-Cron-Env: <SHELL=/bin/sh> X-Cron-Env: <HOME=/home/ted> X-Cron-Env: <PATH=/usr/bin:/bin> X-Cron-Env: <LOGNAME=ted> /bin/sh: line 1: /home/ted/sweeper.sh: No such file or directory
Environment variables can be added to the crontab file as well as comments. cron sets very few environment variables. The path is set to /usr/bin:/bin, and the shell is /bin/sh. If environment variables from the shell are needed, they must be set manually in the crontab file. For example, the following crontab sets DBHOME, DBINST, and the PATH variable:
# DO NOT EDIT THIS FILE - edit the master and reinstall. # (/tmp/crontab.1828 installed on Mon Sep 13 17:26:58 2004) # (Cron version -- $Id: crontab.c,v 2.13 1994/01/17 03:20:37 vixie Exp $) DBHOME=/prod_serv/scripts DBINST=prod PATH=/home/susan/bin:/usr/local/bin:/usr/bin:/usr/X11R6/bin:/bin:/usr/gam es:/opt/gnome/bin:/opt/kde3/bin: 30 17 * * * /prod_serv/scripts/prod_daily_report
Output from a cron job is mailed to the owner of the crontab. There is a cron environment variable MAILTO. If set, any cron email goes to the user specified by MAILTO. If MAILTO="", no email is sent by cron. For further information, see the crontab(5) man page.
cron and at are similar but not identical among Linux distributions. We show Red Hat and SUSE examples and provide techniques to understand the differences in other Linux distributions.
The crontab files are stored in the /var/spool/cron directory in Red Hat and /var/spool/cron/tabs in SUSE. The directory contains one file for every user with a cron schedule. The user name is the name of the crontab file. The crontab(1) man page has more detailed information.
The capability to use crontab can be restricted by the system administrator by creating an allow or deny file. In Red Hat, the files are /etc/cron.allow and /etc/cron. deny. In SUSE, the files are /var/spool/cron/allow and deny. The allow file is a list of users who can run the crontab command. The deny file is a list of users who cannot. Both files are just lists of user names. For example:
$ cat /etc/cron.allow dave root
If the allow file exists but does not contain dbuser, then the database administrator (DBA) sees the following message when trying to run crontab while logged in as dbuser:
$ crontab -e You (dbuser) are not allowed to use this program (crontab) See crontab(1) for more information
If the deny file exists and the allow file does not exist, all users can run crontab except those listed in the deny file. The allow file takes precedence. If both allow and deny exist, a user listed in both files can use crontab. To prevent any user from running crontab, including root, create an empty allow file. The at command uses /etc/at.allow and /etc/at.deny and follows the same rules as crontab.
The directory permissions on /var/spool/cron or /var/spool/cron/tabs limit access to only the root user to prevent users from manually creating or editing a crontab file. This forces users to use only the crontab command to change their crontab files. The system administrator should not manually edit these files either.
# ls -al /var/spool/cron total 16 drwx------- 2 root root 4096 Aug 11 10:54 . drwxr-xr-x 16 root root 4096 Nov 6 2003 .. -rw------- 1 root dave 254 Jul 31 12:53 dave -rw------- 1 root dbadmin 280 Aug 11 10:51 dbadmin
The crontab command has the setuid bit set so that non-root users can edit their own crontab files:
# ls -l /usr/bin/crontab -rwsr-xr-x 1 root root 110114 Feb 19 2003 /usr/bin/crontab
Try to lock down the crontab command by changing the permissions to 555, and you receive the following error when running it as a non-root user:
[dave@sawnee dave]$ crontab -e seteuid: Operation not permitted
Root has a special crontab file, /etc/crontab. The format is slightly different. The job command line has an additional field to specify what user cron should use to run the job. The default Red Hat /etc/crontab is:
SHELL=/bin/bash PATH=/sbin:/bin:/usr/sbin:/usr/bin MAILTO=root HOME=/ # run-parts 01 * * * * 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
The /etc/crontab supplied with Red Hat Linux makes use of the run-parts script. On a Linux installation, there are probably several processes that should be run daily such as backups and reports. There can be weekly or monthly jobs such as reports, software updates, system scans, and so on. This is the beauty of the run-parts script. The /etc/crontab shown previously runs the daily jobs at 4:02 a.m., the weekly jobs at 4:22 a.m. on Sunday, and the monthly jobs at 4:42 a.m. on the first day of the month.
The /usr/bin/run-parts script expects to be supplied with a directory path as an argument. The run-parts script executes all the scripts contained in that directory except for those ending in rpmsave, rpmorig, rpmnew, and swp scripts. There is no man page for run-parts, but it is a simple script to read and understand.
The functionality provided by /usr/bin/run-parts is very important. A software package that includes a cron job can be written to place a file in the appropriate /etc/cron.hourly, cron.daily, cron.weekly, or cron.monthly directory rather than trying to manipulate root's crontab file. This capability makes creating packages containing cron jobs manageable. You can see which packages delivered cron jobs to a Linux system with the command rpm -qa --filesbypkg grep '/etc/cron'.
The SUSE /etc/crontab file is similar to Red Hat's /etc/crontab:
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 59 * * * * root rm -f /var/spool/cron/lastrun/cron.hourly 14 4 * * * root rm -f /var/spool/cron/lastrun/cron.daily 29 4 * * 6 root rm -f /var/spool/cron/lastrun/cron.weekly 44 4 1 * * root rm -f /var/spool/cron/lastrun/cron.monthly
SUSE Linux supplies the run-crons script. It runs the jobs in the /etc/cron.* directories like run-parts does on Red Hat. cron on SUSE is configured to use /var/spool/cron/lastrun to keep track of the last time that the /etc/cron.* scripts were run. cron does not log the run-crons job execution.
Make sure only root can write to the /etc/cron.hourly, /etc/cron.daily, /etc/cron.weekly, and /etc/cron.monthly directories. Otherwise, any user can save a script in one of these directories and use cron to run his or her process with root privileges. Notice that the command line indicates that root should run these scripts. Even if the script in /etc/cron.daily is owned by a user, it is executed with root privileges.
# ls -ld /etc/cron.* drwxr-xr-x 2 root root 4096 Feb 19 2003 /etc/cron.d drwxr-xr-x 2 root root 4096 Aug 10 04:08 /etc/cron.daily drwxr-xr-x 2 root root 4096 Nov 6 2003 /etc/cron.hourly drwxr-xr-x 2 root root 4096 Nov 6 2003 /etc/cron.monthly drwxr-xr-x 2 root root 4096 Nov 6 2003 /etc/cron.weekly
You can confirm that the permissions of a package are correct with the rpm V cron_package_name command. You can confirm the permissions of a single file or directory with rpm V -f filename. troubleshooting using rpm is covered later in this chapter.
Here is a sample /etc/cron.daily:
# ll /etc/cron.daily total 36 -rwxr-xr-x 1 root root 135 Jan 25 2003 00webalizer -rwxr-xr-x 1 root root 276 Jan 24 2003 0anacron -rwxr-xr-x 1 root root 123 Jan 26 2003 inn-cron-expire -rwxr-xr-x 1 root root 51 Jan 24 2003 logrotate -rwxr-xr-x 1 root root 418 Feb 10 2003 makewhatis.cron -rwxr-xr-x 1 root root 135 May 14 15:59 rpm -rwxr-xr-x 1 root root 132 Jan 21 2004 slocate.cron -rwxr-xr-x 1 root root 164 May 17 09:18 sophos -rwxr-xr-x 1 root root 193 Feb 10 2003 tmpwatch
The cron daemon (/usr/sbin/cron for SUSE and /usr/sbin/crond for Red Hat) is responsible for running the cron jobs. Every minute, the cron daemon looks at the crontabs, loads new or modified crontabs into memory, and checks whether any jobs are scheduled to execute during that minute. The cron daemon is started during the startup scripts at runlevels 2, 3, 4, and 5.
#chkconfig --list crond crond 0:off 1:off 2:on 3:on 4:on 5:on 6:off
The startup script is /etc/init.d/crond in Red Hat and /etc/init.d/cron in SUSE. For more information on startup scripts, refer to Chapter 1, "System Boot, Startup, and Shutdown Issues."
A log entry is created when cron jobs are run, crontab commands are used, the cron daemon is started, and so on. cron uses the syslog daemon to log cron events. The syslog facility for cron messages is cron. See the syslogd(8) man page for an explanation of how syslog routes messages. The log file for cron is determined by /etc/syslog. conf. Red Hat has a log just for cron, /var/log/cron, to log cron messages. SUSE uses /var/log/messages. A Red Hat /etc/syslog.conf has the following entry to route cron messages to /var/log/cron:
# Log cron stuff cron.* /var/log/cron
With Red Hat, cron messages are not duplicated in /var/log/messages because of the cron.none on the following syslog.conf line:
It would be a simple matter to change SUSE systems to log cron messages to /var/log/cron. Here is a sample of the entries that are written to Red Hat's /var/log/cron file:
Aug 15 04:22:00 sawnee CROND: (root) CMD (run-parts /etc/cron.weekly) Aug 15 04:22:04 sawnee anacron: Updated timestamp for job 'cron.weekly' to 2004-08-15 Aug 15 05:01:00 sawnee CROND: (root) CMD (run-parts /etc/cron.hourly) Aug 15 06:01:00 sawnee CROND: (root) CMD (run-parts /etc/cron.hourly) Aug 15 07:01:00 sawnee CROND: (root) CMD (run-parts /etc/cron.hourly) Aug 15 08:01:00 sawnee CROND: (root) CMD (run-parts /etc/cron.hourly) Aug 15 09:01:00 sawnee CROND: (root) CMD (run-parts /etc/cron.hourly) Aug 15 10:01:00 sawnee CROND: (root) CMD (run-parts /etc/cron.hourly) Aug 15 11:01:00 sawnee CROND: (root) CMD (run-parts /etc/cron.hourly) Aug 15 12:01:00 sawnee CROND: (root) CMD (run-parts /etc/cron.hourly) Aug 15 13:01:00 sawnee CROND: (root) CMD (run-parts /etc/cron.hourly) Aug 15 14:01:00 sawnee CROND: (root) CMD (run-parts /etc/cron.hourly) Aug 15 14:35:46 sawnee crontab: (dave) LIST (dave) Aug 15 14:36:56 sawnee crontab: (dave) BEGIN EDIT (dave) Aug 15 14:37:03 sawnee crontab: (dave) REPLACE (dave) Aug 15 14:37:03 sawnee crontab: (dave) END EDIT (dave) Aug 15 14:37:09 sawnee crontab: (dave) BEGIN EDIT (dave) Aug 15 14:37:13 sawnee crontab: (dave) REPLACE (dave) Aug 15 14:37:13 sawnee crontab: (dave) END EDIT (dave) Aug 15 14:38:00 sawnee crond: (dave) RELOAD (cron/dave) Aug 15 14:38:00 sawnee CROND: (dave) CMD (/home/dave/daily_rpt)
The sample cron log shows cron activity on host sawnee. cron events are broken out by crond, crontab, and CROND (which shows jobs being started). The number between the  is the process ID. Everything that crontab performs is logged. Note that run-parts is listed as one job and is not broken down by each job in /etc/cron.hourly.
As we noted earlier, cron and at are similar but not identical across Linux distributions. To understand the differences, look closely at the man pages, see which packages are installed, and look for additional documentation supplied with the packages. Run rpm -qa to see what packages are installed. This list is from a Red Hat 9.0 system:
# rpm -qa|grep cron crontabs-1.10-5 vixie-cron-3.0.1-74 anacron-2.3-25
A typical SUSE 9.0 system might show:
# rpm -qa|grep cron cron-3.0.1-824
The package name doesn't indicate it, but this is vixie-cron too, which can be verified in the README supplied with the package.
Look at the files delivered with the packages by running rpm -q --filesbypkg. Take note of man pages, READMEs, and other documentation provided with each package. You can see what commands are available with the package as well as what documentation you can review. Here are the files delivered with Red Hat 9.0:
# rpm -q --filesbypkg vixie-cron-3.0.1-74 vixie-cron /etc/cron.d vixie-cron /etc/rc.d/init.d/crond vixie-cron /usr/bin/crontab vixie-cron /usr/sbin/crond vixie-cron /usr/share/man/man1/crontab.1.gz vixie-cron /usr/share/man/man5/crontab.5.gz vixie-cron /usr/share/man/man8/cron.8.gz vixie-cron /usr/share/man/man8/crond.8.gz vixie-cron /var/spool/cron # rpm -q --filesbypkg crontabs-1.10-5 crontabs /etc/cron.daily crontabs /etc/cron.hourly crontabs /etc/cron.monthly crontabs /etc/cron.weekly crontabs /etc/crontab crontabs /usr/bin/run-parts
SUSE 9.0 delivers the following files with the cron package:
# rpm -q --filesbypkg cron-3.0.1-824 cron /etc/crontab cron /etc/init.d/cron cron /usr/bin/crontab cron /usr/lib/cron cron /usr/lib/cron/run-crons cron /usr/sbin/cron cron /usr/sbin/rccron cron /usr/share/doc/packages/cron cron /usr/share/doc/packages/cron/CHANGES cron /usr/share/doc/packages/cron/CONVERSION cron /usr/share/doc/packages/cron/FEATURES cron /usr/share/doc/packages/cron/MAIL cron /usr/share/doc/packages/cron/MANIFEST cron /usr/share/doc/packages/cron/README cron /usr/share/doc/packages/cron/THANKS cron /usr/share/man/man1/crontab.1.gz cron /usr/share/man/man5/crontab.5.gz cron /usr/share/man/man8/cron.8.gz cron /var/spool/cron cron /var/spool/cron/deny cron /var/spool/cron/lastrun cron /var/spool/cron/tabs
Listing the files delivered in the package makes it easy to see the differences between distributions.
A nice graphical front-end utility is available for the crontab command. The kcron utility is part of KDE and is supplied with the optional kdeadmin package. The kcron utility is a simple, intuitive method for users to manage their cron jobs. The English version of the kcron handbook is available at http://docs.kde.org/en/3.1/kdeadmin/kcron/index.html. To start kcron, choose System Tools, Task Scheduler from the main KDE menu, and you will see the interface shown in Figure 10-1.
Figure 10-1. The kcron interface
No crontab knowledge is needed to schedule jobs when kcron is used. Users don't have to learn vi just to schedule a job. kcron inserts a header and a footer in the crontab file, so the system administrator knows it was saved from kcron. Here is an example:
$ crontab -l # DO NOT EDIT THIS FILE - edit the master and reinstall. # (/tmp/kde-susan/kcronzMmGJa.tmp installed on Tue Sep 7 09:47:40 2004) # (Cron version -- $Id: crontab.c,v 2.13 1994/01/17 03:20:37 vixie Exp $) # 5 4 * * * /home/susan/screening.sh # This file was written by KCron. Copyright (c) 1999, Gary Meyer # Although KCron supports most crontab formats, use care when editing. # Note: Lines beginning with "#\" indicates a disabled task.
There are a couple of wrinkles with kcron. kcron does not seem to be aware of the crontab allow and deny files, meaning users who are restricted from using the crontab command can still create cron tasks.
If kcron is run as root, the save function saves crontab files for every user on the system even if only root's jobs were modified. If the user already has a crontab file, kcron inserts its header and footer. If the user doesn't have a crontab file, kcron creates one with the normal crontab header plus the kcron header line. We don't recommend using kcron as root, but it is fine for other users.
To see the list of known bugs in kcron, visit http://bugs.kde.org/. We submitted new bug reports for those we mentioned here:
More information about KDE is available at http://www.kde.org/.