Results 1 to 1 of 1
Hello,
The included code fails on Linux but not on OS X. I'm struggling to
understand why. I get:
Code:
line 60, errno != EAGAIN && errno != EINTR: Input/output ...
- 07-22-2008 #1Just Joined!
- Join Date
- Jul 2008
- Posts
- 1
pseudo-terminals: read(2) gives EIO
Hello,
The included code fails on Linux but not on OS X. I'm struggling to
understand why. I get:
An errno value of 5 is EIO on my Linux installation. The code invokes the program you give it on the command line and this error appears to occur right at the end, as the child is finishing.Code:line 60, errno != EAGAIN && errno != EINTR: Input/output error (errno = 5) Aborted
If I use a pipe instead of a pseudo-terminal (a small change in
make_pt), it also seems to work fine.
Here's the code (also uploaded to http://www.mr-edd.co.uk/files/guff/invoke.c).
It aims to run the program specified by argv[1], ... , argv[argc-1]
and forward the output to the parent stdout and stderr.
Any insights and corrections are greatly appreciated!Code:#ifndef _XOPEN_SOURCE #define _XOPEN_SOURCE 600 #endif #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> #include <sys/time.h> #include <sys/uio.h> #include <sys/select.h> #include <sys/param.h> #include <fcntl.h> #include <string.h> #include <stdio.h> #include <errno.h> #include <stdlib.h> #define BAIL_IF(cond) \ do \ { \ if ((cond)) \ { \ int e = errno; \ fprintf(stderr, "line %d, %s: %s (errno = %d)\n", \ (int)__LINE__, \ #cond, \ strerror(e), \ e); \ abort(); \ } \ } \ while (0) void make_pt(int *m, int *s) { const char *name; BAIL_IF((*m = posix_openpt(O_RDWR | O_NOCTTY)) < 0); BAIL_IF(grantpt(*m) < 0); BAIL_IF(unlockpt(*m) < 0); BAIL_IF((name = ptsname(*m)) == NULL); BAIL_IF((*s = open(name, O_RDWR | O_NOCTTY)) < 0); } void set_non_blocking(int fd) { int flags; BAIL_IF((flags = fcntl(fd, F_GETFL)) < 0); fcntl(fd, F_SETFL, flags | O_NONBLOCK); } void forward_child_output(fd_set fds, int *fd, FILE *target) { if (*fd >= 0 && FD_ISSET(*fd, &fds)) { char buff[1024 > SSIZE_MAX ? SSIZE_MAX : 1024]; int r = read(*fd, buff, sizeof buff); if (r > 0) BAIL_IF(fwrite(buff, 1, r, target) != (unsigned)r); else if (r == 0) *fd = -1; else BAIL_IF(errno != EAGAIN && errno != EINTR); } } void select_loop(int iomaster, int emaster, pid_t child_id) { pid_t pid = 0; fd_set fds; int waitstat = 0; while (1) { int n = 0; FD_ZERO(&fds); if (iomaster != -1) FD_SET(iomaster, &fds); if (emaster != -1) FD_SET(emaster, &fds); n = (iomaster > n) ? (iomaster > emaster ? iomaster :emaster) : n; /* TODO: forward input to child. */ if (n > 0) { struct timeval tv = { 0, 10000 }; int s = select(n + 1, &fds, NULL, NULL, &tv); BAIL_IF(s < 0); forward_child_output(fds, &iomaster, stdout); forward_child_output(fds, &emaster, stderr); } if (pid == 0) BAIL_IF((pid = waitpid(child_id, &waitstat, WNOHANG)) < 0); /* If communications channels are closed and the child has finished, * we're done */ if (pid != 0 && iomaster == -1 && emaster == -1) break; } } int main(int argc, char **argv) { int iomaster, ioslave, emaster, eslave; pid_t pid; BAIL_IF(argc < 2); make_pt(&iomaster, &ioslave); make_pt(&emaster, &eslave); BAIL_IF((pid = fork()) < 0); if (pid == 0) { /* in the child */ close(iomaster); close(emaster); BAIL_IF(dup2(ioslave, STDIN_FILENO) < 0); BAIL_IF(dup2(ioslave, STDOUT_FILENO) < 0); BAIL_IF(dup2(eslave, STDERR_FILENO) < 0); BAIL_IF(execvp(argv[1], argv + 1) < 0); } else { /* in the parent */ close(ioslave); close(eslave); set_non_blocking(iomaster); set_non_blocking(emaster); select_loop(iomaster, emaster, pid); close(iomaster); close(emaster); } return 0; }Last edited by edd____; 07-22-2008 at 07:35 PM. Reason: Added code tags


Reply With Quote