diff options
author | Todd C. Miller <millert@cvs.openbsd.org> | 2020-04-15 01:59:35 +0000 |
---|---|---|
committer | Todd C. Miller <millert@cvs.openbsd.org> | 2020-04-15 01:59:35 +0000 |
commit | a69625443ec6afc469b0f69ed71716e6e5a2b8ec (patch) | |
tree | fdb388a21d3dc30d481af40c0c66d96f2fcbac2b /usr.sbin | |
parent | ba9b883e5956e7bc06530c9af36709a8d70a5688 (diff) |
Add support for random values using the '~' operator.
For example "0~30" will result in a random value between 0 and 30
inclusive. If either (or both) of the numbers on either side of
the '~' are omitted, the appropriate limit (low or high) for the
field will be used. OK deraadt@ beck@ jmc@
Diffstat (limited to 'usr.sbin')
-rw-r--r-- | usr.sbin/cron/crontab.5 | 24 | ||||
-rw-r--r-- | usr.sbin/cron/entry.c | 61 |
2 files changed, 65 insertions, 20 deletions
diff --git a/usr.sbin/cron/crontab.5 b/usr.sbin/cron/crontab.5 index f9b4446cf87..ef9ac0a6672 100644 --- a/usr.sbin/cron/crontab.5 +++ b/usr.sbin/cron/crontab.5 @@ -17,9 +17,9 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT .\" OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.\" $OpenBSD: crontab.5,v 1.37 2020/01/06 19:44:09 job Exp $ +.\" $OpenBSD: crontab.5,v 1.38 2020/04/15 01:59:34 millert Exp $ .\" -.Dd $Mdocdate: January 6 2020 $ +.Dd $Mdocdate: April 15 2020 $ .Dt CRONTAB 5 .Os .Sh NAME @@ -144,7 +144,18 @@ For example, .Ar hour entry specifies execution at hours 8, 9, 10 and 11. .Pp -Step values can be used in conjunction with ranges. +A random value (within the legal range) may be obtained by using the +.Ql ~ +character in a field. +The interval of the random value may be specified explicitly, for example +.Dq 0~30 +will result in a random value between 0 and 30 inclusive. +If either (or both) of the numbers on either side of the +.Ql ~ +are omitted, the appropriate limit (low or high) for the field will be used. +.Pp +Step values can be used in conjunction with ranges (but not random ranges +which represent a single number). Following a range with .No / Ns Ar number specifies skips of @@ -318,6 +329,9 @@ MAILTO=paul 23 0-23/2 * * * echo "run 23 minutes after midn, 2am, 4am ..., everyday" 5 4 * * sun echo "run at 5 after 4 every sunday" + +# run hourly at a random time within the first 30 minutes of the hour +0~30 * * * * /usr/libexec/spamd-setup .Ed .Sh SEE ALSO .Xr crontab 1 , @@ -338,6 +352,10 @@ field may use 7 to represent Sunday. Ranges may include .Dq steps . .It +Random intervals are supported using the +.Ql ~ +character. +.It Months or days of the week can be specified by name. .It Mailing after a successful run can be suppressed with diff --git a/usr.sbin/cron/entry.c b/usr.sbin/cron/entry.c index bb0221bffb6..e3f919a86e3 100644 --- a/usr.sbin/cron/entry.c +++ b/usr.sbin/cron/entry.c @@ -1,4 +1,4 @@ -/* $OpenBSD: entry.c,v 1.49 2018/06/13 11:27:30 job Exp $ */ +/* $OpenBSD: entry.c,v 1.50 2020/04/15 01:59:34 millert Exp $ */ /* * Copyright 1988,1990,1993,1994 by Paul Vixie @@ -450,33 +450,29 @@ static int get_range(bitstr_t *bits, int low, int high, const char *names[], int ch, FILE *file) { - /* range = number | number "-" number [ "/" number ] + /* range = number | number* "~" number* | number "-" number ["/" number] */ int i, num1, num2, num3; + num1 = low; + num2 = high; + if (ch == '*') { - /* '*' means "first-last" but can still be modified by /step + /* '*' means [low, high] but can still be modified by /step */ - num1 = low; - num2 = high; ch = get_char(file); if (ch == EOF) return (EOF); } else { - ch = get_number(&num1, low, names, ch, file, ",- \t\n"); - if (ch == EOF) - return (EOF); - - if (ch != '-') { - /* not a range, it's a single number. - */ - if (EOF == set_element(bits, low, high, num1)) { - unget_char(ch, file); + if (ch != '~') { + ch = get_number(&num1, low, names, ch, file, ",-~ \t\n"); + if (ch == EOF) return (EOF); - } - return (ch); - } else { + } + + switch (ch) { + case '-': /* eat the dash */ ch = get_char(file); @@ -488,6 +484,37 @@ get_range(bitstr_t *bits, int low, int high, const char *names[], ch = get_number(&num2, low, names, ch, file, "/, \t\n"); if (ch == EOF || num1 > num2) return (EOF); + break; + case '~': + /* eat the tilde + */ + ch = get_char(file); + if (ch == EOF) + return (EOF); + + /* get the (optional) number following the tilde + */ + ch = get_number(&num2, low, names, ch, file, ", \t\n"); + if (ch == EOF) + ch = get_char(file); + if (ch == EOF || num1 > num2) { + unget_char(ch, file); + return (EOF); + } + + /* get a random number in the interval [num1, num2] + */ + num3 = num1; + num1 = arc4random_uniform(num2 - num3 + 1) + num3; + /* FALLTHROUGH */ + default: + /* not a range, it's a single number. + */ + if (EOF == set_element(bits, low, high, num1)) { + unget_char(ch, file); + return (EOF); + } + return (ch); } } |