]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal/journald-kmsg.c
localed: system-setup-keyboard is no more on fedora
[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
22#include <unistd.h>
23#include <sys/epoll.h>
24#include <fcntl.h>
25#include <sys/mman.h>
4871690d 26#include <sys/socket.h>
ef63833d
LP
27
28#include <systemd/sd-messages.h>
29#include <libudev.h>
30
31#include "journald.h"
32#include "journald-kmsg.h"
35e2e347 33#include "journald-syslog.h"
ef63833d
LP
34
35void 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
96static 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
107static 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 {
5809560d 278 syslog_parse_identifier((const char**) &p, &identifier, &pid);
ef63833d
LP
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
307finish:
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
321int 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
351int 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_info("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
376int 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
406int 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 * persistant 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}