]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal/journald-kmsg.c
util: split out escaping code into escape.[ch]
[thirdparty/systemd.git] / src / journal / journald-kmsg.c
CommitLineData
ef63833d
LP
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
ef63833d 22#include <fcntl.h>
4f5dd394 23#include <sys/epoll.h>
ef63833d 24#include <sys/mman.h>
4871690d 25#include <sys/socket.h>
4f5dd394 26#include <unistd.h>
ef63833d 27
4f5dd394
LP
28#include "libudev.h"
29#include "sd-messages.h"
ef63833d 30
4f5dd394
LP
31#include "escape.h"
32#include "formats-util.h"
d025f1e4 33#include "journald-server.h"
35e2e347 34#include "journald-syslog.h"
0b452006 35#include "process-util.h"
4f5dd394 36#include "journald-kmsg.h"
ef63833d
LP
37
38void server_forward_kmsg(
39 Server *s,
40 int priority,
41 const char *identifier,
42 const char *message,
3b3154df 43 const struct ucred *ucred) {
ef63833d
LP
44
45 struct iovec iovec[5];
3b97fcbd 46 char header_priority[DECIMAL_STR_MAX(priority) + 3],
5ffa8c81 47 header_pid[sizeof("[]: ")-1 + DECIMAL_STR_MAX(pid_t) + 1];
ef63833d
LP
48 int n = 0;
49 char *ident_buf = NULL;
50
51 assert(s);
52 assert(priority >= 0);
53 assert(priority <= 999);
54 assert(message);
55
56 if (_unlikely_(LOG_PRI(priority) > s->max_level_kmsg))
57 return;
58
59 if (_unlikely_(s->dev_kmsg_fd < 0))
60 return;
61
62 /* Never allow messages with kernel facility to be written to
63 * kmsg, regardless where the data comes from. */
64 priority = syslog_fixup_facility(priority);
65
66 /* First: priority field */
5ffa8c81 67 xsprintf(header_priority, "<%i>", priority);
ef63833d
LP
68 IOVEC_SET_STRING(iovec[n++], header_priority);
69
70 /* Second: identifier and PID */
71 if (ucred) {
72 if (!identifier) {
73 get_process_comm(ucred->pid, &ident_buf);
74 identifier = ident_buf;
75 }
76
5ffa8c81 77 xsprintf(header_pid, "["PID_FMT"]: ", ucred->pid);
ef63833d
LP
78
79 if (identifier)
80 IOVEC_SET_STRING(iovec[n++], identifier);
81
82 IOVEC_SET_STRING(iovec[n++], header_pid);
83 } else if (identifier) {
84 IOVEC_SET_STRING(iovec[n++], identifier);
85 IOVEC_SET_STRING(iovec[n++], ": ");
86 }
87
88 /* Fourth: message */
89 IOVEC_SET_STRING(iovec[n++], message);
90 IOVEC_SET_STRING(iovec[n++], "\n");
91
92 if (writev(s->dev_kmsg_fd, iovec, n) < 0)
56f64d95 93 log_debug_errno(errno, "Failed to write to /dev/kmsg for logging: %m");
ef63833d
LP
94
95 free(ident_buf);
96}
97
98static bool is_us(const char *pid) {
99 pid_t t;
100
101 assert(pid);
102
103 if (parse_pid(pid, &t) < 0)
104 return false;
105
106 return t == getpid();
107}
108
3b3154df 109static void dev_kmsg_record(Server *s, const char *p, size_t l) {
ef63833d
LP
110 struct iovec iovec[N_IOVEC_META_FIELDS + 7 + N_IOVEC_KERNEL_FIELDS + 2 + N_IOVEC_UDEV_FIELDS];
111 char *message = NULL, *syslog_priority = NULL, *syslog_pid = NULL, *syslog_facility = NULL, *syslog_identifier = NULL, *source_time = NULL;
112 int priority, r;
113 unsigned n = 0, z = 0, j;
e9f600f2 114 unsigned long long usec;
ef63833d
LP
115 char *identifier = NULL, *pid = NULL, *e, *f, *k;
116 uint64_t serial;
117 size_t pl;
118 char *kernel_device = NULL;
119
120 assert(s);
121 assert(p);
122
123 if (l <= 0)
124 return;
125
126 e = memchr(p, ',', l);
127 if (!e)
128 return;
129 *e = 0;
130
131 r = safe_atoi(p, &priority);
132 if (r < 0 || priority < 0 || priority > 999)
133 return;
134
135 if (s->forward_to_kmsg && (priority & LOG_FACMASK) != LOG_KERN)
136 return;
137
138 l -= (e - p) + 1;
139 p = e + 1;
140 e = memchr(p, ',', l);
141 if (!e)
142 return;
143 *e = 0;
144
145 r = safe_atou64(p, &serial);
146 if (r < 0)
147 return;
148
149 if (s->kernel_seqnum) {
150 /* We already read this one? */
151 if (serial < *s->kernel_seqnum)
152 return;
153
154 /* Did we lose any? */
155 if (serial > *s->kernel_seqnum)
507f22bd 156 server_driver_message(s, SD_MESSAGE_JOURNAL_MISSED, "Missed %"PRIu64" kernel messages",
b9c488f6 157 serial - *s->kernel_seqnum);
ef63833d
LP
158
159 /* Make sure we never read this one again. Note that
160 * we always store the next message serial we expect
161 * here, simply because this makes handling the first
162 * message with serial 0 easy. */
163 *s->kernel_seqnum = serial + 1;
164 }
165
166 l -= (e - p) + 1;
167 p = e + 1;
168 f = memchr(p, ';', l);
169 if (!f)
170 return;
171 /* Kernel 3.6 has the flags field, kernel 3.5 lacks that */
172 e = memchr(p, ',', l);
173 if (!e || f < e)
174 e = f;
175 *e = 0;
176
e9f600f2 177 r = safe_atollu(p, &usec);
ef63833d
LP
178 if (r < 0)
179 return;
180
181 l -= (f - p) + 1;
182 p = f + 1;
183 e = memchr(p, '\n', l);
184 if (!e)
185 return;
186 *e = 0;
187
188 pl = e - p;
189 l -= (e - p) + 1;
190 k = e + 1;
191
192 for (j = 0; l > 0 && j < N_IOVEC_KERNEL_FIELDS; j++) {
193 char *m;
dc61b7e4 194 /* Metadata fields attached */
ef63833d
LP
195
196 if (*k != ' ')
197 break;
198
199 k ++, l --;
200
201 e = memchr(k, '\n', l);
202 if (!e)
203 return;
204
205 *e = 0;
206
527b7a42 207 if (cunescape_length_with_prefix(k, e - k, "_KERNEL_", UNESCAPE_RELAX, &m) < 0)
ef63833d
LP
208 break;
209
210 if (startswith(m, "_KERNEL_DEVICE="))
211 kernel_device = m + 15;
212
213 IOVEC_SET_STRING(iovec[n++], m);
214 z++;
215
216 l -= (e - k) + 1;
217 k = e + 1;
218 }
219
220 if (kernel_device) {
221 struct udev_device *ud;
222
223 ud = udev_device_new_from_device_id(s->udev, kernel_device);
224 if (ud) {
225 const char *g;
226 struct udev_list_entry *ll;
227 char *b;
228
229 g = udev_device_get_devnode(ud);
230 if (g) {
231 b = strappend("_UDEV_DEVNODE=", g);
232 if (b) {
233 IOVEC_SET_STRING(iovec[n++], b);
234 z++;
235 }
236 }
237
238 g = udev_device_get_sysname(ud);
239 if (g) {
240 b = strappend("_UDEV_SYSNAME=", g);
241 if (b) {
242 IOVEC_SET_STRING(iovec[n++], b);
243 z++;
244 }
245 }
246
247 j = 0;
248 ll = udev_device_get_devlinks_list_entry(ud);
249 udev_list_entry_foreach(ll, ll) {
250
251 if (j > N_IOVEC_UDEV_FIELDS)
252 break;
253
254 g = udev_list_entry_get_name(ll);
ef63833d 255 if (g) {
4b94f3b8
ZJS
256 b = strappend("_UDEV_DEVLINK=", g);
257 if (b) {
258 IOVEC_SET_STRING(iovec[n++], b);
259 z++;
260 }
ef63833d
LP
261 }
262
263 j++;
264 }
265
266 udev_device_unref(ud);
267 }
268 }
269
e9f600f2 270 if (asprintf(&source_time, "_SOURCE_MONOTONIC_TIMESTAMP=%llu", usec) >= 0)
ef63833d
LP
271 IOVEC_SET_STRING(iovec[n++], source_time);
272
273 IOVEC_SET_STRING(iovec[n++], "_TRANSPORT=kernel");
274
275 if (asprintf(&syslog_priority, "PRIORITY=%i", priority & LOG_PRIMASK) >= 0)
276 IOVEC_SET_STRING(iovec[n++], syslog_priority);
277
36dd072c
MS
278 if (asprintf(&syslog_facility, "SYSLOG_FACILITY=%i", LOG_FAC(priority)) >= 0)
279 IOVEC_SET_STRING(iovec[n++], syslog_facility);
280
ef63833d
LP
281 if ((priority & LOG_FACMASK) == LOG_KERN)
282 IOVEC_SET_STRING(iovec[n++], "SYSLOG_IDENTIFIER=kernel");
283 else {
e88baee8 284 pl -= syslog_parse_identifier((const char**) &p, &identifier, &pid);
ef63833d
LP
285
286 /* Avoid any messages we generated ourselves via
287 * log_info() and friends. */
288 if (pid && is_us(pid))
289 goto finish;
290
291 if (identifier) {
292 syslog_identifier = strappend("SYSLOG_IDENTIFIER=", identifier);
293 if (syslog_identifier)
294 IOVEC_SET_STRING(iovec[n++], syslog_identifier);
295 }
296
297 if (pid) {
298 syslog_pid = strappend("SYSLOG_PID=", pid);
299 if (syslog_pid)
300 IOVEC_SET_STRING(iovec[n++], syslog_pid);
301 }
ef63833d
LP
302 }
303
527b7a42 304 if (cunescape_length_with_prefix(p, pl, "MESSAGE=", UNESCAPE_RELAX, &message) >= 0)
ef63833d
LP
305 IOVEC_SET_STRING(iovec[n++], message);
306
968f3196 307 server_dispatch_message(s, iovec, n, ELEMENTSOF(iovec), NULL, NULL, NULL, 0, NULL, priority, 0);
ef63833d
LP
308
309finish:
310 for (j = 0; j < z; j++)
311 free(iovec[j].iov_base);
312
313 free(message);
314 free(syslog_priority);
315 free(syslog_identifier);
316 free(syslog_pid);
317 free(syslog_facility);
318 free(source_time);
319 free(identifier);
320 free(pid);
321}
322
f9a810be 323static int server_read_dev_kmsg(Server *s) {
ef63833d
LP
324 char buffer[8192+1]; /* the kernel-side limit per record is 8K currently */
325 ssize_t l;
326
327 assert(s);
328 assert(s->dev_kmsg_fd >= 0);
329
330 l = read(s->dev_kmsg_fd, buffer, sizeof(buffer) - 1);
331 if (l == 0)
332 return 0;
333 if (l < 0) {
334 /* Old kernels who don't allow reading from /dev/kmsg
335 * return EINVAL when we try. So handle this cleanly,
336 * but don' try to ever read from it again. */
337 if (errno == EINVAL) {
f9a810be 338 s->dev_kmsg_event_source = sd_event_source_unref(s->dev_kmsg_event_source);
ef63833d
LP
339 return 0;
340 }
341
342 if (errno == EAGAIN || errno == EINTR || errno == EPIPE)
343 return 0;
344
56f64d95 345 log_error_errno(errno, "Failed to read from kernel: %m");
ef63833d
LP
346 return -errno;
347 }
348
349 dev_kmsg_record(s, buffer, l);
350 return 1;
351}
352
353int server_flush_dev_kmsg(Server *s) {
354 int r;
355
356 assert(s);
357
358 if (s->dev_kmsg_fd < 0)
359 return 0;
360
361 if (!s->dev_kmsg_readable)
362 return 0;
363
2b43f939 364 log_debug("Flushing /dev/kmsg...");
ef63833d
LP
365
366 for (;;) {
367 r = server_read_dev_kmsg(s);
368 if (r < 0)
369 return r;
370
371 if (r == 0)
372 break;
373 }
374
375 return 0;
376}
377
f9a810be
LP
378static int dispatch_dev_kmsg(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
379 Server *s = userdata;
380
381 assert(es);
382 assert(fd == s->dev_kmsg_fd);
383 assert(s);
384
385 if (revents & EPOLLERR)
386 log_warning("/dev/kmsg buffer overrun, some messages lost.");
387
388 if (!(revents & EPOLLIN))
389 log_error("Got invalid event from epoll for /dev/kmsg: %"PRIx32, revents);
390
391 return server_read_dev_kmsg(s);
392}
393
ef63833d 394int server_open_dev_kmsg(Server *s) {
f9a810be 395 int r;
ef63833d
LP
396
397 assert(s);
398
399 s->dev_kmsg_fd = open("/dev/kmsg", O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
400 if (s->dev_kmsg_fd < 0) {
445ea9be
LP
401 log_full(errno == ENOENT ? LOG_DEBUG : LOG_WARNING,
402 "Failed to open /dev/kmsg, ignoring: %m");
ef63833d
LP
403 return 0;
404 }
405
151b9b96 406 r = sd_event_add_io(s->event, &s->dev_kmsg_event_source, s->dev_kmsg_fd, EPOLLIN, dispatch_dev_kmsg, s);
f9a810be 407 if (r < 0) {
ef63833d
LP
408
409 /* This will fail with EPERM on older kernels where
410 * /dev/kmsg is not readable. */
c0f71f46
LP
411 if (r == -EPERM) {
412 r = 0;
413 goto fail;
414 }
ef63833d 415
da927ba9 416 log_error_errno(r, "Failed to add /dev/kmsg fd to event loop: %m");
c0f71f46 417 goto fail;
f9a810be
LP
418 }
419
420 r = sd_event_source_set_priority(s->dev_kmsg_event_source, SD_EVENT_PRIORITY_IMPORTANT+10);
421 if (r < 0) {
da927ba9 422 log_error_errno(r, "Failed to adjust priority of kmsg event source: %m");
c0f71f46 423 goto fail;
ef63833d
LP
424 }
425
426 s->dev_kmsg_readable = true;
427
428 return 0;
c0f71f46
LP
429
430fail:
03e334a1
LP
431 s->dev_kmsg_event_source = sd_event_source_unref(s->dev_kmsg_event_source);
432 s->dev_kmsg_fd = safe_close(s->dev_kmsg_fd);
c0f71f46
LP
433
434 return r;
ef63833d
LP
435}
436
437int server_open_kernel_seqnum(Server *s) {
03e334a1 438 _cleanup_close_ int fd;
ef63833d
LP
439 uint64_t *p;
440
441 assert(s);
442
443 /* We store the seqnum we last read in an mmaped file. That
444 * way we can just use it like a variable, but it is
b2e6df73 445 * persistent and automatically flushed at reboot. */
ef63833d
LP
446
447 fd = open("/run/systemd/journal/kernel-seqnum", O_RDWR|O_CREAT|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0644);
448 if (fd < 0) {
56f64d95 449 log_error_errno(errno, "Failed to open /run/systemd/journal/kernel-seqnum, ignoring: %m");
ef63833d
LP
450 return 0;
451 }
452
453 if (posix_fallocate(fd, 0, sizeof(uint64_t)) < 0) {
56f64d95 454 log_error_errno(errno, "Failed to allocate sequential number file, ignoring: %m");
ef63833d
LP
455 return 0;
456 }
457
458 p = mmap(NULL, sizeof(uint64_t), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
459 if (p == MAP_FAILED) {
56f64d95 460 log_error_errno(errno, "Failed to map sequential number file, ignoring: %m");
ef63833d
LP
461 return 0;
462 }
463
ef63833d
LP
464 s->kernel_seqnum = p;
465
466 return 0;
467}