A sane Anacron setup
Table of Contents
cron
is a program that, continuously sitting in the background, runs an executable at a set time of day, as set up in a configuration file crontab
.
anacron
is a program, that, continually called by cron
, runs an executable at a set day (week, month), as set up in a configuration file anacrontab
.
An (ana)cron
job is every such entry in the (ana)crontab
, that tells (ana)cron
which executable to run at which time/day.
Whereas cron
will skip a job if the computer was down at the set time, anacron
will only skip a job if the computer was down during the whole set day (week, month).
That is, anacron
seizes every chance it gets to run the executable.
Therefore, whereas cron
is made for servers, that are always on, anacron
it made for personal computers, such as desktops, laptops, tablets, that are sometimes turned off.
Here, we want to go one step further and make anacron
only run an executable if the computer is online and/or on power supply:
Instead of
- configuring
anacron
by listing the executables and their frequency (day, week or month) in a configuration file, - we place them in appropriate folders, depending on their frequency (daily, weekly or monthly) and condition under which to be run (none, online, on power supply, or both).
Aim
Run the executables in the folders
~
| .config/
| | anacron.daily/
| | | on/
| | | on_ac/
| | | on_line/
| | | on_line_ac/
| | anacron.weekly/
| | | on/
| | | on_ac/
| | | on_line/
| | | on_line_ac/
| | anacron.monthly/
| | | on/
| | | on_ac/
| | | on_line/
| | | on_line_ac/
daily (in anacron.daily
), weekly (in anacron.weekly
) and monthly (in anacron.monthly
) either
- unconditionally (in
on
), - when on power supply (= AC/DC), for example, updating a file index (in
on_ac
), - when online, for example, updating an online backup (in
on_line
), or - when on power supply and online, for example, updating software (in
on_line_ac
).
Prerequisites
Besides having installed cron
and anacron
, the following programs have to be marked executable and placed into $PATH
(note that we will add the folder ~/bin
to $PATH
, so that they all can be put inside ~/bin
.):
- The script run-parts.sh runs sequentially all executables in a folder.
- The script on_ac_power tests whether the computer runs on battery or AC/DC.
-
The command-line tool
nm-online
tests whether the computer is online. However, the computer may be online, but behind a paywall or certain ports are blocked, such as the port21
forSSH
-connections. Therefore a better bet for checking connectivity is the programnc
, though the check depends on a chosen server being up and running, saygithub.com
. Bothnm-online
andnc
are included in many Linux distributions. - The schedulers
chrt
andionice
run programs in the background, so that they will not hog the CPU respectively hard disc. Bothchrt
andionice
are included in many Linux distributions. - The auxiliary tool
cronic
to pass on (standard out and standard error) output only if the passed command (= cron job) fails (exits nonzero or crashes). For this error output (by default readable bymailx
) to be most useful, the shell script of every cron job should begin withset -o xtrace -o errtrace -o errexit -o nounset -o pipefail
to show debug output, exit on error or use of undeclared variable or pipe error. The tiny shell scriptcronic
is available at Chuck Houpt’s homepage (and one of its many variants, such aschronic
in Joey Hess’s moreutils, included in many Linux distributions).
Quick-Start
To readily set up the anacron
as shown next step by step, clone this repository and follow its quick-start guide.
Implementation
We assume the user name konfekt
, that is, the user’s home directory ~
is /home/konfekt
.
Setting up the Executables
Create the folder ~/.config/cron.hourly
.
Inside it, put the four executables
anacrontab_on.sh
anacrontab_on_ac.sh
anacrontab_on_line.sh
anacrontab_on_line_ac.sh
First, anacrontab_on_line_ac.sh
runs anacron only if the computer is online and on AC/DC, and reads
#!/bin/sh
# Do not run jobs when on battery power
(command -v on_ac_power >/dev/null /2> &1 && on_ac_power) || exit 0
# Do not run jobs when off-line
# (command -v nm-online >/dev/null /2> &1 && nm-online --timeout=10 --quiet) || exit 0
(nc -zw3 github.com 22) || exit 0
mkdir --parents "$XDG_DATA_HOME/anacron"
/usr/sbin/anacron -S "$XDG_DATA_HOME/anacron" -t "$XDG_CONFIG_HOME/anacrontab/on_line_ac" -s
Accordingly anacrontab_on_line.sh
runs anacron only if the computer is online, and reads
#!/bin/sh
# Do not run jobs when off-line
# (command -v nm-online >/dev/null /2> &1 && nm-online --timeout=10 --quiet) || exit 0
(nc -zw3 github.com 22) || exit 0
mkdir --parents "$XDG_DATA_HOME/anacron"
/usr/sbin/anacron -S "$XDG_DATA_HOME/anacron" -t "$XDG_CONFIG_HOME/anacrontab/on_line_ac" -s
and anacrontab_on_ac.sh
runs anacron only if the computer is on AC/DC, and reads
#!/bin/sh
# Do not run jobs when on battery power
(command -v on_ac_power >/dev/null /2> &1 && on_ac_power) || exit 0
mkdir --parents "$XDG_DATA_HOME/anacron"
/usr/sbin/anacron -S "$XDG_DATA_HOME/anacron" -t "$XDG_CONFIG_HOME/anacrontab/on_line_ac" -s
and anacrontab_on.sh
runs anacron unconditionally, and reads
#!/bin/sh
mkdir --parents "$XDG_DATA_HOME/anacron"
/usr/sbin/anacron -S "$XDG_DATA_HOME/anacron" -t "$XDG_CONFIG_HOME/anacrontab/on_line_ac" -s
Setting up Anacron
Create the folder ~/.config/anacrontab
.
Inside it, put the four anacron configuration files
~/.config/anacrontab/on
~/.config/anacrontab/on_ac
~/.config/anacrontab/on_line
~/.config/anacrontab/on_line_ac
First, ~/.config/anacrontab/on_line_ac
runs all due daily, weekly and monthly anacron jobs to be run when the computer is online and on AC/DC.
It reads
SHELL=/bin/bash
USER=konfekt
HOME=/home/konfekt
BASH_ENV=/home/konfekt/.bash_profile
XDG_CONFIG_HOME=/home/konfekt/.config
XDG_CACHE_HOME=/home/konfekt/.cache
XDG_DATA_HOME=/home/konfekt/.local/share
PATH=/home/konfekt/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
# RANDOM_DELAY=5
# START_HOURS_RANGE=10-16
# period delay job-identifier command
1 0 daily.on_line_ac cronic chrt --idle 0 ionice -c2 -n7 run-parts.sh -v $XDG_CONFIG_HOME/anacron.daily/on_line_ac
7 5 weekly.on_line_ac cronic chrt --idle 0 ionice -c2 -n7 run-parts.sh -v $XDG_CONFIG_HOME/anacron.weekly/on_line_ac
@monthly 10 monthly.on_line_ac cronic chrt --idle 0 ionice -c2 -n7 run-parts.sh -v $XDG_CONFIG_HOME/anacron.monthly/on_line_ac
Accordingly,
~/.config/anacrontab/on_line
runs all due daily, weekly and monthly anacron jobs to be run when the computer is online.~/.config/anacrontab/on_ac
runs all due daily, weekly and monthly anacron jobs to be run when the computer is on AC/DC.~/.config/anacrontab/on
runs all due daily, weekly and monthly anacron jobs to be run unconditionally.
They read accordingly, that is, on_line_ac
is replaced everywhere by on_line
, on_ac
, on
respectively.
Setting up Cron
Add a file
~/.config/crontab
with content
SHELL=/bin/bash
USER=konfekt
HOME=/home/konfekt
BASH_ENV=/home/konfekt/.bash_profile
XDG_CONFIG_HOME=/home/konfekt/.config
XDG_CACHE_HOME=/home/konfekt/.cache
XDG_DATA_HOME=/home/konfekt/.local/share
PATH=/home/konfekt/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
# RANDOM_DELAY=5
# START_HOURS_RANGE=10-16
# period command
* * * * * * cronic chrt --idle 0 ionice -c2 -n7 run-parts.sh -v $XDG_CONFIG_HOME/cron.hourly
On the terminal, run
crontab ~/.config/crontab
This way, cron
checks, via anacron
, every minute for all due (daily, weekly and monthly) jobs to be run unconditionally or when the computer is either online, on AC/DC, or online and on AC/DC.
Extras
If you run jobs that need an SSH connection, for example an online backup over rsync, then the program keychain
may interest you:
A shell script that will cache your passphrase, so that cron
jobs can access it.
To set it up, initialize it on start-up of the user’s session by
eval "$(keychain --agents ssh --quiet --eval ~/.ssh/id_rsa)"
(for example, KDE
has the folder ~/.config/autostart-scripts
for this purpose) and call
[ -z "$HOSTNAME" ] && HOSTNAME="$(uname -n)"
[ -f ~/.keychain/"$HOSTNAME"-sh ] && . ~/.keychain/"$HOSTNAME"-sh
before the cron
job, for example one using rsync
to back up files to a distant SSH
server.
Example
For an example anacron job, here is a sample shell script which backs up all the files inside the home directory that are listed in files
, except those listed in exclude
, to a server;
see this repository for an expanded version and full instructions:
#!/bin/bash
set -o xtrace -o errtrace -o errexit -o nounset -o pipefail
# set up keychain to pass passphrase to ssh in cron jobs
[ -z "$HOSTNAME" ] && HOSTNAME="$(uname -n)"
[ -f ~/.keychain/"$HOSTNAME"-sh ] && . ~/.keychain/"$HOSTNAME"-sh
# CONFIG
FROM_FOLDER=$HOME
TO_FOLDER="$USER@rsync.server.com:/users/$USER"
FILES_FILE=$XDG_CONFIG_HOME/backup/files
EXCLUDE_FILE=$XDG_CONFIG_HOME/backup/exclude
LOG_FILE=$XDG_CACHE_HOME/backup/cloud/log
# because --files-from disables --recursive in --archive it must enable explicitly
RSYNC_BKP_ARGS="--recursive --archive --hard-links --ignore-errors --modify-window=1 --delete --compress --partial --human-readable --info=progress2 "
SSH_ARGS="-v -P"
# BACKUP Local -> Server:
LOG_FILE_DIR=$(dirname "${LOG_FILE}")
mkdir --parents "$LOG_FILE_DIR"
rsync $RSYNC_BKP_ARGS --rsh="ssh $SSH_ARGS" --log-file="$LOG_FILE" --files-from="$FILES_FILE" --exclude-from="$EXCLUDE_FILE" "$FROM_FOLDER" "$TO_FOLDER"
To run it daily as soon as the computer is online, put it into the folder :
~
| .config/
| | anacron.daily/
| | | on_line/