logo

openpt

Fake a pseudo-terminal for testsuites
commit: e4a6c2af624388ebff4a8ceb18cfb7c8834b58f8
parent 76ba985473c5fffaf058eef9180ebf3b749f5782
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date:   Sun,  2 Jun 2024 07:16:35 +0200

Rename to openpt

pts: Taken by OpenAFS
pty: Taken by FreeBSD for a slightly different tool

Diffstat:

M.gitignore6+++---
MMakefile10+++++-----
Aopenpt.c180+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dpts.c180-------------------------------------------------------------------------------
4 files changed, 188 insertions(+), 188 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2017 Haelwenn (lanodan) Monnier <contact+utils-pts@hacktivis.me> +# SPDX-FileCopyrightText: 2017 Haelwenn (lanodan) Monnier <contact+utils-openpt@hacktivis.me> # SPDX-License-Identifier: MIT -/pts -\ No newline at end of file +/openpt +\ No newline at end of file diff --git a/Makefile b/Makefile @@ -1,17 +1,17 @@ -# SPDX-FileCopyrightText: 2017 Haelwenn (lanodan) Monnier <contact+utils-pts@hacktivis.me> +# SPDX-FileCopyrightText: 2017 Haelwenn (lanodan) Monnier <contact+utils-openpt@hacktivis.me> # SPDX-License-Identifier: MIT PREFIX ?= /usr/local BINDIR ?= ${PREFIX}/bin -pts: pts.c +openpt: openpt.c ${CC} -std=c99 ${CFLAGS} -o $@ $< ${LDFLAGS} .PHONY: clean clean: - rm pts + rm openpt .PHONY: install -install: pts +install: openpt mkdir -p ${BINDIR}/ - cp -p pts ${DESTDIR}/${BINDIR}/pts + cp -p openpt ${DESTDIR}/${BINDIR}/openpt diff --git a/openpt.c b/openpt.c @@ -0,0 +1,180 @@ +// SPDX-FileCopyrightText: 2017 Haelwenn (lanodan) Monnier <contact+utils-openpt@hacktivis.me> +// SPDX-License-Identifier: MIT + +#define _POSIX_C_SOURCE 200809L +#define _XOPEN_SOURCE 800 + +#include <stdlib.h> // posix_openpt, ptsname +#include <fcntl.h> // O_* +#include <string.h> // strerror +#include <stdio.h> // fprintf, perror +#include <errno.h> +#include <poll.h> +#include <unistd.h> // execvp, dup2 +#include <sys/wait.h> +#include <signal.h> + +static int child_status = 0; +static pid_t pid = -1; + +static void +handle_sigchld(int sig) +{ + (void)sig; + waitpid(pid, &child_status, WNOHANG); + exit(WEXITSTATUS(child_status)); +} + +int +main(int argc, char *argv[]) +{ + argc--; + argv++; + if(argc < 1) + { + fprintf(stderr, "openpt: Expected >= 1 arguments, got %d\n", argc); + return 1; + } + + int manager = posix_openpt(O_RDWR|O_NOCTTY); + if(manager < 0) + { + fprintf(stderr, "openpt: Failed opening pseudo-terminal: %s\n", strerror(errno)); + return 1; + } + + if(grantpt(manager) < 0) + { + perror("openpt: Error in grantpt(manager)"); + return 1; + } + + if(unlockpt(manager) < 0) + { + perror("openpt: Error in unlockpt(manager)"); + return 1; + } + + pid = fork(); + if(pid < 0) + { + fprintf(stderr, "openpt: Fork failed: %s\n", strerror(errno)); + return 1; + } + + if(pid != 0) + { + nfds_t nfds = 2; + struct pollfd pfds[2] = { + { + .fd = manager, + .events = POLLIN + }, + { + .fd = STDIN_FILENO, + .events = POLLIN + } + }; + + if(signal(SIGCHLD, handle_sigchld) == SIG_ERR) + { + fprintf(stderr, "timeout: Failed registering handler for SIGCHLD: %s\n", strerror(errno)); + return 1; + } + + // parent + do { + int ret = poll(pfds, nfds, -1); + if(ret < 0) + { + fprintf(stderr, "openpt: Poll failed: %s\n", strerror(errno)); + return 1; + } + if(ret == 0) continue; // timeout + + if(pfds[0].revents & POLLIN) + { + char buf[BUFSIZ] = ""; + ssize_t nread = read(pfds[0].fd, buf, BUFSIZ); + if(nread < 0) + { + fprintf(stderr, "openpt: Failed reading from pseudo-terminal: %s\n", strerror(errno)); + return 1; + } + + if(nread == 0) break; + + if(write(STDOUT_FILENO, buf, nread) < 0) + { + fprintf(stderr, "openpt: Failed writing pseudo-terminal content to stdout: %s\n", strerror(errno)); + return 1; + } + } + + if(pfds[1].revents & POLLIN) + { + char buf[BUFSIZ] = ""; + ssize_t nread = read(pfds[1].fd, buf, BUFSIZ); + if(nread < 0) + { + fprintf(stderr, "openpt: Failed reading from stdin: %s\n", strerror(errno)); + return 1; + } + + if(nread == 0) break; + + if(write(manager, buf, nread) < 0) + { + fprintf(stderr, "openpt: Failed writing stdin content to pseudo-terminal: %s\n", strerror(errno)); + return 1; + } + } + + if(waitpid(pid, &child_status, WNOHANG) < 0) + { + fprintf(stderr, "openpt: Failed getting status for child process: %s\n", strerror(errno)); + return 1; + } + } while(child_status == 0 || !WIFEXITED(child_status)); + + return WEXITSTATUS(child_status); + } + else + { + // child + char *name = ptsname(manager); + + int sub = open(name, O_RDWR|O_NOCTTY); + if(sub < 0) + { + fprintf(stderr, "openpt: Failed opening subsidiary pseudo-terminal at '%s': %s\n", name, strerror(errno)); + return 1; + } + + if(dup2(sub, STDIN_FILENO) < 0) + { + fprintf(stderr, "openpt: Failed assigning subsidiary pseudo-terminal to stdin: %s\n", strerror(errno)); + return 1; + } + + if(dup2(sub, STDOUT_FILENO) < 0) + { + fprintf(stderr, "openpt: Failed assigning subsidiary pseudo-terminal to stdout: %s\n", strerror(errno)); + return 1; + } + + if(dup2(sub, STDERR_FILENO) < 0) + { + fprintf(stderr, "openpt: Failed assigning subsidiary pseudo-terminal to stderr: %s\n", strerror(errno)); + return 1; + } + + if(execvp(argv[0], argv) < 0) + { + fprintf(stderr, "openpt: Failed to execute '%s': %s\n", argv[0], strerror(errno)); + return errno == ENOENT ? 127 : 126; + } + + abort(); + } +} diff --git a/pts.c b/pts.c @@ -1,180 +0,0 @@ -// SPDX-FileCopyrightText: 2017 Haelwenn (lanodan) Monnier <contact+utils-pts@hacktivis.me> -// SPDX-License-Identifier: MIT - -#define _POSIX_C_SOURCE 200809L -#define _XOPEN_SOURCE 800 - -#include <stdlib.h> // posix_openpt, ptsname -#include <fcntl.h> // O_* -#include <string.h> // strerror -#include <stdio.h> // fprintf, perror -#include <errno.h> -#include <poll.h> -#include <unistd.h> // execvp, dup2 -#include <sys/wait.h> -#include <signal.h> - -static int child_status = 0; -static pid_t pid = -1; - -static void -handle_sigchld(int sig) -{ - (void)sig; - waitpid(pid, &child_status, WNOHANG); - exit(WEXITSTATUS(child_status)); -} - -int -main(int argc, char *argv[]) -{ - argc--; - argv++; - if(argc < 1) - { - fprintf(stderr, "pts: Expected >= 1 arguments, got %d\n", argc); - return 1; - } - - int manager = posix_openpt(O_RDWR|O_NOCTTY); - if(manager < 0) - { - fprintf(stderr, "pts: Failed opening pseudo-terminal: %s\n", strerror(errno)); - return 1; - } - - if(grantpt(manager) < 0) - { - perror("pts: Error in grantpt(manager)"); - return 1; - } - - if(unlockpt(manager) < 0) - { - perror("pts: Error in unlockpt(manager)"); - return 1; - } - - pid = fork(); - if(pid < 0) - { - fprintf(stderr, "pts: Fork failed: %s\n", strerror(errno)); - return 1; - } - - if(pid != 0) - { - nfds_t nfds = 2; - struct pollfd pfds[2] = { - { - .fd = manager, - .events = POLLIN - }, - { - .fd = STDIN_FILENO, - .events = POLLIN - } - }; - - if(signal(SIGCHLD, handle_sigchld) == SIG_ERR) - { - fprintf(stderr, "timeout: Failed registering handler for SIGCHLD: %s\n", strerror(errno)); - return 1; - } - - // parent - do { - int ret = poll(pfds, nfds, -1); - if(ret < 0) - { - fprintf(stderr, "pts: Poll failed: %s\n", strerror(errno)); - return 1; - } - if(ret == 0) continue; // timeout - - if(pfds[0].revents & POLLIN) - { - char buf[BUFSIZ] = ""; - ssize_t nread = read(pfds[0].fd, buf, BUFSIZ); - if(nread < 0) - { - fprintf(stderr, "pts: Failed reading from pseudo-terminal: %s\n", strerror(errno)); - return 1; - } - - if(nread == 0) break; - - if(write(STDOUT_FILENO, buf, nread) < 0) - { - fprintf(stderr, "pts: Failed writing pseudo-terminal content to stdout: %s\n", strerror(errno)); - return 1; - } - } - - if(pfds[1].revents & POLLIN) - { - char buf[BUFSIZ] = ""; - ssize_t nread = read(pfds[1].fd, buf, BUFSIZ); - if(nread < 0) - { - fprintf(stderr, "pts: Failed reading from stdin: %s\n", strerror(errno)); - return 1; - } - - if(nread == 0) break; - - if(write(manager, buf, nread) < 0) - { - fprintf(stderr, "pts: Failed writing stdin content to pseudo-terminal: %s\n", strerror(errno)); - return 1; - } - } - - if(waitpid(pid, &child_status, WNOHANG) < 0) - { - fprintf(stderr, "pts: Failed getting status for child process: %s\n", strerror(errno)); - return 1; - } - } while(child_status == 0 || !WIFEXITED(child_status)); - - return WEXITSTATUS(child_status); - } - else - { - // child - char *name = ptsname(manager); - - int sub = open(name, O_RDWR|O_NOCTTY); - if(sub < 0) - { - fprintf(stderr, "pts: Failed opening subsidiary pseudo-terminal at '%s': %s\n", name, strerror(errno)); - return 1; - } - - if(dup2(sub, STDIN_FILENO) < 0) - { - fprintf(stderr, "pts: Failed assigning subsidiary pseudo-terminal to stdin: %s\n", strerror(errno)); - return 1; - } - - if(dup2(sub, STDOUT_FILENO) < 0) - { - fprintf(stderr, "pts: Failed assigning subsidiary pseudo-terminal to stdout: %s\n", strerror(errno)); - return 1; - } - - if(dup2(sub, STDERR_FILENO) < 0) - { - fprintf(stderr, "pts: Failed assigning subsidiary pseudo-terminal to stderr: %s\n", strerror(errno)); - return 1; - } - - if(execvp(argv[0], argv) < 0) - { - fprintf(stderr, "pts: Failed to execute '%s': %s\n", argv[0], strerror(errno)); - return errno == ENOENT ? 127 : 126; - } - - abort(); - } -}