X-Git-Url: https://diplodocus.org/git/nmh/blobdiff_plain/d11f8c6ba92fc28c3ea4d76676ff7d5148c36d7d..485fa064f8388272fe00ebfd29e4babf6dfed019:/test/runpty.c?ds=sidebyside diff --git a/test/runpty.c b/test/runpty.c index e5de14e0..1585df94 100644 --- a/test/runpty.c +++ b/test/runpty.c @@ -23,8 +23,8 @@ int main(int argc, char *argv[]) { - int master, slave, cc, sendeof = 0, status; - time_t starttime; + int master_in, master_out, slave, cc, status; + time_t starttime, now; const char *slavename; pid_t child; unsigned char readbuf[1024]; @@ -36,59 +36,91 @@ main(int argc, char *argv[]) exit(1); } - if ((master = posix_openpt(O_RDWR | O_NOCTTY)) < 0) { + if ((master_in = posix_openpt(O_RDWR | O_NOCTTY)) < 0) { fprintf(stderr, "Unable to open master pseudo-tty: %s\n", strerror(errno)); exit(1); } - if (grantpt(master) < 0) { - fprintf(stderr, "Unable to grant permissions to master pty: %s\n", + if ((master_out = posix_openpt(O_RDWR | O_NOCTTY)) < 0) { + fprintf(stderr, "Unable to open master pseudo-tty: %s\n", strerror(errno)); exit(1); } - if (unlockpt(master) < 0) { - fprintf(stderr, "Unable to unlock master pty: %s\n", strerror(errno)); + if (grantpt(master_in) < 0) { + fprintf(stderr, "Unable to grant permissions to master pty: %s\n", + strerror(errno)); exit(1); } - if (!(slavename = ptsname(master))) { - fprintf(stderr, "Unable to determine name of slave pty: %s\n", + if (grantpt(master_out) < 0) { + fprintf(stderr, "Unable to grant permissions to master pty: %s\n", strerror(errno)); exit(1); } - if ((slave = open(slavename, O_RDWR | O_NOCTTY)) < 0) { - fprintf(stderr, "Unable to open slave pty \"%s\": %s\n", slavename, - strerror(errno)); + if (unlockpt(master_in) < 0) { + fprintf(stderr, "Unable to unlock master pty: %s\n", strerror(errno)); + exit(1); + } + + if (unlockpt(master_out) < 0) { + fprintf(stderr, "Unable to unlock master pty: %s\n", strerror(errno)); exit(1); } child = fork(); /* - * Start the child process if we are in the child; close the master - * as we are supposed to only use the slave ptys here. + * Start the child process if we are in the child; open the two + * slave pseudo-ttys and close the masters after we are done with them. */ if (child == 0) { - close(master); + if (!(slavename = ptsname(master_in))) { + fprintf(stderr, "Unable to determine name of slave pty: %s\n", + strerror(errno)); + exit(1); + } + + if ((slave = open(slavename, O_RDWR)) < 0) { + fprintf(stderr, "Unable to open slave pty \"%s\": %s\n", slavename, + strerror(errno)); + exit(1); + } + dup2(slave, STDIN_FILENO); + close(slave); + close(master_in); + + if (!(slavename = ptsname(master_out))) { + fprintf(stderr, "Unable to determine name of slave pty: %s\n", + strerror(errno)); + exit(1); + } + + if ((slave = open(slavename, O_RDWR | O_NOCTTY)) < 0) { + fprintf(stderr, "Unable to open slave pty \"%s\": %s\n", slavename, + strerror(errno)); + exit(1); + } + dup2(slave, STDOUT_FILENO); dup2(slave, STDERR_FILENO); close(slave); + close(master_out); execvp(argv[2], argv + 2); fprintf(stderr, "execvp(%s) failed: %s\n", argv[2], strerror(errno)); + exit(1); + } else if (child < 0) { fprintf(stderr, "fork() failed: %s\n", strerror(errno)); exit(1); } - close(slave); - if (!(output = fopen(argv[1], "w"))) { fprintf(stderr, "Unable to open \"%s\" for output: %s\n", argv[1], strerror(errno)); @@ -103,65 +135,51 @@ main(int argc, char *argv[]) FD_ZERO(&readfds); - FD_SET(master, &readfds); + FD_SET(master_out, &readfds); /* - * Okay, what's going on here? - * - * We want to send the EOF character (to simulate a "end of file", - * as if we redirected stdin to /dev/null). We can't just close - * master, because we won't be able to get any data back. So, - * after we get SOME data, set sendeof, and that will cause us to - * send the EOF character after the first select call. If we are - * doing sendeof, set the timeout to 1 second; otherwise, set the - * timeout to COMMAND_TIMEOUT seconds remaining. + * After we get our first bit of data, close the master pty + * connected to standard input on our slave; that will generate + * an EOF. */ - if (sendeof) { - tv.tv_sec = 1; - } else { - tv.tv_sec = starttime + COMMAND_TIMEOUT - time(NULL); - if (tv.tv_sec < 0) - tv.tv_sec = 0; - } + tv.tv_sec = starttime + COMMAND_TIMEOUT - time(NULL); + if (tv.tv_sec < 0) + tv.tv_sec = 0; tv.tv_usec = 0; - cc = select(master + 1, &readfds, NULL, NULL, &tv); + cc = select(master_out + 1, &readfds, NULL, NULL, &tv); if (cc < 0) { fprintf(stderr, "select() failed: %s\n", strerror(errno)); exit(1); } - if (cc > 0 && FD_ISSET(master, &readfds)) { - cc = read(master, readbuf, sizeof(readbuf)); + if (cc > 0 && FD_ISSET(master_out, &readfds)) { + cc = read(master_out, readbuf, sizeof(readbuf)); if (cc <= 0) break; fwrite(readbuf, 1, cc, output); - } - - if (cc == 0 && sendeof) { - struct termios rtty; - if (tcgetattr(master, &rtty) < 0) { - fprintf(stderr, "tcgetattr() failed: %s\n", strerror(errno)); - exit(1); + if (master_in != -1) { + close(master_in); + master_in = -1; } + } - if (rtty.c_lflag & ICANON) - write(master, &rtty.c_cc[VEOF], 1); - } else if (!sendeof) - sendeof = 1; - - if (time(NULL) > starttime + COMMAND_TIMEOUT) { - fprintf(stderr, "Command execution timed out\n"); + now = time(NULL); + if (now >= starttime + COMMAND_TIMEOUT) { + fprintf(stderr, "Command execution timed out: %ld to %ld: %d\n", + starttime, now, cc); break; } } - close(master); + if (master_in != -1) + close(master_in); + close(master_out); fclose(output); waitpid(child, &status, 0);