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