]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/log.c
Merge branch 'python-systemd-reader'
[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 int saved_errno, r;
602
603 /* This modifies the buffer... */
604
605 if (_likely_(LOG_PRI(level) > log_max_level))
606 return 0;
607
608 saved_errno = errno;
609 r = log_dispatch(level, file, line, func, NULL, NULL, buffer);
610 errno = saved_errno;
611
612 return r;
613 }
614
615 int log_metav(
616 int level,
617 const char*file,
618 int line,
619 const char *func,
620 const char *format,
621 va_list ap) {
622
623 char buffer[LINE_MAX];
624 int saved_errno, r;
625
626 if (_likely_(LOG_PRI(level) > log_max_level))
627 return 0;
628
629 saved_errno = errno;
630 vsnprintf(buffer, sizeof(buffer), format, ap);
631 char_array_0(buffer);
632
633 r = log_dispatch(level, file, line, func, NULL, NULL, buffer);
634 errno = saved_errno;
635
636 return r;
637 }
638
639 int log_meta(
640 int level,
641 const char*file,
642 int line,
643 const char *func,
644 const char *format, ...) {
645
646 int r;
647 va_list ap;
648
649 va_start(ap, format);
650 r = log_metav(level, file, line, func, format, ap);
651 va_end(ap);
652
653 return r;
654 }
655
656 int log_metav_object(
657 int level,
658 const char*file,
659 int line,
660 const char *func,
661 const char *object_name,
662 const char *object,
663 const char *format,
664 va_list ap) {
665
666 char buffer[LINE_MAX];
667 int saved_errno, r;
668
669 if (_likely_(LOG_PRI(level) > log_max_level))
670 return 0;
671
672 saved_errno = errno;
673 vsnprintf(buffer, sizeof(buffer), format, ap);
674 char_array_0(buffer);
675
676 r = log_dispatch(level, file, line, func,
677 object_name, object, buffer);
678 errno = saved_errno;
679
680 return r;
681 }
682
683 int log_meta_object(
684 int level,
685 const char*file,
686 int line,
687 const char *func,
688 const char *object_name,
689 const char *object,
690 const char *format, ...) {
691
692 int r;
693 va_list ap;
694
695 va_start(ap, format);
696 r = log_metav_object(level, file, line, func,
697 object_name, object, format, ap);
698 va_end(ap);
699
700 return r;
701 }
702
703 #pragma GCC diagnostic push
704 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
705 _noreturn_ static void log_assert(const char *text, const char *file, int line, const char *func, const char *format) {
706 static char buffer[LINE_MAX];
707
708 snprintf(buffer, sizeof(buffer), format, text, file, line, func);
709
710 char_array_0(buffer);
711 log_abort_msg = buffer;
712
713 log_dispatch(LOG_CRIT, file, line, func, NULL, NULL, buffer);
714 abort();
715 }
716 #pragma GCC diagnostic pop
717
718 _noreturn_ void log_assert_failed(const char *text, const char *file, int line, const char *func) {
719 log_assert(text, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Aborting.");
720 }
721
722 _noreturn_ void log_assert_failed_unreachable(const char *text, const char *file, int line, const char *func) {
723 log_assert(text, file, line, func, "Code should not be reached '%s' at %s:%u, function %s(). Aborting.");
724 }
725
726 int log_oom_internal(const char *file, int line, const char *func) {
727 log_meta(LOG_ERR, file, line, func, "Out of memory.");
728 return -ENOMEM;
729 }
730
731 int log_struct_internal(
732 int level,
733 const char *file,
734 int line,
735 const char *func,
736 const char *format, ...) {
737
738 int saved_errno;
739 va_list ap;
740 int r;
741
742 if (_likely_(LOG_PRI(level) > log_max_level))
743 return 0;
744
745 if (log_target == LOG_TARGET_NULL)
746 return 0;
747
748 if ((level & LOG_FACMASK) == 0)
749 level = log_facility | LOG_PRI(level);
750
751 saved_errno = errno;
752
753 if ((log_target == LOG_TARGET_AUTO ||
754 log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
755 log_target == LOG_TARGET_JOURNAL) &&
756 journal_fd >= 0) {
757
758 char header[LINE_MAX];
759 struct iovec iovec[17] = {{0}};
760 unsigned n = 0, i;
761 struct msghdr mh;
762 static const char nl = '\n';
763
764 /* If the journal is available do structured logging */
765 log_do_header(header, sizeof(header), level,
766 file, line, func, NULL, NULL);
767 IOVEC_SET_STRING(iovec[n++], header);
768
769 va_start(ap, format);
770 while (format && n + 1 < ELEMENTSOF(iovec)) {
771 char *buf;
772 va_list aq;
773
774 /* We need to copy the va_list structure,
775 * since vasprintf() leaves it afterwards at
776 * an undefined location */
777
778 va_copy(aq, ap);
779 if (vasprintf(&buf, format, aq) < 0) {
780 va_end(aq);
781 r = -ENOMEM;
782 goto finish;
783 }
784 va_end(aq);
785
786 /* Now, jump enough ahead, so that we point to
787 * the next format string */
788 VA_FORMAT_ADVANCE(format, ap);
789
790 IOVEC_SET_STRING(iovec[n++], buf);
791
792 iovec[n].iov_base = (char*) &nl;
793 iovec[n].iov_len = 1;
794 n++;
795
796 format = va_arg(ap, char *);
797 }
798
799 zero(mh);
800 mh.msg_iov = iovec;
801 mh.msg_iovlen = n;
802
803 if (sendmsg(journal_fd, &mh, MSG_NOSIGNAL) < 0)
804 r = -errno;
805 else
806 r = 1;
807
808 finish:
809 va_end(ap);
810 for (i = 1; i < n; i += 2)
811 free(iovec[i].iov_base);
812
813 } else {
814 char buf[LINE_MAX];
815 bool found = false;
816
817 /* Fallback if journal logging is not available */
818
819 va_start(ap, format);
820 while (format) {
821 va_list aq;
822
823 va_copy(aq, ap);
824 vsnprintf(buf, sizeof(buf), format, aq);
825 va_end(aq);
826 char_array_0(buf);
827
828 if (startswith(buf, "MESSAGE=")) {
829 found = true;
830 break;
831 }
832
833 VA_FORMAT_ADVANCE(format, ap);
834
835 format = va_arg(ap, char *);
836 }
837 va_end(ap);
838
839 if (found)
840 r = log_dispatch(level, file, line, func,
841 NULL, NULL, buf + 8);
842 else
843 r = -EINVAL;
844 }
845
846 errno = saved_errno;
847 return r;
848 }
849
850 int log_set_target_from_string(const char *e) {
851 LogTarget t;
852
853 t = log_target_from_string(e);
854 if (t < 0)
855 return -EINVAL;
856
857 log_set_target(t);
858 return 0;
859 }
860
861 int log_set_max_level_from_string(const char *e) {
862 int t;
863
864 t = log_level_from_string(e);
865 if (t < 0)
866 return t;
867
868 log_set_max_level(t);
869 return 0;
870 }
871
872 void log_parse_environment(void) {
873 const char *e;
874
875 e = secure_getenv("SYSTEMD_LOG_TARGET");
876 if (e && log_set_target_from_string(e) < 0)
877 log_warning("Failed to parse log target %s. Ignoring.", e);
878
879 e = secure_getenv("SYSTEMD_LOG_LEVEL");
880 if (e && log_set_max_level_from_string(e) < 0)
881 log_warning("Failed to parse log level %s. Ignoring.", e);
882
883 e = secure_getenv("SYSTEMD_LOG_COLOR");
884 if (e && log_show_color_from_string(e) < 0)
885 log_warning("Failed to parse bool %s. Ignoring.", e);
886
887 e = secure_getenv("SYSTEMD_LOG_LOCATION");
888 if (e && log_show_location_from_string(e) < 0)
889 log_warning("Failed to parse bool %s. Ignoring.", e);
890 }
891
892 LogTarget log_get_target(void) {
893 return log_target;
894 }
895
896 int log_get_max_level(void) {
897 return log_max_level;
898 }
899
900 void log_show_color(bool b) {
901 show_color = b;
902 }
903
904 void log_show_location(bool b) {
905 show_location = b;
906 }
907
908 int log_show_color_from_string(const char *e) {
909 int t;
910
911 t = parse_boolean(e);
912 if (t < 0)
913 return t;
914
915 log_show_color(t);
916 return 0;
917 }
918
919 int log_show_location_from_string(const char *e) {
920 int t;
921
922 t = parse_boolean(e);
923 if (t < 0)
924 return t;
925
926 log_show_location(t);
927 return 0;
928 }
929
930 bool log_on_console(void) {
931 if (log_target == LOG_TARGET_CONSOLE)
932 return true;
933
934 return syslog_fd < 0 && kmsg_fd < 0 && journal_fd < 0;
935 }
936
937 static const char *const log_target_table[] = {
938 [LOG_TARGET_CONSOLE] = "console",
939 [LOG_TARGET_KMSG] = "kmsg",
940 [LOG_TARGET_JOURNAL] = "journal",
941 [LOG_TARGET_JOURNAL_OR_KMSG] = "journal-or-kmsg",
942 [LOG_TARGET_SYSLOG] = "syslog",
943 [LOG_TARGET_SYSLOG_OR_KMSG] = "syslog-or-kmsg",
944 [LOG_TARGET_AUTO] = "auto",
945 [LOG_TARGET_SAFE] = "safe",
946 [LOG_TARGET_NULL] = "null"
947 };
948
949 DEFINE_STRING_TABLE_LOOKUP(log_target, LogTarget);