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