monitoring-plugins/tools/p1.pl
2002-05-02 16:22:13 +00:00

151 lines
3.7 KiB
Perl

package Embed::Persistent;
#
# Hacked version of the sample code from the perlembedded doco.
#
# Only major changes are to separate the compiling and cacheing from
# the execution so that the cache can be kept in "non-volatile" parent
# process while the execution is done from "volatile" child processes
# and that STDOUT is redirected to a file by means of a tied filehandle
# so that it can be returned to NetSaint in the same way as for
# commands executed via the normal popen method.
#
use strict;
use vars '%Cache';
use Symbol qw(delete_package);
package OutputTrap;
#
# Methods for use by tied STDOUT in embedded PERL module.
#
# Simply redirects STDOUT to a temporary file associated with the
# current child/grandchild process.
#
use strict;
# Perl before 5.6 does not seem to have warnings.pm ???
#use warnings;
use IO::File;
sub TIEHANDLE {
my ($class, $fn) = @_;
my $handle = new IO::File "> $fn" or die "Cannot open embedded work filei $!\n";
bless { FH => $handle, Value => 0}, $class;
}
sub PRINT {
my $self = shift;
my $handle = $self -> {FH};
print $handle join("",@_);
}
sub PRINTF {
my $self = shift;
my $fmt = shift;
my $handle = $self -> {FH};
printf $handle ($fmt,@_);
}
sub CLOSE {
my $self = shift;
my $handle = $self -> {FH};
close $handle;
}
package Embed::Persistent;
sub valid_package_name {
my($string) = @_;
$string =~ s/([^A-Za-z0-9\/])/sprintf("_%2x",unpack("C",$1))/eg;
# second pass only for words starting with a digit
$string =~ s|/(\d)|sprintf("/_%2x",unpack("C",$1))|eg;
# Dress it up as a real package name
$string =~ s|/|::|g;
return "Embed::" . $string;
}
sub eval_file {
my $filename = shift;
my $delete = shift;
my $pn = substr($filename, rindex($filename,"/")+1);
my $package = valid_package_name($pn);
my $mtime = -M $filename;
if(defined $Cache{$package}{mtime}
&&
$Cache{$package}{mtime} <= $mtime)
{
# we have compiled this subroutine already,
# it has not been updated on disk, nothing left to do
#print STDERR "already compiled $package->hndlr\n";
}
else {
local *FH;
open FH, $filename or die "open '$filename' $!";
local($/) = undef;
my $sub = <FH>;
close FH;
# cater for routines that expect to get args without prgname
# and for those using @ARGV
$sub = "shift(\@_);\n\@ARGV=\@_;\n" . $sub;
# cater for scripts that have embedded EOF symbols (__END__)
$sub =~ s/__END__/\;}\n__END__/;
#wrap the code into a subroutine inside our unique package
my $eval = qq{
package main;
use subs 'CORE::GLOBAL::exit';
sub CORE::GLOBAL::exit { die "ExitTrap: \$_[0] ($package)"; }
package $package; sub hndlr { $sub; }
};
{
# hide our variables within this block
my($filename,$mtime,$package,$sub);
eval $eval;
}
if ($@){
print STDERR $@."\n";
die;
}
#cache it unless we're cleaning out each time
$Cache{$package}{mtime} = $mtime unless $delete;
}
}
sub run_package {
my $filename = shift;
my $delete = shift;
my $tmpfname = shift;
my $ar = shift;
my $pn = substr($filename, rindex($filename,"/")+1);
my $package = valid_package_name($pn);
my $res = 0;
tie (*STDOUT, 'OutputTrap', $tmpfname);
my @a = split(/ /,$ar);
eval {$res = $package->hndlr(@a);};
if ($@){
if ($@ =~ /^ExitTrap: /) {
$res = 0;
} else {
# get return code (which may be negative)
if ($@ =~ /^ExitTrap: (-?\d+)/) {
$res = $1;
} else {
$res = 2;
print STDERR "<".$@.">\n";
}
}
}
untie *STDOUT;
return $res;
}
1;