diff --git a/ChangeLog.md b/ChangeLog.md index 4812db3..e9ff49d 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -14,6 +14,7 @@ Bug fix release. the bundled logger, the `syslog()` API in the C library is used, which may not necessarily set the timestamp. When sysklogd infers timestamp it was offset by the number of years since 1969, i.e., `boot_time` +- Issue #29: kernel messages repeated if syslogd is restarted at runtime - Issue #31: time calculation issue on 32-bit systems - Issue #32: remote kernel messages being mapped to uucp instead of user diff --git a/src/syslogd.c b/src/syslogd.c index 5741e99..25d4216 100644 --- a/src/syslogd.c +++ b/src/syslogd.c @@ -60,6 +60,7 @@ static char sccsid[] __attribute__((unused)) = #include #include #include +#include #include #include #include @@ -122,6 +123,7 @@ struct filed consfile; static int Debug; /* debug flag */ static int Foreground = 0; /* don't fork - don't run in daemon mode */ static time_t boot_time; /* Offset for printsys() */ +static uint64_t sys_seqno = 0; /* Last seen kernel log message */ static int resolve = 1; /* resolve hostname */ static char LocalHostName[MAXHOSTNAMELEN + 1]; /* our hostname */ static char *LocalDomain; /* our local domain name */ @@ -195,6 +197,54 @@ static int addpeer(struct peer *pe0) return 0; } +static void sys_seqno_load(void) +{ + char buf[32], *str; + FILE *fp; + + fp = fopen(_PATH_CACHE, "r"); + if (!fp) + return; + + while ((str = fgets(buf, sizeof(buf), fp))) { + uint64_t val; + char *end; + + if (str[strlen(str) - 1] == '\n') + str[strlen(str) - 1] = 0; + + errno = 0; + val = strtoull(str, &end, 10); + if (val == 0 && end == str) + break; /* str was not a number */ + else if (val == ULLONG_MAX && errno) + break; /* the value of str does not fit in unsigned long long */ + else if (*end) + break; /* str began with a number but has junk left over at the end */ + + sys_seqno = val; + } + fclose(fp); +} + +static void sys_seqno_save(void) +{ + static uint64_t prev = 0; + FILE *fp; + + if (prev == sys_seqno) + return; /* no changes since last save */ + + fp = fopen(_PATH_CACHE, "w"); + if (!fp) + return; /* best effort, ignore any errors */ + + fprintf(fp, "%" PRIu64 "\n", sys_seqno); + fclose(fp); + + prev = sys_seqno; +} + int usage(int code) { printf("Usage:\n" @@ -389,6 +439,7 @@ int main(int argc, char *argv[]) * /dev/kmsg and fall back to _PROC_KLOG, which on GLIBC * systems is /proc/kmsg, and /dev/klog on *BSD. */ + sys_seqno_load(); if (opensys("/dev/kmsg")) { if (opensys(_PATH_KLOG)) warn("Kernel logging disabled, failed opening %s", _PATH_KLOG); @@ -453,6 +504,8 @@ int main(int argc, char *argv[]) if (rc < 0 && errno != EINTR) ERR("select()"); + + sys_seqno_save(); } } @@ -1134,6 +1187,11 @@ void printsys(char *msg) while (isdigit(*p)) seqno = 10 * seqno + (*p++ - '0'); + /* Check if logged already (we've been restarted) */ + if (sys_seqno > 0 && seqno <= sys_seqno) + return; + sys_seqno = seqno; + p++; /* skip ',' */ /* timestamp */ diff --git a/src/syslogd.h b/src/syslogd.h index d68e59d..a9a1f6a 100644 --- a/src/syslogd.h +++ b/src/syslogd.h @@ -85,6 +85,10 @@ #define _PATH_LOGPID RUNSTATEDIR "/syslogd.pid" #endif +#ifndef _PATH_CACHE +#define _PATH_CACHE RUNSTATEDIR "/syslogd.cache" +#endif + #ifndef _PATH_DEV #define _PATH_DEV "/dev/" #endif