chiark / gitweb /
util: add a bit of syntactic sugar for saving/restoring errno
[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         PROTECT_ERRNO;
602
603         /* This modifies the buffer... */
604
605         if (_likely_(LOG_PRI(level) > log_max_level))
606                 return 0;
607
608         return log_dispatch(level, file, line, func, NULL, NULL, buffer);
609 }
610
611 int log_metav(
612         int level,
613         const char*file,
614         int line,
615         const char *func,
616         const char *format,
617         va_list ap) {
618
619         PROTECT_ERRNO;
620         char buffer[LINE_MAX];
621
622         if (_likely_(LOG_PRI(level) > log_max_level))
623                 return 0;
624
625         vsnprintf(buffer, sizeof(buffer), format, ap);
626         char_array_0(buffer);
627
628         return log_dispatch(level, file, line, func, NULL, NULL, buffer);
629 }
630
631 int log_meta(
632         int level,
633         const char*file,
634         int line,
635         const char *func,
636         const char *format, ...) {
637
638         int r;
639         va_list ap;
640
641         va_start(ap, format);
642         r = log_metav(level, file, line, func, format, ap);
643         va_end(ap);
644
645         return r;
646 }
647
648 int log_metav_object(
649         int level,
650         const char*file,
651         int line,
652         const char *func,
653         const char *object_name,
654         const char *object,
655         const char *format,
656         va_list ap) {
657
658         PROTECT_ERRNO;
659         char buffer[LINE_MAX];
660
661         if (_likely_(LOG_PRI(level) > log_max_level))
662                 return 0;
663
664         vsnprintf(buffer, sizeof(buffer), format, ap);
665         char_array_0(buffer);
666
667         return log_dispatch(level, file, line, func,
668                             object_name, object, buffer);
669 }
670
671 int log_meta_object(
672         int level,
673         const char*file,
674         int line,
675         const char *func,
676         const char *object_name,
677         const char *object,
678         const char *format, ...) {
679
680         int r;
681         va_list ap;
682
683         va_start(ap, format);
684         r = log_metav_object(level, file, line, func,
685                              object_name, object, format, ap);
686         va_end(ap);
687
688         return r;
689 }
690
691 #pragma GCC diagnostic push
692 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
693 _noreturn_ static void log_assert(const char *text, const char *file, int line, const char *func, const char *format) {
694         static char buffer[LINE_MAX];
695
696         snprintf(buffer, sizeof(buffer), format, text, file, line, func);
697
698         char_array_0(buffer);
699         log_abort_msg = buffer;
700
701         log_dispatch(LOG_CRIT, file, line, func, NULL, NULL, buffer);
702         abort();
703 }
704 #pragma GCC diagnostic pop
705
706 _noreturn_ void log_assert_failed(const char *text, const char *file, int line, const char *func) {
707         log_assert(text, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Aborting.");
708 }
709
710 _noreturn_ void log_assert_failed_unreachable(const char *text, const char *file, int line, const char *func) {
711         log_assert(text, file, line, func, "Code should not be reached '%s' at %s:%u, function %s(). Aborting.");
712 }
713
714 int log_oom_internal(const char *file, int line, const char *func) {
715         log_meta(LOG_ERR, file, line, func, "Out of memory.");
716         return -ENOMEM;
717 }
718
719 int log_struct_internal(
720                 int level,
721                 const char *file,
722                 int line,
723                 const char *func,
724                 const char *format, ...) {
725
726         PROTECT_ERRNO;
727         va_list ap;
728         int r;
729
730         if (_likely_(LOG_PRI(level) > log_max_level))
731                 return 0;
732
733         if (log_target == LOG_TARGET_NULL)
734                 return 0;
735
736         if ((level & LOG_FACMASK) == 0)
737                 level = log_facility | LOG_PRI(level);
738
739         if ((log_target == LOG_TARGET_AUTO ||
740              log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
741              log_target == LOG_TARGET_JOURNAL) &&
742             journal_fd >= 0) {
743
744                 char header[LINE_MAX];
745                 struct iovec iovec[17] = {{0}};
746                 unsigned n = 0, i;
747                 struct msghdr mh;
748                 static const char nl = '\n';
749
750                 /* If the journal is available do structured logging */
751                 log_do_header(header, sizeof(header), level,
752                               file, line, func, NULL, NULL);
753                 IOVEC_SET_STRING(iovec[n++], header);
754
755                 va_start(ap, format);
756                 while (format && n + 1 < ELEMENTSOF(iovec)) {
757                         char *buf;
758                         va_list aq;
759
760                         /* We need to copy the va_list structure,
761                          * since vasprintf() leaves it afterwards at
762                          * an undefined location */
763
764                         va_copy(aq, ap);
765                         if (vasprintf(&buf, format, aq) < 0) {
766                                 va_end(aq);
767                                 r = -ENOMEM;
768                                 goto finish;
769                         }
770                         va_end(aq);
771
772                         /* Now, jump enough ahead, so that we point to
773                          * the next format string */
774                         VA_FORMAT_ADVANCE(format, ap);
775
776                         IOVEC_SET_STRING(iovec[n++], buf);
777
778                         iovec[n].iov_base = (char*) &nl;
779                         iovec[n].iov_len = 1;
780                         n++;
781
782                         format = va_arg(ap, char *);
783                 }
784
785                 zero(mh);
786                 mh.msg_iov = iovec;
787                 mh.msg_iovlen = n;
788
789                 if (sendmsg(journal_fd, &mh, MSG_NOSIGNAL) < 0)
790                         r = -errno;
791                 else
792                         r = 1;
793
794         finish:
795                 va_end(ap);
796                 for (i = 1; i < n; i += 2)
797                         free(iovec[i].iov_base);
798
799         } else {
800                 char buf[LINE_MAX];
801                 bool found = false;
802
803                 /* Fallback if journal logging is not available */
804
805                 va_start(ap, format);
806                 while (format) {
807                         va_list aq;
808
809                         va_copy(aq, ap);
810                         vsnprintf(buf, sizeof(buf), format, aq);
811                         va_end(aq);
812                         char_array_0(buf);
813
814                         if (startswith(buf, "MESSAGE=")) {
815                                 found = true;
816                                 break;
817                         }
818
819                         VA_FORMAT_ADVANCE(format, ap);
820
821                         format = va_arg(ap, char *);
822                 }
823                 va_end(ap);
824
825                 if (found)
826                         r = log_dispatch(level, file, line, func,
827                                          NULL, NULL, buf + 8);
828                 else
829                         r = -EINVAL;
830         }
831
832         return r;
833 }
834
835 int log_set_target_from_string(const char *e) {
836         LogTarget t;
837
838         t = log_target_from_string(e);
839         if (t < 0)
840                 return -EINVAL;
841
842         log_set_target(t);
843         return 0;
844 }
845
846 int log_set_max_level_from_string(const char *e) {
847         int t;
848
849         t = log_level_from_string(e);
850         if (t < 0)
851                 return t;
852
853         log_set_max_level(t);
854         return 0;
855 }
856
857 void log_parse_environment(void) {
858         const char *e;
859
860         e = secure_getenv("SYSTEMD_LOG_TARGET");
861         if (e && log_set_target_from_string(e) < 0)
862                 log_warning("Failed to parse log target %s. Ignoring.", e);
863
864         e = secure_getenv("SYSTEMD_LOG_LEVEL");
865         if (e && log_set_max_level_from_string(e) < 0)
866                 log_warning("Failed to parse log level %s. Ignoring.", e);
867
868         e = secure_getenv("SYSTEMD_LOG_COLOR");
869         if (e && log_show_color_from_string(e) < 0)
870                 log_warning("Failed to parse bool %s. Ignoring.", e);
871
872         e = secure_getenv("SYSTEMD_LOG_LOCATION");
873         if (e && log_show_location_from_string(e) < 0)
874                 log_warning("Failed to parse bool %s. Ignoring.", e);
875 }
876
877 LogTarget log_get_target(void) {
878         return log_target;
879 }
880
881 int log_get_max_level(void) {
882         return log_max_level;
883 }
884
885 void log_show_color(bool b) {
886         show_color = b;
887 }
888
889 void log_show_location(bool b) {
890         show_location = b;
891 }
892
893 int log_show_color_from_string(const char *e) {
894         int t;
895
896         t = parse_boolean(e);
897         if (t < 0)
898                 return t;
899
900         log_show_color(t);
901         return 0;
902 }
903
904 int log_show_location_from_string(const char *e) {
905         int t;
906
907         t = parse_boolean(e);
908         if (t < 0)
909                 return t;
910
911         log_show_location(t);
912         return 0;
913 }
914
915 bool log_on_console(void) {
916         if (log_target == LOG_TARGET_CONSOLE)
917                 return true;
918
919         return syslog_fd < 0 && kmsg_fd < 0 && journal_fd < 0;
920 }
921
922 static const char *const log_target_table[] = {
923         [LOG_TARGET_CONSOLE] = "console",
924         [LOG_TARGET_KMSG] = "kmsg",
925         [LOG_TARGET_JOURNAL] = "journal",
926         [LOG_TARGET_JOURNAL_OR_KMSG] = "journal-or-kmsg",
927         [LOG_TARGET_SYSLOG] = "syslog",
928         [LOG_TARGET_SYSLOG_OR_KMSG] = "syslog-or-kmsg",
929         [LOG_TARGET_AUTO] = "auto",
930         [LOG_TARGET_SAFE] = "safe",
931         [LOG_TARGET_NULL] = "null"
932 };
933
934 DEFINE_STRING_TABLE_LOOKUP(log_target, LogTarget);