geektron has asked for the wisdom of the Perl Monks concerning the following question:

this is a snippet from a child process ( the $to_parent is an already-defined IO::Socket object that sends info back to the parent process for data collection ). i'm consistently getting 'Permission Denied' errors - which is fine, because I want to trap errors also - but they're printed to STDOUT, and not captured in the read filehandle passed into open3. am i missing something obvious? mininal code sample
my $writer = IO::Handle->new(); my $reader = IO::Handle->new(); eval { my $cpid = open3( $writer, $reader, $reader, "rsh $name show hard +serial" ); }; print $to_parent "ERROR::$name--refused RCP command\n" if ( $@ =~ /ope +n3/ ); my $return_val = <$reader> ; chomp $return_val; #for debugging print STDOUT "RETURNED: $return_val\n"; print $to_parent "RESULTS::RCP:$name--RCP Successful\n" if ( $return_v +al );

Replies are listed 'Best First'.
RE (tilly) 1: Open3 in child process not capturing errors correctly. .
by tilly (Archbishop) on Oct 26, 2000 at 05:19 UTC
    I would guess that rsh is doing something strange. I don't have it here but the code example looks like it should work. Certainly the following snippet works perfectly:
    #! /usr/bin/perl use IPC::Open3; use IO::Handle; my $writer = IO::Handle->new(); my $reader = IO::Handle->new(); eval { my $cpid = open3( $writer, $reader, $reader, "perl" ); }; die if $@; print $writer <<'PROG'; print STDOUT "Hello to STDOUT\n"; print STDERR "Hello to STDERR\n"; PROG close($writer); print <$reader> if @ARGV;
    I would try the rsh command from the shell, redirecting errors using the standard 2>&1 syntax.

    But an important non-stylistic note. After your eval, check $@ and if it is true then make darned sure that you register an error. Also make sure that the error message has all of the information listed in perlstyle. In this case that would include your description of what was going on, the exact rpc command, and the full text of the error. Look for the "open3" pattern to figure out whether you will die or print a message. But make that message actually useful for debugging!!!

    Based on past painful experience I will refuse to work with code that doesn't take this basic step. Education is key. And a job where I found myself dealing with this kind of code without being allowed to do something about it (eg rewrite) would be a job I would shortly leave...

      on the non-stylistic tip: i had the check for $@ in there originally. it was rather sloppy of me to not have it in the posted snippet.

      i'm just stumped, because a similar throw-away script i wrote works fine ( but has globbed filehandles instead of IO::Handle objects ).

Re: Open3 in child process not capturing errors correctly. .
by Fastolfe (Vicar) on Oct 26, 2000 at 00:45 UTC
    open3 requires three different file handles for stdin, stdout and stderr. You're attempting to use the same one for stdout and stderr, which I suspect will only cause it to catch data being sent to stderr. Try breaking it up into 3 distinct file handles and deal with both stdout and stderr separately.

    Update: My bad, guess you can do it that way.

      not according to perldoc:
      perldoc IPC::Open3 snippage here. . . . DESCRIPTION Extremely similar to open2(), open3() spawns the given $cmd and connects RDRFH for reading, WTRFH for writing, and ERRFH for errors. If ERRFH is '', or the same as RDRFH, then STDOUT and STDERR of the child are on the same file handle. The WTRFH will have autoflush turned on. If WTRFH begins with "<&", then WTRFH will be closed in the parent, and the child will read from it directly. If RDRFH or ERRFH begins with ">&", then the child will send output directly to that file handle. In both cases, there will be a dup(2) instead of a pipe(2) made.

      the open3 STDOUT and STDERR can be on the same filehandle.

Re: Open3 in child process not capturing errors correctly. .
by mdillon (Priest) on Oct 26, 2000 at 00:45 UTC
    you're passing the same file handle for STDERR and STDOUT. try creating a third handle $error and pass it as the third parameter to open3.
      see reply to Fastolfe's advice.

      besides, i tried it anyway, and it didn't work . . .

Re: Open3 in child process not capturing errors correctly. .
by Anonymous Monk on Oct 26, 2000 at 05:48 UTC
    I've had really weird problems with open3, trying to write a wrapper for megahal. I ended up having to use open2() and just ignore stderr altogether, otherwise megahal would eventually just sieze up on me.

    The only thing I could think of is that IPC::Open3 isn't cooking things correctly.

RE: Open3 in child process not capturing errors correctly. .
by geektron (Curate) on Oct 27, 2000 at 01:44 UTC
    FIXED!!!

    after watching  truss output and getting another set of eyes on the whole script, we found that a little piece of duct-tape was breaking the  open3 bindings:

    this was in the child process BEFORE the actual processing was done:

     *STDERR = $to_parent;

    and that broke the redirection for  open3 because of something about incorrect file descriptor numbers. . . .