I try to use forkpty to execvp a ls / and then from the parent process read its output and write to stdout.
I got it, and running it under Valgrind also shows no errors.
EDIT: Valgrind does not show memory errors. The last read still gives EIO under Valgrind.
However, the last read always returns -1 and sets errno to EIO . I studied and read the manual pages, but I still do not understand why this is happening:
EIO I/O error. This will happen for example when the process is in a background process group, tries to read from its controlling terminal, and either it is ignoring or blocking SIGTTIN or its process group is orphaned. It may also occur when there is a low-level I/O error while reading from a disk or tape.
I also noticed that if I catch SIGCHLD signals that I can know when ls came out, but if I listed a larger directory like /usr/bin , then I get this signal for the ls child process even if there is a lot of read , who succeed.
Here is an example output:
$ ./a.out bin dev initrd.img.old libx32 opt sbin usr boot etc lib lost+found proc srv var build home lib32 media root sys vmlinuz core initrd.img lib64 mnt run tmp vmlinuz.old # read: Input/output error
Am I missing something obvious?
#include <pty.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> int main(int argc, char* argv[]) { int master_fd; pid_t child_pid = forkpty(&master_fd, NULL, NULL, NULL); if (child_pid == -1) { perror("# forkpty"); return EXIT_FAILURE; } else if (!child_pid) { /* CHILD */ char* ls_argv[] = { "ls", "/", NULL, }; execvp(ls_argv[0], ls_argv); perror("# execvp"); abort(); } else { /* PARENT */ uint8_t buffer[BUFSIZ]; ssize_t read_count; while ((read_count = read(master_fd, buffer, BUFSIZ)) > 0) { uint8_t* ptr = buffer; size_t ptr_len = (size_t) read_count; while (ptr_len > 0) { ssize_t write_count = write(STDOUT_FILENO, ptr, ptr_len); if (write_count == -1) { perror("# write"); return EXIT_FAILURE; } ptr += write_count; ptr_len -= write_count; } } if (read_count == -1) { perror("# read"); return EXIT_FAILURE; } if (close(master_fd) == -1) { perror("# close"); return EXIT_FAILURE; } int child_status; if (waitpid(child_pid, &child_status, 0) == -1) { perror("# waitpid"); return EXIT_FAILURE; } if (!WIFEXITED(child_status)) { fprintf(stderr, "# main: subprocess did not exit normally\n"); return EXIT_FAILURE; } return child_status; } }