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
M
makefile
+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+}