Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Perl > Perl Misc > re-launch piped external program

Reply
Thread Tools

re-launch piped external program

 
 
rihad
Guest
Posts: n/a
 
      09-21-2007
Hello, Perl hackers,

I'm writing a Perl script that runs FreeBSD's ipfw( and writes
certain commands to it through a pipe, line by line:

open OUT, "|-", "ipfw", "/dev/stdin" or die "$! $?";
while (1) {
print OUT $command, "\n";
}

Sometimes $command causes parse errors (due to manipulation of a
nonexistent rule, or similar), and ipfw dies... Is there any way to
catch and acknowledge that fact, and re-run myprog for subsequent
iterations?

 
Reply With Quote
 
 
 
 
Ben Morrow
Guest
Posts: n/a
 
      09-21-2007

Quoth rihad <(E-Mail Removed)>:
> Hello, Perl hackers,
>
> I'm writing a Perl script that runs FreeBSD's ipfw( and writes
> certain commands to it through a pipe, line by line:
>
> open OUT, "|-", "ipfw", "/dev/stdin" or die "$! $?";


Don't use global filehandles. Use variable instead, and give them proper
names:

open my $IPFW, "|-", "ipfw", "/dev/stdin" or...

> while (1) {
> print OUT $command, "\n";


You can avoid the need for this "\n" by setting $\.

> }
>
> Sometimes $command causes parse errors (due to manipulation of a
> nonexistent rule, or similar), and ipfw dies... Is there any way to
> catch and acknowledge that fact, and re-run myprog for subsequent
> iterations?


If you attempt to write to a pipe which has been closed (say, because
the process on the other end has died) your program will be sent a
SIGPIPE. The default action for this is to terminate your program, but
you can catch it (see perldoc perlipc) and recover. Alternatively, you
can ignore it ($SIG{PIPE} = 'IGNORE') and check the return value from
print. If it failed, and $! == EPIPE (EPIPE can be imported from the
POSIX module), then your process has died. This may be simpler than
trying to use a signal handler (signals don't really behave terribly
well).

Note that you should explicitly close the filehandle if the process
dies, as that causes perl to wait for the child; if you don't, you'll
start accumulating zombie processes.

Ben

 
Reply With Quote
 
 
 
 
xhoster@gmail.com
Guest
Posts: n/a
 
      09-21-2007
rihad <(E-Mail Removed)> wrote:
> Hello, Perl hackers,
>
> I'm writing a Perl script that runs FreeBSD's ipfw( and writes
> certain commands to it through a pipe, line by line:
>
> open OUT, "|-", "ipfw", "/dev/stdin" or die "$! $?";
> while (1) {
> print OUT $command, "\n";
> }
>
> Sometimes $command causes parse errors (due to manipulation of a
> nonexistent rule, or similar), and ipfw dies... Is there any way to
> catch and acknowledge that fact, and re-run myprog for subsequent
> iterations?


If ipfw dies, then your process should be delivered a CHLD signal,
which can be captured by putting code in $SIG{CHLD};

my $foo;
while (1) {
$foo=1;
$SIG{CHLD}=sub {$foo=0};
open OUT, "|-", "ipfw", "/dev/stdin" or die "$! $?";
while ($foo) {
print OUT $command, "\n";
}
close OUT or warn "failed with $? $!";
};

There is no general reason to think that the program will die instantly
or that the signal will be delivered instantly, so you may not fall out of
the loop until several iterations after the $command that actually
triggered the error. So you are playing with fire. (especially since you
don't show us how $command ever changes, so there may be hidden problems
there as well).

Xho

--
-------------------- http://NewsReader.Com/ --------------------
The costs of publication of this article were defrayed in part by the
payment of page charges. This article must therefore be hereby marked
advertisement in accordance with 18 U.S.C. Section 1734 solely to indicate
this fact.
 
Reply With Quote
 
rihad
Guest
Posts: n/a
 
      09-21-2007
Thanks to you both, guys. I'll try the EPIPE trick as soon as I get
over this small problem:

$\ = "\n";
$| = 1;
open my $FW, "|-", "sudo", "ipfw", "/dev/stdin" or die "can't run
ipfw: $!";
$| = 1;
print $FW 'add';
sleep 10;
exit;

I gave ipfw erroneous input on purpose ('add' requires argument list).
No matter what I tried: ipfw's pre-mortem line on stderr "Line 1:
missing action" won't show up on the screen until after 10 seconds
have passed. And I can see ipfw hanging there during that time from
another console using ps. Looks like Perl holds on to the line for
some reason. Someone care to explain what I did wrong?

 
Reply With Quote
 
xhoster@gmail.com
Guest
Posts: n/a
 
      09-21-2007
rihad <(E-Mail Removed)> wrote:
> Thanks to you both, guys. I'll try the EPIPE trick as soon as I get
> over this small problem:
>
> $\ = "\n";
> $| = 1;
> open my $FW, "|-", "sudo", "ipfw", "/dev/stdin" or die "can't run
> ipfw: $!";
> $| = 1;
> print $FW 'add';
> sleep 10;
> exit;
>
> I gave ipfw erroneous input on purpose ('add' requires argument list).
> No matter what I tried: ipfw's pre-mortem line on stderr "Line 1:
> missing action" won't show up on the screen until after 10 seconds
> have passed. And I can see ipfw hanging there during that time from
> another console using ps. Looks like Perl holds on to the line for
> some reason. Someone care to explain what I did wrong?


Maybe ipfw doesn't flush stderr until either the buffer is full or until
its stdin gets closed, which doesn't happen here until the parent program
exits.

Xho

--
-------------------- http://NewsReader.Com/ --------------------
The costs of publication of this article were defrayed in part by the
payment of page charges. This article must therefore be hereby marked
advertisement in accordance with 18 U.S.C. Section 1734 solely to indicate
this fact.
 
Reply With Quote
 
rihad
Guest
Posts: n/a
 
      09-22-2007
> > have passed. And I can see ipfw hanging there during that time from
> > another console using ps. Looks like Perl holds on to the line for
> > some reason. Someone care to explain what I did wrong?

>
> Maybe ipfw doesn't flush stderr until either the buffer is full or until
> its stdin gets closed, which doesn't happen here until the parent program
> exits.
>


*Perl* holds on to the $command line even though I turned auto-flush
on with $| = 1;
As I said ipfw is hanging there all along, which wouldn't be the case
if it got the flawed command from the pipe immediately.

 
Reply With Quote
 
Peter Scott
Guest
Posts: n/a
 
      09-22-2007
On Fri, 21 Sep 2007 11:46:28 -0700, rihad wrote:
> Thanks to you both, guys. I'll try the EPIPE trick as soon as I get
> over this small problem:
>
> $\ = "\n";
> $| = 1;
> open my $FW, "|-", "sudo", "ipfw", "/dev/stdin" or die "can't run
> ipfw: $!";
> $| = 1;
> print $FW 'add';
> sleep 10;
> exit;


perldoc perlvar:

$| If set to nonzero, forces a flush right away and after every
write or print on the currently selected output channel.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

You did not select $FW as the current output channel.

--
Peter Scott
http://www.perlmedic.com/
http://www.perldebugged.com/

 
Reply With Quote
 
Martien verbruggen
Guest
Posts: n/a
 
      09-22-2007
On Sat, 22 Sep 2007 11:39:51 GMT,
Peter Scott <(E-Mail Removed)> wrote:
> On Fri, 21 Sep 2007 11:46:28 -0700, rihad wrote:
>> Thanks to you both, guys. I'll try the EPIPE trick as soon as I get
>> over this small problem:
>>
>> $\ = "\n";
>> $| = 1;
>> open my $FW, "|-", "sudo", "ipfw", "/dev/stdin" or die "can't run
>> ipfw: $!";
>> $| = 1;
>> print $FW 'add';
>> sleep 10;
>> exit;

>
> perldoc perlvar:
>
> $| If set to nonzero, forces a flush right away and after every
> write or print on the currently selected output channel.
>
> You did not select $FW as the current output channel.


This probably is a good spot to draw attention to IO::Handle's autoflush
method. rather than selecting the file handle you want to flush, you set
the autoflush attribute on those filehandles you want to flush. I find
that generally fits better with the way I think it should work.

Regards,
Martien
--
|
Martien Verbruggen | "In a world without fences,
| who needs Gates?"
|
 
Reply With Quote
 
rihad
Guest
Posts: n/a
 
      09-22-2007
> You did not select $FW as the current output channel.
>


Thank you! Worked like a charm. On a sidenote: I'm a bit new to Perl
(surprise!), and I'm at chapter 4 of "Learning Perl" ("The Llama
book") right now. Then I will read Programming Perl ("The Camel book")
and tons of perldocs. I think perldocs are best at giving minute
technical details, as you mentioned. Thanks again!

 
Reply With Quote
 
rihad
Guest
Posts: n/a
 
      09-24-2007
How can I *easily* run an external program, writing commands to it on
a filehandle, and reading its replies from another? Ironically,
reading Perl FAQ[*] left one question unanswered: where's chat2.pl so
much talked about? I'm asking someone to give a modern (v5.8.
example.
[*] http://www.faqs.org/faqs/perl-faq/part5/

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
capturing STDOUT from and piped "into" program Tim Perl Misc 6 05-02-2007 07:02 PM
Invoking 'diff' from java with piped input David Kensche Java 11 12-10-2004 03:00 PM
Wrapping Piped Streams? Ryan Stewart Java 10 01-11-2004 03:45 PM
reading piped input in Windows Patrick Useldinger Python 4 11-16-2003 02:19 AM
Piped stream help. Andrew Tucker Java 3 10-06-2003 07:39 PM



Advertisments