]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core: Limit terminal reset using ANSI sequences to /dev/console
authorDaan De Meyer <daan.j.demeyer@gmail.com>
Mon, 22 Apr 2024 20:58:49 +0000 (22:58 +0200)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Tue, 23 Apr 2024 13:05:50 +0000 (15:05 +0200)
Doing this in reset_terminal_fd() is a bit too invasive, see
https://github.com/systemd/systemd/pull/32406#issuecomment-2070923583.

Let's only do this for /dev/console so that we work around weird firmwares
disabling line-wrapping, but avoid messing too much with other things.

While we're at it, let's handle more than just line wrapping, and do a
more general reset of stuff to get the terminal into a sane state.

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

index 11c0da870c72b24af237e199c87b6f2060f7ec5f..dda592089cb2a46bef8c02232618d22761ddf9ff 100644 (file)
@@ -306,29 +306,9 @@ int reset_terminal_fd(int fd, bool switch_to_text) {
         termios.c_cc[VMIN]   = 1;
 
         r = RET_NERRNO(tcsetattr(fd, TCSANOW, &termios));
-        if (r < 0) {
+        if (r < 0)
                 log_debug_errno(r, "Failed to set terminal parameters: %m");
-                goto finish;
-        }
-
-        if (!terminal_is_dumb()) {
-                r = fd_nonblock(fd, true);
-                if (r < 0) {
-                        log_debug_errno(r, "Failed to set terminal to non-blocking mode: %m");
-                        goto finish;
-                }
-
-                 /* Enable line wrapping. */
-                (void) loop_write_full(fd, "\033[?7h", SIZE_MAX, 50 * USEC_PER_MSEC);
 
-                if (r > 0) {
-                        r = fd_nonblock(fd, false);
-                        if (r < 0) {
-                                log_debug_errno(r, "Failed to set terminal back to blocking mode: %m");
-                                goto finish;
-                        }
-                }
-        }
 finish:
         /* Just in case, flush all crap out */
         (void) tcflush(fd, TCIOFLUSH);
@@ -1565,6 +1545,37 @@ int set_terminal_cursor_position(int fd, unsigned int row, unsigned int column)
         return 0;
 }
 
+int terminal_reset_ansi_seq(int fd) {
+        int r, k;
+
+        assert(fd >= 0);
+
+        if (getenv_terminal_is_dumb())
+                return 0;
+
+        r = fd_nonblock(fd, true);
+        if (r < 0)
+                return log_debug_errno(r, "Failed to set terminal to non-blocking mode: %m");
+
+        k = loop_write_full(fd,
+                            "\033c"        /* reset to initial state */
+                            "\033[!p"      /* soft terminal reset */
+                            "\033]104\007" /* reset colors */
+                            "\033[?7h",    /* enable line-wrapping */
+                            SIZE_MAX,
+                            50 * USEC_PER_MSEC);
+        if (k < 0)
+                log_debug_errno(k, "Failed to write to terminal: %m");
+
+        if (r > 0) {
+                r = fd_nonblock(fd, false);
+                if (r < 0)
+                        log_debug_errno(r, "Failed to set terminal back to blocking mode: %m");
+        }
+
+        return k < 0 ? k : r;
+}
+
 void termios_disable_echo(struct termios *termios) {
         assert(termios);
 
index 2596752e562e86f684feee1555d9f6375b5e28bb..ecfe574451ea48513cdc96048b6f891556a6ae3d 100644 (file)
@@ -98,6 +98,7 @@ bool isatty_safe(int fd);
 int reset_terminal_fd(int fd, bool switch_to_text);
 int reset_terminal(const char *name);
 int set_terminal_cursor_position(int fd, unsigned int row, unsigned int column);
+int terminal_reset_ansi_seq(int fd);
 
 int open_terminal(const char *name, int mode);
 
index 83a2b5b66144b373c3556a47784767b969ee1434..7362a6a82205491b7d4f1634f601a37d780e72ae 100644 (file)
@@ -208,13 +208,17 @@ static int console_setup(void) {
 
         r = proc_cmdline_tty_size("/dev/console", &rows, &cols);
         if (r < 0)
-                log_warning_errno(r, "Failed to get terminal size, ignoring: %m");
+                log_warning_errno(r, "Failed to get /dev/console size, ignoring: %m");
         else {
                 r = terminal_set_size_fd(tty_fd, NULL, rows, cols);
                 if (r < 0)
-                        log_warning_errno(r, "Failed to set terminal size, ignoring: %m");
+                        log_warning_errno(r, "Failed to set /dev/console size, ignoring: %m");
         }
 
+        r = terminal_reset_ansi_seq(tty_fd);
+        if (r < 0)
+                log_warning_errno(r, "Failed to reset /dev/console using ANSI sequences, ignoring: %m");
+
         return 0;
 }