--- cron.1 | 18 +++++ cron.c | 246 ++++++++++++++++++++++++++++----------------------------- 2 files changed, 141 insertions(+), 123 deletions(-) diff --git a/cron.1 b/cron.1 index 1cb90a4..da8284e 100644 --- a/cron.1 +++ b/cron.1 _AT_@ -21,3 +21,21 @@ instead of the default .It Fl n Do not daemonize. .El +.Sh NOTES +This +.Nm +accepts Vixie cron syntax. +It also includes the '~' syntax for random ranges, +which is non-standard. +.Pp +This +.Nm +doesn't support crontabs in /var/spool. If one wishes to have +per-user crontabs, one should, at login time, or at boot time, +start +.Nm +with the user-supplied file and the correct user permissions. +Accordingly, crontab will not work with this +.Nm . +.Sh SEE ALSO +.Xf crontab 5 diff --git a/cron.c b/cron.c index 77304cc..59e7fbc 100644 --- a/cron.c +++ b/cron.c _AT_@ -17,19 +17,13 @@ #include "queue.h" #include "util.h" -struct field { - enum { - ERROR, - WILDCARD, - NUMBER, - RANGE, - REPEAT, - LIST - } type; - long *val; - int len; +struct range { + long low, high, repeat; + TAILQ_ENTRY(range) entry; }; +TAILQ_HEAD(field, range); + struct ctabentry { struct field min; struct field hour; _AT_@ -202,143 +196,146 @@ matchentry(struct ctabentry *cte, struct tm *tm) { .f = &cte->wday, .tm = tm->tm_wday, .len = 7 }, }; size_t i; - int j; + int found, t; + struct range *r; for (i = 0; i < LEN(matchtbl); i++) { - switch (matchtbl[i].f->type) { - case WILDCARD: - continue; - case NUMBER: - if (matchtbl[i].f->val[0] == matchtbl[i].tm) - continue; - break; - case RANGE: - if (matchtbl[i].f->val[0] <= matchtbl[i].tm) - if (matchtbl[i].f->val[1] >= matchtbl[i].tm) - continue; - break; - case REPEAT: - if (matchtbl[i].tm > 0) { - if (matchtbl[i].tm % matchtbl[i].f->val[0] == 0) - continue; - } else { - if (matchtbl[i].len % matchtbl[i].f->val[0] == 0) - continue; + found = 0; + t = matchtbl[i].tm; + TAILQ_FOREACH(r, matchtbl[i].f, entry) { + if (r->low <= t && r->high >= t && t % r->repeat == 0) { + found = 1; + break; } - break; - case LIST: - for (j = 0; j < matchtbl[i].f->len; j++) - if (matchtbl[i].f->val[j] == matchtbl[i].tm) - break; - if (j < matchtbl[i].f->len) - continue; - break; - default: - break; } - break; + if (!found) + break; } if (i != LEN(matchtbl)) return 0; + return 1; } static int -parsefield(const char *field, long low, long high, struct field *f) +parserange(char *str, long low, long high, struct range *r) { - int i; - char *e1, *e2; - const char *p; - - p = field; - while (isdigit(*p)) - p++; - - f->type = ERROR; - - switch (*p) { - case '*': - if (strcmp(field, "*") == 0) { - f->val = NULL; - f->len = 0; - f->type = WILDCARD; - } else if (strncmp(field, "*/", 2) == 0) { - f->val = emalloc(sizeof(*f->val)); - f->len = 1; - - errno = 0; - f->val[0] = strtol(field + 2, &e1, 10); - if (e1[0] != '\0' || errno != 0 || f->val[0] == 0) - break; + /* range = number + * | [number] "~" [number] ["/" number] + * | number "-" number ["/" number] + */ + char *range, *repeat, *strlow, *strhigh; + char *e; + int random; + + random = 0; + + range = strsep(&str, "/"); + repeat = strsep(&str, "/"); + if (!range || !*range) + return -1; - f->type = REPEAT; - } + switch (*range) { + case '~': + random = 1; + case '*': /* fallthru */ + if (range[1] != '\0') + return -1; + r->low = low; + r->high = high; break; - case '\0': - f->val = emalloc(sizeof(*f->val)); - f->len = 1; + ARGNUM: + strlow = strsep(&range, "-"); + strhigh = strsep(&range, "-"); + if (!*strlow) /* i.e. - */ + return -1; errno = 0; - f->val[0] = strtol(field, &e1, 10); - if (e1[0] != '\0' || errno != 0) - break; - - f->type = NUMBER; + r->low = strtol(strlow, &e, 10); + if ((*e && *e != '~') || errno != 0) + return -1; + if (strhigh) { + if (!*strhigh || range != NULL) /* i.e. N- or N-M-... */ + return -1; + errno = 0; + r->high = strtol(strhigh, &e, 10); + if (*e || errno != 0) + return -1; + } else { + e = strsep(&strlow, "~"); + if (!strlow) /* i.e. N */ + r->high = r->low; + strhigh = strsep(&strlow, "-"); + if (strhigh) { + if (!*strhigh || strlow != NULL) /* i.e. N~ or N~M~... */ + return -1; + random = 1; + + errno = 0; + r->high = strtol(strhigh, &e, 10); + if (*e || errno != 0) + return -1; + } + } break; - case '-': - f->val = emalloc(2 * sizeof(*f->val)); - f->len = 2; - - errno = 0; - f->val[0] = strtol(field, &e1, 10); - if (e1[0] != '-' || errno != 0) - break; + } + if (repeat) { + if (!*repeat || str != NULL) + return -1; errno = 0; - f->val[1] = strtol(e1 + 1, &e2, 10); - if (e2[0] != '\0' || errno != 0) - break; + r->repeat = strtol(repeat, &e, 10); + if (*e || errno != 0 || r->repeat == 0) + return -1; + } else if (random) { + r->repeat = r->low; + } else { + r->repeat = 1; + } - f->type = RANGE; - break; - case ',': - for (i = 1; isdigit(*p) || *p == ','; p++) - if (*p == ',') - i++; - f->val = emalloc(i * sizeof(*f->val)); - f->len = i; + if (random) + r->low = rng32_bounded(r->high - r->low+1) + r->low; - errno = 0; - f->val[0] = strtol(field, &e1, 10); - if (f->val[0] < low || f->val[0] > high) - break; + if (r->low < low || r->low > high || r->high < low || r->high > high || r->repeat < low || r->repeat > high) + return -1; - for (i = 1; *e1 == ',' && errno == 0; i++) { - errno = 0; - f->val[i] = strtol(e1 + 1, &e2, 10); - e1 = e2; - } - if (e1[0] != '\0' || errno != 0) - break; + return 0; +} - f->type = LIST; - break; - default: - return -1; +static int +parsefield(char *field, long low, long high, struct field *f) +{ + char *elem; + struct range *r; + + int first = 1; + while ((elem = strsep(&field, ",")) != NULL) { + if (*elem == '\0') + return -1; + first = 0; + + r = emalloc(sizeof(*r)); + if (parserange(elem, low, high, r)) + return -1; + TAILQ_INSERT_TAIL(f, r, entry); } - for (i = 0; i < f->len; i++) - if (f->val[i] < low || f->val[i] > high) - f->type = ERROR; - - if (f->type == ERROR) { - free(f->val); + if (first) return -1; - } return 0; } +static void +freefield(struct field *f) +{ + struct range *r; + while ((r = TAILQ_FIRST(f))) { + TAILQ_REMOVE(f, r, entry); + free(r); + } +} + static void freecte(struct ctabentry *cte, int nfields) { _AT_@ -346,15 +343,15 @@ freecte(struct ctabentry *cte, int nfields) case 6: free(cte->cmd); case 5: - free(cte->wday.val); + freefield(&cte->wday); case 4: - free(cte->mon.val); + freefield(&cte->mon); case 3: - free(cte->mday.val); + freefield(&cte->mday); case 2: - free(cte->hour.val); + freefield(&cte->hour); case 1: - free(cte->min.val); + freefield(&cte->min); } free(cte); } _AT_@ -412,6 +409,7 @@ loadentries(void) flim[4].f = &cte->wday; for (x = 0; x < LEN(flim); x++) { + TAILQ_INIT(flim[x].f); do col = strsep(&p, "\t\n "); while (col && col[0] == '\0'); _AT_@ -525,6 +523,8 @@ main(int argc, char *argv[]) sigaction(SIGHUP, &sa, NULL); sigaction(SIGTERM, &sa, NULL); + rng32_seed(); + loadentries(); while (1) { -- 2.47.1Received on Thu Dec 19 2024 - 18:42:02 CET
This archive was generated by hypermail 2.3.0 : Thu Dec 19 2024 - 18:48:42 CET