chiark / gitweb /
trivial: fix typo
[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.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         usec_t 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 = parse_usec(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                                 b = strappend("_UDEV_DEVLINK=", g);
254                                 if (g) {
255                                         IOVEC_SET_STRING(iovec[n++], b);
256                                         z++;
257                                 }
258
259                                 j++;
260                         }
261
262                         udev_device_unref(ud);
263                 }
264         }
265
266         if (asprintf(&source_time, "_SOURCE_MONOTONIC_TIMESTAMP=%llu",
267                      (unsigned long long) usec) >= 0)
268                 IOVEC_SET_STRING(iovec[n++], source_time);
269
270         IOVEC_SET_STRING(iovec[n++], "_TRANSPORT=kernel");
271
272         if (asprintf(&syslog_priority, "PRIORITY=%i", priority & LOG_PRIMASK) >= 0)
273                 IOVEC_SET_STRING(iovec[n++], syslog_priority);
274
275         if ((priority & LOG_FACMASK) == LOG_KERN)
276                 IOVEC_SET_STRING(iovec[n++], "SYSLOG_IDENTIFIER=kernel");
277         else {
278                 syslog_parse_identifier((const char**) &p, &identifier, &pid);
279
280                 /* Avoid any messages we generated ourselves via
281                  * log_info() and friends. */
282                 if (pid && is_us(pid))
283                         goto finish;
284
285                 if (identifier) {
286                         syslog_identifier = strappend("SYSLOG_IDENTIFIER=", identifier);
287                         if (syslog_identifier)
288                                 IOVEC_SET_STRING(iovec[n++], syslog_identifier);
289                 }
290
291                 if (pid) {
292                         syslog_pid = strappend("SYSLOG_PID=", pid);
293                         if (syslog_pid)
294                                 IOVEC_SET_STRING(iovec[n++], syslog_pid);
295                 }
296
297                 if (asprintf(&syslog_facility, "SYSLOG_FACILITY=%i", LOG_FAC(priority)) >= 0)
298                         IOVEC_SET_STRING(iovec[n++], syslog_facility);
299         }
300
301         message = cunescape_length_with_prefix(p, pl, "MESSAGE=");
302         if (message)
303                 IOVEC_SET_STRING(iovec[n++], message);
304
305         server_dispatch_message(s, iovec, n, ELEMENTSOF(iovec), NULL, NULL, NULL, 0, NULL, priority);
306
307 finish:
308         for (j = 0; j < z; j++)
309                 free(iovec[j].iov_base);
310
311         free(message);
312         free(syslog_priority);
313         free(syslog_identifier);
314         free(syslog_pid);
315         free(syslog_facility);
316         free(source_time);
317         free(identifier);
318         free(pid);
319 }
320
321 int server_read_dev_kmsg(Server *s) {
322         char buffer[8192+1]; /* the kernel-side limit per record is 8K currently */
323         ssize_t l;
324
325         assert(s);
326         assert(s->dev_kmsg_fd >= 0);
327
328         l = read(s->dev_kmsg_fd, buffer, sizeof(buffer) - 1);
329         if (l == 0)
330                 return 0;
331         if (l < 0) {
332                 /* Old kernels who don't allow reading from /dev/kmsg
333                  * return EINVAL when we try. So handle this cleanly,
334                  * but don' try to ever read from it again. */
335                 if (errno == EINVAL) {
336                         epoll_ctl(s->epoll_fd, EPOLL_CTL_DEL, s->dev_kmsg_fd, NULL);
337                         return 0;
338                 }
339
340                 if (errno == EAGAIN || errno == EINTR || errno == EPIPE)
341                         return 0;
342
343                 log_error("Failed to read from kernel: %m");
344                 return -errno;
345         }
346
347         dev_kmsg_record(s, buffer, l);
348         return 1;
349 }
350
351 int server_flush_dev_kmsg(Server *s) {
352         int r;
353
354         assert(s);
355
356         if (s->dev_kmsg_fd < 0)
357                 return 0;
358
359         if (!s->dev_kmsg_readable)
360                 return 0;
361
362         log_debug("Flushing /dev/kmsg...");
363
364         for (;;) {
365                 r = server_read_dev_kmsg(s);
366                 if (r < 0)
367                         return r;
368
369                 if (r == 0)
370                         break;
371         }
372
373         return 0;
374 }
375
376 int server_open_dev_kmsg(Server *s) {
377         struct epoll_event ev;
378
379         assert(s);
380
381         s->dev_kmsg_fd = open("/dev/kmsg", O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
382         if (s->dev_kmsg_fd < 0) {
383                 log_warning("Failed to open /dev/kmsg, ignoring: %m");
384                 return 0;
385         }
386
387         zero(ev);
388         ev.events = EPOLLIN;
389         ev.data.fd = s->dev_kmsg_fd;
390         if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, s->dev_kmsg_fd, &ev) < 0) {
391
392                 /* This will fail with EPERM on older kernels where
393                  * /dev/kmsg is not readable. */
394                 if (errno == EPERM)
395                         return 0;
396
397                 log_error("Failed to add /dev/kmsg fd to epoll object: %m");
398                 return -errno;
399         }
400
401         s->dev_kmsg_readable = true;
402
403         return 0;
404 }
405
406 int server_open_kernel_seqnum(Server *s) {
407         int fd;
408         uint64_t *p;
409
410         assert(s);
411
412         /* We store the seqnum we last read in an mmaped file. That
413          * way we can just use it like a variable, but it is
414          * persistent and automatically flushed at reboot. */
415
416         fd = open("/run/systemd/journal/kernel-seqnum", O_RDWR|O_CREAT|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0644);
417         if (fd < 0) {
418                 log_error("Failed to open /run/systemd/journal/kernel-seqnum, ignoring: %m");
419                 return 0;
420         }
421
422         if (posix_fallocate(fd, 0, sizeof(uint64_t)) < 0) {
423                 log_error("Failed to allocate sequential number file, ignoring: %m");
424                 close_nointr_nofail(fd);
425                 return 0;
426         }
427
428         p = mmap(NULL, sizeof(uint64_t), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
429         if (p == MAP_FAILED) {
430                 log_error("Failed to map sequential number file, ignoring: %m");
431                 close_nointr_nofail(fd);
432                 return 0;
433         }
434
435         close_nointr_nofail(fd);
436         s->kernel_seqnum = p;
437
438         return 0;
439 }