
Hi all, I found this blogpost from Bryan O'Sullivan http://www.serpentine.com/blog/2008/09/30/unix-hacking-in-haskell-better-pse... and I wanted to try it out. Before moving to an interactive command (which needs pty), I just did a small test for "ls -l /" to see if it worked. I got it to compile, but when running, it throws an exception when reaching the end of the output (in this case because I evaluate the length to force reading all). Main: /dev/ptmx: hGetContents: hardware fault (Input/output error) Please have a look at the hpaste to see what I did: http://hpaste.org/fastcgi/hpaste.fcgi/view?id=23343 What's wrong? :) My guess is that hGetContents doesn't receive a nice EOF when the process exits (ls doesn't stay around waiting for input), but I have no idea on how to fix this. And further... If I do want to use an interactive program which needs input, how do I send ctrl-d or ctrl-c? tail -f needs ctrl-c (or I need to kill the process) Thanks for any help Mathijs PS: I know about libexpect, it's not useful for what I wanna do (multiple processes, having 'answers' from 1 be used to decide what to input the other, without ending the 'answer' process)

And further... If I do want to use an interactive program which needs input, how do I send ctrl-d or ctrl-c? tail -f needs ctrl-c (or I need to kill the process)
You want Ctrl-d in Unix-based OSs and Ctrl-z in Windows: http://en.wikipedia.org/wiki/End_of_File . Ctrl-c kills a program. -- Ivan Lazar Miljenovic Ivan.Miljenovic@gmail.com IvanMiljenovic.wordpress.com

On Mar 9, 2010, at 9:35 AM, Ivan Lazar Miljenovic wrote:
And further... If I do want to use an interactive program which needs input, how do I send ctrl-d or ctrl-c? tail -f needs ctrl-c (or I need to kill the process)
You want Ctrl-d in Unix-based OSs and Ctrl-z in Windows: http://en.wikipedia.org/wiki/End_of_File . Ctrl-c kills a program.
The statement about UNIX is not quite right. UNIX has *NO FIXED END-OF-FILE CHARACTER*. Strictly speaking, it doesn't have an end-of-file character at all. What the UNIX terminal driver (and interfaces that emulate it) has is a "send this line now with no terminator" character. abcd<EOF> sends "abcd" to the program sans \n ab<EOF> sends "ab" to the program sans \n <EOF> sends "" to the program Program does n = read(0, buffer, sizeof buffer); User types ab<EOF> buffer gets "ab", n gets 2. Program does if (n == 0) handle_eof(); which does nothing. Program calls read again, User types <EOF> buffer gets no data, n gets 0, program tests n against 0 and goes off to do the EOF thing. So the <EOF> character *only* means <EOF> when nothing precedes it on the current line. Why do I write <EOF> rather than ^D? Because nothing in UNIX anywhere says that <EOF> *has* to be ^D, it's just a default. Back in the old V6 days, I saw no more reason to stick with that default than I saw to stick with the default of '#' for character erase and '@' for line kill. I've been using ^Z for <EOF> in UNIX longer than Windows (or DOS before it) has _existed_. If you want to know what character to send for end-of-file when communicating with a UNIX system, use stty(1) to find out what the <EOF> character actually is. Insisting on ^D is not just wrong, it's rude.

On 20:38 Mon 08 Mar , Mathijs Kwik wrote:
Hi all,
I found this blogpost from Bryan O'Sullivan http://www.serpentine.com/blog/2008/09/30/unix-hacking-in-haskell-better-pse... and I wanted to try it out.
Before moving to an interactive command (which needs pty), I just did a small test for "ls -l /" to see if it worked. I got it to compile, but when running, it throws an exception when reaching the end of the output (in this case because I evaluate the length to force reading all). Main: /dev/ptmx: hGetContents: hardware fault (Input/output error)
You have just stumbled into the wonderful world of pseudo-terminals, where their behaviour is subtly different on every bloody platform. It appears that on your platform, after the last user closes the slave port (i.e. after your child process terminates), subsequent reads from the master port return EIO. One would normally detect this condition with the poll system call, by looking for POLLHUP on the master port. On some platforms (but evidently not yours), the last close of the slave port causes the behaviour you seem to have expected, where a subsequent read returns 0.
What's wrong? :)
Presumably the problem is that handle-based I/O is not suitable for pseudo-terminal masters. Definitely not lazy I/O.
And further... If I do want to use an interactive program which needs input, how do I send ctrl-d or ctrl-c? tail -f needs ctrl-c (or I need to kill the process)
These so-called "control characters" are normally configured by termios. If suitably configured, the appropriate action will be performed when the control characters are written to the master port. -- Nick Bowler, Elliptic Technologies (http://www.elliptictech.com/)

Ok, cool
I got a bit further now.
I'm not using handles anymore (they seem to break indeed for ptys).
Just using executePseudoTerminalFd now (from the original blogpost)
and fdRead/fdWrite.
Now I can communicate with the process and all goes well.
If I really want lazy-like behaviour, I can just forkIo and talk
through a Chan, but for now this is enough.
Also sending "\^C" and "\^D" work as expected, although I just saw the
reply mentioning I should ask stty for the current EOF character.
The only thing I'm still looking for is a way to stop echoing input.
Right now, fdRead gives me back the output of the process, mixed with
the input I supplied.
I'm pretty sure this can be turned off.
Any suggestions?
On Mon, Mar 8, 2010 at 11:11 PM, Nick Bowler
On 20:38 Mon 08 Mar , Mathijs Kwik wrote:
Hi all,
I found this blogpost from Bryan O'Sullivan http://www.serpentine.com/blog/2008/09/30/unix-hacking-in-haskell-better-pse... and I wanted to try it out.
Before moving to an interactive command (which needs pty), I just did a small test for "ls -l /" to see if it worked. I got it to compile, but when running, it throws an exception when reaching the end of the output (in this case because I evaluate the length to force reading all). Main: /dev/ptmx: hGetContents: hardware fault (Input/output error)
You have just stumbled into the wonderful world of pseudo-terminals, where their behaviour is subtly different on every bloody platform. It appears that on your platform, after the last user closes the slave port (i.e. after your child process terminates), subsequent reads from the master port return EIO.
One would normally detect this condition with the poll system call, by looking for POLLHUP on the master port.
On some platforms (but evidently not yours), the last close of the slave port causes the behaviour you seem to have expected, where a subsequent read returns 0.
What's wrong? :)
Presumably the problem is that handle-based I/O is not suitable for pseudo-terminal masters. Definitely not lazy I/O.
And further... If I do want to use an interactive program which needs input, how do I send ctrl-d or ctrl-c? tail -f needs ctrl-c (or I need to kill the process)
These so-called "control characters" are normally configured by termios. If suitably configured, the appropriate action will be performed when the control characters are written to the master port.
-- Nick Bowler, Elliptic Technologies (http://www.elliptictech.com/)

And to reply to myself again...
ta <- getTerminalAttributes fd
setTerminalAttributes fd (withoutMode ta EnableEcho) Immediately
-- and to find the right EOF character:
let Just eofChar = controlChar ta EndOfFile
On Tue, Mar 9, 2010 at 12:23 AM, Mathijs Kwik
Ok, cool
I got a bit further now. I'm not using handles anymore (they seem to break indeed for ptys). Just using executePseudoTerminalFd now (from the original blogpost) and fdRead/fdWrite. Now I can communicate with the process and all goes well. If I really want lazy-like behaviour, I can just forkIo and talk through a Chan, but for now this is enough.
Also sending "\^C" and "\^D" work as expected, although I just saw the reply mentioning I should ask stty for the current EOF character.
The only thing I'm still looking for is a way to stop echoing input. Right now, fdRead gives me back the output of the process, mixed with the input I supplied. I'm pretty sure this can be turned off.
Any suggestions?
On Mon, Mar 8, 2010 at 11:11 PM, Nick Bowler
wrote: On 20:38 Mon 08 Mar , Mathijs Kwik wrote:
Hi all,
I found this blogpost from Bryan O'Sullivan http://www.serpentine.com/blog/2008/09/30/unix-hacking-in-haskell-better-pse... and I wanted to try it out.
Before moving to an interactive command (which needs pty), I just did a small test for "ls -l /" to see if it worked. I got it to compile, but when running, it throws an exception when reaching the end of the output (in this case because I evaluate the length to force reading all). Main: /dev/ptmx: hGetContents: hardware fault (Input/output error)
You have just stumbled into the wonderful world of pseudo-terminals, where their behaviour is subtly different on every bloody platform. It appears that on your platform, after the last user closes the slave port (i.e. after your child process terminates), subsequent reads from the master port return EIO.
One would normally detect this condition with the poll system call, by looking for POLLHUP on the master port.
On some platforms (but evidently not yours), the last close of the slave port causes the behaviour you seem to have expected, where a subsequent read returns 0.
What's wrong? :)
Presumably the problem is that handle-based I/O is not suitable for pseudo-terminal masters. Definitely not lazy I/O.
And further... If I do want to use an interactive program which needs input, how do I send ctrl-d or ctrl-c? tail -f needs ctrl-c (or I need to kill the process)
These so-called "control characters" are normally configured by termios. If suitably configured, the appropriate action will be performed when the control characters are written to the master port.
-- Nick Bowler, Elliptic Technologies (http://www.elliptictech.com/)
participants (4)
-
Ivan Lazar Miljenovic
-
Mathijs Kwik
-
Nick Bowler
-
Richard O'Keefe