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