aboutsummaryrefslogtreecommitdiff
path: root/usr.sbin/cron
diff options
context:
space:
mode:
authorMaxim Sobolev <sobomax@FreeBSD.org>2012-10-15 08:21:49 +0000
committerMaxim Sobolev <sobomax@FreeBSD.org>2012-10-15 08:21:49 +0000
commit2543786a37e37dcf9c42db54681d36f7359542eb (patch)
tree4480269ff163dda5d57dde705f23d272bfb89474 /usr.sbin/cron
parente76163a539e5e860edd7a48c4586f597ab81ff2f (diff)
downloadsrc-2543786a37e37dcf9c42db54681d36f7359542eb.tar.gz
src-2543786a37e37dcf9c42db54681d36f7359542eb.zip
Add per-second scheduling into the cron(8). Right now it's
only available via the new @every_second shortcut. ENOTIME to implement crontab(5) format extensions to allow more flexible scheduling. In order to address some concerns expressed by Terry Lambert while discussing the topic few years ago, about per-second cron possibly causing some bad effects on /etc/crontab by stat()ing it every second instead of every minute now (i.e. atime update), only check that database needs to be reloaded on every 60-th loop run. This should be close enough to the current behaviour. Add "@every_minute" shortcut while I am here. MFC after: 1 month
Notes
Notes: svn path=/head/; revision=241576
Diffstat (limited to 'usr.sbin/cron')
-rw-r--r--usr.sbin/cron/cron/cron.c26
-rw-r--r--usr.sbin/cron/cron/cron.h5
-rw-r--r--usr.sbin/cron/crontab/crontab.52
-rw-r--r--usr.sbin/cron/lib/entry.c21
4 files changed, 45 insertions, 9 deletions
diff --git a/usr.sbin/cron/cron/cron.c b/usr.sbin/cron/cron/cron.c
index 8524ff9dfcb8..011458a537f1 100644
--- a/usr.sbin/cron/cron/cron.c
+++ b/usr.sbin/cron/cron/cron.c
@@ -98,6 +98,7 @@ main(argc, argv)
char *argv[];
{
cron_db database;
+ int runnum;
ProgramName = argv[0];
@@ -149,21 +150,24 @@ main(argc, argv)
load_database(&database);
run_reboot_jobs(&database);
cron_sync();
+ runnum = 0;
while (TRUE) {
# if DEBUGGING
/* if (!(DebugFlags & DTEST)) */
# endif /*DEBUGGING*/
cron_sleep(&database);
- load_database(&database);
+ if (runnum % 60 == 0)
+ load_database(&database);
/* do this iteration
*/
cron_tick(&database);
- /* sleep 1 minute
+ /* sleep 1 second
*/
- TargetTime += 60;
+ TargetTime += 1;
+ runnum += 1;
}
}
@@ -194,22 +198,23 @@ cron_tick(db)
static time_t diff = 0, /* time difference in seconds from the last offset change */
difflimit = 0; /* end point for the time zone correction */
struct tm otztm; /* time in the old time zone */
- int otzminute, otzhour, otzdom, otzmonth, otzdow;
+ int otzsecond, otzminute, otzhour, otzdom, otzmonth, otzdow;
register struct tm *tm = localtime(&TargetTime);
- register int minute, hour, dom, month, dow;
+ register int second, minute, hour, dom, month, dow;
register user *u;
register entry *e;
/* make 0-based values out of these so we can use them as indicies
*/
+ second = tm->tm_sec -FIRST_SECOND;
minute = tm->tm_min -FIRST_MINUTE;
hour = tm->tm_hour -FIRST_HOUR;
dom = tm->tm_mday -FIRST_DOM;
month = tm->tm_mon +1 /* 0..11 -> 1..12 */ -FIRST_MONTH;
dow = tm->tm_wday -FIRST_DOW;
- Debug(DSCH, ("[%d] tick(%d,%d,%d,%d,%d)\n",
- getpid(), minute, hour, dom, month, dow))
+ Debug(DSCH, ("[%d] tick(%d,%d,%d,%d,%d,%d)\n",
+ getpid(), second, minute, hour, dom, month, dow))
if (dst_enabled && last_time != 0
&& TargetTime > last_time /* exclude stepping back */
@@ -262,6 +267,7 @@ cron_tick(db)
/* make 0-based values out of these so we can use them as indicies
*/
+ otzsecond = otztm.tm_sec -FIRST_SECOND;
otzminute = otztm.tm_min -FIRST_MINUTE;
otzhour = otztm.tm_hour -FIRST_HOUR;
otzdom = otztm.tm_mday -FIRST_DOM;
@@ -283,7 +289,8 @@ cron_tick(db)
e->uid, e->gid, e->cmd))
if ( diff != 0 && (e->flags & (RUN_AT|NOT_UNTIL)) ) {
- if (bit_test(e->minute, otzminute)
+ if (bit_test(e->second, otzsecond)
+ && bit_test(e->minute, otzminute)
&& bit_test(e->hour, otzhour)
&& bit_test(e->month, otzmonth)
&& ( ((e->flags & DOM_STAR) || (e->flags & DOW_STAR))
@@ -302,7 +309,8 @@ cron_tick(db)
continue;
}
- if (bit_test(e->minute, minute)
+ if (bit_test(e->second, second)
+ && bit_test(e->minute, minute)
&& bit_test(e->hour, hour)
&& bit_test(e->month, month)
&& ( ((e->flags & DOM_STAR) || (e->flags & DOW_STAR))
diff --git a/usr.sbin/cron/cron/cron.h b/usr.sbin/cron/cron/cron.h
index 38eb33b0c6f5..387c72bbed09 100644
--- a/usr.sbin/cron/cron/cron.h
+++ b/usr.sbin/cron/cron/cron.h
@@ -124,6 +124,10 @@
LineNumber = ln; \
}
+#define FIRST_SECOND 0
+#define LAST_SECOND 59
+#define SECOND_COUNT (LAST_SECOND - FIRST_SECOND + 1)
+
#define FIRST_MINUTE 0
#define LAST_MINUTE 59
#define MINUTE_COUNT (LAST_MINUTE - FIRST_MINUTE + 1)
@@ -165,6 +169,7 @@ 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);
diff --git a/usr.sbin/cron/crontab/crontab.5 b/usr.sbin/cron/crontab/crontab.5
index 458175e7a48d..9be37df264e5 100644
--- a/usr.sbin/cron/crontab/crontab.5
+++ b/usr.sbin/cron/crontab/crontab.5
@@ -232,6 +232,8 @@ string meaning
@daily Run once a day, "0 0 * * *".
@midnight (same as @daily)
@hourly Run once an hour, "0 * * * *".
+@every_minute Run once a minute, "*/1 * * * *".
+@every_second Run once a second.
.Ed
.Sh EXAMPLE CRON FILE
.Bd -literal
diff --git a/usr.sbin/cron/lib/entry.c b/usr.sbin/cron/lib/entry.c
index ea015da62704..9c1106a3d735 100644
--- a/usr.sbin/cron/lib/entry.c
+++ b/usr.sbin/cron/lib/entry.c
@@ -151,6 +151,7 @@ load_entry(file, error_func, pw, envp)
e->flags |= WHEN_REBOOT;
} else if (!strcmp("yearly", cmd) || !strcmp("annually", cmd)){
Debug(DPARS, ("load_entry()...yearly shortcut\n"))
+ bit_set(e->second, 0);
bit_set(e->minute, 0);
bit_set(e->hour, 0);
bit_set(e->dom, 0);
@@ -159,6 +160,7 @@ load_entry(file, error_func, pw, envp)
e->flags |= DOW_STAR;
} else if (!strcmp("monthly", cmd)) {
Debug(DPARS, ("load_entry()...monthly shortcut\n"))
+ bit_set(e->second, 0);
bit_set(e->minute, 0);
bit_set(e->hour, 0);
bit_set(e->dom, 0);
@@ -167,6 +169,7 @@ load_entry(file, error_func, pw, envp)
e->flags |= DOW_STAR;
} else if (!strcmp("weekly", cmd)) {
Debug(DPARS, ("load_entry()...weekly shortcut\n"))
+ bit_set(e->second, 0);
bit_set(e->minute, 0);
bit_set(e->hour, 0);
bit_nset(e->dom, 0, (LAST_DOM-FIRST_DOM+1));
@@ -175,6 +178,7 @@ load_entry(file, error_func, pw, envp)
bit_set(e->dow, 0);
} else if (!strcmp("daily", cmd) || !strcmp("midnight", cmd)) {
Debug(DPARS, ("load_entry()...daily shortcut\n"))
+ bit_set(e->second, 0);
bit_set(e->minute, 0);
bit_set(e->hour, 0);
bit_nset(e->dom, 0, (LAST_DOM-FIRST_DOM+1));
@@ -182,11 +186,28 @@ load_entry(file, error_func, pw, envp)
bit_nset(e->dow, 0, (LAST_DOW-FIRST_DOW+1));
} else if (!strcmp("hourly", cmd)) {
Debug(DPARS, ("load_entry()...hourly shortcut\n"))
+ bit_set(e->second, 0);
bit_set(e->minute, 0);
bit_nset(e->hour, 0, (LAST_HOUR-FIRST_HOUR+1));
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 (!strcmp("every_minute", cmd)) {
+ Debug(DPARS, ("load_entry()...every_minute shortcut\n"))
+ bit_set(e->second, 0);
+ bit_nset(e->minute, 0, (LAST_MINUTE-FIRST_MINUTE+1));
+ bit_nset(e->hour, 0, (LAST_HOUR-FIRST_HOUR+1));
+ 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 (!strcmp("every_second", cmd)) {
+ Debug(DPARS, ("load_entry()...every_second shortcut\n"))
+ bit_nset(e->second, 0, (LAST_SECOND-FIRST_SECOND+1));
+ bit_nset(e->minute, 0, (LAST_MINUTE-FIRST_MINUTE+1));
+ bit_nset(e->hour, 0, (LAST_HOUR-FIRST_HOUR+1));
+ 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 {
ecode = e_timespec;
goto eof;