From d0aa368c85adf2efa29c363a6671927fe7e8e76f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 31 Jan 2024 18:48:53 +0100 Subject: [PATCH 1/7] ptyfwd: tweaks to background tinting logic This makes two changes: 1. it resets the background color not only on NL (aka LF) but also on CR, but without erasing things to the end of the line. This increases compatbility with tools such as "less" which use CR to jump back to the beginning of the line. 2. previously we'd not process series of newlines or ansi sequences without intermediate other characters correctly, we'd always assume what follows is regular text. Fix that, and correctly determine the right state from the subsequent character. --- src/shared/ptyfwd.c | 67 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 52 insertions(+), 15 deletions(-) diff --git a/src/shared/ptyfwd.c b/src/shared/ptyfwd.c index c05ce79489..3214749595 100644 --- a/src/shared/ptyfwd.c +++ b/src/shared/ptyfwd.c @@ -34,6 +34,7 @@ typedef enum AnsiColorState { ANSI_COLOR_STATE_ESC, ANSI_COLOR_STATE_CSI_SEQUENCE, ANSI_COLOR_STATE_NEWLINE, + ANSI_COLOR_STATE_CARRIAGE_RETURN, _ANSI_COLOR_STATE_MAX, _ANSI_COLOR_STATE_INVALID = -EINVAL, } AnsiColorState; @@ -230,9 +231,7 @@ static char *background_color_sequence(PTYForward *f) { assert(f); assert(f->background_color); - /* This sets the background color to the desired one, and erase the rest of the line with it */ - - return strjoin("\x1B[", f->background_color, "m", ANSI_ERASE_TO_END_OF_LINE); + return strjoin("\x1B[", f->background_color, "m"); } static int insert_string(PTYForward *f, size_t offset, const char *s) { @@ -257,12 +256,33 @@ static int insert_string(PTYForward *f, size_t offset, const char *s) { return (int) l; } -static int insert_erase_newline(PTYForward *f, size_t offset) { +static int insert_newline_color_erase(PTYForward *f, size_t offset) { _cleanup_free_ char *s = NULL; assert(f); assert(f->background_color); + /* When we see a newline (ASCII 10) then this sets the background color to the desired one, and erase the rest + * of the line with it */ + + s = background_color_sequence(f); + if (!s) + return -ENOMEM; + + if (!strextend(&s, ANSI_ERASE_TO_END_OF_LINE)) + return -ENOMEM; + + return insert_string(f, offset, s); +} + +static int insert_carriage_return_color(PTYForward *f, size_t offset) { + _cleanup_free_ char *s = NULL; + + assert(f); + assert(f->background_color); + + /* When we see a carriage return (ASCII 13) this this sets only the background */ + s = background_color_sequence(f); if (!s) return -ENOMEM; @@ -369,31 +389,36 @@ static int pty_forward_ansi_process(PTYForward *f, size_t offset) { switch (f->ansi_color_state) { case ANSI_COLOR_STATE_TEXT: - if (c == '\n') - f->ansi_color_state = ANSI_COLOR_STATE_NEWLINE; - if (c == 0x1B) /* ESC */ - f->ansi_color_state = ANSI_COLOR_STATE_ESC; break; case ANSI_COLOR_STATE_NEWLINE: { /* Immediately after a newline insert an ANSI sequence to erase the line with a background color */ - r = insert_erase_newline(f, i); + r = insert_newline_color_erase(f, i); if (r < 0) return r; i += r; + break; + } - f->ansi_color_state = ANSI_COLOR_STATE_TEXT; + case ANSI_COLOR_STATE_CARRIAGE_RETURN: { + /* Immediately after a carriage return insert an ANSI sequence set the background color back */ + + r = insert_carriage_return_color(f, i); + if (r < 0) + return r; + + i += r; break; } case ANSI_COLOR_STATE_ESC: { - if (c == '[') + if (c == '[') { f->ansi_color_state = ANSI_COLOR_STATE_CSI_SEQUENCE; - else - f->ansi_color_state = ANSI_COLOR_STATE_TEXT; + continue; + } break; } @@ -408,7 +433,7 @@ static int pty_forward_ansi_process(PTYForward *f, size_t offset) { /* Safety check: lets not accept unbounded CSI sequences */ f->csi_sequence = mfree(f->csi_sequence); - f->ansi_color_state = ANSI_COLOR_STATE_TEXT; + break; } else if (!strextend(&f->csi_sequence, CHAR_TO_STR(c))) return -ENOMEM; } else { @@ -427,12 +452,21 @@ static int pty_forward_ansi_process(PTYForward *f, size_t offset) { f->ansi_color_state = ANSI_COLOR_STATE_TEXT; } - break; + continue; } default: assert_not_reached(); } + + if (c == '\n') + f->ansi_color_state = ANSI_COLOR_STATE_NEWLINE; + else if (c == '\r') + f->ansi_color_state = ANSI_COLOR_STATE_CARRIAGE_RETURN; + else if (c == 0x1B) /* ESC */ + f->ansi_color_state = ANSI_COLOR_STATE_ESC; + else + f->ansi_color_state = ANSI_COLOR_STATE_TEXT; } return 0; @@ -450,6 +484,9 @@ static int shovel(PTYForward *f) { if (!f->out_buffer) return pty_forward_done(f, log_oom()); + if (!strextend(&f->out_buffer, ANSI_ERASE_TO_END_OF_LINE)) + return pty_forward_done(f, log_oom()); + f->out_buffer_full = strlen(f->out_buffer); f->out_buffer_size = MALLOC_SIZEOF_SAFE(f->out_buffer); } From ddba81d8dd02df70e901f06f462db0196183ecf7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 1 Feb 2024 10:07:30 +0100 Subject: [PATCH 2/7] ptyfwd: optionally update window title if we are running a ptyfwd session --- src/basic/terminal-util.h | 4 +++ src/shared/ptyfwd.c | 70 +++++++++++++++++++++++++++++++++------ src/shared/ptyfwd.h | 2 ++ 3 files changed, 66 insertions(+), 10 deletions(-) diff --git a/src/basic/terminal-util.h b/src/basic/terminal-util.h index 4822917f28..2aed260526 100644 --- a/src/basic/terminal-util.h +++ b/src/basic/terminal-util.h @@ -89,6 +89,10 @@ /* Set cursor to top left corner and clear screen */ #define ANSI_HOME_CLEAR "\x1B[H\x1B[2J" +/* Push/pop a window title off the stack of window titles */ +#define ANSI_WINDOW_TITLE_PUSH "\x1b[22;2t" +#define ANSI_WINDOW_TITLE_POP "\x1b[23;2t" + bool isatty_safe(int fd); int reset_terminal_fd(int fd, bool switch_to_text); diff --git a/src/shared/ptyfwd.c b/src/shared/ptyfwd.c index 3214749595..f2e5fbb0ad 100644 --- a/src/shared/ptyfwd.c +++ b/src/shared/ptyfwd.c @@ -92,6 +92,8 @@ struct PTYForward { char *background_color; AnsiColorState ansi_color_state; char *csi_sequence; + + char *title; }; #define ESCAPE_USEC (1*USEC_PER_SEC) @@ -115,9 +117,13 @@ static void pty_forward_disconnect(PTYForward *f) { /* STDIN/STDOUT should not be non-blocking normally, so let's reset it */ (void) fd_nonblock(f->output_fd, false); - if (colors_enabled()) + if (colors_enabled()) { (void) loop_write(f->output_fd, ANSI_NORMAL ANSI_ERASE_TO_END_OF_SCREEN, SIZE_MAX); + if (f->title) + (void) loop_write(f->output_fd, ANSI_WINDOW_TITLE_POP, SIZE_MAX); + } + if (f->close_output_fd) f->output_fd = safe_close(f->output_fd); } @@ -478,17 +484,28 @@ static int shovel(PTYForward *f) { assert(f); - if (f->out_buffer_size == 0 && f->background_color) { - /* Erase the first line when we start */ - f->out_buffer = background_color_sequence(f); - if (!f->out_buffer) - return pty_forward_done(f, log_oom()); + if (f->out_buffer_size == 0) { + if (f->background_color) { + /* Erase the first line when we start */ + f->out_buffer = background_color_sequence(f); + if (!f->out_buffer) + return pty_forward_done(f, log_oom()); - if (!strextend(&f->out_buffer, ANSI_ERASE_TO_END_OF_LINE)) - return pty_forward_done(f, log_oom()); + if (!strextend(&f->out_buffer, ANSI_ERASE_TO_END_OF_LINE)) + return pty_forward_done(f, log_oom()); + } - f->out_buffer_full = strlen(f->out_buffer); - f->out_buffer_size = MALLOC_SIZEOF_SAFE(f->out_buffer); + if (f->title) { + if (!strextend(&f->out_buffer, + ANSI_WINDOW_TITLE_PUSH + "\x1b]2;", f->title, "\a")) + return pty_forward_done(f, log_oom()); + } + + if (f->out_buffer) { + f->out_buffer_full = strlen(f->out_buffer); + f->out_buffer_size = MALLOC_SIZEOF_SAFE(f->out_buffer); + } } if (f->out_buffer_size < LINE_MAX) { @@ -855,6 +872,7 @@ PTYForward *pty_forward_free(PTYForward *f) { return NULL; pty_forward_disconnect(f); free(f->background_color); + free(f->title); return mfree(f); } @@ -995,3 +1013,35 @@ int pty_forward_set_background_color(PTYForward *f, const char *color) { return free_and_strdup(&f->background_color, color); } + +int pty_forward_set_title(PTYForward *f, const char *title) { + assert(f); + + /* Refuse accepting a title when we already started shoveling */ + if (f->out_buffer_size > 0) + return -EBUSY; + + return free_and_strdup(&f->title, title); +} + +int pty_forward_set_titlef(PTYForward *f, const char *format, ...) { + _cleanup_free_ char *title = NULL; + va_list ap; + int r; + + assert(f); + assert(format); + + if (f->out_buffer_size > 0) + return -EBUSY; + + va_start(ap, format); + DISABLE_WARNING_FORMAT_NONLITERAL; + r = vasprintf(&title, format, ap); + REENABLE_WARNING; + va_end(ap); + if (r < 0) + return -ENOMEM; + + return free_and_replace(f->title, title); +} diff --git a/src/shared/ptyfwd.h b/src/shared/ptyfwd.h index bae8d3591e..3f0d7811a2 100644 --- a/src/shared/ptyfwd.h +++ b/src/shared/ptyfwd.h @@ -40,5 +40,7 @@ int pty_forward_set_priority(PTYForward *f, int64_t priority); int pty_forward_set_width_height(PTYForward *f, unsigned width, unsigned height); int pty_forward_set_background_color(PTYForward *f, const char *color); +int pty_forward_set_title(PTYForward *f, const char *title); +int pty_forward_set_titlef(PTYForward *f, const char *format, ...) _printf_(2,3); DEFINE_TRIVIAL_CLEANUP_FUNC(PTYForward*, pty_forward_free); From c80139f078f2915200c05bc626b4b14848beb99d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 1 Feb 2024 11:14:24 +0100 Subject: [PATCH 3/7] glyph-util: add colored circle glyphs --- src/basic/glyph-util.c | 7 +++++++ src/basic/glyph-util.h | 3 +++ src/test/test-locale-util.c | 5 ++++- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/basic/glyph-util.c b/src/basic/glyph-util.c index 803bdd90e2..2cec3d82cf 100644 --- a/src/basic/glyph-util.c +++ b/src/basic/glyph-util.c @@ -74,6 +74,9 @@ const char *special_glyph_full(SpecialGlyph code, bool force_utf) { [SPECIAL_GLYPH_SPARKLES] = "*", [SPECIAL_GLYPH_LOW_BATTERY] = "!", [SPECIAL_GLYPH_WARNING_SIGN] = "!", + [SPECIAL_GLYPH_RED_CIRCLE] = "o", + [SPECIAL_GLYPH_YELLOW_CIRCLE] = "o", + [SPECIAL_GLYPH_BLUE_CIRCLE] = "o", }, /* UTF-8 */ @@ -136,6 +139,10 @@ const char *special_glyph_full(SpecialGlyph code, bool force_utf) { [SPECIAL_GLYPH_WARNING_SIGN] = u8"⚠️", [SPECIAL_GLYPH_COMPUTER_DISK] = u8"💽", [SPECIAL_GLYPH_WORLD] = u8"🌍", + + [SPECIAL_GLYPH_RED_CIRCLE] = u8"🔴", + [SPECIAL_GLYPH_YELLOW_CIRCLE] = u8"🟡", + [SPECIAL_GLYPH_BLUE_CIRCLE] = u8"🔵", }, }; diff --git a/src/basic/glyph-util.h b/src/basic/glyph-util.h index a7709976e1..e476fefe94 100644 --- a/src/basic/glyph-util.h +++ b/src/basic/glyph-util.h @@ -49,6 +49,9 @@ typedef enum SpecialGlyph { SPECIAL_GLYPH_WARNING_SIGN, SPECIAL_GLYPH_COMPUTER_DISK, SPECIAL_GLYPH_WORLD, + SPECIAL_GLYPH_RED_CIRCLE, + SPECIAL_GLYPH_YELLOW_CIRCLE, + SPECIAL_GLYPH_BLUE_CIRCLE, _SPECIAL_GLYPH_MAX, _SPECIAL_GLYPH_INVALID = -EINVAL, } SpecialGlyph; diff --git a/src/test/test-locale-util.c b/src/test/test-locale-util.c index 39f71c67d3..dd9a8134bf 100644 --- a/src/test/test-locale-util.c +++ b/src/test/test-locale-util.c @@ -82,7 +82,7 @@ TEST(keymaps) { #define dump_glyph(x) log_info(STRINGIFY(x) ": %s", special_glyph(x)) TEST(dump_special_glyphs) { - assert_cc(SPECIAL_GLYPH_WORLD + 1 == _SPECIAL_GLYPH_MAX); + assert_cc(SPECIAL_GLYPH_BLUE_CIRCLE + 1 == _SPECIAL_GLYPH_MAX); log_info("is_locale_utf8: %s", yes_no(is_locale_utf8())); @@ -127,6 +127,9 @@ TEST(dump_special_glyphs) { dump_glyph(SPECIAL_GLYPH_WARNING_SIGN); dump_glyph(SPECIAL_GLYPH_COMPUTER_DISK); dump_glyph(SPECIAL_GLYPH_WORLD); + dump_glyph(SPECIAL_GLYPH_RED_CIRCLE); + dump_glyph(SPECIAL_GLYPH_YELLOW_CIRCLE); + dump_glyph(SPECIAL_GLYPH_BLUE_CIRCLE); } DEFINE_TEST_MAIN(LOG_INFO); From ab03434aa7b1cc174bfc75a21923165d394e47b3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 1 Feb 2024 11:13:07 +0100 Subject: [PATCH 4/7] nspawn: set window title from container name Let's update the window title with an ANSI sequence if we can. We'll insert a blue dot, to match the blue tinting of the terminal screen, indicating that we are in a container. --- src/nspawn/nspawn.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index ae5172853b..2384a94945 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -4451,6 +4451,22 @@ static int setup_notify_parent(sd_event *event, int fd, pid_t *inner_child_pid, return 0; } +static void set_window_title(PTYForward *f) { + _cleanup_free_ char *hn = NULL, *dot = NULL; + + assert(f); + + (void) gethostname_strict(&hn); + + if (emoji_enabled()) + dot = strjoin(special_glyph(SPECIAL_GLYPH_BLUE_CIRCLE), " "); + + if (hn) + (void) pty_forward_set_titlef(f, "%sContainer %s on %s", strempty(dot), arg_machine, hn); + else + (void) pty_forward_set_titlef(f, "%sContainer %s", strempty(dot), arg_machine); +} + static int merge_settings(Settings *settings, const char *path) { int rl; @@ -5383,6 +5399,7 @@ static int run_container( } else if (!isempty(arg_background)) (void) pty_forward_set_background_color(forward, arg_background); + set_window_title(forward); break; default: From 8496b938ab28e039a37fad820d788eef82517d9c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 1 Feb 2024 10:43:44 +0100 Subject: [PATCH 5/7] run: set window title In interactive terminal mode, let's set a window title that reflects our change of context to the target. Let's prefix it it with red/yellow emoji dot in case we changed privileges. --- src/run/run.c | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/run/run.c b/src/run/run.c index a695fea0f0..b42ed44231 100644 --- a/src/run/run.c +++ b/src/run/run.c @@ -22,6 +22,7 @@ #include "exit-status.h" #include "fd-util.h" #include "format-util.h" +#include "hostname-util.h" #include "main-func.h" #include "parse-argument.h" #include "parse-util.h" @@ -188,6 +189,13 @@ static int help_sudo_mode(void) { return 0; } +static bool privileged_execution(void) { + if (arg_runtime_scope != RUNTIME_SCOPE_SYSTEM) + return false; + + return !arg_exec_user || STR_IN_SET(arg_exec_user, "root", "0"); +} + static int add_timer_property(const char *name, const char *val) { char *p; @@ -941,7 +949,7 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) { if (!arg_background && arg_stdio == ARG_STDIO_PTY) { double hue; - if (!arg_exec_user || STR_IN_SET(arg_exec_user, "root", "0")) + if (privileged_execution()) hue = 0; /* red */ else hue = 60 /* yellow */; @@ -1584,6 +1592,26 @@ static int acquire_invocation_id(sd_bus *bus, const char *unit, sd_id128_t *ret) return !sd_id128_is_null(*ret); } +static void set_window_title(PTYForward *f) { + _cleanup_free_ char *hn = NULL, *cl = NULL, *dot = NULL; + assert(f); + + if (!arg_host) + (void) gethostname_strict(&hn); + + cl = strv_join(arg_cmdline, " "); + if (!cl) + return (void) log_oom(); + + if (emoji_enabled()) + dot = strjoin(special_glyph(privileged_execution() ? SPECIAL_GLYPH_RED_CIRCLE : SPECIAL_GLYPH_YELLOW_CIRCLE), " "); + + if (arg_host || hn) + (void) pty_forward_set_titlef(f, "%s%s on %s", strempty(dot), cl, arg_host ?: hn); + else + (void) pty_forward_set_titlef(f, "%s%s", strempty(dot), cl); +} + static int start_transient_service(sd_bus *bus) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; @@ -1739,6 +1767,8 @@ static int start_transient_service(sd_bus *bus) { if (!isempty(arg_background)) (void) pty_forward_set_background_color(c.forward, arg_background); + + set_window_title(c.forward); } path = unit_dbus_path_from_name(service); From 8f1fe0410dc28c5edfb228741201cd52d38d8754 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 6 Feb 2024 11:30:02 +0100 Subject: [PATCH 6/7] ptyfwd: simplify error handling in shovel() We treat all errors the same, hence let's just have a common handling for that, and normalize how we propagate errors from shovel(). No change in behaviour, just some refactoring. --- src/shared/ptyfwd.c | 50 ++++++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/src/shared/ptyfwd.c b/src/shared/ptyfwd.c index f2e5fbb0ad..f6082580a3 100644 --- a/src/shared/ptyfwd.c +++ b/src/shared/ptyfwd.c @@ -478,7 +478,7 @@ static int pty_forward_ansi_process(PTYForward *f, size_t offset) { return 0; } -static int shovel(PTYForward *f) { +static int do_shovel(PTYForward *f) { ssize_t k; int r; @@ -489,17 +489,17 @@ static int shovel(PTYForward *f) { /* Erase the first line when we start */ f->out_buffer = background_color_sequence(f); if (!f->out_buffer) - return pty_forward_done(f, log_oom()); + return log_oom(); if (!strextend(&f->out_buffer, ANSI_ERASE_TO_END_OF_LINE)) - return pty_forward_done(f, log_oom()); + return log_oom(); } if (f->title) { if (!strextend(&f->out_buffer, ANSI_WINDOW_TITLE_PUSH "\x1b]2;", f->title, "\a")) - return pty_forward_done(f, log_oom()); + return log_oom(); } if (f->out_buffer) { @@ -512,7 +512,7 @@ static int shovel(PTYForward *f) { /* Make sure we always have room for at least one "line" */ void *p = realloc(f->out_buffer, LINE_MAX); if (!p) - return pty_forward_done(f, log_oom()); + return log_oom(); f->out_buffer = p; f->out_buffer_size = MALLOC_SIZEOF_SAFE(p); @@ -535,10 +535,8 @@ static int shovel(PTYForward *f) { f->stdin_hangup = true; f->stdin_event_source = sd_event_source_unref(f->stdin_event_source); - } else { - log_error_errno(errno, "read(): %m"); - return pty_forward_done(f, -errno); - } + } else + return log_error_errno(errno, "read(): %m"); } else if (k == 0) { /* EOF on stdin */ f->stdin_readable = false; @@ -549,7 +547,7 @@ static int shovel(PTYForward *f) { /* Check if ^] has been pressed three times within one second. If we get this we quite * immediately. */ if (look_for_escape(f, f->in_buffer + f->in_buffer_full, k)) - return pty_forward_done(f, -ECANCELED); + return -ECANCELED; f->in_buffer_full += (size_t) k; } @@ -567,10 +565,8 @@ static int shovel(PTYForward *f) { f->master_hangup = true; f->master_event_source = sd_event_source_unref(f->master_event_source); - } else { - log_error_errno(errno, "write(): %m"); - return pty_forward_done(f, -errno); - } + } else + return log_error_errno(errno, "write(): %m"); } else { assert(f->in_buffer_full >= (size_t) k); memmove(f->in_buffer, f->in_buffer + k, f->in_buffer_full - k); @@ -594,10 +590,8 @@ static int shovel(PTYForward *f) { f->master_hangup = true; f->master_event_source = sd_event_source_unref(f->master_event_source); - } else { - log_error_errno(errno, "read(): %m"); - return pty_forward_done(f, -errno); - } + } else + return log_error_errno(errno, "read(): %m"); } else { f->read_from_master = true; size_t scan_index = f->out_buffer_full; @@ -605,7 +599,7 @@ static int shovel(PTYForward *f) { r = pty_forward_ansi_process(f, scan_index); if (r < 0) - return pty_forward_done(f, log_error_errno(r, "Failed to scan for ANSI sequences: %m")); + return log_error_errno(r, "Failed to scan for ANSI sequences: %m"); } } @@ -620,10 +614,8 @@ static int shovel(PTYForward *f) { f->stdout_writable = false; f->stdout_hangup = true; f->stdout_event_source = sd_event_source_unref(f->stdout_event_source); - } else { - log_error_errno(errno, "write(): %m"); - return pty_forward_done(f, -errno); - } + } else + return log_error_errno(errno, "write(): %m"); } else { @@ -656,6 +648,18 @@ static int shovel(PTYForward *f) { return 0; } +static int shovel(PTYForward *f) { + int r; + + assert(f); + + r = do_shovel(f); + if (r < 0) + return pty_forward_done(f, r); + + return r; +} + static int on_master_event(sd_event_source *e, int fd, uint32_t revents, void *userdata) { PTYForward *f = ASSERT_PTR(userdata); From d7c37242583fcdea86913bc3feda0cca84407dda Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 7 Feb 2024 17:15:20 +0100 Subject: [PATCH 7/7] ptyfwd: automatically turn off tinting/window title logic on dumb terminals If we are not talking to a reasonable terminal let's not try to set the window title or tint the background. --- src/shared/ptyfwd.c | 13 ++++++++++++- src/shared/ptyfwd.h | 10 +++++++--- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/shared/ptyfwd.c b/src/shared/ptyfwd.c index f6082580a3..654e719180 100644 --- a/src/shared/ptyfwd.c +++ b/src/shared/ptyfwd.c @@ -389,6 +389,9 @@ static int pty_forward_ansi_process(PTYForward *f, size_t offset) { if (!f->background_color) return 0; + if (FLAGS_SET(f->flags, PTY_FORWARD_DUMB_TERMINAL)) + return 0; + for (size_t i = offset; i < f->out_buffer_full; i++) { char c = f->out_buffer[i]; @@ -484,7 +487,11 @@ static int do_shovel(PTYForward *f) { assert(f); - if (f->out_buffer_size == 0) { + if (f->out_buffer_size == 0 && !FLAGS_SET(f->flags, PTY_FORWARD_DUMB_TERMINAL)) { + /* If the output hasn't been allocated yet, we are at the beginning of the first + * shovelling. Hence, possibly send some initial ANSI sequences. But do so only if we are + * talking to an actual TTY. */ + if (f->background_color) { /* Erase the first line when we start */ f->out_buffer = background_color_sequence(f); @@ -792,6 +799,10 @@ int pty_forward_new( f->master = master; + /* Disable color/window title setting unless we talk to a good TTY */ + if (!isatty_safe(f->output_fd) || get_color_mode() == COLOR_OFF) + f->flags |= PTY_FORWARD_DUMB_TERMINAL; + if (ioctl(f->output_fd, TIOCGWINSZ, &ws) < 0) /* If we can't get the resolution from the output fd, then use our internal, regular width/height, * i.e. something derived from $COLUMNS and $LINES if set. */ diff --git a/src/shared/ptyfwd.h b/src/shared/ptyfwd.h index 3f0d7811a2..f87becd030 100644 --- a/src/shared/ptyfwd.h +++ b/src/shared/ptyfwd.h @@ -10,13 +10,17 @@ typedef struct PTYForward PTYForward; typedef enum PTYForwardFlags { - PTY_FORWARD_READ_ONLY = 1, + /* Only output to STDOUT, never try to read from STDIN */ + PTY_FORWARD_READ_ONLY = 1 << 0, /* Continue reading after hangup? */ - PTY_FORWARD_IGNORE_VHANGUP = 2, + PTY_FORWARD_IGNORE_VHANGUP = 1 << 1, /* Continue reading after hangup but only if we never read anything else? */ - PTY_FORWARD_IGNORE_INITIAL_VHANGUP = 4, + PTY_FORWARD_IGNORE_INITIAL_VHANGUP = 1 << 2, + + /* Don't tint the background, or set window title */ + PTY_FORWARD_DUMB_TERMINAL = 1 << 3, } PTYForwardFlags; typedef int (*PTYForwardHandler)(PTYForward *f, int rcode, void *userdata);