From a2e0b6901cb4eef7ad1d78bee0d70c577c61e0f5 Mon Sep 17 00:00:00 2001 From: Curtis McEnroe Date: Sun, 25 Feb 2018 19:16:56 -0500 Subject: Rewrite everything --- view.c | 177 ++++++++++++++++++++++++++++++----------------------------------- 1 file changed, 82 insertions(+), 95 deletions(-) (limited to 'view.c') diff --git a/view.c b/view.c index 9ae0ec6..47c6c5b 100644 --- a/view.c +++ b/view.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, Curtis McEnroe +/* Copyright (C) 2018 Causal Agent June * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by @@ -19,10 +19,6 @@ #include #include #include -#include -#include -#include -#include #include #include #include @@ -30,133 +26,124 @@ #include #include -static struct termios saveTerm; -static void restoreTerm(void) { - tcsetattr(STDOUT_FILENO, TCSADRAIN, &saveTerm); -} +extern int winch(void); static struct { - int read; - int write; -} winch; - -static void sigwinch() { - struct winsize localWindow; - int error = ioctl(STDERR_FILENO, TIOCGWINSZ, &localWindow); - if (error) err(EX_IOERR, "ioctl(%d, TIOCGWINSZ, ...)", STDERR_FILENO); - - ssize_t size = write(winch.write, &localWindow, sizeof(localWindow)); - if (size < 0) err(EX_IOERR, "write(%d)", winch.write); - if ((size_t)size < sizeof(localWindow)) { - errx(EX_IOERR, "short write(%d)", winch.write); - } -} + int winch; + int remote; + int local; + int input; +} fd = { -1, -1, STDOUT_FILENO, STDIN_FILENO }; -static struct winsize remoteWindow; -static void readRemoteWindow(int remote) { - ssize_t size = read(remote, &remoteWindow, sizeof(remoteWindow)); - if (size < 0) err(EX_IOERR, "read(%d)", remote); - if ((size_t)size < sizeof(remoteWindow)) errx(EX_IOERR, "short read(%d)", remote); +static struct termios saveTerm; +static void restoreTerm(void) { + tcsetattr(fd.input, TCSADRAIN, &saveTerm); } int main(int argc, char *argv[]) { int error; - if (argc < 2) return EX_USAGE; - const char *path = argv[1]; + if (argc < 2) errx(EX_USAGE, "missing public id"); + if (!isatty(fd.local)) errx(EX_USAGE, "no terminal (use ssh -t)"); - int input = STDIN_FILENO; - int local = STDOUT_FILENO; + const char *path = argv[1]; + fd.remote = open(path, O_RDONLY); + if (fd.remote < 0) err(EX_NOINPUT, "%s", path); - error = tcgetattr(local, &saveTerm); + error = tcgetattr(fd.input, &saveTerm); if (error) err(EX_IOERR, "tcgetattr"); atexit(restoreTerm); struct termios term = saveTerm; term.c_lflag &= ~(ICANON | ECHO); - error = tcsetattr(local, TCSADRAIN, &term); + error = tcsetattr(fd.input, TCSADRAIN, &term); if (error) err(EX_IOERR, "tcsetattr"); - error = pipe((int *)&winch); - if (error) err(EX_OSERR, "pipe"); - signal(SIGWINCH, sigwinch); - sigwinch(); - - int remote = open(path, O_RDONLY); - if (remote < 0) err(EX_NOINPUT, "%s", path); - readRemoteWindow(remote); + struct winsize localWindow; + error = ioctl(fd.local, TIOCGWINSZ, &localWindow); + if (error) err(EX_IOERR, "TIOCGWINSZ"); + fd.winch = winch(); int kq = kqueue(); if (kq < 0) err(EX_OSERR, "kqueue"); struct kevent events[3] = { - { .ident = winch.read, .filter = EVFILT_READ, .flags = EV_ADD }, - { .ident = input, .filter = EVFILT_READ, .flags = EV_ADD }, - { .ident = remote, .filter = EVFILT_READ, .flags = EV_ADD }, + { .ident = fd.input, .filter = EVFILT_READ, .flags = EV_ADD }, + { .ident = fd.remote, .filter = EVFILT_READ, .flags = EV_ADD }, + { .ident = fd.winch, .filter = EVFILT_READ, .flags = EV_ADD }, }; int nevents = kevent(kq, events, 3, NULL, 0, NULL); if (nevents < 0) err(EX_OSERR, "kevent"); - char buf[4096]; - bool truncated = false; for (;;) { - struct kevent event; - int nevents = kevent(kq, NULL, 0, &event, 1, NULL); - if (nevents < 0) { - if (errno == EINTR) continue; - err(EX_OSERR, "kevent"); + off_t off = lseek(fd.remote, 0, SEEK_SET); + if (off < 0) err(EX_IOERR, "%s", path); + + // FIXME: Hack spin waiting for remote window. + struct winsize remoteWindow; + ssize_t size; + for (int i = 0; i < 100; ++i, usleep(100)) { + size = read(fd.remote, &remoteWindow, sizeof(remoteWindow)); + if (size < 0) err(EX_IOERR, "read(%d)", fd.remote); + if (size) break; } - if (!nevents) continue; - - if (event.ident == (uintptr_t)winch.read) { - for (;;) { - struct winsize localWindow; - ssize_t size = read(winch.read, &localWindow, sizeof(localWindow)); - if (size < 0) err(EX_IOERR, "read(%d)", winch.read); - if ((size_t)size < sizeof(localWindow)) { - errx(EX_IOERR, "short read(%d)", winch.read); - } - - if ( - localWindow.ws_col == remoteWindow.ws_col - && localWindow.ws_row == remoteWindow.ws_row - ) break; - - warnx( - "Please resize your terminal %hux%hu -> %hux%hu", - localWindow.ws_col, localWindow.ws_row, - remoteWindow.ws_col, remoteWindow.ws_row - ); - } + if ((size_t)size < sizeof(remoteWindow)) { + errx(EX_DATAERR, "no window size (stream not started)"); } - if (event.ident == (uintptr_t)input) { - ssize_t size = read(input, buf, sizeof(buf)); - if (size < 0) err(EX_IOERR, "read(%d)", input); - if (size == 1 && buf[0] == 'q') return EX_OK; + if ( + localWindow.ws_col < remoteWindow.ws_col + || localWindow.ws_row < remoteWindow.ws_row + ) { + warnx( + "resize window %hux%hu to at least %hux%hu", + localWindow.ws_col, localWindow.ws_row, + remoteWindow.ws_col, remoteWindow.ws_row + ); + + ssize_t size = read(fd.winch, &localWindow, sizeof(localWindow)); + if (size < 0) err(EX_IOERR, "read(%d)", fd.winch); + if ((size_t)size < sizeof(localWindow)) { + errx(EX_IOERR, "short read(%d)", fd.winch); + } + continue; } - if (event.ident == (uintptr_t)remote) { - if (event.data < 0) { - off_t offset = lseek(remote, 0, SEEK_SET); - if (offset < 0) err(EX_IOERR, "lseek(%d)", remote); - truncated = true; - continue; + char buf[4096]; + for (;;) { + struct kevent event; + int nevents = kevent(kq, NULL, 0, &event, 1, NULL); + if (nevents < 0) { + if (errno == EINTR) continue; + err(EX_OSERR, "kevent"); } + if (!nevents) continue; - if (truncated) { - readRemoteWindow(remote); - sigwinch(); - truncated = false; - continue; + if (event.ident == (uintptr_t)fd.input) { + ssize_t size = read(fd.input, buf, sizeof(buf)); + if (size < 0) err(EX_IOERR, "read(%d)", fd.input); + if (size == 1 && buf[0] == 'q') return EX_OK; } - ssize_t readSize = read(remote, buf, sizeof(buf)); - if (readSize < 0) err(EX_IOERR, "read(%d)", remote); + if (event.ident == (uintptr_t)fd.remote) { + if (event.data < 0) break; - ssize_t writeSize = write(local, buf, readSize); - if (writeSize < 0) err(EX_IOERR, "write(%d)", local); - if (writeSize < readSize) errx(EX_IOERR, "short write(%d)", local); + ssize_t readSize = read(fd.remote, buf, sizeof(buf)); + if (readSize < 0) err(EX_IOERR, "read(%d)", fd.remote); + + ssize_t writeSize = write(fd.local, buf, readSize); + if (writeSize < 0) err(EX_IOERR, "write(%d)", fd.local); + if (writeSize < readSize) errx(EX_IOERR, "short write(%d)", fd.local); + } + + if (event.ident == (uintptr_t)fd.winch) { + ssize_t size = read(fd.winch, &localWindow, sizeof(localWindow)); + if (size < 0) err(EX_IOERR, "read(%d)", fd.winch); + if ((size_t)size < sizeof(localWindow)) { + errx(EX_IOERR, "short read(%d)", fd.winch); + } + break; + } } } } -- cgit 1.4.1