cron(8): schedule interval jobs that get loaded during execution
Jobs using the @<second> syntax currently only get executed if they exist when cron is started. The simplest reproducer of this is: echo '@20 root echo "Hello!"' >> /etc/cron.d/myjob myjob will get loaded at the next second==0, but this echo job will not run until cron restarts. These jobs are normally handled in run_reboot_jobs(), which sets e->lastexit of INTERVAL jobs to the startup time so they run 'n' seconds later. Fix this by special-casing TargetTime > 0 in the database load. Preexisting jobs will be handled at startup during run_reboot_jobs as normal, but if we've reloaded a database during runtime we'll hit this case and set e->lastexit to the current time when we process it. They will then run every 'n' seconds from that point, and a full restart of cron is no longer required to make these jobs work. Reported by: Juraj Lutter (otis_sk.freebsd.org) Reviewed by: allanjude, bapt, bjk (earlier version), Juraj Lutter MFC after: 3 days Differential Revision: https://reviews.freebsd.org/D19924
This commit is contained in:
parent
93096fecb6
commit
bd6174f74c
@ -259,6 +259,8 @@ process_crontab(uname, fname, tabname, statbuf, new_db, old_db)
|
||||
struct passwd *pw = NULL;
|
||||
int crontab_fd = OK - 1;
|
||||
user *u;
|
||||
entry *e;
|
||||
time_t now;
|
||||
|
||||
if (strcmp(fname, SYS_NAME) && !(pw = getpwnam(uname))) {
|
||||
/* file doesn't have a user in passwd file.
|
||||
@ -307,6 +309,21 @@ process_crontab(uname, fname, tabname, statbuf, new_db, old_db)
|
||||
u = load_user(crontab_fd, pw, fname);
|
||||
if (u != NULL) {
|
||||
u->mtime = statbuf->st_mtime;
|
||||
/*
|
||||
* TargetTime == 0 when we're initially populating the database,
|
||||
* and TargetTime > 0 any time after that (i.e. we're reloading
|
||||
* cron.d/ files because they've been created/modified). In the
|
||||
* latter case, we should check for any interval jobs and run
|
||||
* them 'n' seconds from the time the job was loaded/reloaded.
|
||||
* Otherwise, they will not be run until cron is restarted.
|
||||
*/
|
||||
if (TargetTime != 0) {
|
||||
now = time(NULL);
|
||||
for (e = u->crontab; e != NULL; e = e->next) {
|
||||
if ((e->flags & INTERVAL) != 0)
|
||||
e->lastexit = now;
|
||||
}
|
||||
}
|
||||
link_user(new_db, u);
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd April 15, 2019
|
||||
.Dd April 19, 2019
|
||||
.Dt CRONTAB 5
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -245,12 +245,14 @@ string meaning
|
||||
The
|
||||
.Sq @
|
||||
symbol followed by a numeric value has a special notion of running
|
||||
a job that much seconds after completion of previous invocation of
|
||||
a job that many seconds after completion of the previous invocation of
|
||||
the job.
|
||||
Unlike regular syntax, it guarantees not to overlap two or more
|
||||
invocations of the same job.
|
||||
The first run is scheduled specified amount of seconds after cron
|
||||
has started.
|
||||
invocations of the same job during normal cron execution.
|
||||
Note, however, that overlap may occur if the job is running when the file
|
||||
containing the job is modified and subsequently reloaded.
|
||||
The first run is scheduled for the specified number of seconds after cron
|
||||
is started or the crontab entry is reloaded.
|
||||
.Sh EXAMPLE CRON FILE
|
||||
.Bd -literal
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user