Created
September 6, 2015 01:05
-
-
Save a0u/2d533ca4ea91764a0fa8 to your computer and use it in GitHub Desktop.
Wrapper for redirecting stdin/stdout of a shell command to a pseudo-terminal
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* \brief Wrapper for redirecting stdin/stdout to a pseudo-terminal | |
* \author Albert Ou <aou@eecs.berkeley.edu> | |
* \copyright BSD 2-Clause License | |
*/ | |
#define _XOPEN_SOURCE (600) | |
#include <stdlib.h> | |
#include <stdio.h> | |
#include <errno.h> | |
#include <signal.h> | |
#include <unistd.h> | |
#include <fcntl.h> | |
#include <poll.h> | |
#include <sys/wait.h> | |
#include <termios.h> | |
int main(int argc, char **argv) | |
{ | |
const char *errmsg; | |
const char *name; | |
int pty, pts; | |
pid_t pid; | |
sigset_t set; | |
struct termios tios; | |
if (argc < 2) { | |
fprintf(stderr, "usage: %s [command]\n", argv[0]); | |
return EXIT_FAILURE; | |
} | |
errno = 0; | |
errmsg = NULL; | |
if ((pty = posix_openpt(O_RDWR | O_NOCTTY)) < 0) { | |
errmsg = "posix_openpt"; | |
goto exit; | |
} | |
if (grantpt(pty)) { | |
errmsg = "grantpt"; | |
goto close; | |
} | |
if (unlockpt(pty)) { | |
errmsg = "unlockpt"; | |
goto close; | |
} | |
name = ptsname(pty); | |
if ((pts = open(name, O_RDWR | O_NOCTTY)) < 0) { | |
errmsg = "open"; | |
goto close; | |
} | |
close(pts); | |
puts(name); | |
/* Poll until HUP condition vanishes, which should | |
indicate that the slave device has been reopened */ | |
for (;;) { | |
struct pollfd fds; | |
fds.fd = pty; | |
fds.events = POLLHUP; | |
if (poll(&fds, 1, 0) < 0) { | |
errmsg = "poll"; | |
goto close; | |
} | |
if (!(fds.revents & POLLHUP)) | |
break; | |
usleep(100); | |
} | |
if (tcgetattr(pty, &tios)) { | |
errmsg = "tcgetattr"; | |
goto close; | |
} | |
tios.c_lflag &= ~(ICANON | ECHO | ISIG); | |
if (tcsetattr(pty, TCSANOW, &tios)) { | |
errmsg = "tcsetattr"; | |
goto close; | |
} | |
if ((pid = fork()) < 0) { | |
errmsg = "fork"; | |
goto close; | |
} | |
if (pid == 0) { | |
if ((dup2(pty, STDIN_FILENO) < 0) || | |
(dup2(pty, STDOUT_FILENO) < 0)) { | |
errmsg = "dup2"; | |
goto close; | |
} | |
execvp(argv[1], argv + 1); | |
errmsg = "execvp"; | |
goto close; | |
} | |
sigemptyset(&set); | |
sigaddset(&set, SIGINT); | |
sigaddset(&set, SIGTERM); | |
sigaddset(&set, SIGCHLD); | |
sigprocmask(SIG_BLOCK, &set, NULL); | |
for (;;) { | |
int signo; | |
sigwait(&set, &signo); | |
if (signo == SIGCHLD) { | |
int status; | |
waitpid(pid, &status, WNOHANG); | |
if (WIFEXITED(status)) | |
break; | |
} else { | |
kill(pid, SIGTERM); | |
break; | |
} | |
} | |
close: | |
close(pty); | |
exit: | |
if (errno) | |
perror(errmsg); | |
return errno; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment