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