]>
diplodocus.org Git - nmh/blob - test/runpty.c
2 * runpty.c - Run a process under a pseudo-tty
4 * This code is Copyright (c) 2017, by the authors of nmh. See the
5 * COPYRIGHT file in the root directory of the nmh distribution for
6 * complete copyright information.
16 #include <sys/types.h>
18 #include <sys/select.h>
22 #define COMMAND_TIMEOUT 30
24 static void run_command(char *argv
[], int master_in
, int master_out
);
25 static int open_master_pty(const char *desc
);
26 static void die(const char *fmt
, ...);
29 main(int argc
, char *argv
[])
31 int master_in
, master_out
, cc
, status
;
32 time_t starttime
, now
;
34 unsigned char readbuf
[1024];
38 die("%s: too few arguments\n"
39 "usage: %s output-filename command [arguments...]\n",
43 master_in
= open_master_pty("input");
44 master_out
= open_master_pty("output");
46 if ((child
= fork()) == -1) {
47 die("fork() failed: %s\n", strerror(errno
));
50 run_command(argv
+ 2, master_in
, master_out
); /* Does not return. */
53 if (!(output
= fopen(argv
[1], "w"))) {
54 die("Unable to open \"%s\" for output: %s\n", argv
[1],
58 starttime
= time(NULL
);
66 FD_SET(master_out
, &readfds
);
69 * After we get our first bit of data, close the master pty
70 * connected to standard input on our slave; that will generate
74 tv
.tv_sec
= starttime
+ COMMAND_TIMEOUT
- time(NULL
);
79 cc
= select(master_out
+ 1, &readfds
, NULL
, NULL
, &tv
);
82 die("select() failed: %s\n", strerror(errno
));
85 if (cc
> 0 && FD_ISSET(master_out
, &readfds
)) {
86 cc
= read(master_out
, readbuf
, sizeof(readbuf
));
91 fwrite(readbuf
, 1, cc
, output
);
93 if (master_in
!= -1) {
100 if (now
>= starttime
+ COMMAND_TIMEOUT
) {
101 fprintf(stderr
, "Command execution timed out: %ld to %ld: %d\n",
112 waitpid(child
, &status
, 0);
118 run_command(char *argv
[], int master_in
, int master_out
)
120 const char *slavename
;
123 /* Open the two slave pseudo-ttys and close the masters after we are
126 if (!(slavename
= ptsname(master_in
))) {
127 die("Unable to determine name of slave pty: %s\n",
131 if ((slave
= open(slavename
, O_RDWR
)) == -1) {
132 die("Unable to open slave pty \"%s\": %s\n", slavename
,
136 dup2(slave
, STDIN_FILENO
);
140 if (!(slavename
= ptsname(master_out
))) {
141 die("Unable to determine name of slave pty: %s\n",
145 if ((slave
= open(slavename
, O_RDWR
| O_NOCTTY
)) < 0) {
146 die("Unable to open slave pty \"%s\": %s\n", slavename
,
150 dup2(slave
, STDOUT_FILENO
);
151 dup2(slave
, STDERR_FILENO
);
157 die("execvp(%s) failed: %s\n", *argv
, strerror(errno
));
161 open_master_pty(const char *desc
)
165 if ((fd
= posix_openpt(O_RDWR
| O_NOCTTY
)) == -1) {
166 die("Unable to open master %s pseudo-tty: %s\n", desc
, strerror(errno
));
168 if (grantpt(fd
) == -1) {
169 die("Unable to grant permissions to master %s pty: %s\n", desc
,
172 if (unlockpt(fd
) == -1) {
173 die("Unable to unlock master %s pty: %s\n", desc
, strerror(errno
));
180 die(const char *fmt
, ...)
185 vfprintf(stderr
, fmt
, args
);