From 7811874b177b97f88f2a48bd7325c7f86c0c100c Mon Sep 17 00:00:00 2001 From: James Antill Date: Tue, 31 May 2022 14:24:53 -0400 Subject: [PATCH] Auto sync2gitlab import of cronie-1.5.2-7.el8.src.rpm --- 0001-Add-random-within-range-operator.patch | 369 ++++++++++++++++++ ...issing-NUL-termination-for-the-scann.patch | 25 ++ ...ession-in-handling-x-crontab-entries.patch | 28 ++ ...sion-in-handling-1-5-crontab-entries.patch | 24 ++ cronie.spec | 15 +- 5 files changed, 460 insertions(+), 1 deletion(-) create mode 100644 0001-Add-random-within-range-operator.patch create mode 100644 0002-get_number-Add-missing-NUL-termination-for-the-scann.patch create mode 100644 0003-Fix-regression-in-handling-x-crontab-entries.patch create mode 100644 0004-Fix-regression-in-handling-1-5-crontab-entries.patch diff --git a/0001-Add-random-within-range-operator.patch b/0001-Add-random-within-range-operator.patch new file mode 100644 index 0000000..b6cbe3e --- /dev/null +++ b/0001-Add-random-within-range-operator.patch @@ -0,0 +1,369 @@ +From 0f1704a0f8c5fd2a4da6f530694bdd93a7ca3226 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ond=C5=99ej=20Poho=C5=99elsk=C3=BD?= + <35430604+opohorel@users.noreply.github.com> +Date: Mon, 8 Nov 2021 16:20:09 +0100 +Subject: [PATCH] Add random within range '~' operator + +With the operator one can specify for a job a random time or date within +a specified range for a field. +The random value is generated when the crontab where the job is +specified, is loaded. +--- + man/crontab.5 | 9 ++ + src/entry.c | 262 ++++++++++++++++++++++++++++++++------------------ + 2 files changed, 176 insertions(+), 95 deletions(-) + +diff --git a/man/crontab.5 b/man/crontab.5 +index a011c89..ba8f0c3 100644 +--- a/man/crontab.5 ++++ b/man/crontab.5 +@@ -199,6 +199,15 @@ hyphen. The specified range is inclusive. For example, 8-11 for + an 'hours' entry specifies execution at hours 8, 9, 10, and 11. The first + number must be less than or equal to the second one. + .PP ++Randomization of the execution time within a range can be used. ++A random number within a range specified as two numbers separated with ++a tilde is picked. The specified range is inclusive. ++For example, 6~15 for a 'minutes' entry picks a random minute ++within 6 to 15 range. The random number is picked when crontab file is parsed. ++The first number must be less than or equal to the second one. You might omit ++one or both of the numbers specifying the range. For example, ~ for a 'minutes' ++entry picks a random minute within 0 to 59 range. ++.PP + Lists are allowed. A list is a set of numbers (or ranges) separated by + commas. Examples: "1,2,5,9", "0-4,8-12". + .PP +diff --git a/src/entry.c b/src/entry.c +index 92b55f5..9276f47 100644 +--- a/src/entry.c ++++ b/src/entry.c +@@ -62,9 +62,22 @@ static const char *ecodes[] = { + "out of memory" + }; + ++typedef enum { ++ R_START, ++ R_AST, ++ R_STEP, ++ R_TERMS, ++ R_NUM1, ++ R_RANGE, ++ R_RANGE_NUM2, ++ R_RANDOM, ++ R_RANDOM_NUM2, ++ R_FINISH, ++} range_state_t; ++ + static int get_list(bitstr_t *, int, int, const char *[], int, FILE *), +-get_range(bitstr_t *, int, int, const char *[], int, FILE *), +-get_number(int *, int, const char *[], int, FILE *, const char *), ++get_range(bitstr_t *, int, int, const char *[], FILE *), ++get_number(int *, int, const char *[], FILE *), + set_element(bitstr_t *, int, int, int); + + void free_entry(entry * e) { +@@ -449,11 +462,14 @@ get_list(bitstr_t * bits, int low, int high, const char *names[], + /* process all ranges + */ + done = FALSE; ++ /* unget ch to allow get_range() to process it properly ++ */ ++ unget_char(ch, file); + while (!done) { +- if (EOF == (ch = get_range(bits, low, high, names, ch, file))) ++ if (EOF == (ch = get_range(bits, low, high, names, file))) + return (EOF); + if (ch == ',') +- ch = get_char(file); ++ continue; + else + done = TRUE; + } +@@ -468,137 +484,193 @@ get_list(bitstr_t * bits, int low, int high, const char *names[], + return (ch); + } + ++inline static int is_separator(int ch) { ++ switch (ch) { ++ case '\t': ++ case '\n': ++ case ' ': ++ case ',': ++ return 1; ++ default: ++ return 0; ++ } ++} ++ ++ + + static int + get_range(bitstr_t * bits, int low, int high, const char *names[], +- int ch, FILE * file) { ++ FILE * file) { + /* range = number | number "-" number [ "/" number ] ++ * | [number] "~" [number] + */ ++ ++ int ch, i, num1, num2, num3; + +- int i, num1, num2, num3; ++ /* default value for step ++ */ ++ num3 = 1; ++ range_state_t state = R_START; ++ ++ while (state != R_FINISH && ((ch = get_char(file)) != EOF)) { ++ switch (state) { ++ case R_START: ++ if (ch == '*') { ++ num1 = low; ++ num2 = high; ++ state = R_AST; ++ break; ++ } ++ if (ch == '~') { ++ num1 = low; ++ state = R_RANDOM; ++ break; ++ } ++ unget_char(ch, file); ++ if (get_number(&num1, low, names, file) != EOF) { ++ state = R_NUM1; ++ break; ++ } ++ return (EOF); + +- Debug(DPARS | DEXT, ("get_range()...entering, exit won't show\n")); ++ case R_AST: ++ if (ch == '/') { ++ state = R_STEP; ++ break; ++ } ++ if (is_separator(ch)) { ++ state = R_FINISH; ++ break; ++ } ++ return (EOF); + +- if (ch == '*') { +- /* '*' means "first-last" 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); ++ case R_STEP: ++ if (get_number(&num3, 0, PPC_NULL, file) != EOF) { ++ state = R_TERMS; ++ break; ++ } ++ return (EOF); + +- if (ch != '-') { +- /* not a range, it's a single number. +- */ +- if (EOF == set_element(bits, low, high, num1)) { +- unget_char(ch, file); ++ case R_TERMS: ++ if (is_separator(ch)) { ++ state = R_FINISH; ++ break; ++ } + return (EOF); +- } +- return (ch); +- } +- else { +- /* eat the dash +- */ +- ch = get_char(file); +- if (ch == EOF) ++ ++ case R_NUM1: ++ if (ch == '-') { ++ state = R_RANGE; ++ break; ++ } ++ if (ch == '~') { ++ state = R_RANDOM; ++ break; ++ } ++ if (is_separator(ch)) { ++ num2 = num1; ++ state = R_FINISH; ++ break; ++ } + return (EOF); + +- /* get the number following the dash +- */ +- ch = get_number(&num2, low, names, ch, file, "/, \t\n"); +- if (ch == EOF || num1 > num2) ++ case R_RANGE: ++ if (get_number(&num2, low, names, file) != EOF) { ++ state = R_RANGE_NUM2; ++ break; ++ } + return (EOF); +- } +- } + +- /* check for step size +- */ +- if (ch == '/') { +- /* eat the slash +- */ +- ch = get_char(file); +- if (ch == EOF) +- return (EOF); ++ case R_RANGE_NUM2: ++ if (ch == '/') { ++ state = R_STEP; ++ break; ++ } ++ if (is_separator(ch)) { ++ state = R_FINISH; ++ break; ++ } ++ return (EOF); + +- /* get the step size -- note: we don't pass the +- * names here, because the number is not an +- * element id, it's a step size. 'low' is +- * sent as a 0 since there is no offset either. +- */ +- ch = get_number(&num3, 0, PPC_NULL, ch, file, ", \t\n"); +- if (ch == EOF || num3 == 0) +- return (EOF); +- } +- else { +- /* no step. default==1. +- */ +- num3 = 1; ++ case R_RANDOM: ++ if (is_separator(ch)) { ++ num2 = high; ++ state = R_FINISH; ++ } ++ else if (unget_char(ch, file), ++ get_number(&num2, low, names, file) != EOF) { ++ state = R_TERMS; ++ } ++ /* fail if couldn't find match on previous term ++ */ ++ else ++ return (EOF); ++ ++ /* if invalid random range was selected */ ++ if (num1 > num2) ++ return (EOF); ++ ++ /* select random number in range ++ */ ++ num1 = num2 = random() % (num2 - num1 + 1) + num1; ++ break; ++ ++ ++ default: ++ /* We should never get here ++ */ ++ return (EOF); ++ } + } ++ if (state != R_FINISH || ch == EOF) ++ return (EOF); + +- /* range. set all elements from num1 to num2, stepping +- * by num3. (the step is a downward-compatible extension +- * proposed conceptually by bob@acornrc, syntactically +- * designed then implemented by paul vixie). +- */ + for (i = num1; i <= num2; i += num3) + if (EOF == set_element(bits, low, high, i)) { + unget_char(ch, file); + return (EOF); + } +- +- return (ch); ++ return ch; + } + + static int +-get_number(int *numptr, int low, const char *names[], int ch, FILE * file, +- const char *terms) { ++get_number(int *numptr, int low, const char *names[], FILE * file) { + char temp[MAX_TEMPSTR], *pc; +- int len, i; ++ int len, i, ch; ++ char *endptr; + + pc = temp; + len = 0; + +- /* first look for a number */ +- while (isdigit((unsigned char) ch)) { ++ /* get all alnum characters available */ ++ while (isalnum((ch = get_char(file)))) { + if (++len >= MAX_TEMPSTR) + goto bad; + *pc++ = (char)ch; +- ch = get_char(file); + } +- *pc = '\0'; +- if (len != 0) { +- /* got a number, check for valid terminator */ +- if (!strchr(terms, ch)) +- goto bad; +- *numptr = atoi(temp); +- return (ch); ++ if (len == 0) ++ goto bad; ++ ++ unget_char(ch, file); ++ ++ /* try to get number */ ++ *numptr = (int) strtol(temp, &endptr, 10); ++ if (*endptr == '\0' && temp != endptr) { ++ /* We have a number */ ++ return 0; + } + + /* no numbers, look for a string if we have any */ + if (names) { +- while (isalpha((unsigned char) ch)) { +- if (++len >= MAX_TEMPSTR) +- goto bad; +- *pc++ = (char)ch; +- ch = get_char(file); +- } +- *pc = '\0'; +- if (len != 0 && strchr(terms, ch)) { +- for (i = 0; names[i] != NULL; i++) { +- Debug(DPARS | DEXT, +- ("get_num, compare(%s,%s)\n", names[i], temp)); +- if (!strcasecmp(names[i], temp)) { +- *numptr = i + low; +- return (ch); +- } ++ for (i = 0; names[i] != NULL; i++) { ++ Debug(DPARS | DEXT, ("get_num, compare(%s,%s)\n", names[i], temp)); ++ if (strcasecmp(names[i], temp) == 0) { ++ *numptr = i + low; ++ return 0; + } + } ++ } else { ++ goto bad; + } + + bad: +-- +2.35.1 + diff --git a/0002-get_number-Add-missing-NUL-termination-for-the-scann.patch b/0002-get_number-Add-missing-NUL-termination-for-the-scann.patch new file mode 100644 index 0000000..0f7c6ab --- /dev/null +++ b/0002-get_number-Add-missing-NUL-termination-for-the-scann.patch @@ -0,0 +1,25 @@ +From 07bf4b9037de19b580cfa24f5ad023b56725b285 Mon Sep 17 00:00:00 2001 +From: Tomas Mraz +Date: Wed, 5 Jan 2022 19:17:18 +0100 +Subject: [PATCH 2/4] get_number: Add missing NUL termination for the scanned + string + +--- + src/entry.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/entry.c b/src/entry.c +index f2bb717..15ce9b5 100644 +--- a/src/entry.c ++++ b/src/entry.c +@@ -666,6 +666,7 @@ get_number(int *numptr, int low, const char *names[], FILE * file) { + goto bad; + *pc++ = (char)ch; + } ++ *pc = '\0'; + if (len == 0) + goto bad; + +-- +2.35.1 + diff --git a/0003-Fix-regression-in-handling-x-crontab-entries.patch b/0003-Fix-regression-in-handling-x-crontab-entries.patch new file mode 100644 index 0000000..ffcb8ae --- /dev/null +++ b/0003-Fix-regression-in-handling-x-crontab-entries.patch @@ -0,0 +1,28 @@ +From 299ef06ea4371afa97301cec64dc8f21c4f7b11b Mon Sep 17 00:00:00 2001 +From: Tomas Mraz +Date: Tue, 22 Mar 2022 14:35:48 +0100 +Subject: [PATCH 3/4] Fix regression in handling */x crontab entries + +Fixes #102 +--- + src/entry.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/src/entry.c b/src/entry.c +index 15ce9b5..e9e258b 100644 +--- a/src/entry.c ++++ b/src/entry.c +@@ -563,7 +563,9 @@ get_range(bitstr_t * bits, int low, int high, const char *names[], + return (EOF); + + case R_STEP: +- if (get_number(&num3, 0, PPC_NULL, file) != EOF) { ++ unget_char(ch, file); ++ if (get_number(&num3, 0, PPC_NULL, file) != EOF ++ && num3 != 0) { + state = R_TERMS; + break; + } +-- +2.35.1 + diff --git a/0004-Fix-regression-in-handling-1-5-crontab-entries.patch b/0004-Fix-regression-in-handling-1-5-crontab-entries.patch new file mode 100644 index 0000000..54d23d8 --- /dev/null +++ b/0004-Fix-regression-in-handling-1-5-crontab-entries.patch @@ -0,0 +1,24 @@ +From 62e53f1cdb9c1e12a01ee7814c92cd937d50328d Mon Sep 17 00:00:00 2001 +From: w30023233 +Date: Wed, 23 Mar 2022 15:40:01 +0800 +Subject: [PATCH 4/4] Fix regression in handling 1-5 crontab entries + +--- + src/entry.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/entry.c b/src/entry.c +index e9e258b..bb7cb62 100644 +--- a/src/entry.c ++++ b/src/entry.c +@@ -595,6 +595,7 @@ get_range(bitstr_t * bits, int low, int high, const char *names[], + return (EOF); + + case R_RANGE: ++ unget_char(ch, file); + if (get_number(&num2, low, names, file) != EOF) { + state = R_RANGE_NUM2; + break; +-- +2.35.1 + diff --git a/cronie.spec b/cronie.spec index 645bc8a..dacc9ce 100644 --- a/cronie.spec +++ b/cronie.spec @@ -6,7 +6,7 @@ Summary: Cron daemon for executing programs at set times Name: cronie Version: 1.5.2 -Release: 6%{?dist} +Release: 7%{?dist} License: MIT and BSD and ISC and GPLv2+ Group: System Environment/Base URL: https://github.com/cronie-crond/cronie @@ -48,6 +48,11 @@ Patch3: cronie-1.5.2-restart-on-failure.patch Patch4: cronie-1.5.2-create-pid-files.patch # Use system-auth in PAM (rhbz#2005526) Patch5: cronie-1.5.2-use-pam-system-auth.patch +# Add support for "~" ("random within range") + regression fixing patches (rhbz#1832510) +Patch6: 0001-Add-random-within-range-operator.patch +Patch7: 0002-get_number-Add-missing-NUL-termination-for-the-scann.patch +Patch8: 0003-Fix-regression-in-handling-x-crontab-entries.patch +Patch9: 0004-Fix-regression-in-handling-1-5-crontab-entries.patch %description Cronie contains the standard UNIX daemon crond that runs specified programs at @@ -96,6 +101,10 @@ extra features. %patch3 -p1 %patch4 -p1 %patch5 -p1 +%patch6 -p1 +%patch7 -p1 +%patch8 -p1 +%patch9 -p1 %build %configure \ @@ -224,6 +233,10 @@ exit 0 %attr(0644,root,root) %config(noreplace) %{_sysconfdir}/cron.d/dailyjobs %changelog +* Mon May 02 2022 Ondřej Pohořelský - 1.5.2-7 + - Add support for "~" ("random within range") + Resolves: rhbz#1832510 + * Mon Sep 20 2021 Jan Staněk - 1.5.2-6 - Use system-auth for PAM authentication Resolves: rhbz#2005526