On Mon, 13 Apr 2020 10:00:52 -0600, Bob Beck wrote: > +1000. a new random time chosen at cron start. > > We see this all the time, and it would be a lot better than the hacks for all > the things > > "R" for random sounds good to me
How about this? If you guys like it I'll update the man page too. So far only tested with a crontab entry like: R * * * * date - todd Index: usr.sbin/cron/cron.c =================================================================== RCS file: /cvs/src/usr.sbin/cron/cron.c,v retrieving revision 1.78 diff -u -p -u -r1.78 cron.c --- usr.sbin/cron/cron.c 11 Feb 2020 12:42:01 -0000 1.78 +++ usr.sbin/cron/cron.c 13 Apr 2020 16:25:44 -0000 @@ -129,6 +129,7 @@ main(int argc, char *argv[]) syslog(LOG_INFO, "(CRON) STARTUP (%s)", CRON_VERSION); } + init_random(); load_database(&database); scan_atjobs(&at_database, NULL); set_time(TRUE); Index: usr.sbin/cron/entry.c =================================================================== RCS file: /cvs/src/usr.sbin/cron/entry.c,v retrieving revision 1.49 diff -u -p -u -r1.49 entry.c --- usr.sbin/cron/entry.c 13 Jun 2018 11:27:30 -0000 1.49 +++ usr.sbin/cron/entry.c 13 Apr 2020 18:49:56 -0000 @@ -54,6 +54,12 @@ static const char *ecodes[] = { "out of memory" }; +typedef enum r_type { + r_minute, r_hour, r_dom, r_month, r_dow +} rtype_e; + +static int rand_vals[5]; + static const char *MonthNames[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", @@ -70,6 +76,8 @@ static int get_list(bitstr_t *, int, int get_number(int *, int, const char *[], int, FILE *, const char *), set_element(bitstr_t *, int, int, int); +static int set_random(bitstr_t *, int, int, FILE *); + void free_entry(entry *e) { @@ -187,10 +195,15 @@ load_entry(FILE *file, void (*error_func goto eof; } } else { - if (ch == '*') - e->flags |= MIN_STAR; - ch = get_list(e->minute, FIRST_MINUTE, LAST_MINUTE, - NULL, ch, file); + if (ch == 'R') { + ch = set_random(e->minute, rand_vals[r_minute], ch, + file); + } else { + if (ch == '*') + e->flags |= MIN_STAR; + ch = get_list(e->minute, FIRST_MINUTE, LAST_MINUTE, + NULL, ch, file); + } if (ch == EOF) { ecode = e_minute; goto eof; @@ -199,10 +212,14 @@ load_entry(FILE *file, void (*error_func /* hours */ - if (ch == '*') - e->flags |= HR_STAR; - ch = get_list(e->hour, FIRST_HOUR, LAST_HOUR, - NULL, ch, file); + if (ch == 'R') { + ch = set_random(e->hour, rand_vals[r_hour], ch, file); + } else { + if (ch == '*') + e->flags |= HR_STAR; + ch = get_list(e->hour, FIRST_HOUR, LAST_HOUR, + NULL, ch, file); + } if (ch == EOF) { ecode = e_hour; goto eof; @@ -211,10 +228,15 @@ load_entry(FILE *file, void (*error_func /* DOM (days of month) */ - if (ch == '*') - e->flags |= DOM_STAR; - ch = get_list(e->dom, FIRST_DOM, LAST_DOM, - NULL, ch, file); + if (ch == 'R') { + /* Note: the DOM value may not exist in this month. */ + ch = set_random(e->dom, rand_vals[r_dom], ch, file); + } else { + if (ch == '*') + e->flags |= DOM_STAR; + ch = get_list(e->dom, FIRST_DOM, LAST_DOM, + NULL, ch, file); + } if (ch == EOF) { ecode = e_dom; goto eof; @@ -223,8 +245,12 @@ load_entry(FILE *file, void (*error_func /* month */ - ch = get_list(e->month, FIRST_MONTH, LAST_MONTH, - MonthNames, ch, file); + if (ch == 'R') { + ch = set_random(e->month, rand_vals[r_month], ch, file); + } else { + ch = get_list(e->month, FIRST_MONTH, LAST_MONTH, + MonthNames, ch, file); + } if (ch == EOF) { ecode = e_month; goto eof; @@ -233,10 +259,14 @@ load_entry(FILE *file, void (*error_func /* DOW (days of week) */ - if (ch == '*') - e->flags |= DOW_STAR; - ch = get_list(e->dow, FIRST_DOW, LAST_DOW, - DowNames, ch, file); + if (ch == 'R') { + ch = set_random(e->dow, rand_vals[r_dow], ch, file); + } else { + if (ch == '*') + e->flags |= DOW_STAR; + ch = get_list(e->dow, FIRST_DOW, LAST_DOW, + DowNames, ch, file); + } if (ch == EOF) { ecode = e_dow; goto eof; @@ -407,6 +437,20 @@ load_entry(FILE *file, void (*error_func } static int +set_random(bitstr_t *bits, int val, int ch, FILE *file) +{ + bit_set(bits, val); + + /* Advance past whitespace after the 'R'. */ + ch = get_char(file); + if (ch == EOF) + return (EOF); + Skip_Blanks(ch, file); + + return (ch); +} + +static int get_list(bitstr_t *bits, int low, int high, const char *names[], int ch, FILE *file) { @@ -587,4 +631,45 @@ set_element(bitstr_t *bits, int low, int bit_set(bits, (number-low)); return (0); +} + +void +init_random(void) +{ + rtype_e r; + + for (r = 0; r < sizeof(rand_vals) / sizeof(rand_vals[0]); r++) { + switch (r) { + case r_minute: + rand_vals[r_minute] = arc4random_uniform(MINUTE_COUNT); + syslog(LOG_DEBUG, + "(CRON) RANDOM (MINUTE %d)", rand_vals[r_minute]); + break; + case r_hour: + rand_vals[r_hour] = arc4random_uniform(HOUR_COUNT); + syslog(LOG_DEBUG, + "(CRON) RANDOM (HOUR %d)", rand_vals[r_hour]); + break; + case r_dom: + rand_vals[r_dom] = arc4random_uniform(DOM_COUNT); + syslog(LOG_DEBUG, + "(CRON) RANDOM (DOM %d)", rand_vals[r_dom]); + break; + case r_month: + rand_vals[r_month] = arc4random_uniform(MONTH_COUNT); + syslog(LOG_DEBUG, + "(CRON) RANDOM (MONTH %d)", rand_vals[r_month]); + break; + case r_dow: + /* Decrement so we only count Sunday once. */ + rand_vals[r_dow] = arc4random_uniform(DOW_COUNT - 1); + syslog(LOG_DEBUG, + "(CRON) RANDOM (DOW %d)", rand_vals[r_dow]); + break; + default: + syslog(LOG_ERR, + "(CRON) ERROR (unexpected random type %d)", r); + break; + } + } } Index: usr.sbin/cron/funcs.h =================================================================== RCS file: /cvs/src/usr.sbin/cron/funcs.h,v retrieving revision 1.29 diff -u -p -u -r1.29 funcs.h --- usr.sbin/cron/funcs.h 5 Feb 2018 03:52:37 -0000 1.29 +++ usr.sbin/cron/funcs.h 13 Apr 2020 16:25:12 -0000 @@ -55,3 +55,5 @@ entry *load_entry(FILE *, void (*)(const char *), struct passwd *, char **); FILE *cron_popen(char *, char *, struct passwd *, pid_t *); + +void init_random(void);