aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGleb Smirnoff <glebius@FreeBSD.org>2018-06-07 22:38:40 +0000
committerGleb Smirnoff <glebius@FreeBSD.org>2018-06-07 22:38:40 +0000
commita08d12d3f2d4f4dabfc01953be696fdc0750da9c (patch)
tree9f8b684c9cdceaaab593b8d4d4230e230ca695cc
parent6d645c57a36e677c5d1610a26a7c771fe0c1cf2f (diff)
Notes
-rw-r--r--usr.sbin/cron/cron/cron.c35
-rw-r--r--usr.sbin/cron/cron/cron.h24
-rw-r--r--usr.sbin/cron/cron/do_command.c12
-rw-r--r--usr.sbin/cron/crontab/crontab.521
-rw-r--r--usr.sbin/cron/lib/entry.c10
5 files changed, 88 insertions, 14 deletions
diff --git a/usr.sbin/cron/cron/cron.c b/usr.sbin/cron/cron/cron.c
index 48f431d9368c..460dd58dbd0d 100644
--- a/usr.sbin/cron/cron/cron.c
+++ b/usr.sbin/cron/cron/cron.c
@@ -46,7 +46,9 @@ static void usage(void),
parse_args(int c, char *v[]);
static int run_at_secres(cron_db *);
+static void find_interval_entry(pid_t);
+static cron_db database;
static time_t last_time = 0;
static int dst_enabled = 0;
static int dont_daemonize = 0;
@@ -100,7 +102,6 @@ main(argc, argv)
int argc;
char *argv[];
{
- cron_db database;
int runnum;
int secres1, secres2;
struct tm *tm;
@@ -154,8 +155,8 @@ main(argc, argv)
database.mtime = (time_t) 0;
load_database(&database);
secres1 = secres2 = run_at_secres(&database);
- run_reboot_jobs(&database);
cron_sync(secres1);
+ run_reboot_jobs(&database);
runnum = 0;
while (TRUE) {
# if DEBUGGING
@@ -210,6 +211,9 @@ run_reboot_jobs(db)
if (e->flags & WHEN_REBOOT) {
job_add(e, u);
}
+ if (e->flags & INTERVAL) {
+ e->lastexit = TargetTime;
+ }
}
}
(void) job_runqueue();
@@ -313,6 +317,13 @@ cron_tick(cron_db *db, int secres)
env_get("LOGNAME", e->envp),
e->uid, e->gid, e->cmd))
+ if (e->flags & INTERVAL) {
+ if (e->lastexit > 0 &&
+ TargetTime >= e->lastexit + e->interval)
+ job_add(e, u);
+ continue;
+ }
+
if ( diff != 0 && (e->flags & (RUN_AT|NOT_UNTIL)) ) {
if (bit_test(e->second, otzsecond)
&& bit_test(e->minute, otzminute)
@@ -489,6 +500,7 @@ sigchld_handler(int x)
("[%d] sigchld...no dead kids\n", getpid()))
return;
default:
+ find_interval_entry(pid);
Debug(DPROC,
("[%d] sigchld...pid #%d died, stat=%d\n",
getpid(), pid, WEXITSTATUS(waiter)))
@@ -557,9 +569,26 @@ run_at_secres(cron_db *db)
for (u = db->head; u != NULL; u = u->next) {
for (e = u->crontab; e != NULL; e = e->next) {
- if ((e->flags & SEC_RES) != 0)
+ if ((e->flags & (SEC_RES | INTERVAL)) != 0)
return 1;
}
}
return 0;
}
+
+static void
+find_interval_entry(pid_t pid)
+{
+ user *u;
+ entry *e;
+
+ for (u = database.head; u != NULL; u = u->next) {
+ for (e = u->crontab; e != NULL; e = e->next) {
+ if ((e->flags & INTERVAL) && e->child == pid) {
+ e->lastexit = time(NULL);
+ e->child = 0;
+ break;
+ }
+ }
+ }
+}
diff --git a/usr.sbin/cron/cron/cron.h b/usr.sbin/cron/cron/cron.h
index a6810be84005..bb4f5287daea 100644
--- a/usr.sbin/cron/cron/cron.h
+++ b/usr.sbin/cron/cron/cron.h
@@ -168,19 +168,29 @@ typedef struct _entry {
#endif
char **envp;
char *cmd;
- bitstr_t bit_decl(second, SECOND_COUNT);
- bitstr_t bit_decl(minute, MINUTE_COUNT);
- bitstr_t bit_decl(hour, HOUR_COUNT);
- bitstr_t bit_decl(dom, DOM_COUNT);
- bitstr_t bit_decl(month, MONTH_COUNT);
- bitstr_t bit_decl(dow, DOW_COUNT);
+ union {
+ struct {
+ bitstr_t bit_decl(second, SECOND_COUNT);
+ bitstr_t bit_decl(minute, MINUTE_COUNT);
+ bitstr_t bit_decl(hour, HOUR_COUNT);
+ bitstr_t bit_decl(dom, DOM_COUNT);
+ bitstr_t bit_decl(month, MONTH_COUNT);
+ bitstr_t bit_decl(dow, DOW_COUNT);
+ };
+ struct {
+ time_t lastexit;
+ time_t interval;
+ pid_t child;
+ };
+ };
int flags;
#define DOM_STAR 0x01
#define DOW_STAR 0x02
#define WHEN_REBOOT 0x04
-#define RUN_AT 0x08
+#define RUN_AT 0x08
#define NOT_UNTIL 0x10
#define SEC_RES 0x20
+#define INTERVAL 0x40
time_t lastrun;
} entry;
diff --git a/usr.sbin/cron/cron/do_command.c b/usr.sbin/cron/cron/do_command.c
index 4d7c1f439d0e..f62303a5df29 100644
--- a/usr.sbin/cron/cron/do_command.c
+++ b/usr.sbin/cron/cron/do_command.c
@@ -47,6 +47,8 @@ do_command(e, u)
entry *e;
user *u;
{
+ pid_t pid;
+
Debug(DPROC, ("[%d] do_command(%s, (%s,%d,%d))\n",
getpid(), e->cmd, u->name, e->uid, e->gid))
@@ -57,9 +59,11 @@ do_command(e, u)
* vfork() is unsuitable, since we have much to do, and the parent
* needs to be able to run off and fork other processes.
*/
- switch (fork()) {
+ switch ((pid = fork())) {
case -1:
log_it("CRON",getpid(),"error","can't fork");
+ if (e->flags & INTERVAL)
+ e->lastexit = time(NULL);
break;
case 0:
/* child process */
@@ -70,6 +74,12 @@ do_command(e, u)
break;
default:
/* parent process */
+ Debug(DPROC, ("[%d] main process forked child #%d, "
+ "returning to work\n", getpid(), pid))
+ if (e->flags & INTERVAL) {
+ e->lastexit = 0;
+ e->child = pid;
+ }
break;
}
Debug(DPROC, ("[%d] main process returning to work\n", getpid()))
diff --git a/usr.sbin/cron/crontab/crontab.5 b/usr.sbin/cron/crontab/crontab.5
index acd6cb5381a6..697242b4d0fc 100644
--- a/usr.sbin/cron/crontab/crontab.5
+++ b/usr.sbin/cron/crontab/crontab.5
@@ -17,7 +17,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd January 5, 2016
+.Dd June 6, 2018
.Dt CRONTAB 5
.Os
.Sh NAME
@@ -220,7 +220,10 @@ would cause a command to be run at 4:30 am on the 1st and 15th of each
month, plus every Friday.
.Pp
Instead of the first five fields,
-one of eight special strings may appear:
+a line may start with
+.Sq @
+symbol followed either by one of eight special strings or by a numeric value.
+The recognized special strings are:
.Bd -literal -offset indent
string meaning
------ -------
@@ -235,6 +238,16 @@ string meaning
@every_minute Run once a minute, "*/1 * * * *".
@every_second Run once a second.
.Ed
+.Pp
+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
+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.
.Sh EXAMPLE CRON FILE
.Bd -literal
@@ -251,6 +264,8 @@ MAILTO=paul
0 22 * * 1-5 mail -s "It's 10pm" joe%Joe,%%Where are your kids?%
23 0-23/2 * * * echo "run 23 minutes after midn, 2am, 4am ..., everyday"
5 4 * * sun echo "run at 5 after 4 every sunday"
+# run at 5 minutes intervals, no matter how long it takes
+@300 svnlite up /usr/src
.Ed
.Sh SEE ALSO
.Xr crontab 1 ,
@@ -292,7 +307,7 @@ either).
.Pp
All of the
.Sq @
-commands that can appear in place of the first five fields
+directives that can appear in place of the first five fields
are extensions.
.Sh AUTHORS
.An Paul Vixie Aq Mt paul@vix.com
diff --git a/usr.sbin/cron/lib/entry.c b/usr.sbin/cron/lib/entry.c
index 57f72554d344..a8ec3ae8b568 100644
--- a/usr.sbin/cron/lib/entry.c
+++ b/usr.sbin/cron/lib/entry.c
@@ -132,6 +132,9 @@ load_entry(file, error_func, pw, envp)
}
if (ch == '@') {
+ long interval;
+ char *endptr;
+
/* all of these should be flagged and load-limited; i.e.,
* instead of @hourly meaning "0 * * * *" it should mean
* "close to the front of every hour but not 'til the
@@ -209,6 +212,13 @@ load_entry(file, error_func, pw, envp)
bit_nset(e->dom, 0, (LAST_DOM-FIRST_DOM+1));
bit_nset(e->month, 0, (LAST_MONTH-FIRST_MONTH+1));
bit_nset(e->dow, 0, (LAST_DOW-FIRST_DOW+1));
+ } else if (*cmd != '\0' &&
+ (interval = strtol(cmd, &endptr, 10)) > 0 &&
+ *endptr == '\0') {
+ Debug(DPARS, ("load_entry()... %ld seconds "
+ "since last run\n", interval))
+ e->interval = interval;
+ e->flags = INTERVAL;
} else {
ecode = e_timespec;
goto eof;