From 949e80f150c9ea6f9b10c93dff998434e58ad5e6 Mon Sep 17 00:00:00 2001 From: Steffen Nurpmeso Date: Thu, 20 Jan 2022 14:34:51 +0100 Subject: [PATCH 1/3] Implement forced log file rotation upon SIGUSR2 --- man/syslogd.8 | 4 ++ src/syslogd.c | 121 ++++++++++++++++++++++++++++++++------------------ 2 files changed, 82 insertions(+), 43 deletions(-) diff --git a/man/syslogd.8 b/man/syslogd.8 index 3aa1e7c..5819875 100644 --- a/man/syslogd.8 +++ b/man/syslogd.8 @@ -483,6 +483,10 @@ SIGTERM. .It USR1 In debug mode this switches debugging on/off. In normal operation it is ignored. +.It USR2 +.Nm +will rotate all files for which rotation is configured when receiving +this signal. .El .Pp For convenience the PID is by default stored in diff --git a/src/syslogd.c b/src/syslogd.c index 6827432..df96ba5 100644 --- a/src/syslogd.c +++ b/src/syslogd.c @@ -103,6 +103,7 @@ char ctty[] = _PATH_CONSOLE; static volatile sig_atomic_t debugging_on; static volatile sig_atomic_t restart; +static volatile sig_atomic_t rotate_signal; /* * Intervals at which we flush out "message repeated" messages, @@ -169,6 +170,9 @@ static void parsemsg(const char *from, char *msg); static int opensys(const char *file); static void printsys(char *msg); static void logmsg(struct buf_msg *buffer); +static void logrotate(struct filed *f); +static void rotate_file(struct filed *f); +static void rotate_all_files(void); static void fprintlog_first(struct filed *f, struct buf_msg *buffer); static void fprintlog_successive(struct filed *f, int flags); void endtty(); @@ -192,6 +196,7 @@ static void notifier_add(struct notifiers *newn, const char *program); static void notifier_invoke(const char *logfile); static void notifier_free_all(void); void reload(int); +static void signal_rotate(int sig); static int validate(struct sockaddr *sa, const char *hname); static int waitdaemon(int); static void timedout(int); @@ -589,6 +594,12 @@ no_klogd: continue; } + if (rotate_signal > 0) { + rotate_signal = 0; + logit("\nReceived SIGUSR2, forcing log rotation.\n"); + rotate_all_files(); + } + if (rc < 0 && errno != EINTR) ERR("select()"); @@ -1560,7 +1571,7 @@ static void logmsg(struct buf_msg *buffer) sigprocmask(SIG_UNBLOCK, &mask, NULL); } -void logrotate(struct filed *f) +static void logrotate(struct filed *f) { struct stat statf; @@ -1571,52 +1582,66 @@ void logrotate(struct filed *f) return; /* bug (mostly harmless): can wrap around if file > 4gb */ - 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 + 5; - int i; - char oldFile[len]; - char newFile[len]; + if (S_ISREG(statf.st_mode) && statf.st_size > f->f_rotatesz) + rotate_file(f); +} - /* First age zipped log files */ - 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); +static void rotate_file(struct filed *f) +{ + if (f->f_rotatecount > 0) { /* always 0..999 */ + int len = strlen(f->f_un.f_fname) + 10 + 5; + int i; + char oldFile[len]; + char newFile[len]; - /* ignore errors - file might be missing */ - (void)rename(oldFile, newFile); - } + /* First age zipped log files */ + 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); - /* rename: f.8 -> f.9; f.7 -> f.8; ... */ - for (i = 1; i > 0; i--) { - snprintf(oldFile, len, "%s.%d", f->f_un.f_fname, i - 1); - snprintf(newFile, len, "%s.%d", f->f_un.f_fname, i); - - if (!rename(oldFile, newFile) && i > 0) { - size_t clen = 18 + strlen(newFile) + 1; - char cmd[clen]; - - snprintf(cmd, sizeof(cmd), "gzip -f %s", newFile); - system(cmd); - } - } - - /* newFile == "f.0" now */ - snprintf(newFile, len, "%s.0", f->f_un.f_fname); - (void)rename(f->f_un.f_fname, newFile); - close(f->f_file); - - f->f_file = open(f->f_un.f_fname, O_CREATE | O_NONBLOCK | O_NOCTTY, 0644); - if (f->f_file < 0) { - f->f_type = F_UNUSED; - ERR("Failed re-opening log file %s after rotation", f->f_un.f_fname); - return; - } - - if (!SIMPLEQ_EMPTY(¬head)) - notifier_invoke(f->f_un.f_fname); + /* ignore errors - file might be missing */ + (void)rename(oldFile, newFile); } - ftruncate(f->f_file, 0); + + /* rename: f.8 -> f.9; f.7 -> f.8; ... */ + for (i = 1; i > 0; i--) { + snprintf(oldFile, len, "%s.%d", f->f_un.f_fname, i - 1); + snprintf(newFile, len, "%s.%d", f->f_un.f_fname, i); + + if (!rename(oldFile, newFile) && i > 0) { + size_t clen = 18 + strlen(newFile) + 1; + char cmd[clen]; + + snprintf(cmd, sizeof(cmd), "gzip -f %s", newFile); + system(cmd); + } + } + + /* newFile == "f.0" now */ + snprintf(newFile, len, "%s.0", f->f_un.f_fname); + (void)rename(f->f_un.f_fname, newFile); + close(f->f_file); + + f->f_file = open(f->f_un.f_fname, O_CREATE | O_NONBLOCK | O_NOCTTY, 0644); + if (f->f_file < 0) { + f->f_type = F_UNUSED; + ERR("Failed re-opening log file %s after rotation", f->f_un.f_fname); + return; + } + + if (!SIMPLEQ_EMPTY(¬head)) + notifier_invoke(f->f_un.f_fname); + } + ftruncate(f->f_file, 0); +} + +static void rotate_all_files(void) +{ + struct filed *f; + + SIMPLEQ_FOREACH(f, &fhead, f_link) { + if (f->f_type == F_FILE && f->f_rotatesz) + rotate_file(f); } } @@ -2443,6 +2468,7 @@ static void signal_init(void) SIGNAL(SIGINT, Debug ? die : SIG_IGN); SIGNAL(SIGQUIT, Debug ? die : SIG_IGN); SIGNAL(SIGUSR1, Debug ? debug_switch : SIG_IGN); + SIGNAL(SIGUSR2, signal_rotate); SIGNAL(SIGXFSZ, SIG_IGN); SIGNAL(SIGHUP, reload); SIGNAL(SIGCHLD, reapchild); @@ -3445,6 +3471,15 @@ void reload(int signo) restart++; } +/* + * SIGUSR2: forced rotation for so-configured files as soon as possible. + */ +static void signal_rotate(int sig) +{ + (void)sig; + rotate_signal++; +} + /** * Local Variables: * indent-tabs-mode: t From 0bc4c82bae8c051a6ab2144c20a210704324ca19 Mon Sep 17 00:00:00 2001 From: Steffen Nurpmeso Date: Thu, 20 Jan 2022 14:35:27 +0100 Subject: [PATCH 2/3] Test for "Implement forced log file rotation upon SIGUSR2" --- test/Makefile.am | 4 +- test/rotate_all.sh | 95 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+), 1 deletion(-) create mode 100755 test/rotate_all.sh diff --git a/test/Makefile.am b/test/Makefile.am index 5282297..3ea946b 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -1,5 +1,6 @@ EXTRA_DIST = lib.sh opts.sh -EXTRA_DIST += api.sh local.sh unicode.sh remote.sh fwd.sh mark.sh notify.sh +EXTRA_DIST += api.sh local.sh unicode.sh remote.sh fwd.sh mark.sh \ + notify.sh rotate_all.sh CLEANFILES = *~ *.trs *.log TEST_EXTENSIONS = .sh TESTS_ENVIRONMENT= unshare -mrun @@ -18,5 +19,6 @@ TESTS += api.sh TESTS += fwd.sh TESTS += mark.sh TESTS += notify.sh +TESTS += rotate_all.sh programs: $(check_PROGRAMS) diff --git a/test/rotate_all.sh b/test/rotate_all.sh new file mode 100755 index 0000000..021e978 --- /dev/null +++ b/test/rotate_all.sh @@ -0,0 +1,95 @@ +#!/bin/sh +set -x + +if [ x"${srcdir}" = x ]; then + srcdir=. +fi +. ${srcdir}/lib.sh + +NOT1=${DIR}/${NM}-1.sh +echo $NOT1 > /tmp/Xxxxx +NOT1STAMP=${DIR}/${NM}-1.stamp +NOT2=${DIR}/${NM}-2.sh +NOT2STAMP=${DIR}/${NM}-2.stamp + +printf '#!/bin/sh -\necho script 1: $* > '${NOT1STAMP}'\n' > ${NOT1} +chmod 0755 ${NOT1} + +cat < ${CONF} +notify ${NOT1} +*.* -${LOG} ;rotate=10k:2,RFC5424 +*.* -${LOG}X ;rotate=10k:2,RFC5424 +EOF + +../src/syslogd -m1 -b :${PORT2} -d -sF -f ${CONF} -p ${SOCK2} -p ${ALTSOCK} -P ${PID2} >${LOG2} & +sleep 3 +cat ${PID2} >> "$DIR/PIDs" + +sleep 1 + +if grep 'notify '${NOT1} ${LOG2}; then + : +else + exit $? +fi + +if [ -x ../src/logger ]; then + : +else + exit 0 +fi + +kill -USR1 `cat ${PID2}` + +../src/logger -u ${SOCK2} notrotall-1 +kill -USR2 `cat ${PID2}` +sleep 1 # XXX async process sync? +if [ -f ${LOG}.0 ] && [ -f ${LOG}X.0 ] && + grep notrotall-1 ${LOG}.0 && + grep notrotall-1 ${LOG}X.0; then + : +else + exit 1 +fi + +rm -f ${NOT1STAMP} +../src/logger -u ${SOCK2} notrotall-2 +kill -USR2 `cat ${PID2}` +sleep 1 # XXX async process sync? +if [ -f ${LOG}.0 ] && [ -f ${LOG}X.0 ] && + [ -f ${LOG}.1.gz ] && [ -f ${LOG}X.1.gz ] && + grep notrotall-2 ${LOG}.0 && + grep notrotall-2 ${LOG}X.0 && + zgrep notrotall-1 ${LOG}.1.gz && + zgrep notrotall-1 ${LOG}X.1.gz; then + : +else + exit 1 +fi + +rm -f ${NOT1STAMP} +../src/logger -u ${SOCK2} notrotall-3 +kill -USR2 `cat ${PID2}` +sleep 1 # XXX async process sync? +if [ -f ${LOG}.0 ] && [ -f ${LOG}X.0 ] && + [ -f ${LOG}.1.gz ] && [ -f ${LOG}X.1.gz ] && + [ -f ${LOG}.2.gz ] && [ -f ${LOG}X.2.gz ] && + grep notrotall-3 ${LOG}.0 && + grep notrotall-3 ${LOG}X.0 && + zgrep notrotall-2 ${LOG}.1.gz && + zgrep notrotall-2 ${LOG}X.1.gz && + zgrep notrotall-1 ${LOG}.2.gz && + zgrep notrotall-1 ${LOG}X.2.gz; then + : +else + exit 1 +fi + +kill -9 `cat ${PID2}` + +sleep 1 # XXX synchronization of async process? +if [ -f ${LOG}.0 ] && grep 'script 1' ${NOT1STAMP}; then + : +else + exit 1 +fi From 908f1e6821fde11999652bd0590faa5edc8791be Mon Sep 17 00:00:00 2001 From: Steffen Nurpmeso Date: Sat, 12 Mar 2022 17:46:47 +0100 Subject: [PATCH 3/3] test/rotate_all.sh: address Joachim Wiberg comments (pull/46) --- test/rotate_all.sh | 80 +++++++++++++++++++++++----------------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/test/rotate_all.sh b/test/rotate_all.sh index 021e978..40ddea1 100755 --- a/test/rotate_all.sh +++ b/test/rotate_all.sh @@ -6,56 +6,49 @@ if [ x"${srcdir}" = x ]; then fi . ${srcdir}/lib.sh +[ -x ../src/logger ] || SKIP 'logger missing' +command -v zgrep >/dev/null 2>&1 || SKIP 'zgrep(1) missing' + NOT1=${DIR}/${NM}-1.sh -echo $NOT1 > /tmp/Xxxxx NOT1STAMP=${DIR}/${NM}-1.stamp NOT2=${DIR}/${NM}-2.sh NOT2STAMP=${DIR}/${NM}-2.stamp -printf '#!/bin/sh -\necho script 1: $* > '${NOT1STAMP}'\n' > ${NOT1} +printf '#!/bin/sh -\necho script 1: $* >> '${NOT1STAMP}'\n' > ${NOT1} chmod 0755 ${NOT1} -cat < ${CONF} +cat < ${CONFD}/rotate_all.conf notify ${NOT1} *.* -${LOG} ;rotate=10k:2,RFC5424 *.* -${LOG}X ;rotate=10k:2,RFC5424 EOF -../src/syslogd -m1 -b :${PORT2} -d -sF -f ${CONF} -p ${SOCK2} -p ${ALTSOCK} -P ${PID2} >${LOG2} & +setup + +rm -f ${NOT1STAMP} +../src/logger -u ${SOCK} notrotall-1 + +kill -USR2 `cat ${PID}` sleep 3 -cat ${PID2} >> "$DIR/PIDs" - -sleep 1 - -if grep 'notify '${NOT1} ${LOG2}; then - : -else - exit $? -fi - -if [ -x ../src/logger ]; then - : -else - exit 0 -fi - -kill -USR1 `cat ${PID2}` - -../src/logger -u ${SOCK2} notrotall-1 -kill -USR2 `cat ${PID2}` -sleep 1 # XXX async process sync? if [ -f ${LOG}.0 ] && [ -f ${LOG}X.0 ] && grep notrotall-1 ${LOG}.0 && grep notrotall-1 ${LOG}X.0; then : else - exit 1 + FAIL 'Missing log entries, I.' +fi +if [ -f ${NOT1STAMP} ] && grep 'script 1' ${NOT1STAMP} && + grep ${LOG} ${NOT1STAMP} && grep ${LOG}X ${NOT1STAMP}; then + : +else + FAIL 'Notifier did not run, I.' fi rm -f ${NOT1STAMP} -../src/logger -u ${SOCK2} notrotall-2 -kill -USR2 `cat ${PID2}` -sleep 1 # XXX async process sync? +../src/logger -u ${SOCK} notrotall-2 + +kill -USR2 `cat ${PID}` +sleep 3 if [ -f ${LOG}.0 ] && [ -f ${LOG}X.0 ] && [ -f ${LOG}.1.gz ] && [ -f ${LOG}X.1.gz ] && grep notrotall-2 ${LOG}.0 && @@ -64,13 +57,21 @@ if [ -f ${LOG}.0 ] && [ -f ${LOG}X.0 ] && zgrep notrotall-1 ${LOG}X.1.gz; then : else - exit 1 + FAIL 'Missing log entries, II.' +fi +if [ -f ${NOT1STAMP} ] && grep 'script 1' ${NOT1STAMP} && + grep ${LOG} ${NOT1STAMP} && grep ${LOG}X ${NOT1STAMP}; then + : +else + FAIL 'Notifier did not run, II.' fi +cp $NOT1STAMP /tmp/ rm -f ${NOT1STAMP} -../src/logger -u ${SOCK2} notrotall-3 -kill -USR2 `cat ${PID2}` -sleep 1 # XXX async process sync? +../src/logger -u ${SOCK} notrotall-3 + +kill -USR2 `cat ${PID}` +sleep 3 if [ -f ${LOG}.0 ] && [ -f ${LOG}X.0 ] && [ -f ${LOG}.1.gz ] && [ -f ${LOG}X.1.gz ] && [ -f ${LOG}.2.gz ] && [ -f ${LOG}X.2.gz ] && @@ -82,14 +83,13 @@ if [ -f ${LOG}.0 ] && [ -f ${LOG}X.0 ] && zgrep notrotall-1 ${LOG}X.2.gz; then : else - exit 1 + FAIL 'Missing log entries, III.' fi - -kill -9 `cat ${PID2}` - -sleep 1 # XXX synchronization of async process? -if [ -f ${LOG}.0 ] && grep 'script 1' ${NOT1STAMP}; then +if [ -f ${NOT1STAMP} ] && grep 'script 1' ${NOT1STAMP} && + grep ${LOG} ${NOT1STAMP} && grep ${LOG}X ${NOT1STAMP}; then : else - exit 1 + FAIL 'Notifier did not run, III.' fi + +OK