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