164 lines
5.0 KiB
Diff
164 lines
5.0 KiB
Diff
|
diff --git a/man/crontab.5 b/man/crontab.5
|
||
|
index 740e393..bfc8414 100644
|
||
|
--- a/man/crontab.5
|
||
|
+++ b/man/crontab.5
|
||
|
@@ -143,6 +143,13 @@ specifications of the particular security context. For more information,
|
||
|
see
|
||
|
.BR crontab (1)\ -s\ option.
|
||
|
.PP
|
||
|
+The
|
||
|
+.I RANDOM_DELAY
|
||
|
+variable allows delaying job startups by random amount of minutes with
|
||
|
+upper limit specified by the variable. The random scaling factor is
|
||
|
+determined during the cron daemon startup so it remains constant for
|
||
|
+the whole run time of the daemon.
|
||
|
+.PP
|
||
|
The format of a cron command is similar to the V7 standard, with a number
|
||
|
of upward-compatible extensions. Each line has five time-and-date fields
|
||
|
followed by a
|
||
|
diff --git a/src/cron.c b/src/cron.c
|
||
|
index 6fd0c31..ec4ace7 100644
|
||
|
--- a/src/cron.c
|
||
|
+++ b/src/cron.c
|
||
|
@@ -39,6 +39,7 @@
|
||
|
#include <sys/types.h>
|
||
|
#include <sys/wait.h>
|
||
|
#include <unistd.h>
|
||
|
+#include <sys/time.h>
|
||
|
|
||
|
#ifdef WITH_INOTIFY
|
||
|
# include <sys/inotify.h>
|
||
|
@@ -202,6 +203,9 @@ int main(int argc, char *argv[]) {
|
||
|
char *cs;
|
||
|
pid_t pid = getpid();
|
||
|
long oldGMToff;
|
||
|
+ struct timeval tv;
|
||
|
+ struct timezone tz;
|
||
|
+ char buf[256];
|
||
|
|
||
|
if ((ProgramName=strrchr(argv[0], '/')) == NULL) {
|
||
|
ProgramName = argv[0];
|
||
|
@@ -298,6 +302,15 @@ int main(int argc, char *argv[]) {
|
||
|
}
|
||
|
|
||
|
pid = getpid();
|
||
|
+
|
||
|
+ /* obtain a random scaling factor for RANDOM_DELAY */
|
||
|
+ if (gettimeofday(&tv, &tz) != 0)
|
||
|
+ tv.tv_usec = 0;
|
||
|
+ srandom(pid + tv.tv_usec);
|
||
|
+ RandomScale = random() / (double)RAND_MAX;
|
||
|
+ snprintf(buf, sizeof(buf), "RANDOM_DELAY will be scaled with factor %d%% if used.", (int)(RandomScale*100));
|
||
|
+ log_it("CRON", pid, "INFO", buf, 0);
|
||
|
+
|
||
|
acquire_daemonlock(0);
|
||
|
database.head = NULL;
|
||
|
database.tail = NULL;
|
||
|
@@ -508,8 +521,6 @@ static void run_reboot_jobs(cron_db * db) {
|
||
|
|
||
|
static void find_jobs(int vtime, cron_db * db, int doWild, int doNonWild, long vGMToff) {
|
||
|
char *orig_tz, *job_tz;
|
||
|
- time_t virtualSecond = vtime * SECONDS_PER_MINUTE;
|
||
|
- time_t virtualGMTSecond = virtualSecond - vGMToff;
|
||
|
struct tm *tm;
|
||
|
int minute, hour, dom, month, dow;
|
||
|
user *u;
|
||
|
@@ -542,11 +553,7 @@ static void find_jobs(int vtime, cron_db * db, int doWild, int doNonWild, long v
|
||
|
} while (0)
|
||
|
|
||
|
orig_tz = getenv("TZ");
|
||
|
- maketime(NULL, orig_tz);
|
||
|
|
||
|
- Debug(DSCH, ("[%ld] tick(%d,%d,%d,%d,%d) %s %s\n",
|
||
|
- (long) getpid(), minute, hour, dom, month, dow,
|
||
|
- doWild ? " " : "No wildcard", doNonWild ? " " : "Wildcard only"));
|
||
|
/* the dom/dow situation is odd. '* * 1,15 * Sun' will run on the
|
||
|
* first and fifteenth AND every Sunday; '* * * * Sun' will run *only*
|
||
|
* on Sundays; '* * 1,15 * *' will run *only* the 1st and 15th. this
|
||
|
@@ -561,6 +568,8 @@ static void find_jobs(int vtime, cron_db * db, int doWild, int doNonWild, long v
|
||
|
uname = e->pwd->pw_name;
|
||
|
/* check if user exists in time of job is being run f.e. ldap */
|
||
|
if (getpwnam(uname) != NULL) {
|
||
|
+ time_t virtualSecond = (vtime - e->delay) * SECONDS_PER_MINUTE;
|
||
|
+ time_t virtualGMTSecond = virtualSecond - vGMToff;
|
||
|
job_tz = env_get("CRON_TZ", e->envp);
|
||
|
maketime(job_tz, orig_tz);
|
||
|
/* here we test whether time is NOW */
|
||
|
diff --git a/src/entry.c b/src/entry.c
|
||
|
index e9142f5..fa69524 100644
|
||
|
--- a/src/entry.c
|
||
|
+++ b/src/entry.c
|
||
|
@@ -35,6 +35,7 @@
|
||
|
#include <string.h>
|
||
|
#include <sys/types.h>
|
||
|
#include <unistd.h>
|
||
|
+#include <errno.h>
|
||
|
|
||
|
#include "bitstring.h"
|
||
|
#include "funcs.h"
|
||
|
@@ -97,6 +98,7 @@ entry *load_entry(FILE * file, void (*error_func) (), struct passwd *pw,
|
||
|
char cmd[MAX_COMMAND];
|
||
|
char envstr[MAX_ENVSTR];
|
||
|
char **tenvp;
|
||
|
+ char *p;
|
||
|
|
||
|
Debug(DPARS, ("load_entry()...about to eat comments\n"));
|
||
|
|
||
|
@@ -297,6 +299,20 @@ entry *load_entry(FILE * file, void (*error_func) (), struct passwd *pw,
|
||
|
}
|
||
|
memset(e->pwd->pw_passwd, 0, strlen(e->pwd->pw_passwd));
|
||
|
|
||
|
+ p = env_get("RANDOM_DELAY", envp);
|
||
|
+ if (p) {
|
||
|
+ char *endptr;
|
||
|
+ long val;
|
||
|
+
|
||
|
+ errno = 0; /* To distinguish success/failure after call */
|
||
|
+ val = strtol(p, &endptr, 10);
|
||
|
+ if (errno != 0 || val < 0 || val > 24*60) {
|
||
|
+ log_it("CRON", getpid(), "ERROR", "bad value of RANDOM_DELAY", 0);
|
||
|
+ } else {
|
||
|
+ e->delay = val * RandomScale;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
/* copy and fix up environment. some variables are just defaults and
|
||
|
* others are overrides.
|
||
|
*/
|
||
|
diff --git a/src/env.c b/src/env.c
|
||
|
index 1ebea62..3ad8bf7 100644
|
||
|
--- a/src/env.c
|
||
|
+++ b/src/env.c
|
||
|
@@ -130,6 +130,7 @@ int env_set_from_environ(char ***envpp) {
|
||
|
"LC_IDENTIFICATION",
|
||
|
"LC_ALL",
|
||
|
"LANGUAGE",
|
||
|
+ "RANDOM_DELAY",
|
||
|
NULL
|
||
|
};
|
||
|
const char **name;
|
||
|
diff --git a/src/globals.h b/src/globals.h
|
||
|
index 4370974..e957c9a 100644
|
||
|
--- a/src/globals.h
|
||
|
+++ b/src/globals.h
|
||
|
@@ -81,6 +81,7 @@ XTRN char MailCmd[MAX_COMMAND];
|
||
|
XTRN char cron_default_mail_charset[MAX_ENVSTR];
|
||
|
XTRN int EnableClustering;
|
||
|
XTRN int ChangePath;
|
||
|
+XTRN double RandomScale;
|
||
|
|
||
|
#if DEBUGGING
|
||
|
XTRN int DebugFlags INIT(0);
|
||
|
diff --git a/src/structs.h b/src/structs.h
|
||
|
index 200d20d..272777a 100644
|
||
|
--- a/src/structs.h
|
||
|
+++ b/src/structs.h
|
||
|
@@ -41,6 +41,7 @@ typedef struct _entry {
|
||
|
bitstr_t bit_decl(month, MONTH_COUNT);
|
||
|
bitstr_t bit_decl(dow, DOW_COUNT);
|
||
|
int flags;
|
||
|
+ int delay;
|
||
|
#define MIN_STAR 0x01
|
||
|
#define HR_STAR 0x02
|
||
|
#define DOM_STAR 0x04
|