1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2010 Lennart Poettering
16 #include <sys/signalfd.h>
17 #include <sys/socket.h>
24 #include "sd-messages.h"
26 #include "alloc-util.h"
28 #include "format-util.h"
33 #include "parse-util.h"
34 #include "proc-cmdline.h"
35 #include "process-util.h"
36 #include "signal-util.h"
37 #include "socket-util.h"
38 #include "stdio-util.h"
39 #include "string-table.h"
40 #include "string-util.h"
41 #include "syslog-util.h"
42 #include "terminal-util.h"
43 #include "time-util.h"
47 #define SNDBUF_SIZE (8*1024*1024)
49 static LogTarget log_target
= LOG_TARGET_CONSOLE
;
50 static int log_max_level
[] = {LOG_INFO
, LOG_INFO
};
51 assert_cc(ELEMENTSOF(log_max_level
) == _LOG_REALM_MAX
);
52 static int log_facility
= LOG_DAEMON
;
54 static int console_fd
= STDERR_FILENO
;
55 static int syslog_fd
= -1;
56 static int kmsg_fd
= -1;
57 static int journal_fd
= -1;
59 static bool syslog_is_stream
= false;
61 static bool show_color
= false;
62 static bool show_location
= false;
64 static bool upgrade_syslog_to_journal
= false;
65 static bool always_reopen_console
= false;
66 static bool open_when_needed
= false;
67 static bool prohibit_ipc
= false;
69 /* Akin to glibc's __abort_msg; which is private and we hence cannot
71 static char *log_abort_msg
= NULL
;
73 /* An assert to use in logging functions that does not call recursively
74 * into our logging functions (since that might lead to a loop). */
75 #define assert_raw(expr) \
77 if (_unlikely_(!(expr))) { \
78 fputs(#expr "\n", stderr); \
83 static void log_close_console(void) {
84 console_fd
= safe_close_above_stdio(console_fd
);
87 static int log_open_console(void) {
89 if (!always_reopen_console
) {
90 console_fd
= STDERR_FILENO
;
95 console_fd
= open_terminal("/dev/console", O_WRONLY
|O_NOCTTY
|O_CLOEXEC
);
99 console_fd
= fd_move_above_stdio(console_fd
);
105 static void log_close_kmsg(void) {
106 kmsg_fd
= safe_close(kmsg_fd
);
109 static int log_open_kmsg(void) {
114 kmsg_fd
= open("/dev/kmsg", O_WRONLY
|O_NOCTTY
|O_CLOEXEC
);
118 kmsg_fd
= fd_move_above_stdio(kmsg_fd
);
122 static void log_close_syslog(void) {
123 syslog_fd
= safe_close(syslog_fd
);
126 static int create_log_socket(int type
) {
130 fd
= socket(AF_UNIX
, type
|SOCK_CLOEXEC
, 0);
134 fd
= fd_move_above_stdio(fd
);
135 (void) fd_inc_sndbuf(fd
, SNDBUF_SIZE
);
137 /* We need a blocking fd here since we'd otherwise lose messages way too early. However, let's not hang forever
138 * in the unlikely case of a deadlock. */
139 if (getpid_cached() == 1)
140 timeval_store(&tv
, 10 * USEC_PER_MSEC
);
142 timeval_store(&tv
, 10 * USEC_PER_SEC
);
143 (void) setsockopt(fd
, SOL_SOCKET
, SO_SNDTIMEO
, &tv
, sizeof(tv
));
148 static int log_open_syslog(void) {
150 static const union sockaddr_union sa
= {
151 .un
.sun_family
= AF_UNIX
,
152 .un
.sun_path
= "/dev/log",
160 syslog_fd
= create_log_socket(SOCK_DGRAM
);
166 if (connect(syslog_fd
, &sa
.sa
, SOCKADDR_UN_LEN(sa
.un
)) < 0) {
167 safe_close(syslog_fd
);
169 /* Some legacy syslog systems still use stream
170 * sockets. They really shouldn't. But what can we
172 syslog_fd
= create_log_socket(SOCK_STREAM
);
178 if (connect(syslog_fd
, &sa
.sa
, SOCKADDR_UN_LEN(sa
.un
)) < 0) {
183 syslog_is_stream
= true;
185 syslog_is_stream
= false;
194 static void log_close_journal(void) {
195 journal_fd
= safe_close(journal_fd
);
198 static int log_open_journal(void) {
200 static const union sockaddr_union sa
= {
201 .un
.sun_family
= AF_UNIX
,
202 .un
.sun_path
= "/run/systemd/journal/socket",
210 journal_fd
= create_log_socket(SOCK_DGRAM
);
211 if (journal_fd
< 0) {
216 if (connect(journal_fd
, &sa
.sa
, SOCKADDR_UN_LEN(sa
.un
)) < 0) {
231 /* Do not call from library code. */
233 /* If we don't use the console we close it here, to not get
234 * killed by SAK. If we don't use syslog we close it here so
235 * that we are not confused by somebody deleting the socket in
236 * the fs, and to make sure we don't use it if prohibit_ipc is
237 * set. If we don't use /dev/kmsg we still keep it open,
238 * because there is no reason to close it. */
240 if (log_target
== LOG_TARGET_NULL
) {
247 if (log_target
!= LOG_TARGET_AUTO
||
248 getpid_cached() == 1 ||
249 isatty(STDERR_FILENO
) <= 0) {
252 IN_SET(log_target
, LOG_TARGET_AUTO
,
253 LOG_TARGET_JOURNAL_OR_KMSG
,
254 LOG_TARGET_JOURNAL
)) {
255 r
= log_open_journal();
264 IN_SET(log_target
, LOG_TARGET_SYSLOG_OR_KMSG
,
265 LOG_TARGET_SYSLOG
)) {
266 r
= log_open_syslog();
274 if (IN_SET(log_target
, LOG_TARGET_AUTO
,
275 LOG_TARGET_JOURNAL_OR_KMSG
,
276 LOG_TARGET_SYSLOG_OR_KMSG
,
291 return log_open_console();
294 void log_set_target(LogTarget target
) {
296 assert(target
< _LOG_TARGET_MAX
);
298 if (upgrade_syslog_to_journal
) {
299 if (target
== LOG_TARGET_SYSLOG
)
300 target
= LOG_TARGET_JOURNAL
;
301 else if (target
== LOG_TARGET_SYSLOG_OR_KMSG
)
302 target
= LOG_TARGET_JOURNAL_OR_KMSG
;
308 void log_close(void) {
309 /* Do not call from library code. */
317 void log_forget_fds(void) {
318 /* Do not call from library code. */
320 console_fd
= kmsg_fd
= syslog_fd
= journal_fd
= -1;
323 void log_set_max_level_realm(LogRealm realm
, int level
) {
324 assert((level
& LOG_PRIMASK
) == level
);
325 assert(realm
< ELEMENTSOF(log_max_level
));
327 log_max_level
[realm
] = level
;
330 void log_set_facility(int facility
) {
331 log_facility
= facility
;
334 static int write_to_console(
340 const char *buffer
) {
342 char location
[256], prefix
[1 + DECIMAL_STR_MAX(int) + 2];
343 struct iovec iovec
[6] = {};
350 if (log_target
== LOG_TARGET_CONSOLE_PREFIXED
) {
351 xsprintf(prefix
, "<%i>", level
);
352 iovec
[n
++] = IOVEC_MAKE_STRING(prefix
);
355 highlight
= LOG_PRI(level
) <= LOG_ERR
&& show_color
;
358 (void) snprintf(location
, sizeof location
, "(%s:%i) ", file
, line
);
359 iovec
[n
++] = IOVEC_MAKE_STRING(location
);
363 iovec
[n
++] = IOVEC_MAKE_STRING(ANSI_HIGHLIGHT_RED
);
364 iovec
[n
++] = IOVEC_MAKE_STRING(buffer
);
366 iovec
[n
++] = IOVEC_MAKE_STRING(ANSI_NORMAL
);
367 iovec
[n
++] = IOVEC_MAKE_STRING("\n");
369 if (writev(console_fd
, iovec
, n
) < 0) {
371 if (errno
== EIO
&& getpid_cached() == 1) {
373 /* If somebody tried to kick us from our
374 * console tty (via vhangup() or suchlike),
375 * try to reconnect */
383 if (writev(console_fd
, iovec
, n
) < 0)
392 static int write_to_syslog(
398 const char *buffer
) {
400 char header_priority
[2 + DECIMAL_STR_MAX(int) + 1],
402 header_pid
[4 + DECIMAL_STR_MAX(pid_t
) + 1];
403 struct iovec iovec
[5] = {};
404 struct msghdr msghdr
= {
406 .msg_iovlen
= ELEMENTSOF(iovec
),
414 xsprintf(header_priority
, "<%i>", level
);
416 t
= (time_t) (now(CLOCK_REALTIME
) / USEC_PER_SEC
);
421 if (strftime(header_time
, sizeof(header_time
), "%h %e %T ", tm
) <= 0)
424 xsprintf(header_pid
, "["PID_FMT
"]: ", getpid_cached());
426 iovec
[0] = IOVEC_MAKE_STRING(header_priority
);
427 iovec
[1] = IOVEC_MAKE_STRING(header_time
);
428 iovec
[2] = IOVEC_MAKE_STRING(program_invocation_short_name
);
429 iovec
[3] = IOVEC_MAKE_STRING(header_pid
);
430 iovec
[4] = IOVEC_MAKE_STRING(buffer
);
432 /* When using syslog via SOCK_STREAM separate the messages by NUL chars */
433 if (syslog_is_stream
)
439 n
= sendmsg(syslog_fd
, &msghdr
, MSG_NOSIGNAL
);
443 if (!syslog_is_stream
||
444 (size_t) n
>= IOVEC_TOTAL_SIZE(iovec
, ELEMENTSOF(iovec
)))
447 IOVEC_INCREMENT(iovec
, ELEMENTSOF(iovec
), n
);
453 static int write_to_kmsg(
459 const char *buffer
) {
461 char header_priority
[2 + DECIMAL_STR_MAX(int) + 1],
462 header_pid
[4 + DECIMAL_STR_MAX(pid_t
) + 1];
463 struct iovec iovec
[5] = {};
468 xsprintf(header_priority
, "<%i>", level
);
469 xsprintf(header_pid
, "["PID_FMT
"]: ", getpid_cached());
471 iovec
[0] = IOVEC_MAKE_STRING(header_priority
);
472 iovec
[1] = IOVEC_MAKE_STRING(program_invocation_short_name
);
473 iovec
[2] = IOVEC_MAKE_STRING(header_pid
);
474 iovec
[3] = IOVEC_MAKE_STRING(buffer
);
475 iovec
[4] = IOVEC_MAKE_STRING("\n");
477 if (writev(kmsg_fd
, iovec
, ELEMENTSOF(iovec
)) < 0)
483 static int log_do_header(
488 const char *file
, int line
, const char *func
,
489 const char *object_field
, const char *object
,
490 const char *extra_field
, const char *extra
) {
493 r
= snprintf(header
, size
,
495 "SYSLOG_FACILITY=%i\n"
496 "%s%.256s%s" /* CODE_FILE */
497 "%s%.*i%s" /* CODE_LINE */
498 "%s%.256s%s" /* CODE_FUNC */
499 "%s%.*i%s" /* ERRNO */
500 "%s%.256s%s" /* object */
501 "%s%.256s%s" /* extra */
502 "SYSLOG_IDENTIFIER=%.256s\n",
505 isempty(file
) ? "" : "CODE_FILE=",
506 isempty(file
) ? "" : file
,
507 isempty(file
) ? "" : "\n",
508 line
? "CODE_LINE=" : "",
509 line
? 1 : 0, line
, /* %.0d means no output too, special case for 0 */
511 isempty(func
) ? "" : "CODE_FUNC=",
512 isempty(func
) ? "" : func
,
513 isempty(func
) ? "" : "\n",
514 error
? "ERRNO=" : "",
515 error
? 1 : 0, error
,
517 isempty(object
) ? "" : object_field
,
518 isempty(object
) ? "" : object
,
519 isempty(object
) ? "" : "\n",
520 isempty(extra
) ? "" : extra_field
,
521 isempty(extra
) ? "" : extra
,
522 isempty(extra
) ? "" : "\n",
523 program_invocation_short_name
);
524 assert_raw((size_t) r
< size
);
529 static int write_to_journal(
535 const char *object_field
,
537 const char *extra_field
,
539 const char *buffer
) {
541 char header
[LINE_MAX
];
542 struct iovec iovec
[4] = {};
543 struct msghdr mh
= {};
548 log_do_header(header
, sizeof(header
), level
, error
, file
, line
, func
, object_field
, object
, extra_field
, extra
);
550 iovec
[0] = IOVEC_MAKE_STRING(header
);
551 iovec
[1] = IOVEC_MAKE_STRING("MESSAGE=");
552 iovec
[2] = IOVEC_MAKE_STRING(buffer
);
553 iovec
[3] = IOVEC_MAKE_STRING("\n");
556 mh
.msg_iovlen
= ELEMENTSOF(iovec
);
558 if (sendmsg(journal_fd
, &mh
, MSG_NOSIGNAL
) < 0)
564 int log_dispatch_internal(
570 const char *object_field
,
572 const char *extra_field
,
581 if (log_target
== LOG_TARGET_NULL
)
584 /* Patch in LOG_DAEMON facility if necessary */
585 if ((level
& LOG_FACMASK
) == 0)
586 level
= log_facility
| LOG_PRI(level
);
588 if (open_when_needed
)
595 buffer
+= strspn(buffer
, NEWLINE
);
600 if ((e
= strpbrk(buffer
, NEWLINE
)))
603 if (IN_SET(log_target
, LOG_TARGET_AUTO
,
604 LOG_TARGET_JOURNAL_OR_KMSG
,
605 LOG_TARGET_JOURNAL
)) {
607 k
= write_to_journal(level
, error
, file
, line
, func
, object_field
, object
, extra_field
, extra
, buffer
);
608 if (k
< 0 && k
!= -EAGAIN
)
612 if (IN_SET(log_target
, LOG_TARGET_SYSLOG_OR_KMSG
,
613 LOG_TARGET_SYSLOG
)) {
615 k
= write_to_syslog(level
, error
, file
, line
, func
, buffer
);
616 if (k
< 0 && k
!= -EAGAIN
)
621 IN_SET(log_target
, LOG_TARGET_AUTO
,
622 LOG_TARGET_SYSLOG_OR_KMSG
,
623 LOG_TARGET_JOURNAL_OR_KMSG
,
629 k
= write_to_kmsg(level
, error
, file
, line
, func
, buffer
);
637 (void) write_to_console(level
, error
, file
, line
, func
, buffer
);
642 if (open_when_needed
)
648 int log_dump_internal(
656 LogRealm realm
= LOG_REALM_REMOVE_LEVEL(level
);
659 /* This modifies the buffer... */
664 if (_likely_(LOG_PRI(level
) > log_max_level
[realm
]))
667 return log_dispatch_internal(level
, error
, file
, line
, func
, NULL
, NULL
, NULL
, NULL
, buffer
);
670 int log_internalv_realm(
679 LogRealm realm
= LOG_REALM_REMOVE_LEVEL(level
);
680 char buffer
[LINE_MAX
];
686 if (_likely_(LOG_PRI(level
) > log_max_level
[realm
]))
689 /* Make sure that %m maps to the specified error (or "Success"). */
692 (void) vsnprintf(buffer
, sizeof buffer
, format
, ap
);
694 return log_dispatch_internal(level
, error
, file
, line
, func
, NULL
, NULL
, NULL
, NULL
, buffer
);
697 int log_internal_realm(
703 const char *format
, ...) {
708 va_start(ap
, format
);
709 r
= log_internalv_realm(level
, error
, file
, line
, func
, format
, ap
);
716 static int log_object_internalv(
722 const char *object_field
,
724 const char *extra_field
,
735 if (_likely_(LOG_PRI(level
) > log_max_level
[LOG_REALM_SYSTEMD
]))
738 /* Make sure that %m maps to the specified error (or "Success"). */
741 /* Prepend the object name before the message */
746 buffer
= newa(char, n
+ 2 + LINE_MAX
);
747 b
= stpcpy(stpcpy(buffer
, object
), ": ");
749 b
= buffer
= newa(char, LINE_MAX
);
751 (void) vsnprintf(b
, LINE_MAX
, format
, ap
);
753 return log_dispatch_internal(level
, error
, file
, line
, func
,
754 object_field
, object
, extra_field
, extra
, buffer
);
757 int log_object_internal(
763 const char *object_field
,
765 const char *extra_field
,
767 const char *format
, ...) {
772 va_start(ap
, format
);
773 r
= log_object_internalv(level
, error
, file
, line
, func
, object_field
, object
, extra_field
, extra
, format
, ap
);
779 static void log_assert(
785 const char *format
) {
787 static char buffer
[LINE_MAX
];
788 LogRealm realm
= LOG_REALM_REMOVE_LEVEL(level
);
790 if (_likely_(LOG_PRI(level
) > log_max_level
[realm
]))
793 DISABLE_WARNING_FORMAT_NONLITERAL
;
794 (void) snprintf(buffer
, sizeof buffer
, format
, text
, file
, line
, func
);
797 log_abort_msg
= buffer
;
799 log_dispatch_internal(level
, 0, file
, line
, func
, NULL
, NULL
, NULL
, NULL
, buffer
);
802 _noreturn_
void log_assert_failed_realm(
809 log_assert(LOG_REALM_PLUS_LEVEL(realm
, LOG_CRIT
), text
, file
, line
, func
,
810 "Assertion '%s' failed at %s:%u, function %s(). Aborting.");
814 _noreturn_
void log_assert_failed_unreachable_realm(
821 log_assert(LOG_REALM_PLUS_LEVEL(realm
, LOG_CRIT
), text
, file
, line
, func
,
822 "Code should not be reached '%s' at %s:%u, function %s(). Aborting.");
826 void log_assert_failed_return_realm(
833 log_assert(LOG_REALM_PLUS_LEVEL(realm
, LOG_DEBUG
), text
, file
, line
, func
,
834 "Assertion '%s' failed at %s:%u, function %s(). Ignoring.");
837 int log_oom_internal(LogRealm realm
, const char *file
, int line
, const char *func
) {
838 return log_internal_realm(LOG_REALM_PLUS_LEVEL(realm
, LOG_ERR
),
839 ENOMEM
, file
, line
, func
, "Out of memory.");
842 int log_format_iovec(
846 bool newline_separator
,
851 static const char nl
= '\n';
853 while (format
&& *n
+ 1 < iovec_len
) {
858 /* We need to copy the va_list structure,
859 * since vasprintf() leaves it afterwards at
860 * an undefined location */
865 r
= vasprintf(&m
, format
, aq
);
870 /* Now, jump enough ahead, so that we point to
871 * the next format string */
872 VA_FORMAT_ADVANCE(format
, ap
);
874 iovec
[(*n
)++] = IOVEC_MAKE_STRING(m
);
876 if (newline_separator
) {
877 iovec
[*n
].iov_base
= (char*) &nl
;
878 iovec
[*n
].iov_len
= 1;
882 format
= va_arg(ap
, char *);
887 int log_struct_internal(
893 const char *format
, ...) {
895 LogRealm realm
= LOG_REALM_REMOVE_LEVEL(level
);
904 if (_likely_(LOG_PRI(level
) > log_max_level
[realm
]))
907 if (log_target
== LOG_TARGET_NULL
)
910 if ((level
& LOG_FACMASK
) == 0)
911 level
= log_facility
| LOG_PRI(level
);
913 if (IN_SET(log_target
,
915 LOG_TARGET_JOURNAL_OR_KMSG
,
916 LOG_TARGET_JOURNAL
)) {
918 if (open_when_needed
)
921 if (journal_fd
>= 0) {
922 char header
[LINE_MAX
];
923 struct iovec iovec
[17] = {};
929 bool fallback
= false;
931 /* If the journal is available do structured logging */
932 log_do_header(header
, sizeof(header
), level
, error
, file
, line
, func
, NULL
, NULL
, NULL
, NULL
);
933 iovec
[n
++] = IOVEC_MAKE_STRING(header
);
935 va_start(ap
, format
);
936 r
= log_format_iovec(iovec
, ELEMENTSOF(iovec
), &n
, true, error
, format
, ap
);
941 (void) sendmsg(journal_fd
, &mh
, MSG_NOSIGNAL
);
945 for (i
= 1; i
< n
; i
+= 2)
946 free(iovec
[i
].iov_base
);
949 if (open_when_needed
)
957 /* Fallback if journal logging is not available or didn't work. */
959 va_start(ap
, format
);
966 (void) vsnprintf(buf
, sizeof buf
, format
, aq
);
969 if (startswith(buf
, "MESSAGE=")) {
974 VA_FORMAT_ADVANCE(format
, ap
);
976 format
= va_arg(ap
, char *);
981 if (open_when_needed
)
987 return log_dispatch_internal(level
, error
, file
, line
, func
, NULL
, NULL
, NULL
, NULL
, buf
+ 8);
990 int log_struct_iovec_internal(
996 const struct iovec input_iovec
[],
997 size_t n_input_iovec
) {
999 LogRealm realm
= LOG_REALM_REMOVE_LEVEL(level
);
1007 if (_likely_(LOG_PRI(level
) > log_max_level
[realm
]))
1010 if (log_target
== LOG_TARGET_NULL
)
1013 if ((level
& LOG_FACMASK
) == 0)
1014 level
= log_facility
| LOG_PRI(level
);
1016 if (IN_SET(log_target
, LOG_TARGET_AUTO
,
1017 LOG_TARGET_JOURNAL_OR_KMSG
,
1018 LOG_TARGET_JOURNAL
) &&
1021 struct iovec iovec
[1 + n_input_iovec
*2];
1022 char header
[LINE_MAX
];
1023 struct msghdr mh
= {
1025 .msg_iovlen
= 1 + n_input_iovec
*2,
1028 log_do_header(header
, sizeof(header
), level
, error
, file
, line
, func
, NULL
, NULL
, NULL
, NULL
);
1029 iovec
[0] = IOVEC_MAKE_STRING(header
);
1031 for (i
= 0; i
< n_input_iovec
; i
++) {
1032 iovec
[1+i
*2] = input_iovec
[i
];
1033 iovec
[1+i
*2+1] = IOVEC_MAKE_STRING("\n");
1036 if (sendmsg(journal_fd
, &mh
, MSG_NOSIGNAL
) >= 0)
1040 for (i
= 0; i
< n_input_iovec
; i
++)
1041 if (memory_startswith(input_iovec
[i
].iov_base
, input_iovec
[i
].iov_len
, "MESSAGE="))
1044 if (_unlikely_(i
>= n_input_iovec
)) /* Couldn't find MESSAGE=? */
1047 m
= strndupa(input_iovec
[i
].iov_base
+ STRLEN("MESSAGE="),
1048 input_iovec
[i
].iov_len
- STRLEN("MESSAGE="));
1050 return log_dispatch_internal(level
, error
, file
, line
, func
, NULL
, NULL
, NULL
, NULL
, m
);
1053 int log_set_target_from_string(const char *e
) {
1056 t
= log_target_from_string(e
);
1064 int log_set_max_level_from_string_realm(LogRealm realm
, const char *e
) {
1067 t
= log_level_from_string(e
);
1071 log_set_max_level_realm(realm
, t
);
1075 static int parse_proc_cmdline_item(const char *key
, const char *value
, void *data
) {
1078 * The systemd.log_xyz= settings are parsed by all tools, and
1081 * However, "quiet" is only parsed by PID 1, and only turns of
1082 * status output to /dev/console, but does not alter the log
1086 if (streq(key
, "debug") && !value
)
1087 log_set_max_level(LOG_DEBUG
);
1089 else if (proc_cmdline_key_streq(key
, "systemd.log_target")) {
1091 if (proc_cmdline_value_missing(key
, value
))
1094 if (log_set_target_from_string(value
) < 0)
1095 log_warning("Failed to parse log target '%s'. Ignoring.", value
);
1097 } else if (proc_cmdline_key_streq(key
, "systemd.log_level")) {
1099 if (proc_cmdline_value_missing(key
, value
))
1102 if (log_set_max_level_from_string(value
) < 0)
1103 log_warning("Failed to parse log level '%s'. Ignoring.", value
);
1105 } else if (proc_cmdline_key_streq(key
, "systemd.log_color")) {
1107 if (log_show_color_from_string(value
?: "1") < 0)
1108 log_warning("Failed to parse log color setting '%s'. Ignoring.", value
);
1110 } else if (proc_cmdline_key_streq(key
, "systemd.log_location")) {
1112 if (log_show_location_from_string(value
?: "1") < 0)
1113 log_warning("Failed to parse log location setting '%s'. Ignoring.", value
);
1119 void log_parse_environment_realm(LogRealm realm
) {
1120 /* Do not call from library code. */
1124 if (get_ctty_devnr(0, NULL
) < 0)
1125 /* Only try to read the command line in daemons. We assume that anything that has a controlling tty is
1127 (void) proc_cmdline_parse(parse_proc_cmdline_item
, NULL
, PROC_CMDLINE_STRIP_RD_PREFIX
);
1129 e
= getenv("SYSTEMD_LOG_TARGET");
1130 if (e
&& log_set_target_from_string(e
) < 0)
1131 log_warning("Failed to parse log target '%s'. Ignoring.", e
);
1133 e
= getenv("SYSTEMD_LOG_LEVEL");
1134 if (e
&& log_set_max_level_from_string_realm(realm
, e
) < 0)
1135 log_warning("Failed to parse log level '%s'. Ignoring.", e
);
1137 e
= getenv("SYSTEMD_LOG_COLOR");
1138 if (e
&& log_show_color_from_string(e
) < 0)
1139 log_warning("Failed to parse bool '%s'. Ignoring.", e
);
1141 e
= getenv("SYSTEMD_LOG_LOCATION");
1142 if (e
&& log_show_location_from_string(e
) < 0)
1143 log_warning("Failed to parse bool '%s'. Ignoring.", e
);
1146 LogTarget
log_get_target(void) {
1150 int log_get_max_level_realm(LogRealm realm
) {
1151 return log_max_level
[realm
];
1154 void log_show_color(bool b
) {
1158 bool log_get_show_color(void) {
1162 void log_show_location(bool b
) {
1166 bool log_get_show_location(void) {
1167 return show_location
;
1170 int log_show_color_from_string(const char *e
) {
1173 t
= parse_boolean(e
);
1181 int log_show_location_from_string(const char *e
) {
1184 t
= parse_boolean(e
);
1188 log_show_location(t
);
1192 bool log_on_console(void) {
1193 if (IN_SET(log_target
, LOG_TARGET_CONSOLE
,
1194 LOG_TARGET_CONSOLE_PREFIXED
))
1197 return syslog_fd
< 0 && kmsg_fd
< 0 && journal_fd
< 0;
1200 static const char *const log_target_table
[_LOG_TARGET_MAX
] = {
1201 [LOG_TARGET_CONSOLE
] = "console",
1202 [LOG_TARGET_CONSOLE_PREFIXED
] = "console-prefixed",
1203 [LOG_TARGET_KMSG
] = "kmsg",
1204 [LOG_TARGET_JOURNAL
] = "journal",
1205 [LOG_TARGET_JOURNAL_OR_KMSG
] = "journal-or-kmsg",
1206 [LOG_TARGET_SYSLOG
] = "syslog",
1207 [LOG_TARGET_SYSLOG_OR_KMSG
] = "syslog-or-kmsg",
1208 [LOG_TARGET_AUTO
] = "auto",
1209 [LOG_TARGET_NULL
] = "null",
1212 DEFINE_STRING_TABLE_LOOKUP(log_target
, LogTarget
);
1214 void log_received_signal(int level
, const struct signalfd_siginfo
*si
) {
1217 if (pid_is_valid(si
->ssi_pid
)) {
1218 _cleanup_free_
char *p
= NULL
;
1220 (void) get_process_comm(si
->ssi_pid
, &p
);
1223 "Received SIG%s from PID %"PRIu32
" (%s).",
1224 signal_to_string(si
->ssi_signo
),
1225 si
->ssi_pid
, strna(p
));
1229 signal_to_string(si
->ssi_signo
));
1232 int log_syntax_internal(
1235 const char *config_file
,
1236 unsigned config_line
,
1241 const char *format
, ...) {
1244 char buffer
[LINE_MAX
];
1246 const char *unit_fmt
= NULL
;
1251 if (_likely_(LOG_PRI(level
) > log_max_level
[LOG_REALM_SYSTEMD
]))
1254 if (log_target
== LOG_TARGET_NULL
)
1259 va_start(ap
, format
);
1260 (void) vsnprintf(buffer
, sizeof buffer
, format
, ap
);
1264 unit_fmt
= getpid_cached() == 1 ? "UNIT=%s" : "USER_UNIT=%s";
1266 return log_struct_internal(
1267 LOG_REALM_PLUS_LEVEL(LOG_REALM_SYSTEMD
, level
),
1270 "MESSAGE_ID=" SD_MESSAGE_INVALID_CONFIGURATION_STR
,
1271 "CONFIG_FILE=%s", config_file
,
1272 "CONFIG_LINE=%u", config_line
,
1273 LOG_MESSAGE("%s:%u: %s", config_file
, config_line
, buffer
),
1278 int log_syntax_invalid_utf8_internal(
1281 const char *config_file
,
1282 unsigned config_line
,
1286 const char *rvalue
) {
1288 _cleanup_free_
char *p
= NULL
;
1291 p
= utf8_escape_invalid(rvalue
);
1293 log_syntax_internal(unit
, level
, config_file
, config_line
, 0, file
, line
, func
,
1294 "String is not UTF-8 clean, ignoring assignment: %s", strna(p
));
1299 void log_set_upgrade_syslog_to_journal(bool b
) {
1300 upgrade_syslog_to_journal
= b
;
1302 /* Make the change effective immediately */
1304 if (log_target
== LOG_TARGET_SYSLOG
)
1305 log_target
= LOG_TARGET_JOURNAL
;
1306 else if (log_target
== LOG_TARGET_SYSLOG_OR_KMSG
)
1307 log_target
= LOG_TARGET_JOURNAL_OR_KMSG
;
1311 void log_set_always_reopen_console(bool b
) {
1312 always_reopen_console
= b
;
1315 void log_set_open_when_needed(bool b
) {
1316 open_when_needed
= b
;
1319 void log_set_prohibit_ipc(bool b
) {
1323 int log_emergency_level(void) {
1324 /* Returns the log level to use for log_emergency() logging. We use LOG_EMERG only when we are PID 1, as only
1325 * then the system of the whole system is obviously affected. */
1327 return getpid_cached() == 1 ? LOG_EMERG
: LOG_ERR
;
1330 int log_dup_console(void) {
1333 /* Duplicate the fd we use for fd logging if it's < 3 and use the copy from now on. This call is useful
1334 * whenever we want to continue logging through the original fd, but want to rearrange stderr. */
1336 if (console_fd
>= 3)
1339 copy
= fcntl(console_fd
, F_DUPFD_CLOEXEC
, 3);