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