From d98e8d43a8f259f14ba8fbe6600d5f60b626fa29 Mon Sep 17 00:00:00 2001 From: neauoire Date: Sat, 11 Nov 2023 09:17:24 -0800 Subject: [PATCH] (console) Added tools to spawn unix process --- makefile | 6 +- src/devices/console.c | 185 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 181 insertions(+), 10 deletions(-) diff --git a/makefile b/makefile index e57094b..e8fc9ee 100644 --- a/makefile +++ b/makefile @@ -29,8 +29,8 @@ clean: @ rm -f bin/uxnasm bin/uxncli bin/uxn11 bin/polycat.rom bin/polycat.rom.sym bin/uxnasm: src/uxnasm.c - @ cc ${RELEASE_flags} src/uxnasm.c -o bin/uxnasm + @ cc ${RELEASE_flags} ${CFLAGS} src/uxnasm.c -o bin/uxnasm bin/uxncli: ${CLI_src} src/uxncli.c - @ cc ${RELEASE_flags} ${CLI_src} src/uxncli.c -pthread -o bin/uxncli + @ cc ${RELEASE_flags} ${CFLAGS} ${CLI_src} src/uxncli.c -lutil -pthread -o bin/uxncli bin/uxn11: ${EMU_src} src/uxn11.c - @ cc ${RELEASE_flags} ${EMU_src} src/uxn11.c -lX11 -pthread -o bin/uxn11 + @ cc ${RELEASE_flags} ${CFLAGS} ${EMU_src} src/uxn11.c -lX11 -lutil -pthread -o bin/uxn11 diff --git a/src/devices/console.c b/src/devices/console.c index 9b5d2b5..4e9e5fa 100644 --- a/src/devices/console.c +++ b/src/devices/console.c @@ -1,5 +1,21 @@ +#undef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200112L + +#include #include #include +#include +#include +#include + +#ifdef __linux +#include +#endif + +#ifdef __NetBSD__ +#include +#include +#endif #include "../uxn.h" #include "console.h" @@ -15,6 +31,54 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE. */ +/* process */ +static char *fork_args[32]; +static pid_t child_pid; +static int child_mode; +static int pty_fd; +static int to_child_fd[2]; +static int from_child_fd[2]; +static int saved_in; +static int saved_out; + +static void +parse_args(Uint8 *d, Uxn *u) +{ + int addr = (d[0x3] << 8) | d[0x4]; + char *pos = (char *)&u->ram[addr]; + int i = 0; + do { + fork_args[i++] = pos; + while (*pos != 0) pos++; + pos++; + } while (*pos != '\0'); + fork_args[i] = NULL; +} + +/* call after we're sure the process has exited */ +static void +clean_after_child() +{ + child_pid = 0; + if (child_mode >= 0x80) { + close(pty_fd); + dup2(saved_in, 0); + dup2(saved_out, 1); + } else { + if (child_mode & 0x01) { + close(to_child_fd[1]); + dup2(saved_out, 1); + } + if (child_mode & 0x06) { + close(from_child_fd[0]); + dup2(saved_in, 0); + } + } + child_mode = 0; + saved_in = -1; + saved_out = -1; +} + int console_input(Uxn *u, char c, int type) { @@ -34,22 +98,129 @@ console_listen(Uxn *u, int i, int argc, char **argv) } } -void -start_fork(Uxn *u, Uint8 *d) +static void +start_fork_pty(Uint8 *d, Uxn *u) { - /* TODO */ + int fd = -1; + pid_t pid = forkpty(&fd, NULL, NULL, NULL); + if (pid < 0) { /* failure */ + d[0x6] = 0xff; + fprintf(stderr, "fork failure\n"); + } else if (pid == 0) { /* child */ + setenv("TERM", "ansi", 1); + execvp(fork_args[0], fork_args); + d[0x6] = 0xff; + fprintf(stderr, "exec failure\n"); + } else { /*parent*/ + child_pid = pid; + pty_fd = fd; + struct winsize ws = {24, 80, 8, 12}; + ioctl(fd, TIOCSWINSZ, &ws); + saved_in = dup(0); + saved_out = dup(1); + dup2(fd, 0); + dup2(fd, 1); + } } -void +static void +start_fork_pipe(Uint8 *d, Uxn *u) +{ + if (child_mode & 0x01) { + /* parent writes to child's stdin */ + if (pipe(to_child_fd) == -1) { + d[0x6] = 0xff; + fprintf(stderr, "pipe error: to child\n"); + return; + } + } + + if (child_mode & 0x06) { + /* parent reads from child's stdout and/or stderr */ + if (pipe(from_child_fd) == -1) { + d[0x6] = 0xff; + fprintf(stderr, "pipe error: from child\n"); + return; + } + } + + pid_t pid = fork(); + if (pid < 0) { /* failure */ + d[0x6] = 0xff; + fprintf(stderr, "fork failure\n"); + } else if (pid == 0) { /* child */ + if (child_mode & 0x01) { + dup2(to_child_fd[0], 0); + close(to_child_fd[1]); + } + if (child_mode & 0x06) { + if (child_mode & 0x02) dup2(from_child_fd[1], 1); + if (child_mode & 0x04) dup2(from_child_fd[1], 2); + close(from_child_fd[0]); + } + execvp(fork_args[0], fork_args); + d[0x6] = 0xff; + fprintf(stderr, "exec failure\n"); + } else { /*parent*/ + child_pid = pid; + if (child_mode & 0x01) { + saved_out = dup(1); + dup2(to_child_fd[1], 1); + close(to_child_fd[0]); + } + if (child_mode & 0x06) { + saved_in = dup(0); + dup2(from_child_fd[0], 0); + close(from_child_fd[1]); + } + } +} + +static void kill_child(Uint8 *d) { - /* TODO */ + if (child_pid) { + kill(child_pid, 9); + int wstatus; + if (waitpid(child_pid, &wstatus, 0)) { + d[0x6] = 1; + d[0x7] = WEXITSTATUS(wstatus); + clean_after_child(); + } + } +} + +static void +start_fork(Uxn *u, Uint8 *d) +{ + fflush(stderr); + kill_child(d); + child_mode = d[0x5]; + parse_args(d, u); + if (child_mode >= 0x80) { + start_fork_pty(d, u); + } else { + start_fork_pipe(d, u); + } } Uint8 console_dei(Uxn *u, Uint8 addr) { - /* TODO */ + Uint8 port = addr & 0x0f, *d = &u->dev[addr & 0xf0]; + switch(port) { + case 0x6: + case 0x7: + if (child_pid) { + int wstatus; + if (waitpid(child_pid, &wstatus, WNOHANG)) { + d[0x6] = 1; + d[0x7] = WEXITSTATUS(wstatus); + clean_after_child(); + } + } + } + return d[port]; } void @@ -66,4 +237,4 @@ console_deo(Uxn *u, Uint8 *d, Uint8 port) fputc(d[port], fd); fflush(fd); } -} \ No newline at end of file +}