| Comments: |
From: dasht_brk Mon, 19-Nov-2007 12:03 AM (UTC)
Ceci n'est pay une pipe | (Link)
|
It's a pty, really.
I wonder if it's one of those cases like on old modem-based BBS' where the hang-up signal of the remote modem could be delivered before some of the type-ahe^D
Doubtless you've done this test already, but it does what you want it to under Linux. Well, under Ubuntu Gutsy anyway.
For some reason, it works just fine on 10.5 when running under dtruss. I don't even claim to understand this.
FWIW, here's an even more minimal test case that doesn't depend on forking:
/* gcc test.c -lutil */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <util.h>
int main (int argc, char **argv) {
int mfd, sfd;
if(openpty(&mfd, &sfd, NULL, NULL, NULL) < 0) {
perror("openpty");
exit(1);
}
write(sfd, "test", 4);
close(sfd);
char buf[64];
int n = read(mfd, buf, 1);
printf("read returned %d\n", n);
exit(0);
}
![[User Picture]](http://p-userpic.livejournal.com/5887295/515656) | From: jwz Mon, 19-Nov-2007 8:39 PM (UTC)
| (Link)
|
Wow, that test does something horrible under 10.4.11 as well. With your code, the read() blocks. But if I comment out the close(), then it hangs after printing "read returned 1", and by "hangs" I mean "kill -9 doesn't work". WTF.
Yikes. Apparently the problem runs deeper than expected.
This works fine for my 10.5.1 install (changing last argument to read to 4 returns whole string).
![[User Picture]](http://p-userpic.livejournal.com/2527387/694455) | From: sweh Mon, 19-Nov-2007 3:39 PM (UTC)
| (Link)
|
Shades of an old old SunOS 4 bug. When the writing end of a pty would close the reader only had a limitted length of time to read the buffer before the kernel would flush it. Annoying. Dunno if Sun ever did fix it. Haven't tested under Solaris 2 'cos I didn't need to do the same sort of work there.
SIGCHILD being interpreted as SIGINT perhaps? SIGDEF'ing SIGCHILD might prove interesting. Python Popen* does this to me sometimes and it really winds me up.
![[User Picture]](http://p-userpic.livejournal.com/5887295/515656) | From: jwz Mon, 19-Nov-2007 8:30 PM (UTC)
| (Link)
|
That would kill the parent, which isn't happening. The pty is getting flushed.
Perhaps you have exceeded your errant punctuation quota.  Feel free to pay me in Basil Hayden my next visit to the bay.
BTW I was joking. I see the bug and am sufficiently bored at work to poke at it. Sec...
Try this:
/* gcc test.c -lutil */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <pty.h> /* or util.h, whatever */
static void crapout(int errfd, const char *what)
{
int save_errno = errno;
dup2(errfd, STDERR_FILENO); /* restore stderr */
errno = save_errno;
perror(what);
_exit(1);
}
static int
do_fork(void)
{
int fd = -1;
pid_t pid;
char slave[42]; /* Can't realistically use PATH_MAX even if it is defined. */
int errfd = dup(STDERR_FILENO);
int save_errno;
fflush(NULL); /* Avoid doubly flushing the same data on exit */
/* but still use _exit() to avoid atexit() weirdness */
slave[0] = 0;
if ((pid = forkpty(&fd, slave, NULL, NULL)) < 0) {
crapout(errfd, "forkpty");
} else if (0 == pid) {
if (NULL == freopen(slave, "w", stdout))
{
crapout(errfd, "freopen");
} else {
close(errfd);
printf("0123456789\n");
_exit(0);
}
} else {
close(errfd);
return fd; /* parent */
}
return -2;
}
int
main (int argc, char **argv)
{
char s[1];
int n;
int fd = do_fork();
/* On 10.4, this prints the whole 10 character line, 1 char per second.
On 10.5, it prints 1 character and stops.
*/
do {
n = read (fd, s, 1);
if (n > 0) fprintf (stderr, "%c", *s);
sleep (1); /* could skip this if '\r'==*s */
} while (n > 0);
return 0;
}
It also works fine if you don't per-byte reads. I'm still not convinced they haven't sinned on this one...
(keeping the same do_fork()):
int main (int argc, char **argv) { char s[1024]; int fd = do_fork();
if(read(fd, s , 1024) != -1) { fprintf(stderr,"child wrote to fd #%d:\n%s",fd, s); } else { perror("read from child borked"); } close(fd); return 0; }
Are you sure this happens on pipes? Your code uses PTYs.
Are you sure that data on PTYs is supposed to hang around indefinitely, according to POSIX, or is that an implementation detail on the other systems? | |