diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2020-04-29 19:12:45 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2020-04-29 19:12:45 +0300 |
commit | 8196b4281500ef4f6e0cba4ff1f20f6d41e92f17 (patch) | |
tree | cec8dfeaf2a2cf0ae73816a84f8dba41bd14274b /src | |
parent | 3ababf4edb89be0b164d8e9cb1cad5b009de9778 (diff) | |
download | wydawca-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.am | 2 | ||||
-rw-r--r-- | src/config.c | 85 | ||||
-rw-r--r-- | src/micron.c | 398 | ||||
-rw-r--r-- | src/micron.h | 40 | ||||
-rw-r--r-- | src/timer.c | 5 | ||||
-rw-r--r-- | src/wydawca.h | 3 |
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; |