]>
diplodocus.org Git - nmh/blob - test/runpty.c
1 /* runpty.c - Run a process under a pseudo-tty
3 * This code is Copyright (c) 2017, by the authors of nmh. See the
4 * COPYRIGHT file in the root directory of the nmh distribution for
5 * complete copyright information.
15 #include <sys/types.h>
17 #include <sys/select.h>
21 #define COMMAND_TIMEOUT 30
23 static void run_command(char *argv
[], int master_in
, int master_out
);
24 static int open_master_pty(const char *desc
);
25 static void die(const char *fmt
, ...);
28 main(int argc
, char *argv
[])
30 int master_in
, master_out
, cc
, status
;
31 time_t starttime
, now
;
33 unsigned char readbuf
[1024];
37 die("%s: too few arguments\n"
38 "usage: %s output-filename command [arguments...]\n",
42 master_in
= open_master_pty("input");
43 master_out
= open_master_pty("output");
45 if ((child
= fork()) == -1) {
46 die("fork() failed: %s\n", strerror(errno
));
49 run_command(argv
+ 2, master_in
, master_out
); /* Does not return. */
52 if (!(output
= fopen(argv
[1], "w"))) {
53 die("Unable to open \"%s\" for output: %s\n", argv
[1],
57 starttime
= time(NULL
);
65 FD_SET(master_out
, &readfds
);
68 * After we get our first bit of data, close the master pty
69 * connected to standard input on our slave; that will generate
73 tv
.tv_sec
= starttime
+ COMMAND_TIMEOUT
- time(NULL
);
78 cc
= select(master_out
+ 1, &readfds
, NULL
, NULL
, &tv
);
81 die("select() failed: %s\n", strerror(errno
));
84 if (cc
> 0 && FD_ISSET(master_out
, &readfds
)) {
85 cc
= read(master_out
, readbuf
, sizeof(readbuf
));
90 fwrite(readbuf
, 1, cc
, output
);
92 if (master_in
!= -1) {
99 if (now
>= starttime
+ COMMAND_TIMEOUT
) {
100 fprintf(stderr
, "Command execution timed out: %ld to %ld: %d\n",
111 waitpid(child
, &status
, 0);
117 run_command(char *argv
[], int master_in
, int master_out
)
119 const char *slavename
;
122 /* Open the two slave pseudo-ttys and close the masters after we are
125 if (!(slavename
= ptsname(master_in
))) {
126 die("Unable to determine name of slave pty: %s\n",
130 if ((slave
= open(slavename
, O_RDWR
)) == -1) {
131 die("Unable to open slave pty \"%s\": %s\n", slavename
,
135 dup2(slave
, STDIN_FILENO
);
139 if (!(slavename
= ptsname(master_out
))) {
140 die("Unable to determine name of slave pty: %s\n",
144 if ((slave
= open(slavename
, O_RDWR
| O_NOCTTY
)) < 0) {
145 die("Unable to open slave pty \"%s\": %s\n", slavename
,
149 dup2(slave
, STDOUT_FILENO
);
150 dup2(slave
, STDERR_FILENO
);
156 die("execvp(%s) failed: %s\n", *argv
, strerror(errno
));
160 open_master_pty(const char *desc
)
164 if ((fd
= posix_openpt(O_RDWR
| O_NOCTTY
)) == -1) {
165 die("Unable to open master %s pseudo-tty: %s\n", desc
, strerror(errno
));
167 if (grantpt(fd
) == -1) {
168 die("Unable to grant permissions to master %s pty: %s\n", desc
,
171 if (unlockpt(fd
) == -1) {
172 die("Unable to unlock master %s pty: %s\n", desc
, strerror(errno
));
179 die(const char *fmt
, ...)
184 vfprintf(stderr
, fmt
, args
);