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