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