chiark / gitweb /
conf-parser: warn when we open configuration files with weird access bits
[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         if (getpid() == 1)
130                 timeval_store(&tv, 10 * USEC_PER_MSEC);
131         else
132                 timeval_store(&tv, 10 * USEC_PER_SEC);
133         setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
134
135         return fd;
136 }
137
138 static int log_open_syslog(void) {
139         int r;
140         union sockaddr_union sa = {
141                 .un.sun_family = AF_UNIX,
142                 .un.sun_path = "/dev/log",
143         };
144
145         if (syslog_fd >= 0)
146                 return 0;
147
148         syslog_fd = create_log_socket(SOCK_DGRAM);
149         if (syslog_fd < 0) {
150                 r = syslog_fd;
151                 goto fail;
152         }
153
154         if (connect(syslog_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
155                 close_nointr_nofail(syslog_fd);
156
157                 /* Some legacy syslog systems still use stream
158                  * sockets. They really shouldn't. But what can we
159                  * do... */
160                 syslog_fd = create_log_socket(SOCK_STREAM);
161                 if (syslog_fd < 0) {
162                         r = syslog_fd;
163                         goto fail;
164                 }
165
166                 if (connect(syslog_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
167                         r = -errno;
168                         goto fail;
169                 }
170
171                 syslog_is_stream = true;
172         } else
173                 syslog_is_stream = false;
174
175         return 0;
176
177 fail:
178         log_close_syslog();
179         return r;
180 }
181
182 void log_close_journal(void) {
183
184         if (journal_fd < 0)
185                 return;
186
187         close_nointr_nofail(journal_fd);
188         journal_fd = -1;
189 }
190
191 static int log_open_journal(void) {
192         union sockaddr_union sa = {
193                 .un.sun_family = AF_UNIX,
194                 .un.sun_path = "/run/systemd/journal/socket",
195         };
196         int r;
197
198         if (journal_fd >= 0)
199                 return 0;
200
201         journal_fd = create_log_socket(SOCK_DGRAM);
202         if (journal_fd < 0) {
203                 r = journal_fd;
204                 goto fail;
205         }
206
207         if (connect(journal_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
208                 r = -errno;
209                 goto fail;
210         }
211
212         return 0;
213
214 fail:
215         log_close_journal();
216         return r;
217 }
218
219 int log_open(void) {
220         int r;
221
222         /* If we don't use the console we close it here, to not get
223          * killed by SAK. If we don't use syslog we close it here so
224          * that we are not confused by somebody deleting the socket in
225          * the fs. If we don't use /dev/kmsg we still keep it open,
226          * because there is no reason to close it. */
227
228         if (log_target == LOG_TARGET_NULL) {
229                 log_close_journal();
230                 log_close_syslog();
231                 log_close_console();
232                 return 0;
233         }
234
235         if ((log_target != LOG_TARGET_AUTO && log_target != LOG_TARGET_SAFE) ||
236             getpid() == 1 ||
237             isatty(STDERR_FILENO) <= 0) {
238
239                 if (log_target == LOG_TARGET_AUTO ||
240                     log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
241                     log_target == LOG_TARGET_JOURNAL) {
242                         r = log_open_journal();
243                         if (r >= 0) {
244                                 log_close_syslog();
245                                 log_close_console();
246                                 return r;
247                         }
248                 }
249
250                 if (log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
251                     log_target == LOG_TARGET_SYSLOG) {
252                         r = log_open_syslog();
253                         if (r >= 0) {
254                                 log_close_journal();
255                                 log_close_console();
256                                 return r;
257                         }
258                 }
259
260                 if (log_target == LOG_TARGET_AUTO ||
261                     log_target == LOG_TARGET_SAFE ||
262                     log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
263                     log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
264                     log_target == LOG_TARGET_KMSG) {
265                         r = log_open_kmsg();
266                         if (r >= 0) {
267                                 log_close_journal();
268                                 log_close_syslog();
269                                 log_close_console();
270                                 return r;
271                         }
272                 }
273         }
274
275         log_close_journal();
276         log_close_syslog();
277
278         return log_open_console();
279 }
280
281 void log_set_target(LogTarget target) {
282         assert(target >= 0);
283         assert(target < _LOG_TARGET_MAX);
284
285         log_target = target;
286 }
287
288 void log_close(void) {
289         log_close_journal();
290         log_close_syslog();
291         log_close_kmsg();
292         log_close_console();
293 }
294
295 void log_forget_fds(void) {
296         console_fd = kmsg_fd = syslog_fd = journal_fd = -1;
297 }
298
299 void log_set_max_level(int level) {
300         assert((level & LOG_PRIMASK) == level);
301
302         log_max_level = level;
303 }
304
305 void log_set_facility(int facility) {
306         log_facility = facility;
307 }
308
309 static int write_to_console(
310                 int level,
311                 const char*file,
312                 int line,
313                 const char *func,
314                 const char *object_name,
315                 const char *object,
316                 const char *buffer) {
317
318         char location[64];
319         struct iovec iovec[5] = {};
320         unsigned n = 0;
321         bool highlight;
322
323         if (console_fd < 0)
324                 return 0;
325
326         highlight = LOG_PRI(level) <= LOG_ERR && show_color;
327
328         if (show_location) {
329                 snprintf(location, sizeof(location), "(%s:%u) ", file, line);
330                 char_array_0(location);
331                 IOVEC_SET_STRING(iovec[n++], location);
332         }
333
334         if (highlight)
335                 IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_RED_ON);
336         IOVEC_SET_STRING(iovec[n++], buffer);
337         if (highlight)
338                 IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_OFF);
339         IOVEC_SET_STRING(iovec[n++], "\n");
340
341         if (writev(console_fd, iovec, n) < 0) {
342
343                 if (errno == EIO && getpid() == 1) {
344
345                         /* If somebody tried to kick us from our
346                          * console tty (via vhangup() or suchlike),
347                          * try to reconnect */
348
349                         log_close_console();
350                         log_open_console();
351
352                         if (console_fd < 0)
353                                 return 0;
354
355                         if (writev(console_fd, iovec, n) < 0)
356                                 return -errno;
357                 } else
358                         return -errno;
359         }
360
361         return 1;
362 }
363
364 static int write_to_syslog(
365         int level,
366         const char*file,
367         int line,
368         const char *func,
369         const char *object_name,
370         const char *object,
371         const char *buffer) {
372
373         char header_priority[16], header_time[64], header_pid[16];
374         struct iovec iovec[5] = {};
375         struct msghdr msghdr = {
376                 .msg_iov = iovec,
377                 .msg_iovlen = ELEMENTSOF(iovec),
378         };
379         time_t t;
380         struct tm *tm;
381
382         if (syslog_fd < 0)
383                 return 0;
384
385         snprintf(header_priority, sizeof(header_priority), "<%i>", level);
386         char_array_0(header_priority);
387
388         t = (time_t) (now(CLOCK_REALTIME) / USEC_PER_SEC);
389         tm = localtime(&t);
390         if (!tm)
391                 return -EINVAL;
392
393         if (strftime(header_time, sizeof(header_time), "%h %e %T ", tm) <= 0)
394                 return -EINVAL;
395
396         snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) getpid());
397         char_array_0(header_pid);
398
399         IOVEC_SET_STRING(iovec[0], header_priority);
400         IOVEC_SET_STRING(iovec[1], header_time);
401         IOVEC_SET_STRING(iovec[2], program_invocation_short_name);
402         IOVEC_SET_STRING(iovec[3], header_pid);
403         IOVEC_SET_STRING(iovec[4], buffer);
404
405         /* When using syslog via SOCK_STREAM separate the messages by NUL chars */
406         if (syslog_is_stream)
407                 iovec[4].iov_len++;
408
409         for (;;) {
410                 ssize_t n;
411
412                 n = sendmsg(syslog_fd, &msghdr, MSG_NOSIGNAL);
413                 if (n < 0)
414                         return -errno;
415
416                 if (!syslog_is_stream ||
417                     (size_t) n >= IOVEC_TOTAL_SIZE(iovec, ELEMENTSOF(iovec)))
418                         break;
419
420                 IOVEC_INCREMENT(iovec, ELEMENTSOF(iovec), n);
421         }
422
423         return 1;
424 }
425
426 static int write_to_kmsg(
427         int level,
428         const char*file,
429         int line,
430         const char *func,
431         const char *object_name,
432         const char *object,
433         const char *buffer) {
434
435         char header_priority[16], header_pid[16];
436         struct iovec iovec[5] = {};
437
438         if (kmsg_fd < 0)
439                 return 0;
440
441         snprintf(header_priority, sizeof(header_priority), "<%i>", level);
442         char_array_0(header_priority);
443
444         snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) getpid());
445         char_array_0(header_pid);
446
447         IOVEC_SET_STRING(iovec[0], header_priority);
448         IOVEC_SET_STRING(iovec[1], program_invocation_short_name);
449         IOVEC_SET_STRING(iovec[2], header_pid);
450         IOVEC_SET_STRING(iovec[3], buffer);
451         IOVEC_SET_STRING(iovec[4], "\n");
452
453         if (writev(kmsg_fd, iovec, ELEMENTSOF(iovec)) < 0)
454                 return -errno;
455
456         return 1;
457 }
458
459 static int log_do_header(char *header, size_t size,
460                          int level,
461                          const char *file, int line, const char *func,
462                          const char *object_name, const char *object) {
463         snprintf(header, size,
464                  "PRIORITY=%i\n"
465                  "SYSLOG_FACILITY=%i\n"
466                  "%s%.*s%s"
467                  "%s%.*i%s"
468                  "%s%.*s%s"
469                  "%s%.*s%s"
470                  "SYSLOG_IDENTIFIER=%s\n",
471                  LOG_PRI(level),
472                  LOG_FAC(level),
473                  file ? "CODE_FILE=" : "",
474                  file ? LINE_MAX : 0, file, /* %.0s means no output */
475                  file ? "\n" : "",
476                  line ? "CODE_LINE=" : "",
477                  line ? 1 : 0, line, /* %.0d means no output too, special case for 0 */
478                  line ? "\n" : "",
479                  func ? "CODE_FUNCTION=" : "",
480                  func ? LINE_MAX : 0, func,
481                  func ? "\n" : "",
482                  object ? object_name : "",
483                  object ? LINE_MAX : 0, object, /* %.0s means no output */
484                  object ? "\n" : "",
485                  program_invocation_short_name);
486         header[size - 1] = '\0';
487         return 0;
488 }
489
490 static int write_to_journal(
491         int level,
492         const char*file,
493         int line,
494         const char *func,
495         const char *object_name,
496         const char *object,
497         const char *buffer) {
498
499         char header[LINE_MAX];
500         struct iovec iovec[4] = {};
501         struct msghdr mh = {};
502
503         if (journal_fd < 0)
504                 return 0;
505
506         log_do_header(header, sizeof(header), level,
507                       file, line, func, object_name, object);
508
509         IOVEC_SET_STRING(iovec[0], header);
510         IOVEC_SET_STRING(iovec[1], "MESSAGE=");
511         IOVEC_SET_STRING(iovec[2], buffer);
512         IOVEC_SET_STRING(iovec[3], "\n");
513
514         mh.msg_iov = iovec;
515         mh.msg_iovlen = ELEMENTSOF(iovec);
516
517         if (sendmsg(journal_fd, &mh, MSG_NOSIGNAL) < 0)
518                 return -errno;
519
520         return 1;
521 }
522
523 static int log_dispatch(
524         int level,
525         const char*file,
526         int line,
527         const char *func,
528         const char *object_name,
529         const char *object,
530         char *buffer) {
531
532         int r = 0;
533
534         if (log_target == LOG_TARGET_NULL)
535                 return 0;
536
537         /* Patch in LOG_DAEMON facility if necessary */
538         if ((level & LOG_FACMASK) == 0)
539                 level = log_facility | LOG_PRI(level);
540
541         do {
542                 char *e;
543                 int k = 0;
544
545                 buffer += strspn(buffer, NEWLINE);
546
547                 if (buffer[0] == 0)
548                         break;
549
550                 if ((e = strpbrk(buffer, NEWLINE)))
551                         *(e++) = 0;
552
553                 if (log_target == LOG_TARGET_AUTO ||
554                     log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
555                     log_target == LOG_TARGET_JOURNAL) {
556
557                         k = write_to_journal(level, file, line, func,
558                                              object_name, object, buffer);
559                         if (k < 0) {
560                                 if (k != -EAGAIN)
561                                         log_close_journal();
562                                 log_open_kmsg();
563                         } else if (k > 0)
564                                 r++;
565                 }
566
567                 if (log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
568                     log_target == LOG_TARGET_SYSLOG) {
569
570                         k = write_to_syslog(level, file, line, func,
571                                             object_name, object, buffer);
572                         if (k < 0) {
573                                 if (k != -EAGAIN)
574                                         log_close_syslog();
575                                 log_open_kmsg();
576                         } else if (k > 0)
577                                 r++;
578                 }
579
580                 if (k <= 0 &&
581                     (log_target == LOG_TARGET_AUTO ||
582                      log_target == LOG_TARGET_SAFE ||
583                      log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
584                      log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
585                      log_target == LOG_TARGET_KMSG)) {
586
587                         k = write_to_kmsg(level, file, line, func,
588                                           object_name, object, buffer);
589                         if (k < 0) {
590                                 log_close_kmsg();
591                                 log_open_console();
592                         } else if (k > 0)
593                                 r++;
594                 }
595
596                 if (k <= 0) {
597                         k = write_to_console(level, file, line, func,
598                                              object_name, object, buffer);
599                         if (k < 0)
600                                 return k;
601                 }
602
603                 buffer = e;
604         } while (buffer);
605
606         return r;
607 }
608
609 int log_dump_internal(
610         int level,
611         const char*file,
612         int line,
613         const char *func,
614         char *buffer) {
615
616         PROTECT_ERRNO;
617
618         /* This modifies the buffer... */
619
620         if (_likely_(LOG_PRI(level) > log_max_level))
621                 return 0;
622
623         return log_dispatch(level, file, line, func, NULL, NULL, buffer);
624 }
625
626 int log_metav(
627         int level,
628         const char*file,
629         int line,
630         const char *func,
631         const char *format,
632         va_list ap) {
633
634         PROTECT_ERRNO;
635         char buffer[LINE_MAX];
636
637         if (_likely_(LOG_PRI(level) > log_max_level))
638                 return 0;
639
640         vsnprintf(buffer, sizeof(buffer), format, ap);
641         char_array_0(buffer);
642
643         return log_dispatch(level, file, line, func, NULL, NULL, buffer);
644 }
645
646 int log_meta(
647         int level,
648         const char*file,
649         int line,
650         const char *func,
651         const char *format, ...) {
652
653         int r;
654         va_list ap;
655
656         va_start(ap, format);
657         r = log_metav(level, file, line, func, format, ap);
658         va_end(ap);
659
660         return r;
661 }
662
663 int log_metav_object(
664         int level,
665         const char*file,
666         int line,
667         const char *func,
668         const char *object_name,
669         const char *object,
670         const char *format,
671         va_list ap) {
672
673         PROTECT_ERRNO;
674         char buffer[LINE_MAX];
675
676         if (_likely_(LOG_PRI(level) > log_max_level))
677                 return 0;
678
679         vsnprintf(buffer, sizeof(buffer), format, ap);
680         char_array_0(buffer);
681
682         return log_dispatch(level, file, line, func,
683                             object_name, object, buffer);
684 }
685
686 int log_meta_object(
687         int level,
688         const char*file,
689         int line,
690         const char *func,
691         const char *object_name,
692         const char *object,
693         const char *format, ...) {
694
695         int r;
696         va_list ap;
697
698         va_start(ap, format);
699         r = log_metav_object(level, file, line, func,
700                              object_name, object, format, ap);
701         va_end(ap);
702
703         return r;
704 }
705
706 #pragma GCC diagnostic push
707 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
708 static void log_assert(int level, const char *text, const char *file, int line, const char *func, const char *format) {
709         static char buffer[LINE_MAX];
710
711         if (_likely_(LOG_PRI(level) > log_max_level))
712                 return;
713
714         snprintf(buffer, sizeof(buffer), format, text, file, line, func);
715
716         char_array_0(buffer);
717         log_abort_msg = buffer;
718
719         log_dispatch(level, file, line, func, NULL, NULL, buffer);
720 }
721 #pragma GCC diagnostic pop
722
723 noreturn void log_assert_failed(const char *text, const char *file, int line, const char *func) {
724         log_assert(LOG_CRIT, text, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Aborting.");
725         abort();
726 }
727
728 noreturn void log_assert_failed_unreachable(const char *text, const char *file, int line, const char *func) {
729         log_assert(LOG_CRIT, text, file, line, func, "Code should not be reached '%s' at %s:%u, function %s(). Aborting.");
730         abort();
731 }
732
733 void log_assert_failed_return(const char *text, const char *file, int line, const char *func) {
734         PROTECT_ERRNO;
735         log_assert(LOG_DEBUG, text, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Ignoring.");
736 }
737
738 int log_oom_internal(const char *file, int line, const char *func) {
739         log_meta(LOG_ERR, file, line, func, "Out of memory.");
740         return -ENOMEM;
741 }
742
743 int log_struct_internal(
744                 int level,
745                 const char *file,
746                 int line,
747                 const char *func,
748                 const char *format, ...) {
749
750         PROTECT_ERRNO;
751         va_list ap;
752         int r;
753
754         if (_likely_(LOG_PRI(level) > log_max_level))
755                 return 0;
756
757         if (log_target == LOG_TARGET_NULL)
758                 return 0;
759
760         if ((level & LOG_FACMASK) == 0)
761                 level = log_facility | LOG_PRI(level);
762
763         if ((log_target == LOG_TARGET_AUTO ||
764              log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
765              log_target == LOG_TARGET_JOURNAL) &&
766             journal_fd >= 0) {
767
768                 char header[LINE_MAX];
769                 struct iovec iovec[17] = {};
770                 unsigned n = 0, i;
771                 struct msghdr mh = {
772                         .msg_iov = iovec,
773                 };
774                 static const char nl = '\n';
775
776                 /* If the journal is available do structured logging */
777                 log_do_header(header, sizeof(header), level,
778                               file, line, func, NULL, NULL);
779                 IOVEC_SET_STRING(iovec[n++], header);
780
781                 va_start(ap, format);
782                 while (format && n + 1 < ELEMENTSOF(iovec)) {
783                         char *buf;
784                         va_list aq;
785
786                         /* We need to copy the va_list structure,
787                          * since vasprintf() leaves it afterwards at
788                          * an undefined location */
789
790                         va_copy(aq, ap);
791                         if (vasprintf(&buf, format, aq) < 0) {
792                                 va_end(aq);
793                                 r = -ENOMEM;
794                                 goto finish;
795                         }
796                         va_end(aq);
797
798                         /* Now, jump enough ahead, so that we point to
799                          * the next format string */
800                         VA_FORMAT_ADVANCE(format, ap);
801
802                         IOVEC_SET_STRING(iovec[n++], buf);
803
804                         iovec[n].iov_base = (char*) &nl;
805                         iovec[n].iov_len = 1;
806                         n++;
807
808                         format = va_arg(ap, char *);
809                 }
810
811                 mh.msg_iovlen = n;
812
813                 if (sendmsg(journal_fd, &mh, MSG_NOSIGNAL) < 0)
814                         r = -errno;
815                 else
816                         r = 1;
817
818         finish:
819                 va_end(ap);
820                 for (i = 1; i < n; i += 2)
821                         free(iovec[i].iov_base);
822
823         } else {
824                 char buf[LINE_MAX];
825                 bool found = false;
826
827                 /* Fallback if journal logging is not available */
828
829                 va_start(ap, format);
830                 while (format) {
831                         va_list aq;
832
833                         va_copy(aq, ap);
834                         vsnprintf(buf, sizeof(buf), format, aq);
835                         va_end(aq);
836                         char_array_0(buf);
837
838                         if (startswith(buf, "MESSAGE=")) {
839                                 found = true;
840                                 break;
841                         }
842
843                         VA_FORMAT_ADVANCE(format, ap);
844
845                         format = va_arg(ap, char *);
846                 }
847                 va_end(ap);
848
849                 if (found)
850                         r = log_dispatch(level, file, line, func,
851                                          NULL, NULL, buf + 8);
852                 else
853                         r = -EINVAL;
854         }
855
856         return r;
857 }
858
859 int log_set_target_from_string(const char *e) {
860         LogTarget t;
861
862         t = log_target_from_string(e);
863         if (t < 0)
864                 return -EINVAL;
865
866         log_set_target(t);
867         return 0;
868 }
869
870 int log_set_max_level_from_string(const char *e) {
871         int t;
872
873         t = log_level_from_string(e);
874         if (t < 0)
875                 return t;
876
877         log_set_max_level(t);
878         return 0;
879 }
880
881 void log_parse_environment(void) {
882         _cleanup_free_ char *line = NULL;
883         const char *e;
884         int r;
885
886         r = proc_cmdline(&line);
887         if (r < 0)
888                 log_warning("Failed to read /proc/cmdline. Ignoring: %s", strerror(-r));
889         else if (r > 0) {
890                 char *w, *state;
891                 size_t l;
892
893                 FOREACH_WORD_QUOTED(w, l, line, state) {
894                         if (l == 5 && startswith(w, "debug")) {
895                                 log_set_max_level(LOG_DEBUG);
896                                 break;
897                         }
898                 }
899         }
900
901         e = secure_getenv("SYSTEMD_LOG_TARGET");
902         if (e && log_set_target_from_string(e) < 0)
903                 log_warning("Failed to parse log target %s. Ignoring.", e);
904
905         e = secure_getenv("SYSTEMD_LOG_LEVEL");
906         if (e && log_set_max_level_from_string(e) < 0)
907                 log_warning("Failed to parse log level %s. Ignoring.", e);
908
909         e = secure_getenv("SYSTEMD_LOG_COLOR");
910         if (e && log_show_color_from_string(e) < 0)
911                 log_warning("Failed to parse bool %s. Ignoring.", e);
912
913         e = secure_getenv("SYSTEMD_LOG_LOCATION");
914         if (e && log_show_location_from_string(e) < 0)
915                 log_warning("Failed to parse bool %s. Ignoring.", e);
916 }
917
918 LogTarget log_get_target(void) {
919         return log_target;
920 }
921
922 int log_get_max_level(void) {
923         return log_max_level;
924 }
925
926 void log_show_color(bool b) {
927         show_color = b;
928 }
929
930 void log_show_location(bool b) {
931         show_location = b;
932 }
933
934 int log_show_color_from_string(const char *e) {
935         int t;
936
937         t = parse_boolean(e);
938         if (t < 0)
939                 return t;
940
941         log_show_color(t);
942         return 0;
943 }
944
945 int log_show_location_from_string(const char *e) {
946         int t;
947
948         t = parse_boolean(e);
949         if (t < 0)
950                 return t;
951
952         log_show_location(t);
953         return 0;
954 }
955
956 bool log_on_console(void) {
957         if (log_target == LOG_TARGET_CONSOLE)
958                 return true;
959
960         return syslog_fd < 0 && kmsg_fd < 0 && journal_fd < 0;
961 }
962
963 static const char *const log_target_table[] = {
964         [LOG_TARGET_CONSOLE] = "console",
965         [LOG_TARGET_KMSG] = "kmsg",
966         [LOG_TARGET_JOURNAL] = "journal",
967         [LOG_TARGET_JOURNAL_OR_KMSG] = "journal-or-kmsg",
968         [LOG_TARGET_SYSLOG] = "syslog",
969         [LOG_TARGET_SYSLOG_OR_KMSG] = "syslog-or-kmsg",
970         [LOG_TARGET_AUTO] = "auto",
971         [LOG_TARGET_SAFE] = "safe",
972         [LOG_TARGET_NULL] = "null"
973 };
974
975 DEFINE_STRING_TABLE_LOOKUP(log_target, LogTarget);