chiark / gitweb /
journal: introduce log target 'journal' for executed processes
[elogind.git] / src / kmsg-syslogd.c
index a2715ae0fa1b960ae68f2b7702bfc41180ddd48a..da83bb2b1eb14d597e62542ee580fd6145f323fa 100644 (file)
 #include <fcntl.h>
 #include <sys/signalfd.h>
 
+#include <systemd/sd-daemon.h>
+
 #include "util.h"
 #include "log.h"
-#include "sd-daemon.h"
 #include "fdset.h"
 
 #define SERVER_FD_MAX 16
-#define TIMEOUT ((int) (5*MSEC_PER_MINUTE))
 
 typedef struct Stream Stream;
 
@@ -66,66 +66,72 @@ static void server_done(Server *s) {
                 fdset_free(s->syslog_fds);
 }
 
-static int server_init(Server *s, unsigned n_sockets) {
-        int r;
-        unsigned i;
+static int server_init(Server *s) {
+        int i, r, n;
         struct epoll_event ev;
         sigset_t mask;
 
         assert(s);
-        assert(n_sockets > 0);
 
         zero(*s);
-
         s->kmsg_fd = s->signal_fd = -1;
 
-        if ((s->epoll_fd = epoll_create1(EPOLL_CLOEXEC)) < 0) {
-                r = -errno;
-                log_error("Failed to create epoll object: %s", strerror(errno));
-                goto fail;
+        s->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
+        if (s->epoll_fd < 0) {
+                log_error("Failed to create epoll object: %m");
+                return -errno;
         }
 
-        if (!(s->syslog_fds = fdset_new())) {
-                r = -ENOMEM;
-                log_error("Failed to allocate file descriptor set: %s", strerror(errno));
-                goto fail;
+        s->syslog_fds = fdset_new();
+        if (!s->syslog_fds) {
+                log_error("Failed to allocate file descriptor set: %s", strerror(ENOMEM));
+                return -ENOMEM;
         }
 
-        for (i = 0; i < n_sockets; i++) {
-                int fd, one = 1;
+        n = sd_listen_fds(true);
+        if (n < 0) {
+                log_error("Failed to read listening file descriptors from environment: %s", strerror(-n));
+                return n;
+        }
+
+        if (n <= 0 || n > SERVER_FD_MAX) {
+                log_error("No or too many file descriptors passed.");
+                return -EINVAL;
+        }
+
+        for (i = 0; i < n; i++) {
+                int fd;
 
                 fd = SD_LISTEN_FDS_START+i;
 
-                if ((r = sd_is_socket(fd, AF_UNSPEC, SOCK_DGRAM, -1)) < 0) {
+                r = sd_is_socket(fd, AF_UNSPEC, SOCK_DGRAM, -1);
+                if (r < 0) {
                         log_error("Failed to determine file descriptor type: %s", strerror(-r));
-                        goto fail;
+                        return r;
                 }
 
                 if (!r) {
                         log_error("Wrong file descriptor type.");
-                        r = -EINVAL;
-                        goto fail;
+                        return -EINVAL;
                 }
 
-                if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0)
-                        log_error("SO_PASSCRED failed: %m");
-
                 zero(ev);
                 ev.events = EPOLLIN;
                 ev.data.fd = fd;
                 if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
-                        r = -errno;
-                        log_error("Failed to add server fd to epoll object: %s", strerror(errno));
-                        goto fail;
+                        log_error("Failed to add server fd to epoll object: %m");
+                        return -errno;
                 }
 
-                if ((r = fdset_put(s->syslog_fds, fd)) < 0) {
+                r = fdset_put(s->syslog_fds, fd);
+                if (r < 0) {
                         log_error("Failed to store file descriptor in set: %s", strerror(-r));
-                        goto fail;
+                        return r;
                 }
         }
 
-        if ((s->kmsg_fd = open("/dev/kmsg", O_WRONLY|O_NOCTTY|O_CLOEXEC)) < 0) {
+        s->kmsg_fd = open("/dev/kmsg", O_WRONLY|O_NOCTTY|O_CLOEXEC);
+        if (s->kmsg_fd < 0) {
                 log_error("Failed to open /dev/kmsg for logging: %m");
                 return -errno;
         }
@@ -134,7 +140,8 @@ static int server_init(Server *s, unsigned n_sockets) {
         sigset_add_many(&mask, SIGINT, SIGTERM, -1);
         assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
 
-        if ((s->signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC)) < 0) {
+        s->signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
+        if (s->signal_fd < 0) {
                 log_error("signalfd(): %m");
                 return -errno;
         }
@@ -149,124 +156,6 @@ static int server_init(Server *s, unsigned n_sockets) {
         }
 
         return 0;
-
-fail:
-        server_done(s);
-        return r;
-}
-
-static int read_priority(const char **buf) {
-        int priority;
-        size_t n;
-        const char *p;
-        int a, b, c;
-
-        assert(buf);
-        assert(*buf);
-
-        p = *buf;
-        n = strlen(p);
-
-        if (n < 3 || p[0] != '<')
-                goto fail;
-
-        if (p[2] == '>') {
-                a = b = 0;
-                c = undecchar(p[1]);
-                p += 3;
-        } else if (n >= 4 && p[3] == '>') {
-                a = 0;
-                b = undecchar(p[1]);
-                c = undecchar(p[2]);
-                p += 4;
-        } else if (n >= 5 && p[4] == '>') {
-                a = undecchar(p[1]);
-                b = undecchar(p[2]);
-                c = undecchar(p[3]);
-                p += 5;
-        } else
-                goto fail;
-
-        if (a < 0 || b < 0 || c < 0)
-                goto fail;
-
-        *buf = p;
-
-        priority = 100*a + 10*b + c;
-        return LOG_PRI(priority);
-
-fail:
-        return LOG_INFO;
-}
-
-static void skip_date(const 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
-        };
-
-        const 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;
 }
 
 static int read_process(const char **buf, struct iovec *iovec) {
@@ -311,51 +200,40 @@ static int read_process(const char **buf, struct iovec *iovec) {
         return 1;
 }
 
-static void skip_pid(const char **buf) {
-        const char *p;
-
-        assert(buf);
-        assert(*buf);
-
-        p = *buf;
-
-        if (*p != '[')
-                return;
-
-        p++;
-        p += strspn(p, "0123456789");
-
-        if (*p != ']')
-                return;
-
-        p++;
-
-        *buf = p;
-}
-
 static int write_message(Server *s, const char *buf, struct ucred *ucred) {
         ssize_t k;
-        char priority[4], pid[16];
+        char priority[6], pid[16];
         struct iovec iovec[5];
         unsigned i = 0;
         char *process = NULL;
         int r = 0;
+        int prio = LOG_USER | LOG_INFO;
 
         assert(s);
         assert(buf);
 
+        parse_syslog_priority((char**) &buf, &prio);
+
+        if (*buf == 0)
+                return 0;
+
+        if ((prio & LOG_FACMASK) == 0)
+                prio = LOG_USER | LOG_PRI(prio);
+
         /* First, set priority field */
-        snprintf(priority, sizeof(priority), "<%i>", read_priority(&buf));
+        snprintf(priority, sizeof(priority), "<%i>", prio);
         char_array_0(priority);
         IOVEC_SET_STRING(iovec[i++], priority);
 
         /* Second, skip date */
-        skip_date(&buf);
+        skip_syslog_date((char**) &buf);
 
         /* Then, add process if set */
         if (read_process(&buf, &iovec[i]) > 0)
                 i++;
-        else if (ucred && get_process_name(ucred->pid, &process) >= 0)
+        else if (ucred &&
+                 ucred->pid > 0 &&
+                 get_process_comm(ucred->pid, &process) >= 0)
                 IOVEC_SET_STRING(iovec[i++], process);
 
         /* Skip the stored PID if we have a better one */
@@ -364,7 +242,7 @@ static int write_message(Server *s, const char *buf, struct ucred *ucred) {
                 char_array_0(pid);
                 IOVEC_SET_STRING(iovec[i++], pid);
 
-                skip_pid(&buf);
+                skip_syslog_pid((char**) &buf);
 
                 if (*buf == ':')
                         buf++;
@@ -402,7 +280,8 @@ static int process_event(Server *s, struct epoll_event *ev) {
                 struct signalfd_siginfo sfsi;
                 ssize_t n;
 
-                if ((n = read(s->signal_fd, &sfsi, sizeof(sfsi))) != sizeof(sfsi)) {
+                n = read(s->signal_fd, &sfsi, sizeof(sfsi));
+                if (n != sizeof(sfsi)) {
 
                         if (n >= 0)
                                 return -EIO;
@@ -413,7 +292,7 @@ static int process_event(Server *s, struct epoll_event *ev) {
                         return -errno;
                 }
 
-                log_debug("Received SIG%s", strna(signal_to_string(sfsi.ssi_signo)));
+                log_debug("Received SIG%s", signal_to_string(sfsi.ssi_signo));
                 return 0;
 
         } else {
@@ -441,7 +320,8 @@ static int process_event(Server *s, struct epoll_event *ev) {
                         msghdr.msg_control = &control;
                         msghdr.msg_controllen = sizeof(control);
 
-                        if ((n = recvmsg(ev->data.fd, &msghdr, MSG_DONTWAIT)) < 0) {
+                        n = recvmsg(ev->data.fd, &msghdr, MSG_DONTWAIT);
+                        if (n < 0) {
 
                                 if (errno == EINTR || errno == EAGAIN)
                                         return 1;
@@ -458,12 +338,14 @@ static int process_event(Server *s, struct epoll_event *ev) {
                         else
                                 ucred = NULL;
 
-                        if ((e = memchr(buf, '\n', n)))
+                        e = memchr(buf, '\n', n);
+                        if (e)
                                 *e = 0;
                         else
                                 buf[n] = 0;
 
-                        if ((k = write_message(s, strstrip(buf), ucred)) < 0)
+                        k = write_message(s, strstrip(buf), ucred);
+                        if (k < 0)
                                 return k;
                 }
         }
@@ -473,7 +355,7 @@ static int process_event(Server *s, struct epoll_event *ev) {
 
 int main(int argc, char *argv[]) {
         Server server;
-        int r = EXIT_FAILURE, n;
+        int r;
 
         if (getppid() != 1) {
                 log_error("This program should be invoked by init only.");
@@ -489,18 +371,11 @@ int main(int argc, char *argv[]) {
         log_parse_environment();
         log_open();
 
-        if ((n = sd_listen_fds(true)) < 0) {
-                log_error("Failed to read listening file descriptors from environment: %s", strerror(-r));
-                return EXIT_FAILURE;
-        }
+        umask(0022);
 
-        if (n <= 0 || n > SERVER_FD_MAX) {
-                log_error("No or too many file descriptors passed.");
-                return EXIT_FAILURE;
-        }
-
-        if (server_init(&server, (unsigned) n) < 0)
-                return EXIT_FAILURE;
+        r = server_init(&server);
+        if (r < 0)
+                goto finish;
 
         log_debug("systemd-kmsg-syslogd running as pid %lu", (unsigned long) getpid());
 
@@ -510,36 +385,33 @@ int main(int argc, char *argv[]) {
 
         for (;;) {
                 struct epoll_event event;
-                int k;
 
-                if ((k = epoll_wait(server.epoll_fd, &event, 1, TIMEOUT)) < 0) {
+                r = epoll_wait(server.epoll_fd, &event, 1, -1);
+                if (r < 0) {
 
                         if (errno == EINTR)
                                 continue;
 
                         log_error("epoll_wait() failed: %m");
-                        goto fail;
-                }
-
-                if (k <= 0)
+                        r = -errno;
+                        goto finish;
+                } else if (r == 0)
                         break;
 
-                if ((k = process_event(&server, &event)) < 0)
-                        goto fail;
-
-                if (k == 0)
+                r = process_event(&server, &event);
+                if (r < 0)
+                        goto finish;
+                else if (r == 0)
                         break;
         }
 
-        r = EXIT_SUCCESS;
-
         log_debug("systemd-kmsg-syslogd stopped as pid %lu", (unsigned long) getpid());
 
-fail:
+finish:
         sd_notify(false,
                   "STATUS=Shutting down...");
 
         server_done(&server);
 
-        return r;
+        return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
 }