vt_disallocate(context->tty_path);
}
+static bool is_terminal_output(ExecOutput o) {
+ return
+ o == EXEC_OUTPUT_TTY ||
+ o == EXEC_OUTPUT_SYSLOG_AND_CONSOLE ||
+ o == EXEC_OUTPUT_KMSG_AND_CONSOLE ||
+ o == EXEC_OUTPUT_JOURNAL_AND_CONSOLE;
+}
+
static int open_null_as(int flags, int nfd) {
int fd, r;
!!context->syslog_level_prefix,
output == EXEC_OUTPUT_SYSLOG || output == EXEC_OUTPUT_SYSLOG_AND_CONSOLE,
output == EXEC_OUTPUT_KMSG || output == EXEC_OUTPUT_KMSG_AND_CONSOLE,
- output == EXEC_OUTPUT_SYSLOG_AND_CONSOLE || output == EXEC_OUTPUT_KMSG_AND_CONSOLE || output == EXEC_OUTPUT_JOURNAL_AND_CONSOLE);
+ is_terminal_output(output));
if (fd != nfd) {
r = dup2(fd, nfd) < 0 ? -errno : nfd;
}
}
-static int setup_output(const ExecContext *context, int socket_fd, const char *ident, const char *unit_id, bool apply_tty_stdin) {
+static int setup_output(const ExecContext *context, int fileno, int socket_fd, const char *ident, const char *unit_id, bool apply_tty_stdin) {
ExecOutput o;
ExecInput i;
+ int r;
assert(context);
assert(ident);
i = fixup_input(context->std_input, socket_fd, apply_tty_stdin);
o = fixup_output(context->std_output, socket_fd);
- /* This expects the input is already set up */
+ if (fileno == STDERR_FILENO) {
+ ExecOutput e;
+ e = fixup_output(context->std_error, socket_fd);
- switch (o) {
+ /* 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 &&
+ !is_terminal_input(context->std_input) &&
+ getppid () != 1)
+ return fileno;
+
+ /* Duplicate from stdout if possible */
+ if (e == o || e == EXEC_OUTPUT_INHERIT)
+ return dup2(STDOUT_FILENO, fileno) < 0 ? -errno : fileno;
- case EXEC_OUTPUT_INHERIT:
+ o = e;
+ } else if (o == EXEC_OUTPUT_INHERIT) {
/* If input got downgraded, inherit the original value */
if (i == EXEC_INPUT_NULL && is_terminal_input(context->std_input))
- return open_terminal_as(tty_path(context), O_WRONLY, STDOUT_FILENO);
+ return open_terminal_as(tty_path(context), O_WRONLY, fileno);
/* If the input is connected to anything that's not a /dev/null, inherit that... */
if (i != EXEC_INPUT_NULL)
- return dup2(STDIN_FILENO, STDOUT_FILENO) < 0 ? -errno : STDOUT_FILENO;
+ return dup2(STDIN_FILENO, fileno) < 0 ? -errno : fileno;
/* 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. So we fall through */
-
- case EXEC_OUTPUT_NULL:
- return open_null_as(O_WRONLY, STDOUT_FILENO);
-
- case EXEC_OUTPUT_TTY:
- if (is_terminal_input(i))
- return dup2(STDIN_FILENO, STDOUT_FILENO) < 0 ? -errno : STDOUT_FILENO;
-
- /* We don't reset the terminal if this is just about output */
- return open_terminal_as(tty_path(context), O_WRONLY, STDOUT_FILENO);
-
- case EXEC_OUTPUT_SYSLOG:
- case EXEC_OUTPUT_SYSLOG_AND_CONSOLE:
- case EXEC_OUTPUT_KMSG:
- case EXEC_OUTPUT_KMSG_AND_CONSOLE:
- case EXEC_OUTPUT_JOURNAL:
- case EXEC_OUTPUT_JOURNAL_AND_CONSOLE:
- return connect_logger_as(context, o, ident, unit_id, STDOUT_FILENO);
-
- case EXEC_OUTPUT_SOCKET:
- assert(socket_fd >= 0);
- return dup2(socket_fd, STDOUT_FILENO) < 0 ? -errno : STDOUT_FILENO;
+ return fileno;
- default:
- assert_not_reached("Unknown output type");
+ /* We need to open /dev/null here anew, to get the right access mode. */
+ return open_null_as(O_WRONLY, fileno);
}
-}
-
-static int setup_error(const ExecContext *context, int socket_fd, const char *ident, const char *unit_id, bool apply_tty_stdin) {
- ExecOutput o, e;
- ExecInput i;
-
- assert(context);
- assert(ident);
-
- i = fixup_input(context->std_input, socket_fd, apply_tty_stdin);
- o = fixup_output(context->std_output, socket_fd);
- e = fixup_output(context->std_error, socket_fd);
-
- /* 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 &&
- !is_terminal_input(context->std_input) &&
- getppid () != 1)
- return STDERR_FILENO;
-
- /* Duplicate from stdout if possible */
- if (e == o || e == EXEC_OUTPUT_INHERIT)
- return dup2(STDOUT_FILENO, STDERR_FILENO) < 0 ? -errno : STDERR_FILENO;
- switch (e) {
+ switch (o) {
case EXEC_OUTPUT_NULL:
- return open_null_as(O_WRONLY, STDERR_FILENO);
+ return open_null_as(O_WRONLY, fileno);
case EXEC_OUTPUT_TTY:
if (is_terminal_input(i))
- return dup2(STDIN_FILENO, STDERR_FILENO) < 0 ? -errno : STDERR_FILENO;
+ return dup2(STDIN_FILENO, fileno) < 0 ? -errno : fileno;
/* We don't reset the terminal if this is just about output */
- return open_terminal_as(tty_path(context), O_WRONLY, STDERR_FILENO);
+ return open_terminal_as(tty_path(context), O_WRONLY, fileno);
case EXEC_OUTPUT_SYSLOG:
case EXEC_OUTPUT_SYSLOG_AND_CONSOLE:
case EXEC_OUTPUT_KMSG_AND_CONSOLE:
case EXEC_OUTPUT_JOURNAL:
case EXEC_OUTPUT_JOURNAL_AND_CONSOLE:
- return connect_logger_as(context, e, ident, unit_id, STDERR_FILENO);
+ r = connect_logger_as(context, o, ident, unit_id, fileno);
+ if (r < 0) {
+ log_struct_unit(LOG_CRIT, unit_id,
+ "MESSAGE=Failed to connect std%s of %s to the journal socket: %s",
+ fileno == STDOUT_FILENO ? "out" : "err",
+ unit_id, strerror(-r),
+ "ERRNO=%d", -r,
+ NULL);
+ r = open_null_as(O_WRONLY, fileno);
+ }
+ return r;
case EXEC_OUTPUT_SOCKET:
assert(socket_fd >= 0);
- return dup2(socket_fd, STDERR_FILENO) < 0 ? -errno : STDERR_FILENO;
+ return dup2(socket_fd, fileno) < 0 ? -errno : fileno;
default:
assert_not_reached("Unknown error type");
goto fail_child;
}
- err = setup_output(context, socket_fd, path_get_file_name(command->path), unit_id, apply_tty_stdin);
+ err = setup_output(context, STDOUT_FILENO, socket_fd, path_get_file_name(command->path), unit_id, apply_tty_stdin);
if (err < 0) {
r = EXIT_STDOUT;
goto fail_child;
}
- err = setup_error(context, socket_fd, path_get_file_name(command->path), unit_id, apply_tty_stdin);
+ err = setup_output(context, STDERR_FILENO, socket_fd, path_get_file_name(command->path), unit_id, apply_tty_stdin);
if (err < 0) {
r = EXIT_STDERR;
goto fail_child;
return 0;
}
+static bool tty_may_match_dev_console(const char *tty) {
+ char *active = NULL, *console;
+ bool b;
+
+ if (startswith(tty, "/dev/"))
+ tty += 5;
+
+ /* trivial identity? */
+ if (streq(tty, "console"))
+ return true;
+
+ console = resolve_dev_console(&active);
+ /* if we could not resolve, assume it may */
+ if (!console)
+ return true;
+
+ /* "tty0" means the active VC, so it may be the same sometimes */
+ b = streq(console, tty) || (streq(console, "tty0") && tty_is_vc(tty));
+ free(active);
+
+ return b;
+}
+
+bool exec_context_may_touch_console(ExecContext *ec) {
+ return (ec->tty_reset || ec->tty_vhangup || ec->tty_vt_disallocate ||
+ is_terminal_input(ec->std_input) ||
+ is_terminal_output(ec->std_output) ||
+ is_terminal_output(ec->std_error)) &&
+ tty_may_match_dev_console(tty_path(ec));
+}
+
static void strv_fprintf(FILE *f, char **l) {
char **g;