1 /* SPDX-License-Identifier: LGPL-2.1+ */
9 #include <sys/signalfd.h>
15 #include "sd-messages.h"
17 #include "alloc-util.h"
18 #include "errno-util.h"
20 #include "format-util.h"
24 #include "parse-util.h"
25 #include "proc-cmdline.h"
26 #include "process-util.h"
27 #include "ratelimit.h"
28 #include "signal-util.h"
29 #include "socket-util.h"
30 #include "stdio-util.h"
31 #include "string-table.h"
32 #include "string-util.h"
33 #include "syslog-util.h"
34 #include "terminal-util.h"
35 #include "time-util.h"
38 #define SNDBUF_SIZE (8*1024*1024)
40 static LogTarget log_target
= LOG_TARGET_CONSOLE
;
41 static int log_max_level
[] = {LOG_INFO
, LOG_INFO
};
42 assert_cc(ELEMENTSOF(log_max_level
) == _LOG_REALM_MAX
);
43 static int log_facility
= LOG_DAEMON
;
45 static int console_fd
= STDERR_FILENO
;
46 static int syslog_fd
= -1;
47 static int kmsg_fd
= -1;
48 static int journal_fd
= -1;
50 static bool syslog_is_stream
= false;
52 static bool show_color
= false;
53 static bool show_location
= false;
54 static bool show_time
= false;
56 static bool upgrade_syslog_to_journal
= false;
57 static bool always_reopen_console
= false;
58 static bool open_when_needed
= false;
59 static bool prohibit_ipc
= false;
61 /* Akin to glibc's __abort_msg; which is private and we hence cannot
63 static char *log_abort_msg
= NULL
;
65 /* An assert to use in logging functions that does not call recursively
66 * into our logging functions (since that might lead to a loop). */
67 #define assert_raw(expr) \
69 if (_unlikely_(!(expr))) { \
70 fputs(#expr "\n", stderr); \
75 static void log_close_console(void) {
76 console_fd
= safe_close_above_stdio(console_fd
);
79 static int log_open_console(void) {
81 if (!always_reopen_console
) {
82 console_fd
= STDERR_FILENO
;
89 fd
= open_terminal("/dev/console", O_WRONLY
|O_NOCTTY
|O_CLOEXEC
);
93 console_fd
= fd_move_above_stdio(fd
);
99 static void log_close_kmsg(void) {
100 kmsg_fd
= safe_close(kmsg_fd
);
103 static int log_open_kmsg(void) {
108 kmsg_fd
= open("/dev/kmsg", O_WRONLY
|O_NOCTTY
|O_CLOEXEC
);
112 kmsg_fd
= fd_move_above_stdio(kmsg_fd
);
116 static void log_close_syslog(void) {
117 syslog_fd
= safe_close(syslog_fd
);
120 static int create_log_socket(int type
) {
124 fd
= socket(AF_UNIX
, type
|SOCK_CLOEXEC
, 0);
128 fd
= fd_move_above_stdio(fd
);
129 (void) fd_inc_sndbuf(fd
, SNDBUF_SIZE
);
131 /* We need a blocking fd here since we'd otherwise lose messages way too early. However, let's not hang forever
132 * in the unlikely case of a deadlock. */
133 if (getpid_cached() == 1)
134 timeval_store(&tv
, 10 * USEC_PER_MSEC
);
136 timeval_store(&tv
, 10 * USEC_PER_SEC
);
137 (void) setsockopt(fd
, SOL_SOCKET
, SO_SNDTIMEO
, &tv
, sizeof(tv
));
142 static int log_open_syslog(void) {
144 static const union sockaddr_union sa
= {
145 .un
.sun_family
= AF_UNIX
,
146 .un
.sun_path
= "/dev/log",
154 syslog_fd
= create_log_socket(SOCK_DGRAM
);
160 if (connect(syslog_fd
, &sa
.sa
, SOCKADDR_UN_LEN(sa
.un
)) < 0) {
161 safe_close(syslog_fd
);
163 /* Some legacy syslog systems still use stream
164 * sockets. They really shouldn't. But what can we
166 syslog_fd
= create_log_socket(SOCK_STREAM
);
172 if (connect(syslog_fd
, &sa
.sa
, SOCKADDR_UN_LEN(sa
.un
)) < 0) {
177 syslog_is_stream
= true;
179 syslog_is_stream
= false;
188 static void log_close_journal(void) {
189 journal_fd
= safe_close(journal_fd
);
192 static int log_open_journal(void) {
194 static const union sockaddr_union sa
= {
195 .un
.sun_family
= AF_UNIX
,
196 .un
.sun_path
= "/run/systemd/journal/socket",
204 journal_fd
= create_log_socket(SOCK_DGRAM
);
205 if (journal_fd
< 0) {
210 if (connect(journal_fd
, &sa
.sa
, SOCKADDR_UN_LEN(sa
.un
)) < 0) {
225 /* Do not call from library code. */
227 /* If we don't use the console we close it here, to not get
228 * killed by SAK. If we don't use syslog we close it here so
229 * that we are not confused by somebody deleting the socket in
230 * the fs, and to make sure we don't use it if prohibit_ipc is
231 * set. If we don't use /dev/kmsg we still keep it open,
232 * because there is no reason to close it. */
234 if (log_target
== LOG_TARGET_NULL
) {
241 if (log_target
!= LOG_TARGET_AUTO
||
242 getpid_cached() == 1 ||
243 isatty(STDERR_FILENO
) <= 0) {
246 IN_SET(log_target
, LOG_TARGET_AUTO
,
247 LOG_TARGET_JOURNAL_OR_KMSG
,
248 LOG_TARGET_JOURNAL
)) {
249 r
= log_open_journal();
258 IN_SET(log_target
, LOG_TARGET_SYSLOG_OR_KMSG
,
259 LOG_TARGET_SYSLOG
)) {
260 r
= log_open_syslog();
268 if (IN_SET(log_target
, LOG_TARGET_AUTO
,
269 LOG_TARGET_JOURNAL_OR_KMSG
,
270 LOG_TARGET_SYSLOG_OR_KMSG
,
285 return log_open_console();
288 void log_set_target(LogTarget target
) {
290 assert(target
< _LOG_TARGET_MAX
);
292 if (upgrade_syslog_to_journal
) {
293 if (target
== LOG_TARGET_SYSLOG
)
294 target
= LOG_TARGET_JOURNAL
;
295 else if (target
== LOG_TARGET_SYSLOG_OR_KMSG
)
296 target
= LOG_TARGET_JOURNAL_OR_KMSG
;
302 void log_close(void) {
303 /* Do not call from library code. */
311 void log_forget_fds(void) {
312 /* Do not call from library code. */
314 console_fd
= kmsg_fd
= syslog_fd
= journal_fd
= -1;
317 void log_set_max_level_realm(LogRealm realm
, int level
) {
318 assert((level
& LOG_PRIMASK
) == level
);
319 assert(realm
< ELEMENTSOF(log_max_level
));
321 log_max_level
[realm
] = level
;
324 void log_set_facility(int facility
) {
325 log_facility
= facility
;
328 static int write_to_console(
334 const char *buffer
) {
337 header_time
[FORMAT_TIMESTAMP_MAX
],
338 prefix
[1 + DECIMAL_STR_MAX(int) + 2];
339 struct iovec iovec
[8] = {};
340 const char *on
= NULL
, *off
= NULL
;
346 if (log_target
== LOG_TARGET_CONSOLE_PREFIXED
) {
347 xsprintf(prefix
, "<%i>", level
);
348 iovec
[n
++] = IOVEC_MAKE_STRING(prefix
);
352 if (format_timestamp(header_time
, sizeof(header_time
), now(CLOCK_REALTIME
))) {
353 iovec
[n
++] = IOVEC_MAKE_STRING(header_time
);
354 iovec
[n
++] = IOVEC_MAKE_STRING(" ");
359 get_log_colors(LOG_PRI(level
), &on
, &off
, NULL
);
362 const char *lon
= "", *loff
= "";
364 lon
= ANSI_HIGHLIGHT_YELLOW4
;
368 (void) snprintf(location
, sizeof location
, "%s%s:%i%s: ", lon
, file
, line
, loff
);
369 iovec
[n
++] = IOVEC_MAKE_STRING(location
);
373 iovec
[n
++] = IOVEC_MAKE_STRING(on
);
374 iovec
[n
++] = IOVEC_MAKE_STRING(buffer
);
376 iovec
[n
++] = IOVEC_MAKE_STRING(off
);
377 iovec
[n
++] = IOVEC_MAKE_STRING("\n");
379 if (writev(console_fd
, iovec
, n
) < 0) {
381 if (errno
== EIO
&& getpid_cached() == 1) {
383 /* If somebody tried to kick us from our console tty (via vhangup() or suchlike), try
387 (void) log_open_console();
391 if (writev(console_fd
, iovec
, n
) < 0)
400 static int write_to_syslog(
406 const char *buffer
) {
408 char header_priority
[2 + DECIMAL_STR_MAX(int) + 1],
410 header_pid
[4 + DECIMAL_STR_MAX(pid_t
) + 1];
411 struct iovec iovec
[5] = {};
412 struct msghdr msghdr
= {
414 .msg_iovlen
= ELEMENTSOF(iovec
),
422 xsprintf(header_priority
, "<%i>", level
);
424 t
= (time_t) (now(CLOCK_REALTIME
) / USEC_PER_SEC
);
425 if (!localtime_r(&t
, &tm
))
428 if (strftime(header_time
, sizeof(header_time
), "%h %e %T ", &tm
) <= 0)
431 xsprintf(header_pid
, "["PID_FMT
"]: ", getpid_cached());
433 iovec
[0] = IOVEC_MAKE_STRING(header_priority
);
434 iovec
[1] = IOVEC_MAKE_STRING(header_time
);
435 iovec
[2] = IOVEC_MAKE_STRING(program_invocation_short_name
);
436 iovec
[3] = IOVEC_MAKE_STRING(header_pid
);
437 iovec
[4] = IOVEC_MAKE_STRING(buffer
);
439 /* When using syslog via SOCK_STREAM separate the messages by NUL chars */
440 if (syslog_is_stream
)
446 n
= sendmsg(syslog_fd
, &msghdr
, MSG_NOSIGNAL
);
450 if (!syslog_is_stream
||
451 (size_t) n
>= IOVEC_TOTAL_SIZE(iovec
, ELEMENTSOF(iovec
)))
454 IOVEC_INCREMENT(iovec
, ELEMENTSOF(iovec
), n
);
460 static int write_to_kmsg(
466 const char *buffer
) {
468 /* Set a ratelimit on the amount of messages logged to /dev/kmsg. This is mostly supposed to be a
469 * safety catch for the case where start indiscriminately logging in a loop. It will not catch cases
470 * where we log excessively, but not in a tight loop.
472 * Note that this ratelimit is per-emitter, so we might still overwhelm /dev/kmsg with multiple
475 static thread_local RateLimit ratelimit
= { 5 * USEC_PER_SEC
, 200 };
477 char header_priority
[2 + DECIMAL_STR_MAX(int) + 1],
478 header_pid
[4 + DECIMAL_STR_MAX(pid_t
) + 1];
479 struct iovec iovec
[5] = {};
484 if (!ratelimit_below(&ratelimit
))
487 xsprintf(header_priority
, "<%i>", level
);
488 xsprintf(header_pid
, "["PID_FMT
"]: ", getpid_cached());
490 iovec
[0] = IOVEC_MAKE_STRING(header_priority
);
491 iovec
[1] = IOVEC_MAKE_STRING(program_invocation_short_name
);
492 iovec
[2] = IOVEC_MAKE_STRING(header_pid
);
493 iovec
[3] = IOVEC_MAKE_STRING(buffer
);
494 iovec
[4] = IOVEC_MAKE_STRING("\n");
496 if (writev(kmsg_fd
, iovec
, ELEMENTSOF(iovec
)) < 0)
502 static int log_do_header(
507 const char *file
, int line
, const char *func
,
508 const char *object_field
, const char *object
,
509 const char *extra_field
, const char *extra
) {
512 error
= IS_SYNTHETIC_ERRNO(error
) ? 0 : ERRNO_VALUE(error
);
514 r
= snprintf(header
, size
,
516 "SYSLOG_FACILITY=%i\n"
517 "%s%.256s%s" /* CODE_FILE */
518 "%s%.*i%s" /* CODE_LINE */
519 "%s%.256s%s" /* CODE_FUNC */
520 "%s%.*i%s" /* ERRNO */
521 "%s%.256s%s" /* object */
522 "%s%.256s%s" /* extra */
523 "SYSLOG_IDENTIFIER=%.256s\n",
526 isempty(file
) ? "" : "CODE_FILE=",
527 isempty(file
) ? "" : file
,
528 isempty(file
) ? "" : "\n",
529 line
? "CODE_LINE=" : "",
530 line
? 1 : 0, line
, /* %.0d means no output too, special case for 0 */
532 isempty(func
) ? "" : "CODE_FUNC=",
533 isempty(func
) ? "" : func
,
534 isempty(func
) ? "" : "\n",
535 error
? "ERRNO=" : "",
536 error
? 1 : 0, error
,
538 isempty(object
) ? "" : object_field
,
539 isempty(object
) ? "" : object
,
540 isempty(object
) ? "" : "\n",
541 isempty(extra
) ? "" : extra_field
,
542 isempty(extra
) ? "" : extra
,
543 isempty(extra
) ? "" : "\n",
544 program_invocation_short_name
);
545 assert_raw((size_t) r
< size
);
550 static int write_to_journal(
556 const char *object_field
,
558 const char *extra_field
,
560 const char *buffer
) {
562 char header
[LINE_MAX
];
563 struct iovec iovec
[4] = {};
564 struct msghdr mh
= {};
569 log_do_header(header
, sizeof(header
), level
, error
, file
, line
, func
, object_field
, object
, extra_field
, extra
);
571 iovec
[0] = IOVEC_MAKE_STRING(header
);
572 iovec
[1] = IOVEC_MAKE_STRING("MESSAGE=");
573 iovec
[2] = IOVEC_MAKE_STRING(buffer
);
574 iovec
[3] = IOVEC_MAKE_STRING("\n");
577 mh
.msg_iovlen
= ELEMENTSOF(iovec
);
579 if (sendmsg(journal_fd
, &mh
, MSG_NOSIGNAL
) < 0)
585 int log_dispatch_internal(
591 const char *object_field
,
593 const char *extra_field
,
599 if (log_target
== LOG_TARGET_NULL
)
600 return -ERRNO_VALUE(error
);
602 /* Patch in LOG_DAEMON facility if necessary */
603 if ((level
& LOG_FACMASK
) == 0)
604 level
|= log_facility
;
606 if (open_when_needed
)
613 buffer
+= strspn(buffer
, NEWLINE
);
618 if ((e
= strpbrk(buffer
, NEWLINE
)))
621 if (IN_SET(log_target
, LOG_TARGET_AUTO
,
622 LOG_TARGET_JOURNAL_OR_KMSG
,
623 LOG_TARGET_JOURNAL
)) {
625 k
= write_to_journal(level
, error
, file
, line
, func
, object_field
, object
, extra_field
, extra
, buffer
);
626 if (k
< 0 && k
!= -EAGAIN
)
630 if (IN_SET(log_target
, LOG_TARGET_SYSLOG_OR_KMSG
,
631 LOG_TARGET_SYSLOG
)) {
633 k
= write_to_syslog(level
, error
, file
, line
, func
, buffer
);
634 if (k
< 0 && k
!= -EAGAIN
)
639 IN_SET(log_target
, LOG_TARGET_AUTO
,
640 LOG_TARGET_SYSLOG_OR_KMSG
,
641 LOG_TARGET_JOURNAL_OR_KMSG
,
647 k
= write_to_kmsg(level
, error
, file
, line
, func
, buffer
);
650 (void) log_open_console();
655 (void) write_to_console(level
, error
, file
, line
, func
, buffer
);
660 if (open_when_needed
)
663 return -ERRNO_VALUE(error
);
666 int log_dump_internal(
674 LogRealm realm
= LOG_REALM_REMOVE_LEVEL(level
);
677 /* This modifies the buffer... */
679 if (_likely_(LOG_PRI(level
) > log_max_level
[realm
]))
680 return -ERRNO_VALUE(error
);
682 return log_dispatch_internal(level
, error
, file
, line
, func
, NULL
, NULL
, NULL
, NULL
, buffer
);
685 int log_internalv_realm(
694 LogRealm realm
= LOG_REALM_REMOVE_LEVEL(level
);
695 char buffer
[LINE_MAX
];
698 if (_likely_(LOG_PRI(level
) > log_max_level
[realm
]))
699 return -ERRNO_VALUE(error
);
701 /* Make sure that %m maps to the specified error (or "Success"). */
702 errno
= ERRNO_VALUE(error
);
704 (void) vsnprintf(buffer
, sizeof buffer
, format
, ap
);
706 return log_dispatch_internal(level
, error
, file
, line
, func
, NULL
, NULL
, NULL
, NULL
, buffer
);
709 int log_internal_realm(
715 const char *format
, ...) {
720 va_start(ap
, format
);
721 r
= log_internalv_realm(level
, error
, file
, line
, func
, format
, ap
);
727 int log_object_internalv(
733 const char *object_field
,
735 const char *extra_field
,
743 if (_likely_(LOG_PRI(level
) > log_max_level
[LOG_REALM_SYSTEMD
]))
744 return -ERRNO_VALUE(error
);
746 /* Make sure that %m maps to the specified error (or "Success"). */
747 errno
= ERRNO_VALUE(error
);
749 /* Prepend the object name before the message */
754 buffer
= newa(char, n
+ 2 + LINE_MAX
);
755 b
= stpcpy(stpcpy(buffer
, object
), ": ");
757 b
= buffer
= newa(char, LINE_MAX
);
759 (void) vsnprintf(b
, LINE_MAX
, format
, ap
);
761 return log_dispatch_internal(level
, error
, file
, line
, func
,
762 object_field
, object
, extra_field
, extra
, buffer
);
765 int log_object_internal(
771 const char *object_field
,
773 const char *extra_field
,
775 const char *format
, ...) {
780 va_start(ap
, format
);
781 r
= log_object_internalv(level
, error
, file
, line
, func
, object_field
, object
, extra_field
, extra
, format
, ap
);
787 static void log_assert(
793 const char *format
) {
795 static char buffer
[LINE_MAX
];
796 LogRealm realm
= LOG_REALM_REMOVE_LEVEL(level
);
798 if (_likely_(LOG_PRI(level
) > log_max_level
[realm
]))
801 DISABLE_WARNING_FORMAT_NONLITERAL
;
802 (void) snprintf(buffer
, sizeof buffer
, format
, text
, file
, line
, func
);
805 log_abort_msg
= buffer
;
807 log_dispatch_internal(level
, 0, file
, line
, func
, NULL
, NULL
, NULL
, NULL
, buffer
);
810 _noreturn_
void log_assert_failed_realm(
817 log_assert(LOG_REALM_PLUS_LEVEL(realm
, LOG_CRIT
), text
, file
, line
, func
,
818 "Assertion '%s' failed at %s:%u, function %s(). Aborting.");
822 _noreturn_
void log_assert_failed_unreachable_realm(
829 log_assert(LOG_REALM_PLUS_LEVEL(realm
, LOG_CRIT
), text
, file
, line
, func
,
830 "Code should not be reached '%s' at %s:%u, function %s(). Aborting.");
834 void log_assert_failed_return_realm(
841 log_assert(LOG_REALM_PLUS_LEVEL(realm
, LOG_DEBUG
), text
, file
, line
, func
,
842 "Assertion '%s' failed at %s:%u, function %s(). Ignoring.");
845 int log_oom_internal(LogRealm realm
, const char *file
, int line
, const char *func
) {
846 return log_internal_realm(LOG_REALM_PLUS_LEVEL(realm
, LOG_ERR
),
847 ENOMEM
, file
, line
, func
, "Out of memory.");
850 int log_format_iovec(
854 bool newline_separator
,
859 static const char nl
= '\n';
861 while (format
&& *n
+ 1 < iovec_len
) {
866 /* We need to copy the va_list structure,
867 * since vasprintf() leaves it afterwards at
868 * an undefined location */
870 errno
= ERRNO_VALUE(error
);
873 r
= vasprintf(&m
, format
, aq
);
878 /* Now, jump enough ahead, so that we point to
879 * the next format string */
880 VA_FORMAT_ADVANCE(format
, ap
);
882 iovec
[(*n
)++] = IOVEC_MAKE_STRING(m
);
884 if (newline_separator
) {
885 iovec
[*n
] = IOVEC_MAKE((char *)&nl
, 1);
889 format
= va_arg(ap
, char *);
894 int log_struct_internal(
900 const char *format
, ...) {
902 LogRealm realm
= LOG_REALM_REMOVE_LEVEL(level
);
908 if (_likely_(LOG_PRI(level
) > log_max_level
[realm
]) ||
909 log_target
== LOG_TARGET_NULL
)
910 return -ERRNO_VALUE(error
);
912 if ((level
& LOG_FACMASK
) == 0)
913 level
|= log_facility
;
915 if (IN_SET(log_target
,
917 LOG_TARGET_JOURNAL_OR_KMSG
,
918 LOG_TARGET_JOURNAL
)) {
920 if (open_when_needed
)
923 if (journal_fd
>= 0) {
924 char header
[LINE_MAX
];
925 struct iovec iovec
[17] = {};
931 bool fallback
= false;
933 /* If the journal is available do structured logging.
934 * Do not report the errno if it is synthetic. */
935 log_do_header(header
, sizeof(header
), level
, error
, file
, line
, func
, NULL
, NULL
, NULL
, NULL
);
936 iovec
[n
++] = IOVEC_MAKE_STRING(header
);
938 va_start(ap
, format
);
939 r
= log_format_iovec(iovec
, ELEMENTSOF(iovec
), &n
, true, error
, format
, ap
);
944 (void) sendmsg(journal_fd
, &mh
, MSG_NOSIGNAL
);
948 for (i
= 1; i
< n
; i
+= 2)
949 free(iovec
[i
].iov_base
);
952 if (open_when_needed
)
955 return -ERRNO_VALUE(error
);
960 /* Fallback if journal logging is not available or didn't work. */
962 va_start(ap
, format
);
966 errno
= ERRNO_VALUE(error
);
969 (void) vsnprintf(buf
, sizeof buf
, format
, aq
);
972 if (startswith(buf
, "MESSAGE=")) {
977 VA_FORMAT_ADVANCE(format
, ap
);
979 format
= va_arg(ap
, char *);
984 if (open_when_needed
)
987 return -ERRNO_VALUE(error
);
990 return log_dispatch_internal(level
, error
, file
, line
, func
, NULL
, NULL
, NULL
, NULL
, buf
+ 8);
993 int log_struct_iovec_internal(
999 const struct iovec input_iovec
[],
1000 size_t n_input_iovec
) {
1002 LogRealm realm
= LOG_REALM_REMOVE_LEVEL(level
);
1007 if (_likely_(LOG_PRI(level
) > log_max_level
[realm
]) ||
1008 log_target
== LOG_TARGET_NULL
)
1009 return -ERRNO_VALUE(error
);
1011 if ((level
& LOG_FACMASK
) == 0)
1012 level
|= log_facility
;
1014 if (IN_SET(log_target
, LOG_TARGET_AUTO
,
1015 LOG_TARGET_JOURNAL_OR_KMSG
,
1016 LOG_TARGET_JOURNAL
) &&
1019 struct iovec iovec
[1 + n_input_iovec
*2];
1020 char header
[LINE_MAX
];
1021 struct msghdr mh
= {
1023 .msg_iovlen
= 1 + n_input_iovec
*2,
1026 log_do_header(header
, sizeof(header
), level
, error
, file
, line
, func
, NULL
, NULL
, NULL
, NULL
);
1027 iovec
[0] = IOVEC_MAKE_STRING(header
);
1029 for (i
= 0; i
< n_input_iovec
; i
++) {
1030 iovec
[1+i
*2] = input_iovec
[i
];
1031 iovec
[1+i
*2+1] = IOVEC_MAKE_STRING("\n");
1034 if (sendmsg(journal_fd
, &mh
, MSG_NOSIGNAL
) >= 0)
1035 return -ERRNO_VALUE(error
);
1038 for (i
= 0; i
< n_input_iovec
; i
++)
1039 if (memory_startswith(input_iovec
[i
].iov_base
, input_iovec
[i
].iov_len
, "MESSAGE="))
1042 if (_unlikely_(i
>= n_input_iovec
)) /* Couldn't find MESSAGE=? */
1043 return -ERRNO_VALUE(error
);
1045 m
= strndupa(input_iovec
[i
].iov_base
+ STRLEN("MESSAGE="),
1046 input_iovec
[i
].iov_len
- STRLEN("MESSAGE="));
1048 return log_dispatch_internal(level
, error
, file
, line
, func
, NULL
, NULL
, NULL
, NULL
, m
);
1051 int log_set_target_from_string(const char *e
) {
1054 t
= log_target_from_string(e
);
1062 int log_set_max_level_from_string_realm(LogRealm realm
, const char *e
) {
1065 t
= log_level_from_string(e
);
1069 log_set_max_level_realm(realm
, t
);
1073 static int parse_proc_cmdline_item(const char *key
, const char *value
, void *data
) {
1076 * The systemd.log_xyz= settings are parsed by all tools, and
1079 * However, "quiet" is only parsed by PID 1, and only turns of
1080 * status output to /dev/console, but does not alter the log
1084 if (streq(key
, "debug") && !value
)
1085 log_set_max_level(LOG_DEBUG
);
1087 else if (proc_cmdline_key_streq(key
, "systemd.log_target")) {
1089 if (proc_cmdline_value_missing(key
, value
))
1092 if (log_set_target_from_string(value
) < 0)
1093 log_warning("Failed to parse log target '%s'. Ignoring.", value
);
1095 } else if (proc_cmdline_key_streq(key
, "systemd.log_level")) {
1097 if (proc_cmdline_value_missing(key
, value
))
1100 if (log_set_max_level_from_string(value
) < 0)
1101 log_warning("Failed to parse log level '%s'. Ignoring.", value
);
1103 } else if (proc_cmdline_key_streq(key
, "systemd.log_color")) {
1105 if (log_show_color_from_string(value
?: "1") < 0)
1106 log_warning("Failed to parse log color setting '%s'. Ignoring.", value
);
1108 } else if (proc_cmdline_key_streq(key
, "systemd.log_location")) {
1110 if (log_show_location_from_string(value
?: "1") < 0)
1111 log_warning("Failed to parse log location setting '%s'. Ignoring.", value
);
1113 } else if (proc_cmdline_key_streq(key
, "systemd.log_time")) {
1115 if (log_show_time_from_string(value
?: "1") < 0)
1116 log_warning("Failed to parse log time setting '%s'. Ignoring.", value
);
1123 void log_parse_environment_realm(LogRealm realm
) {
1124 /* Do not call from library code. */
1128 if (getpid_cached() == 1 || get_ctty_devnr(0, NULL
) < 0)
1129 /* Only try to read the command line in daemons. We assume that anything that has a
1130 * controlling tty is user stuff. For PID1 we do a special check in case it hasn't
1131 * closed the console yet. */
1132 (void) proc_cmdline_parse(parse_proc_cmdline_item
, NULL
, PROC_CMDLINE_STRIP_RD_PREFIX
);
1134 e
= getenv("SYSTEMD_LOG_TARGET");
1135 if (e
&& log_set_target_from_string(e
) < 0)
1136 log_warning("Failed to parse log target '%s'. Ignoring.", e
);
1138 e
= getenv("SYSTEMD_LOG_LEVEL");
1139 if (e
&& log_set_max_level_from_string_realm(realm
, e
) < 0)
1140 log_warning("Failed to parse log level '%s'. Ignoring.", e
);
1142 e
= getenv("SYSTEMD_LOG_COLOR");
1143 if (e
&& log_show_color_from_string(e
) < 0)
1144 log_warning("Failed to parse log color '%s'. Ignoring.", e
);
1146 e
= getenv("SYSTEMD_LOG_LOCATION");
1147 if (e
&& log_show_location_from_string(e
) < 0)
1148 log_warning("Failed to parse log location '%s'. Ignoring.", e
);
1150 e
= getenv("SYSTEMD_LOG_TIME");
1151 if (e
&& log_show_time_from_string(e
) < 0)
1152 log_warning("Failed to parse log time '%s'. Ignoring.", e
);
1155 LogTarget
log_get_target(void) {
1159 int log_get_max_level_realm(LogRealm realm
) {
1160 return log_max_level
[realm
];
1163 void log_show_color(bool b
) {
1167 bool log_get_show_color(void) {
1171 void log_show_location(bool b
) {
1175 bool log_get_show_location(void) {
1176 return show_location
;
1179 void log_show_time(bool b
) {
1183 bool log_get_show_time(void) {
1187 int log_show_color_from_string(const char *e
) {
1190 t
= parse_boolean(e
);
1198 int log_show_location_from_string(const char *e
) {
1201 t
= parse_boolean(e
);
1205 log_show_location(t
);
1209 int log_show_time_from_string(const char *e
) {
1212 t
= parse_boolean(e
);
1220 bool log_on_console(void) {
1221 if (IN_SET(log_target
, LOG_TARGET_CONSOLE
,
1222 LOG_TARGET_CONSOLE_PREFIXED
))
1225 return syslog_fd
< 0 && kmsg_fd
< 0 && journal_fd
< 0;
1228 static const char *const log_target_table
[_LOG_TARGET_MAX
] = {
1229 [LOG_TARGET_CONSOLE
] = "console",
1230 [LOG_TARGET_CONSOLE_PREFIXED
] = "console-prefixed",
1231 [LOG_TARGET_KMSG
] = "kmsg",
1232 [LOG_TARGET_JOURNAL
] = "journal",
1233 [LOG_TARGET_JOURNAL_OR_KMSG
] = "journal-or-kmsg",
1234 [LOG_TARGET_SYSLOG
] = "syslog",
1235 [LOG_TARGET_SYSLOG_OR_KMSG
] = "syslog-or-kmsg",
1236 [LOG_TARGET_AUTO
] = "auto",
1237 [LOG_TARGET_NULL
] = "null",
1240 DEFINE_STRING_TABLE_LOOKUP(log_target
, LogTarget
);
1242 void log_received_signal(int level
, const struct signalfd_siginfo
*si
) {
1245 if (pid_is_valid(si
->ssi_pid
)) {
1246 _cleanup_free_
char *p
= NULL
;
1248 (void) get_process_comm(si
->ssi_pid
, &p
);
1251 "Received SIG%s from PID %"PRIu32
" (%s).",
1252 signal_to_string(si
->ssi_signo
),
1253 si
->ssi_pid
, strna(p
));
1257 signal_to_string(si
->ssi_signo
));
1260 int log_syntax_internal(
1263 const char *config_file
,
1264 unsigned config_line
,
1269 const char *format
, ...) {
1272 char buffer
[LINE_MAX
];
1274 const char *unit_fmt
= NULL
;
1276 if (_likely_(LOG_PRI(level
) > log_max_level
[LOG_REALM_SYSTEMD
]) ||
1277 log_target
== LOG_TARGET_NULL
)
1278 return -ERRNO_VALUE(error
);
1280 errno
= ERRNO_VALUE(error
);
1282 va_start(ap
, format
);
1283 (void) vsnprintf(buffer
, sizeof buffer
, format
, ap
);
1287 unit_fmt
= getpid_cached() == 1 ? "UNIT=%s" : "USER_UNIT=%s";
1290 if (config_line
> 0)
1291 return log_struct_internal(
1292 LOG_REALM_PLUS_LEVEL(LOG_REALM_SYSTEMD
, level
),
1295 "MESSAGE_ID=" SD_MESSAGE_INVALID_CONFIGURATION_STR
,
1296 "CONFIG_FILE=%s", config_file
,
1297 "CONFIG_LINE=%u", config_line
,
1298 LOG_MESSAGE("%s:%u: %s", config_file
, config_line
, buffer
),
1302 return log_struct_internal(
1303 LOG_REALM_PLUS_LEVEL(LOG_REALM_SYSTEMD
, level
),
1306 "MESSAGE_ID=" SD_MESSAGE_INVALID_CONFIGURATION_STR
,
1307 "CONFIG_FILE=%s", config_file
,
1308 LOG_MESSAGE("%s: %s", config_file
, buffer
),
1312 return log_struct_internal(
1313 LOG_REALM_PLUS_LEVEL(LOG_REALM_SYSTEMD
, level
),
1316 "MESSAGE_ID=" SD_MESSAGE_INVALID_CONFIGURATION_STR
,
1317 LOG_MESSAGE("%s: %s", unit
, buffer
),
1321 return log_struct_internal(
1322 LOG_REALM_PLUS_LEVEL(LOG_REALM_SYSTEMD
, level
),
1325 "MESSAGE_ID=" SD_MESSAGE_INVALID_CONFIGURATION_STR
,
1326 LOG_MESSAGE("%s", buffer
),
1330 int log_syntax_invalid_utf8_internal(
1333 const char *config_file
,
1334 unsigned config_line
,
1338 const char *rvalue
) {
1340 _cleanup_free_
char *p
= NULL
;
1343 p
= utf8_escape_invalid(rvalue
);
1345 log_syntax_internal(unit
, level
, config_file
, config_line
, 0, file
, line
, func
,
1346 "String is not UTF-8 clean, ignoring assignment: %s", strna(p
));
1351 void log_set_upgrade_syslog_to_journal(bool b
) {
1352 upgrade_syslog_to_journal
= b
;
1354 /* Make the change effective immediately */
1356 if (log_target
== LOG_TARGET_SYSLOG
)
1357 log_target
= LOG_TARGET_JOURNAL
;
1358 else if (log_target
== LOG_TARGET_SYSLOG_OR_KMSG
)
1359 log_target
= LOG_TARGET_JOURNAL_OR_KMSG
;
1363 void log_set_always_reopen_console(bool b
) {
1364 always_reopen_console
= b
;
1367 void log_set_open_when_needed(bool b
) {
1368 open_when_needed
= b
;
1371 void log_set_prohibit_ipc(bool b
) {
1375 int log_emergency_level(void) {
1376 /* Returns the log level to use for log_emergency() logging. We use LOG_EMERG only when we are PID 1, as only
1377 * then the system of the whole system is obviously affected. */
1379 return getpid_cached() == 1 ? LOG_EMERG
: LOG_ERR
;
1382 int log_dup_console(void) {
1385 /* Duplicate the fd we use for fd logging if it's < 3 and use the copy from now on. This call is useful
1386 * whenever we want to continue logging through the original fd, but want to rearrange stderr. */
1388 if (console_fd
>= 3)
1391 copy
= fcntl(console_fd
, F_DUPFD_CLOEXEC
, 3);
1399 void log_setup_service(void) {
1400 /* Sets up logging the way it is most appropriate for running a program as a service. Note that using this
1401 * doesn't make the binary unsuitable for invocation on the command line, as log output will still go to the
1402 * terminal if invoked interactively. */
1404 log_set_target(LOG_TARGET_AUTO
);
1405 log_parse_environment();