From 6b8da827224f0efe27fd15ac069a98f77a5b7b27 Mon Sep 17 00:00:00 2001 From: Boris Faure Date: Sun, 5 Apr 2020 15:50:12 +0200 Subject: [PATCH] tycommon: ensure common tools are running in terminology This is done by reading the tertiary device attributes and expecting terminology's value. --- src/bin/tycommon.c | 113 +++++++++++++++++++++++++++++++++++++++++---- src/bin/tycommon.h | 4 +- 2 files changed, 107 insertions(+), 10 deletions(-) diff --git a/src/bin/tycommon.c b/src/bin/tycommon.c index 18776374..7503eeaa 100644 --- a/src/bin/tycommon.c +++ b/src/bin/tycommon.c @@ -1,20 +1,117 @@ #include "private.h" #include +#include #include +#include +#include +#include +#include +#include #include #include "tycommon.h" - +/* returns 0 if running in terminology, something else otherwise */ int -is_running_in_terminology(void) +expect_running_in_terminology(void) { - if (!getenv("TERMINOLOGY")) return 0; - // Terminology's escape codes do not got through tmux - if (getenv("TMUX")) return 0; - // Terminology's escape codes do not got through screen - if (getenv("STY")) return 0; + char buf[32]; + ssize_t len = 0; + const char *expected = "\033P!|7E7E5459\033\\"; + const char *pos = expected; + fd_set readset; + struct timeval tv; + struct termios ttystate, ttysave; + int res = -1; - return 1; + /* get current terminal state */ + if (tcgetattr(STDIN_FILENO, &ttystate)) + { + perror("tcgetattr"); + return -1; + } + ttysave = ttystate; + + /* turn off canonical (buffered) mode and echo */ + ttystate.c_lflag &= ~(ICANON | ECHO); + /* minimum of number input read: 1 byte. */ + ttystate.c_cc[VMIN] = 1; + ttystate.c_cc[VTIME] = 0; + + /* set new terminal attributes */ + if (tcsetattr(STDIN_FILENO, TCSANOW, &ttystate)) + { + perror("tcsetattr"); + return -1; + } + + /* Query device attributes 3 */ + buf[0] = '\033'; + buf[1] = '['; + buf[2] = '='; + buf[3] = 'c'; + len = ty_write(STDOUT_FILENO, buf, 4); + if (len != 4) + { + perror("write"); + res = -1; + goto end; + } + + while (pos != (expected + strlen(expected))) + { + /* wait up to 1 second */ + tv.tv_sec = 1; + tv.tv_usec = 0; + + FD_ZERO(&readset); + FD_SET(STDIN_FILENO, &readset); + + errno = 0; + if (select(1, &readset, NULL, NULL, &tv) < 0) + { + perror("select"); + res = -1; + goto end; + } + + if (FD_ISSET(STDIN_FILENO, &readset)) + { + len = read(STDIN_FILENO, buf, 1); + if (len != 1) + { + perror("read"); + res = -1; + goto end; + } + + if (buf[0] == *pos) + pos++; + else if (pos == expected) + continue; + else + { + res = -1; + goto end; + } + } + else + { + res = -1; + goto end; + } + } + res = 0; + +end: + + /* restore attributes */ + if (tcsetattr(STDIN_FILENO, TCSANOW, &ttysave)) + { + perror("tcsetattr"); + return -1; + } + + return res; } ssize_t diff --git a/src/bin/tycommon.h b/src/bin/tycommon.h index d5bf90e6..7688b3ac 100644 --- a/src/bin/tycommon.h +++ b/src/bin/tycommon.h @@ -1,13 +1,13 @@ #ifndef _TY_COMMON_H__ #define _TY_COMMON_H__ 1 -int is_running_in_terminology(void); +int expect_running_in_terminology(void); ssize_t ty_write(int fd, const void *buf, size_t count); #define ON_NOT_RUNNING_IN_TERMINOLOGY_EXIT_1() \ do \ { \ - if (!is_running_in_terminology()) \ + if (expect_running_in_terminology() != 0) \ { \ fprintf(stderr, "not directly running in terminology\n"); \ exit(1); \