commit d98e8d4

neauoire  ·  2023-11-11 17:17:24 +0000 UTC
parent d69d150
(console) Added tools to spawn unix process
2 files changed,  +181, -10
+3, -3
 1@@ -29,8 +29,8 @@ clean:
 2 	@ rm -f bin/uxnasm bin/uxncli bin/uxn11 bin/polycat.rom bin/polycat.rom.sym
 3 
 4 bin/uxnasm: src/uxnasm.c
 5-	@ cc ${RELEASE_flags} src/uxnasm.c -o bin/uxnasm
 6+	@ cc ${RELEASE_flags} ${CFLAGS} src/uxnasm.c -o bin/uxnasm
 7 bin/uxncli: ${CLI_src} src/uxncli.c
 8-	@ cc ${RELEASE_flags} ${CLI_src} src/uxncli.c -pthread -o bin/uxncli
 9+	@ cc ${RELEASE_flags} ${CFLAGS} ${CLI_src} src/uxncli.c -lutil -pthread -o bin/uxncli
10 bin/uxn11: ${EMU_src} src/uxn11.c
11-	@ cc ${RELEASE_flags} ${EMU_src} src/uxn11.c -lX11 -pthread -o bin/uxn11
12+	@ cc ${RELEASE_flags} ${CFLAGS} ${EMU_src} src/uxn11.c -lX11 -lutil -pthread -o bin/uxn11
+178, -7
  1@@ -1,5 +1,21 @@
  2+#undef _POSIX_C_SOURCE
  3+#define _POSIX_C_SOURCE 200112L
  4+
  5+#include <signal.h>
  6 #include <stdio.h>
  7 #include <stdlib.h>
  8+#include <sys/select.h>
  9+#include <sys/wait.h>
 10+#include <unistd.h>
 11+
 12+#ifdef __linux
 13+#include <pty.h>
 14+#endif
 15+
 16+#ifdef __NetBSD__
 17+#include <sys/ioctl.h>
 18+#include <util.h>
 19+#endif
 20 
 21 #include "../uxn.h"
 22 #include "console.h"
 23@@ -15,6 +31,54 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 24 WITH REGARD TO THIS SOFTWARE.
 25 */
 26 
 27+/* process */
 28+static char *fork_args[32];
 29+static pid_t child_pid;
 30+static int child_mode;
 31+static int pty_fd;
 32+static int to_child_fd[2];
 33+static int from_child_fd[2];
 34+static int saved_in;
 35+static int saved_out;
 36+
 37+static void
 38+parse_args(Uint8 *d, Uxn *u)
 39+{
 40+	int addr = (d[0x3] << 8) | d[0x4];
 41+	char *pos = (char *)&u->ram[addr];
 42+	int i = 0;
 43+	do {
 44+		fork_args[i++] = pos;
 45+		while (*pos != 0) pos++;
 46+		pos++;
 47+	} while (*pos != '\0');
 48+	fork_args[i] = NULL;
 49+}
 50+
 51+/* call after we're sure the process has exited */
 52+static void
 53+clean_after_child()
 54+{
 55+	child_pid = 0;
 56+	if (child_mode >= 0x80) {
 57+		close(pty_fd);
 58+		dup2(saved_in, 0);
 59+		dup2(saved_out, 1);
 60+	} else {
 61+		if (child_mode & 0x01) {
 62+			close(to_child_fd[1]);
 63+			dup2(saved_out, 1);
 64+		}
 65+		if (child_mode & 0x06) {
 66+			close(from_child_fd[0]);
 67+			dup2(saved_in, 0);
 68+		}
 69+	}
 70+	child_mode = 0;
 71+	saved_in = -1;
 72+	saved_out = -1;
 73+}
 74+
 75 int
 76 console_input(Uxn *u, char c, int type)
 77 {
 78@@ -34,22 +98,129 @@ console_listen(Uxn *u, int i, int argc, char **argv)
 79 	}
 80 }
 81 
 82-void
 83-start_fork(Uxn *u, Uint8 *d)
 84+static void
 85+start_fork_pty(Uint8 *d, Uxn *u)
 86 {
 87-	/* TODO */
 88+	int fd = -1;
 89+	pid_t pid = forkpty(&fd, NULL, NULL, NULL);
 90+	if (pid < 0) { /* failure */
 91+		d[0x6] = 0xff;
 92+		fprintf(stderr, "fork failure\n");
 93+	} else if (pid == 0) { /* child */
 94+		setenv("TERM", "ansi", 1);
 95+		execvp(fork_args[0], fork_args);
 96+		d[0x6] = 0xff;
 97+		fprintf(stderr, "exec failure\n");
 98+	} else { /*parent*/
 99+		child_pid = pid;
100+		pty_fd = fd;
101+		struct winsize ws = {24, 80, 8, 12};
102+		ioctl(fd, TIOCSWINSZ, &ws);
103+		saved_in = dup(0);
104+		saved_out = dup(1);
105+		dup2(fd, 0);
106+		dup2(fd, 1);
107+	}
108 }
109 
110-void
111+static void
112+start_fork_pipe(Uint8 *d, Uxn *u)
113+{
114+	if (child_mode & 0x01) {
115+		/* parent writes to child's stdin */
116+		if (pipe(to_child_fd) == -1) {
117+			d[0x6] = 0xff;
118+			fprintf(stderr, "pipe error: to child\n");
119+			return;
120+		}
121+	}
122+
123+	if (child_mode & 0x06) {
124+		/* parent reads from child's stdout and/or stderr */
125+		if (pipe(from_child_fd) == -1) {
126+			d[0x6] = 0xff;
127+			fprintf(stderr, "pipe error: from child\n");
128+			return;
129+		}
130+	}
131+
132+	pid_t pid = fork();
133+	if (pid < 0) { /* failure */
134+		d[0x6] = 0xff;
135+		fprintf(stderr, "fork failure\n");
136+	} else if (pid == 0) { /* child */
137+		if (child_mode & 0x01) {
138+			dup2(to_child_fd[0], 0);
139+			close(to_child_fd[1]);
140+		}
141+		if (child_mode & 0x06) {
142+			if (child_mode & 0x02) dup2(from_child_fd[1], 1);
143+			if (child_mode & 0x04) dup2(from_child_fd[1], 2);
144+			close(from_child_fd[0]);
145+		}
146+		execvp(fork_args[0], fork_args);
147+		d[0x6] = 0xff;
148+		fprintf(stderr, "exec failure\n");
149+	} else { /*parent*/
150+		child_pid = pid;
151+		if (child_mode & 0x01) {
152+			saved_out = dup(1);
153+			dup2(to_child_fd[1], 1);
154+			close(to_child_fd[0]);
155+		}
156+		if (child_mode & 0x06) {
157+			saved_in = dup(0);
158+			dup2(from_child_fd[0], 0);
159+			close(from_child_fd[1]);
160+		}
161+	}
162+}
163+
164+static void
165 kill_child(Uint8 *d)
166 {
167-	/* TODO */
168+	if (child_pid) {
169+		kill(child_pid, 9);
170+		int wstatus;
171+		if (waitpid(child_pid, &wstatus, 0)) {
172+			d[0x6] = 1;
173+			d[0x7] = WEXITSTATUS(wstatus);
174+			clean_after_child();
175+		}
176+	}
177+}
178+
179+static void
180+start_fork(Uxn *u, Uint8 *d)
181+{
182+	fflush(stderr);
183+	kill_child(d);
184+	child_mode = d[0x5];
185+	parse_args(d, u);
186+	if (child_mode >= 0x80) {
187+		start_fork_pty(d, u);
188+	} else {
189+		start_fork_pipe(d, u);
190+	}
191 }
192 
193 Uint8
194 console_dei(Uxn *u, Uint8 addr)
195 {
196-	/* TODO */
197+	Uint8 port = addr & 0x0f, *d = &u->dev[addr & 0xf0];
198+	switch(port) {
199+	case 0x6:
200+	case 0x7:
201+		if (child_pid) {
202+			int wstatus;
203+			if (waitpid(child_pid, &wstatus, WNOHANG)) {
204+				d[0x6] = 1;
205+				d[0x7] = WEXITSTATUS(wstatus);
206+				clean_after_child();
207+			}
208+		}
209+	}
210+	return d[port];
211 }
212 
213 void
214@@ -66,4 +237,4 @@ console_deo(Uxn *u, Uint8 *d, Uint8 port)
215 		fputc(d[port], fd);
216 		fflush(fd);
217 	}
218-}
219+}