From b5e199d2b237e270369f596192ac975231a181bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Tue, 25 Jun 2024 09:06:21 +0800 Subject: [PATCH] IO (Linux): make sure `stdin` and `stdout` are tty when querying terminal --- src/common/io/io_unix.c | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/src/common/io/io_unix.c b/src/common/io/io_unix.c index 501e23015..20eb3b3b0 100644 --- a/src/common/io/io_unix.c +++ b/src/common/io/io_unix.c @@ -136,29 +136,44 @@ const char* ffGetTerminalResponse(const char* request, const char* format, ...) if (instance.config.display.pipe) return "Not supported in --pipe mode"; + int fin = STDIN_FILENO, fout = STDOUT_FILENO; + FF_AUTO_CLOSE_FD int ftty = -1; + + if (!isatty(STDIN_FILENO)) + { + if (ftty < 0) + ftty = open("/dev/tty", O_RDWR | O_CLOEXEC); + fin = ftty; + } + if (!isatty(STDOUT_FILENO)) + { + if (ftty < 0) + ftty = open("/dev/tty", O_RDWR | O_CLOEXEC); + fout = ftty; + } + struct termios oldTerm, newTerm; - if(tcgetattr(STDIN_FILENO, &oldTerm) == -1) + if(tcgetattr(fin, &oldTerm) == -1) return "tcgetattr(STDIN_FILENO, &oldTerm) failed"; newTerm = oldTerm; newTerm.c_lflag &= (tcflag_t) ~(ICANON | ECHO); - if(tcsetattr(STDIN_FILENO, TCSANOW, &newTerm) == -1) + if(tcsetattr(fin, TCSANOW, &newTerm) == -1) return "tcsetattr(STDIN_FILENO, TCSANOW, &newTerm)"; - fputs(request, stdout); - fflush(stdout); + ffWriteFDData(fout, strlen(request), request); //Give the terminal 35ms to respond - if(poll(&(struct pollfd) { .fd = STDIN_FILENO, .events = POLLIN }, 1, FF_IO_TERM_RESP_WAIT_MS) <= 0) + if(poll(&(struct pollfd) { .fd = fin, .events = POLLIN }, 1, FF_IO_TERM_RESP_WAIT_MS) <= 0) { - tcsetattr(STDIN_FILENO, TCSANOW, &oldTerm); + tcsetattr(fin, TCSANOW, &oldTerm); return "poll() timeout or failed"; } char buffer[512]; - ssize_t bytesRead = read(STDIN_FILENO, buffer, sizeof(buffer) - 1); + ssize_t bytesRead = read(fin, buffer, sizeof(buffer) - 1); - tcsetattr(STDIN_FILENO, TCSANOW, &oldTerm); + tcsetattr(fin, TCSANOW, &oldTerm); if(bytesRead <= 0) return "read(STDIN_FILENO, buffer, sizeof(buffer) - 1) failed";