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