aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2020-04-29 19:12:45 +0300
committerSergey Poznyakoff <gray@gnu.org>2020-04-29 19:12:45 +0300
commit8196b4281500ef4f6e0cba4ff1f20f6d41e92f17 (patch)
treecec8dfeaf2a2cf0ae73816a84f8dba41bd14274b /src
parent3ababf4edb89be0b164d8e9cb1cad5b009de9778 (diff)
downloadwydawca-8196b4281500ef4f6e0cba4ff1f20f6d41e92f17.tar.gz
wydawca-8196b4281500ef4f6e0cba4ff1f20f6d41e92f17.tar.bz2
Improve statistic reporter scheduling.
Use crontab format specification to define the frequency of statistic report generation. * src/wydawca.h (stat_report_schedule): New variable. Replaces stat_report_interval. * configure.ac: Check for struct tm.tm_gmtoff. * src/config.c: New keyword: stat-report-schedule. * src/micron.c: New file. * src/micron.h: New file. * src/Makefile.am: Add new files. * src/timer.c (wy_thr_stat): Use micron scheduler. * doc/wydawca.texi: Document stat-report-schedule. * NEWS: Document stat-report-schedule.
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am2
-rw-r--r--src/config.c85
-rw-r--r--src/micron.c398
-rw-r--r--src/micron.h40
-rw-r--r--src/timer.c5
-rw-r--r--src/wydawca.h3
6 files changed, 497 insertions, 36 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 5b70f5e..15238d4 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -44,6 +44,8 @@ wydawca_SOURCES=\
null.c\
timer.c\
thread_name.c\
+ micron.h\
+ micron.c\
queue.h
if COND_INOTIFY
diff --git a/src/config.c b/src/config.c
index f213fc7..3ba0e5a 100644
--- a/src/config.c
+++ b/src/config.c
@@ -249,7 +249,7 @@ string_to_wy_event(grecs_locus_t * locus, const char *val,
int
-wy_assert_string_arg(grecs_locus_t * locus,
+wy_assert_string_arg(grecs_locus_t *locus,
enum grecs_callback_command cmd,
const grecs_value_t * value)
{
@@ -280,7 +280,7 @@ get_arg(grecs_value_t * value, unsigned n, int type)
}
static int
-cb_interval(enum grecs_callback_command cmd, grecs_node_t * node,
+cb_interval(enum grecs_callback_command cmd, grecs_node_t *node,
void *varptr, void *cb_data)
{
int rc;
@@ -426,7 +426,7 @@ parse_statmask(grecs_locus_t *loc, grecs_value_t *val, unsigned long *pmask)
}
int
-wy_cb_statistics(enum grecs_callback_command cmd, grecs_node_t * node,
+wy_cb_statistics(enum grecs_callback_command cmd, grecs_node_t *node,
void *varptr, void *cb_data)
{
return parse_statmask(&node->locus, node->v.value, varptr);
@@ -434,7 +434,7 @@ wy_cb_statistics(enum grecs_callback_command cmd, grecs_node_t * node,
static int
-cb_sql_host(enum grecs_callback_command cmd, grecs_node_t * node,
+cb_sql_host(enum grecs_callback_command cmd, grecs_node_t *node,
void *varptr, void *cb_data)
{
struct sqlconn *pconn = varptr;
@@ -476,7 +476,7 @@ cb_sql_host(enum grecs_callback_command cmd, grecs_node_t * node,
}
static int
-cb_sql(enum grecs_callback_command cmd, grecs_node_t * node,
+cb_sql(enum grecs_callback_command cmd, grecs_node_t *node,
void *varptr, void *cb_data)
{
struct sqlconn *pconn;
@@ -539,7 +539,7 @@ static struct grecs_keyword sql_kw[] = {
};
static int
-cb_syslog_facility(enum grecs_callback_command cmd, grecs_node_t * node,
+cb_syslog_facility(enum grecs_callback_command cmd, grecs_node_t *node,
void *varptr, void *cb_data)
{
grecs_locus_t *locus = &node->locus;
@@ -577,7 +577,7 @@ static struct grecs_keyword syslog_kw[] = {
};
static int
-cb_metadata_mode(enum grecs_callback_command cmd, grecs_node_t * node,
+cb_metadata_mode(enum grecs_callback_command cmd, grecs_node_t *node,
void *varptr, void *cb_data)
{
grecs_locus_t *locus = &node->locus;
@@ -603,7 +603,7 @@ cb_metadata_mode(enum grecs_callback_command cmd, grecs_node_t * node,
}
static int
-arg_to_uid(grecs_value_t * value, uid_t * uid)
+arg_to_uid(grecs_value_t *value, uid_t *uid)
{
char const *user = value->v.string;
unsigned long n;
@@ -642,7 +642,7 @@ arg_to_uid(grecs_value_t * value, uid_t * uid)
}
static int
-arg_to_gid(grecs_value_t * value, gid_t * gid)
+arg_to_gid(grecs_value_t *value, gid_t *gid)
{
char const *group = value->v.string;
unsigned long n;
@@ -681,7 +681,7 @@ arg_to_gid(grecs_value_t * value, gid_t * gid)
}
static int
-cb_metadata_owner(enum grecs_callback_command cmd, grecs_node_t * node,
+cb_metadata_owner(enum grecs_callback_command cmd, grecs_node_t *node,
void *varptr, void *cb_data)
{
grecs_value_t *value = node->v.value, *uval, *gval;
@@ -732,7 +732,7 @@ get_backup_version(grecs_locus_t * locus, const char *ctx,
}
static int
-cb_backup(enum grecs_callback_command cmd, grecs_node_t * node,
+cb_backup(enum grecs_callback_command cmd, grecs_node_t *node,
void *varptr, void *cb_data)
{
enum backup_type *ptype = varptr;
@@ -769,7 +769,7 @@ static struct grecs_keyword archive_kw[] = {
};
static int
-cb_archive(enum grecs_callback_command cmd, grecs_node_t * node,
+cb_archive(enum grecs_callback_command cmd, grecs_node_t *node,
void *varptr, void *cb_data)
{
struct archive_descr *arch = varptr;
@@ -829,7 +829,7 @@ cb_archive(enum grecs_callback_command cmd, grecs_node_t * node,
}
static int
-cb_event(enum grecs_callback_command cmd, grecs_node_t * node,
+cb_event(enum grecs_callback_command cmd, grecs_node_t *node,
void *varptr, void *cb_data)
{
enum wy_event *pev = varptr;
@@ -859,7 +859,7 @@ static struct grecs_keyword notify_event_kw[] = {
};
static int
-cb_notify_event(enum grecs_callback_command cmd, grecs_node_t * node,
+cb_notify_event(enum grecs_callback_command cmd, grecs_node_t *node,
void *varptr, void *cb_data)
{
struct notification *ntf;
@@ -905,7 +905,7 @@ string_to_dictionary_type(const char *str)
}
static int
-cb_dictionary_type(enum grecs_callback_command cmd, grecs_node_t * node,
+cb_dictionary_type(enum grecs_callback_command cmd, grecs_node_t *node,
void *varptr, void *cb_data)
{
enum dictionary_type *ptype = varptr;
@@ -922,7 +922,7 @@ cb_dictionary_type(enum grecs_callback_command cmd, grecs_node_t * node,
}
static int
-cb_dictionary_params(enum grecs_callback_command cmd, grecs_node_t * node,
+cb_dictionary_params(enum grecs_callback_command cmd, grecs_node_t *node,
void *varptr, void *cb_data)
{
struct dictionary *meth = varptr;
@@ -1001,7 +1001,7 @@ string_to_dictionary_id(grecs_locus_t * locus,
}
static int
-cb_dictionary(enum grecs_callback_command cmd, grecs_node_t * node,
+cb_dictionary(enum grecs_callback_command cmd, grecs_node_t *node,
void *varptr, void *cb_data)
{
struct dictionary **pmeth, *meth;
@@ -1054,7 +1054,7 @@ cb_dictionary(enum grecs_callback_command cmd, grecs_node_t * node,
}
static int
-cb_url(enum grecs_callback_command cmd, grecs_node_t * node,
+cb_url(enum grecs_callback_command cmd, grecs_node_t *node,
void *varptr, void *cb_data)
{
wy_url_t *purl = varptr, url;
@@ -1144,7 +1144,7 @@ static struct grecs_keyword spool_kw[] = {
};
static int
-cb_spool(enum grecs_callback_command cmd, grecs_node_t * node,
+cb_spool(enum grecs_callback_command cmd, grecs_node_t *node,
void *varptr, void *cb_data)
{
struct spool *spool;
@@ -1226,7 +1226,7 @@ cb_spool(enum grecs_callback_command cmd, grecs_node_t * node,
}
static int
-cb_user(enum grecs_callback_command cmd, grecs_node_t * node,
+cb_user(enum grecs_callback_command cmd, grecs_node_t *node,
void *varptr, void *cb_data)
{
struct passwd *pw;
@@ -1250,7 +1250,7 @@ cb_user(enum grecs_callback_command cmd, grecs_node_t * node,
}
static int
-cb_supp_groups(enum grecs_callback_command cmd, grecs_node_t * node,
+cb_supp_groups(enum grecs_callback_command cmd, grecs_node_t *node,
void *varptr, void *cb_data)
{
grecs_locus_t *locus = &node->locus;
@@ -1297,7 +1297,7 @@ cb_supp_groups(enum grecs_callback_command cmd, grecs_node_t * node,
}
static int
-cb_load_path(enum grecs_callback_command cmd, grecs_node_t * node,
+cb_load_path(enum grecs_callback_command cmd, grecs_node_t *node,
void *varptr, void *cb_data)
{
struct grecs_list **lpp = varptr, *lp;
@@ -1339,7 +1339,7 @@ cb_load_path(enum grecs_callback_command cmd, grecs_node_t * node,
}
static int
-cb_upload_version(enum grecs_callback_command cmd, grecs_node_t * node,
+cb_upload_version(enum grecs_callback_command cmd, grecs_node_t *node,
void *varptr, void *cb_data)
{
unsigned *pversion = varptr, n;
@@ -1368,6 +1368,30 @@ cb_upload_version(enum grecs_callback_command cmd, grecs_node_t * node,
}
static int
+cb_cron(enum grecs_callback_command cmd, grecs_node_t *node,
+ void *varptr, void *cb_data)
+{
+ grecs_locus_t *locus = &node->locus;
+ grecs_value_t *value = node->v.value;
+ struct micronent *entry = varptr;
+ int rc;
+ char *endp;
+
+ if (wy_assert_string_arg(locus, cmd, value))
+ return 1;
+ rc = micron_parse(value->v.string, &endp, entry);
+ if (rc) {
+ grecs_error(&value->locus, 0, "%s near %s",
+ micron_strerror(rc), endp);
+ return 0;
+ }
+ if (endp[strcspn(endp, " \t")])
+ grecs_error(&value->locus, 0, "garbage after cron specification");
+
+ return 0;
+}
+
+static int
cb_daemon_mode(enum grecs_callback_command cmd, grecs_node_t *node,
void *varptr, void *cb_data)
{
@@ -1466,10 +1490,11 @@ static struct grecs_keyword wydawca_kw[] = {
N_("Control implicit signature archivation"),
grecs_type_bool, GRECS_DFLT, &archive_signatures },
- { "stat-report-interval", N_("interval"),
- N_("Interval for periodic statistics reports"),
+ { "stat-report-schedule", N_("spec"),
+ N_("Schedule periodic statistics reports (in crontab format)"),
grecs_type_string, GRECS_DFLT,
- &stat_report_interval, 0, cb_interval },
+ &stat_report_schedule, 0, cb_cron },
+
{ "statistics", N_("items"),
N_("Print these statistic items periodically"),
grecs_type_string, GRECS_CONST, &print_stats, 0, wy_cb_statistics },
@@ -1710,6 +1735,8 @@ config_finish(struct grecs_node *tree)
struct grecs_node *p;
int err;
+ micron_parse("@hourly", NULL, &stat_report_schedule);
+
if (grecs_tree_process(tree, wydawca_kw))
exit(EX_CONFIG);
for (p = tree->down; p; p = p->next) {
@@ -1732,10 +1759,4 @@ config_finish(struct grecs_node *tree)
_("%s too low; reverting to the default %lus"),
"file-sweep-time", (unsigned long)file_sweep_time);
}
- if (stat_report_interval <= 0) {
- stat_report_interval = DEFAULT_STAT_REPORT_INTERVAL;
- wy_log(LOG_NOTICE,
- _("%s too low; reverting to the default %lus"),
- "stat-report-interval", (unsigned long)stat_report_interval);
- }
}
diff --git a/src/micron.c b/src/micron.c
new file mode 100644
index 0000000..2fb6e3b
--- /dev/null
+++ b/src/micron.c
@@ -0,0 +1,398 @@
+/* micron - a minimal cron implementation
+ Copyright (C) 2020 Sergey Poznyakoff
+
+ Micron is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ Micron is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with micron. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <time.h>
+#include "micron.h"
+
+static char const *mon_names[] = {
+ "jan", "feb", "mar",
+ "apr", "may", "jun",
+ "jul", "aug", "sep",
+ "oct", "nov", "dec"
+};
+
+static char const *dow_names[] = {
+ "sun", "mon", "tue", "wed", "thu", "fri", "sat"
+};
+
+static int
+xlat_name(char const *xlat[], int n, char const *name, char const *allowed)
+{
+ int i;
+ if (strlen(name) < 3 || (name[3] && strchr(allowed, name[3]) == 0))
+ return -1;
+ for (i = 0; i < n; i++)
+ if (strncasecmp(xlat[i], name, 3) == 0)
+ return i;
+ return -1;
+}
+
+static int
+micron_parse_range(char const *spec, char **endp, char *map, int len, int start,
+ char const **xlat)
+{
+ int r_min, r_max, r_step;
+ unsigned long n;
+ char *p;
+ int list_ok;
+
+ if (*spec == '*') {
+ spec++;
+ r_min = 0;
+ r_max = len - 1;
+ list_ok = 0;
+ } else if (isdigit(*spec)) {
+ errno = 0;
+ n = strtoul(spec, &p, 10);
+ if (errno || p == spec || n < start || n - start > len - 1) {
+ *endp = (char*) spec;
+ return MICRON_E_RANGE;
+ }
+ r_min = n - start;
+
+ spec = p;
+
+ if (*spec == '-') {
+ spec++;
+ errno = 0;
+ n = strtoul(spec, &p, 10);
+ if (errno || p == spec || n < start || n - start > len - 1) {
+ *endp = (char*) spec;
+ return MICRON_E_RANGE;
+ }
+ r_max = n - start;
+ spec = p;
+ } else
+ r_max = r_min;
+ list_ok = 1;
+ } else if (xlat) {
+ int d = xlat_name(xlat, len, spec, "-, ");
+ if (d == -1)
+ goto esynt;
+ spec += 3;
+ r_min = d;
+
+ if (*spec == '-') {
+ spec++;
+ d = xlat_name(xlat, len, spec, "/, ");
+ if (d == -1)
+ goto esynt;
+ spec += 3;
+ r_max = d;
+ } else
+ r_max = r_min;
+ list_ok = 1;
+ } else {
+esynt:
+ *endp = (char*) spec;
+ return MICRON_E_SYNT;
+ }
+
+ if (r_max != r_min && *spec == '/') {
+ spec++;
+ errno = 0;
+ n = strtoul(spec, &p, 10);
+ if (errno || p == spec || n >= len) {
+ *endp = (char*) spec;
+ return MICRON_E_RANGE;
+ }
+ r_step = n;
+ spec = p;
+ } else
+ r_step = 1;
+
+ if (r_min > r_max) {
+ for (; r_min < len; r_min += r_step)
+ map[r_min] = 1;
+ r_min = 0;
+ }
+
+ for (; r_min <= r_max; r_min += r_step)
+ map[r_min] = 1;
+
+ *endp = (char*) spec;
+ if (!list_ok && *spec == ',')
+ return MICRON_E_SYNT;
+ return MICRON_E_OK;
+}
+
+static int
+micron_parse_field(char const *spec, char **endp, char *map, int len, int start,
+ char const **xlat)
+{
+ int rc;
+ char *p;
+
+ while (*spec && isspace(*spec))
+ spec++;
+ if (!*spec) {
+ *endp = (char*) spec;
+ return MICRON_E_EOF;
+ }
+ memset(map, 0, len * sizeof(map[0]));
+ do {
+ rc = micron_parse_range(spec, &p, map, len, start, xlat);
+ spec = p;
+ if (*spec != ',')
+ break;
+ spec++;
+ } while (rc == MICRON_E_OK);
+ *endp = (char*) spec;
+ return rc;
+}
+
+#define micron_parse_entry_field(spec,endp,fld,start,xlat) \
+ micron_parse_field(spec, \
+ endp, \
+ fld, \
+ sizeof(fld)/sizeof((fld)[0]), start, xlat)
+
+int
+micron_parse_timespec(char const *spec, char **endp, struct micronent *ent)
+{
+ char *p;
+ int rc;
+
+ rc = micron_parse_entry_field(spec, &p, ent->min, 0, NULL);
+ if (rc == 0) {
+ rc = micron_parse_entry_field(p, &p, ent->hrs, 0, NULL);
+ if (rc == 0) {
+ rc = micron_parse_entry_field(p, &p, ent->day, 1, NULL);
+ if (rc == 0) {
+ rc = micron_parse_entry_field(p, &p, ent->mon, 1, mon_names);
+ if (rc == 0) {
+ rc = micron_parse_entry_field(p, &p, ent->dow, 0,
+ dow_names);
+ if (rc == 0) {
+ if (ent->dow[7]) {
+ ent->dow[0] = 1;
+ ent->dow[7] = 0;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (endp)
+ *endp = p;
+ return rc;
+}
+
+static struct micron_equiv {
+ char const *name;
+ int len;
+ char const *equiv;
+} micron_special[] = {
+#define S(s) #s, sizeof(#s)-1
+ { S(hourly), "0 * * * *" },
+ { S(daily), "0 0 * * *" },
+ { S(midnight), "0 0 * * *" },
+ { S(weekly), "0 0 * * 0" },
+ { S(monthly), "0 0 1 * *" },
+ { S(yearly), "0 0 1 1 *" },
+ { S(annually), "0 0 1 1 *" },
+ { NULL }
+#undef S
+};
+
+int
+micron_parse(char const *spec, char **endp, struct micronent *ent)
+{
+ while (*spec && isspace(*spec))
+ spec++;
+ if (!*spec) {
+ *endp = (char*) spec;
+ return MICRON_E_EOF;
+ }
+
+ if (*spec == '@') {
+ struct micron_equiv *eqv;
+ spec++;
+ for (eqv = micron_special; eqv->name; eqv++) {
+ if (!strncmp(spec, eqv->name, eqv->len)
+ && (spec[eqv->len] == 0|| isspace(spec[eqv->len]))) {
+ micron_parse_timespec(eqv->equiv, NULL, ent);
+ if (endp)
+ *endp = (char*)spec + eqv->len;
+ return MICRON_E_OK;
+ }
+ }
+ if (endp)
+ *endp = (char*) spec;
+ return MICRON_E_SYNT;
+ }
+
+ return micron_parse_timespec(spec, endp, ent);
+}
+
+static char const *micron_error_str[] = {
+ [MICRON_E_OK] = "no error",
+ [MICRON_E_EOF] = "premature end of input",
+ [MICRON_E_RANGE] = "value out of range",
+ [MICRON_E_SYNT] = "syntax error",
+ [MICRON_E_SYS] = "system error",
+ [MICRON_E_BADCRON] = "malformed crontab entry"
+};
+
+char const *
+micron_strerror(int ec)
+{
+ if (ec >= 0 && ec < sizeof(micron_error_str)/sizeof(micron_error_str[0]))
+ return micron_error_str[ec];
+ return "unknown error";
+}
+
+static int
+julianday(struct tm *tm)
+{
+ int a = (13 - tm->tm_mon) / 12;
+ int y = tm->tm_year + 6700 - a;
+ int m = tm->tm_mon + 12*a - 2;
+
+ return tm->tm_mday + (153*m + 2)/5 + 365*y + y/4 - y/100 + y/400 - 32045;
+}
+
+/* Compute day of week (0 - Sunday) */
+static inline int
+dayofweek(struct tm *tm)
+{
+ return (julianday(tm) + 1) % 7;
+}
+
+static int month_start[]=
+ { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
+ /* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */
+ /* 31 28 31 30 31 30 31 31 30 31 30 31 */
+
+static inline int
+is_leap_year(int y)
+{
+ return (y % 4 == 0 && (y % 100 != 0 || y % 400 == 0));
+}
+
+static inline int
+monthdays(struct tm *tm)
+{
+ return month_start[tm->tm_mon + 1] - month_start[tm->tm_mon]
+ + ((tm->tm_mon == 1) ? is_leap_year(tm->tm_year + 1900) : 0);
+}
+
+static inline void
+next_month(struct tm *tm)
+{
+ if (++tm->tm_mon == 12) {
+ tm->tm_mon = 0;
+ tm->tm_year++;
+ }
+ tm->tm_mday = 1;
+ tm->tm_hour = 0;
+ tm->tm_min = 0;
+ tm->tm_wday = dayofweek(tm);
+}
+
+static inline void
+next_day(struct tm *tm)
+{
+ tm->tm_hour = 0;
+ tm->tm_min = 0;
+ tm->tm_wday = (tm->tm_wday + 1) % 7;
+ if (++tm->tm_mday > monthdays(tm)) {
+ tm->tm_mday = 1;
+ next_month(tm);
+ }
+}
+
+static inline void
+next_hour(struct tm *tm)
+{
+ tm->tm_min = 0;
+ if (++tm->tm_hour == 24) {
+ tm->tm_hour = 0;
+ next_day(tm);
+ }
+}
+
+static inline void
+next_minute(struct tm *tm)
+{
+ if (++tm->tm_min == 60) {
+ tm->tm_min = 0;
+ next_hour(tm);
+ }
+}
+
+void
+micron_next(struct micronent const *ent, struct tm const *now, struct tm *next)
+{
+ *next = *now;
+ next->tm_sec = 0;
+ next_minute(next);
+
+ while (1) {
+ if (!ent->mon[next->tm_mon]) {
+ next_month(next);
+ continue;
+ }
+
+ if (!(ent->day[next->tm_mday-1] == 1
+ && ent->dow[next->tm_wday])) {
+ next_day(next);
+ continue;
+ }
+
+ if (!ent->hrs[next->tm_hour]) {
+ next_hour(next);
+ continue;
+ }
+
+ if (!ent->min[next->tm_min]) {
+ next_minute(next);
+ continue;
+ }
+ break;
+ }
+}
+
+int
+micron_next_time(struct micronent const *ent, struct timespec *ts)
+{
+ struct timespec ts_now;
+ struct tm now, next;
+ time_t t;
+
+ clock_gettime(CLOCK_REALTIME, &ts_now);
+ t = ts_now.tv_sec;
+ if (!localtime_r(&t, &now))
+ return MICRON_E_SYS;
+ micron_next(ent, &now, &next);
+ t = mktime(&next);
+ if (t == (time_t)-1)
+ return MICRON_E_SYS;
+#ifdef HAVE_STRUCT_TM_TM_GMTOFF
+ t += now.tm_gmtoff - next.tm_gmtoff;
+#endif
+ ts->tv_sec = t;
+ ts->tv_nsec = 0;
+ return MICRON_E_OK;
+}
diff --git a/src/micron.h b/src/micron.h
new file mode 100644
index 0000000..c415f50
--- /dev/null
+++ b/src/micron.h
@@ -0,0 +1,40 @@
+/* micron - a minimal cron implementation
+ Copyright (C) 2020 Sergey Poznyakoff
+
+ Micron is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ Micron is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with micron. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <time.h>
+
+enum {
+ MICRON_E_OK,
+ MICRON_E_EOF,
+ MICRON_E_RANGE,
+ MICRON_E_SYNT,
+ MICRON_E_SYS,
+ MICRON_E_BADCRON
+};
+
+struct micronent {
+ char min[60];
+ char hrs[24];
+ char day[32];
+ char mon[12];
+ char dow[8]; /* 0 or 7 is Sun */
+};
+
+int micron_parse(char const *spec, char **endp, struct micronent *ent);
+char const *micron_strerror(int ec);
+void micron_next(struct micronent const *ent, struct tm const *now,
+ struct tm *next);
+int micron_next_time(struct micronent const *ent, struct timespec *ts);
diff --git a/src/timer.c b/src/timer.c
index 1de7cfb..ff8dfce 100644
--- a/src/timer.c
+++ b/src/timer.c
@@ -258,7 +258,7 @@ wydawca_stat_reset(void)
_timer_reset(&wydawca_global_timer_table[i]);
}
-time_t stat_report_interval = DEFAULT_STAT_REPORT_INTERVAL;
+struct micronent stat_report_schedule;
void *
wy_thr_stat(void *ptr)
@@ -270,8 +270,7 @@ wy_thr_stat(void *ptr)
wydawca_global_timer_table = get_thread_timer_table();
while (!stat_stop) {
struct timespec ts;
- clock_gettime(CLOCK_REALTIME, &ts);
- ts.tv_sec += stat_report_interval;
+ micron_next_time(&stat_report_schedule, &ts);
pthread_cond_timedwait(&global_stats_cond, &global_stats_mutex, &ts);
wydawca_stat_log();
notify_stat();
diff --git a/src/wydawca.h b/src/wydawca.h
index 5fbb106..95f11f0 100644
--- a/src/wydawca.h
+++ b/src/wydawca.h
@@ -54,6 +54,7 @@
#include "grecs.h"
#include "wordsplit.h"
#include "queue.h"
+#include "micron.h"
#ifndef O_SEARCH
# define O_SEARCH 0
@@ -328,7 +329,7 @@ extern char *conffile; /* Configuration file name */
extern int syslog_include_prio; /* Syslog priority indication */
extern time_t file_sweep_time; /* Unlink stale file after this amount of time
*/
-extern time_t stat_report_interval;
+extern struct micronent stat_report_schedule;
extern char *tar_command_name; /* Name of the tar command */
extern unsigned long print_stats;
extern int archive_signatures;

Return to:

Send suggestions and report system problems to the System administrator.