From c68fc6de5e2f0b9137d1838a3b01667c97ab0f44 Mon Sep 17 00:00:00 2001 From: Emile Clark-Boman Date: Tue, 9 Sep 2025 15:43:54 +1000 Subject: [PATCH] add custom pty interface --- cli/main.c | 24 ++++++++++ cli/mkpty.c | 132 ++++++++++++++++++++++++++++++++++++++++++++++++++++ cli/mkpty.h | 14 ++++++ 3 files changed, 170 insertions(+) create mode 100644 cli/main.c create mode 100644 cli/mkpty.c create mode 100644 cli/mkpty.h diff --git a/cli/main.c b/cli/main.c new file mode 100644 index 0000000..86f4ffd --- /dev/null +++ b/cli/main.c @@ -0,0 +1,24 @@ +#include "mkpty.h" +#include "sys/types.h" + + +// struct d_window { +// int ptmx; // fd +// }; + +// struct d_window new_window() { +// struct d_window w = { +// .ptmx = posix_openpt(O_RDWR | O_NOCTTY), +// }; +// } + +int main(int argc, char **argv) { + pid_t pid; + switch (pid = forkmkpty()) { + case -1: + break; + case 0: + default: + break; + } +} diff --git a/cli/mkpty.c b/cli/mkpty.c new file mode 100644 index 0000000..4344a85 --- /dev/null +++ b/cli/mkpty.c @@ -0,0 +1,132 @@ +/* _XOPEN_SOURCE unlocks pty/ptmx/pts declarations. */ +#define _XOPEN_SOURCE 600 +/* _GNU_SOURCE unlocks the ptsname_r declaration*/ +#define _GNU_SOURCE +#include +#include +#include +#include /* TIOC* constants */ +#include + +#ifdef PATH_MAX +# define SNAME_MAX PATH_MAX +#else +# define SNAME_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. + * REF: glibc.git:/login/openpty.c + */ +int mkpty(int *fdmx, int *fds) { + int _fdmx = -1, _fds = -1; + char sname[SNAME_MAX]; + + // Configure PTY master (file descriptor) + _fdmx = posix_openpt(O_RDWR | O_NOCTTY); + if (_fdmx == -1) + return EXIT_FAILURE; + + if (grantpt(_fdmx)) + goto fail; + if (unlockpt(_fdmx)) + goto fail; + +#ifdef TIOCGPTPEER + /* Try to allocate slave fd solely based on PTMX fd first. */ + _fds = ioctl(_fdmx, TIOCGPTPEER, O_RDWR | O_NOCTTY); +#endif + if (_fds == -1) { + /* Fallback to path-based slave fd allocation + * (if the kernel doesn't support TIOCGPTPEER, ie Linux <4.13) */ + if(ptsname_r(_fdmx, sname, sizeof(sname))) + goto fail; + + _fds = open(sname, O_RDWR | O_NOCTTY); + if (_fds == -1) + goto fail; + } + + // Propagate file descriptors via parameters + *fdmx = _fdmx; + *fds = _fds; + return EXIT_SUCCESS; + +fail: + if (_fdmx == -1) { + close(_fdmx); + if (_fds == -1) + close(_fds); + } + return EXIT_FAILURE; +} + +/* + */ +pid_t forkmkpty() { + int fdmx, fds; + pid_t pid; + if (mkpty(&fdmx, &fds)) + return EXIT_FAILURE; + + switch (pid = fork()) { + case -1: + close(fdmx); + close(fds); + return -1; + case 0: + /* Child Process */ + close(fdmx); + break; + + default: + /* Parent Process */ + close(fds); + break; + } + + /* Both Processes */ + return pid; +} + +/* Set pseudoterminal slave's window size. + * Returns 0 on success, and fails with -1 if the kernel doesn't + * implement this, or 1 for general errors (errno will be set). + * NOTE: Typically this is part of a glibc openpty() call. + */ +int setptsxy(const unsigned short rows, const unsigned short cols, const int fds) { +#ifndef TIOCSWINSZ + /* Fail if kernel doesn't support TIOCSWINSZ. */ + return -1; +#else + struct winsize win = { + .ws_row = rows, + .ws_col = cols, + }; + + if (ioctl(fds, TIOCSWINSZ, &win)) + return EXIT_FAILURE; + return EXIT_SUCCESS; +#endif /* TIOCSWINSZ */ +} + +/* Get pseudoterminal slave's window size. + * Returns 0 on success, and fails with -1 if the kernel doesn't + * implement this, or 1 for general errors (errno will be set). + */ +int getptsxy(unsigned short *rows, unsigned short *cols, const int fds) { +#ifndef TIOCGWINSZ + /* Fail if kernel doesn't support TIOCGWINSZ. */ + return -1; +#else + struct winsize win = (struct winsize){ 0 }; + if (ioctl(fds, TIOCGWINSZ, &win)) + return EXIT_FAILURE; + *rows = win.ws_row; + *cols = win.ws_col; + return EXIT_SUCCESS; +#endif /* TIOCGWINSZ */ +} diff --git a/cli/mkpty.h b/cli/mkpty.h new file mode 100644 index 0000000..ed0bce8 --- /dev/null +++ b/cli/mkpty.h @@ -0,0 +1,14 @@ +#ifndef DORNE_MKPTY_H +#define DORNE_MKPTY_H + +#include + +/* Custom implementations of openpty() */ +int mkpty(int *fdmx, int *fds); +/* Custom implementations of forkpty() */ +pid_t forkmkpty(); + +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 */