vtwrap

Fake ptty allocator
git clone https://git.sinitax.com/sinitax/vtwrap
Log | Files | Refs | LICENSE | sfeed.txt

commit a760023437c0cf376ca3b030972009c48f3a7dee
Author: Louis Burda <quent.burda@gmail.com>
Date:   Sun, 12 Nov 2023 22:45:44 +0100

Initial prototype

Diffstat:
A.gitignore | 1+
ALICENSE | 21+++++++++++++++++++++
AMakefile | 21+++++++++++++++++++++
Aapty.c | 135+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 178 insertions(+), 0 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -0,0 +1 @@ +apty diff --git a/LICENSE b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Louis Burda + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Makefile b/Makefile @@ -0,0 +1,21 @@ +ifeq ($(DEBUG), 1) +CFLAGS = -Og -g +else +CFLAGS = -O2 +endif + +.PHONY: all clean install uninstall + +all: apty + +apty: apty.c + $(CC) -o $@ $< $(CFLAGS) $(EXTRA_CFLAGS) + +clean: + rm -f apty + +install: + install -m755 apty -t "$(DESTDIR)$(PREFIX)$(BINDIR)" + +uninstall: + rm -f "$(DESTDIR)$(PREFIX)$(BINDIR)/apty" diff --git a/apty.c b/apty.c @@ -0,0 +1,135 @@ +#define _XOPEN_SOURCE 600 +#define _DEFAULT_SOURCE + +#include <sys/select.h> +#include <sys/wait.h> +#include <sys/epoll.h> +#include <fcntl.h> +#include <termios.h> +#include <unistd.h> +#include <pty.h> +#include <err.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <stdbool.h> +#include <stdlib.h> + +#define MAX_EVENTS 10 + +static char buf[BUFSIZ] = { 0 }; + +static int +writeall(int fd, char *buffer, size_t size) +{ + ssize_t nbytes; + + while (size) { + nbytes = write(fd, buffer, size); + if (nbytes <= 0) return 1; + buffer += nbytes; + size -= nbytes; + } + + return 0; +} + +static int +fwd(int in, int out) +{ + static char buffer[8194]; + ssize_t got, i, last; + + do { + got = read(in, buffer, sizeof(buffer)); + if (got < 0) return 1; + + if (writeall(out, buffer, got)) + return 1; + } while (got == sizeof(buffer)); + + return 0; +} + +static void +mitm(int pts) +{ + fd_set fds; + + while (1) { + FD_ZERO(&fds); + FD_SET(0, &fds); + FD_SET(pts, &fds); + + //fprintf(stderr, "?\n"); + if (select(pts + 1, &fds, 0, 0, 0) == -1) { + if (errno == EINTR) continue; + return; + } + + //fprintf(stderr, "!\n"); + + if (FD_ISSET(0, &fds)) { /* stdin -> ptty */ + if (fwd(0, pts)) return; + } + + if (FD_ISSET(pts, &fds)) { /* ptty -> stdout + pipe */ + if (fwd(pts, 1)) return; + } + } +} + +int +main(int argc, char **argv) +{ + char **arg, **cmd; + struct termios termios = {0}; + struct winsize winsize = {0}; + int exitcode; + int master, tty; + pid_t child; + + if (argc <= 1) errx(1, "missing args"); + + winsize.ws_col = 120; + winsize.ws_row = 80; + cfmakeraw(&termios); + + if (isatty(0)) { + if (ioctl(0, TIOCGWINSZ, &winsize)) + err(1, "tcgetwinsize"); + + if (tcgetattr(0, &termios)) + err(1, "tcgettattr"); + termios.c_lflag &= ~ICANON; + if (tcsetattr(0, TCSANOW, &termios)) + err(1, "tcsetattr"); + } + + for (arg = argv + 1; *arg; arg++) { + if (!strcmp(*arg, "-w") || !strcmp(*arg, "--width")) + winsize.ws_col = atoi(*++arg); + else if (!strcmp(*arg, "-h") || !strcmp(*arg, "--height")) + winsize.ws_row = atoi(*++arg); + else + break; + } + + if (!*arg) errx(1, "missing command"); + cmd = arg; + + child = forkpty(&master, NULL, &termios, &winsize); + if (child < 0) err(1, "fork"); + + if (child == 0) { + execvp(*cmd, cmd); + err(1, "execvp %s", *cmd); + } else { + mitm(master); + + waitpid(child, &exitcode, 0); + close(master); + } + + return exitcode; +}