#include "time-util.h"
#include "utf8.h"
-/* How much to wait for a reply to a terminal sequence */
-#define CONSOLE_REPLY_WAIT_USEC (333 * USEC_PER_MSEC)
+/* How much to wait when reading/writing ANSI sequences from/to the console */
+#define CONSOLE_ANSI_SEQUENCE_TIMEOUT_USEC (333 * USEC_PER_MSEC)
static volatile unsigned cached_columns = 0;
static volatile unsigned cached_lines = 0;
"\033[3J" /* clear screen including scrollback, requires Linux 2.6.40 */
"\033c", /* reset to initial state */
SIZE_MAX,
- 100 * USEC_PER_MSEC);
+ CONSOLE_ANSI_SEQUENCE_TIMEOUT_USEC);
}
static int vt_default_utf8(void) {
}
int terminal_reset_ansi_seq(int fd) {
- int r, k;
+ _cleanup_(nonblock_resetp) int nonblock_reset = -EBADF;
+ int r;
assert(fd >= 0);
r = fd_nonblock(fd, true);
if (r < 0)
return log_debug_errno(r, "Failed to set terminal to non-blocking mode: %m");
+ if (r > 0)
+ nonblock_reset = fd;
- k = loop_write_full(fd,
+ r = loop_write_full(fd,
"\033[!p" /* soft terminal reset */
ANSI_OSC "104" ANSI_ST /* reset color palette via OSC 104 */
ANSI_NORMAL /* reset colors */
"\033[1G" /* place cursor at beginning of current line */
"\033[0J", /* erase till end of screen */
SIZE_MAX,
- 100 * USEC_PER_MSEC);
- if (k < 0)
- log_debug_errno(k, "Failed to reset terminal through ANSI sequences: %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");
- }
+ CONSOLE_ANSI_SEQUENCE_TIMEOUT_USEC);
+ if (r < 0)
+ log_debug_errno(r, "Failed to reset terminal through ANSI sequences: %m");
- return k < 0 ? k : r;
+ return r;
}
void reset_dev_console_fd(int fd, bool switch_to_text) {
if (r < 0)
return r;
- usec_t end = usec_add(now(CLOCK_MONOTONIC), CONSOLE_REPLY_WAIT_USEC);
+ usec_t end = usec_add(now(CLOCK_MONOTONIC), CONSOLE_ANSI_SEQUENCE_TIMEOUT_USEC);
char buf[STRLEN("\x1B[1;1R")]; /* The shortest valid reply possible */
size_t buf_full = 0;
CursorPositionContext context = {};
if (r < 0)
return r;
- usec_t end = usec_add(now(CLOCK_MONOTONIC), CONSOLE_REPLY_WAIT_USEC);
+ usec_t end = usec_add(now(CLOCK_MONOTONIC), CONSOLE_ANSI_SEQUENCE_TIMEOUT_USEC);
char buf[STRLEN(ANSI_OSC "11;rgb:0/0/0" ANSI_ST)]; /* shortest possible reply */
size_t buf_full = 0;
BackgroundColorContext context = {};
/* Use DECSC/DECRC to save/restore cursor instead of querying position via DSR. This way the cursor
* is always restored — even on timeout — and we only need one DSR response instead of two. */
- r = loop_write(output_fd,
- "\x1B" "7" /* DECSC: save cursor position */
- "\x1B[32766;32766H" /* CUP: position cursor far to the right and to the bottom, staying within 16bit signed range */
- "\x1B[6n" /* DSR: request cursor position (CPR) */
- "\x1B" "8", /* DECRC: restore cursor position */
- SIZE_MAX);
+ r = loop_write_full(output_fd,
+ "\x1B" "7" /* DECSC: save cursor position */
+ "\x1B[32766;32766H" /* CUP: position cursor far to the right and to the bottom, staying within 16bit signed range */
+ "\x1B[6n" /* DSR: request cursor position (CPR) */
+ "\x1B" "8", /* DECRC: restore cursor position */
+ SIZE_MAX,
+ CONSOLE_ANSI_SEQUENCE_TIMEOUT_USEC);
if (r < 0)
return r;
- usec_t end = usec_add(now(CLOCK_MONOTONIC), CONSOLE_REPLY_WAIT_USEC);
+ usec_t end = usec_add(now(CLOCK_MONOTONIC), CONSOLE_ANSI_SEQUENCE_TIMEOUT_USEC);
char buf[STRLEN("\x1B[1;1R")]; /* The shortest valid reply possible */
size_t buf_full = 0;
CursorPositionContext context = {};
assert(nonblock_input_fd >= 0);
assert(output_fd >= 0);
- r = loop_write(output_fd, CSI18_Q, SIZE_MAX);
+ r = loop_write_full(output_fd, CSI18_Q, SIZE_MAX, CONSOLE_ANSI_SEQUENCE_TIMEOUT_USEC);
if (r < 0)
return r;
- usec_t end = usec_add(now(CLOCK_MONOTONIC), CONSOLE_REPLY_WAIT_USEC);
+ usec_t end = usec_add(now(CLOCK_MONOTONIC), CONSOLE_ANSI_SEQUENCE_TIMEOUT_USEC);
char buf[STRLEN(CSI18_R1)];
size_t bytes = 0;
_cleanup_close_ int nonblock_input_fd = -EBADF;
struct termios old_termios = TERMIOS_NULL;
CLEANUP_TERMIOS_RESET(nonblock_input_fd, old_termios);
+ _cleanup_(nonblock_resetp) int nonblock_reset = -EBADF;
int r;
assert(try_dsr || try_csi18);
if (r < 0)
return r;
+ /* Put the output fd in non-blocking mode with a write timeout, to avoid blocking indefinitely on
+ * write if the terminal is not consuming data (e.g. serial console with flow control). */
+ r = fd_nonblock(output_fd, true);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to set terminal to non-blocking mode: %m");
+ if (r > 0)
+ nonblock_reset = output_fd;
+
/* Flush any stale input that might confuse the response parsers. */
(void) tcflush(nonblock_input_fd, TCIFLUSH);
if (r < 0)
return r;
- usec_t end = usec_add(now(CLOCK_MONOTONIC), CONSOLE_REPLY_WAIT_USEC);
+ usec_t end = usec_add(now(CLOCK_MONOTONIC), CONSOLE_ANSI_SEQUENCE_TIMEOUT_USEC);
char buf[STRLEN(DCS_TERMINFO_R1) + MAX_TERMINFO_LENGTH + STRLEN(ANSI_ST)];
size_t bytes = 0;