From 01a46ae8ccc518e4e3ade0bc59777efc41cf0177 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Mon, 24 Sep 2018 14:17:28 +0200 Subject: [PATCH 01/10] Compress rotated files >= .1, keep .0 uncompressed This patch adds support for rotating compressed files as well as compressing (gzip) all files older than .1. Props goes to @Znahoj for the first prototype implementation made at Westermo. Only minor changes to his draft were made. Signed-off-by: Joachim Nilsson --- src/syslogd.c | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/src/syslogd.c b/src/syslogd.c index cae50bf..bbcdb32 100644 --- a/src/syslogd.c +++ b/src/syslogd.c @@ -1863,22 +1863,36 @@ void logrotate(struct filed *f) fstat(f->f_file, &statf); /* bug (mostly harmless): can wrap around if file > 4gb */ if (S_ISREG(statf.st_mode) && statf.st_size > RotateSz) { - if (RotateCnt) { /* always 0..99 */ - int i = strlen(f->f_un.f_fname) + 3 + 1; - char oldFile[i]; - char newFile[i]; + if (RotateCnt > 0) { /* always 0..999 */ + int len = strlen(f->f_un.f_fname) + 10 + 1; + char oldFile[len]; + char newFile[len]; + + /* First age zipped log files */ + for (int i = RotateCnt; i > 1; i--) { + snprintf(oldFile, len, "%s.%d.gz", f->f_un.f_fname, i - 1); + snprintf(newFile, len, "%s.%d.gz", f->f_un.f_fname, i); - i = RotateCnt - 1; - /* rename: f.8 -> f.9; f.7 -> f.8; ... */ - while (1) { - sprintf(newFile, "%s.%d", f->f_un.f_fname, i); - if (i == 0) - break; - sprintf(oldFile, "%s.%d", f->f_un.f_fname, --i); /* ignore errors - file might be missing */ - rename(oldFile, newFile); + (void)rename(oldFile, newFile); } + + /* rename: f.8 -> f.9; f.7 -> f.8; ... */ + for (int i = 1; i > 0; i--) { + sprintf(oldFile, "%s.%d", f->f_un.f_fname, i - 1); + sprintf(newFile, "%s.%d", f->f_un.f_fname, i); + + if (!rename(oldFile, newFile) && i > 0) { + size_t len = 18 + strlen(newFile) + 1; + char cmd[len]; + + snprintf(cmd, sizeof(cmd), "gzip -f %s", newFile); + system(cmd); + } + } + /* newFile == "f.0" now */ + sprintf(newFile, "%s.0", f->f_un.f_fname); rename(f->f_un.f_fname, newFile); close(f->f_file); f->f_file = open(f->f_un.f_fname, O_WRONLY | O_APPEND | O_CREAT | O_NONBLOCK | O_NOCTTY, 0644); From bc92e860ef1df5af04bcdea6201d62ee7f3d4e9d Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Mon, 24 Sep 2018 17:03:54 +0200 Subject: [PATCH 02/10] Initial support for per log file rotate size:count as last arg. Signed-off-by: Joachim Nilsson --- src/syslogd.c | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/src/syslogd.c b/src/syslogd.c index bbcdb32..b18459e 100644 --- a/src/syslogd.c +++ b/src/syslogd.c @@ -696,6 +696,8 @@ struct filed { int f_prevcount; /* repetition cnt of prevline */ size_t f_repeatcount; /* number of "repeated" msgs */ int f_flags; /* store some additional flags */ + int f_rotatecount; + int f_rotatesz; }; /* @@ -1857,19 +1859,19 @@ void logrotate(struct filed *f) { struct stat statf; - if (!RotateSz) + if (!f->f_rotatesz) return; fstat(f->f_file, &statf); /* bug (mostly harmless): can wrap around if file > 4gb */ - if (S_ISREG(statf.st_mode) && statf.st_size > RotateSz) { - if (RotateCnt > 0) { /* always 0..999 */ + if (S_ISREG(statf.st_mode) && statf.st_size > f->f_rotatesz) { + if (f->f_rotatecount > 0) { /* always 0..999 */ int len = strlen(f->f_un.f_fname) + 10 + 1; char oldFile[len]; char newFile[len]; /* First age zipped log files */ - for (int i = RotateCnt; i > 1; i--) { + for (int i = f->f_rotatecount; i > 1; i--) { snprintf(oldFile, len, "%s.%d.gz", f->f_un.f_fname, i - 1); snprintf(newFile, len, "%s.%d.gz", f->f_un.f_fname, i); @@ -2769,6 +2771,10 @@ void cfline(char *line, struct filed *f) f->f_flags = 0; } + /* default rotate from command line */ + f->f_rotatecount = RotateCnt; + f->f_rotatesz = RotateSz; + /* scan through the list of selectors */ for (p = line; *p && *p != '\t' && *p != ' ';) { @@ -2922,6 +2928,23 @@ void cfline(char *line, struct filed *f) case '|': case '/': + /* Look for optional per-file rotate BYTES:COUNT */ + for (q = p; !isspace(*q); q++) + ; + if (isspace(*q)) { + int sz = 0, cnt = 0; + + *q++ = 0; + while (*q == '\t' || *q == ' ') + q++; + + sscanf(q, "%d:%d", &sz, &cnt); + if (sz > 0 && cnt > 0) { + f->f_rotatecount = cnt; + f->f_rotatesz = sz; + } + } + (void)strcpy(f->f_un.f_fname, p); logit("filename: %s\n", p); /*ASP*/ if (syncfile) From 84437f88e3c72432d7f1ba877910c391c1517dcd Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Mon, 24 Sep 2018 17:28:26 +0200 Subject: [PATCH 03/10] Avoid for loop initial declarations May need to build on/for systems with quite old GCC version. Also, fixes build on Travis-CI. (Enabling C99 brings in a lot of other warnings that we'll take care of at a later stage.) Signed-off-by: Joachim Nilsson --- src/syslogd.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/syslogd.c b/src/syslogd.c index b18459e..028bab2 100644 --- a/src/syslogd.c +++ b/src/syslogd.c @@ -1867,11 +1867,12 @@ void logrotate(struct filed *f) if (S_ISREG(statf.st_mode) && statf.st_size > f->f_rotatesz) { if (f->f_rotatecount > 0) { /* always 0..999 */ int len = strlen(f->f_un.f_fname) + 10 + 1; + int i; char oldFile[len]; char newFile[len]; /* First age zipped log files */ - for (int i = f->f_rotatecount; i > 1; i--) { + for (i = f->f_rotatecount; i > 1; i--) { snprintf(oldFile, len, "%s.%d.gz", f->f_un.f_fname, i - 1); snprintf(newFile, len, "%s.%d.gz", f->f_un.f_fname, i); @@ -1880,7 +1881,7 @@ void logrotate(struct filed *f) } /* rename: f.8 -> f.9; f.7 -> f.8; ... */ - for (int i = 1; i > 0; i--) { + for (i = 1; i > 0; i--) { sprintf(oldFile, "%s.%d", f->f_un.f_fname, i - 1); sprintf(newFile, "%s.%d", f->f_un.f_fname, i); From 234cd4e669a3ae6d2a36f1d2f4cfcd1f9d44bd7f Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Mon, 24 Sep 2018 19:58:53 +0200 Subject: [PATCH 04/10] Add required feature flags for when building with -std=c11 These feature flags are required to build with modern GCC that default to newser C standard. However, we should never enforce a standard on the user -- there are far too many old/embedded systems out there with very old toolchains that just want bug fixes and minor features for an otherwise stable system. Signed-off-by: Joachim Nilsson --- src/Makefile.am | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 186268c..e9153ba 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -21,8 +21,10 @@ sbin_PROGRAMS = syslogd klogd AM_CFLAGS = -fomit-frame-pointer -fno-strength-reduce -Wno-unused-result syslogd_SOURCES = syslogd.c pidfile.c pidfile.h -syslogd_CPPFLAGS = -DSYSV -DFSSTND -DSYSLOG_INET -DINET6 -DNO_SCCS -DSYSLOG_UNIXAF +syslogd_CPPFLAGS = -DSYSV -DFSSTND -DSYSLOG_INET -DINET6 -DNO_SCCS -DSYSLOG_UNIXAF \ + -D_BSD_SOURCE -D_SVID_SOURCE -D_DEFAULT_SOURCE -klogd_SOURCES = klogd.c klogd.h syslog.c pidfile.c pidfile.h \ +klogd_SOURCES = klogd.c klogd.h syslog.c pidfile.c pidfile.h \ ksym.c ksyms.h ksym_mod.c module.h -klogd_CPPFLAGS = -DSYSV -DFSSTND -DALLOW_KERNEL_LOGGING +klogd_CPPFLAGS = -DSYSV -DFSSTND -DALLOW_KERNEL_LOGGING \ + -D_BSD_SOURCE -D_SVID_SOURCE -D_DEFAULT_SOURCE From 3039c285e3375c5869b4a4695c82e4e100d10ae3 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Mon, 24 Sep 2018 19:59:29 +0200 Subject: [PATCH 05/10] Add missing getopt.h include Signed-off-by: Joachim Nilsson --- src/klogd.c | 1 + src/syslogd.c | 1 + 2 files changed, 2 insertions(+) diff --git a/src/klogd.c b/src/klogd.c index 897879d..f6e92be 100644 --- a/src/klogd.c +++ b/src/klogd.c @@ -257,6 +257,7 @@ /* Includes. */ #include +#include #include #include #ifdef SYSV diff --git a/src/syslogd.c b/src/syslogd.c index 028bab2..4a178be 100644 --- a/src/syslogd.c +++ b/src/syslogd.c @@ -521,6 +521,7 @@ static char sccsid[] = "@(#)syslogd.c 5.27 (Berkeley) 10/10/88"; #define CONT_LINE 1 /* Allow continuation lines */ #include +#include #include #include #include From 179a137a1d61ab85c2a596c1487bd0a4e466cf23 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Mon, 24 Sep 2018 20:05:19 +0200 Subject: [PATCH 06/10] Update ReadMe and ChangeLog for upcoming v1.6 release Signed-off-by: Joachim Nilsson --- ChangeLog.md | 8 ++++++++ README.md | 5 +++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 832588a..005a12d 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -9,12 +9,19 @@ All relevant changes to the project are documented in this file. ### Changes - IPv6 support forward ported from FreeBSD, by John Haxby - Built-in log rotation support from BusyBox syslogd, disabled by default +- Automatic compression (gzip) of rotated files from .1 - Only read /etc/services when needed, by Martin Schulze - Improved sleep/alarm/mark implementation, by Alan Jenkins - Move hostname setting code from `main()` into `init()`, by Thomas Jarosch - Documentation update by Martin Schulze +- Reindent code to Linux KNF +- Touch PID file on `SIGHUP`, for integration with Finit +- Add systemd unit files +- Add GNU configure & build system + - Add configure flags to enable features and control behavior + - Detect systemd PATHs ### Fixes - Correct continuation line problems on 64bit architecture, @@ -138,6 +145,7 @@ All relevant changes to the project are documented in this file. [UNRELEASED]: https://github.com/troglobit/sysklogd/compare/v1.5...HEAD +[v1.6]: https://github.com/troglobit/sysklogd/compare/v1.5...v1.6 [v1.5.1]: https://github.com/troglobit/sysklogd/compare/v1.5...v1.5.1 [v1.5]: https://github.com/troglobit/sysklogd/compare/v1.4...v1.5 [v1.4]: https://github.com/troglobit/sysklogd/compare/v1.3...v1.4 diff --git a/README.md b/README.md index 96e1739..e267137 100644 --- a/README.md +++ b/README.md @@ -30,11 +30,12 @@ determine a `System.map` file. Main differences from the original sysklogd are: -- Built-in log-rotation support, useful for embedded systems. No need - for cron and a separate logrotate daemon +- Built-in log-rotation support, with compression by default, useful for + embedded systems. No need for cron and a separate logrotate daemon - FreeBSD socket receive buffer size patch - Avoid blocking `syslogd` if console is backed up - Touch PID file on `SIGHUP`, for integration with [Finit][] +- GNU configure & build system to ease porting/cross-compiling - Support for configuring remote syslog timeouot From 141b3d5c7c484e860e3a857820b54ec862f3262f Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Tue, 25 Sep 2018 09:39:16 +0200 Subject: [PATCH 07/10] Update man pages with info on new per-file log rotation settings Signed-off-by: Joachim Nilsson --- man/sysklogd.8 | 14 ++++++++++++-- man/syslog.conf.5 | 32 ++++++++++++++++++++++++++------ 2 files changed, 38 insertions(+), 8 deletions(-) diff --git a/man/sysklogd.8 b/man/sysklogd.8 index 65f8714..b60330f 100644 --- a/man/sysklogd.8 +++ b/man/sysklogd.8 @@ -111,7 +111,12 @@ described by the people from OpenBSD at .BI "\-b " "size" This option controls the max size of files in the built-in log-rotation. When present on the command line it activates log rotation of all files -with the given maximum size. Default: disabled (0). +with the given maximum size. It is also possible to control log rotate +per log file, see +.BR syslog.conf (5) +for details. + +Default: disabled (0). .TP .BI "\-c " "count" This option controls the max number of files kept by the built-in @@ -119,7 +124,12 @@ log-rotation. To activate the built-in log rotation this option must be combined with the .BI "\-b" option. The number of files kept include both gzipped files and the -first rotated (not zipped) file. Default: 5. +first rotated (not zipped) file. It is also possible to control log +rotate per log file, see +.BR syslog.conf (5) +for details. + +Default: 5. .TP .B "\-d" Turns on debug mode. Using this the daemon will not proceed a diff --git a/man/syslog.conf.5 b/man/syslog.conf.5 index 4327a17..96f6758 100644 --- a/man/syslog.conf.5 +++ b/man/syslog.conf.5 @@ -30,13 +30,20 @@ for logging. For special features see the .BR sysklogd (8) manpage. -Every rule consists of two fields, a +Every rule consists of two fields, a .I selector -field and an -.I action -field. These two fields are separated by one or more spaces or -tabs. The selector field specifies a pattern of facilities and -priorities belonging to the specified action. +field an +.I action +and an optional +.I logrotate +field. The fields are separated by one or more spaces or tabs. The +selector field specifies a pattern of facilities and priorities +belonging to the specified action. The action details where or what to +do with the selected input. The optional logrotate field is only for +files and details the max SIZE:COUNT a file can reach before it is +rotated, and later compressed. The log rotated feature is mostly +intended for embedded systems that do not want to have cron and a +separate log rotate daemon. Lines starting with a hash mark (``#'') and empty lines are ignored. @@ -326,6 +333,19 @@ and store them in the file # *.=info;*.=notice;\\ mail.none /var/log/messages +.fi +.LP +The following is almost the same but will also log rotate and compress +aged out messages. Notice the leading '-' to ensure the file is flushed +to disk after each message. + +.IP +.nf +# Log all messages, including kernel, to messages file +# rotated every 100 kiB and keep up to 10 aged out and +# compressed files. +*.*;kern,kern.none -/log/messages 1048576:10 + .fi .LP This lets the From ab24b2efffc235c6625a52ebbb56afd94c067f6f Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Tue, 25 Sep 2018 10:10:28 +0200 Subject: [PATCH 08/10] Add configurable retry timeout for remote syslog servers Signed-off-by: Joachim Nilsson --- configure.ac | 10 ++++++++++ src/syslogd.c | 3 +-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 7eb2181..012447a 100644 --- a/configure.ac +++ b/configure.ac @@ -31,6 +31,10 @@ AC_HEADER_STDC # Check for required packages PKG_PROG_PKG_CONFIG +AC_ARG_WITH(suspend-time, + AS_HELP_STRING([--with-suspend-time=SEC], [Retry timeout for remote syslogd servers, default: 180]), + [suspend_time=$withval], [suspend_time='no']) + AC_ARG_WITH(klogd-delay, AS_HELP_STRING([--with-klogd-delay=SEC], [when started at the same time as syslogd, default: 0]), [klogd_delay=$withval], [klogd_delay='no']) @@ -43,6 +47,12 @@ AC_ARG_WITH(systemd, [AS_HELP_STRING([--with-systemd=DIR], [Directory for systemd service files])],, [with_systemd=auto]) +AS_IF([test "x$suspend_time" != "xno"],[ + AS_IF([test "x$suspend_time" = "xyes"],[ + AC_MSG_ERROR([Must supply argument])]) + ] + AC_DEFINE_UNQUOTED(INET_SUSPEND_TIME, $suspend_time, [Retry timeout for remote syslgod servers, default: 180])) + AS_IF([test "x$klogd_delay" != "xno"],[ AS_IF([test "x$klogd_delay" = "xyes"],[ AC_MSG_ERROR([Must supply argument])]) diff --git a/src/syslogd.c b/src/syslogd.c index 4a178be..cd269b5 100644 --- a/src/syslogd.c +++ b/src/syslogd.c @@ -1965,8 +1965,7 @@ void fprintlog(struct filed *f, char *from, int flags, char *msg) logit(" %s\n", f->f_un.f_forw.f_hname); logit("Forwarding suspension not over, time " "left: %d.\n", - INET_SUSPEND_TIME - - fwd_suspend); + INET_SUSPEND_TIME - fwd_suspend); } break; From 98f6f3ae3df709f8b048426d5f686b6693dcb4e1 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Tue, 25 Sep 2018 10:16:17 +0200 Subject: [PATCH 09/10] Minor, spelling Signed-off-by: Joachim Nilsson --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e267137..37bc195 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ Main differences from the original sysklogd are: - Avoid blocking `syslogd` if console is backed up - Touch PID file on `SIGHUP`, for integration with [Finit][] - GNU configure & build system to ease porting/cross-compiling -- Support for configuring remote syslog timeouot +- Support for configuring remote syslog timeout Build & Install From ea24aa537862e8287ed32a146ee47ae54fa1ea28 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Tue, 25 Sep 2018 17:14:10 +0200 Subject: [PATCH 10/10] Usability, size modifiers to log rotate: 100k:5, 1G:3, and 100M:5 This applies to both the command line '-b SIZE' option and the optional per log file setting. Modifiers supported are: k, M, G Signed-off-by: Joachim Nilsson --- man/sysklogd.8 | 3 +++ man/syslog.conf.5 | 9 +++++---- src/syslogd.c | 45 +++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 49 insertions(+), 8 deletions(-) diff --git a/man/sysklogd.8 b/man/sysklogd.8 index b60330f..0a63a8f 100644 --- a/man/sysklogd.8 +++ b/man/sysklogd.8 @@ -116,6 +116,9 @@ per log file, see .BR syslog.conf (5) for details. +The size argument takes optional modifiers; k, M, G. E.g., 100M is +100MB, 42k is 42 kB, etc. + Default: disabled (0). .TP .BI "\-c " "count" diff --git a/man/syslog.conf.5 b/man/syslog.conf.5 index 96f6758..1bb1f03 100644 --- a/man/syslog.conf.5 +++ b/man/syslog.conf.5 @@ -336,15 +336,16 @@ and store them in the file .fi .LP The following is almost the same but will also log rotate and compress -aged out messages. Notice the leading '-' to ensure the file is flushed -to disk after each message. +aged out messages. The size argument takes the same modifiers as the +command line '-b' option. Notice the leading '-' to ensure the file is +flushed to disk after each message. .IP .nf # Log all messages, including kernel, to messages file -# rotated every 100 kiB and keep up to 10 aged out and +# rotated every 100 kB and keep up to 10 aged out and # compressed files. -*.*;kern,kern.none -/log/messages 1048576:10 +*.*;kern,kern.none -/log/messages 100k:10 .fi .LP diff --git a/src/syslogd.c b/src/syslogd.c index cd269b5..c5949a1 100644 --- a/src/syslogd.c +++ b/src/syslogd.c @@ -842,6 +842,7 @@ void die(int sig); void doexit(int sig); #endif void init(); +static int strtobytes(char *arg); void cfline(char *line, struct filed *f); int decode(char *name, struct code *codetab); static void logit(char *, ...); @@ -930,7 +931,7 @@ int main(int argc, char *argv[]) break; case 'b': /* Max file size (bytes) before rotating log file. */ - RotateSz = atoi(optarg); + RotateSz = strtobytes(optarg); break; case 'c': /* Number (count) of log files to keep. */ @@ -2744,6 +2745,35 @@ void init(void) } /* balance parentheses for emacs */ #endif +static int strtobytes(char *arg) +{ + int mod = 0, bytes; + size_t pos; + + if (!arg) + return -1; + + pos = strspn(arg, "0123456789"); + if (arg[pos] != 0) { + if (arg[pos] == 'G') + mod = 3; + else if (arg[pos] == 'M') + mod = 2; + else if (arg[pos] == 'k') + mod = 1; + else + return -1; + + arg[pos] = 0; + } + + bytes = atoi(arg); + while (mod--) + bytes *= 1000; + + return bytes; +} + /* * Crack a configuration file line */ @@ -2930,16 +2960,23 @@ void cfline(char *line, struct filed *f) case '|': case '/': /* Look for optional per-file rotate BYTES:COUNT */ - for (q = p; !isspace(*q); q++) + for (q = p; *q && !isspace(*q); q++) ; if (isspace(*q)) { + char *c; int sz = 0, cnt = 0; *q++ = 0; - while (*q == '\t' || *q == ' ') + while (*q && isspace(*q)) q++; - sscanf(q, "%d:%d", &sz, &cnt); + c = strchr(q, ':'); + if (c) { + *c++ = 0; + cnt = atoi(c); + } + + sz = strtobytes(q); if (sz > 0 && cnt > 0) { f->f_rotatecount = cnt; f->f_rotatesz = sz;