Click here to get back home

IO::Pty - reads/writes fail *only* with system()

 HomeNewsGroups | Search | About
 comp.lang.perl.modules    Post an article   get this group's latest topics as an RSS feed add this group's latest topics to your My MSN content add this group's latest topics to your My Yahoo content
Subject Author Date
IO::Pty - reads/writes fail *only* with system() Alexis Huxley 01-10-2006
Posted by Alexis Huxley on January 10, 2006, 1:59 pm
Please log in for more thread options


Starting from the example in the IO::Pty man page I've now got a
perl script which forks, the child reopens stdin/stdout on the
slave side of the pty, and the parent reopens on the master side.

The child writes to STDOUT using 'print', the parent reads from
STDIN using 'while (<>) ...'. This works fine.

I changed the child to write using 'system("echo ...")' and later
I changed the parent to read using 'sed' or 'cat'. This fails,
and I can't see why.

Using only the child using 'system()' the output simply never
appears on the parent side. Using only the parent using 'system()'
results in:

        sed: read error on stdin: Bad file descriptor

I tried various combinations of the set_raw() and setting the
controlling terminal of the child using the documented methods,
but still no dice. Googling brings up plenty of pre-OO examples
of pty but nothing besides what's in the FAQ and the perlipc
man page.

Judging by the sed error message, I guess somehow my plumbing
of file handles has gone wrong, but I just can't see it, especially
as it works when - as mentioned above - I use 'print' for the
output and 'while (<>) ..." for the input. Has anybody any ideas?

The script is short and reproduced below. As it is it works, but
with either of the current write/read lines replaced by the
system() equivalents, it will fail:

#!/usr/bin/perl

use IO::Pty;
$pty = new IO::Pty;
$slave = $pty->slave;
(defined($pid = fork)) || die "fork failed";


# Child
if ($pid == 0) {
$pty->make_slave_controlling_terminal() || die;
close($pty);

# Remap stdin and stdout to slave side of pty
close(STDOUT);
open(STDOUT, ">&=" . $slave->fileno) || die;
close(STDIN);
open(STDIN, "<&=" . $slave->fileno) || die;

# -- write options: print works, system doesn't!
print "To be or not to be, that is the question.\n";
#system("echo \"To be or not to be, that is the question.\"");

# Tidy up
close($slave);

# Parent
} else {
$pty->close_slave();

# Remap stdin and stdout to master side of pty
close(STDOUT);
open(STDOUT, ">&=" . $pty->fileno) || die;
close(STDIN);
open(STDIN, "<&=" . $pty->fileno) || die;

# -- read options: print (<>), system doesn't!
while (<>) { chomp; print STDERR "parent read from slave: $_\n"; }
#system("sed 's/^/parent read from slave: /'");

# Tidy up
close($pty);
}

In case it's relevent:

This is perl, v5.8.4 built for i386-linux-thread-multi, running on
Debian Linux.

(Ultimately what I'm trying to do is rewrite a script I googled called
ssh-ppp, which runs 'ssh <host> pppd' in one half, and 'pppd' in
the other. Yes, I know that pppd has a 'pty' directive, but that just
doesn't cut the mustard for what I want ,which is to do
'su -c "ssh -t <first-hop> ssh -t <second-hop> slogin <third-hop>"'
where my shell on <third-hop> is pppd, and all hops require inputting
password, and avoiding entering passwords by using RSA authentication
is neither possible nor desirable.)

Thanks for reading so far :-) and any advice you can offer; the
results of this labour will be google-able.

Alexis


Posted by harryfmudd [AT] comcast [DOT] on January 10, 2006, 9:16 am
Please log in for more thread options


Alexis Huxley wrote:
> Starting from the example in the IO::Pty man page I've now got a
> perl script which forks, the child reopens stdin/stdout on the
> slave side of the pty, and the parent reopens on the master side.
>
> The child writes to STDOUT using 'print', the parent reads from
> STDIN using 'while (<>) ...'. This works fine.
>
> I changed the child to write using 'system("echo ...")' and later
> I changed the parent to read using 'sed' or 'cat'. This fails,
> and I can't see why.
>
> Using only the child using 'system()' the output simply never
> appears on the parent side. Using only the parent using 'system()'
> results in:
>
>         sed: read error on stdin: Bad file descriptor
>
> I tried various combinations of the set_raw() and setting the
> controlling terminal of the child using the documented methods,
> but still no dice. Googling brings up plenty of pre-OO examples
> of pty but nothing besides what's in the FAQ and the perlipc
> man page.
>
> Judging by the sed error message, I guess somehow my plumbing
> of file handles has gone wrong, but I just can't see it, especially
> as it works when - as mentioned above - I use 'print' for the
> output and 'while (<>) ..." for the input. Has anybody any ideas?
>
> The script is short and reproduced below. As it is it works, but
> with either of the current write/read lines replaced by the
> system() equivalents, it will fail:
>
> #!/usr/bin/perl
>
> use IO::Pty;
> $pty = new IO::Pty;
> $slave = $pty->slave;
> (defined($pid = fork)) || die "fork failed";
>
>
> # Child
> if ($pid == 0) {
> $pty->make_slave_controlling_terminal() || die;
> close($pty);
>
> # Remap stdin and stdout to slave side of pty
> close(STDOUT);
> open(STDOUT, ">&=" . $slave->fileno) || die;
> close(STDIN);
> open(STDIN, "<&=" . $slave->fileno) || die;
>
> # -- write options: print works, system doesn't!
> print "To be or not to be, that is the question.\n";
> #system("echo \"To be or not to be, that is the question.\"");

How about

print `echo "To be or not to be, what was the question?"`;

>
> # Tidy up
> close($slave);
>
> # Parent
> } else {
> $pty->close_slave();
>
> # Remap stdin and stdout to master side of pty
> close(STDOUT);
> open(STDOUT, ">&=" . $pty->fileno) || die;
> close(STDIN);
> open(STDIN, "<&=" . $pty->fileno) || die;
>
> # -- read options: print (<>), system doesn't!
> while (<>) { chomp; print STDERR "parent read from slave: $_\n"; }
> #system("sed 's/^/parent read from slave: /'");

How about

open SED, "|sed 's/^parent read from slave: /'" or die;
while (<>) {print SED}

But I'm not sure what sed does for you that Perl won't. My sed is really
rusty, but I suspect your sed is the equivalent of command different from

while (<>) {s/^/parent read from slave: /; print}

and I suspect that anything you wanted to do to the input stream could
be done just as well with Perl.

>
> # Tidy up
> close($pty);
> }
>
> In case it's relevent:
>
> This is perl, v5.8.4 built for i386-linux-thread-multi, running on
> Debian Linux.
>
> (Ultimately what I'm trying to do is rewrite a script I googled called
> ssh-ppp, which runs 'ssh <host> pppd' in one half, and 'pppd' in
> the other. Yes, I know that pppd has a 'pty' directive, but that just
> doesn't cut the mustard for what I want ,which is to do
> 'su -c "ssh -t <first-hop> ssh -t <second-hop> slogin <third-hop>"'
> where my shell on <third-hop> is pppd, and all hops require inputting
> password, and avoiding entering passwords by using RSA authentication
> is neither possible nor desirable.)
>
> Thanks for reading so far :-) and any advice you can offer; the
> results of this labour will be google-able.
>
> Alexis

The basic problem is that just kicking off a system command doesn't
necessarily magically connect the command's STDIN and STDOUT to yours.

Tom Wyant


Posted by Alexis Huxley on January 10, 2006, 3:27 pm
Please log in for more thread options


>> Starting from the example in the IO::Pty man page I've now got a
>> perl script which forks, the child reopens stdin/stdout on the
>> slave side of the pty, and the parent reopens on the master side.
>> ...
>
> print `echo "To be or not to be, what was the question?"`;
>
> How about
>
> open SED, "|sed 's/^parent read from slave: /'" or die;
> while (<>) {print SED}
>
>> ...
>> (Ultimately what I'm trying to do is rewrite a script I googled called
>> ssh-ppp, which runs 'ssh <host> pppd' in one half, and 'pppd' in
>> the other. Yes, I know that pppd has a 'pty' directive, but that just
>> doesn't cut the mustard for what I want ,which is to do

Maybe I wasn't clear enough; the echo and sed commands are not what I
want to do *ultimately*; they will be replaced by calls to ssh and to
pppd respectively. But I want to start simple.

> The basic problem is that just kicking off a system command doesn't
> necessarily magically connect the command's STDIN and STDOUT to yours.

Yes, as I said, I think my plumbing is somehow wrong. But still, these
handles are generally inherited otherwise the following command would
produce some output, which it doesn't:

        sh -c 'echo hello >&2' 2>/dev/null

and that being so, my the error in my script isn't obvious to me; hence
asking, specifically, what did I do wrong? THanks!

Alexis


Similar ThreadsPosted
CPAN testers and FAIL/NA. November 8, 2004, 5:32 am
WARNING do not install Devel::Fail::MakeTest February 11, 2005, 7:53 am
LWP fail to catch loading balacing websites March 9, 2005, 6:10 am
system return value? January 26, 2007, 5:52 pm
System call fails in webserver February 11, 2006, 11:04 am
List of all modules installed on a system August 8, 2007, 1:41 pm
Detecting Intruders on Your System Is Fun and Easy December 11, 2007, 8:52 am
Excel file manipulation in HPUX system October 14, 2004, 8:13 am
Problems building Javascript-1.00 on Win32 system November 11, 2006, 9:59 pm
Perl module disk usage, for embedded system. December 5, 2005, 8:38 am

Our other projects:

Art Dolls, Fairies and Mermaids - Sunnyfaces.net

Roy's Linux, Programming and Search Engines messages

1-Script XML SitemapXML Sitemap