int r = 0;
assert(fd >= 0);
+ assert(!FLAGS_SET(flags, TERMINAL_RESET_AVOID_ANSI_SEQ|TERMINAL_RESET_FORCE_ANSI_SEQ));
- /* Resets the terminal comprehensively, but defensively. i.e. both resets the tty via ioctl()s and
- * via ANSI sequences, but avoids the latter in case we are talking to a pty. That's a safety measure
- * because ptys might be connected to shell pipelines where we cannot expect such ansi sequences to
- * work. Given that ptys are generally short-lived (and not recycled) this restriction shouldn't hurt
- * much.
- *
- * The specified fd should be open for *writing*! */
+ /* Resets the terminal comprehensively, i.e. via both ioctl()s and via ANSI sequences, but do so only
+ * if $TERM is unset or set to "dumb" */
if (!isatty_safe(fd))
return -ENOTTY;
RET_GATHER(r, terminal_reset_ioctl(fd, FLAGS_SET(flags, TERMINAL_RESET_SWITCH_TO_TEXT)));
- if (terminal_is_pty_fd(fd) == 0)
+ if (!FLAGS_SET(flags, TERMINAL_RESET_AVOID_ANSI_SEQ) &&
+ (FLAGS_SET(flags, TERMINAL_RESET_FORCE_ANSI_SEQ) || !getenv_terminal_is_dumb()))
RET_GATHER(r, terminal_reset_ansi_seq(fd));
return r;
typedef enum TerminalResetFlags {
TERMINAL_RESET_SWITCH_TO_TEXT = 1 << 0,
+ TERMINAL_RESET_AVOID_ANSI_SEQ = 1 << 1,
+ TERMINAL_RESET_FORCE_ANSI_SEQ = 1 << 2,
} TerminalResetFlags;
int terminal_reset_defensive(int fd, TerminalResetFlags flags);
p->stdout_fd >= 0))
return;
+ /* Let's explicitly determine whether to reset via ANSI sequences or not, taking our ExecContext
+ * information into account */
+ bool use_ansi = exec_context_shall_ansi_seq_reset(context);
+
if (context->tty_reset) {
/* When we are resetting the TTY, then let's create a lock first, to synchronize access. This
* in particular matters as concurrent resets and the TTY size ANSI DSR logic done by the
if (lock_fd < 0)
log_exec_debug_errno(context, p, lock_fd, "Failed to lock /dev/console, ignoring: %m");
- (void) terminal_reset_defensive(STDOUT_FILENO, /* flags= */ 0);
+ /* We explicitly control whether to send ansi sequences or not here, since we want to consult
+ * the env vars explicitly configured in the ExecContext, rather than our own environment
+ * block. */
+ (void) terminal_reset_defensive(STDOUT_FILENO, use_ansi ? TERMINAL_RESET_FORCE_ANSI_SEQ : TERMINAL_RESET_AVOID_ANSI_SEQ);
}
(void) exec_context_apply_tty_size(context, STDIN_FILENO, STDOUT_FILENO, /* tty_path= */ NULL);
rows == UINT_MAX ? &rows : NULL,
cols == UINT_MAX ? &cols : NULL);
- /* If we got nothing so far and we are talking to a physical device, and the TTY reset logic is on,
- * then let's query dimensions from the ANSI driver. */
+ /* If we got nothing so far and we are talking to a physical device, then let's query dimensions from
+ * the ANSI terminal driver. Note that we will not bother with this in case terminal reset via ansi
+ * sequences is not enabled, as the DSR logic relies on ANSI sequences after all, and if we shall not
+ * use those during initialization we need to skip it. */
if (rows == UINT_MAX && cols == UINT_MAX &&
- context->tty_reset &&
- terminal_is_pty_fd(output_fd) == 0 &&
+ exec_context_shall_ansi_seq_reset(context) &&
isatty_safe(input_fd)) {
r = terminal_get_size_by_dsr(input_fd, output_fd, &rows, &cols);
if (r < 0)
log_warning_errno(lock_fd, "Failed to lock /dev/console, proceeding without lock: %m");
if (context->tty_reset)
- (void) terminal_reset_defensive(fd, TERMINAL_RESET_SWITCH_TO_TEXT);
+ (void) terminal_reset_defensive(
+ fd,
+ TERMINAL_RESET_SWITCH_TO_TEXT |
+ (exec_context_shall_ansi_seq_reset(context) ? TERMINAL_RESET_FORCE_ANSI_SEQ : TERMINAL_RESET_AVOID_ANSI_SEQ));
r = exec_context_apply_tty_size(context, fd, fd, path);
if (r < 0)
tty_may_match_dev_console(exec_context_tty_path(ec));
}
+bool exec_context_shall_ansi_seq_reset(const ExecContext *c) {
+ assert(c);
+
+ /* Determines whether ANSI sequences shall be used during any terminal initialisation:
+ *
+ * 1. If the reset logic is enabled at all, this is an immediate no.
+ *
+ * 2. If $TERM is set to anything other than "dumb", it's a yes.
+ */
+
+ if (!c->tty_reset)
+ return false;
+
+ return !streq_ptr(strv_env_get(c->environment, "TERM"), "dumb");
+}
+
static void strv_fprintf(FILE *f, char **l) {
assert(f);
bool exec_context_may_touch_console(const ExecContext *c);
bool exec_context_maintains_privileges(const ExecContext *c);
+bool exec_context_shall_ansi_seq_reset(const ExecContext *c);
int exec_context_get_effective_ioprio(const ExecContext *c);
bool exec_context_get_effective_mount_apivfs(const ExecContext *c);