chiark / gitweb /
log: fix repeated invocation of vsnprintf()/vaprintf() in log_struct()
[elogind.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 *buffer) {
312
313         char location[64];
314         struct iovec iovec[5];
315         unsigned n = 0;
316         bool highlight;
317
318         if (console_fd < 0)
319                 return 0;
320
321         highlight = LOG_PRI(level) <= LOG_ERR && show_color;
322
323         zero(iovec);
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                 return -errno;
340
341         return 1;
342 }
343
344 static int write_to_syslog(
345         int level,
346         const char*file,
347         int line,
348         const char *func,
349         const char *buffer) {
350
351         char header_priority[16], header_time[64], header_pid[16];
352         struct iovec iovec[5];
353         struct msghdr msghdr;
354         time_t t;
355         struct tm *tm;
356
357         if (syslog_fd < 0)
358                 return 0;
359
360         snprintf(header_priority, sizeof(header_priority), "<%i>", level);
361         char_array_0(header_priority);
362
363         t = (time_t) (now(CLOCK_REALTIME) / USEC_PER_SEC);
364         if (!(tm = localtime(&t)))
365                 return -EINVAL;
366
367         if (strftime(header_time, sizeof(header_time), "%h %e %T ", tm) <= 0)
368                 return -EINVAL;
369
370         snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) getpid());
371         char_array_0(header_pid);
372
373         zero(iovec);
374         IOVEC_SET_STRING(iovec[0], header_priority);
375         IOVEC_SET_STRING(iovec[1], header_time);
376         IOVEC_SET_STRING(iovec[2], program_invocation_short_name);
377         IOVEC_SET_STRING(iovec[3], header_pid);
378         IOVEC_SET_STRING(iovec[4], buffer);
379
380         /* When using syslog via SOCK_STREAM separate the messages by NUL chars */
381         if (syslog_is_stream)
382                 iovec[4].iov_len++;
383
384         zero(msghdr);
385         msghdr.msg_iov = iovec;
386         msghdr.msg_iovlen = ELEMENTSOF(iovec);
387
388         for (;;) {
389                 ssize_t n;
390
391                 n = sendmsg(syslog_fd, &msghdr, MSG_NOSIGNAL);
392                 if (n < 0)
393                         return -errno;
394
395                 if (!syslog_is_stream ||
396                     (size_t) n >= IOVEC_TOTAL_SIZE(iovec, ELEMENTSOF(iovec)))
397                         break;
398
399                 IOVEC_INCREMENT(iovec, ELEMENTSOF(iovec), n);
400         }
401
402         return 1;
403 }
404
405 static int write_to_kmsg(
406         int level,
407         const char*file,
408         int line,
409         const char *func,
410         const char *buffer) {
411
412         char header_priority[16], header_pid[16];
413         struct iovec iovec[5];
414
415         if (kmsg_fd < 0)
416                 return 0;
417
418         snprintf(header_priority, sizeof(header_priority), "<%i>", level);
419         char_array_0(header_priority);
420
421         snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) getpid());
422         char_array_0(header_pid);
423
424         zero(iovec);
425         IOVEC_SET_STRING(iovec[0], header_priority);
426         IOVEC_SET_STRING(iovec[1], program_invocation_short_name);
427         IOVEC_SET_STRING(iovec[2], header_pid);
428         IOVEC_SET_STRING(iovec[3], buffer);
429         IOVEC_SET_STRING(iovec[4], "\n");
430
431         if (writev(kmsg_fd, iovec, ELEMENTSOF(iovec)) < 0)
432                 return -errno;
433
434         return 1;
435 }
436
437 static int write_to_journal(
438         int level,
439         const char*file,
440         int line,
441         const char *func,
442         const char *buffer) {
443
444         char header[LINE_MAX];
445         struct iovec iovec[3];
446         struct msghdr mh;
447
448         if (journal_fd < 0)
449                 return 0;
450
451         snprintf(header, sizeof(header),
452                  "PRIORITY=%i\n"
453                  "SYSLOG_FACILITY=%i\n"
454                  "CODE_FILE=%s\n"
455                  "CODE_LINE=%i\n"
456                  "CODE_FUNCTION=%s\n"
457                  "SYSLOG_IDENTIFIER=%s\n"
458                  "MESSAGE=",
459                  LOG_PRI(level),
460                  LOG_FAC(level),
461                  file,
462                  line,
463                  func,
464                  program_invocation_short_name);
465
466         char_array_0(header);
467
468         zero(iovec);
469         IOVEC_SET_STRING(iovec[0], header);
470         IOVEC_SET_STRING(iovec[1], buffer);
471         IOVEC_SET_STRING(iovec[2], "\n");
472
473         zero(mh);
474         mh.msg_iov = iovec;
475         mh.msg_iovlen = ELEMENTSOF(iovec);
476
477         if (sendmsg(journal_fd, &mh, MSG_NOSIGNAL) < 0)
478                 return -errno;
479
480         return 1;
481 }
482
483 static int log_dispatch(
484         int level,
485         const char*file,
486         int line,
487         const char *func,
488         char *buffer) {
489
490         int r = 0;
491
492         if (log_target == LOG_TARGET_NULL)
493                 return 0;
494
495         /* Patch in LOG_DAEMON facility if necessary */
496         if ((level & LOG_FACMASK) == 0)
497                 level = log_facility | LOG_PRI(level);
498
499         do {
500                 char *e;
501                 int k = 0;
502
503                 buffer += strspn(buffer, NEWLINE);
504
505                 if (buffer[0] == 0)
506                         break;
507
508                 if ((e = strpbrk(buffer, NEWLINE)))
509                         *(e++) = 0;
510
511                 if (log_target == LOG_TARGET_AUTO ||
512                     log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
513                     log_target == LOG_TARGET_JOURNAL) {
514
515                         k = write_to_journal(level, file, line, func, buffer);
516                         if (k < 0) {
517                                 if (k != -EAGAIN)
518                                         log_close_journal();
519                                 log_open_kmsg();
520                         } else if (k > 0)
521                                 r++;
522                 }
523
524                 if (log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
525                     log_target == LOG_TARGET_SYSLOG) {
526
527                         k = write_to_syslog(level, file, line, func, buffer);
528                         if (k < 0) {
529                                 if (k != -EAGAIN)
530                                         log_close_syslog();
531                                 log_open_kmsg();
532                         } else if (k > 0)
533                                 r++;
534                 }
535
536                 if (k <= 0 &&
537                     (log_target == LOG_TARGET_AUTO ||
538                      log_target == LOG_TARGET_SAFE ||
539                      log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
540                      log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
541                      log_target == LOG_TARGET_KMSG)) {
542
543                         k = write_to_kmsg(level, file, line, func, buffer);
544                         if (k < 0) {
545                                 log_close_kmsg();
546                                 log_open_console();
547                         } else if (k > 0)
548                                 r++;
549                 }
550
551                 if (k <= 0) {
552                         k = write_to_console(level, file, line, func, buffer);
553                         if (k < 0)
554                                 return k;
555                 }
556
557                 buffer = e;
558         } while (buffer);
559
560         return r;
561 }
562
563 int log_dump_internal(
564         int level,
565         const char*file,
566         int line,
567         const char *func,
568         char *buffer) {
569
570         int saved_errno, r;
571
572         /* This modifies the buffer... */
573
574         if (_likely_(LOG_PRI(level) > log_max_level))
575                 return 0;
576
577         saved_errno = errno;
578         r = log_dispatch(level, file, line, func, buffer);
579         errno = saved_errno;
580
581         return r;
582 }
583
584 int log_metav(
585         int level,
586         const char*file,
587         int line,
588         const char *func,
589         const char *format,
590         va_list ap) {
591
592         char buffer[LINE_MAX];
593         int saved_errno, r;
594
595         if (_likely_(LOG_PRI(level) > log_max_level))
596                 return 0;
597
598         saved_errno = errno;
599         vsnprintf(buffer, sizeof(buffer), format, ap);
600         char_array_0(buffer);
601
602         r = log_dispatch(level, file, line, func, buffer);
603         errno = saved_errno;
604
605         return r;
606 }
607
608 int log_meta(
609         int level,
610         const char*file,
611         int line,
612         const char *func,
613         const char *format, ...) {
614
615         int r;
616         va_list ap;
617
618         va_start(ap, format);
619         r = log_metav(level, file, line, func, format, ap);
620         va_end(ap);
621
622         return r;
623 }
624
625 #pragma GCC diagnostic push
626 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
627 _noreturn_ static void log_assert(const char *text, const char *file, int line, const char *func, const char *format) {
628         static char buffer[LINE_MAX];
629
630         snprintf(buffer, sizeof(buffer), format, text, file, line, func);
631
632         char_array_0(buffer);
633         log_abort_msg = buffer;
634
635         log_dispatch(LOG_CRIT, file, line, func, buffer);
636         abort();
637 }
638 #pragma GCC diagnostic pop
639
640 _noreturn_ void log_assert_failed(const char *text, const char *file, int line, const char *func) {
641         log_assert(text, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Aborting.");
642 }
643
644 _noreturn_ void log_assert_failed_unreachable(const char *text, const char *file, int line, const char *func) {
645         log_assert(text, file, line, func, "Code should not be reached '%s' at %s:%u, function %s(). Aborting.");
646 }
647
648 int log_oom_internal(const char *file, int line, const char *func) {
649         log_meta(LOG_ERR, file, line, func, "Out of memory.");
650         return -ENOMEM;
651 }
652
653 int log_struct_internal(
654                 int level,
655                 const char *file,
656                 int line,
657                 const char *func,
658                 const char *format, ...) {
659
660         int saved_errno;
661         va_list ap;
662         int r;
663
664         if (_likely_(LOG_PRI(level) > log_max_level))
665                 return 0;
666
667         if (log_target == LOG_TARGET_NULL)
668                 return 0;
669
670         if ((level & LOG_FACMASK) == 0)
671                 level = log_facility | LOG_PRI(level);
672
673         saved_errno = errno;
674
675         if ((log_target == LOG_TARGET_AUTO ||
676              log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
677              log_target == LOG_TARGET_JOURNAL) &&
678             journal_fd >= 0) {
679
680                 char header[LINE_MAX];
681                 struct iovec iovec[17];
682                 unsigned n = 0, i;
683                 struct msghdr mh;
684                 const char nl = '\n';
685
686                 /* If the journal is available do structured logging */
687
688                 snprintf(header, sizeof(header),
689                         "PRIORITY=%i\n"
690                         "SYSLOG_FACILITY=%i\n"
691                         "CODE_FILE=%s\n"
692                         "CODE_LINE=%i\n"
693                         "CODE_FUNCTION=%s\n"
694                         "SYSLOG_IDENTIFIER=%s\n",
695                         LOG_PRI(level),
696                         LOG_FAC(level),
697                         file,
698                         line,
699                         func,
700                         program_invocation_short_name);
701                 char_array_0(header);
702
703                 zero(iovec);
704                 IOVEC_SET_STRING(iovec[n++], header);
705
706                 va_start(ap, format);
707                 while (format && n + 1 < ELEMENTSOF(iovec)) {
708                         char *buf;
709                         va_list aq;
710
711                         /* We need to copy the va_list structure,
712                          * since vasprintf() leaves it afterwards at
713                          * an undefined location */
714
715                         va_copy(aq, ap);
716                         if (vasprintf(&buf, format, aq) < 0) {
717                                 va_end(aq);
718                                 r = -ENOMEM;
719                                 goto finish;
720                         }
721                         va_end(aq);
722
723                         /* Now, jump enough ahead, so that we point to
724                          * the next format string */
725                         VA_FORMAT_ADVANCE(format, ap);
726
727                         IOVEC_SET_STRING(iovec[n++], buf);
728
729                         iovec[n].iov_base = (char*) &nl;
730                         iovec[n].iov_len = 1;
731                         n++;
732
733                         format = va_arg(ap, char *);
734                 }
735
736                 zero(mh);
737                 mh.msg_iov = iovec;
738                 mh.msg_iovlen = n;
739
740                 if (sendmsg(journal_fd, &mh, MSG_NOSIGNAL) < 0)
741                         r = -errno;
742                 else
743                         r = 1;
744
745         finish:
746                 va_end(ap);
747                 for (i = 1; i < n; i += 2)
748                         free(iovec[i].iov_base);
749
750         } else {
751                 char buf[LINE_MAX];
752                 bool found = false;
753
754                 /* Fallback if journal logging is not available */
755
756                 va_start(ap, format);
757                 while (format) {
758                         va_list aq;
759
760                         va_copy(aq, ap);
761                         vsnprintf(buf, sizeof(buf), format, aq);
762                         va_end(aq);
763                         char_array_0(buf);
764
765                         if (startswith(buf, "MESSAGE=")) {
766                                 found = true;
767                                 break;
768                         }
769
770                         VA_FORMAT_ADVANCE(format, ap);
771
772                         format = va_arg(ap, char *);
773                 }
774                 va_end(ap);
775
776                 if (found)
777                         r = log_dispatch(level, file, line, func, buf + 8);
778                 else
779                         r = -EINVAL;
780         }
781
782         errno = saved_errno;
783         return r;
784 }
785
786 int log_set_target_from_string(const char *e) {
787         LogTarget t;
788
789         t = log_target_from_string(e);
790         if (t < 0)
791                 return -EINVAL;
792
793         log_set_target(t);
794         return 0;
795 }
796
797 int log_set_max_level_from_string(const char *e) {
798         int t;
799
800         t = log_level_from_string(e);
801         if (t < 0)
802                 return t;
803
804         log_set_max_level(t);
805         return 0;
806 }
807
808 void log_parse_environment(void) {
809         const char *e;
810
811         e = secure_getenv("SYSTEMD_LOG_TARGET");
812         if (e && log_set_target_from_string(e) < 0)
813                 log_warning("Failed to parse log target %s. Ignoring.", e);
814
815         e = secure_getenv("SYSTEMD_LOG_LEVEL");
816         if (e && log_set_max_level_from_string(e) < 0)
817                 log_warning("Failed to parse log level %s. Ignoring.", e);
818
819         e = secure_getenv("SYSTEMD_LOG_COLOR");
820         if (e && log_show_color_from_string(e) < 0)
821                 log_warning("Failed to parse bool %s. Ignoring.", e);
822
823         e = secure_getenv("SYSTEMD_LOG_LOCATION");
824         if (e && log_show_location_from_string(e) < 0)
825                 log_warning("Failed to parse bool %s. Ignoring.", e);
826 }
827
828 LogTarget log_get_target(void) {
829         return log_target;
830 }
831
832 int log_get_max_level(void) {
833         return log_max_level;
834 }
835
836 void log_show_color(bool b) {
837         show_color = b;
838 }
839
840 void log_show_location(bool b) {
841         show_location = b;
842 }
843
844 int log_show_color_from_string(const char *e) {
845         int t;
846
847         t = parse_boolean(e);
848         if (t < 0)
849                 return t;
850
851         log_show_color(t);
852         return 0;
853 }
854
855 int log_show_location_from_string(const char *e) {
856         int t;
857
858         t = parse_boolean(e);
859         if (t < 0)
860                 return t;
861
862         log_show_location(t);
863         return 0;
864 }
865
866 bool log_on_console(void) {
867         if (log_target == LOG_TARGET_CONSOLE)
868                 return true;
869
870         return syslog_fd < 0 && kmsg_fd < 0 && journal_fd < 0;
871 }
872
873 static const char *const log_target_table[] = {
874         [LOG_TARGET_CONSOLE] = "console",
875         [LOG_TARGET_KMSG] = "kmsg",
876         [LOG_TARGET_JOURNAL] = "journal",
877         [LOG_TARGET_JOURNAL_OR_KMSG] = "journal-or-kmsg",
878         [LOG_TARGET_SYSLOG] = "syslog",
879         [LOG_TARGET_SYSLOG_OR_KMSG] = "syslog-or-kmsg",
880         [LOG_TARGET_AUTO] = "auto",
881         [LOG_TARGET_SAFE] = "safe",
882         [LOG_TARGET_NULL] = "null"
883 };
884
885 DEFINE_STRING_TABLE_LOOKUP(log_target, LogTarget);