***/
#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;
/* 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;
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)
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;
if (l <= 0 ||
p[l-1] != ':')
- return;
+ return 0;
e = l;
l--;
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(
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);
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;
+}