1
0
mirror of https://github.com/systemd/systemd.git synced 2025-01-03 05:18:09 +03:00

terminal-util: temporarily turn on nonblocking mode when waiting for ANSI seq responses

We never know, maybe there's some spurious POLLIN and read() will fail
with EAGAIN even though we saw POLLIN. Handle that.

(this can happen if we area not the only process reading from the tty,
or in case of hups and such).

Fixes: #35499
This commit is contained in:
Lennart Poettering 2024-12-13 20:11:35 +01:00
parent 9914b95a3f
commit a0c314d6b0

View File

@ -1900,6 +1900,7 @@ static int scan_background_color_response(
} }
int get_default_background_color(double *ret_red, double *ret_green, double *ret_blue) { int get_default_background_color(double *ret_red, double *ret_green, double *ret_blue) {
_cleanup_close_ int nonblock_input_fd = -EBADF;
int r; int r;
assert(ret_red); assert(ret_red);
@ -1933,6 +1934,13 @@ int get_default_background_color(double *ret_red, double *ret_green, double *ret
if (r < 0) if (r < 0)
goto finish; goto finish;
/* Open a 2nd input fd, in non-blocking mode, so that we won't ever hang in read() should someone
* else process the POLLIN. */
nonblock_input_fd = fd_reopen(STDIN_FILENO, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
if (nonblock_input_fd < 0)
return nonblock_input_fd;
usec_t end = usec_add(now(CLOCK_MONOTONIC), 333 * USEC_PER_MSEC); usec_t end = usec_add(now(CLOCK_MONOTONIC), 333 * USEC_PER_MSEC);
char buf[STRLEN(ANSI_OSC "11;rgb:0/0/0" ANSI_ST)]; /* shortest possible reply */ char buf[STRLEN(ANSI_OSC "11;rgb:0/0/0" ANSI_ST)]; /* shortest possible reply */
size_t buf_full = 0; size_t buf_full = 0;
@ -1941,13 +1949,12 @@ int get_default_background_color(double *ret_red, double *ret_green, double *ret
for (bool first = true;; first = false) { for (bool first = true;; first = false) {
if (buf_full == 0) { if (buf_full == 0) {
usec_t n = now(CLOCK_MONOTONIC); usec_t n = now(CLOCK_MONOTONIC);
if (n >= end) { if (n >= end) {
r = -EOPNOTSUPP; r = -EOPNOTSUPP;
goto finish; goto finish;
} }
r = fd_wait_for_event(STDIN_FILENO, POLLIN, usec_sub_unsigned(end, n)); r = fd_wait_for_event(nonblock_input_fd, POLLIN, usec_sub_unsigned(end, n));
if (r < 0) if (r < 0)
goto finish; goto finish;
if (r == 0) { if (r == 0) {
@ -1958,8 +1965,10 @@ int get_default_background_color(double *ret_red, double *ret_green, double *ret
/* On the first try, read multiple characters, i.e. the shortest valid /* On the first try, read multiple characters, i.e. the shortest valid
* reply. Afterwards read byte-wise, since we don't want to read too much, and * reply. Afterwards read byte-wise, since we don't want to read too much, and
* unnecessarily drop too many characters from the input queue. */ * unnecessarily drop too many characters from the input queue. */
ssize_t l = read(STDIN_FILENO, buf, first ? sizeof(buf) : 1); ssize_t l = read(nonblock_input_fd, buf, first ? sizeof(buf) : 1);
if (l < 0) { if (l < 0) {
if (errno == EAGAIN)
continue;
r = -errno; r = -errno;
goto finish; goto finish;
} }
@ -2083,6 +2092,8 @@ int terminal_get_size_by_dsr(
unsigned *ret_rows, unsigned *ret_rows,
unsigned *ret_columns) { unsigned *ret_columns) {
_cleanup_close_ int nonblock_input_fd = -EBADF;
assert(input_fd >= 0); assert(input_fd >= 0);
assert(output_fd >= 0); assert(output_fd >= 0);
@ -2130,6 +2141,13 @@ int terminal_get_size_by_dsr(
if (r < 0) if (r < 0)
goto finish; goto finish;
/* Open a 2nd input fd, in non-blocking mode, so that we won't ever hang in read() should someone
* else process the POLLIN. */
nonblock_input_fd = fd_reopen(input_fd, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
if (nonblock_input_fd < 0)
return nonblock_input_fd;
usec_t end = usec_add(now(CLOCK_MONOTONIC), 333 * USEC_PER_MSEC); usec_t end = usec_add(now(CLOCK_MONOTONIC), 333 * USEC_PER_MSEC);
char buf[STRLEN("\x1B[1;1R")]; /* The shortest valid reply possible */ char buf[STRLEN("\x1B[1;1R")]; /* The shortest valid reply possible */
size_t buf_full = 0; size_t buf_full = 0;
@ -2138,13 +2156,12 @@ int terminal_get_size_by_dsr(
for (bool first = true;; first = false) { for (bool first = true;; first = false) {
if (buf_full == 0) { if (buf_full == 0) {
usec_t n = now(CLOCK_MONOTONIC); usec_t n = now(CLOCK_MONOTONIC);
if (n >= end) { if (n >= end) {
r = -EOPNOTSUPP; r = -EOPNOTSUPP;
goto finish; goto finish;
} }
r = fd_wait_for_event(input_fd, POLLIN, usec_sub_unsigned(end, n)); r = fd_wait_for_event(nonblock_input_fd, POLLIN, usec_sub_unsigned(end, n));
if (r < 0) if (r < 0)
goto finish; goto finish;
if (r == 0) { if (r == 0) {
@ -2155,8 +2172,11 @@ int terminal_get_size_by_dsr(
/* On the first try, read multiple characters, i.e. the shortest valid /* On the first try, read multiple characters, i.e. the shortest valid
* reply. Afterwards read byte-wise, since we don't want to read too much, and * reply. Afterwards read byte-wise, since we don't want to read too much, and
* unnecessarily drop too many characters from the input queue. */ * unnecessarily drop too many characters from the input queue. */
ssize_t l = read(input_fd, buf, first ? sizeof(buf) : 1); ssize_t l = read(nonblock_input_fd, buf, first ? sizeof(buf) : 1);
if (l < 0) { if (l < 0) {
if (errno == EAGAIN)
continue;
r = -errno; r = -errno;
goto finish; goto finish;
} }