Cron
"Scheduled jobs" are run by the crond service, which is busybox crond started as crond -f -c /etc/crontabs. It runs as root, reads one file per user from /etc/crontabs and starts each job as the owner of the file. Its output is written to /var/log/crond/current; see services.
File format
The file is named after the user. A line has five time fields, which are the minute, the hour, the day of the month, the month and the day of the week, followed by the command. A line that begins with # is a comment. The command is run with /bin/sh, which is bash from the profile.
New and changed files are read without a restart, and a job runs at the next full minute. Only root may write to the directory, so a user file such as /etc/crontabs/dave must be written by root.
The jobs of the system
# cat /etc/crontabs/root
# minute hour day month weekday command
0 4 * * 0 fstrim -a
0 5 1 * * btrfs scrub start -B /
The first job runs on Sundays at 04:00 and informs every mounted filesystem that supports it which blocks are free. Run by hand, it prints:
# fstrim -a -v
/boot: 225 MiB (235945472 bytes) trimmed on /dev/vda1
/run/scram/top: 10.5 GiB (11252236288 bytes) trimmed on /dev/vda2
The second job runs on the first of each month at 05:00. -B keeps it in the foreground, so that it's report goes to the cron log. A scrub reads every block and compares it with its checksum:
# btrfs scrub start -B /
Starting scrub on devid 1
scrub done for af62787a-3caf-46b7-a78d-fca84d5ac031
Scrub started: Mon Nov 2 17:03:08 2026
Status: finished
Duration: 0:00:04
Total to scrub: 1.85GiB
Rate: 473.01MiB/s
Error summary: no errors found
On a single device, btrfs can repair a bad block only from a second copy, and a data block usually has none. The scrub then reports the error and the file that contains it. You may restore the file from a frame with scram restore, or from a backup. A frame is stored on the same disk, so it does not help if the frame contains the same bad block.
The hourly frame is made by the autoframe service.
What a job sees
A root job that writes its environment to a file:
* * * * * echo "$PATH|$SHELL|$HOME|$LOGNAME|$(id -un)|$(pwd)" > /tmp/ct/env
# cat /tmp/ct/env
/rod/bin:/rod/profile/bin:/rod/init/bin|/bin/sh|/root|root|root|/root
PATH is the value that the run script of crond sets, so fstrim and the busybox applets are found without a full path. The working directory is the home directory of the user.
Whatever a job prints, on standard output or on standard error, is added to the cron log with a timestamp. crond also logs each start.
# tail /var/log/crond/current
crond[222]: USER root pid 421 cmd exit 3
2026-11-02_16:59:00.72127 noisy output
2026-11-02_16:59:00.72136 to-stderr
2026-11-02_16:59:00.72151 /bin/sh: line 1: /tmp/ct/ann: Permission denied
The last line comes from a job in /etc/crontabs/dave that tried to write into a directory owned by root, which shows that the job ran as dave. The output of a job that prints on every run should be redirected, or the log fills up. Cron sends no mail.
Add a job
# echo '30 2 * * * rsync -a /home/ann/ /mnt/backup/ann/' >> /etc/crontabs/root
# cat /etc/crontabs/root
To list a file with the applet, you must give the directory, because the default /var/spool/cron/crontabs does not exist:
# /rod/init/bin/crontab -c /etc/crontabs -l
# minute hour day month weekday command
0 4 * * 0 fstrim -a
0 5 1 * * btrfs scrub start -B /
Remove or stop
To remove a job, delete the line or the file. sv down crond stops all jobs until the next boot, and rm /etc/service/crond stops them permanently.
Limits
- A job that was due while the machine was off does not run later.
- To run something at boot, use
/etc/rc.local, which runs before the services start.