]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core: use terminal DCS sequence to set $TERM
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Tue, 20 May 2025 17:02:31 +0000 (19:02 +0200)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Thu, 29 May 2025 17:20:31 +0000 (19:20 +0200)
query_term_for_tty() is used in two places: in fixup_environment(),
which affects PID1 itself, and in build_environment(), which affects
spawned services. There is obviously some cost to the extra call,
but I think it's worthwhile to do it. When $TERM is set incorrectly,
basic output works OK, but then there are various annoying corner
cases. In particular, we get the support for color (or lack of it)
wrong, and when output is garbled, users are annoyed. Things like
text editors are almost certain to behave incorrectly. Testing in
test-terminal-util indicates that the time required to make a successful
query is on the order of a dozen microseconds, and an unsuccessful
query costs as much as our timeout, i.e. currently 1/3 ms. I think
this is an acceptable tradeoff.

No caching is used, because fixup_environment() is only called once,
and the other place in build_environment(), only affects services
which are connected to a tty, which is only a handful of services,
and often only started in special circumstances.

Fixes https://github.com/systemd/systemd/issues/36994.

src/basic/terminal-util.h
src/core/exec-invoke.c
src/core/main.c

index 688d6808a6791cf6d30ead778d56198576e3b4a5..8438a3fb210c2307f790aa3547f786f45894e809 100644 (file)
@@ -143,6 +143,9 @@ assert_cc((TTY_MODE & 0711) == 0600);
 
 void termios_disable_echo(struct termios *termios);
 
+/* The $TERM value we use for terminals other than the Linux console */
+#define FALLBACK_TERM "vt220"
+
 int get_default_background_color(double *ret_red, double *ret_green, double *ret_blue);
 int terminal_get_size_by_dsr(int input_fd, int output_fd, unsigned *ret_rows, unsigned *ret_columns);
 int terminal_fix_size(int input_fd, int output_fd);
index b27358d8dc96c69dec18a33360caeb6cc9738970..f4e090297c9fd45de879a2252b6abd181d370be0 100644 (file)
@@ -2038,7 +2038,7 @@ static int build_environment(
         }
 
         if (exec_context_needs_term(c)) {
-                _cleanup_free_ char *cmdline = NULL;
+                _cleanup_free_ char *cmdline = NULL, *dcs_term = NULL;
                 const char *tty_path, *term = NULL;
 
                 tty_path = exec_context_tty_path(c);
@@ -2063,8 +2063,16 @@ static int build_environment(
                                 term = cmdline;
                 }
 
+                if (!term && tty_path) {
+                        /* This handles real virtual terminals (returning "linux") and
+                         * any terminals which support the DCS +q query sequence. */
+                        r = query_term_for_tty(tty_path, &dcs_term);
+                        if (r >= 0)
+                                term = dcs_term;
+                }
+
                 if (!term) {
-                        /* If no precise $TERM is known and we pick a fallback default, then let's also set
+                        /* If $TERM is not known and we pick a fallback default, then let's also set
                          * $COLORTERM=truecolor. That's because our fallback default is vt220, which is
                          * generally a safe bet (as it supports PageUp/PageDown unlike vt100, and is quite
                          * universally available in terminfo/termcap), except for the fact that real DEC
@@ -2083,7 +2091,7 @@ static int build_environment(
 
                         our_env[n_env++] = x;
 
-                        term = default_term_for_tty(tty_path);
+                        term = FALLBACK_TERM;
                 }
 
                 x = strjoin("TERM=", term);
index 2005d733c64f6713d4f60e639c0ae1dfb7ac35b6..b1f7cc941bc05e2f8c4e399eb565bed7012744a9 100644 (file)
@@ -1594,8 +1594,10 @@ static int fixup_environment(void) {
                         return r;
         }
 
-        const char *t = term ?: default_term_for_tty("/dev/console");
-        if (setenv("TERM", t, /* overwrite= */ true) < 0)
+        if (!term)
+                (void) query_term_for_tty("/dev/console", &term);
+
+        if (setenv("TERM", term ?: FALLBACK_TERM, /* overwrite= */ true) < 0)
                 return -errno;
 
         /* The kernels sets HOME=/ for init. Let's undo this. */