syslogd: optional support for dropping dups. closes bug 436.
authorDenis Vlasenko <vda.linux@googlemail.com>
Tue, 26 Feb 2008 20:13:52 +0000 (20:13 -0000)
committerDenis Vlasenko <vda.linux@googlemail.com>
Tue, 26 Feb 2008 20:13:52 +0000 (20:13 -0000)
include/usage.h
sysklogd/Config.in
sysklogd/syslogd.c

index 3ef4211971f72dcaccdfeab74c35d4caeb51ae67..6b54a1266b746f9e30b7b10f33cdfd39c2d1cf4a 100644 (file)
@@ -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"
index 78097eea1f2d05c590325b2c1b9d755800f37541..45f86ed625b936d6b1a09cfd98676910f50fb59a 100644 (file)
@@ -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
index 0d004bc27caa603146d1e782c097c750d681173e..e54ade7fd209c2924b431dc46d621eb409be5e8d 100644 (file)
@@ -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 (;;) */
 }