On Mon, Apr 13, 2020 at 09:23:23PM -0600, Todd C. Miller wrote:
> On Mon, 13 Apr 2020 20:27:30 -0600, Bob Beck wrote:
>
> > In my hearts desire I'd love for "R" to be chosen for each line once at
> > start
> > up. (so in
> > the above example the things are randomly distributed). but not sure how
> > har
> > d that is..
> >
> > If it saves code and effort I really think this is only useful for hours
> > and
> > minutes
>
> Here's a version that uses a suggestion from Theo to support ranges
> like "0~30" to mean a random number between 0 and 30 and just a
> bare "~" to mean a random value in the valid range for that field.
>
> The random values are chosen when the file is parsed which means
> that on reload due to crontab edit they will change. I was trying
> to avoid that initially but now I don't think it is a big deal.
Like this one plenty. I think it's ok the values change on reload.
>
> - todd
>
> 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 14 Apr 2020 01:52:13 -0000
> @@ -450,13 +450,30 @@ 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;
>
> + /* XXX - parse ~, X~Y, X~ and ~Y */
> +
> + if (ch == '~') {
> + /* '~' means a random number [high, low]
> + */
> + num1 = arc4random_uniform(high - low + 1) + low;
> + ch = get_char(file);
> + if (ch == EOF)
> + return (EOF);
> +
> + if (EOF == set_element(bits, low, high, num1)) {
> + unget_char(ch, file);
> + return (EOF);
> + }
> + return (ch);
> + }
> +
> if (ch == '*') {
> - /* '*' means "first-last" but can still be modified by /step
> + /* '*' means "high-low" but can still be modified by /step
> */
> num1 = low;
> num2 = high;
> @@ -464,30 +481,45 @@ get_range(bitstr_t *bits, int low, int h
> if (ch == EOF)
> return (EOF);
> } else {
> - ch = get_number(&num1, low, names, ch, file, ",- \t\n");
> + 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);
> - return (EOF);
> - }
> - return (ch);
> - } else {
> - /* eat the dash
> + switch (ch) {
> + case '-':
> + case '~':
> + num3 = ch;
> +
> + /* eat the dash/tilde
> */
> ch = get_char(file);
> if (ch == EOF)
> return (EOF);
>
> - /* get the number following the dash
> + /* get the number following the dash/tilde
> */
> ch = get_number(&num2, low, names, ch, file, "/, \t\n");
> if (ch == EOF || num1 > num2)
> return (EOF);
> +
> + /* if it's a standard range, we're done here.
> + */
> + if (num3 == '-')
> + break;
> +
> + /* get a random number in the range [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);
> }
> }
>
>