chiark / gitweb /
journal: new logging macros to include UNIT=
[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 write_to_journal(
445         int level,
446         const char*file,
447         int line,
448         const char *func,
449         const char *object_name,
450         const char *object,
451         const char *buffer) {
452
453         char header[LINE_MAX];
454         struct iovec iovec[3];
455         struct msghdr mh;
456
457         if (journal_fd < 0)
458                 return 0;
459
460         snprintf(header, sizeof(header),
461                  "PRIORITY=%i\n"
462                  "SYSLOG_FACILITY=%i\n"
463                  "CODE_FILE=%s\n"
464                  "CODE_LINE=%i\n"
465                  "CODE_FUNCTION=%s\n"
466                  "%s%.*s%s"
467                  "SYSLOG_IDENTIFIER=%s\n"
468                  "MESSAGE=",
469                  LOG_PRI(level),
470                  LOG_FAC(level),
471                  file,
472                  line,
473                  func,
474                  object ? object_name : "",
475                  object ? LINE_MAX : 0, object, /* %.0s means no output */
476                  object ? "\n" : "",
477                  program_invocation_short_name);
478
479         char_array_0(header);
480
481         zero(iovec);
482         IOVEC_SET_STRING(iovec[0], header);
483         IOVEC_SET_STRING(iovec[1], buffer);
484         IOVEC_SET_STRING(iovec[2], "\n");
485
486         zero(mh);
487         mh.msg_iov = iovec;
488         mh.msg_iovlen = ELEMENTSOF(iovec);
489
490         if (sendmsg(journal_fd, &mh, MSG_NOSIGNAL) < 0)
491                 return -errno;
492
493         return 1;
494 }
495
496 static int log_dispatch(
497         int level,
498         const char*file,
499         int line,
500         const char *func,
501         const char *object_name,
502         const char *object,
503         char *buffer) {
504
505         int r = 0;
506
507         if (log_target == LOG_TARGET_NULL)
508                 return 0;
509
510         /* Patch in LOG_DAEMON facility if necessary */
511         if ((level & LOG_FACMASK) == 0)
512                 level = log_facility | LOG_PRI(level);
513
514         do {
515                 char *e;
516                 int k = 0;
517
518                 buffer += strspn(buffer, NEWLINE);
519
520                 if (buffer[0] == 0)
521                         break;
522
523                 if ((e = strpbrk(buffer, NEWLINE)))
524                         *(e++) = 0;
525
526                 if (log_target == LOG_TARGET_AUTO ||
527                     log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
528                     log_target == LOG_TARGET_JOURNAL) {
529
530                         k = write_to_journal(level, file, line, func,
531                                              object_name, object, buffer);
532                         if (k < 0) {
533                                 if (k != -EAGAIN)
534                                         log_close_journal();
535                                 log_open_kmsg();
536                         } else if (k > 0)
537                                 r++;
538                 }
539
540                 if (log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
541                     log_target == LOG_TARGET_SYSLOG) {
542
543                         k = write_to_syslog(level, file, line, func,
544                                             object_name, object, buffer);
545                         if (k < 0) {
546                                 if (k != -EAGAIN)
547                                         log_close_syslog();
548                                 log_open_kmsg();
549                         } else if (k > 0)
550                                 r++;
551                 }
552
553                 if (k <= 0 &&
554                     (log_target == LOG_TARGET_AUTO ||
555                      log_target == LOG_TARGET_SAFE ||
556                      log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
557                      log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
558                      log_target == LOG_TARGET_KMSG)) {
559
560                         k = write_to_kmsg(level, file, line, func,
561                                           object_name, object, buffer);
562                         if (k < 0) {
563                                 log_close_kmsg();
564                                 log_open_console();
565                         } else if (k > 0)
566                                 r++;
567                 }
568
569                 if (k <= 0) {
570                         k = write_to_console(level, file, line, func,
571                                              object_name, object, buffer);
572                         if (k < 0)
573                                 return k;
574                 }
575
576                 buffer = e;
577         } while (buffer);
578
579         return r;
580 }
581
582 int log_dump_internal(
583         int level,
584         const char*file,
585         int line,
586         const char *func,
587         char *buffer) {
588
589         int saved_errno, r;
590
591         /* This modifies the buffer... */
592
593         if (_likely_(LOG_PRI(level) > log_max_level))
594                 return 0;
595
596         saved_errno = errno;
597         r = log_dispatch(level, file, line, func, NULL, NULL, buffer);
598         errno = saved_errno;
599
600         return r;
601 }
602
603 int log_metav(
604         int level,
605         const char*file,
606         int line,
607         const char *func,
608         const char *format,
609         va_list ap) {
610
611         char buffer[LINE_MAX];
612         int saved_errno, r;
613
614         if (_likely_(LOG_PRI(level) > log_max_level))
615                 return 0;
616
617         saved_errno = errno;
618         vsnprintf(buffer, sizeof(buffer), format, ap);
619         char_array_0(buffer);
620
621         r = log_dispatch(level, file, line, func, NULL, NULL, buffer);
622         errno = saved_errno;
623
624         return r;
625 }
626
627 int log_meta(
628         int level,
629         const char*file,
630         int line,
631         const char *func,
632         const char *format, ...) {
633
634         int r;
635         va_list ap;
636
637         va_start(ap, format);
638         r = log_metav(level, file, line, func, format, ap);
639         va_end(ap);
640
641         return r;
642 }
643
644 int log_metav_object(
645         int level,
646         const char*file,
647         int line,
648         const char *func,
649         const char *object_name,
650         const char *object,
651         const char *format,
652         va_list ap) {
653
654         char buffer[LINE_MAX];
655         int saved_errno, r;
656
657         if (_likely_(LOG_PRI(level) > log_max_level))
658                 return 0;
659
660         saved_errno = errno;
661         vsnprintf(buffer, sizeof(buffer), format, ap);
662         char_array_0(buffer);
663
664         r = log_dispatch(level, file, line, func,
665                          object_name, object, buffer);
666         errno = saved_errno;
667
668         return r;
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         int saved_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         saved_errno = errno;
740
741         if ((log_target == LOG_TARGET_AUTO ||
742              log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
743              log_target == LOG_TARGET_JOURNAL) &&
744             journal_fd >= 0) {
745
746                 char header[LINE_MAX];
747                 struct iovec iovec[17];
748                 unsigned n = 0, i;
749                 struct msghdr mh;
750                 const char nl = '\n';
751
752                 /* If the journal is available do structured logging */
753
754                 snprintf(header, sizeof(header),
755                         "PRIORITY=%i\n"
756                         "SYSLOG_FACILITY=%i\n"
757                         "CODE_FILE=%s\n"
758                         "CODE_LINE=%i\n"
759                         "CODE_FUNCTION=%s\n"
760                         "SYSLOG_IDENTIFIER=%s\n",
761                         LOG_PRI(level),
762                         LOG_FAC(level),
763                         file,
764                         line,
765                         func,
766                         program_invocation_short_name);
767                 char_array_0(header);
768
769                 zero(iovec);
770                 IOVEC_SET_STRING(iovec[n++], header);
771
772                 va_start(ap, format);
773                 while (format && n + 1 < ELEMENTSOF(iovec)) {
774                         char *buf;
775                         va_list aq;
776
777                         /* We need to copy the va_list structure,
778                          * since vasprintf() leaves it afterwards at
779                          * an undefined location */
780
781                         va_copy(aq, ap);
782                         if (vasprintf(&buf, format, aq) < 0) {
783                                 va_end(aq);
784                                 r = -ENOMEM;
785                                 goto finish;
786                         }
787                         va_end(aq);
788
789                         /* Now, jump enough ahead, so that we point to
790                          * the next format string */
791                         VA_FORMAT_ADVANCE(format, ap);
792
793                         IOVEC_SET_STRING(iovec[n++], buf);
794
795                         iovec[n].iov_base = (char*) &nl;
796                         iovec[n].iov_len = 1;
797                         n++;
798
799                         format = va_arg(ap, char *);
800                 }
801
802                 zero(mh);
803                 mh.msg_iov = iovec;
804                 mh.msg_iovlen = n;
805
806                 if (sendmsg(journal_fd, &mh, MSG_NOSIGNAL) < 0)
807                         r = -errno;
808                 else
809                         r = 1;
810
811         finish:
812                 va_end(ap);
813                 for (i = 1; i < n; i += 2)
814                         free(iovec[i].iov_base);
815
816         } else {
817                 char buf[LINE_MAX];
818                 bool found = false;
819
820                 /* Fallback if journal logging is not available */
821
822                 va_start(ap, format);
823                 while (format) {
824                         va_list aq;
825
826                         va_copy(aq, ap);
827                         vsnprintf(buf, sizeof(buf), format, aq);
828                         va_end(aq);
829                         char_array_0(buf);
830
831                         if (startswith(buf, "MESSAGE=")) {
832                                 found = true;
833                                 break;
834                         }
835
836                         VA_FORMAT_ADVANCE(format, ap);
837
838                         format = va_arg(ap, char *);
839                 }
840                 va_end(ap);
841
842                 if (found)
843                         r = log_dispatch(level, file, line, func,
844                                          NULL, NULL, buf + 8);
845                 else
846                         r = -EINVAL;
847         }
848
849         errno = saved_errno;
850         return r;
851 }
852
853 int log_set_target_from_string(const char *e) {
854         LogTarget t;
855
856         t = log_target_from_string(e);
857         if (t < 0)
858                 return -EINVAL;
859
860         log_set_target(t);
861         return 0;
862 }
863
864 int log_set_max_level_from_string(const char *e) {
865         int t;
866
867         t = log_level_from_string(e);
868         if (t < 0)
869                 return t;
870
871         log_set_max_level(t);
872         return 0;
873 }
874
875 void log_parse_environment(void) {
876         const char *e;
877
878         e = secure_getenv("SYSTEMD_LOG_TARGET");
879         if (e && log_set_target_from_string(e) < 0)
880                 log_warning("Failed to parse log target %s. Ignoring.", e);
881
882         e = secure_getenv("SYSTEMD_LOG_LEVEL");
883         if (e && log_set_max_level_from_string(e) < 0)
884                 log_warning("Failed to parse log level %s. Ignoring.", e);
885
886         e = secure_getenv("SYSTEMD_LOG_COLOR");
887         if (e && log_show_color_from_string(e) < 0)
888                 log_warning("Failed to parse bool %s. Ignoring.", e);
889
890         e = secure_getenv("SYSTEMD_LOG_LOCATION");
891         if (e && log_show_location_from_string(e) < 0)
892                 log_warning("Failed to parse bool %s. Ignoring.", e);
893 }
894
895 LogTarget log_get_target(void) {
896         return log_target;
897 }
898
899 int log_get_max_level(void) {
900         return log_max_level;
901 }
902
903 void log_show_color(bool b) {
904         show_color = b;
905 }
906
907 void log_show_location(bool b) {
908         show_location = b;
909 }
910
911 int log_show_color_from_string(const char *e) {
912         int t;
913
914         t = parse_boolean(e);
915         if (t < 0)
916                 return t;
917
918         log_show_color(t);
919         return 0;
920 }
921
922 int log_show_location_from_string(const char *e) {
923         int t;
924
925         t = parse_boolean(e);
926         if (t < 0)
927                 return t;
928
929         log_show_location(t);
930         return 0;
931 }
932
933 bool log_on_console(void) {
934         if (log_target == LOG_TARGET_CONSOLE)
935                 return true;
936
937         return syslog_fd < 0 && kmsg_fd < 0 && journal_fd < 0;
938 }
939
940 static const char *const log_target_table[] = {
941         [LOG_TARGET_CONSOLE] = "console",
942         [LOG_TARGET_KMSG] = "kmsg",
943         [LOG_TARGET_JOURNAL] = "journal",
944         [LOG_TARGET_JOURNAL_OR_KMSG] = "journal-or-kmsg",
945         [LOG_TARGET_SYSLOG] = "syslog",
946         [LOG_TARGET_SYSLOG_OR_KMSG] = "syslog-or-kmsg",
947         [LOG_TARGET_AUTO] = "auto",
948         [LOG_TARGET_SAFE] = "safe",
949         [LOG_TARGET_NULL] = "null"
950 };
951
952 DEFINE_STRING_TABLE_LOOKUP(log_target, LogTarget);