]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core/exec-invoke: split out maybe_inherit_stdout_from_stdin(), use exec_input_is_inhe...
authorMike Yuan <me@yhndnzj.com>
Sat, 22 Nov 2025 18:23:53 +0000 (19:23 +0100)
committerLuca Boccassi <bluca@debian.org>
Wed, 17 Dec 2025 23:23:22 +0000 (23:23 +0000)
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.

src/core/exec-invoke.c

index 4312fad505eda1941075df1a52494937ce3bfb6a..7cc377a253539a7a5bca11bfb5b8b655ea4b820b 100644 (file)
@@ -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) {