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