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

I'm using a library method repeatedly which makes similar system calls. The problem is, because of a possible fault in a new IOS release the piped command appears to be jamming the filehandle, following calls to the method fail badly. method summary
sub if ($? > 0 ) { $? = 0; } if ( defined(SNMP) ) { close SNMP; } print " /@/ gettable called ($?)\n"; my ($target,$table,$fieldstring,$comstr) = @_; $snmpCmd = "mibtable -table $table -fields $fieldstring -node $ta +rget |"; open (SNMP, $snmpCmd ) || die print STDERR "Couldn't open pipe +: $! \/ $? \/ $@\n"; $error = $?; while (<SNMP>) { # do stuff } my $closed = 13; $closed = close (SNMP) || $! ? "Error closing sort pipe: $!" : "Exit status $? from sort"; print "\tDid filehandle get closed: '$closed'\n"; undef SNMP; print STDERR "!!!! $! \/ $? \/ $@\n";
The first call to this method appears to works fine, even though the child process prints an error to STDERR. The method completes normally. Subsequent calls fail. Here's the output, the test script hits two separate mibtable, if the order is reversed, the second one would succeed.
dncms@case3 ~ 621 > perl testSnmp2.pl node /@/ gettable called (0) snmpCmd: 'mibtable -table table1 -fields fields1 -node node |' pid: 1168 -1- (bootflash + 65451748 65536000) -2- (sw1-slot2-dfc-bootflash + 15990784 15990784) -3- (sw1-slot3-dfc-bootflash + 15990784 15990784) -4- (sw1-slot6-dfc-bootflash + 15990784 15990784) -5- (sw1-slot7-dfc-bootflash + 15990784 15990784) Error retrieving information from node No response arrived before timeout Did filehandle get closed: 'Exit status 256 from sort' !!!! / 256 / END GETTABLE (What is $?: 256) Errno from pipe: (piped exit code: 1) / (signal: 0) / (core dump: 0) [ +0] What is $?: 256 /@/ gettable called (0) snmpCmd: 'mibtable -table table1 -fields fields2 -node node |' pid: 1171 Error retrieving information from node No response arrived before timeout Did filehandle get closed: 'Exit status 256 from sort' !!!! / 256 / END GETTABLE What is $?: 256
All I know is that the 'mibtable' command is returning "Error retrieving information from node No response arrived before timeout" to STDERR and $? is being set to 256. Despite the filehandle SNMP being closed and undeffed, subsequent attempts to use the method fail because, presumably, the filehandle is jammed in some way. It doesn't clear until the perl script exits. BTW- I'm using Perl 5.6.1. Any ideas how to clear the FH so I can reuse the method? Thanks!

Replies are listed 'Best First'.
Re: Jammed FH pipe
by ikegami (Patriarch) on Oct 07, 2009 at 21:08 UTC

    Start by not using a global var (*SNMP). If you insist, at least localize it. If it ceases to exist, it's hard for it to be "jammed".

    Fixed along with *many* other problems:

    sub { my ($target, $table, $fieldstring, $comstr) = @_; my @cmd = ( mibtable => ( -table => $table, -fields => $fieldstring, -node => $target, ); open(my $fr_child, '-|', @cmd) or die("Can't launch $cmd[0]: $!\n"); while (<$fr_child>) { # do stuff } close($fr_child) or die("Can't wait for child: $!\n"); die("Child died from signal ", ($? & 0x7F), "\n") if $? & 0x7F; die("Child died with code ", ($? >> 8), "\n") if $? >> 8; print("Child exited successfully\n"); }
      Thanks, I tried some of these changes to the 'open' line, but problems still choke the process:

      $pid = open( my $fr_child, '-|', @cmd) or die("Can't launch $cmd[0]: $!\n");
      fails with an error: Can't use an undefined value as filehandle reference at testSnmp2.pl line 192.

      Tweaked to look like this

      $pid = open( my $fr_child, '-|', $snmpCmd) or die("Can't launch $cmd[0]: $!\n");
      The open succeeds, but I get this error from the child proc
      Child exited successfully !!!! Illegal seek / 0 /
      and I get no data back.

      Tweaked again to be

      $pid = open( my $fr_child, $snmpCmd) or die("Can't launch $cmd[0]: $!\n");
      I get the following response: Can't wait for child: with an $? value of 256.

      If it helps, I'm running on Solaris 8.

        I just noticed the 5.6 limit now. That explains some of the reasons my code won't do for you.

        Reverting to using $snmpCmd is wrong though. Sure, you'll need to provide the command as a string in 5.6, but you don't properly convert the args into shell literals at the moment.

        Nothing in my code can output "!!!! Illegal seek / 0 /", so I don't know anything about that.

        I get the following response: Can't wait for child: with an $? value of 256.

        Looks like there's a bug in Perl's design. There's no reliable way to tell if close returns a system error ($!) or a child error ($?)*.

        ( On second thought, we'll get the wrong error message at worse, so I will use $!==0 )

        sub to_shell_literal { my ($s) = @_; #return $s if m{^[a-zA-Z0-9/_-]+\z}; $s =~ s/'/'\\''/g; return "'$s'"; } sub { my ($target, $table, $fieldstring, $comstr) = @_; my @cmd = ( mibtable => ( -table => $table, -fields => $fieldstring, -node => $target, ); my $cmd = join ' ', map to_shell_literal($_), @cmd; open(my $fr_child, "$cmd |") or die("Can't launch $cmd[0]: $!\n"); while (<$fr_child>) { # do stuff } if (!close($fr_child)) { die("Can't wait for child: $!\n") if $! != 0; die("Child died from signal ", $? & 0x7F, "\n") if $? & 0x7F; die("Child died with code ", $? >> 8, "\n") if $? >> 8; die("Unknown error waiting for child\n"); } print("Child exited successfully\n"); }

        * — Yeah, the documentation says $! will be zero in this instance, but I don't trust it. At least one other instance where the docs ignored "$! is only meaningful on error" has turned out to be wrong.

        I don't know the mibtable program, but are you sure it works in a pipe? Is Illegal seek coming from perl or mibtable? I suggest you try the program with exactly the same parameters on the command-line piped to something like od(1). Maybe it is trying to do operations (like a seek) on the pipe which are illegal. An strace or truss might help as well.