chiark / gitweb /
Do not log all assert_return failures
[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 static void log_assert(int level, const char *text, const char *file, int line, const char *func, const char *format) {
691         static char buffer[LINE_MAX];
692
693         if (_likely_(LOG_PRI(level) > log_max_level))
694                 return;
695
696         snprintf(buffer, sizeof(buffer), format, text, file, line, func);
697
698         char_array_0(buffer);
699         log_abort_msg = buffer;
700
701         log_dispatch(level, file, line, func, NULL, NULL, buffer);
702 }
703 #pragma GCC diagnostic pop
704
705 _noreturn_ void log_assert_failed(const char *text, const char *file, int line, const char *func) {
706         log_assert(LOG_CRIT, text, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Aborting.");
707         abort();
708 }
709
710 _noreturn_ void log_assert_failed_unreachable(const char *text, const char *file, int line, const char *func) {
711         log_assert(LOG_CRIT, text, file, line, func, "Code should not be reached '%s' at %s:%u, function %s(). Aborting.");
712         abort();
713 }
714
715 void log_assert_failed_return(const char *text, const char *file, int line, const char *func) {
716         log_assert(LOG_DEBUG, text, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Ignoring.");
717 }
718
719 int log_oom_internal(const char *file, int line, const char *func) {
720         log_meta(LOG_ERR, file, line, func, "Out of memory.");
721         return -ENOMEM;
722 }
723
724 int log_struct_internal(
725                 int level,
726                 const char *file,
727                 int line,
728                 const char *func,
729                 const char *format, ...) {
730
731         PROTECT_ERRNO;
732         va_list ap;
733         int r;
734
735         if (_likely_(LOG_PRI(level) > log_max_level))
736                 return 0;
737
738         if (log_target == LOG_TARGET_NULL)
739                 return 0;
740
741         if ((level & LOG_FACMASK) == 0)
742                 level = log_facility | LOG_PRI(level);
743
744         if ((log_target == LOG_TARGET_AUTO ||
745              log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
746              log_target == LOG_TARGET_JOURNAL) &&
747             journal_fd >= 0) {
748
749                 char header[LINE_MAX];
750                 struct iovec iovec[17] = {};
751                 unsigned n = 0, i;
752                 struct msghdr mh = {
753                         .msg_iov = iovec,
754                 };
755                 static const char nl = '\n';
756
757                 /* If the journal is available do structured logging */
758                 log_do_header(header, sizeof(header), level,
759                               file, line, func, NULL, NULL);
760                 IOVEC_SET_STRING(iovec[n++], header);
761
762                 va_start(ap, format);
763                 while (format && n + 1 < ELEMENTSOF(iovec)) {
764                         char *buf;
765                         va_list aq;
766
767                         /* We need to copy the va_list structure,
768                          * since vasprintf() leaves it afterwards at
769                          * an undefined location */
770
771                         va_copy(aq, ap);
772                         if (vasprintf(&buf, format, aq) < 0) {
773                                 va_end(aq);
774                                 r = -ENOMEM;
775                                 goto finish;
776                         }
777                         va_end(aq);
778
779                         /* Now, jump enough ahead, so that we point to
780                          * the next format string */
781                         VA_FORMAT_ADVANCE(format, ap);
782
783                         IOVEC_SET_STRING(iovec[n++], buf);
784
785                         iovec[n].iov_base = (char*) &nl;
786                         iovec[n].iov_len = 1;
787                         n++;
788
789                         format = va_arg(ap, char *);
790                 }
791
792                 mh.msg_iovlen = n;
793
794                 if (sendmsg(journal_fd, &mh, MSG_NOSIGNAL) < 0)
795                         r = -errno;
796                 else
797                         r = 1;
798
799         finish:
800                 va_end(ap);
801                 for (i = 1; i < n; i += 2)
802                         free(iovec[i].iov_base);
803
804         } else {
805                 char buf[LINE_MAX];
806                 bool found = false;
807
808                 /* Fallback if journal logging is not available */
809
810                 va_start(ap, format);
811                 while (format) {
812                         va_list aq;
813
814                         va_copy(aq, ap);
815                         vsnprintf(buf, sizeof(buf), format, aq);
816                         va_end(aq);
817                         char_array_0(buf);
818
819                         if (startswith(buf, "MESSAGE=")) {
820                                 found = true;
821                                 break;
822                         }
823
824                         VA_FORMAT_ADVANCE(format, ap);
825
826                         format = va_arg(ap, char *);
827                 }
828                 va_end(ap);
829
830                 if (found)
831                         r = log_dispatch(level, file, line, func,
832                                          NULL, NULL, buf + 8);
833                 else
834                         r = -EINVAL;
835         }
836
837         return r;
838 }
839
840 int log_set_target_from_string(const char *e) {
841         LogTarget t;
842
843         t = log_target_from_string(e);
844         if (t < 0)
845                 return -EINVAL;
846
847         log_set_target(t);
848         return 0;
849 }
850
851 int log_set_max_level_from_string(const char *e) {
852         int t;
853
854         t = log_level_from_string(e);
855         if (t < 0)
856                 return t;
857
858         log_set_max_level(t);
859         return 0;
860 }
861
862 void log_parse_environment(void) {
863         const char *e;
864
865         e = secure_getenv("SYSTEMD_LOG_TARGET");
866         if (e && log_set_target_from_string(e) < 0)
867                 log_warning("Failed to parse log target %s. Ignoring.", e);
868
869         e = secure_getenv("SYSTEMD_LOG_LEVEL");
870         if (e && log_set_max_level_from_string(e) < 0)
871                 log_warning("Failed to parse log level %s. Ignoring.", e);
872
873         e = secure_getenv("SYSTEMD_LOG_COLOR");
874         if (e && log_show_color_from_string(e) < 0)
875                 log_warning("Failed to parse bool %s. Ignoring.", e);
876
877         e = secure_getenv("SYSTEMD_LOG_LOCATION");
878         if (e && log_show_location_from_string(e) < 0)
879                 log_warning("Failed to parse bool %s. Ignoring.", e);
880 }
881
882 LogTarget log_get_target(void) {
883         return log_target;
884 }
885
886 int log_get_max_level(void) {
887         return log_max_level;
888 }
889
890 void log_show_color(bool b) {
891         show_color = b;
892 }
893
894 void log_show_location(bool b) {
895         show_location = b;
896 }
897
898 int log_show_color_from_string(const char *e) {
899         int t;
900
901         t = parse_boolean(e);
902         if (t < 0)
903                 return t;
904
905         log_show_color(t);
906         return 0;
907 }
908
909 int log_show_location_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_location(t);
917         return 0;
918 }
919
920 bool log_on_console(void) {
921         if (log_target == LOG_TARGET_CONSOLE)
922                 return true;
923
924         return syslog_fd < 0 && kmsg_fd < 0 && journal_fd < 0;
925 }
926
927 static const char *const log_target_table[] = {
928         [LOG_TARGET_CONSOLE] = "console",
929         [LOG_TARGET_KMSG] = "kmsg",
930         [LOG_TARGET_JOURNAL] = "journal",
931         [LOG_TARGET_JOURNAL_OR_KMSG] = "journal-or-kmsg",
932         [LOG_TARGET_SYSLOG] = "syslog",
933         [LOG_TARGET_SYSLOG_OR_KMSG] = "syslog-or-kmsg",
934         [LOG_TARGET_AUTO] = "auto",
935         [LOG_TARGET_SAFE] = "safe",
936         [LOG_TARGET_NULL] = "null"
937 };
938
939 DEFINE_STRING_TABLE_LOOKUP(log_target, LogTarget);