diff --git a/src/activate/activate.c b/src/activate/activate.c index ea141c54bd..4a63970326 100644 --- a/src/activate/activate.c +++ b/src/activate/activate.c @@ -81,6 +81,7 @@ static int open_sockets(int *ret_epoll_fd, bool accept) { log_close(); log_set_open_when_needed(true); + log_settle_target(); r = close_all_fds(except, n); if (r < 0) diff --git a/src/basic/log.c b/src/basic/log.c index 8b973f9e0a..21c6f2a685 100644 --- a/src/basic/log.c +++ b/src/basic/log.c @@ -1264,6 +1264,24 @@ LogTarget log_get_target(void) { return log_target; } +void log_settle_target(void) { + + /* If we're using LOG_TARGET_AUTO and opening the log again on every single log call, we'll check if + * stderr is attached to the journal every single log call. However, if we then close all file + * descriptors later, that will stop working because stderr will be closed as well. To avoid that + * problem, this function is used to permanently change the log target depending on whether stderr is + * connected to the journal or not. */ + + LogTarget t = log_get_target(); + + if (t != LOG_TARGET_AUTO) + return; + + t = getpid_cached() == 1 || stderr_is_journal() ? (prohibit_ipc ? LOG_TARGET_KMSG : LOG_TARGET_JOURNAL_OR_KMSG) + : LOG_TARGET_CONSOLE; + log_set_target(t); +} + int log_get_max_level(void) { return log_max_level; } diff --git a/src/basic/log.h b/src/basic/log.h index c4ac73e27b..226402522c 100644 --- a/src/basic/log.h +++ b/src/basic/log.h @@ -54,6 +54,7 @@ void log_set_target(LogTarget target); void log_set_target_and_open(LogTarget target); int log_set_target_from_string(const char *e); LogTarget log_get_target(void) _pure_; +void log_settle_target(void); void log_set_max_level(int level); int log_set_max_level_from_string(const char *e); diff --git a/src/basic/process-util.c b/src/basic/process-util.c index 5d499a57b4..2fc2f92450 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -1223,6 +1223,7 @@ int safe_fork_full( /* Close the logs if requested, before we log anything. And make sure we reopen it if needed. */ log_close(); log_set_open_when_needed(true); + log_settle_target(); } if (name) { diff --git a/src/core/execute.c b/src/core/execute.c index 3f85b5f3cd..1532833c31 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -4488,6 +4488,7 @@ static int exec_child( log_forget_fds(); log_set_open_when_needed(true); + log_settle_target(); /* In case anything used libc syslog(), close this here, too */ closelog(); diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 056fad005d..f872b2e8f6 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -3551,6 +3551,7 @@ static int inner_child( * it again. Note that the other fds closed here are at least the locking and barrier fds. */ log_close(); log_set_open_when_needed(true); + log_settle_target(); (void) fdset_close_others(fds); diff --git a/src/test/test-fd-util.c b/src/test/test-fd-util.c index 1f14f0b6cb..148694e029 100644 --- a/src/test/test-fd-util.c +++ b/src/test/test-fd-util.c @@ -278,6 +278,7 @@ static void test_close_all_fds_inner(void) { /* Close logging fd first, so that we don't confuse it by closing its fd */ log_close(); log_set_open_when_needed(true); + log_settle_target(); /* Close all but the ones to keep */ assert_se(close_all_fds(keep, n_keep) >= 0);