]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/log.c
systemd: use pager for --test and --help
[thirdparty/systemd.git] / src / shared / log.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
5899f3b7 2
a7334b09
LP
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
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
a7334b09
LP
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
5430f7f2 16 Lesser General Public License for more details.
a7334b09 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
a7334b09
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
5899f3b7
LP
22#include <stdarg.h>
23#include <stdio.h>
c9b97d2a 24#include <errno.h>
16801e90
LP
25#include <unistd.h>
26#include <fcntl.h>
27#include <sys/socket.h>
28#include <sys/un.h>
5ba081b0 29#include <stddef.h>
963ddb91 30#include <printf.h>
5899f3b7
LP
31
32#include "log.h"
16801e90 33#include "util.h"
4db17f29 34#include "missing.h"
16801e90 35#include "macro.h"
5ba081b0 36#include "socket-util.h"
5899f3b7 37
bb99a35a
LP
38#define SNDBUF_SIZE (8*1024*1024)
39
16801e90 40static LogTarget log_target = LOG_TARGET_CONSOLE;
bbe63281 41static int log_max_level = LOG_INFO;
3eff4208 42static int log_facility = LOG_DAEMON;
16801e90 43
843d2643 44static int console_fd = STDERR_FILENO;
16801e90
LP
45static int syslog_fd = -1;
46static int kmsg_fd = -1;
5ba081b0 47static int journal_fd = -1;
16801e90 48
c31e1495
LP
49static bool syslog_is_stream = false;
50
bbe63281
LP
51static bool show_color = false;
52static bool show_location = false;
53
35b8ca3a 54/* Akin to glibc's __abort_msg; which is private and we hence cannot
185986c6
LP
55 * use here. */
56static char *log_abort_msg = NULL;
57
843d2643
LP
58void log_close_console(void) {
59
60 if (console_fd < 0)
61 return;
16801e90 62
c8513d54
LP
63 if (getpid() == 1) {
64 if (console_fd >= 3)
03e334a1 65 safe_close(console_fd);
c8513d54 66
843d2643 67 console_fd = -1;
16801e90
LP
68 }
69}
70
843d2643 71static int log_open_console(void) {
16801e90 72
843d2643 73 if (console_fd >= 0)
16801e90 74 return 0;
843d2643
LP
75
76 if (getpid() == 1) {
5ba081b0 77 console_fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
cd15c418 78 if (console_fd < 0)
843d2643 79 return console_fd;
843d2643
LP
80 } else
81 console_fd = STDERR_FILENO;
82
83 return 0;
84}
85
86void log_close_kmsg(void) {
03e334a1 87 kmsg_fd = safe_close(kmsg_fd);
843d2643
LP
88}
89
90static int log_open_kmsg(void) {
16801e90
LP
91
92 if (kmsg_fd >= 0)
93 return 0;
94
674f8283 95 kmsg_fd = open("/dev/kmsg", O_WRONLY|O_NOCTTY|O_CLOEXEC);
cd15c418 96 if (kmsg_fd < 0)
16801e90 97 return -errno;
0dae83f9 98
16801e90
LP
99 return 0;
100}
101
102void log_close_syslog(void) {
03e334a1 103 syslog_fd = safe_close(syslog_fd);
16801e90
LP
104}
105
c31e1495 106static int create_log_socket(int type) {
c31e1495 107 int fd;
8b18fdc1 108 struct timeval tv;
c31e1495 109
8b18fdc1 110 fd = socket(AF_UNIX, type|SOCK_CLOEXEC, 0);
5ba081b0 111 if (fd < 0)
c31e1495
LP
112 return -errno;
113
bb99a35a
LP
114 fd_inc_sndbuf(fd, SNDBUF_SIZE);
115
8b18fdc1
LP
116 /* We need a blocking fd here since we'd otherwise lose
117 messages way too early. However, let's not hang forever in the
118 unlikely case of a deadlock. */
4d89874a
ZJS
119 if (getpid() == 1)
120 timeval_store(&tv, 10 * USEC_PER_MSEC);
121 else
122 timeval_store(&tv, 10 * USEC_PER_SEC);
8b18fdc1
LP
123 setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
124
c31e1495
LP
125 return fd;
126}
127
843d2643 128static int log_open_syslog(void) {
16801e90 129 int r;
b92bea5d
ZJS
130 union sockaddr_union sa = {
131 .un.sun_family = AF_UNIX,
132 .un.sun_path = "/dev/log",
133 };
16801e90 134
16801e90
LP
135 if (syslog_fd >= 0)
136 return 0;
137
5ba081b0
LP
138 syslog_fd = create_log_socket(SOCK_DGRAM);
139 if (syslog_fd < 0) {
140 r = syslog_fd;
843d2643 141 goto fail;
16801e90
LP
142 }
143
3338b959 144 if (connect(syslog_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
03e334a1 145 safe_close(syslog_fd);
c31e1495
LP
146
147 /* Some legacy syslog systems still use stream
148 * sockets. They really shouldn't. But what can we
149 * do... */
5ba081b0
LP
150 syslog_fd = create_log_socket(SOCK_STREAM);
151 if (syslog_fd < 0) {
152 r = syslog_fd;
c31e1495
LP
153 goto fail;
154 }
155
3338b959 156 if (connect(syslog_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
c31e1495
LP
157 r = -errno;
158 goto fail;
159 }
160
161 syslog_is_stream = true;
162 } else
163 syslog_is_stream = false;
164
16801e90 165 return 0;
843d2643
LP
166
167fail:
168 log_close_syslog();
843d2643
LP
169 return r;
170}
171
5ba081b0 172void log_close_journal(void) {
03e334a1 173 journal_fd = safe_close(journal_fd);
5ba081b0
LP
174}
175
176static int log_open_journal(void) {
b92bea5d
ZJS
177 union sockaddr_union sa = {
178 .un.sun_family = AF_UNIX,
179 .un.sun_path = "/run/systemd/journal/socket",
180 };
5ba081b0
LP
181 int r;
182
183 if (journal_fd >= 0)
184 return 0;
185
186 journal_fd = create_log_socket(SOCK_DGRAM);
187 if (journal_fd < 0) {
188 r = journal_fd;
189 goto fail;
190 }
191
5ba081b0
LP
192 if (connect(journal_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
193 r = -errno;
194 goto fail;
195 }
196
5ba081b0
LP
197 return 0;
198
199fail:
200 log_close_journal();
5ba081b0
LP
201 return r;
202}
203
843d2643
LP
204int log_open(void) {
205 int r;
206
207 /* If we don't use the console we close it here, to not get
208 * killed by SAK. If we don't use syslog we close it here so
209 * that we are not confused by somebody deleting the socket in
210 * the fs. If we don't use /dev/kmsg we still keep it open,
211 * because there is no reason to close it. */
212
9fae33d2 213 if (log_target == LOG_TARGET_NULL) {
5ba081b0 214 log_close_journal();
9fae33d2
LP
215 log_close_syslog();
216 log_close_console();
217 return 0;
218 }
219
a6903061 220 if ((log_target != LOG_TARGET_AUTO && log_target != LOG_TARGET_SAFE) ||
bb7df0da 221 getpid() == 1 ||
f41c094c 222 isatty(STDERR_FILENO) <= 0) {
bb7df0da
LP
223
224 if (log_target == LOG_TARGET_AUTO ||
5ba081b0
LP
225 log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
226 log_target == LOG_TARGET_JOURNAL) {
227 r = log_open_journal();
228 if (r >= 0) {
229 log_close_syslog();
bb7df0da
LP
230 log_close_console();
231 return r;
232 }
5ba081b0
LP
233 }
234
235 if (log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
236 log_target == LOG_TARGET_SYSLOG) {
237 r = log_open_syslog();
238 if (r >= 0) {
239 log_close_journal();
240 log_close_console();
241 return r;
242 }
243 }
244
bb7df0da 245 if (log_target == LOG_TARGET_AUTO ||
a6903061 246 log_target == LOG_TARGET_SAFE ||
5ba081b0 247 log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
bb7df0da 248 log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
5ba081b0
LP
249 log_target == LOG_TARGET_KMSG) {
250 r = log_open_kmsg();
251 if (r >= 0) {
252 log_close_journal();
bb7df0da
LP
253 log_close_syslog();
254 log_close_console();
255 return r;
256 }
5ba081b0 257 }
bb7df0da 258 }
843d2643 259
5ba081b0 260 log_close_journal();
843d2643 261 log_close_syslog();
dcdf86bb 262
843d2643 263 return log_open_console();
16801e90
LP
264}
265
266void log_set_target(LogTarget target) {
267 assert(target >= 0);
268 assert(target < _LOG_TARGET_MAX);
269
270 log_target = target;
271}
272
871e5809 273void log_close(void) {
5ba081b0 274 log_close_journal();
871e5809 275 log_close_syslog();
5ba081b0
LP
276 log_close_kmsg();
277 log_close_console();
871e5809
LP
278}
279
4d8a7798 280void log_forget_fds(void) {
5ba081b0 281 console_fd = kmsg_fd = syslog_fd = journal_fd = -1;
4d8a7798
MS
282}
283
16801e90
LP
284void log_set_max_level(int level) {
285 assert((level & LOG_PRIMASK) == level);
286
287 log_max_level = level;
288}
289
3eff4208
LP
290void log_set_facility(int facility) {
291 log_facility = facility;
292}
293
843d2643 294static int write_to_console(
20c03b7b
LP
295 int level,
296 const char*file,
297 int line,
298 const char *func,
fdf9f9bb
ZJS
299 const char *object_name,
300 const char *object,
20c03b7b 301 const char *buffer) {
5899f3b7 302
843d2643 303 char location[64];
b92bea5d 304 struct iovec iovec[5] = {};
843d2643
LP
305 unsigned n = 0;
306 bool highlight;
5899f3b7 307
843d2643
LP
308 if (console_fd < 0)
309 return 0;
310
bbe63281 311 highlight = LOG_PRI(level) <= LOG_ERR && show_color;
843d2643 312
674f8283
LP
313 if (show_location) {
314 snprintf(location, sizeof(location), "(%s:%u) ", file, line);
315 char_array_0(location);
bbe63281 316 IOVEC_SET_STRING(iovec[n++], location);
674f8283
LP
317 }
318
843d2643 319 if (highlight)
c1072ea0 320 IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_RED_ON);
843d2643
LP
321 IOVEC_SET_STRING(iovec[n++], buffer);
322 if (highlight)
61cbdc4b 323 IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_OFF);
843d2643
LP
324 IOVEC_SET_STRING(iovec[n++], "\n");
325
0e6eaa2d
LP
326 if (writev(console_fd, iovec, n) < 0) {
327
328 if (errno == EIO && getpid() == 1) {
329
330 /* If somebody tried to kick us from our
331 * console tty (via vhangup() or suchlike),
332 * try to reconnect */
333
334 log_close_console();
335 log_open_console();
336
337 if (console_fd < 0)
338 return 0;
339
340 if (writev(console_fd, iovec, n) < 0)
341 return -errno;
342 } else
343 return -errno;
344 }
5899f3b7 345
843d2643 346 return 1;
16801e90 347}
5899f3b7 348
16801e90
LP
349static int write_to_syslog(
350 int level,
351 const char*file,
352 int line,
353 const char *func,
fdf9f9bb
ZJS
354 const char *object_name,
355 const char *object,
843d2643 356 const char *buffer) {
16801e90
LP
357
358 char header_priority[16], header_time[64], header_pid[16];
b92bea5d
ZJS
359 struct iovec iovec[5] = {};
360 struct msghdr msghdr = {
361 .msg_iov = iovec,
362 .msg_iovlen = ELEMENTSOF(iovec),
363 };
16801e90
LP
364 time_t t;
365 struct tm *tm;
366
367 if (syslog_fd < 0)
843d2643 368 return 0;
16801e90 369
29db5834 370 snprintf(header_priority, sizeof(header_priority), "<%i>", level);
16801e90
LP
371 char_array_0(header_priority);
372
373 t = (time_t) (now(CLOCK_REALTIME) / USEC_PER_SEC);
fdf9f9bb
ZJS
374 tm = localtime(&t);
375 if (!tm)
16801e90
LP
376 return -EINVAL;
377
378 if (strftime(header_time, sizeof(header_time), "%h %e %T ", tm) <= 0)
379 return -EINVAL;
380
de0671ee 381 snprintf(header_pid, sizeof(header_pid), "["PID_FMT"]: ", getpid());
16801e90
LP
382 char_array_0(header_pid);
383
16801e90
LP
384 IOVEC_SET_STRING(iovec[0], header_priority);
385 IOVEC_SET_STRING(iovec[1], header_time);
5b6319dc 386 IOVEC_SET_STRING(iovec[2], program_invocation_short_name);
16801e90
LP
387 IOVEC_SET_STRING(iovec[3], header_pid);
388 IOVEC_SET_STRING(iovec[4], buffer);
389
c899f8c6 390 /* When using syslog via SOCK_STREAM separate the messages by NUL chars */
c31e1495
LP
391 if (syslog_is_stream)
392 iovec[4].iov_len++;
393
c31e1495
LP
394 for (;;) {
395 ssize_t n;
396
8f7f7a1b
MS
397 n = sendmsg(syslog_fd, &msghdr, MSG_NOSIGNAL);
398 if (n < 0)
c31e1495
LP
399 return -errno;
400
401 if (!syslog_is_stream ||
402 (size_t) n >= IOVEC_TOTAL_SIZE(iovec, ELEMENTSOF(iovec)))
403 break;
404
405 IOVEC_INCREMENT(iovec, ELEMENTSOF(iovec), n);
406 }
16801e90 407
843d2643 408 return 1;
16801e90
LP
409}
410
411static int write_to_kmsg(
412 int level,
413 const char*file,
414 int line,
415 const char *func,
fdf9f9bb
ZJS
416 const char *object_name,
417 const char *object,
843d2643 418 const char *buffer) {
16801e90
LP
419
420 char header_priority[16], header_pid[16];
b92bea5d 421 struct iovec iovec[5] = {};
16801e90
LP
422
423 if (kmsg_fd < 0)
843d2643 424 return 0;
16801e90 425
29db5834 426 snprintf(header_priority, sizeof(header_priority), "<%i>", level);
16801e90
LP
427 char_array_0(header_priority);
428
de0671ee 429 snprintf(header_pid, sizeof(header_pid), "["PID_FMT"]: ", getpid());
16801e90
LP
430 char_array_0(header_pid);
431
16801e90 432 IOVEC_SET_STRING(iovec[0], header_priority);
5b6319dc 433 IOVEC_SET_STRING(iovec[1], program_invocation_short_name);
16801e90
LP
434 IOVEC_SET_STRING(iovec[2], header_pid);
435 IOVEC_SET_STRING(iovec[3], buffer);
843d2643 436 IOVEC_SET_STRING(iovec[4], "\n");
16801e90
LP
437
438 if (writev(kmsg_fd, iovec, ELEMENTSOF(iovec)) < 0)
439 return -errno;
440
843d2643 441 return 1;
16801e90
LP
442}
443
41a79f10
ZJS
444static int log_do_header(char *header, size_t size,
445 int level,
446 const char *file, int line, const char *func,
447 const char *object_name, const char *object) {
448 snprintf(header, size,
5ba081b0 449 "PRIORITY=%i\n"
3eff4208 450 "SYSLOG_FACILITY=%i\n"
e429981b
ZJS
451 "%s%.*s%s"
452 "%s%.*i%s"
453 "%s%.*s%s"
fdf9f9bb 454 "%s%.*s%s"
41a79f10 455 "SYSLOG_IDENTIFIER=%s\n",
5ba081b0 456 LOG_PRI(level),
3eff4208 457 LOG_FAC(level),
e429981b
ZJS
458 file ? "CODE_FILE=" : "",
459 file ? LINE_MAX : 0, file, /* %.0s means no output */
460 file ? "\n" : "",
461 line ? "CODE_LINE=" : "",
462 line ? 1 : 0, line, /* %.0d means no output too, special case for 0 */
463 line ? "\n" : "",
464 func ? "CODE_FUNCTION=" : "",
465 func ? LINE_MAX : 0, func,
466 func ? "\n" : "",
fdf9f9bb
ZJS
467 object ? object_name : "",
468 object ? LINE_MAX : 0, object, /* %.0s means no output */
469 object ? "\n" : "",
d29b05a4 470 program_invocation_short_name);
41a79f10
ZJS
471 header[size - 1] = '\0';
472 return 0;
473}
5ba081b0 474
41a79f10
ZJS
475static int write_to_journal(
476 int level,
477 const char*file,
478 int line,
479 const char *func,
480 const char *object_name,
481 const char *object,
482 const char *buffer) {
483
484 char header[LINE_MAX];
b92bea5d
ZJS
485 struct iovec iovec[4] = {};
486 struct msghdr mh = {};
41a79f10
ZJS
487
488 if (journal_fd < 0)
489 return 0;
490
491 log_do_header(header, sizeof(header), level,
492 file, line, func, object_name, object);
5ba081b0 493
5ba081b0 494 IOVEC_SET_STRING(iovec[0], header);
41a79f10
ZJS
495 IOVEC_SET_STRING(iovec[1], "MESSAGE=");
496 IOVEC_SET_STRING(iovec[2], buffer);
497 IOVEC_SET_STRING(iovec[3], "\n");
5ba081b0 498
5ba081b0
LP
499 mh.msg_iov = iovec;
500 mh.msg_iovlen = ELEMENTSOF(iovec);
501
502 if (sendmsg(journal_fd, &mh, MSG_NOSIGNAL) < 0)
503 return -errno;
504
505 return 1;
506}
507
843d2643
LP
508static int log_dispatch(
509 int level,
510 const char*file,
511 int line,
512 const char *func,
fdf9f9bb
ZJS
513 const char *object_name,
514 const char *object,
9726b29e 515 char *buffer) {
843d2643 516
9726b29e 517 int r = 0;
843d2643 518
9fae33d2
LP
519 if (log_target == LOG_TARGET_NULL)
520 return 0;
521
29db5834 522 /* Patch in LOG_DAEMON facility if necessary */
7d76f312 523 if ((level & LOG_FACMASK) == 0)
3eff4208 524 level = log_facility | LOG_PRI(level);
29db5834 525
9726b29e
LP
526 do {
527 char *e;
9499b235 528 int k = 0;
843d2643 529
9726b29e 530 buffer += strspn(buffer, NEWLINE);
843d2643 531
9726b29e
LP
532 if (buffer[0] == 0)
533 break;
843d2643 534
9726b29e
LP
535 if ((e = strpbrk(buffer, NEWLINE)))
536 *(e++) = 0;
843d2643 537
bb7df0da 538 if (log_target == LOG_TARGET_AUTO ||
5ba081b0
LP
539 log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
540 log_target == LOG_TARGET_JOURNAL) {
541
fdf9f9bb
ZJS
542 k = write_to_journal(level, file, line, func,
543 object_name, object, buffer);
4e7bc3f3
LP
544 if (k < 0) {
545 if (k != -EAGAIN)
5ba081b0
LP
546 log_close_journal();
547 log_open_kmsg();
4e7bc3f3 548 } else if (k > 0)
5ba081b0
LP
549 r++;
550 }
551
552 if (log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
9726b29e
LP
553 log_target == LOG_TARGET_SYSLOG) {
554
fdf9f9bb
ZJS
555 k = write_to_syslog(level, file, line, func,
556 object_name, object, buffer);
4e7bc3f3
LP
557 if (k < 0) {
558 if (k != -EAGAIN)
8f7f7a1b 559 log_close_syslog();
9726b29e 560 log_open_kmsg();
4e7bc3f3 561 } else if (k > 0)
9726b29e
LP
562 r++;
563 }
564
9499b235 565 if (k <= 0 &&
bb7df0da 566 (log_target == LOG_TARGET_AUTO ||
a6903061 567 log_target == LOG_TARGET_SAFE ||
bb7df0da 568 log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
678d485a 569 log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
9499b235 570 log_target == LOG_TARGET_KMSG)) {
9726b29e 571
fdf9f9bb
ZJS
572 k = write_to_kmsg(level, file, line, func,
573 object_name, object, buffer);
4e7bc3f3
LP
574 if (k < 0) {
575 log_close_kmsg();
9726b29e 576 log_open_console();
4e7bc3f3 577 } else if (k > 0)
9726b29e
LP
578 r++;
579 }
580
8f7f7a1b 581 if (k <= 0) {
fdf9f9bb
ZJS
582 k = write_to_console(level, file, line, func,
583 object_name, object, buffer);
8f7f7a1b
MS
584 if (k < 0)
585 return k;
586 }
9726b29e
LP
587
588 buffer = e;
589 } while (buffer);
590
591 return r;
843d2643
LP
592}
593
2149e37c
LP
594int log_dump_internal(
595 int level,
596 const char*file,
597 int line,
598 const char *func,
599 char *buffer) {
600
5c0aa72a 601 PROTECT_ERRNO;
2149e37c
LP
602
603 /* This modifies the buffer... */
604
605 if (_likely_(LOG_PRI(level) > log_max_level))
606 return 0;
607
5c0aa72a 608 return log_dispatch(level, file, line, func, NULL, NULL, buffer);
2149e37c
LP
609}
610
17a94911 611int log_metav(
16801e90
LP
612 int level,
613 const char*file,
614 int line,
615 const char *func,
17a94911
LP
616 const char *format,
617 va_list ap) {
16801e90 618
5c0aa72a 619 PROTECT_ERRNO;
addab137 620 char buffer[LINE_MAX];
16801e90 621
93a46b0b 622 if (_likely_(LOG_PRI(level) > log_max_level))
843d2643 623 return 0;
16801e90 624
843d2643 625 vsnprintf(buffer, sizeof(buffer), format, ap);
843d2643
LP
626 char_array_0(buffer);
627
5c0aa72a 628 return log_dispatch(level, file, line, func, NULL, NULL, buffer);
185986c6 629}
16801e90 630
17a94911
LP
631int log_meta(
632 int level,
633 const char*file,
634 int line,
635 const char *func,
636 const char *format, ...) {
637
638 int r;
639 va_list ap;
640
641 va_start(ap, format);
642 r = log_metav(level, file, line, func, format, ap);
643 va_end(ap);
644
645 return r;
646}
647
fdf9f9bb
ZJS
648int log_metav_object(
649 int level,
650 const char*file,
651 int line,
652 const char *func,
653 const char *object_name,
654 const char *object,
655 const char *format,
656 va_list ap) {
657
5c0aa72a 658 PROTECT_ERRNO;
fdf9f9bb 659 char buffer[LINE_MAX];
fdf9f9bb
ZJS
660
661 if (_likely_(LOG_PRI(level) > log_max_level))
662 return 0;
663
fdf9f9bb
ZJS
664 vsnprintf(buffer, sizeof(buffer), format, ap);
665 char_array_0(buffer);
666
5c0aa72a
LP
667 return log_dispatch(level, file, line, func,
668 object_name, object, buffer);
fdf9f9bb
ZJS
669}
670
671int log_meta_object(
672 int level,
673 const char*file,
674 int line,
675 const char *func,
676 const char *object_name,
677 const char *object,
678 const char *format, ...) {
679
680 int r;
681 va_list ap;
682
683 va_start(ap, format);
684 r = log_metav_object(level, file, line, func,
685 object_name, object, format, ap);
686 va_end(ap);
687
688 return r;
689}
690
80514f9c 691static void log_assert(int level, const char *text, const char *file, int line, const char *func, const char *format) {
addab137 692 static char buffer[LINE_MAX];
185986c6 693
50f72bca
ZJS
694 if (_likely_(LOG_PRI(level) > log_max_level))
695 return;
696
bcfce235 697 DISABLE_WARNING_FORMAT_NONLITERAL;
b7f33638 698 snprintf(buffer, sizeof(buffer), format, text, file, line, func);
bcfce235 699 REENABLE_WARNING;
185986c6
LP
700
701 char_array_0(buffer);
702 log_abort_msg = buffer;
703
80514f9c 704 log_dispatch(level, file, line, func, NULL, NULL, buffer);
5899f3b7 705}
34f0e866 706
919ce0b7 707noreturn void log_assert_failed(const char *text, const char *file, int line, const char *func) {
80514f9c
LP
708 log_assert(LOG_CRIT, text, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Aborting.");
709 abort();
b7f33638
MS
710}
711
919ce0b7 712noreturn void log_assert_failed_unreachable(const char *text, const char *file, int line, const char *func) {
80514f9c
LP
713 log_assert(LOG_CRIT, text, file, line, func, "Code should not be reached '%s' at %s:%u, function %s(). Aborting.");
714 abort();
715}
716
717void log_assert_failed_return(const char *text, const char *file, int line, const char *func) {
e5ca092c 718 PROTECT_ERRNO;
80514f9c 719 log_assert(LOG_DEBUG, text, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Ignoring.");
b7f33638
MS
720}
721
877d54e9 722int log_oom_internal(const char *file, int line, const char *func) {
6dc1e7e0
MS
723 log_meta(LOG_ERR, file, line, func, "Out of memory.");
724 return -ENOMEM;
725}
726
877d54e9
LP
727int log_struct_internal(
728 int level,
729 const char *file,
730 int line,
731 const char *func,
732 const char *format, ...) {
733
5c0aa72a 734 PROTECT_ERRNO;
877d54e9
LP
735 va_list ap;
736 int r;
737
738 if (_likely_(LOG_PRI(level) > log_max_level))
739 return 0;
740
741 if (log_target == LOG_TARGET_NULL)
742 return 0;
743
744 if ((level & LOG_FACMASK) == 0)
745 level = log_facility | LOG_PRI(level);
746
877d54e9
LP
747 if ((log_target == LOG_TARGET_AUTO ||
748 log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
749 log_target == LOG_TARGET_JOURNAL) &&
750 journal_fd >= 0) {
751
752 char header[LINE_MAX];
b92bea5d 753 struct iovec iovec[17] = {};
877d54e9 754 unsigned n = 0, i;
543295ad
ZJS
755 struct msghdr mh = {
756 .msg_iov = iovec,
757 };
41a79f10 758 static const char nl = '\n';
877d54e9
LP
759
760 /* If the journal is available do structured logging */
41a79f10
ZJS
761 log_do_header(header, sizeof(header), level,
762 file, line, func, NULL, NULL);
877d54e9
LP
763 IOVEC_SET_STRING(iovec[n++], header);
764
765 va_start(ap, format);
766 while (format && n + 1 < ELEMENTSOF(iovec)) {
767 char *buf;
963ddb91 768 va_list aq;
877d54e9 769
963ddb91
LP
770 /* We need to copy the va_list structure,
771 * since vasprintf() leaves it afterwards at
772 * an undefined location */
773
774 va_copy(aq, ap);
775 if (vasprintf(&buf, format, aq) < 0) {
776 va_end(aq);
877d54e9
LP
777 r = -ENOMEM;
778 goto finish;
779 }
963ddb91
LP
780 va_end(aq);
781
782 /* Now, jump enough ahead, so that we point to
783 * the next format string */
784 VA_FORMAT_ADVANCE(format, ap);
877d54e9
LP
785
786 IOVEC_SET_STRING(iovec[n++], buf);
787
788 iovec[n].iov_base = (char*) &nl;
789 iovec[n].iov_len = 1;
790 n++;
791
792 format = va_arg(ap, char *);
793 }
877d54e9 794
877d54e9
LP
795 mh.msg_iovlen = n;
796
797 if (sendmsg(journal_fd, &mh, MSG_NOSIGNAL) < 0)
798 r = -errno;
799 else
800 r = 1;
801
802 finish:
e98055de 803 va_end(ap);
877d54e9
LP
804 for (i = 1; i < n; i += 2)
805 free(iovec[i].iov_base);
806
807 } else {
808 char buf[LINE_MAX];
809 bool found = false;
810
811 /* Fallback if journal logging is not available */
812
813 va_start(ap, format);
814 while (format) {
963ddb91 815 va_list aq;
877d54e9 816
963ddb91
LP
817 va_copy(aq, ap);
818 vsnprintf(buf, sizeof(buf), format, aq);
819 va_end(aq);
877d54e9
LP
820 char_array_0(buf);
821
822 if (startswith(buf, "MESSAGE=")) {
823 found = true;
824 break;
825 }
826
963ddb91
LP
827 VA_FORMAT_ADVANCE(format, ap);
828
877d54e9
LP
829 format = va_arg(ap, char *);
830 }
831 va_end(ap);
832
833 if (found)
fdf9f9bb
ZJS
834 r = log_dispatch(level, file, line, func,
835 NULL, NULL, buf + 8);
877d54e9
LP
836 else
837 r = -EINVAL;
838 }
839
877d54e9
LP
840 return r;
841}
842
34f0e866
LP
843int log_set_target_from_string(const char *e) {
844 LogTarget t;
845
5ba081b0
LP
846 t = log_target_from_string(e);
847 if (t < 0)
34f0e866
LP
848 return -EINVAL;
849
850 log_set_target(t);
851 return 0;
852}
853
854int log_set_max_level_from_string(const char *e) {
855 int t;
856
5ba081b0
LP
857 t = log_level_from_string(e);
858 if (t < 0)
859 return t;
34f0e866
LP
860
861 log_set_max_level(t);
862 return 0;
863}
864
865void log_parse_environment(void) {
b8d0ffc2 866 _cleanup_free_ char *line = NULL;
34f0e866 867 const char *e;
b8d0ffc2
LP
868 int r;
869
870 r = proc_cmdline(&line);
871 if (r < 0)
872 log_warning("Failed to read /proc/cmdline. Ignoring: %s", strerror(-r));
873 else if (r > 0) {
874 char *w, *state;
875 size_t l;
876
877 FOREACH_WORD_QUOTED(w, l, line, state) {
878 if (l == 5 && startswith(w, "debug")) {
879 log_set_max_level(LOG_DEBUG);
880 break;
881 }
882 }
883 }
34f0e866 884
4db17f29 885 e = secure_getenv("SYSTEMD_LOG_TARGET");
88fae6e0
LP
886 if (e && log_set_target_from_string(e) < 0)
887 log_warning("Failed to parse log target %s. Ignoring.", e);
34f0e866 888
4db17f29 889 e = secure_getenv("SYSTEMD_LOG_LEVEL");
88fae6e0
LP
890 if (e && log_set_max_level_from_string(e) < 0)
891 log_warning("Failed to parse log level %s. Ignoring.", e);
bbe63281 892
4db17f29 893 e = secure_getenv("SYSTEMD_LOG_COLOR");
88fae6e0
LP
894 if (e && log_show_color_from_string(e) < 0)
895 log_warning("Failed to parse bool %s. Ignoring.", e);
bbe63281 896
4db17f29 897 e = secure_getenv("SYSTEMD_LOG_LOCATION");
88fae6e0
LP
898 if (e && log_show_location_from_string(e) < 0)
899 log_warning("Failed to parse bool %s. Ignoring.", e);
34f0e866
LP
900}
901
1adf1049
LP
902LogTarget log_get_target(void) {
903 return log_target;
904}
905
906int log_get_max_level(void) {
907 return log_max_level;
908}
909
bbe63281
LP
910void log_show_color(bool b) {
911 show_color = b;
912}
913
b1e90ec5
ZJS
914bool log_get_show_color(void) {
915 return show_color;
916}
917
bbe63281
LP
918void log_show_location(bool b) {
919 show_location = b;
920}
921
b1e90ec5
ZJS
922bool log_get_show_location(void) {
923 return show_location;
924}
925
bbe63281
LP
926int log_show_color_from_string(const char *e) {
927 int t;
928
5ba081b0
LP
929 t = parse_boolean(e);
930 if (t < 0)
931 return t;
bbe63281
LP
932
933 log_show_color(t);
934 return 0;
935}
936
937int log_show_location_from_string(const char *e) {
938 int t;
939
5ba081b0
LP
940 t = parse_boolean(e);
941 if (t < 0)
942 return t;
bbe63281
LP
943
944 log_show_location(t);
945 return 0;
946}
947
81270860
LP
948bool log_on_console(void) {
949 if (log_target == LOG_TARGET_CONSOLE)
950 return true;
951
952 return syslog_fd < 0 && kmsg_fd < 0 && journal_fd < 0;
953}
954
2c5859af 955static const char *const log_target_table[_LOG_TARGET_MAX] = {
34f0e866 956 [LOG_TARGET_CONSOLE] = "console",
34f0e866 957 [LOG_TARGET_KMSG] = "kmsg",
5ba081b0
LP
958 [LOG_TARGET_JOURNAL] = "journal",
959 [LOG_TARGET_JOURNAL_OR_KMSG] = "journal-or-kmsg",
960 [LOG_TARGET_SYSLOG] = "syslog",
843d2643 961 [LOG_TARGET_SYSLOG_OR_KMSG] = "syslog-or-kmsg",
5ba081b0 962 [LOG_TARGET_AUTO] = "auto",
a6903061 963 [LOG_TARGET_SAFE] = "safe",
5ba081b0 964 [LOG_TARGET_NULL] = "null"
34f0e866
LP
965};
966
967DEFINE_STRING_TABLE_LOOKUP(log_target, LogTarget);
4daf54a8
ZJS
968
969void log_received_signal(int level, const struct signalfd_siginfo *si) {
970 if (si->ssi_pid > 0) {
971 _cleanup_free_ char *p = NULL;
972
973 get_process_comm(si->ssi_pid, &p);
974
975 log_full(level,
976 "Received SIG%s from PID "PID_FMT" (%s).",
977 signal_to_string(si->ssi_signo),
978 si->ssi_pid, strna(p));
979 } else
980 log_full(level,
981 "Received SIG%s.",
982 signal_to_string(si->ssi_signo));
983
984}