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