diff --git a/include/usage.h b/include/usage.h index 3ef421197..6b54a1266 100644 --- a/include/usage.h +++ b/include/usage.h @@ -3686,22 +3686,24 @@ USE_FEATURE_RUN_PARTS_FANCY("\n -l Prints names of all matching files even when "[OPTION]..." #define syslogd_full_usage \ "System logging utility.\n" \ - "Note that this version of syslogd ignores /etc/syslog.conf." \ - "\n\nOptions:" \ - "\n -n Run in foreground" \ - "\n -O FILE Log to given file (default=/var/log/messages)" \ - "\n -l n Set local log level" \ - "\n -S Smaller logging output" \ + "Note that this version of syslogd ignores /etc/syslog.conf.\n" \ + "\nOptions:" \ + "\n -n Run in foreground" \ + "\n -O FILE Log to given file (default=/var/log/messages)" \ + "\n -l n Set local log level" \ + "\n -S Smaller logging output" \ USE_FEATURE_ROTATE_LOGFILE( \ - "\n -s SIZE Max size (KB) before rotate (default=200KB, 0=off)" \ - "\n -b NUM Number of rotated logs to keep (default=1, max=99, 0=purge)") \ + "\n -s SIZE Max size (KB) before rotate (default=200KB, 0=off)" \ + "\n -b NUM Number of rotated logs to keep (default=1, max=99, 0=purge)") \ USE_FEATURE_REMOTE_LOG( \ - "\n -R HOST[:PORT] Log to IP or hostname on PORT (default PORT=514/UDP)" \ - "\n -L Log locally and via network (default is network only if -R)") \ + "\n -R HOST[:PORT] Log to IP or hostname on PORT (default PORT=514/UDP)" \ + "\n -L Log locally and via network (default is network only if -R)") \ + USE_FEATURE_SYSLOGD_DUP( \ + "\n -D Drop duplicates") \ USE_FEATURE_IPC_SYSLOG( \ - "\n -C[size(KiB)] Log to shared mem buffer (read it using logread)") + "\n -C[size(KiB)] Log to shared mem buffer (read it using logread)") /* NB: -Csize shouldn't have space (because size is optional) */ -/* "\n -m MIN Minutes between MARK lines (default=20, 0=off)" */ +/* "\n -m MIN Minutes between MARK lines (default=20, 0=off)" */ #define syslogd_example_usage \ "$ syslogd -R masterlog:514\n" \ "$ syslogd -R 192.168.1.1:601\n" diff --git a/sysklogd/Config.in b/sysklogd/Config.in index 78097eea1..45f86ed62 100644 --- a/sysklogd/Config.in +++ b/sysklogd/Config.in @@ -42,6 +42,14 @@ config FEATURE_REMOTE_LOG measure to prevent system logs from being tampered with by an intruder. +config FEATURE_SYSLOGD_DUP + bool "Support -D (drop dups) option" + default n + depends on SYSLOGD + help + Option -D instructs syslogd to drop consecutive messages + which are totally the same. + config FEATURE_IPC_SYSLOG bool "Circular Buffer support" default n diff --git a/sysklogd/syslogd.c b/sysklogd/syslogd.c index 0d004bc27..e54ade7fd 100644 --- a/sysklogd/syslogd.c +++ b/sysklogd/syslogd.c @@ -101,7 +101,7 @@ struct globals { char *hostname; /* We recv into recvbuf... */ - char recvbuf[MAX_READ]; + char recvbuf[MAX_READ * (1 + ENABLE_FEATURE_SYSLOGD_DUP)]; /* ...then copy to parsebuf, escaping control chars */ /* (can grow x2 max) */ char parsebuf[MAX_READ*2]; @@ -152,6 +152,7 @@ enum { USE_FEATURE_REMOTE_LOG( OPTBIT_remote ,) // -R USE_FEATURE_REMOTE_LOG( OPTBIT_locallog ,) // -L USE_FEATURE_IPC_SYSLOG( OPTBIT_circularlog,) // -C + USE_FEATURE_SYSLOGD_DUP( OPTBIT_dup ,) // -D OPT_mark = 1 << OPTBIT_mark , OPT_nofork = 1 << OPTBIT_nofork , @@ -163,13 +164,15 @@ enum { OPT_remotelog = USE_FEATURE_REMOTE_LOG( (1 << OPTBIT_remote )) + 0, OPT_locallog = USE_FEATURE_REMOTE_LOG( (1 << OPTBIT_locallog )) + 0, OPT_circularlog = USE_FEATURE_IPC_SYSLOG( (1 << OPTBIT_circularlog)) + 0, + OPT_dup = USE_FEATURE_SYSLOGD_DUP( (1 << OPTBIT_dup )) + 0, }; #define OPTION_STR "m:nO:l:S" \ USE_FEATURE_ROTATE_LOGFILE("s:" ) \ USE_FEATURE_ROTATE_LOGFILE("b:" ) \ USE_FEATURE_REMOTE_LOG( "R:" ) \ USE_FEATURE_REMOTE_LOG( "L" ) \ - USE_FEATURE_IPC_SYSLOG( "C::") + USE_FEATURE_IPC_SYSLOG( "C::") \ + USE_FEATURE_SYSLOGD_DUP( "D" ) #define OPTION_DECL *opt_m, *opt_l \ USE_FEATURE_ROTATE_LOGFILE(,*opt_s) \ USE_FEATURE_ROTATE_LOGFILE(,*opt_b) \ @@ -538,6 +541,13 @@ static void do_syslogd(void) ATTRIBUTE_NORETURN; static void do_syslogd(void) { int sock_fd; +#if ENABLE_FEATURE_SYSLOGD_DUP + int last_sz = -1; + char *last_buf; + char *recvbuf = G.recvbuf; +#else +#define recvbuf (G.recvbuf) +#endif /* Set up signal handlers */ bb_signals(0 @@ -561,8 +571,16 @@ static void do_syslogd(void) for (;;) { size_t sz; + +#if ENABLE_FEATURE_SYSLOGD_DUP + last_buf = recvbuf; + if (recvbuf == G.recvbuf) + recvbuf = G.recvbuf + MAX_READ; + else + recvbuf = G.recvbuf; +#endif read_again: - sz = safe_read(sock_fd, G.recvbuf, MAX_READ - 1); + sz = safe_read(sock_fd, recvbuf, MAX_READ - 1); if (sz < 0) bb_perror_msg_and_die("read from /dev/log"); @@ -577,11 +595,16 @@ static void do_syslogd(void) * IOW: newline is passed verbatim! * I take it to mean that it's syslogd's job * to make those look identical in the log files. */ - if (G.recvbuf[sz-1] != '\0' && G.recvbuf[sz-1] != '\n') + if (recvbuf[sz-1] != '\0' && recvbuf[sz-1] != '\n') break; sz--; } - /* TODO: maybe suppress duplicates? */ +#if ENABLE_FEATURE_SYSLOGD_DUP + if ((option_mask32 & OPT_dup) && (sz == last_sz)) + if (memcmp(last_buf, recvbuf, sz) == 0) + continue; + last_sz = sz; +#endif #if ENABLE_FEATURE_REMOTE_LOG /* We are not modifying log messages in any way before send */ /* Remote site cannot trust _us_ anyway and need to do validation again */ @@ -593,18 +616,18 @@ static void do_syslogd(void) } /* Stock syslogd sends it '\n'-terminated * over network, mimic that */ - G.recvbuf[sz] = '\n'; + recvbuf[sz] = '\n'; /* send message to remote logger, ignore possible error */ /* TODO: on some errors, close and set G.remoteFD to -1 * so that DNS resolution and connect is retried? */ - sendto(G.remoteFD, G.recvbuf, sz+1, MSG_DONTWAIT, + sendto(G.remoteFD, recvbuf, sz+1, MSG_DONTWAIT, &G.remoteAddr->u.sa, G.remoteAddr->len); no_luck: ; } #endif if (!ENABLE_FEATURE_REMOTE_LOG || (option_mask32 & OPT_locallog)) { - G.recvbuf[sz] = '\0'; /* ensure it *is* NUL terminated */ - split_escape_and_log(G.recvbuf, sz); + recvbuf[sz] = '\0'; /* ensure it *is* NUL terminated */ + split_escape_and_log(recvbuf, sz); } } /* for (;;) */ }