diff --git a/pandora_agents/unix/pandora_agent b/pandora_agents/unix/pandora_agent
index 51005a3f66..0461b2ff47 100755
--- a/pandora_agents/unix/pandora_agent
+++ b/pandora_agents/unix/pandora_agent
@@ -33,6 +33,9 @@ use IO::Socket;
use Sys::Syslog;
use Time::Local;
+use lib '/usr/lib/perl5';
+use PandoraFMS::Omnishell;
+
# Agent XML data
my $Xml;
@@ -43,7 +46,7 @@ my $Sem = undef;
my $ThreadSem = undef;
use constant AGENT_VERSION => '7.0NG.749';
-use constant AGENT_BUILD => '200930';
+use constant AGENT_BUILD => '201001';
# Agent log default file size maximum and instances
use constant DEFAULT_MAX_LOG_SIZE => 600000;
@@ -1058,8 +1061,6 @@ sub fix_directory ($) {
return $dir . $char;
}
-
-
################################################################################
# Sends a file to the server.
################################################################################
@@ -3079,8 +3080,11 @@ my $main_agent = -1;
# base time to start eatch iteration with the same interval.
my $iter_base_time = time();
$LogFileIdx = -1;
+
# Loop
while (1) {
+ my $omnishell;
+
if (-e $Conf{'logfile'} && (stat($Conf{'logfile'}))[7] > $Conf{'logsize'}) {
rotate_log();
}
@@ -3095,15 +3099,17 @@ while (1) {
# Check file collections
check_collections () unless ($Conf{'debug'} eq '1');
- if ($Conf{'debug'} ne '1') {
- # Check scheduled commands
- my $omni = new PandoraFMS::Omnishell(\%Conf);
- log_message('log', "Running omnishell process");
- if (!$omni->run()) {
- log_message('error', "Failed to run omnishell process: ".$omni->get_last_error());
- } else {
- log_message('log', "Omnishell process completed.");
- }
+ eval {
+ # Omnishell controller.
+ $omnishell = new PandoraFMS::Omnishell(
+ {
+ %Conf,
+ 'ConfDir' => $ConfDir
+ }
+ );
+ };
+ if ($@) {
+ log_message('error', "Omnishell process error: ".$@);
}
# Launch broker agents
@@ -3237,18 +3243,22 @@ while (1) {
if (ref ($Conf{'commands'}) eq "HASH") {
foreach my $command (keys %{$Conf{'commands'}}) {
- my $result = evaluate_command($command);
- if (ref($result) eq "HASH") {
- # Process command result.
- $Xml .= "\n";
- $Xml .= " \n";
- $Xml .= " {'name'}."]]>\n";
- $Xml .= " \n";
- $Xml .= " {'error_level'}."]]>\n";
- $Xml .= " {'stdout'}."]]>\n";
- $Xml .= " {'stderr'}."]]>\n";
- $Xml .= " \n";
- $Xml .= "\n";
+ eval {
+ if ($Conf{'debug'} eq '1') {
+ log_message('debug', 'Running omnishell commmand ['.$command.']');
+ }
+
+ my $output = $omnishell->run($command, 'xml');
+ if (!empty($output)) {
+ $Xml .= $output;
+ } else {
+ if ($Conf{'debug'} eq '1') {
+ log_message('error', 'Omnishell result: '.$omnishell->get_last_error());
+ }
+ }
+ };
+ if ($@) {
+ log_message('error', 'Omnishell error: '.$@);
}
}
}
diff --git a/pandora_server/lib/PandoraFMS/Omnishell.pm b/pandora_server/lib/PandoraFMS/Omnishell.pm
index 3a46a81b49..223bf5bca9 100644
--- a/pandora_server/lib/PandoraFMS/Omnishell.pm
+++ b/pandora_server/lib/PandoraFMS/Omnishell.pm
@@ -8,15 +8,20 @@ package PandoraFMS::Omnishell;
use strict;
use warnings;
+use File::Copy;
+use Scalar::Util qw(looks_like_number);
+use lib '/usr/lib/perl5';
+use PandoraFMS::PluginTools qw/init read_configuration read_file empty trim/;
+
my $YAML = 0;
# Dynamic load. Avoid unwanted behaviour.
eval {
- eval 'require YAML::Tiny;1' or die('YAML::Tiny lib not found, commands feature won\'t be available');
+ eval 'require YAML::Tiny;1' or die('YAML::Tiny lib not found, commands feature won\'t be available');
};
if ($@) {
- $YAML = 0;
+ $YAML = 0;
} else {
- $YAML = 1;
+ $YAML = 1;
}
use lib '/usr/lib/perl5';
@@ -26,6 +31,137 @@ our %EXPORT_TAGS = ( 'all' => [ qw( ) ] );
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
our @EXPORT = qw();
+# 2 to the power of 32.
+use constant POW232 => 2**32;
+
+################################################################################
+# Return the MD5 checksum of the given string as a hex string.
+# Pseudocode from: http://en.wikipedia.org/wiki/MD5#Pseudocode
+################################################################################
+my @S = (
+ 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
+ 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
+ 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
+ 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21
+);
+my @K = (
+ 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
+ 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
+ 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
+ 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
+ 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
+ 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
+ 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
+ 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
+ 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
+ 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
+ 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
+ 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
+ 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
+ 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
+ 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
+ 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
+);
+sub md5 {
+ my $str = shift;
+
+ # No input!
+ if (!defined($str)) {
+ return "";
+ }
+
+ # Note: All variables are unsigned 32 bits and wrap modulo 2^32 when
+ # calculating.
+
+ # Initialize variables.
+ my $h0 = 0x67452301;
+ my $h1 = 0xEFCDAB89;
+ my $h2 = 0x98BADCFE;
+ my $h3 = 0x10325476;
+
+ # Pre-processing.
+ my $msg = unpack ("B*", pack ("A*", $str));
+ my $bit_len = length ($msg);
+
+ # Append "1" bit to message.
+ $msg .= '1';
+
+ # Append "0" bits until message length in bits ≡ 448 (mod 512).
+ $msg .= '0' while ((length ($msg) % 512) != 448);
+
+ # Append bit /* bit, not byte */ length of unpadded message as 64-bit
+ # little-endian integer to message.
+ $msg .= unpack ("B32", pack ("V", $bit_len));
+ $msg .= unpack ("B32", pack ("V", ($bit_len >> 16) >> 16));
+
+ # Process the message in successive 512-bit chunks.
+ for (my $i = 0; $i < length ($msg); $i += 512) {
+
+ my @w;
+ my $chunk = substr ($msg, $i, 512);
+
+ # Break chunk into sixteen 32-bit little-endian words w[i], 0 <= i <=
+ # 15.
+ for (my $j = 0; $j < length ($chunk); $j += 32) {
+ push (@w, unpack ("V", pack ("B32", substr ($chunk, $j, 32))));
+ }
+
+ # Initialize hash value for this chunk.
+ my $a = $h0;
+ my $b = $h1;
+ my $c = $h2;
+ my $d = $h3;
+ my $f;
+ my $g;
+
+ # Main loop.
+ for (my $y = 0; $y < 64; $y++) {
+ if ($y <= 15) {
+ $f = $d ^ ($b & ($c ^ $d));
+ $g = $y;
+ }
+ elsif ($y <= 31) {
+ $f = $c ^ ($d & ($b ^ $c));
+ $g = (5 * $y + 1) % 16;
+ }
+ elsif ($y <= 47) {
+ $f = $b ^ $c ^ $d;
+ $g = (3 * $y + 5) % 16;
+ }
+ else {
+ $f = $c ^ ($b | (0xFFFFFFFF & (~ $d)));
+ $g = (7 * $y) % 16;
+ }
+
+ my $temp = $d;
+ $d = $c;
+ $c = $b;
+ $b = ($b + leftrotate (($a + $f + $K[$y] + $w[$g]) % POW232, $S[$y])) % POW232;
+ $a = $temp;
+ }
+
+ # Add this chunk's hash to result so far.
+ $h0 = ($h0 + $a) % POW232;
+ $h1 = ($h1 + $b) % POW232;
+ $h2 = ($h2 + $c) % POW232;
+ $h3 = ($h3 + $d) % POW232;
+ }
+
+ # Digest := h0 append h1 append h2 append h3 #(expressed as little-endian)
+ return unpack ("H*", pack ("V", $h0)) .
+ unpack ("H*", pack ("V", $h1)) .
+ unpack ("H*", pack ("V", $h2)) .
+ unpack ("H*", pack ("V", $h3));
+}
+
+################################################################################
+# MD5 leftrotate function. See: http://en.wikipedia.org/wiki/MD5#Pseudocode
+################################################################################
+sub leftrotate {
+ my ($x, $c) = @_;
+
+ return (0xFFFFFFFF & ($x << $c)) | ($x >> (32 - $c));
+}
################################################################################
# return last error.
@@ -33,46 +169,57 @@ our @EXPORT = qw();
sub get_last_error {
my ($self) = @_;
- if (!is_empty($self->{'last_error'})) {
+ if (!empty($self->{'last_error'})) {
return $self->{'last_error'};
}
return '';
}
+################################################################################
+# Update last error.
+################################################################################
+sub set_last_error {
+ my ($self, $error) = @_;
+
+ $self->{'last_error'} = $error;
+}
+
################################################################################
# Try to load extra libraries.c
################################################################################
sub load_libraries {
- my $self = shift;
+ my $self = shift;
- # Dynamic load. Avoid unwanted behaviour.
- eval {eval 'require YAML::Tiny;1' or die('YAML::Tiny lib not found, commands feature won\'t be available');};
- if ($@) {
- $self->set_last_error($@);
- return 0;
- } else {
- return 1;
- }
+ # Dynamic load. Avoid unwanted behaviour.
+ eval {eval 'require YAML::Tiny;1' or die('YAML::Tiny lib not found, commands feature won\'t be available');};
+ if ($@) {
+ $self->set_last_error($@);
+ return 0;
+ } else {
+ return 1;
+ }
}
################################################################################
# Create new omnishell handler.
################################################################################
sub new {
- my ($class,$args) = @_;
+ my ($class, $args) = @_;
if (ref($args) ne 'HASH') {
return undef;
}
+ my $system = init();
my $self = {
'last_error' => undef,
- %{$args}
+ %{$system},
+ %{$args},
};
-
$self = bless($self, $class);
+ $self->prepare_commands();
return $self;
}
@@ -81,11 +228,35 @@ sub new {
# Run process.
################################################################################
sub run {
- my ($self) = @_;
+ my ($self, $ref, $output_mode) = @_;
- if($self->load_libraries()) {
- $self->prepare_commands();
- }
+ if($self->load_libraries()) {
+ # Functionality possible.
+ my $command = $self->{'commands'}->{$ref};
+ my $result = $self->evaluate_command($ref);
+ if (ref($result) eq "HASH") {
+ # Process command result.
+ if (defined($output_mode) && $output_mode eq 'xml') {
+ my $output = '';
+ $output .= "\n";
+ $output .= " \n";
+ $output .= " {'name'}."]]>\n";
+ $output .= " \n";
+ $output .= " {'error_level'}."]]>\n";
+ $output .= " {'stdout'}."]]>\n";
+ $output .= " {'stderr'}."]]>\n";
+ $output .= " \n";
+ $output .= "\n";
+
+ return $output;
+ }
+ return $result;
+ } else {
+ $self->set_last_error('Failed to process ['.$ref.']: '.$result);
+ }
+ }
+
+ return undef;
}
################################################################################
@@ -94,127 +265,117 @@ sub run {
sub prepare_commands {
my ($self) = @_;
- if ($YAML == 0) {
- log_message(
- 'error',
- 'Cannot use commands without YAML dependency, please install it.'
- );
- return;
- }
+ if ($YAML == 0) {
+ $self->set_last_error('Cannot use commands without YAML dependency, please install it.');
+ return;
+ }
- # Force configuration file read.
- my @commands = read_config('cmd_file');
+ # Force configuration file read.
+ my $commands = $self->{'commands'};
- if (empty(\@commands)) {
- $self->{'commands'} = {};
- } else {
- foreach my $rcmd (@commands) {
- $self->{'commands'}->{trim($rcmd)} = {};
- }
- }
+ if (empty($commands)) {
+ $self->{'commands'} = {};
+ } else {
+ foreach my $rcmd (keys %{$commands}) {
+ $self->{'commands'}->{trim($rcmd)} = {};
+ }
+ }
- # Cleanup old commands. Not registered.
- cleanup_old_commands();
+ # Cleanup old commands. Not registered.
+ $self->cleanup_old_commands();
- foreach my $ref (keys %{$self->{'commands'}}) {
- my $file_content;
- my $download = 0;
- my $rcmd_file = $self->{'ConfDir'}.'/commands/'.$ref.'.rcmd';
+ foreach my $ref (keys %{$self->{'commands'}}) {
+ my $file_content;
+ my $download = 0;
+ my $rcmd_file = $self->{'ConfDir'}.'/commands/'.$ref.'.rcmd';
- # Check for local .rcmd.done files
- if (-e $rcmd_file.'.done') {
- # Ignore.
- delete $self->{'commands'}->{$ref};
- next;
- }
+ # Search for local .rcmd file
+ if (-e $rcmd_file) {
+ my $remote_md5_file = $self->{'temporal'}.'/'.$ref.'.md5';
- # Search for local .rcmd file
- if (-e $rcmd_file) {
- my $remote_md5_file = $self->{'temporal'}.'/'.$ref.'.md5';
+ $file_content = read_file($rcmd_file);
+ if ($self->recv_file($ref.'.md5', $remote_md5_file) != 0) {
+ # Remote file could not be retrieved, skip.
+ delete $self->{'commands'}->{$ref};
+ next;
+ }
- $file_content = read_file($rcmd_file);
- if (recv_file($ref.'.md5', $remote_md5_file) != 0) {
- # Remote file could not be retrieved, skip.
- delete $self->{'commands'}->{$ref};
- next;
- }
+ my $local_md5 = md5($file_content);
+ my $remote_md5 = md5(read_file($remote_md5_file));
- my $local_md5 = md5($file_content);
- my $remote_md5 = md5(read_file($remote_md5_file));
+ if ($local_md5 ne $remote_md5) {
+ # Must be downloaded again.
+ $download = 1;
+ }
+ } else {
+ $download = 1;
+ }
+
+ # Search for remote .rcmd file
+ if ($download == 1) {
+ # Download .rcmd file
+ if ($self->recv_file($ref.'.rcmd') != 0) {
+ # Remote file could not be retrieved, skip.
+ delete $self->{'commands'}->{$ref};
+ next;
+ } else {
+ # Success
+ move($self->{'temporal'}.'/'.$ref.'.rcmd', $rcmd_file);
+ }
+ }
+
+ # Parse and prepare in memory skel.
+ eval {
+ $self->{'commands'}->{$ref} = YAML::Tiny->read($rcmd_file);
+ };
+ if ($@) {
+ # Failed.
+ $self->set_last_error('Failed to decode command. ' . "\n".$@);
+ delete $self->{'commands'}->{$ref};
+ next;
+ }
- if ($local_md5 ne $remote_md5) {
- # Must be downloaded again.
- $download = 1;
- }
- } else {
- $download = 1;
- }
-
- # Search for remote .rcmd file
- if ($download == 1) {
- # Download .rcmd file
- if (recv_file($ref.'.rcmd') != 0) {
- # Remote file could not be retrieved, skip.
- delete $self->{'commands'}->{$ref};
- next;
- } else {
- # Success
- move($self->{'temporal'}.'/'.$ref.'.rcmd', $rcmd_file);
- }
- }
-
- # Parse and prepare in memory skel.
- eval {
- $self->{'commands'}->{$ref} = YAML::Tiny->read($rcmd_file);
- };
- if ($@) {
- # Failed.
- log_message('error', 'Failed to decode command. ' . "\n".$@);
- delete $self->{'commands'}->{$ref};
- next;
- }
-
- }
+ }
}
################################################################################
# Command report.
################################################################################
sub report_command {
- my ($self, $ref, $err_level) = @_;
+ my ($self, $ref, $err_level) = @_;
# Retrieve content from .stdout and .stderr
- my $stdout_file = $self->{'temporal'}.'/'.$ref.'.stdout';
- my $stderr_file = $self->{'temporal'}.'/'.$ref.'.stderr';
+ my $stdout_file = $self->{'temporal'}.'/'.$ref.'.stdout';
+ my $stderr_file = $self->{'temporal'}.'/'.$ref.'.stderr';
- my $return;
- eval {
- $return = {
- 'error_level' => $err_level,
- 'stdout' => read_file($stdout_file),
- 'stderr' => read_file($stderr_file),
- };
+ my $return;
+ eval {
+ $return = {
+ 'error_level' => $err_level,
+ 'stdout' => read_file($stdout_file),
+ 'stderr' => read_file($stderr_file),
+ };
- $return->{'name'} = $self->{'commands'}->{$ref}->[0]->{'name'};
- };
- if ($@) {
- log_message('error', 'Failed to report command output. ' . $@);
- }
+ $return->{'name'} = $self->{'commands'}->{$ref}->[0]->{'name'};
+ };
+ if ($@) {
+ $self->set_last_error('Failed to report command output. ' . $@);
+ }
- # Cleanup
- unlink($stdout_file) if (-e $stdout_file);
- unlink($stderr_file) if (-e $stderr_file);
+ # Cleanup
+ unlink($stdout_file) if (-e $stdout_file);
+ unlink($stderr_file) if (-e $stderr_file);
- # Mark command as done.
- open (my $R_FILE, '> '.$self->{'ConfDir'}.'/commands/'.$ref.'.rcmd.done');
- print $R_FILE $err_level;
- close($R_FILE);
+ # Mark command as done.
+ open (my $R_FILE, '> '.$self->{'ConfDir'}.'/commands/'.$ref.'.rcmd.done');
+ print $R_FILE $err_level;
+ close($R_FILE);
- $return->{'stdout'} = '' unless defined ($return->{'stdout'});
- $return->{'stderr'} = '' unless defined ($return->{'stderr'});
+ $return->{'stdout'} = '' unless defined ($return->{'stdout'});
+ $return->{'stderr'} = '' unless defined ($return->{'stderr'});
- return $return;
+ return $return;
}
################################################################################
@@ -223,28 +384,28 @@ sub report_command {
sub cleanup_old_commands {
my ($self) = @_;
- # Cleanup old .rcmd and .rcmd.done files.
- my %registered = map { $_.'.rcmd' => 1 } keys %{$self->{'commands'}};
- if(opendir(my $dir, $self->{'ConfDir'}.'/commands/')) {
- while (my $item = readdir($dir)) {
+ # Cleanup old .rcmd and .rcmd.done files.
+ my %registered = map { $_.'.rcmd' => 1 } keys %{$self->{'commands'}};
+ if(opendir(my $dir, $self->{'ConfDir'}.'/commands/')) {
+ while (my $item = readdir($dir)) {
- # Skip other files.
- next if ($item !~ /\.rcmd$/);
+ # Skip other files.
+ next if ($item !~ /\.rcmd$/);
- # Clean .rcmd.done file if its command is not referenced in conf.
- if (!defined($registered{$item})) {
- if (-e $self->{'ConfDir'}.'/commands/'.$item) {
- unlink($self->{'ConfDir'}.'/commands/'.$item);
- }
- if (-e $self->{'ConfDir'}.'/commands/'.$item.'.done') {
- unlink($self->{'ConfDir'}.'/commands/'.$item.'.done');
- }
- }
- }
+ # Clean .rcmd.done file if its command is not referenced in conf.
+ if (!defined($registered{$item})) {
+ if (-e $self->{'ConfDir'}.'/commands/'.$item) {
+ unlink($self->{'ConfDir'}.'/commands/'.$item);
+ }
+ if (-e $self->{'ConfDir'}.'/commands/'.$item.'.done') {
+ unlink($self->{'ConfDir'}.'/commands/'.$item.'.done');
+ }
+ }
+ }
- # Close dir.
- closedir($dir);
- }
+ # Close dir.
+ closedir($dir);
+ }
}
@@ -252,68 +413,68 @@ sub cleanup_old_commands {
# Executes a command using defined timeout.
################################################################################
sub execute_command_timeout {
- my ($cmd, $timeout) = @_;
+ my ($self, $cmd, $timeout) = @_;
- if (!defined($timeout)
- || !looks_like_number($timeout)
- || $timeout <= 0
- ) {
- `$cmd`;
- return $?>>8;
- }
+ if (!defined($timeout)
+ || !looks_like_number($timeout)
+ || $timeout <= 0
+ ) {
+ `$cmd`;
+ return $?>>8;
+ }
- my $remaining_timeout = $timeout;
+ my $remaining_timeout = $timeout;
- my $RET;
- my $output;
+ my $RET;
+ my $output;
- my $pid = open ($RET, "-|");
- if (!defined($pid)) {
- # Failed to fork.
- log_message('error', '[command] Failed to fork.');
- return undef;
- }
- if ($pid == 0) {
- # Child.
- my $ret;
- eval {
- local $SIG{ALRM} = sub { die "timeout\n" };
- alarm $timeout;
- `$cmd`;
- alarm 0;
- };
+ my $pid = open ($RET, "-|");
+ if (!defined($pid)) {
+ # Failed to fork.
+ $self->set_last_error('[command] Failed to fork.');
+ return undef;
+ }
+ if ($pid == 0) {
+ # Child.
+ my $ret;
+ eval {
+ local $SIG{ALRM} = sub { die "timeout\n" };
+ alarm $timeout;
+ `$cmd`;
+ alarm 0;
+ };
- my $result = ($?>>8);
- return $result;
+ my $result = ($?>>8);
+ return $result;
- # Exit child.
- # Child finishes.
- exit;
+ # Exit child.
+ # Child finishes.
+ exit;
- } else {
- # Parent waiting.
- while( --$remaining_timeout > 0 ){
- if (wait == -1) {
- last;
- }
- # Wait child up to timeout seconds.
- sleep 1;
- }
- }
+ } else {
+ # Parent waiting.
+ while( --$remaining_timeout > 0 ){
+ if (wait == -1) {
+ last;
+ }
+ # Wait child up to timeout seconds.
+ sleep 1;
+ }
+ }
- if ($remaining_timeout > 0) {
- # Retrieve output from child.
- $output = do { local $/; <$RET> };
- $output = $output>>8;
- }
- else {
- # Timeout expired.
- return 124;
- }
+ if ($remaining_timeout > 0) {
+ # Retrieve output from child.
+ $output = do { local $/; <$RET> };
+ $output = $output>>8;
+ }
+ else {
+ # Timeout expired.
+ return 124;
+ }
- close($RET);
+ close($RET);
- return $output;
+ return $output;
}
################################################################################
@@ -322,104 +483,183 @@ sub execute_command_timeout {
# $std_files = ' >> /tmp/stdout 2>> /tmp/stderr
################################################################################
sub execute_command_block {
- my ($commands, $std_files, $timeout, $retry) = @_;
+ my ($self, $commands, $std_files, $timeout, $retry) = @_;
- return 0 unless defined($commands);
+ return 0 unless defined($commands);
- my $retries = $retry;
+ my $retries = $retry;
- $retries = 1 unless looks_like_number($retries) && $retries > 0;
+ $retries = 1 unless looks_like_number($retries) && $retries > 0;
- my $err_level = 0;
- $std_files = '' unless defined ($std_files);
+ my $err_level = 0;
+ $std_files = '' unless defined ($std_files);
- if (ref($commands) ne "ARRAY") {
- return 0 if $commands eq '';
+ if (ref($commands) ne "ARRAY") {
+ return 0 if $commands eq '';
- do {
- $err_level = execute_command_timeout(
- "($commands) $std_files",
- $timeout
- );
+ do {
+ $err_level = $self->execute_command_timeout(
+ "($commands) $std_files",
+ $timeout
+ );
- # Do not retry if success.
- last if looks_like_number($err_level) && $err_level == 0;
- } while ((--$retries) > 0);
+ # Do not retry if success.
+ last if looks_like_number($err_level) && $err_level == 0;
+ } while ((--$retries) > 0);
- } else {
- foreach my $comm (@{$commands}) {
- next unless defined($comm);
- $retries = $retry;
- $retries = 1 unless looks_like_number($retries) && $retries > 0;
+ } else {
+ foreach my $comm (@{$commands}) {
+ next unless defined($comm);
+ $retries = $retry;
+ $retries = 1 unless looks_like_number($retries) && $retries > 0;
- do {
- $err_level = execute_command_timeout(
- "($comm) $std_files",
- $timeout
- );
+ do {
+ $err_level = $self->execute_command_timeout(
+ "($comm) $std_files",
+ $timeout
+ );
- # Do not retry if success.
- $retries = 0 if looks_like_number($err_level) && $err_level == 0;
+ # Do not retry if success.
+ $retries = 0 if looks_like_number($err_level) && $err_level == 0;
- } while ((--$retries) > 0);
+ } while ((--$retries) > 0);
- # Do not continue evaluating block if failed.
- last unless ($err_level == 0);
- }
- }
+ # Do not continue evaluating block if failed.
+ last unless ($err_level == 0);
+ }
+ }
- return $err_level;
+ return $err_level;
}
################################################################################
# Evalate given command.
################################################################################
sub evaluate_command {
- my ($self, $ref) = @_;
+ my ($self, $ref) = @_;
- # Not found.
- return unless defined $self->{'commands'}->{$ref};
+ # Not found.
+ return "undefined command" unless defined $self->{'commands'}->{$ref};
- # Already completed.
- return if (-e $self->{'ConfDir'}.'/commands/'.$ref.'.rcmd.done');
+ # Already completed.
+ return "already executed" if (-e $self->{'ConfDir'}.'/commands/'.$ref.'.rcmd.done');
- # [0] because how library works.
- my $cmd = $self->{'commands'}->{$ref}->[0];
+ # [0] because how library works.
+ my $cmd = $self->{'commands'}->{$ref}->[0];
- my $std_files = ' >> '.$self->{'temporal'}.'/'.$ref.'.stdout ';
- $std_files .= ' 2>> '.$self->{'temporal'}.'/'.$ref.'.stderr ';
+ my $std_files = ' >> '.$self->{'temporal'}.'/'.$ref.'.stdout ';
+ $std_files .= ' 2>> '.$self->{'temporal'}.'/'.$ref.'.stderr ';
- # Check preconditions
- my $err_level;
-
- $err_level = execute_command_block(
- $cmd->{'preconditions'},
- $std_files,
- $cmd->{'timeout'}
- );
+ # Check preconditions
+ my $err_level;
+
+ $err_level = $self->execute_command_block(
+ $cmd->{'preconditions'},
+ $std_files,
+ $cmd->{'timeout'}
+ );
- # Precondition not satisfied.
- return report_command($ref, $err_level) unless ($err_level == 0);
+ # Precondition not satisfied.
+ return $self->report_command($ref, $err_level) unless ($err_level == 0);
- # Main run.
- $err_level = execute_command_block(
- $cmd->{'script'},
- $std_files,
- $cmd->{'timeout'}
- );
+ # Main run.
+ $err_level = $self->execute_command_block(
+ $cmd->{'script'},
+ $std_files,
+ $cmd->{'timeout'}
+ );
- # Script not success.
- return report_command($ref, $err_level) unless ($err_level == 0);
+ # Script not success.
+ return $self->report_command($ref, $err_level) unless ($err_level == 0);
- # Check postconditions
- $err_level = execute_command_block(
- $cmd->{'postconditions'},
- $std_files,
- $cmd->{'timeout'}
- );
+ # Check postconditions
+ $err_level = $self->execute_command_block(
+ $cmd->{'postconditions'},
+ $std_files,
+ $cmd->{'timeout'}
+ );
- # Return results.
- return report_command($ref, $err_level);
+ # Return results.
+ return $self->report_command($ref, $err_level);
}
+################################################################################
+# File transference and imported methods
+################################################################################
+################################################################################
+## Remove any trailing / from directory names.
+################################################################################
+sub fix_directory ($) {
+ my $dir = shift;
+
+ my $char = chop($dir);
+ return $dir if ($char eq '/');
+ return $dir . $char;
+}
+
+################################################################################
+# Receive a file from the server.
+################################################################################
+sub recv_file {
+ my ($self, $file, $relative) = @_;
+ my $output;
+
+ my $DevNull = $self->{'__system'}->{'devnull'};
+ my $CmdSep = $self->{'__system'}->{'cmdsep'};
+
+ my $pid = fork();
+ return 1 unless defined $pid;
+
+ # Fix remote dir to some transfer mode
+ my $remote_dir = $self->{'server_path'};
+ $remote_dir .= "/" . fix_directory($relative) if defined($relative);
+
+ if ($pid == 0) {
+ # execute the transfer program by child process.
+ eval {
+ local $SIG{'ALRM'} = sub {die};
+ alarm ($self->{'transfer_timeout'});
+ if ($self->{'transfer_mode'} eq 'tentacle') {
+ $output = `cd "$self->{'temporal'}"$CmdSep tentacle_client -v -g -a $self->{'server_ip'} -p $self->{'server_port'} $self->{'server_opts'} $file 2>&1 >$DevNull`
+ } elsif ($self->{'transfer_mode'} eq 'ssh') {
+ $output = `scp -P $self->{'server_port'} pandora@"$self->{'server_ip'}:$self->{'server_path'}/$file" $self->{'temporal'} 2>&1 >$DevNull`;
+ } elsif ($self->{'transfer_mode'} eq 'ftp') {
+ my $base = basename ($file);
+ my $dir = dirname ($file);
+
+ $output = `ftp -n $self->{'server_opts'} $self->{'server_ip'} $self->{'server_port'} 2>&1 >$DevNull <{'server_user'}
+ quote PASS $self->{'server_pwd'}
+ lcd "$self->{'temporal'}"
+ cd "$self->{'server_path'}"
+ get "$file"
+ quit
+ FEOF1`
+ } elsif ($self->{'transfer_mode'} eq 'local') {
+ $output = `cp "$remote_dir/$file" $self->{'temporal'} 2>&1 >$DevNull`;
+ }
+ alarm (0);
+ };
+
+ if ($@) {
+ $self->set_last_error("Error retrieving file: '.$file.' File transfer command is not responding.");
+ exit 1;
+ }
+
+ # Get the errorlevel
+ my $rc = $? >> 8;
+ if ($rc != 0) {
+ $self->set_last_error("Error retrieving file: '$file' $output");
+ }
+ exit $rc;
+ }
+
+ # Wait the child process termination and get the errorlevel
+ waitpid ($pid, 0);
+ my $rc = $? >> 8;
+
+ return $rc;
+}
+
+
1;
\ No newline at end of file
diff --git a/pandora_server/lib/PandoraFMS/PluginTools.pm b/pandora_server/lib/PandoraFMS/PluginTools.pm
index bbf419afe1..b3584c8762 100644
--- a/pandora_server/lib/PandoraFMS/PluginTools.pm
+++ b/pandora_server/lib/PandoraFMS/PluginTools.pm
@@ -1165,6 +1165,7 @@ sub init_system {
$system{echo} = "echo";
$system{wcl} = "wc -l";
$system{tmp} = ".\\";
+ $system{cmdsep} = "\&";
}
else {
$system{devnull} = "/dev/null";
@@ -1175,6 +1176,7 @@ sub init_system {
$system{echo} = "echo";
$system{wcl} = "wc -l";
$system{tmp} = "/tmp";
+ $system{cmdsep} = ";";
if ($^O =~ /hpux/i) {
$system{os} = "HPUX";