From d04f14c038548503c8c61bcb55d2f9f2e647a965 Mon Sep 17 00:00:00 2001 From: Emile Clark-Boman Date: Tue, 9 Sep 2025 21:03:40 +1000 Subject: [PATCH] reformat and refactor mkpty.* --- cli/mkpty.c | 62 +++++++++++++++++++++++++---------------------------- cli/mkpty.h | 20 ++++++++++++++--- 2 files changed, 46 insertions(+), 36 deletions(-) diff --git a/cli/mkpty.c b/cli/mkpty.c index 4cda39c..dd845b4 100644 --- a/cli/mkpty.c +++ b/cli/mkpty.c @@ -12,26 +12,18 @@ #define _XOPEN_SOURCE 600 /* _GNU_SOURCE unlocks the ptsname_r declaration*/ #define _GNU_SOURCE -#include #include #include -#include #include /* TIOC* constants */ #include #include "mkpty.h" -#ifdef PATH_MAX -# define TTYNAME_MAX PATH_MAX -#else -# define TTYNAME_MAX 512 -#endif /* PATH_MAX */ - /* Allocate PTY master and slave file descriptors. * errno will have been set if newpty() fails. * * NOTE: This function is my alternative to GLibC's - * openpty() function. It exists as a learning resource. + * NOTE: openpty() function. It exists as a learning resource. * REF: https://sourceware.org/git/glibc.git -> ./login/openpty.c */ int mkpty(int *fdmx, int *fds) { @@ -80,59 +72,63 @@ fail: /* Set fdty as the controlling terminal for the calling process. * Returns 0 on success, and 1 on failure. * NOTE: This function is my alternative to GLibC's - * login_tty() function. It exists as a learning resource. + * NOTE: login_tty() function. It exists as a learning resource. * REF: https://sourceware.org/git/glibc.git -> ./login/login_tty.c + */ +inline int setctty(const int fdty) { + /* We assume any kernel compiling this defines TIOCSCTTY, + * otherwise this implementation won't exactly work... */ + return (ioctl(fdty, TIOCSCTTY, 0) != -1); +} + +/* Bind fdty (terminal fd) to stdin/stdout/stderr for the calling process. + * This functions blocks until the EBUSY (see `man dup2`) race condition lifts. + * NOTE: This function is my alternative to GLibC's + * NOTE: login_tty() function. It exists as a learning resource. * WARNING: This function maintains the original University of California * WARNING: LICENSE (1990-1993) as per glibc.git:/login/login_tty.c * WARNING: available at LICENSES/UC-LICENSE in this repo. + * REF: https://sourceware.org/git/glibc.git -> ./login/login_tty.c */ -int bindpty(const int fdty) { - /* We assume any kernel compiling this defines TIOCSCTTY, - * otherwise this implementation won't exactly work... - */ - if (ioctl(fdty, TIOCSCTTY, 0) == -1) - return EXIT_FAILURE; - +inline void bindpty(const int fdty) { /* Adjust stdin/stdout/stderr to refer to fd*/ - while (dup2(fdty, STDIN_FILENO) == -1 && errno == EBUSY) - ; - while (dup2(fdty, STDOUT_FILENO) == -1 && errno == EBUSY) - ; - while (dup2(fdty, STDERR_FILENO) == -1 && errno == EBUSY) - ; + BIND(fdty, STDIN_FILENO); + BIND(fdty, STDOUT_FILENO); + BIND(fdty, STDERR_FILENO); if (fdty > 2) close(fdty); - - return EXIT_SUCCESS; } -/* Allocate a PTY and fork, binding the parent to ptmx (master), - * and the child to pts (slave). +/* Allocate a PTY and fork, giving ptmx (master) to the parent + * and binding the child's stdin/stdout/stderr to pts (slave). * Return value is indentical to fork(2). * NOTE: This function is my alternative to GLibC's - * forkpty() function. It exists as a learning resource. + * NOTE: forkpty() function. It exists as a learning resource. * REF: https://sourceware.org/git/glibc.git -> ./login/forkpty.c */ -pid_t forkmkpty(void) { - int fdmx, fds; +pid_t forkmkpty(int *fdmx) { + int _fdmx, fds; pid_t pid; - if (mkpty(&fdmx, &fds)) + if (mkpty(&_fdmx, &fds)) return EXIT_FAILURE; switch (pid = fork()) { case -1: - close(fdmx); + close(_fdmx); close(fds); return -1; case 0: /* Child Process */ - close(fdmx); + close(_fdmx); + setctty(fds); bindpty(fds); break; default: /* Parent Process */ close(fds); + // propagate ptmx (master) fd + *fdmx = _fdmx; break; } diff --git a/cli/mkpty.h b/cli/mkpty.h index a62a27a..3c80b95 100644 --- a/cli/mkpty.h +++ b/cli/mkpty.h @@ -1,16 +1,30 @@ #ifndef DORNE_MKPTY_H #define DORNE_MKPTY_H +#include +#include #include +#include + +#ifdef PATH_MAX +#define TTYNAME_MAX PATH_MAX +#else +#define TTYNAME_MAX 512 +#endif /* PATH_MAX */ + +#define BIND(fdsrc, fddst) \ + while (dup2(fdsrc, fddst) == -1 && errno == EBUSY) \ + ; /* Custom implementation of glibc::openpty() */ int mkpty(int *fdmx, int *fds); /* Custom implementation of glibc::login_tty() */ -int bindpty(const int fdty); +void bindpty(const int fdty); /* Custom implementation of glibc::forkpty() */ -pid_t forkmkpty(void); +pid_t forkmkpty(int *fdmx); -int setptsxy(const unsigned short rows, const unsigned short cols, const int fds); +int setptsxy(const unsigned short rows, const unsigned short cols, + const int fds); int getptsxy(unsigned short *rows, unsigned short *cols, const int fds); #endif /* DORNE_MKPTY_H */