From: Mike Yuan Date: Sat, 22 Nov 2025 18:23:53 +0000 (+0100) Subject: core/exec-invoke: split out maybe_inherit_stdout_from_stdin(), use exec_input_is_inhe... X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a8e1796b09f8fa634b1ef2624836bfa326b2ca95;p=thirdparty%2Fsystemd.git core/exec-invoke: split out maybe_inherit_stdout_from_stdin(), use exec_input_is_inheritable() Note that exec_input_is_inheritable() rightfully refuses EXEC_INPUT_FILE, in which case std_output would have been reset in service_fix_stdio() already. While at it, use the generic fallback logic of first trying user manager stdout when stdin is not writable. --- diff --git a/src/core/exec-invoke.c b/src/core/exec-invoke.c index 4312fad505e..7cc377a2535 100644 --- a/src/core/exec-invoke.c +++ b/src/core/exec-invoke.c @@ -460,6 +460,41 @@ static bool can_inherit_stderr_from_stdout(const ExecContext *context) { return true; } +static int maybe_inherit_stdout_from_stdin(const ExecContext *context, ExecInput i) { + int r; + + assert(context); + + if (context->std_output != EXEC_OUTPUT_INHERIT) + return 0; + + /* If input got downgraded, inherit the original value */ + if (i == EXEC_INPUT_NULL && exec_input_is_terminal(context->std_input)) + return open_terminal_as(exec_context_tty_path(context), O_WRONLY, STDOUT_FILENO); + + if (!exec_input_is_inheritable(i)) + goto fallback; + + r = fd_is_writable(STDIN_FILENO); + if (r <= 0) { + if (r < 0) + log_warning_errno(r, "Failed to check if inherited stdin is writable for stdout, using fallback: %m"); + else + log_warning("Inherited stdin is not writable for stdout, using fallback: %m"); + goto fallback; + } + + return RET_NERRNO(dup2(STDIN_FILENO, STDOUT_FILENO)); + +fallback: + /* If we are not started from PID 1 we just inherit STDOUT from our parent process. */ + if (getppid() != 1) + return STDOUT_FILENO; + + /* We need to open /dev/null here anew, to get the right access mode. */ + return open_null_as(O_WRONLY, STDOUT_FILENO); +} + static int setup_output( const ExecContext *context, const ExecParameters *params, @@ -498,19 +533,15 @@ static int setup_output( } i = fixup_input(context, params->flags & EXEC_APPLY_TTY_STDIN); - o = context->std_output; if (fileno == STDERR_FILENO) { - ExecOutput e = context->std_error; - /* This expects the input and output are already set up */ /* Don't change the stderr file descriptor if we inherit all * the way and are not on a tty */ - if (e == EXEC_OUTPUT_INHERIT && - o == EXEC_OUTPUT_INHERIT && - i == EXEC_INPUT_NULL && - !exec_input_is_terminal(context->std_input) && + if (context->std_error == EXEC_OUTPUT_INHERIT && + context->std_output == EXEC_OUTPUT_INHERIT && + i == EXEC_INPUT_NULL && !exec_input_is_terminal(context->std_input) && getppid() != 1) return fileno; @@ -527,34 +558,16 @@ static int setup_output( return RET_NERRNO(dup2(STDOUT_FILENO, fileno)); } - o = e; - - } else if (o == EXEC_OUTPUT_INHERIT) { - /* If input got downgraded, inherit the original value */ - if (i == EXEC_INPUT_NULL && exec_input_is_terminal(context->std_input)) - return open_terminal_as(exec_context_tty_path(context), O_WRONLY, fileno); + o = context->std_error; - /* If the input is connected to anything that's not a /dev/null or a data fd, inherit that... */ - if (!IN_SET(i, EXEC_INPUT_NULL, EXEC_INPUT_DATA)) { - r = fd_is_writable(STDIN_FILENO); - if (r <= 0) { - if (r < 0) - log_warning_errno(r, "Failed to check if inherited stdin is writable for %s, falling back to /dev/null.", - fileno == STDOUT_FILENO ? "stdout" : "stderr"); - else - log_warning("Inherited stdin is not writable for %s, falling back to /dev/null.", - fileno == STDOUT_FILENO ? "stdout" : "stderr"); - return open_null_as(O_WRONLY, fileno); - } - return RET_NERRNO(dup2(STDIN_FILENO, fileno)); - } + } else { + assert(fileno == STDOUT_FILENO); - /* If we are not started from PID 1 we just inherit STDOUT from our parent process. */ - if (getppid() != 1) - return fileno; + r = maybe_inherit_stdout_from_stdin(context, i); + if (r != 0) + return r; - /* We need to open /dev/null here anew, to get the right access mode. */ - return open_null_as(O_WRONLY, fileno); + o = context->std_output; } switch (o) {