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