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