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);

Reply via email to