diff options
-rw-r--r-- | bin/.gitignore | 1 | ||||
-rw-r--r-- | bin/Makefile | 2 | ||||
-rw-r--r-- | bin/README | 4 | ||||
-rw-r--r-- | bin/modem.c | 101 |
4 files changed, 107 insertions, 1 deletions
diff --git a/bin/.gitignore b/bin/.gitignore index c84d690b..4e9c104e 100644 --- a/bin/.gitignore +++ b/bin/.gitignore @@ -6,6 +6,7 @@ dtch gfxx glitch hnel +modem pbcopy pbd pbpaste diff --git a/bin/Makefile b/bin/Makefile index 685ea6f0..92c02f26 100644 --- a/bin/Makefile +++ b/bin/Makefile @@ -1,4 +1,4 @@ -ANY_BINS = atch brot dtch gfxx glitch hnel pbcopy pbd pbpaste pngo scheme wake xx +ANY_BINS = atch brot dtch gfxx glitch hnel modem pbcopy pbd pbpaste pngo scheme wake xx BSD_BINS = klon watch LIN_BINS = bri fbatt fbclock ALL_BINS = $(ANY_BINS) $(BSD_BINS) $(LIN_BINS) diff --git a/bin/README b/bin/README index c15f6f5a..0ea3970a 100644 --- a/bin/README +++ b/bin/README @@ -96,6 +96,10 @@ Klondike solitaire for curses. BSD-only for arc4random_uniform. 1-7 tableau ^M auto-foundation + modem + +PTY wrapper with a fixed baud rate of 19.2 kbps. + pbd/pbcopy/pbpaste TCP server which pipes into macOS pbcopy(1) and from pbpaste(1), and diff --git a/bin/modem.c b/bin/modem.c new file mode 100644 index 00000000..11b447ea --- /dev/null +++ b/bin/modem.c @@ -0,0 +1,101 @@ +/* Copyright (C) 2018 June McEnroe <june@causal.agency> + * + * 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 + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <err.h> +#include <poll.h> +#include <stdlib.h> +#include <sys/ioctl.h> +#include <sys/wait.h> +#include <sysexits.h> +#include <termios.h> +#include <unistd.h> + +#if defined __FreeBSD__ +#include <libutil.h> +#elif defined __linux__ +#include <pty.h> +#else +#include <util.h> +#endif + +static const int BAUD_RATE = 19200; + +static struct termios saveTerm; +static void restoreTerm(void) { + tcsetattr(STDIN_FILENO, TCSADRAIN, &saveTerm); +} + +int main(int argc, char *argv[]) { + int error; + + if (argc < 2) return EX_USAGE; + + error = tcgetattr(STDIN_FILENO, &saveTerm); + if (error) err(EX_IOERR, "tcgetattr"); + atexit(restoreTerm); + + struct termios raw; + cfmakeraw(&raw); + error = tcsetattr(STDIN_FILENO, TCSADRAIN, &raw); + if (error) err(EX_IOERR, "tcsetattr"); + + struct winsize window; + error = ioctl(STDIN_FILENO, TIOCGWINSZ, &window); + if (error) err(EX_IOERR, "TIOCGWINSZ"); + + int pty; + pid_t pid = forkpty(&pty, NULL, NULL, &window); + if (pid < 0) err(EX_OSERR, "forkpty"); + + if (!pid) { + execvp(argv[1], &argv[1]); + err(EX_NOINPUT, "%s", argv[1]); + } + + for (;;) { + usleep(8 * 1000000 / BAUD_RATE); + + struct pollfd fds[2] = { + { .events = POLLIN, .fd = STDIN_FILENO }, + { .events = POLLIN, .fd = pty }, + }; + int n = poll(fds, 2, -1); + if (n < 0) err(EX_IOERR, "poll"); + + if (fds[0].revents) { + char c; + ssize_t size = read(STDIN_FILENO, &c, 1); + if (size < 0) err(EX_IOERR, "read(%d)", STDIN_FILENO); + + size = write(pty, &c, 1); + if (size < 0) err(EX_IOERR, "write(%d)", pty); + } + + if (fds[1].revents) { + char c; + ssize_t size = read(pty, &c, 1); + if (size < 0) err(EX_IOERR, "read(%d)", pty); + + size = write(STDOUT_FILENO, &c, 1); + if (size < 0) err(EX_IOERR, "write(%d)", STDOUT_FILENO); + } + + int status; + pid_t dead = waitpid(pid, &status, WNOHANG); + if (dead < 0) err(EX_OSERR, "waitpid"); + if (dead) return WIFEXITED(status) ? WEXITSTATUS(status) : EX_SOFTWARE; + } +} |