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 #include #include +#include #ifdef WITH_INOTIFY # include @@ -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 #include #include +#include #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