From b2f204a2cb8ca9608e2c21be3ef1c7e10fcf41f3 Mon Sep 17 00:00:00 2001 From: Emile Clark-Boman Date: Tue, 9 Sep 2025 21:07:34 +1000 Subject: [PATCH] add epty.* to extend _pty.* stdout/stderr independence for child process --- cli/epty.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ cli/epty.h | 8 ++++++++ 2 files changed, 53 insertions(+) create mode 100644 cli/epty.c create mode 100644 cli/epty.h diff --git a/cli/epty.c b/cli/epty.c new file mode 100644 index 0000000..85182e4 --- /dev/null +++ b/cli/epty.c @@ -0,0 +1,45 @@ +#include + +#include "mkpty.h" + +#define PIPE_READ 0 +#define PIPE_WRITE 1 + +/* Allocate a PTY and fork, giving fdmx (master) to the parent + * and binding the child's stdin/stdout to fds (slave). + * Return value is indentical to fork(2). + * NOTE: This function is my alternative to GLibC's + * NOTE: forkpty() function. It exists as a learning resource. + * REF: https://sourceware.org/git/glibc.git -> ./login/forkpty.c + */ +pid_t forkepty(int *fdmx, int *fderr) { + // master/slave, and stderr pipe fds + int epipe[2]; + pid_t pid; + + if (pipe(epipe) == -1) + return EXIT_FAILURE; + switch (pid = forkmkpty(fdmx)) { + case -1: + /* forkmkpty() will close fdmx/fds for us */ + close(epipe[PIPE_READ]); + close(epipe[PIPE_WRITE]); + return -1; + case 0: + /* Child Process */ + /* forkmkpty() will close fdmx for us */ + close(epipe[PIPE_READ]); + BIND(epipe[PIPE_WRITE], STDERR_FILENO); + break; + + default: + /* Parent Process */ + /* forkmkpty() will close fds for us */ + close(epipe[PIPE_WRITE]); + *fderr = epipe[PIPE_READ]; + break; + } + + /* Both Processes */ + return pid; +} diff --git a/cli/epty.h b/cli/epty.h new file mode 100644 index 0000000..8dd18e4 --- /dev/null +++ b/cli/epty.h @@ -0,0 +1,8 @@ +#ifndef DORNE_EPTY_H +#define DORNE_EPTY_H + +#include + +pid_t forkepty(int *fdmx, int *fderr); + +#endif /* DORNE_EPTY_H */