diff options
| author | Marc André Tanner <mat@brain-dump.org> | 2016-11-15 20:43:48 +0100 |
|---|---|---|
| committer | Marc André Tanner <mat@brain-dump.org> | 2016-11-16 23:52:33 +0100 |
| commit | 813133186ef4023f16c24cf307917e4ba58a76bd (patch) | |
| tree | 9640a22b4deb3af14d5c1a68da5e16040a4336cb /ui-curses.c | |
| parent | bab044b8fda309b36b21e6afaa7a91d67a974d26 (diff) | |
| download | vis-813133186ef4023f16c24cf307917e4ba58a76bd.tar.gz vis-813133186ef4023f16c24cf307917e4ba58a76bd.tar.xz | |
ui: work around libtermkey bug when stdin is /dev/null
Libtermkey tries to write a terminal initialization sequence even when
stdin is not a terminal as is the case when running `vis < /dev/null`
or within the Travis CI environment.
The broken code is in libtermkey's driver-ti.c function `start_driver`:
/* There's no point trying to write() to a pipe */
if(fstat(tk->fd, &statbuf) == -1)
return 0;
if(S_ISFIFO(statbuf.st_mode))
return 1;
Instead they should simply be using isatty(3).
As a workaround we catch the resulting EBADF failure and try to re-open
/dev/tty as stdin. If this fails too (as is the case in the Mac OS X
Travis CI runner) create an abstract termkey instance instead. In this
state vis will not be able to consume any input and will instead spin
with 100% CPU usage in the mainloop. This is solely done to make the Lua
tests, which control vis through other means, work within the Travis CI
environment.
Diffstat (limited to 'ui-curses.c')
| -rw-r--r-- | ui-curses.c | 56 |
1 files changed, 36 insertions, 20 deletions
diff --git a/ui-curses.c b/ui-curses.c index b1972da..9042f82 100644 --- a/ui-curses.c +++ b/ui-curses.c @@ -15,6 +15,7 @@ #include <sys/stat.h> #include <fcntl.h> #include <termios.h> +#include <errno.h> #include "ui-curses.h" #include "vis.h" @@ -1055,6 +1056,18 @@ static TermKey *ui_termkey_new(int fd) { return termkey; } +static TermKey *ui_termkey_reopen(Ui *ui, int fd) { + int tty = open("/dev/tty", O_RDWR); + if (tty == -1) + return NULL; + if (tty != fd && dup2(tty, fd) == -1) { + close(tty); + return NULL; + } + close(tty); + return ui_termkey_new(fd); +} + static TermKey *ui_termkey_get(Ui *ui) { UiCurses *uic = (UiCurses*)ui; return uic->termkey; @@ -1070,18 +1083,11 @@ static bool ui_getkey(Ui *ui, TermKeyKey *key) { TermKeyResult ret = termkey_getkey(uic->termkey, key); if (ret == TERMKEY_RES_EOF) { - int tty = open("/dev/tty", O_RDWR); - if (tty == -1) - goto fatal; - if (tty != STDIN_FILENO && dup2(tty, STDIN_FILENO) == -1) { - close(tty); - goto fatal; - } - close(tty); termkey_destroy(uic->termkey); - if (!(uic->termkey = ui_termkey_new(STDIN_FILENO))) - goto fatal; - return NULL; + errno = 0; + if (!(uic->termkey = ui_termkey_reopen(ui, STDIN_FILENO))) + ui_die_msg(ui, "Failed to re-open stdin as /dev/tty: %s\n", errno != 0 ? strerror(errno) : ""); + return false; } if (ret == TERMKEY_RES_AGAIN) { @@ -1093,9 +1099,6 @@ static bool ui_getkey(Ui *ui, TermKeyKey *key) { } return ret == TERMKEY_RES_KEY; -fatal: - ui_die_msg(ui, "Failed to re-open stdin as /dev/tty\n"); - return false; } static void ui_terminal_save(Ui *ui) { @@ -1120,15 +1123,28 @@ static int ui_colors(Ui *ui) { static bool ui_init(Ui *ui, Vis *vis) { UiCurses *uic = (UiCurses*)ui; uic->vis = vis; - tcgetattr(STDERR_FILENO, &uic->tio); - if (!(uic->termkey = ui_termkey_new(STDIN_FILENO))) - goto err; + setlocale(LC_CTYPE, ""); - if (!getenv("ESCDELAY")) - set_escdelay(50); + char *term = getenv("TERM"); if (!term) term = "xterm"; + + tcgetattr(STDERR_FILENO, &uic->tio); + errno = 0; + if (!(uic->termkey = ui_termkey_new(STDIN_FILENO))) { + /* work around libtermkey bug which fails if stdin is /dev/null */ + if (errno == EBADF && !isatty(STDIN_FILENO)) { + errno = 0; + if (!(uic->termkey = ui_termkey_reopen(ui, STDIN_FILENO)) && errno == ENXIO) + uic->termkey = termkey_new_abstract(term, TERMKEY_FLAG_UTF8); + } + if (!uic->termkey) + goto err; + } + + if (!getenv("ESCDELAY")) + set_escdelay(50); if (!newterm(term, stderr, stdin)) { snprintf(uic->info, sizeof(uic->info), "Warning: unknown term `%s'", term); if (!newterm(strstr(term, "-256color") ? "xterm-256color" : "xterm", stderr, stdin)) @@ -1154,7 +1170,7 @@ static bool ui_init(Ui *ui, Vis *vis) { return true; err: - ui_die_msg(ui, "Failed to start curses interface\n"); + ui_die_msg(ui, "Failed to start curses interface: %s\n", errno != 0 ? strerror(errno) : ""); return false; } |
