commit a760023437c0cf376ca3b030972009c48f3a7dee
Author: Louis Burda <quent.burda@gmail.com>
Date: Sun, 12 Nov 2023 22:45:44 +0100
Initial prototype
Diffstat:
A | .gitignore | | | 1 | + |
A | LICENSE | | | 21 | +++++++++++++++++++++ |
A | Makefile | | | 21 | +++++++++++++++++++++ |
A | apty.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;
+}