/* * Test closing file descriptors opened via forkpty() when not all data has been * read. A following waitpid() blocks, when we opened two childs and try to * close the file descriptor and then waitpid() for that child... */ #include #include #include #include #include #include #include #include #include #define READ_SIZE 4096 /* * Set PAGER variables and start a man(1) process. */ void do_child(void); void do_child() { char *e_argv[3] = {"man", "groff_ms", NULL}; putenv("PAGER=cat"); putenv("MANPAGER=cat"); execvp("man", e_argv); } int main() { unsigned char read_buffer[READ_SIZE]; int pty_fd; int pty_fd1; int wstatus; pid_t child_pid; pid_t child_pid1; pid_t ret_pid; ssize_t ret; /* * Start a child to send us a manual page. */ child_pid = forkpty(&pty_fd, NULL, NULL, NULL); if (child_pid == -1) { fprintf(stderr, "forkpty(): %s\n", strerror(errno)); exit(EXIT_FAILURE); } ret = fcntl(pty_fd, F_SETFD, FD_CLOEXEC); if (child_pid == 0) do_child(); printf("child_pid = %jd\n", (intmax_t) child_pid); memset(read_buffer, '\0', READ_SIZE); ret = read(pty_fd, read_buffer, READ_SIZE); if (ret == -1) { fprintf(stderr, "read(): %s\n", strerror(errno)); exit(EXIT_FAILURE); } printf("%s\n", read_buffer); printf("%ld bytes read.\n", ret); /* * Start another child to send us a manual page. */ child_pid1 = forkpty(&pty_fd1, NULL, NULL, NULL); if (child_pid1 == -1) { fprintf(stderr, "forkpty(): %s\n", strerror(errno)); exit(EXIT_FAILURE); } ret = fcntl(pty_fd1, F_SETFD, FD_CLOEXEC); if (child_pid1 == 0) do_child(); printf("child_pid1 = %jd\n", (intmax_t) child_pid1); memset(read_buffer, '\0', READ_SIZE); ret = read(pty_fd1, read_buffer, READ_SIZE); if (ret == -1) { fprintf(stderr, "read(): %s\n", strerror(errno)); exit(EXIT_FAILURE); } printf("%s\n", read_buffer); printf("%ld bytes read.\n", ret); close(pty_fd); ret_pid = waitpid(child_pid, &wstatus, 0); printf("ret_pid = %jd\n", (intmax_t) ret_pid); exit(EXIT_SUCCESS); }