chiark / gitweb /
Merge branch 'python-systemd-reader'
[elogind.git] / src / shared / log.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2010 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <stdarg.h>
23 #include <stdio.h>
24 #include <errno.h>
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <sys/socket.h>
28 #include <sys/un.h>
29 #include <stddef.h>
30 #include <printf.h>
31
32 #include "log.h"
33 #include "util.h"
34 #include "missing.h"
35 #include "macro.h"
36 #include "socket-util.h"
37
38 #define SNDBUF_SIZE (8*1024*1024)
39
40 static LogTarget log_target = LOG_TARGET_CONSOLE;
41 static int log_max_level = LOG_INFO;
42 static int log_facility = LOG_DAEMON;
43
44 static int console_fd = STDERR_FILENO;
45 static int syslog_fd = -1;
46 static int kmsg_fd = -1;
47 static int journal_fd = -1;
48
49 static bool syslog_is_stream = false;
50
51 static bool show_color = false;
52 static bool show_location = false;
53
54 /* Akin to glibc's __abort_msg; which is private and we hence cannot
55  * use here. */
56 static char *log_abort_msg = NULL;
57
58 void log_close_console(void) {
59
60         if (console_fd < 0)
61                 return;
62
63         if (getpid() == 1) {
64                 if (console_fd >= 3)
65                         close_nointr_nofail(console_fd);
66
67                 console_fd = -1;
68         }
69 }
70
71 static int log_open_console(void) {
72
73         if (console_fd >= 0)
74                 return 0;
75
76         if (getpid() == 1) {
77                 console_fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
78                 if (console_fd < 0)
79                         return console_fd;
80         } else
81                 console_fd = STDERR_FILENO;
82
83         return 0;
84 }
85
86 void log_close_kmsg(void) {
87
88         if (kmsg_fd < 0)
89                 return;
90
91         close_nointr_nofail(kmsg_fd);
92         kmsg_fd = -1;
93 }
94
95 static int log_open_kmsg(void) {
96
97         if (kmsg_fd >= 0)
98                 return 0;
99
100         kmsg_fd = open("/dev/kmsg", O_WRONLY|O_NOCTTY|O_CLOEXEC);
101         if (kmsg_fd < 0)
102                 return -errno;
103
104         return 0;
105 }
106
107 void log_close_syslog(void) {
108
109         if (syslog_fd < 0)
110                 return;
111
112         close_nointr_nofail(syslog_fd);
113         syslog_fd = -1;
114 }
115
116 static int create_log_socket(int type) {
117         int fd;
118
119         /* All output to the syslog/journal fds we do asynchronously,
120          * and if the buffers are full we just drop the messages */
121
122         fd = socket(AF_UNIX, type|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
123         if (fd < 0)
124                 return -errno;
125
126         fd_inc_sndbuf(fd, SNDBUF_SIZE);
127
128         return fd;
129 }
130
131 static int log_open_syslog(void) {
132         union sockaddr_union sa;
133         int r;
134
135         if (syslog_fd >= 0)
136                 return 0;
137
138         zero(sa);
139         sa.un.sun_family = AF_UNIX;
140         strncpy(sa.un.sun_path, "/dev/log", sizeof(sa.un.sun_path));
141
142         syslog_fd = create_log_socket(SOCK_DGRAM);
143         if (syslog_fd < 0) {
144                 r = syslog_fd;
145                 goto fail;
146         }
147
148         if (connect(syslog_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
149                 close_nointr_nofail(syslog_fd);
150
151                 /* Some legacy syslog systems still use stream
152                  * sockets. They really shouldn't. But what can we
153                  * do... */
154                 syslog_fd = create_log_socket(SOCK_STREAM);
155                 if (syslog_fd < 0) {
156                         r = syslog_fd;
157                         goto fail;
158                 }
159
160                 if (connect(syslog_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
161                         r = -errno;
162                         goto fail;
163                 }
164
165                 syslog_is_stream = true;
166         } else
167                 syslog_is_stream = false;
168
169         return 0;
170
171 fail:
172         log_close_syslog();
173         return r;
174 }
175
176 void log_close_journal(void) {
177
178         if (journal_fd < 0)
179                 return;
180
181         close_nointr_nofail(journal_fd);
182         journal_fd = -1;
183 }
184
185 static int log_open_journal(void) {
186         union sockaddr_union sa;
187         int r;
188
189         if (journal_fd >= 0)
190                 return 0;
191
192         journal_fd = create_log_socket(SOCK_DGRAM);
193         if (journal_fd < 0) {
194                 r = journal_fd;
195                 goto fail;
196         }
197
198         zero(sa);
199         sa.un.sun_family = AF_UNIX;
200         strncpy(sa.un.sun_path, "/run/systemd/journal/socket", sizeof(sa.un.sun_path));
201
202         if (connect(journal_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
203                 r = -errno;
204                 goto fail;
205         }
206
207         return 0;
208
209 fail:
210         log_close_journal();
211         return r;
212 }
213
214 int log_open(void) {
215         int r;
216
217         /* If we don't use the console we close it here, to not get
218          * killed by SAK. If we don't use syslog we close it here so
219          * that we are not confused by somebody deleting the socket in
220          * the fs. If we don't use /dev/kmsg we still keep it open,
221          * because there is no reason to close it. */
222
223         if (log_target == LOG_TARGET_NULL) {
224                 log_close_journal();
225                 log_close_syslog();
226                 log_close_console();
227                 return 0;
228         }
229
230         if ((log_target != LOG_TARGET_AUTO && log_target != LOG_TARGET_SAFE) ||
231             getpid() == 1 ||
232             isatty(STDERR_FILENO) <= 0) {
233
234                 if (log_target == LOG_TARGET_AUTO ||
235                     log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
236                     log_target == LOG_TARGET_JOURNAL) {
237                         r = log_open_journal();
238                         if (r >= 0) {
239                                 log_close_syslog();
240                                 log_close_console();
241                                 return r;
242                         }
243                 }
244
245                 if (log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
246                     log_target == LOG_TARGET_SYSLOG) {
247                         r = log_open_syslog();
248                         if (r >= 0) {
249                                 log_close_journal();
250                                 log_close_console();
251                                 return r;
252                         }
253                 }
254
255                 if (log_target == LOG_TARGET_AUTO ||
256                     log_target == LOG_TARGET_SAFE ||
257                     log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
258                     log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
259                     log_target == LOG_TARGET_KMSG) {
260                         r = log_open_kmsg();
261                         if (r >= 0) {
262                                 log_close_journal();
263                                 log_close_syslog();
264                                 log_close_console();
265                                 return r;
266                         }
267                 }
268         }
269
270         log_close_journal();
271         log_close_syslog();
272
273         /* Get the real /dev/console if we are PID=1, hence reopen */
274         log_close_console();
275         return log_open_console();
276 }
277
278 void log_set_target(LogTarget target) {
279         assert(target >= 0);
280         assert(target < _LOG_TARGET_MAX);
281
282         log_target = target;
283 }
284
285 void log_close(void) {
286         log_close_journal();
287         log_close_syslog();
288         log_close_kmsg();
289         log_close_console();
290 }
291
292 void log_forget_fds(void) {
293         console_fd = kmsg_fd = syslog_fd = journal_fd = -1;
294 }
295
296 void log_set_max_level(int level) {
297         assert((level & LOG_PRIMASK) == level);
298
299         log_max_level = level;
300 }
301
302 void log_set_facility(int facility) {
303         log_facility = facility;
304 }
305
306 static int write_to_console(
307                 int level,
308                 const char*file,
309                 int line,
310                 const char *func,
311                 const char *object_name,
312                 const char *object,
313                 const char *buffer) {
314
315         char location[64];
316         struct iovec iovec[5];
317         unsigned n = 0;
318         bool highlight;
319
320         if (console_fd < 0)
321                 return 0;
322
323         highlight = LOG_PRI(level) <= LOG_ERR && show_color;
324
325         zero(iovec);
326
327         if (show_location) {
328                 snprintf(location, sizeof(location), "(%s:%u) ", file, line);
329                 char_array_0(location);
330                 IOVEC_SET_STRING(iovec[n++], location);
331         }
332
333         if (highlight)
334                 IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_RED_ON);
335         IOVEC_SET_STRING(iovec[n++], buffer);
336         if (highlight)
337                 IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_OFF);
338         IOVEC_SET_STRING(iovec[n++], "\n");
339
340         if (writev(console_fd, iovec, n) < 0)
341                 return -errno;
342
343         return 1;
344 }
345
346 static int write_to_syslog(
347         int level,
348         const char*file,
349         int line,
350         const char *func,
351         const char *object_name,
352         const char *object,
353         const char *buffer) {
354
355         char header_priority[16], header_time[64], header_pid[16];
356         struct iovec iovec[5];
357         struct msghdr msghdr;
358         time_t t;
359         struct tm *tm;
360
361         if (syslog_fd < 0)
362                 return 0;
363
364         snprintf(header_priority, sizeof(header_priority), "<%i>", level);
365         char_array_0(header_priority);
366
367         t = (time_t) (now(CLOCK_REALTIME) / USEC_PER_SEC);
368         tm = localtime(&t);
369         if (!tm)
370                 return -EINVAL;
371
372         if (strftime(header_time, sizeof(header_time), "%h %e %T ", tm) <= 0)
373                 return -EINVAL;
374
375         snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) getpid());
376         char_array_0(header_pid);
377
378         zero(iovec);
379         IOVEC_SET_STRING(iovec[0], header_priority);
380         IOVEC_SET_STRING(iovec[1], header_time);
381         IOVEC_SET_STRING(iovec[2], program_invocation_short_name);
382         IOVEC_SET_STRING(iovec[3], header_pid);
383         IOVEC_SET_STRING(iovec[4], buffer);
384
385         /* When using syslog via SOCK_STREAM separate the messages by NUL chars */
386         if (syslog_is_stream)
387                 iovec[4].iov_len++;
388
389         zero(msghdr);
390         msghdr.msg_iov = iovec;
391         msghdr.msg_iovlen = ELEMENTSOF(iovec);
392
393         for (;;) {
394                 ssize_t n;
395
396                 n = sendmsg(syslog_fd, &msghdr, MSG_NOSIGNAL);
397                 if (n < 0)
398                         return -errno;
399
400                 if (!syslog_is_stream ||
401                     (size_t) n >= IOVEC_TOTAL_SIZE(iovec, ELEMENTSOF(iovec)))
402                         break;
403
404                 IOVEC_INCREMENT(iovec, ELEMENTSOF(iovec), n);
405         }
406
407         return 1;
408 }
409
410 static int write_to_kmsg(
411         int level,
412         const char*file,
413         int line,
414         const char *func,
415         const char *object_name,
416         const char *object,
417         const char *buffer) {
418
419         char header_priority[16], header_pid[16];
420         struct iovec iovec[5];
421
422         if (kmsg_fd < 0)
423                 return 0;
424
425         snprintf(header_priority, sizeof(header_priority), "<%i>", level);
426         char_array_0(header_priority);
427
428         snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) getpid());
429         char_array_0(header_pid);
430
431         zero(iovec);
432         IOVEC_SET_STRING(iovec[0], header_priority);
433         IOVEC_SET_STRING(iovec[1], program_invocation_short_name);
434         IOVEC_SET_STRING(iovec[2], header_pid);
435         IOVEC_SET_STRING(iovec[3], buffer);
436         IOVEC_SET_STRING(iovec[4], "\n");
437
438         if (writev(kmsg_fd, iovec, ELEMENTSOF(iovec)) < 0)
439                 return -errno;
440
441         return 1;
442 }
443
444 static int log_do_header(char *header, size_t size,
445                          int level,
446                          const char *file, int line, const char *func,
447                          const char *object_name, const char *object) {
448         snprintf(header, size,
449                  "PRIORITY=%i\n"
450                  "SYSLOG_FACILITY=%i\n"
451                  "%s%.*s%s"
452                  "%s%.*i%s"
453                  "%s%.*s%s"
454                  "%s%.*s%s"
455                  "SYSLOG_IDENTIFIER=%s\n",
456                  LOG_PRI(level),
457                  LOG_FAC(level),
458                  file ? "CODE_FILE=" : "",
459                  file ? LINE_MAX : 0, file, /* %.0s means no output */
460                  file ? "\n" : "",
461                  line ? "CODE_LINE=" : "",
462                  line ? 1 : 0, line, /* %.0d means no output too, special case for 0 */
463                  line ? "\n" : "",
464                  func ? "CODE_FUNCTION=" : "",
465                  func ? LINE_MAX : 0, func,
466                  func ? "\n" : "",
467                  object ? object_name : "",
468                  object ? LINE_MAX : 0, object, /* %.0s means no output */
469                  object ? "\n" : "",
470                  program_invocation_short_name);
471         header[size - 1] = '\0';
472         return 0;
473 }
474
475 static int write_to_journal(
476         int level,
477         const char*file,
478         int line,
479         const char *func,
480         const char *object_name,
481         const char *object,
482         const char *buffer) {
483
484         char header[LINE_MAX];
485         struct iovec iovec[4] = {{0}};
486         struct msghdr mh = {0};
487
488         if (journal_fd < 0)
489                 return 0;
490
491         log_do_header(header, sizeof(header), level,
492                       file, line, func, object_name, object);
493
494         IOVEC_SET_STRING(iovec[0], header);
495         IOVEC_SET_STRING(iovec[1], "MESSAGE=");
496         IOVEC_SET_STRING(iovec[2], buffer);
497         IOVEC_SET_STRING(iovec[3], "\n");
498
499         mh.msg_iov = iovec;
500         mh.msg_iovlen = ELEMENTSOF(iovec);
501
502         if (sendmsg(journal_fd, &mh, MSG_NOSIGNAL) < 0)
503                 return -errno;
504
505         return 1;
506 }
507
508 static int log_dispatch(
509         int level,
510         const char*file,
511         int line,
512         const char *func,
513         const char *object_name,
514         const char *object,
515         char *buffer) {
516
517         int r = 0;
518
519         if (log_target == LOG_TARGET_NULL)
520                 return 0;
521
522         /* Patch in LOG_DAEMON facility if necessary */
523         if ((level & LOG_FACMASK) == 0)
524                 level = log_facility | LOG_PRI(level);
525
526         do {
527                 char *e;
528                 int k = 0;
529
530                 buffer += strspn(buffer, NEWLINE);
531
532                 if (buffer[0] == 0)
533                         break;
534
535                 if ((e = strpbrk(buffer, NEWLINE)))
536                         *(e++) = 0;
537
538                 if (log_target == LOG_TARGET_AUTO ||
539                     log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
540                     log_target == LOG_TARGET_JOURNAL) {
541
542                         k = write_to_journal(level, file, line, func,
543                                              object_name, object, buffer);
544                         if (k < 0) {
545                                 if (k != -EAGAIN)
546                                         log_close_journal();
547                                 log_open_kmsg();
548                         } else if (k > 0)
549                                 r++;
550                 }
551
552                 if (log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
553                     log_target == LOG_TARGET_SYSLOG) {
554
555                         k = write_to_syslog(level, file, line, func,
556                                             object_name, object, buffer);
557                         if (k < 0) {
558                                 if (k != -EAGAIN)
559                                         log_close_syslog();
560                                 log_open_kmsg();
561                         } else if (k > 0)
562                                 r++;
563                 }
564
565                 if (k <= 0 &&
566                     (log_target == LOG_TARGET_AUTO ||
567                      log_target == LOG_TARGET_SAFE ||
568                      log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
569                      log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
570                      log_target == LOG_TARGET_KMSG)) {
571
572                         k = write_to_kmsg(level, file, line, func,
573                                           object_name, object, buffer);
574                         if (k < 0) {
575                                 log_close_kmsg();
576                                 log_open_console();
577                         } else if (k > 0)
578                                 r++;
579                 }
580
581                 if (k <= 0) {
582                         k = write_to_console(level, file, line, func,
583                                              object_name, object, buffer);
584                         if (k < 0)
585                                 return k;
586                 }
587
588                 buffer = e;
589         } while (buffer);
590
591         return r;
592 }
593
594 int log_dump_internal(
595         int level,
596         const char*file,
597         int line,
598         const char *func,
599         char *buffer) {
600
601         int saved_errno, r;
602
603         /* This modifies the buffer... */
604
605         if (_likely_(LOG_PRI(level) > log_max_level))
606                 return 0;
607
608         saved_errno = errno;
609         r = log_dispatch(level, file, line, func, NULL, NULL, buffer);
610         errno = saved_errno;
611
612         return r;
613 }
614
615 int log_metav(
616         int level,
617         const char*file,
618         int line,
619         const char *func,
620         const char *format,
621         va_list ap) {
622
623         char buffer[LINE_MAX];
624         int saved_errno, r;
625
626         if (_likely_(LOG_PRI(level) > log_max_level))
627                 return 0;
628
629         saved_errno = errno;
630         vsnprintf(buffer, sizeof(buffer), format, ap);
631         char_array_0(buffer);
632
633         r = log_dispatch(level, file, line, func, NULL, NULL, buffer);
634         errno = saved_errno;
635
636         return r;
637 }
638
639 int log_meta(
640         int level,
641         const char*file,
642         int line,
643         const char *func,
644         const char *format, ...) {
645
646         int r;
647         va_list ap;
648
649         va_start(ap, format);
650         r = log_metav(level, file, line, func, format, ap);
651         va_end(ap);
652
653         return r;
654 }
655
656 int log_metav_object(
657         int level,
658         const char*file,
659         int line,
660         const char *func,
661         const char *object_name,
662         const char *object,
663         const char *format,
664         va_list ap) {
665
666         char buffer[LINE_MAX];
667         int saved_errno, r;
668
669         if (_likely_(LOG_PRI(level) > log_max_level))
670                 return 0;
671
672         saved_errno = errno;
673         vsnprintf(buffer, sizeof(buffer), format, ap);
674         char_array_0(buffer);
675
676         r = log_dispatch(level, file, line, func,
677                          object_name, object, buffer);
678         errno = saved_errno;
679
680         return r;
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 _noreturn_ static void log_assert(const char *text, const char *file, int line, const char *func, const char *format) {
706         static char buffer[LINE_MAX];
707
708         snprintf(buffer, sizeof(buffer), format, text, file, line, func);
709
710         char_array_0(buffer);
711         log_abort_msg = buffer;
712
713         log_dispatch(LOG_CRIT, file, line, func, NULL, NULL, buffer);
714         abort();
715 }
716 #pragma GCC diagnostic pop
717
718 _noreturn_ void log_assert_failed(const char *text, const char *file, int line, const char *func) {
719         log_assert(text, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Aborting.");
720 }
721
722 _noreturn_ void log_assert_failed_unreachable(const char *text, const char *file, int line, const char *func) {
723         log_assert(text, file, line, func, "Code should not be reached '%s' at %s:%u, function %s(). Aborting.");
724 }
725
726 int log_oom_internal(const char *file, int line, const char *func) {
727         log_meta(LOG_ERR, file, line, func, "Out of memory.");
728         return -ENOMEM;
729 }
730
731 int log_struct_internal(
732                 int level,
733                 const char *file,
734                 int line,
735                 const char *func,
736                 const char *format, ...) {
737
738         int saved_errno;
739         va_list ap;
740         int r;
741
742         if (_likely_(LOG_PRI(level) > log_max_level))
743                 return 0;
744
745         if (log_target == LOG_TARGET_NULL)
746                 return 0;
747
748         if ((level & LOG_FACMASK) == 0)
749                 level = log_facility | LOG_PRI(level);
750
751         saved_errno = errno;
752
753         if ((log_target == LOG_TARGET_AUTO ||
754              log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
755              log_target == LOG_TARGET_JOURNAL) &&
756             journal_fd >= 0) {
757
758                 char header[LINE_MAX];
759                 struct iovec iovec[17] = {{0}};
760                 unsigned n = 0, i;
761                 struct msghdr mh;
762                 static const char nl = '\n';
763
764                 /* If the journal is available do structured logging */
765                 log_do_header(header, sizeof(header), level,
766                               file, line, func, NULL, NULL);
767                 IOVEC_SET_STRING(iovec[n++], header);
768
769                 va_start(ap, format);
770                 while (format && n + 1 < ELEMENTSOF(iovec)) {
771                         char *buf;
772                         va_list aq;
773
774                         /* We need to copy the va_list structure,
775                          * since vasprintf() leaves it afterwards at
776                          * an undefined location */
777
778                         va_copy(aq, ap);
779                         if (vasprintf(&buf, format, aq) < 0) {
780                                 va_end(aq);
781                                 r = -ENOMEM;
782                                 goto finish;
783                         }
784                         va_end(aq);
785
786                         /* Now, jump enough ahead, so that we point to
787                          * the next format string */
788                         VA_FORMAT_ADVANCE(format, ap);
789
790                         IOVEC_SET_STRING(iovec[n++], buf);
791
792                         iovec[n].iov_base = (char*) &nl;
793                         iovec[n].iov_len = 1;
794                         n++;
795
796                         format = va_arg(ap, char *);
797                 }
798
799                 zero(mh);
800                 mh.msg_iov = iovec;
801                 mh.msg_iovlen = n;
802
803                 if (sendmsg(journal_fd, &mh, MSG_NOSIGNAL) < 0)
804                         r = -errno;
805                 else
806                         r = 1;
807
808         finish:
809                 va_end(ap);
810                 for (i = 1; i < n; i += 2)
811                         free(iovec[i].iov_base);
812
813         } else {
814                 char buf[LINE_MAX];
815                 bool found = false;
816
817                 /* Fallback if journal logging is not available */
818
819                 va_start(ap, format);
820                 while (format) {
821                         va_list aq;
822
823                         va_copy(aq, ap);
824                         vsnprintf(buf, sizeof(buf), format, aq);
825                         va_end(aq);
826                         char_array_0(buf);
827
828                         if (startswith(buf, "MESSAGE=")) {
829                                 found = true;
830                                 break;
831                         }
832
833                         VA_FORMAT_ADVANCE(format, ap);
834
835                         format = va_arg(ap, char *);
836                 }
837                 va_end(ap);
838
839                 if (found)
840                         r = log_dispatch(level, file, line, func,
841                                          NULL, NULL, buf + 8);
842                 else
843                         r = -EINVAL;
844         }
845
846         errno = saved_errno;
847         return r;
848 }
849
850 int log_set_target_from_string(const char *e) {
851         LogTarget t;
852
853         t = log_target_from_string(e);
854         if (t < 0)
855                 return -EINVAL;
856
857         log_set_target(t);
858         return 0;
859 }
860
861 int log_set_max_level_from_string(const char *e) {
862         int t;
863
864         t = log_level_from_string(e);
865         if (t < 0)
866                 return t;
867
868         log_set_max_level(t);
869         return 0;
870 }
871
872 void log_parse_environment(void) {
873         const char *e;
874
875         e = secure_getenv("SYSTEMD_LOG_TARGET");
876         if (e && log_set_target_from_string(e) < 0)
877                 log_warning("Failed to parse log target %s. Ignoring.", e);
878
879         e = secure_getenv("SYSTEMD_LOG_LEVEL");
880         if (e && log_set_max_level_from_string(e) < 0)
881                 log_warning("Failed to parse log level %s. Ignoring.", e);
882
883         e = secure_getenv("SYSTEMD_LOG_COLOR");
884         if (e && log_show_color_from_string(e) < 0)
885                 log_warning("Failed to parse bool %s. Ignoring.", e);
886
887         e = secure_getenv("SYSTEMD_LOG_LOCATION");
888         if (e && log_show_location_from_string(e) < 0)
889                 log_warning("Failed to parse bool %s. Ignoring.", e);
890 }
891
892 LogTarget log_get_target(void) {
893         return log_target;
894 }
895
896 int log_get_max_level(void) {
897         return log_max_level;
898 }
899
900 void log_show_color(bool b) {
901         show_color = b;
902 }
903
904 void log_show_location(bool b) {
905         show_location = b;
906 }
907
908 int log_show_color_from_string(const char *e) {
909         int t;
910
911         t = parse_boolean(e);
912         if (t < 0)
913                 return t;
914
915         log_show_color(t);
916         return 0;
917 }
918
919 int log_show_location_from_string(const char *e) {
920         int t;
921
922         t = parse_boolean(e);
923         if (t < 0)
924                 return t;
925
926         log_show_location(t);
927         return 0;
928 }
929
930 bool log_on_console(void) {
931         if (log_target == LOG_TARGET_CONSOLE)
932                 return true;
933
934         return syslog_fd < 0 && kmsg_fd < 0 && journal_fd < 0;
935 }
936
937 static const char *const log_target_table[] = {
938         [LOG_TARGET_CONSOLE] = "console",
939         [LOG_TARGET_KMSG] = "kmsg",
940         [LOG_TARGET_JOURNAL] = "journal",
941         [LOG_TARGET_JOURNAL_OR_KMSG] = "journal-or-kmsg",
942         [LOG_TARGET_SYSLOG] = "syslog",
943         [LOG_TARGET_SYSLOG_OR_KMSG] = "syslog-or-kmsg",
944         [LOG_TARGET_AUTO] = "auto",
945         [LOG_TARGET_SAFE] = "safe",
946         [LOG_TARGET_NULL] = "null"
947 };
948
949 DEFINE_STRING_TABLE_LOOKUP(log_target, LogTarget);