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