chiark / gitweb /
journald: remove a number of malloc()s from the syslog message handling
[elogind.git] / src / journal / journald-syslog.c
index 000f5acc100b8637c6d74de0578462ad65abebf5..ce6c2a3af4f2bca112ce65de54fdde320725809d 100644 (file)
 
 #include "systemd/sd-messages.h"
 #include "socket-util.h"
+#include "selinux-util.h"
 #include "journald-server.h"
 #include "journald-syslog.h"
 #include "journald-kmsg.h"
 #include "journald-console.h"
+#include "journald-wall.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) {
+static void forward_syslog_iovec(Server *s, const struct iovec *iovec, unsigned n_iovec, const struct ucred *ucred, const struct timeval *tv) {
 
-        union sockaddr_union sa = {
+        static const union sockaddr_union sa = {
                 .un.sun_family = AF_UNIX,
                 .un.sun_path = "/run/systemd/journal/syslog",
         };
         struct msghdr msghdr = {
                 .msg_iov = (struct iovec *) iovec,
                 .msg_iovlen = n_iovec,
-                .msg_name = &sa,
+                .msg_name = (struct sockaddr*) &sa.sa,
                 .msg_namelen = offsetof(union sockaddr_union, un.sun_path)
-                               + sizeof("/run/systemd/journal/syslog") - 1,
+                               + strlen("/run/systemd/journal/syslog"),
         };
         struct cmsghdr *cmsg;
         union {
@@ -107,7 +109,7 @@ static void forward_syslog_iovec(Server *s, const struct iovec *iovec, unsigned
                 log_debug("Failed to forward syslog message: %m");
 }
 
-static void forward_syslog_raw(Server *s, int priority, const char *buffer, struct ucred *ucred, struct timeval *tv) {
+static void forward_syslog_raw(Server *s, int priority, const char *buffer, const struct ucred *ucred, const struct timeval *tv) {
         struct iovec iovec;
 
         assert(s);
@@ -120,7 +122,7 @@ static void forward_syslog_raw(Server *s, int priority, const char *buffer, stru
         forward_syslog_iovec(s, &iovec, 1, ucred, tv);
 }
 
-void server_forward_syslog(Server *s, int priority, const char *identifier, const char *message, struct ucred *ucred, struct timeval *tv) {
+void server_forward_syslog(Server *s, int priority, const char *identifier, const char *message, const struct ucred *ucred, const struct timeval *tv) {
         struct iovec iovec[5];
         char header_priority[6], header_time[64], header_pid[16];
         int n = 0;
@@ -157,7 +159,7 @@ void server_forward_syslog(Server *s, int priority, const char *identifier, cons
                         identifier = ident_buf;
                 }
 
-                snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) ucred->pid);
+                snprintf(header_pid, sizeof(header_pid), "["PID_FMT"]: ", ucred->pid);
                 char_array_0(header_pid);
 
                 if (identifier)
@@ -236,7 +238,7 @@ size_t syslog_parse_identifier(const char **buf, char **identifier, char **pid)
         return e;
 }
 
-void syslog_parse_priority(char **p, int *priority) {
+void syslog_parse_priority(const char **p, int *priority, bool with_facility) {
         int a = 0, b = 0, c = 0;
         int k;
 
@@ -265,10 +267,14 @@ void syslog_parse_priority(char **p, int *priority) {
         } else
                 return;
 
-        if (a < 0 || b < 0 || c < 0)
+        if (a < 0 || b < 0 || c < 0 ||
+            (!with_facility && (a || b || c > 7)))
                 return;
 
-        *priority = a*100+b*10+c;
+        if (with_facility)
+                *priority = a*100 + b*10 + c;
+        else
+                *priority = (*priority & LOG_FACMASK) | c;
         *p += k;
 }
 
@@ -345,23 +351,25 @@ static void syslog_skip_date(char **buf) {
 void server_process_syslog_message(
         Server *s,
         const char *buf,
-        struct ucred *ucred,
-        struct timeval *tv,
+        const struct ucred *ucred,
+        const struct timeval *tv,
         const char *label,
         size_t label_len) {
 
-        char *message = NULL, *syslog_priority = NULL, *syslog_facility = NULL, *syslog_identifier = NULL, *syslog_pid = NULL;
+        char syslog_priority[sizeof("PRIORITY=") + DECIMAL_STR_MAX(int)],
+             syslog_facility[sizeof("SYSLOG_FACILITY") + DECIMAL_STR_MAX(int)];
+        const char *message = NULL, *syslog_identifier = NULL, *syslog_pid = NULL;
         struct iovec iovec[N_IOVEC_META_FIELDS + 6];
         unsigned n = 0;
         int priority = LOG_USER | LOG_INFO;
-        char *identifier = NULL, *pid = NULL;
+        _cleanup_free_ char *identifier = NULL, *pid = NULL;
         const char *orig;
 
         assert(s);
         assert(buf);
 
         orig = buf;
-        syslog_parse_priority((char**) &buf, &priority);
+        syslog_parse_priority(&buf, &priority, true);
 
         if (s->forward_to_syslog)
                 forward_syslog_raw(s, priority, orig, ucred, tv);
@@ -375,52 +383,48 @@ void server_process_syslog_message(
         if (s->forward_to_console)
                 server_forward_console(s, priority, identifier, buf, ucred);
 
+        if (s->forward_to_wall)
+                server_forward_wall(s, priority, identifier, buf, ucred);
+
         IOVEC_SET_STRING(iovec[n++], "_TRANSPORT=syslog");
 
-        if (asprintf(&syslog_priority, "PRIORITY=%i", priority & LOG_PRIMASK) >= 0)
-                IOVEC_SET_STRING(iovec[n++], syslog_priority);
+        sprintf(syslog_priority, "PRIORITY=%i", priority & LOG_PRIMASK);
+        IOVEC_SET_STRING(iovec[n++], syslog_priority);
 
-        if (priority & LOG_FACMASK)
-                if (asprintf(&syslog_facility, "SYSLOG_FACILITY=%i", LOG_FAC(priority)) >= 0)
-                        IOVEC_SET_STRING(iovec[n++], syslog_facility);
+        if (priority & LOG_FACMASK) {
+                sprintf(syslog_facility, "SYSLOG_FACILITY=%i", LOG_FAC(priority));
+                IOVEC_SET_STRING(iovec[n++], syslog_facility);
+        }
 
         if (identifier) {
-                syslog_identifier = strappend("SYSLOG_IDENTIFIER=", identifier);
+                syslog_identifier = strappenda("SYSLOG_IDENTIFIER=", identifier);
                 if (syslog_identifier)
                         IOVEC_SET_STRING(iovec[n++], syslog_identifier);
         }
 
         if (pid) {
-                syslog_pid = strappend("SYSLOG_PID=", pid);
+                syslog_pid = strappenda("SYSLOG_PID=", pid);
                 if (syslog_pid)
                         IOVEC_SET_STRING(iovec[n++], syslog_pid);
         }
 
-        message = strappend("MESSAGE=", buf);
+        message = strappenda("MESSAGE=", buf);
         if (message)
                 IOVEC_SET_STRING(iovec[n++], message);
 
-        server_dispatch_message(s, iovec, n, ELEMENTSOF(iovec), ucred, tv, label, label_len, NULL, priority);
-
-        free(message);
-        free(identifier);
-        free(pid);
-        free(syslog_priority);
-        free(syslog_facility);
-        free(syslog_identifier);
-        free(syslog_pid);
+        server_dispatch_message(s, iovec, n, ELEMENTSOF(iovec), ucred, tv, label, label_len, NULL, priority, 0);
 }
 
 int server_open_syslog_socket(Server *s) {
-        int one, r;
-        struct epoll_event ev;
+        static const int one = 1;
+        int r;
 
         assert(s);
 
         if (s->syslog_fd < 0) {
-                union sockaddr_union sa = {
+                static const union sockaddr_union sa = {
                         .un.sun_family = AF_UNIX,
-                        .un.sun_path = "/dev/log",
+                        .un.sun_path = "/run/systemd/journal/dev-log",
                 };
 
                 s->syslog_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
@@ -433,7 +437,7 @@ int server_open_syslog_socket(Server *s) {
 
                 r = bind(s->syslog_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
                 if (r < 0) {
-                        log_error("bind() failed: %m");
+                        log_error("bind(%s) failed: %m", sa.un.sun_path);
                         return -errno;
                 }
 
@@ -441,7 +445,6 @@ int server_open_syslog_socket(Server *s) {
         } else
                 fd_nonblock(s->syslog_fd, 1);
 
-        one = 1;
         r = setsockopt(s->syslog_fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
         if (r < 0) {
                 log_error("SO_PASSCRED failed: %m");
@@ -449,25 +452,23 @@ int server_open_syslog_socket(Server *s) {
         }
 
 #ifdef HAVE_SELINUX
-        one = 1;
-        r = setsockopt(s->syslog_fd, SOL_SOCKET, SO_PASSSEC, &one, sizeof(one));
-        if (r < 0)
-                log_warning("SO_PASSSEC failed: %m");
+        if (mac_selinux_use()) {
+                r = setsockopt(s->syslog_fd, SOL_SOCKET, SO_PASSSEC, &one, sizeof(one));
+                if (r < 0)
+                        log_warning("SO_PASSSEC failed: %m");
+        }
 #endif
 
-        one = 1;
         r = setsockopt(s->syslog_fd, SOL_SOCKET, SO_TIMESTAMP, &one, sizeof(one));
         if (r < 0) {
                 log_error("SO_TIMESTAMP failed: %m");
                 return -errno;
         }
 
-        zero(ev);
-        ev.events = EPOLLIN;
-        ev.data.fd = s->syslog_fd;
-        if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, s->syslog_fd, &ev) < 0) {
-                log_error("Failed to add syslog server fd to epoll object: %m");
-                return -errno;
+        r = sd_event_add_io(s->event, &s->syslog_event_source, s->syslog_fd, EPOLLIN, process_datagram, s);
+        if (r < 0) {
+                log_error("Failed to add syslog server fd to event loop: %s", strerror(-r));
+                return r;
         }
 
         return 0;