journald-kmsg.c revision 0b452006de98294d1690f045f6ea2f7f6630ec3b
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering This file is part of systemd.
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering Copyright 2011 Lennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering systemd is free software; you can redistribute it and/or modify it
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering under the terms of the GNU Lesser General Public License as published by
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering the Free Software Foundation; either version 2.1 of the License, or
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering (at your option) any later version.
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering systemd is distributed in the hope that it will be useful, but
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering Lesser General Public License for more details.
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering You should have received a copy of the GNU Lesser General Public License
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen#include "systemd/sd-messages.h"
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering char header_priority[DECIMAL_STR_MAX(priority) + 3],
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering header_pid[sizeof("[]: ")-1 + DECIMAL_STR_MAX(pid_t) + 1];
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (_unlikely_(LOG_PRI(priority) > s->max_level_kmsg))
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering /* Never allow messages with kernel facility to be written to
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering * kmsg, regardless where the data comes from. */
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering priority = syslog_fixup_facility(priority);
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers /* First: priority field */
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers /* Second: identifier and PID */
f18ca9dcdeda247e208f7143e834fd2fb2070d80Kay Sievers xsprintf(header_pid, "["PID_FMT"]: ", ucred->pid);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering IOVEC_SET_STRING(iovec[n++], header_pid);
599659860c770058f2eb04d578c521c16e0b1853Lennart Poettering IOVEC_SET_STRING(iovec[n++], identifier);
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering /* Fourth: message */
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering if (writev(s->dev_kmsg_fd, iovec, n) < 0)
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering log_debug_errno(errno, "Failed to write to /dev/kmsg for logging: %m");
9ff09bcb86fb125768667aca9bc0b10b1745370aShawn Landden return t == getpid();
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmekstatic void dev_kmsg_record(Server *s, const char *p, size_t l) {
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek struct iovec iovec[N_IOVEC_META_FIELDS + 7 + N_IOVEC_KERNEL_FIELDS + 2 + N_IOVEC_UDEV_FIELDS];
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek char *message = NULL, *syslog_priority = NULL, *syslog_pid = NULL, *syslog_facility = NULL, *syslog_identifier = NULL, *source_time = NULL;
9ff09bcb86fb125768667aca9bc0b10b1745370aShawn Landden unsigned n = 0, z = 0, j;
9ff09bcb86fb125768667aca9bc0b10b1745370aShawn Landden unsigned long long usec;
9ff09bcb86fb125768667aca9bc0b10b1745370aShawn Landden char *identifier = NULL, *pid = NULL, *e, *f, *k;
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering if (r < 0 || priority < 0 || priority > 999)
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering if (s->forward_to_kmsg && (priority & LOG_FACMASK) != LOG_KERN)
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering l -= (e - p) + 1;
c264aeab4b0e7b69f469e12e78d4a48b3ed7a66eKay Sievers /* We already read this one? */
07a062a79374406e8f6b5a1e2f80c80baf031567Jason St. John /* Did we lose any? */
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering server_driver_message(s, SD_MESSAGE_JOURNAL_MISSED, "Missed %"PRIu64" kernel messages",
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers /* Make sure we never read this one again. Note that
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers * we always store the next message serial we expect
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers * here, simply because this makes handling the first
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers * message with serial 0 easy. */
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers l -= (e - p) + 1;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen /* Kernel 3.6 has the flags field, kernel 3.5 lacks that */
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers if (!e || f < e)
adacb9575a09981fcf11279f2f661e3fc21e58ffLennart Poettering l -= (f - p) + 1;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering l -= (e - p) + 1;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen for (j = 0; l > 0 && j < N_IOVEC_KERNEL_FIELDS; j++) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering /* Meta data fields attached */
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (*k != ' ')
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen if (cunescape_length_with_prefix(k, e - k, "_KERNEL_", UNESCAPE_RELAX, &m) < 0)
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen if (startswith(m, "_KERNEL_DEVICE="))
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen IOVEC_SET_STRING(iovec[n++], m);
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen l -= (e - k) + 1;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen ud = udev_device_new_from_device_id(s->udev, kernel_device);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering const char *g;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen b = strappend("_UDEV_DEVNODE=", g);
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen IOVEC_SET_STRING(iovec[n++], b);
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen g = udev_device_get_sysname(ud);
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen b = strappend("_UDEV_SYSNAME=", g);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering ll = udev_device_get_devlinks_list_entry(ud);
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen if (asprintf(&source_time, "_SOURCE_MONOTONIC_TIMESTAMP=%llu", usec) >= 0)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering IOVEC_SET_STRING(iovec[n++], source_time);
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen IOVEC_SET_STRING(iovec[n++], "_TRANSPORT=kernel");
e5609878d8802e2469c433be418bcbcf55fbe63bLennart Poettering if (asprintf(&syslog_priority, "PRIORITY=%i", priority & LOG_PRIMASK) >= 0)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering IOVEC_SET_STRING(iovec[n++], syslog_priority);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (asprintf(&syslog_facility, "SYSLOG_FACILITY=%i", LOG_FAC(priority)) >= 0)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering IOVEC_SET_STRING(iovec[n++], syslog_facility);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if ((priority & LOG_FACMASK) == LOG_KERN)
e5609878d8802e2469c433be418bcbcf55fbe63bLennart Poettering IOVEC_SET_STRING(iovec[n++], "SYSLOG_IDENTIFIER=kernel");
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering pl -= syslog_parse_identifier((const char**) &p, &identifier, &pid);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering /* Avoid any messages we generated ourselves via
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering * log_info() and friends. */
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen syslog_identifier = strappend("SYSLOG_IDENTIFIER=", identifier);
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen IOVEC_SET_STRING(iovec[n++], syslog_identifier);
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen syslog_pid = strappend("SYSLOG_PID=", pid);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering IOVEC_SET_STRING(iovec[n++], syslog_pid);
7568345034f2890af745747783c5abfbf6eccf0fLennart Poettering if (cunescape_length_with_prefix(p, pl, "MESSAGE=", UNESCAPE_RELAX, &message) >= 0)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering server_dispatch_message(s, iovec, n, ELEMENTSOF(iovec), NULL, NULL, NULL, 0, NULL, priority, 0);
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt for (j = 0; j < z; j++)
4f8f66cb4236783cd3cbee97fefc9aaa8469ac08Zbigniew Jędrzejewski-Szmekstatic int server_read_dev_kmsg(Server *s) {
4f8f66cb4236783cd3cbee97fefc9aaa8469ac08Zbigniew Jędrzejewski-Szmek char buffer[8192+1]; /* the kernel-side limit per record is 8K currently */
4f8f66cb4236783cd3cbee97fefc9aaa8469ac08Zbigniew Jędrzejewski-Szmek l = read(s->dev_kmsg_fd, buffer, sizeof(buffer) - 1);
4f8f66cb4236783cd3cbee97fefc9aaa8469ac08Zbigniew Jędrzejewski-Szmek /* Old kernels who don't allow reading from /dev/kmsg
3906ab4adf0aa7b952e39100262a11acd55cd79bRonny Chevalier * return EINVAL when we try. So handle this cleanly,
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering * but don' try to ever read from it again. */
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering s->dev_kmsg_event_source = sd_event_source_unref(s->dev_kmsg_event_source);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (errno == EAGAIN || errno == EINTR || errno == EPIPE)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering log_error_errno(errno, "Failed to read from kernel: %m");
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersenint server_flush_dev_kmsg(Server *s) {
601185b43da638b1c74153deae01dbd518680889Zbigniew Jędrzejewski-Szmek log_debug("Flushing /dev/kmsg...");
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersenstatic int dispatch_dev_kmsg(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen assert(fd == s->dev_kmsg_fd);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering log_warning("/dev/kmsg buffer overrun, some messages lost.");
546158bc6f46f8004cc11e81d19d223e0da56730Jan Janssen log_error("Got invalid event from epoll for /dev/kmsg: %"PRIx32, revents);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering s->dev_kmsg_fd = open("/dev/kmsg", O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering log_full(errno == ENOENT ? LOG_DEBUG : LOG_WARNING,
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering "Failed to open /dev/kmsg, ignoring: %m");
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering r = sd_event_add_io(s->event, &s->dev_kmsg_event_source, s->dev_kmsg_fd, EPOLLIN, dispatch_dev_kmsg, s);
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen /* This will fail with EPERM on older kernels where
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering * /dev/kmsg is not readable. */
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering log_error_errno(r, "Failed to add /dev/kmsg fd to event loop: %m");
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering r = sd_event_source_set_priority(s->dev_kmsg_event_source, SD_EVENT_PRIORITY_IMPORTANT+10);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering log_error_errno(r, "Failed to adjust priority of kmsg event source: %m");
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering s->dev_kmsg_event_source = sd_event_source_unref(s->dev_kmsg_event_source);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering s->dev_kmsg_fd = safe_close(s->dev_kmsg_fd);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poetteringint server_open_kernel_seqnum(Server *s) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering /* We store the seqnum we last read in an mmaped file. That
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering * way we can just use it like a variable, but it is
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering * persistent and automatically flushed at reboot. */
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering fd = open("/run/systemd/journal/kernel-seqnum", O_RDWR|O_CREAT|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0644);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering log_error_errno(errno, "Failed to open /run/systemd/journal/kernel-seqnum, ignoring: %m");
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (posix_fallocate(fd, 0, sizeof(uint64_t)) < 0) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering log_error_errno(errno, "Failed to allocate sequential number file, ignoring: %m");
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering p = mmap(NULL, sizeof(uint64_t), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering log_error_errno(errno, "Failed to map sequential number file, ignoring: %m");