]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/log.c
log: when we log to /dev/console and got disconnected (maybe due to vhangup) reconnect
[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 struct timeval tv;
119
120 fd = socket(AF_UNIX, type|SOCK_CLOEXEC, 0);
121 if (fd < 0)
122 return -errno;
123
124 fd_inc_sndbuf(fd, SNDBUF_SIZE);
125
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
132 return fd;
133 }
134
135 static int log_open_syslog(void) {
136 int r;
137 union sockaddr_union sa = {
138 .un.sun_family = AF_UNIX,
139 .un.sun_path = "/dev/log",
140 };
141
142 if (syslog_fd >= 0)
143 return 0;
144
145 syslog_fd = create_log_socket(SOCK_DGRAM);
146 if (syslog_fd < 0) {
147 r = syslog_fd;
148 goto fail;
149 }
150
151 if (connect(syslog_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
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... */
157 syslog_fd = create_log_socket(SOCK_STREAM);
158 if (syslog_fd < 0) {
159 r = syslog_fd;
160 goto fail;
161 }
162
163 if (connect(syslog_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
164 r = -errno;
165 goto fail;
166 }
167
168 syslog_is_stream = true;
169 } else
170 syslog_is_stream = false;
171
172 return 0;
173
174 fail:
175 log_close_syslog();
176 return r;
177 }
178
179 void 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
188 static int log_open_journal(void) {
189 union sockaddr_union sa = {
190 .un.sun_family = AF_UNIX,
191 .un.sun_path = "/run/systemd/journal/socket",
192 };
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
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
209 return 0;
210
211 fail:
212 log_close_journal();
213 return r;
214 }
215
216 int 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
225 if (log_target == LOG_TARGET_NULL) {
226 log_close_journal();
227 log_close_syslog();
228 log_close_console();
229 return 0;
230 }
231
232 if ((log_target != LOG_TARGET_AUTO && log_target != LOG_TARGET_SAFE) ||
233 getpid() == 1 ||
234 isatty(STDERR_FILENO) <= 0) {
235
236 if (log_target == LOG_TARGET_AUTO ||
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();
242 log_close_console();
243 return r;
244 }
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
257 if (log_target == LOG_TARGET_AUTO ||
258 log_target == LOG_TARGET_SAFE ||
259 log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
260 log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
261 log_target == LOG_TARGET_KMSG) {
262 r = log_open_kmsg();
263 if (r >= 0) {
264 log_close_journal();
265 log_close_syslog();
266 log_close_console();
267 return r;
268 }
269 }
270 }
271
272 log_close_journal();
273 log_close_syslog();
274
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 if (show_location) {
326 snprintf(location, sizeof(location), "(%s:%u) ", file, line);
327 char_array_0(location);
328 IOVEC_SET_STRING(iovec[n++], location);
329 }
330
331 if (highlight)
332 IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_RED_ON);
333 IOVEC_SET_STRING(iovec[n++], buffer);
334 if (highlight)
335 IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_OFF);
336 IOVEC_SET_STRING(iovec[n++], "\n");
337
338 if (writev(console_fd, iovec, n) < 0) {
339
340 if (errno == EIO && getpid() == 1) {
341
342 /* If somebody tried to kick us from our
343 * console tty (via vhangup() or suchlike),
344 * try to reconnect */
345
346 log_close_console();
347 log_open_console();
348
349 if (console_fd < 0)
350 return 0;
351
352 if (writev(console_fd, iovec, n) < 0)
353 return -errno;
354 } else
355 return -errno;
356 }
357
358 return 1;
359 }
360
361 static int write_to_syslog(
362 int level,
363 const char*file,
364 int line,
365 const char *func,
366 const char *object_name,
367 const char *object,
368 const char *buffer) {
369
370 char header_priority[16], header_time[64], header_pid[16];
371 struct iovec iovec[5] = {};
372 struct msghdr msghdr = {
373 .msg_iov = iovec,
374 .msg_iovlen = ELEMENTSOF(iovec),
375 };
376 time_t t;
377 struct tm *tm;
378
379 if (syslog_fd < 0)
380 return 0;
381
382 snprintf(header_priority, sizeof(header_priority), "<%i>", level);
383 char_array_0(header_priority);
384
385 t = (time_t) (now(CLOCK_REALTIME) / USEC_PER_SEC);
386 tm = localtime(&t);
387 if (!tm)
388 return -EINVAL;
389
390 if (strftime(header_time, sizeof(header_time), "%h %e %T ", tm) <= 0)
391 return -EINVAL;
392
393 snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) getpid());
394 char_array_0(header_pid);
395
396 IOVEC_SET_STRING(iovec[0], header_priority);
397 IOVEC_SET_STRING(iovec[1], header_time);
398 IOVEC_SET_STRING(iovec[2], program_invocation_short_name);
399 IOVEC_SET_STRING(iovec[3], header_pid);
400 IOVEC_SET_STRING(iovec[4], buffer);
401
402 /* When using syslog via SOCK_STREAM separate the messages by NUL chars */
403 if (syslog_is_stream)
404 iovec[4].iov_len++;
405
406 for (;;) {
407 ssize_t n;
408
409 n = sendmsg(syslog_fd, &msghdr, MSG_NOSIGNAL);
410 if (n < 0)
411 return -errno;
412
413 if (!syslog_is_stream ||
414 (size_t) n >= IOVEC_TOTAL_SIZE(iovec, ELEMENTSOF(iovec)))
415 break;
416
417 IOVEC_INCREMENT(iovec, ELEMENTSOF(iovec), n);
418 }
419
420 return 1;
421 }
422
423 static int write_to_kmsg(
424 int level,
425 const char*file,
426 int line,
427 const char *func,
428 const char *object_name,
429 const char *object,
430 const char *buffer) {
431
432 char header_priority[16], header_pid[16];
433 struct iovec iovec[5] = {};
434
435 if (kmsg_fd < 0)
436 return 0;
437
438 snprintf(header_priority, sizeof(header_priority), "<%i>", level);
439 char_array_0(header_priority);
440
441 snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) getpid());
442 char_array_0(header_pid);
443
444 IOVEC_SET_STRING(iovec[0], header_priority);
445 IOVEC_SET_STRING(iovec[1], program_invocation_short_name);
446 IOVEC_SET_STRING(iovec[2], header_pid);
447 IOVEC_SET_STRING(iovec[3], buffer);
448 IOVEC_SET_STRING(iovec[4], "\n");
449
450 if (writev(kmsg_fd, iovec, ELEMENTSOF(iovec)) < 0)
451 return -errno;
452
453 return 1;
454 }
455
456 static int log_do_header(char *header, size_t size,
457 int level,
458 const char *file, int line, const char *func,
459 const char *object_name, const char *object) {
460 snprintf(header, size,
461 "PRIORITY=%i\n"
462 "SYSLOG_FACILITY=%i\n"
463 "%s%.*s%s"
464 "%s%.*i%s"
465 "%s%.*s%s"
466 "%s%.*s%s"
467 "SYSLOG_IDENTIFIER=%s\n",
468 LOG_PRI(level),
469 LOG_FAC(level),
470 file ? "CODE_FILE=" : "",
471 file ? LINE_MAX : 0, file, /* %.0s means no output */
472 file ? "\n" : "",
473 line ? "CODE_LINE=" : "",
474 line ? 1 : 0, line, /* %.0d means no output too, special case for 0 */
475 line ? "\n" : "",
476 func ? "CODE_FUNCTION=" : "",
477 func ? LINE_MAX : 0, func,
478 func ? "\n" : "",
479 object ? object_name : "",
480 object ? LINE_MAX : 0, object, /* %.0s means no output */
481 object ? "\n" : "",
482 program_invocation_short_name);
483 header[size - 1] = '\0';
484 return 0;
485 }
486
487 static int write_to_journal(
488 int level,
489 const char*file,
490 int line,
491 const char *func,
492 const char *object_name,
493 const char *object,
494 const char *buffer) {
495
496 char header[LINE_MAX];
497 struct iovec iovec[4] = {};
498 struct msghdr mh = {};
499
500 if (journal_fd < 0)
501 return 0;
502
503 log_do_header(header, sizeof(header), level,
504 file, line, func, object_name, object);
505
506 IOVEC_SET_STRING(iovec[0], header);
507 IOVEC_SET_STRING(iovec[1], "MESSAGE=");
508 IOVEC_SET_STRING(iovec[2], buffer);
509 IOVEC_SET_STRING(iovec[3], "\n");
510
511 mh.msg_iov = iovec;
512 mh.msg_iovlen = ELEMENTSOF(iovec);
513
514 if (sendmsg(journal_fd, &mh, MSG_NOSIGNAL) < 0)
515 return -errno;
516
517 return 1;
518 }
519
520 static int log_dispatch(
521 int level,
522 const char*file,
523 int line,
524 const char *func,
525 const char *object_name,
526 const char *object,
527 char *buffer) {
528
529 int r = 0;
530
531 if (log_target == LOG_TARGET_NULL)
532 return 0;
533
534 /* Patch in LOG_DAEMON facility if necessary */
535 if ((level & LOG_FACMASK) == 0)
536 level = log_facility | LOG_PRI(level);
537
538 do {
539 char *e;
540 int k = 0;
541
542 buffer += strspn(buffer, NEWLINE);
543
544 if (buffer[0] == 0)
545 break;
546
547 if ((e = strpbrk(buffer, NEWLINE)))
548 *(e++) = 0;
549
550 if (log_target == LOG_TARGET_AUTO ||
551 log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
552 log_target == LOG_TARGET_JOURNAL) {
553
554 k = write_to_journal(level, file, line, func,
555 object_name, object, buffer);
556 if (k < 0) {
557 if (k != -EAGAIN)
558 log_close_journal();
559 log_open_kmsg();
560 } else if (k > 0)
561 r++;
562 }
563
564 if (log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
565 log_target == LOG_TARGET_SYSLOG) {
566
567 k = write_to_syslog(level, file, line, func,
568 object_name, object, buffer);
569 if (k < 0) {
570 if (k != -EAGAIN)
571 log_close_syslog();
572 log_open_kmsg();
573 } else if (k > 0)
574 r++;
575 }
576
577 if (k <= 0 &&
578 (log_target == LOG_TARGET_AUTO ||
579 log_target == LOG_TARGET_SAFE ||
580 log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
581 log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
582 log_target == LOG_TARGET_KMSG)) {
583
584 k = write_to_kmsg(level, file, line, func,
585 object_name, object, buffer);
586 if (k < 0) {
587 log_close_kmsg();
588 log_open_console();
589 } else if (k > 0)
590 r++;
591 }
592
593 if (k <= 0) {
594 k = write_to_console(level, file, line, func,
595 object_name, object, buffer);
596 if (k < 0)
597 return k;
598 }
599
600 buffer = e;
601 } while (buffer);
602
603 return r;
604 }
605
606 int log_dump_internal(
607 int level,
608 const char*file,
609 int line,
610 const char *func,
611 char *buffer) {
612
613 PROTECT_ERRNO;
614
615 /* This modifies the buffer... */
616
617 if (_likely_(LOG_PRI(level) > log_max_level))
618 return 0;
619
620 return log_dispatch(level, file, line, func, NULL, NULL, buffer);
621 }
622
623 int log_metav(
624 int level,
625 const char*file,
626 int line,
627 const char *func,
628 const char *format,
629 va_list ap) {
630
631 PROTECT_ERRNO;
632 char buffer[LINE_MAX];
633
634 if (_likely_(LOG_PRI(level) > log_max_level))
635 return 0;
636
637 vsnprintf(buffer, sizeof(buffer), format, ap);
638 char_array_0(buffer);
639
640 return log_dispatch(level, file, line, func, NULL, NULL, buffer);
641 }
642
643 int log_meta(
644 int level,
645 const char*file,
646 int line,
647 const char *func,
648 const char *format, ...) {
649
650 int r;
651 va_list ap;
652
653 va_start(ap, format);
654 r = log_metav(level, file, line, func, format, ap);
655 va_end(ap);
656
657 return r;
658 }
659
660 int log_metav_object(
661 int level,
662 const char*file,
663 int line,
664 const char *func,
665 const char *object_name,
666 const char *object,
667 const char *format,
668 va_list ap) {
669
670 PROTECT_ERRNO;
671 char buffer[LINE_MAX];
672
673 if (_likely_(LOG_PRI(level) > log_max_level))
674 return 0;
675
676 vsnprintf(buffer, sizeof(buffer), format, ap);
677 char_array_0(buffer);
678
679 return log_dispatch(level, file, line, func,
680 object_name, object, buffer);
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 static void log_assert(int level, const char *text, const char *file, int line, const char *func, const char *format) {
706 static char buffer[LINE_MAX];
707
708 if (_likely_(LOG_PRI(level) > log_max_level))
709 return;
710
711 snprintf(buffer, sizeof(buffer), format, text, file, line, func);
712
713 char_array_0(buffer);
714 log_abort_msg = buffer;
715
716 log_dispatch(level, file, line, func, NULL, NULL, buffer);
717 }
718 #pragma GCC diagnostic pop
719
720 noreturn void log_assert_failed(const char *text, const char *file, int line, const char *func) {
721 log_assert(LOG_CRIT, text, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Aborting.");
722 abort();
723 }
724
725 noreturn void log_assert_failed_unreachable(const char *text, const char *file, int line, const char *func) {
726 log_assert(LOG_CRIT, text, file, line, func, "Code should not be reached '%s' at %s:%u, function %s(). Aborting.");
727 abort();
728 }
729
730 void log_assert_failed_return(const char *text, const char *file, int line, const char *func) {
731 PROTECT_ERRNO;
732 log_assert(LOG_DEBUG, text, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Ignoring.");
733 }
734
735 int log_oom_internal(const char *file, int line, const char *func) {
736 log_meta(LOG_ERR, file, line, func, "Out of memory.");
737 return -ENOMEM;
738 }
739
740 int log_struct_internal(
741 int level,
742 const char *file,
743 int line,
744 const char *func,
745 const char *format, ...) {
746
747 PROTECT_ERRNO;
748 va_list ap;
749 int r;
750
751 if (_likely_(LOG_PRI(level) > log_max_level))
752 return 0;
753
754 if (log_target == LOG_TARGET_NULL)
755 return 0;
756
757 if ((level & LOG_FACMASK) == 0)
758 level = log_facility | LOG_PRI(level);
759
760 if ((log_target == LOG_TARGET_AUTO ||
761 log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
762 log_target == LOG_TARGET_JOURNAL) &&
763 journal_fd >= 0) {
764
765 char header[LINE_MAX];
766 struct iovec iovec[17] = {};
767 unsigned n = 0, i;
768 struct msghdr mh = {
769 .msg_iov = iovec,
770 };
771 static const char nl = '\n';
772
773 /* If the journal is available do structured logging */
774 log_do_header(header, sizeof(header), level,
775 file, line, func, NULL, NULL);
776 IOVEC_SET_STRING(iovec[n++], header);
777
778 va_start(ap, format);
779 while (format && n + 1 < ELEMENTSOF(iovec)) {
780 char *buf;
781 va_list aq;
782
783 /* We need to copy the va_list structure,
784 * since vasprintf() leaves it afterwards at
785 * an undefined location */
786
787 va_copy(aq, ap);
788 if (vasprintf(&buf, format, aq) < 0) {
789 va_end(aq);
790 r = -ENOMEM;
791 goto finish;
792 }
793 va_end(aq);
794
795 /* Now, jump enough ahead, so that we point to
796 * the next format string */
797 VA_FORMAT_ADVANCE(format, ap);
798
799 IOVEC_SET_STRING(iovec[n++], buf);
800
801 iovec[n].iov_base = (char*) &nl;
802 iovec[n].iov_len = 1;
803 n++;
804
805 format = va_arg(ap, char *);
806 }
807
808 mh.msg_iovlen = n;
809
810 if (sendmsg(journal_fd, &mh, MSG_NOSIGNAL) < 0)
811 r = -errno;
812 else
813 r = 1;
814
815 finish:
816 va_end(ap);
817 for (i = 1; i < n; i += 2)
818 free(iovec[i].iov_base);
819
820 } else {
821 char buf[LINE_MAX];
822 bool found = false;
823
824 /* Fallback if journal logging is not available */
825
826 va_start(ap, format);
827 while (format) {
828 va_list aq;
829
830 va_copy(aq, ap);
831 vsnprintf(buf, sizeof(buf), format, aq);
832 va_end(aq);
833 char_array_0(buf);
834
835 if (startswith(buf, "MESSAGE=")) {
836 found = true;
837 break;
838 }
839
840 VA_FORMAT_ADVANCE(format, ap);
841
842 format = va_arg(ap, char *);
843 }
844 va_end(ap);
845
846 if (found)
847 r = log_dispatch(level, file, line, func,
848 NULL, NULL, buf + 8);
849 else
850 r = -EINVAL;
851 }
852
853 return r;
854 }
855
856 int log_set_target_from_string(const char *e) {
857 LogTarget t;
858
859 t = log_target_from_string(e);
860 if (t < 0)
861 return -EINVAL;
862
863 log_set_target(t);
864 return 0;
865 }
866
867 int log_set_max_level_from_string(const char *e) {
868 int t;
869
870 t = log_level_from_string(e);
871 if (t < 0)
872 return t;
873
874 log_set_max_level(t);
875 return 0;
876 }
877
878 void log_parse_environment(void) {
879 const char *e;
880
881 e = secure_getenv("SYSTEMD_LOG_TARGET");
882 if (e && log_set_target_from_string(e) < 0)
883 log_warning("Failed to parse log target %s. Ignoring.", e);
884
885 e = secure_getenv("SYSTEMD_LOG_LEVEL");
886 if (e && log_set_max_level_from_string(e) < 0)
887 log_warning("Failed to parse log level %s. Ignoring.", e);
888
889 e = secure_getenv("SYSTEMD_LOG_COLOR");
890 if (e && log_show_color_from_string(e) < 0)
891 log_warning("Failed to parse bool %s. Ignoring.", e);
892
893 e = secure_getenv("SYSTEMD_LOG_LOCATION");
894 if (e && log_show_location_from_string(e) < 0)
895 log_warning("Failed to parse bool %s. Ignoring.", e);
896 }
897
898 LogTarget log_get_target(void) {
899 return log_target;
900 }
901
902 int log_get_max_level(void) {
903 return log_max_level;
904 }
905
906 void log_show_color(bool b) {
907 show_color = b;
908 }
909
910 void log_show_location(bool b) {
911 show_location = b;
912 }
913
914 int log_show_color_from_string(const char *e) {
915 int t;
916
917 t = parse_boolean(e);
918 if (t < 0)
919 return t;
920
921 log_show_color(t);
922 return 0;
923 }
924
925 int log_show_location_from_string(const char *e) {
926 int t;
927
928 t = parse_boolean(e);
929 if (t < 0)
930 return t;
931
932 log_show_location(t);
933 return 0;
934 }
935
936 bool log_on_console(void) {
937 if (log_target == LOG_TARGET_CONSOLE)
938 return true;
939
940 return syslog_fd < 0 && kmsg_fd < 0 && journal_fd < 0;
941 }
942
943 static const char *const log_target_table[] = {
944 [LOG_TARGET_CONSOLE] = "console",
945 [LOG_TARGET_KMSG] = "kmsg",
946 [LOG_TARGET_JOURNAL] = "journal",
947 [LOG_TARGET_JOURNAL_OR_KMSG] = "journal-or-kmsg",
948 [LOG_TARGET_SYSLOG] = "syslog",
949 [LOG_TARGET_SYSLOG_OR_KMSG] = "syslog-or-kmsg",
950 [LOG_TARGET_AUTO] = "auto",
951 [LOG_TARGET_SAFE] = "safe",
952 [LOG_TARGET_NULL] = "null"
953 };
954
955 DEFINE_STRING_TABLE_LOOKUP(log_target, LogTarget);