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