chiark / gitweb /
journal-gatewayd: minor cleanup
[elogind.git] / src / journal / journald-syslog.c
index 91664762e64a2706ead10ffdbb9343fc329bd286..afddca3630097162bc7c6677efaa3b309f1d263b 100644 (file)
 ***/
 
 #include <unistd.h>
+#include <stddef.h>
 #include <sys/epoll.h>
 
+#include "systemd/sd-messages.h"
 #include "socket-util.h"
-#include "journald.h"
+#include "journald-server.h"
 #include "journald-syslog.h"
 #include "journald-kmsg.h"
+#include "journald-console.h"
+
+/* Warn once every 30s if we missed syslog message */
+#define WARN_FORWARD_SYSLOG_MISSED_USEC (30 * USEC_PER_SEC)
 
 static void forward_syslog_iovec(Server *s, const struct iovec *iovec, unsigned n_iovec, struct ucred *ucred, struct timeval *tv) {
         struct msghdr msghdr;
@@ -72,8 +78,10 @@ static void forward_syslog_iovec(Server *s, const struct iovec *iovec, unsigned
 
         /* The socket is full? I guess the syslog implementation is
          * too slow, and we shouldn't wait for that... */
-        if (errno == EAGAIN)
+        if (errno == EAGAIN) {
+                s->n_forward_syslog_missed++;
                 return;
+        }
 
         if (ucred && errno == ESRCH) {
                 struct ucred u;
@@ -89,8 +97,10 @@ static void forward_syslog_iovec(Server *s, const struct iovec *iovec, unsigned
                 if (sendmsg(s->syslog_fd, &msghdr, MSG_NOSIGNAL) >= 0)
                         return;
 
-                if (errno == EAGAIN)
+                if (errno == EAGAIN) {
+                        s->n_forward_syslog_missed++;
                         return;
+                }
         }
 
         if (errno != ENOENT)
@@ -175,7 +185,7 @@ int syslog_fixup_facility(int priority) {
         return priority;
 }
 
-void syslog_read_identifier(const char **buf, char **identifier, char **pid) {
+size_t syslog_parse_identifier(const char **buf, char **identifier, char **pid) {
         const char *p;
         char *t;
         size_t l, e;
@@ -191,7 +201,7 @@ void syslog_read_identifier(const char **buf, char **identifier, char **pid) {
 
         if (l <= 0 ||
             p[l-1] != ':')
-                return;
+                return 0;
 
         e = l;
         l--;
@@ -221,8 +231,115 @@ void syslog_read_identifier(const char **buf, char **identifier, char **pid) {
         if (t)
                 *identifier = t;
 
+        e += strspn(p + e, WHITESPACE);
         *buf = p + e;
-        *buf += strspn(*buf, WHITESPACE);
+        return e;
+}
+
+void syslog_parse_priority(char **p, int *priority) {
+        int a = 0, b = 0, c = 0;
+        int k;
+
+        assert(p);
+        assert(*p);
+        assert(priority);
+
+        if ((*p)[0] != '<')
+                return;
+
+        if (!strchr(*p, '>'))
+                return;
+
+        if ((*p)[2] == '>') {
+                c = undecchar((*p)[1]);
+                k = 3;
+        } else if ((*p)[3] == '>') {
+                b = undecchar((*p)[1]);
+                c = undecchar((*p)[2]);
+                k = 4;
+        } else if ((*p)[4] == '>') {
+                a = undecchar((*p)[1]);
+                b = undecchar((*p)[2]);
+                c = undecchar((*p)[3]);
+                k = 5;
+        } else
+                return;
+
+        if (a < 0 || b < 0 || c < 0)
+                return;
+
+        *priority = a*100+b*10+c;
+        *p += k;
+}
+
+static void syslog_skip_date(char **buf) {
+        enum {
+                LETTER,
+                SPACE,
+                NUMBER,
+                SPACE_OR_NUMBER,
+                COLON
+        } sequence[] = {
+                LETTER, LETTER, LETTER,
+                SPACE,
+                SPACE_OR_NUMBER, NUMBER,
+                SPACE,
+                SPACE_OR_NUMBER, NUMBER,
+                COLON,
+                SPACE_OR_NUMBER, NUMBER,
+                COLON,
+                SPACE_OR_NUMBER, NUMBER,
+                SPACE
+        };
+
+        char *p;
+        unsigned i;
+
+        assert(buf);
+        assert(*buf);
+
+        p = *buf;
+
+        for (i = 0; i < ELEMENTSOF(sequence); i++, p++) {
+
+                if (!*p)
+                        return;
+
+                switch (sequence[i]) {
+
+                case SPACE:
+                        if (*p != ' ')
+                                return;
+                        break;
+
+                case SPACE_OR_NUMBER:
+                        if (*p == ' ')
+                                break;
+
+                        /* fall through */
+
+                case NUMBER:
+                        if (*p < '0' || *p > '9')
+                                return;
+
+                        break;
+
+                case LETTER:
+                        if (!(*p >= 'A' && *p <= 'Z') &&
+                            !(*p >= 'a' && *p <= 'z'))
+                                return;
+
+                        break;
+
+                case COLON:
+                        if (*p != ':')
+                                return;
+                        break;
+
+                }
+        }
+
+        *buf = p;
 }
 
 void server_process_syslog_message(
@@ -250,7 +367,7 @@ void server_process_syslog_message(
                 forward_syslog_raw(s, priority, orig, ucred, tv);
 
         syslog_skip_date((char**) &buf);
-        syslog_read_identifier(&buf, &identifier, &pid);
+        syslog_parse_identifier(&buf, &identifier, &pid);
 
         if (s->forward_to_kmsg)
                 server_forward_kmsg(s, priority, identifier, buf, ucred);
@@ -356,3 +473,20 @@ int server_open_syslog_socket(Server *s) {
 
         return 0;
 }
+
+void server_maybe_warn_forward_syslog_missed(Server *s) {
+        usec_t n;
+        assert(s);
+
+        if (s->n_forward_syslog_missed <= 0)
+                return;
+
+        n = now(CLOCK_MONOTONIC);
+        if (s->last_warn_forward_syslog_missed + WARN_FORWARD_SYSLOG_MISSED_USEC > n)
+                return;
+
+        server_driver_message(s, SD_MESSAGE_FORWARD_SYSLOG_MISSED, "Forwarding to syslog missed %u messages.", s->n_forward_syslog_missed);
+
+        s->n_forward_syslog_missed = 0;
+        s->last_warn_forward_syslog_missed = n;
+}