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