chiark / gitweb /
journald: be more careful when we try to flush the runtime journal to disk and the...
[elogind.git] / src / journal / journald-kmsg.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2011 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <unistd.h>
23 #include <sys/epoll.h>
24 #include <fcntl.h>
25 #include <sys/mman.h>
26 #include <sys/socket.h>
27
28 #include <systemd/sd-messages.h>
29 #include <libudev.h>
30
31 #include "journald-server.h"
32 #include "journald-kmsg.h"
33 #include "journald-syslog.h"
34
35 void server_forward_kmsg(
36         Server *s,
37         int priority,
38         const char *identifier,
39         const char *message,
40         struct ucred *ucred) {
41
42         struct iovec iovec[5];
43         char header_priority[6], header_pid[16];
44         int n = 0;
45         char *ident_buf = NULL;
46
47         assert(s);
48         assert(priority >= 0);
49         assert(priority <= 999);
50         assert(message);
51
52         if (_unlikely_(LOG_PRI(priority) > s->max_level_kmsg))
53                 return;
54
55         if (_unlikely_(s->dev_kmsg_fd < 0))
56                 return;
57
58         /* Never allow messages with kernel facility to be written to
59          * kmsg, regardless where the data comes from. */
60         priority = syslog_fixup_facility(priority);
61
62         /* First: priority field */
63         snprintf(header_priority, sizeof(header_priority), "<%i>", priority);
64         char_array_0(header_priority);
65         IOVEC_SET_STRING(iovec[n++], header_priority);
66
67         /* Second: identifier and PID */
68         if (ucred) {
69                 if (!identifier) {
70                         get_process_comm(ucred->pid, &ident_buf);
71                         identifier = ident_buf;
72                 }
73
74                 snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) ucred->pid);
75                 char_array_0(header_pid);
76
77                 if (identifier)
78                         IOVEC_SET_STRING(iovec[n++], identifier);
79
80                 IOVEC_SET_STRING(iovec[n++], header_pid);
81         } else if (identifier) {
82                 IOVEC_SET_STRING(iovec[n++], identifier);
83                 IOVEC_SET_STRING(iovec[n++], ": ");
84         }
85
86         /* Fourth: message */
87         IOVEC_SET_STRING(iovec[n++], message);
88         IOVEC_SET_STRING(iovec[n++], "\n");
89
90         if (writev(s->dev_kmsg_fd, iovec, n) < 0)
91                 log_debug("Failed to write to /dev/kmsg for logging: %s", strerror(errno));
92
93         free(ident_buf);
94 }
95
96 static bool is_us(const char *pid) {
97         pid_t t;
98
99         assert(pid);
100
101         if (parse_pid(pid, &t) < 0)
102                 return false;
103
104         return t == getpid();
105 }
106
107 static void dev_kmsg_record(Server *s, char *p, size_t l) {
108         struct iovec iovec[N_IOVEC_META_FIELDS + 7 + N_IOVEC_KERNEL_FIELDS + 2 + N_IOVEC_UDEV_FIELDS];
109         char *message = NULL, *syslog_priority = NULL, *syslog_pid = NULL, *syslog_facility = NULL, *syslog_identifier = NULL, *source_time = NULL;
110         int priority, r;
111         unsigned n = 0, z = 0, j;
112         unsigned long long usec;
113         char *identifier = NULL, *pid = NULL, *e, *f, *k;
114         uint64_t serial;
115         size_t pl;
116         char *kernel_device = NULL;
117
118         assert(s);
119         assert(p);
120
121         if (l <= 0)
122                 return;
123
124         e = memchr(p, ',', l);
125         if (!e)
126                 return;
127         *e = 0;
128
129         r = safe_atoi(p, &priority);
130         if (r < 0 || priority < 0 || priority > 999)
131                 return;
132
133         if (s->forward_to_kmsg && (priority & LOG_FACMASK) != LOG_KERN)
134                 return;
135
136         l -= (e - p) + 1;
137         p = e + 1;
138         e = memchr(p, ',', l);
139         if (!e)
140                 return;
141         *e = 0;
142
143         r = safe_atou64(p, &serial);
144         if (r < 0)
145                 return;
146
147         if (s->kernel_seqnum) {
148                 /* We already read this one? */
149                 if (serial < *s->kernel_seqnum)
150                         return;
151
152                 /* Did we lose any? */
153                 if (serial > *s->kernel_seqnum)
154                         server_driver_message(s, SD_MESSAGE_JOURNAL_MISSED, "Missed %llu kernel messages", (unsigned long long) serial - *s->kernel_seqnum - 1);
155
156                 /* Make sure we never read this one again. Note that
157                  * we always store the next message serial we expect
158                  * here, simply because this makes handling the first
159                  * message with serial 0 easy. */
160                 *s->kernel_seqnum = serial + 1;
161         }
162
163         l -= (e - p) + 1;
164         p = e + 1;
165         f = memchr(p, ';', l);
166         if (!f)
167                 return;
168         /* Kernel 3.6 has the flags field, kernel 3.5 lacks that */
169         e = memchr(p, ',', l);
170         if (!e || f < e)
171                 e = f;
172         *e = 0;
173
174         r = safe_atollu(p, &usec);
175         if (r < 0)
176                 return;
177
178         l -= (f - p) + 1;
179         p = f + 1;
180         e = memchr(p, '\n', l);
181         if (!e)
182                 return;
183         *e = 0;
184
185         pl = e - p;
186         l -= (e - p) + 1;
187         k = e + 1;
188
189         for (j = 0; l > 0 && j < N_IOVEC_KERNEL_FIELDS; j++) {
190                 char *m;
191                 /* Meta data fields attached */
192
193                 if (*k != ' ')
194                         break;
195
196                 k ++, l --;
197
198                 e = memchr(k, '\n', l);
199                 if (!e)
200                         return;
201
202                 *e = 0;
203
204                 m = cunescape_length_with_prefix(k, e - k, "_KERNEL_");
205                 if (!m)
206                         break;
207
208                 if (startswith(m, "_KERNEL_DEVICE="))
209                         kernel_device = m + 15;
210
211                 IOVEC_SET_STRING(iovec[n++], m);
212                 z++;
213
214                 l -= (e - k) + 1;
215                 k = e + 1;
216         }
217
218         if (kernel_device) {
219                 struct udev_device *ud;
220
221                 ud = udev_device_new_from_device_id(s->udev, kernel_device);
222                 if (ud) {
223                         const char *g;
224                         struct udev_list_entry *ll;
225                         char *b;
226
227                         g = udev_device_get_devnode(ud);
228                         if (g) {
229                                 b = strappend("_UDEV_DEVNODE=", g);
230                                 if (b) {
231                                         IOVEC_SET_STRING(iovec[n++], b);
232                                         z++;
233                                 }
234                         }
235
236                         g = udev_device_get_sysname(ud);
237                         if (g) {
238                                 b = strappend("_UDEV_SYSNAME=", g);
239                                 if (b) {
240                                         IOVEC_SET_STRING(iovec[n++], b);
241                                         z++;
242                                 }
243                         }
244
245                         j = 0;
246                         ll = udev_device_get_devlinks_list_entry(ud);
247                         udev_list_entry_foreach(ll, ll) {
248
249                                 if (j > N_IOVEC_UDEV_FIELDS)
250                                         break;
251
252                                 g = udev_list_entry_get_name(ll);
253                                 if (g) {
254                                         b = strappend("_UDEV_DEVLINK=", g);
255                                         if (b) {
256                                                 IOVEC_SET_STRING(iovec[n++], b);
257                                                 z++;
258                                         }
259                                 }
260
261                                 j++;
262                         }
263
264                         udev_device_unref(ud);
265                 }
266         }
267
268         if (asprintf(&source_time, "_SOURCE_MONOTONIC_TIMESTAMP=%llu", usec) >= 0)
269                 IOVEC_SET_STRING(iovec[n++], source_time);
270
271         IOVEC_SET_STRING(iovec[n++], "_TRANSPORT=kernel");
272
273         if (asprintf(&syslog_priority, "PRIORITY=%i", priority & LOG_PRIMASK) >= 0)
274                 IOVEC_SET_STRING(iovec[n++], syslog_priority);
275
276         if ((priority & LOG_FACMASK) == LOG_KERN)
277                 IOVEC_SET_STRING(iovec[n++], "SYSLOG_IDENTIFIER=kernel");
278         else {
279                 pl -= syslog_parse_identifier((const char**) &p, &identifier, &pid);
280
281                 /* Avoid any messages we generated ourselves via
282                  * log_info() and friends. */
283                 if (pid && is_us(pid))
284                         goto finish;
285
286                 if (identifier) {
287                         syslog_identifier = strappend("SYSLOG_IDENTIFIER=", identifier);
288                         if (syslog_identifier)
289                                 IOVEC_SET_STRING(iovec[n++], syslog_identifier);
290                 }
291
292                 if (pid) {
293                         syslog_pid = strappend("SYSLOG_PID=", pid);
294                         if (syslog_pid)
295                                 IOVEC_SET_STRING(iovec[n++], syslog_pid);
296                 }
297
298                 if (asprintf(&syslog_facility, "SYSLOG_FACILITY=%i", LOG_FAC(priority)) >= 0)
299                         IOVEC_SET_STRING(iovec[n++], syslog_facility);
300         }
301
302         message = cunescape_length_with_prefix(p, pl, "MESSAGE=");
303         if (message)
304                 IOVEC_SET_STRING(iovec[n++], message);
305
306         server_dispatch_message(s, iovec, n, ELEMENTSOF(iovec), NULL, NULL, NULL, 0, NULL, priority);
307
308 finish:
309         for (j = 0; j < z; j++)
310                 free(iovec[j].iov_base);
311
312         free(message);
313         free(syslog_priority);
314         free(syslog_identifier);
315         free(syslog_pid);
316         free(syslog_facility);
317         free(source_time);
318         free(identifier);
319         free(pid);
320 }
321
322 int server_read_dev_kmsg(Server *s) {
323         char buffer[8192+1]; /* the kernel-side limit per record is 8K currently */
324         ssize_t l;
325
326         assert(s);
327         assert(s->dev_kmsg_fd >= 0);
328
329         l = read(s->dev_kmsg_fd, buffer, sizeof(buffer) - 1);
330         if (l == 0)
331                 return 0;
332         if (l < 0) {
333                 /* Old kernels who don't allow reading from /dev/kmsg
334                  * return EINVAL when we try. So handle this cleanly,
335                  * but don' try to ever read from it again. */
336                 if (errno == EINVAL) {
337                         epoll_ctl(s->epoll_fd, EPOLL_CTL_DEL, s->dev_kmsg_fd, NULL);
338                         return 0;
339                 }
340
341                 if (errno == EAGAIN || errno == EINTR || errno == EPIPE)
342                         return 0;
343
344                 log_error("Failed to read from kernel: %m");
345                 return -errno;
346         }
347
348         dev_kmsg_record(s, buffer, l);
349         return 1;
350 }
351
352 int server_flush_dev_kmsg(Server *s) {
353         int r;
354
355         assert(s);
356
357         if (s->dev_kmsg_fd < 0)
358                 return 0;
359
360         if (!s->dev_kmsg_readable)
361                 return 0;
362
363         log_debug("Flushing /dev/kmsg...");
364
365         for (;;) {
366                 r = server_read_dev_kmsg(s);
367                 if (r < 0)
368                         return r;
369
370                 if (r == 0)
371                         break;
372         }
373
374         return 0;
375 }
376
377 int server_open_dev_kmsg(Server *s) {
378         struct epoll_event ev;
379
380         assert(s);
381
382         s->dev_kmsg_fd = open("/dev/kmsg", O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
383         if (s->dev_kmsg_fd < 0) {
384                 log_warning("Failed to open /dev/kmsg, ignoring: %m");
385                 return 0;
386         }
387
388         zero(ev);
389         ev.events = EPOLLIN;
390         ev.data.fd = s->dev_kmsg_fd;
391         if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, s->dev_kmsg_fd, &ev) < 0) {
392
393                 /* This will fail with EPERM on older kernels where
394                  * /dev/kmsg is not readable. */
395                 if (errno == EPERM)
396                         return 0;
397
398                 log_error("Failed to add /dev/kmsg fd to epoll object: %m");
399                 return -errno;
400         }
401
402         s->dev_kmsg_readable = true;
403
404         return 0;
405 }
406
407 int server_open_kernel_seqnum(Server *s) {
408         int fd;
409         uint64_t *p;
410
411         assert(s);
412
413         /* We store the seqnum we last read in an mmaped file. That
414          * way we can just use it like a variable, but it is
415          * persistent and automatically flushed at reboot. */
416
417         fd = open("/run/systemd/journal/kernel-seqnum", O_RDWR|O_CREAT|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0644);
418         if (fd < 0) {
419                 log_error("Failed to open /run/systemd/journal/kernel-seqnum, ignoring: %m");
420                 return 0;
421         }
422
423         if (posix_fallocate(fd, 0, sizeof(uint64_t)) < 0) {
424                 log_error("Failed to allocate sequential number file, ignoring: %m");
425                 close_nointr_nofail(fd);
426                 return 0;
427         }
428
429         p = mmap(NULL, sizeof(uint64_t), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
430         if (p == MAP_FAILED) {
431                 log_error("Failed to map sequential number file, ignoring: %m");
432                 close_nointr_nofail(fd);
433                 return 0;
434         }
435
436         close_nointr_nofail(fd);
437         s->kernel_seqnum = p;
438
439         return 0;
440 }