cron

This service runs every minute, looks for jobs stored in its crontab files, and checks if it must be run in the current minute. If anything is found, it is executed; otherwise, cron will be rerun the next minute and so forth. Once the job has been executed, the output of the commands issued is mailed to the owner of the crontab or to the user specified in the MAILTO environment variable in the crontab, if any. Notably, every minute, cron not only reads the crontab files but also checks the modification file of its spool directory or if /etc/crontab has changed and, if so, it will analyze the modification time of all the crontab files and reload them to get any changes made to the job's specification. So, we do not worry about restarting cron if we changed anything. It will manage the changes by itself, but cron is also able to cope with clock changes: if the time has been changed by less than 3 hours backward, the already run jobs will not be rerun. Then, if the time shifts forward to less than 3 hours, the skipped jobs will be run as soon as the clock will hit the new time. This affects only those jobs that have been set with a specific execution time. So, those tasks, using keywords such as @hourly, and those who have the wildcard * in the hour or minute specification for the runtime will not be affected. If the clock is shifted by more than 3 hours, all the jobs will be run following the new time set.

Each distribution can implement a different kind of cron facility and have the configuration files in a slightly different location. If unsure, man cron and man crontab will show what is supported by the service and which locations the relevant files are kept at.

Then, there is one more surprise: there is no cron. Well, we can chuckle because actually we call cron the daemon part of the service, but what is actually used to provide that service can change according to the distribution that we are using. There are different schedulers available for our purposes. Here are some of them:

  • vixie-cron: This is the father of all the modern crons: the venerable cron from Paul Vixie, coded in 1987.
  • bcron: It is a cron replacement focused to provide a secure service.
  • cronie: It is a Fedora-based form of vixie-cron.
  • dcron: Dillon's cron is a stripped-down version of a cron; it is secure and simple.
  • fcron: It could be a nice replacement to the classic vixie cron and it is designed for a system that is not continuously running. So, it has some interesting features like the ability to schedule jobs at startup.

These are just some cron implementations, and we are confident that somewhere there are some more, a fork or something original that addresses some precise requirement. For the purpose of this book, we will refer to vixie-cron as installed on a Debian system.

We do not have many options to interact with cron, but let's see what it supports:

  • -f: It does not daemonize and will stay in the foreground. It is useful to debug what is going on with it.
  • -l: It enables the Linux Standard Base compliant script names for files inside /etc/cron.d (http://lanana.org/lsbreg/cron/index.html). Only the files inside this directory will be affected; those under /etc/cron.hourly, /etc/cron.daily, /etc/cron/weekly , and /etc/cron/monthly will not be affected.
  • -n: Includes the Fully Qualified Domain Name in the subject of the email sent after a job has been run; otherwise, only the hostname will be used.
  • -l: Sets the log level. Errors are always logged; but, different levels unlock additional information that is recorded using the system log facility, usually syslog under the cron facility. The single level values can be summed and the resulting value will enable the collection of more than one kind of information:
    • 1: It logs the start of all cron jobs
    • 2: It logs the end of all cron jobs
    • 4: It logs the end of all failed jobs, so all jobs with exit status are different from 0
    • 8: It logs the process identification number of all cron jobs
    • 15: It will collect all the information (8+4+2+1) grabbed in the preceding levels
    • The default log level is 1, but we can specify 0 if we want to disable logging at all

There are a couple of things to keep in mind when using cron:

The cron daemons set up a number of environment variables when dealing with jobs, such as follows:

  • SHELL: Set to /bin/sh
  • LOGNAME: Set from the content of /etc/passwd line related to the crontab owner
  • HOME: Set from the content of /etc/passwd line related to the crontab owner
  • PATH: Set to /usr/bin:/bin

If any other environment variables must be set by the user, the easiest way to accomplish this is to set them into crontab definitions for vixie-cron; other implementations such as cronie do not allow this, so you can resort to prepend them on the crontab line entry before calling the script or program belonging to the job:

# m h dom mon dow command
export HTTP_PROXY=http://192.168.0.1:8080; env >> /var/log/proxy

If we take a look at the syslog file, we can see the crontab being installed:

Apr 28 16:57:35 moveaway crontab[27929]: (root) REPLACE (root)
Apr 28 16:57:35 moveaway crontab[27929]: (root) END EDIT (root)
Apr 28 16:58:01 moveaway cron[607]: (root) RELOAD (crontabs/root)
Apr 28 16:58:01 moveaway CRON[27977]: (root) CMD (export HTTP_PROXY=http://192.168.0.1:8080; env >> /var/log/proxy)

So, if we did not make any mistakes, we should see the /var/log/proxy file being created and updated with the content of the environment the command named env has been invoked from:

root:# cat /var/log/proxy
LANGUAGE=en_GB:en
HOME=/root
LOGNAME=root
PATH=/usr/bin:/bin
LANG=en_GB.UTF-8
SHELL=/bin/sh
PWD=/root
HTTP_PROXY=http://192.168.0.1:8080
LANGUAGE=en_GB:en
HOME=/root
LOGNAME=root
PATH=/usr/bin:/bin
LANG=en_GB.UTF-8
SHELL=/bin/sh
PWD=/root

The HTTP_PROXY environment variable is set for the job, and we will see more and more of these lines growing into the file, so we will see in a while how to remove this crontab or the single job.

One environment is read instead of being set and this is called MAILTO. If it is defined, the output of the job will be sent to the name specified; if it is empty, no mail will be sent. MAILTO can also be set to send emails to a list of users separated by commas. If not, MAILTO is set so the outcome of a job will be sent to the owner of the crontab.

Some of the cron implementations support PAM, so if they happen to set up a new cron job for a user, and we face some authorization issues we have three files to look at:

  • /etc/cron.allow
  • /etc/cron.deny
  • /etc/pam.d/cron

/etc/at.allow is the first file to be read if it exists. If any account names are found in it, these will be the only accounts to be allowed to submit jobs using the crontab utility. If /etc/cron.allow does not exist, then /etc/cron.deny is parsed and every account name found in it will be forbidden to send jobs to cron. If the file exists, but it is empty, only the superuser or those listed in /etc/cron.allow will be able to submit jobs. If neither /etc/cron.allow nor /etc/cron.deny are available, any user will be allowed to submit jobs to cron.

We talked about the crontab utility. What is this? It is actually the program that lets us write the crontab files, which instruct cron on which jobs to execute, when, and on behalf of whom. Indeed, each user can have his/her own crontab, which is stored in /var/spool/cron/crontabs; but we should not edit them manually. We must resort to the crontab utility, which will let us edit and install the crontab file in the correct way. So, how do we use crontab? Let's say we already have a file with our job specifications, and we will see later on how to write it; the only command we have to issue is here:

crontab filename

This will install a new crontab for the current user from the file specified, but we can also manually enter our job details by typing them on the command line with crontab.

As we can imply from the preceding command lines, if crontab is called without passing a username, it will work on the cron jobs of the user who invoked it. So, if we want to list or modify a user crontab, given that we have sufficient privileges, this is being superuser, we can issue the following:

root:# crontab -u zarrelli -l
no crontab for zarrelli

If we want to edit and install a new cron job, we can use the following syntax:

crontab -u user -e

Look at the following example:

root:# crontab -e -u zarrelli
no crontab for zarrelli - using an empty one

Select an editor. To change later, run 'select-editor'.
1. /bin/nano <---- easiest
2. /usr/bin/mcedit
3. /usr/bin/vim.gtk
4. /usr/bin/vim.tiny

Choose 1-4 [1]:

Being the first time the crontab utility is invoked by the user, it could ask for the default editor to be used; if not, the visual or editor environment variable are instanced. If nothing is set, /usr/bin/editor will be used.

In the example shown, the Debian distribution triggered the configuration of /etc/alternatives, which provides the link to the default editor.

Once into the editor, each cron job must be specified on a line on its own, such as * * * * * ps.

We will see later what this sequence means; as of now, we just exit the editor and save the content:

crontab: installing new crontab

Once done, crontab informs us that the crontab has been installed, and it could be interesting to have it displayed on the stdout:

crontab -u zarrelli -l

As shown in the following example:

root:# crontab -u zarrelli -l
# Edit this file to introduce tasks to be run by cron.
#
# Each task to run has to be defined through a single line
# indicating with different fields when the task will be run
# and what command to run for the task
#
# To define the time you can provide concrete values for
# minute (m), hour (h), day of month (dom), month (mon),
# and day of week (dow) or use '*' in these fields (for 'any').#
# Notice that tasks will be started based on the cron's system
# daemon's notion of time and timezones.
#
# Output of the crontab jobs (including errors) is sent through
# email to the user the crontab file belongs to (unless redirected).
#
# For example, you can run a backup of all your user accounts
# at 5 a.m every week with:
# 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/
#
# For more information see the manual pages of crontab(5) and cron(8)
#
# m h dom mon dow command
* * * * * ps

If we want to get rid of the crontab, there is a handy option that will remove it completely:

crontab -u zarrelli -r 

But be careful-if you want to get rid of some jobs but retain the others, the best solution is to edit the crontab again, delete the lines related to the jobs we do not want, and then save it. The new crontab with the remaining jobs will be installed and will completely replace the old one.

If we are not confident in deleting a crontab, we could set an alias that points to crontab -i -r , which works with -r and prompts the user for a confirmation before deleting the crontab:

root:# crontab -ir
crontab: really delete root's crontab? (y/n)

We will not touch some distribution specific configurations, such as the support for /etc/cron.hourly, /etc/cron.daily, /etc/cron.weekly, and /etc/cron.monthly provided through the /etc/crontab file, since otherwise, we would end up drilling down all the bits and configurations of all possible cron implementations in all the main distributions.

What interests us here is to understand the underlying basic notions on how to deal with cron so that whatever different implementation we find, we will be able to deal with it and look into its idiosyncrasies. There are a couple of interesting things left to see now: one is the syntax we will use to define a job and the other is a quick glance to anacron: a utility we have often heard of.

Even if a crontab file can look a bit cryptic at first glance, it is not so difficult to understand what the sequence of the characters mean: the first field is for the minute when the job must be executed; the second for the hour; the third for the day of the month; the fourth for the month; the fifth for the day of the week; and the sixth for the command to execute. So, the crontab we just created a few lines ago can be read as laid out in the following table:

Fields

*
*
*
*
*
ps

Minutes

X

Hours

X

Day of the month

X

Month

X

Day of the week

X

Command

X
What the fields mean

Okay, now we know what these fields mean, but what are those asterisks and what can we write into each field? Another table will make all this easier to understand:

Field

Allowed values

Metacharacters

Minutes

0-59

* , - /

Hours

0-23

* , - /

Day of the month

1-31

* , - /

Month

1-12 or Jan-Dec

* , - /

Day of the week

0-7 or Sun-Sat

* , - /

Which values can be used inside each field

We are almost there. Just a few things more to learn and we will be able to fully understand a crontab line; but first, what are those metacharacters and what do they mean?

Keep in mind that Sunday can be specified both as 0 and 7 in the day of the week field.
  • *: This stands for every and can be used in all the fields. So, inside a minute field it will tell cron to run the job every minute, inside the hour every hour, and so forth.
  • ,: The comma defines a list. For instance, 1, 5, and 15 in the day of the month will instruct cron to run the job on the first, the fifth, and on the fifteenth day.
  • -: The hyphen defines an inclusive range. For instance, 4-7 in the day of the week field will force cron to execute the job from Thursday to Sunday.
  • /: The forward slash is used to define steps, and it can be used with ranges so that it will skip the value of the number through the range. So, 1-59/2 in the minute field will give us all the odd minutes in one hour, since it will start from one and wait 2 minutes before the next execution; this can be specified as a list as well: 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, and 59.

As we can see, steps can be quite handy. The forward slash can also be combined with the asterisk: */2 in the hours field means every 2 hours, in the month field would be every two months, and so forth.

Some implementations of cron support an extra field for the year, with values from 1970 to 2099 supporting the * and - metacharacters.

There is one set of special markers we have to see before analyzing a crontab line. We can define some recurrences using special keywords prefixed by an @, as shown in the next table:

Keyword

Execution

The same as

@yearly

Once a year, at midnight of Jan 1st

0 0 1 1 *

@annually

Equivalent to @yearly

0 0 1 1 *

@montly

Once a month, at midnight of the first day of the month

0 0 1 * *

@weekly

Once a week, at midnight between Sat and Sun

0 0 * * 0

@daily

Once a day, at midnight

0 0 * * *

@midnight

Equivalent to @daily

0 0 * * *

@hourly

Once an hour, at the tick of the hour

0 * * * *

@reboot

At cron daemon startup

nothing

Keywords with special meanings

This replaces all the first five fields altogether and can become handy if you do not have special constraints about hours or days, but you want something being executed in a generic time frame.

Before proceeding there are a few things to be aware of:

  • Each line specifying a cron job must be ended by a newline.
  • The percent sign % used in the command field is turned into a newline character, and all the data after the first % is sent to the stdin of the command to be executed. The percentage can be escaped by doubling it %% so that it will not be interpreted as a newline.
  • Inside the crontab file, blank lines, leading spaces, and tabs are not parsed. If a line starts with # , it will be treated as a comment and not parsed.
  • In the crontab file, we can either set some variables or define a cron job; nothing else is allowed.
  • A variable can be assigned as VARIABLE_NAME = value.
  • Spaces surrounding the equals sign are optional.
  • No expansions or substitutions are performed on variables. So, VARIABLE_NAME=$LOGNAME will not instance VARIABLE_NAME since the value string is not even parsed for expansion or substitution.
  • An empty value must be surrounded by quotes, and if the values contain blanks, quotes are required to preserve them.
  • No per user time zones are available. The default system time zone is used instead.

So, with this in mind, let's have a look at a cron job specification:

35

1-24/4

*

*

Mon,Thu

/opt/scripts/script.sh

minutes

hours

Day of the month

month

Day of the week

command

Execute at minute 35 past every 4th hour, from 1 through 24 on Monday and Thursday


A useful grid to make sense of a job specification line

Caged in a table, the job specification is easier to understand and becomes much easier if we use some keywords:

@weekly /opt/scripts/script.sh

That's all, the definition was shortened to two simple fields. But fiddling with the fields can lead us to something tricky:

1-59/2 * * * * /opt/scripts/script.sh

What does this do? Simply executes the script every odd minute, not even, odd.

But what if the system is rebooted or is a desktop, which can stay off for days or weeks? Using cron would lead to some jobs not being executed at all or just skipped, and this is not a desirable behavior. This is where anacron comes in handy: it will run a job even if we switch on the desktop after the scheduled time. How can it be? Simply, this utility keeps a log of all the jobs and when they were executed using a series of timestamped files held in /var/spool/anacron.

Let's proceed in an orderly manner and have a look at the file which drives anacron, whose name is /etc/anacron.

To better understand it, we must have a peek into its content:

root:# cat /etc/anacrontab 
# /etc/anacrontab: configuration file for anacron
# See anacron(8) and anacrontab(5) for details.
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
HOME=/root
LOGNAME=root
# These replace cron's entries
1 5 cron.daily run-parts --report /etc/cron.daily
7 10 cron.weekly run-parts --report /etc/cron.weekly
@monthly 15 cron.monthly run-parts --report /etc/cron.monthly

As we can notice, we can have variables with crontab, but the format of a job definition is slightly different and can have one of the following syntaxes:

period delay job_name command
@period_identifier delay job_name command
  • period: Expressed in days specifying the frequency the job is run at. For instance, 10 is every 10 days.
  • @period: Allows to use some keywords to specify the frequency: @daily, @weekly, and @monthly for once per day, week, and month.
  • delay: Expressed in minutes, defines the delay after which anacron executes a scheduled job when the threshold is hit.
  • job-name: We can give a job whatever identifier we want, but no slashes are allowed. It will be used by anacron as the name for the timestamp file of the job.
  • command: Can be whatever command.

As we can see, the standard anacron file in the example will run the run-parts utility along with the directory argument. And, the exact job of run-parts is to run the scripts it finds in the directory it is being given as arguments. So, interpreting the anacron lines should be easy now, should't it? Editing it is easy as well: we can do it by hand, no special utilities are required or available.

The way anacron works is amazingly straightforward and effective: it checks each job specified in the anacrontab file and sees whether it has been executed in the last x specified in the period field. If it has not been run and the threshold is hit, it will execute the job after waiting for the delay set in the second field of the job definition. Once the task has been executed, anacron records the date in a timestamp file related to the job; so next time, it will just have to read it to know what to do:

root:# cat /var/spool/anacron/cron.weekly
20170424

Once all the jobs scheduled have been executed, anacron exits; but, we also send anacron a SIGUSR1 signal to kill it: it will wait for any running jobs to finish and then will cleanly exit.

But there is also another task performed by anacron once a job has been executed: if any output is created by the job, it is mailed to the user running anacron, usually root, or the one whose email is specified in the MAILTO environment variable from anacrontab. If a LOGNAME variable is instanced, it will be used as the sender of the email.

Finally, let's see which options are supported by anacron:

  • -f: Forces anacron to execute all the defined jobs, regardless of the timestamps.
  • -u: Just updates the timestamps of the jobs to the current date without executing them.
  • -s: Serializes the execution of the jobs; meaning that, before starting the next job, anacron will wait for the current one to be completed.
  • -n: Ignores the delay specification for each job and runs them as they hit the threshold. Implies the -s option.
  • -d: Usually anacron goes in background, but this option will force it to the foreground. It is useful for debugging, since anacron will sendn the runtime messages to the stderr and to syslog. The output emails will be sent to the recipient anyway.
  • -q: Does not print messages to the stderr and implies the -d option.
  • -t file: Reads the jobs, definitions from the specified file instead of the default anacrontab.
  • -T: Tests the validity of anacrontab. If there are any errors, they will be shown and anacron will return the value of 1; otherwise, it will return 0.
  • -S directory: Uses the specified directory to store the timestamp files.
  • -V: Prints anacron version and exits.
  • -h: Prints the usage help and exits.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.226.4.239