From daaa63e1925a8c419d2aee674c399e1e50ac5355 Mon Sep 17 00:00:00 2001
From: slerena <slerena@gmail.com>
Date: Thu, 13 Mar 2008 18:33:44 +0000
Subject: [PATCH] 2008-03-13  Sancho Lerena <slerena@gmail.com>

    * lib/PandoraFMS/Config.pm: New pandora_startlog function. Added support to manage PID
    in daemon mode. Added support for quiet mode. Added prediction_threads option.

    * lib/PandoraFMS/Tools.pm: daemonize function now manages PID and store in a file when
    it forks.

    * lib/PandoraFMS/DB.pm: Removed some gotos.  Modified generic-access DB functions and
    added one to manage entire row in a hash: get_db_free_row ().

    * bin/pandora_plugin: A lot of fixes. This code actually works fine :-)

    * bin/pandora_prediction: First version of usable code. Works but not seriously tested.

    * bin/pandora_network: Adjusted to work with new features (quiet mode) and new db
    schema. Some code cleanup.

    * util/pandora_dbstress.pl: Updated default values.

    * util/pandora_dbstress.README: Improved README documentation for dbstress tool.



git-svn-id: https://svn.code.sf.net/p/pandora/code/trunk@747 c3f86ba8-e40f-0410-aaad-9ba5e7f4b01f
---
 pandora_server/ChangeLog                    |  22 ++
 pandora_server/bin/pandora_network          |  73 ++--
 pandora_server/bin/pandora_plugin           | 133 ++++---
 pandora_server/bin/pandora_prediction       | 413 ++++++++++++++++++++
 pandora_server/lib/PandoraFMS/Config.pm     | 165 +++++---
 pandora_server/lib/PandoraFMS/DB.pm         | 230 ++++++-----
 pandora_server/lib/PandoraFMS/Tools.pm      |  41 +-
 pandora_server/util/pandora_dbstress.README |  30 +-
 pandora_server/util/pandora_dbstress.pl     |   4 +-
 9 files changed, 858 insertions(+), 253 deletions(-)
 create mode 100755 pandora_server/bin/pandora_prediction

diff --git a/pandora_server/ChangeLog b/pandora_server/ChangeLog
index 7ab443a1fd..3327ed392d 100644
--- a/pandora_server/ChangeLog
+++ b/pandora_server/ChangeLog
@@ -1,3 +1,25 @@
+2008-03-13  Sancho Lerena <slerena@gmail.com>
+
+    * lib/PandoraFMS/Config.pm: New pandora_startlog function. Added support to manage PID
+    in daemon mode. Added support for quiet mode. Added prediction_threads option. 
+
+    * lib/PandoraFMS/Tools.pm: daemonize function now manages PID and store in a file when
+    it forks. 
+
+    * lib/PandoraFMS/DB.pm: Removed some gotos.  Modified generic-access DB functions and 
+    added one to manage entire row in a hash: get_db_free_row ().
+
+    * bin/pandora_plugin: A lot of fixes. This code actually works fine :-)
+
+    * bin/pandora_prediction: First version of usable code. Works but not seriously tested.
+
+    * bin/pandora_network: Adjusted to work with new features (quiet mode) and new db 
+    schema. Some code cleanup.
+
+    * util/pandora_dbstress.pl: Updated default values.
+
+    * util/pandora_dbstress.README: Improved README documentation for dbstress tool.
+
 2008-03-11 Manuel Arostegui <marostegui@artica.es>
 
         * pandora_server, pandora_network, pandora_recon:
diff --git a/pandora_server/bin/pandora_network b/pandora_server/bin/pandora_network
index 244d3b0c14..c6c49ebc7d 100755
--- a/pandora_server/bin/pandora_network
+++ b/pandora_server/bin/pandora_network
@@ -62,13 +62,20 @@ pandora_loadconfig (\%pa_config,1);
 # Audit server starting
 pandora_audit (\%pa_config, "Pandora FMS Network Daemon starting", "SYSTEM", "System");
 
-print " [*] Starting up network threads\n";
-
-if ( $pa_config{"daemon"} eq "1" ) {
-	print " [*] Backgrounding Pandora FMS Network Server process.\n\n";
-	&daemonize;
+# Thread startup
+if ($pa_config{"quiet"} == 0){
+    print " [*] Starting up network threads\n";
 }
 
+# Daemonize and put in background
+if ( $pa_config{"daemon"} eq "1" ){
+    if ($pa_config{"quiet"} eq "0"){
+        print " [*] Backgrounding Pandora FMS Network Server process.\n\n";
+    }
+    &pandora_daemonize ( \%pa_config);
+}
+
+
 # Launch now all network threads
 # $ax is local thread id for this server
 for (my $ax=0; $ax < $pa_config{'network_threads'}; $ax++){
@@ -78,9 +85,15 @@ for (my $ax=0; $ax < $pa_config{'network_threads'}; $ax++){
 # Launch now the network producer thread
 threads->new( \&pandora_network_producer, \%pa_config);
 
-print " [*] All threads loaded and running \n\n";
-# Last thread is the main process (this process)
 
+if ($pa_config{"quiet"} == 0){
+    print " [*] All threads loaded and running \n\n";
+}
+
+# Start Pandora FMS loggin 
+pandora_startlog (\%pa_config);
+
+# Last thread is the main process (this process)
 my $dbhost = $pa_config{'dbhost'};
 my $dbname = $pa_config{'dbname'};
 my $dbh = DBI->connect("DBI:mysql:$dbname:$dbhost:3306",
@@ -122,7 +135,9 @@ sub pandora_network_consumer ($$) {
 	my $pa_config = $_[0];
 	my $thread_id = $_[1];
 
-	print " [*] Starting up Network Consumer Thread # $thread_id \n";
+    if ($pa_config->{"quiet"} == 0){
+	    print " [*] Starting up Network Consumer Thread # $thread_id \n";
+    }
 	
 	my $data_id_agent_module;
 	# Create Database handler
@@ -170,7 +185,10 @@ sub pandora_network_consumer ($$) {
 
 sub pandora_network_producer ($) {
 	my $pa_config = $_[0];
-	print " [*] Starting up Network Producer Thread ...\n";
+
+    if ($pa_config->{"quiet"} == 0){
+	    print " [*] Starting up Network Producer Thread ...\n";
+    }
 
 	my $dbh = DBI->connect("DBI:mysql:$pa_config->{'dbname'}:$pa_config->{'dbhost'}:3306", $pa_config->{'dbuser'}, $pa_config->{'dbpass'}, { RaiseError => 1, AutoCommit => 1 });
 	
@@ -192,13 +210,17 @@ sub pandora_network_producer ($) {
 			FROM
 				tagente, tagente_modulo, tagente_estado
 			WHERE
-				id_server = $server_id
+				id_network_server = $server_id
 			AND 
 				tagente_modulo.id_agente = tagente.id_agente
 			AND
 				tagente.disabled = 0
 			AND
-				tagente_modulo.id_tipo_modulo > 4
+				tagente_modulo.id_tipo_modulo > 4 
+            AND
+                tagente_modulo.id_tipo_modulo < 19 
+            AND
+                tagente_modulo.disabled = 0
 			AND
 				tagente_estado.id_agente_modulo = tagente_modulo.id_agente_modulo
 			AND (
@@ -215,12 +237,16 @@ sub pandora_network_producer ($) {
 				FROM
 					tagente, tagente_modulo, tagente_estado, tserver
 				WHERE
-				( 	(tagente.id_server = $server_id AND tagente_modulo.id_agente = tagente.id_agente) OR
-					(tagente.id_server != $server_id AND tagente_modulo.id_agente = tagente.id_agente AND tagente.id_server = tserver.id_server AND tserver.status = 0)
+				( 	(tagente.id_network_server = $server_id AND tagente_modulo.id_agente = tagente.id_agente) OR
+					(tagente.id_network_server != $server_id AND tagente_modulo.id_agente = tagente.id_agente AND tagente.id_network_server = tserver.id_server AND tserver.status = 0)
 				) AND
 					tagente.disabled = 0
+                AND
+                    tagente_modulo.disabled = 0
 				AND
 					tagente_modulo.id_tipo_modulo > 4
+                AND
+                    tagente_modulo.id_tipo_modulo < 19 
 				AND
 					tagente_estado.id_agente_modulo = tagente_modulo.id_agente_modulo
 				AND
@@ -600,10 +626,12 @@ sub exec_network_module {
         }
     }
 
-	# --------------------------------------------------------
+
 	# Write data section
 	my $timestamp = &UnixDate("today","%Y-%m-%d %H:%M:%S");
 	my $utimestamp = &UnixDate("today","%s");
+
+    # Is everything goes ok
 	if ($module_result == 0) {
 		my %part;
 		$part{'name'}[0]=$nombre;
@@ -626,17 +654,19 @@ sub exec_network_module {
 		}
 		else {
 			logger ($pa_config, "Problem with unknown module type '$tipo_modulo'", 0);
-			goto skipdb_execmod;
+			$module_result = 1;
 		}
 		# Update agent last contact
 		# Insert Pandora version as agent version
 		pandora_lastagentcontact ($pa_config, $timestamp, $agent_name,  $pa_config->{'servername'}.$pa_config->{"servermode"}, $pa_config->{'version'}, -1, $dbh);
-	} else { 
-		# $module_result != 0)
-		
+	}
+    
+    if ($module_result != 0) { 
+
 		if ($module_interval == 0){
-                	$module_interval = dame_intervalo ($pa_config, $id_agente, $dbh);
-        	}
+            $module_interval = dame_intervalo ($pa_config, $id_agente, $dbh);
+        }
+
 		# Modules who cannot connect or something go bad, update last_execution_try field
 		logger ($pa_config, "Cannot obtain exec Network Module $nombre from agent $agent_name", 4);
 		my $query_act = "UPDATE tagente_estado SET current_interval = $module_interval,  last_execution_try = $utimestamp WHERE id_agente_modulo = $id_agente_modulo ";
@@ -644,7 +674,4 @@ sub exec_network_module {
 		$a_idages->execute;
 		$a_idages->finish();
 	}
-	
-skipdb_execmod:
-	#$dbh->disconnect();
 }
diff --git a/pandora_server/bin/pandora_plugin b/pandora_server/bin/pandora_plugin
index aa5e567e89..b8bcc51064 100755
--- a/pandora_server/bin/pandora_plugin
+++ b/pandora_server/bin/pandora_plugin
@@ -57,27 +57,30 @@ pandora_loadconfig (\%pa_config, 4);
 # Audit server starting
 pandora_audit (\%pa_config, "Pandora FMS Plugin server starting", "SYSTEM", "System");
 
-print " [*] Starting up plugin threads\n";
-
-die "Aqui me quedo";
-
-if ( $pa_config{"daemon"} eq "1" ) {
-	print " [*] Backgrounding Pandora FMS Plugin Server process.\n\n";
-	&daemonize;
+# Daemonize and put in background
+if ( $pa_config{"daemon"} eq "1" ){
+    if ($pa_config{"quiet"} eq "0"){
+	    print " [*] Backgrounding Pandora FMS Plugin Server process.\n\n";
+    }
+	&pandora_daemonize ( \%pa_config);
 }
 
-=for COMMENT BLOCK
 # Launch now all plugin threads
 # $ax is local thread id for this server
 for (my $ax=0; $ax < $pa_config{'plugin_threads'}; $ax++){
 	threads->new( \&pandora_plugin_consumer, \%pa_config, $ax);
 }
-=cut
+
 # Launch now the producer thread
 threads->new( \&pandora_plugin_producer, \%pa_config);
 
-print " [*] All threads loaded and running \n\n";
 # Last thread is the main process (this process)
+if ($pa_config{"quiet"} == 0){
+    print " [*] All threads loaded and running \n\n";
+}
+
+# Start Pandora FMS loggin 
+pandora_startlog (\%pa_config);
 
 my $dbhost = $pa_config{'dbhost'};
 my $dbname = $pa_config{'dbname'};
@@ -88,7 +91,7 @@ my $dbh = DBI->connect("DBI:mysql:$dbname:$dbhost:3306",
 
 # Server keepalive thread running in main thread on a infinite loop
 while (1) {
-	pandora_serverkeepaliver (\%pa_config, 1, $dbh);
+	pandora_serverkeepaliver (\%pa_config, 4, $dbh);
 	threads->yield;
 	sleep ($pa_config{"server_threshold"});
 }
@@ -120,7 +123,9 @@ sub pandora_plugin_consumer ($$) {
 	my $pa_config = $_[0];
 	my $thread_id = $_[1];
 
-	print " [*] Starting up Plugin Consumer Thread # $thread_id \n";
+    if ($pa_config->{"quiet"} == 0){
+	    print " [*] Starting up Plugin Consumer Thread # $thread_id \n";
+    }
 	
 	my $data_id_agent_module;
 	# Create Database handler
@@ -139,6 +144,7 @@ sub pandora_plugin_consumer ($$) {
 			{
 				lock $queue_lock;
 				$data_id_agent_module = shift(@pending_task);
+#print "[CLIENT] Pop out of queue module (pending queue) $data_id_agent_module \n";
 				delete($pending_task_hash{$data_id_agent_module});
 				$current_task_hash{$data_id_agent_module}=1;
 			}
@@ -147,6 +153,7 @@ sub pandora_plugin_consumer ($$) {
 			eval {
 				# Call network execution process
 				# exec_network_module ( $pa_config, $data_id_agent_module, $dbh);
+print "[CLIENT] Executing module $data_id_agent_module \n";
                 exec_plugin_module ($pa_config, $data_id_agent_module, $dbh);
 			};
 			if ($@){
@@ -158,6 +165,7 @@ sub pandora_plugin_consumer ($$) {
 			# not been processed, but has been freed from task queue
 			{
 				lock $queue_lock;
+#print "[CLIENT] Removing from queue (current task) module $data_id_agent_module \n";
 				delete($current_task_hash{$data_id_agent_module});
 			}
 			$counter = 0;
@@ -191,13 +199,15 @@ sub pandora_plugin_producer ($) {
 			FROM
 				tagente, tagente_modulo, tagente_estado
 			WHERE
-				id_server = $server_id
+				id_plugin_server = $server_id
 			AND 
 				tagente_modulo.id_agente = tagente.id_agente
 			AND
 				tagente.disabled = 0
+            AND
+                tagente_modulo.id_plugin != 0
 			AND
-				tagente_modulo.id_tipo_modulo > 4
+				tagente_modulo.disabled = 0
 			AND
 				tagente_estado.id_agente_modulo = tagente_modulo.id_agente_modulo
 			AND (
@@ -214,23 +224,28 @@ sub pandora_plugin_producer ($) {
 				FROM
 					tagente, tagente_modulo, tagente_estado, tserver
 				WHERE
-				( 	(tagente.id_server = $server_id AND tagente_modulo.id_agente = tagente.id_agente) OR
-					(tagente.id_server != $server_id AND tagente_modulo.id_agente = tagente.id_agente AND tagente.id_server = tserver.id_server AND tserver.status = 0)
+				( 	(tagente.id_plugin_server = $server_id AND tagente_modulo.id_agente = tagente.id_agente) OR
+					(tagente.id_plugin_server != $server_id AND tagente_modulo.id_agente = tagente.id_agente AND tagente.id_plugin_server = tserver.id_server AND tserver.status = 0)
 				) AND
 					tagente.disabled = 0
+                AND 
+                    tagente_modulo.disabled = 0
 				AND
-					tagente_modulo.id_tipo_modulo > 4
+					tagente_modulo.id_plugin != 0
 				AND
 					tagente_estado.id_agente_modulo = tagente_modulo.id_agente_modulo
 				AND
 					((tagente_estado.last_execution_try + tagente_estado.current_interval) < UNIX_TIMESTAMP() OR tagente_modulo.flag = 1 )
 				ORDER BY last_execution_try ASC";
 		}
+#print "[DEBUG] SQL is $query1 \n";
 		$exec_sql1 = $dbh->prepare($query1);
 		$exec_sql1 ->execute;
 		while (@sql_data1 = $exec_sql1->fetchrow_array()) {	
 			$data_id_agente_modulo = $sql_data1[0];
 			$data_flag = $sql_data1[1];
+print "[DEBUG] Procesando candidato $data_id_agente_modulo\n";
+
 			# Skip modules already queued
 			if ((!defined($pending_task_hash{$data_id_agente_modulo})) &&
 				(!defined($current_task_hash{$data_id_agente_modulo}))) {
@@ -239,6 +254,7 @@ sub pandora_plugin_producer ($) {
 				}
 				# Locking scope, do not remove redundant { }
 				{
+#print "[DEBUG] Metiendo $data_id_agente_modulo en cola \n";
 					lock $queue_lock;
 					push (@pending_task, $data_id_agente_modulo);
 					$pending_task_hash {$data_id_agente_modulo}=1;
@@ -246,6 +262,7 @@ sub pandora_plugin_producer ($) {
 			}
 		}
 		#logger ($pa_config, "Items in Network Pending Queue: ".scalar(@pending_task),  5);
+#print "[DEBUG] Items in Network Pending Queue: ".scalar(@pending_task);
 		$exec_sql1->finish();
 		sleep($pa_config->{"server_threshold"});
 	} # Main loop
@@ -263,17 +280,17 @@ sub exec_plugin_module {
 
     # Set global variables for this sub
     my $timeout = $pa_config->{'plugin_timeout'};
-	my $agent_plugin; # hash container for tagent_plugin record
+	my $agent_module; # hash container for tagente_modulo record
     my $plugin; # hash container for tplugin
 
-    # Get a full hash for agent_plugin record reference ($agent_plugin)
+    # Get a full hash for agent_plugin record reference ($agent_module)
 	my $query_sql = "SELECT * FROM tagente_modulo WHERE id_agente_modulo = $id_am";
 	my $exec_sql = $dbh->prepare($query_sql);
 	$exec_sql ->execute;
-	$agent_plugin = $exec_sql->fetchrow_hashref;
+	$agent_module = $exec_sql->fetchrow_hashref;
 
     # Get a full hash for plugin record reference ($plugin)
-    $query_sql = "SELECT * FROM tplugin WHERE id = ".$agent_plugin->{'id_plugin'};
+    $query_sql = "SELECT * FROM tplugin WHERE id = ".$agent_module->{'id_plugin'};
     $exec_sql = $dbh->prepare($query_sql);
     $exec_sql->execute();
     $plugin = $exec_sql->fetchrow_hashref;
@@ -284,7 +301,7 @@ sub exec_plugin_module {
     }
 
     # Initialize another global sub variables.
-	my $agent_name = dame_agente_nombre ($pa_config, $agent_plugin->{'id_agente'}, $dbh);
+	my $agent_name = dame_agente_nombre ($pa_config, $agent_module->{'id_agente'}, $dbh);
 	my $module_result = 1;  # Fail by default
 	my $module_data = 0;    # 0 data for default
     my $module_interval = 0;
@@ -293,23 +310,23 @@ sub exec_plugin_module {
     my $exec_output = "";
     my $plugin_command = $plugin->{"execute"};
     if ($plugin->{'net_dst_opt'} ne ""){
-        $plugin_command = $plugin_command . " ". $plugin->{'net_dst_opt'} ." ". $agent_plugin->{'ip_target'};
+        $plugin_command = $plugin_command . " ". $plugin->{'net_dst_opt'} ." ". $agent_module->{'ip_target'};
     } 
     if ($plugin->{'net_port_opt'} ne "") {
-        $plugin_command = $plugin_command . " ". $plugin->{'net_port_opt'} ." ". $agent_plugin->{'tcp_port'};
+        $plugin_command = $plugin_command . " ". $plugin->{'net_port_opt'} ." ". $agent_module->{'tcp_port'};
     }
     if ($plugin->{'user_opt'} ne "") {
-        $plugin_command = $plugin_command . " ". $plugin->{'user_opt'} ." ". $agent_plugin->{'plugin_user'};
+        $plugin_command = $plugin_command . " ". $plugin->{'user_opt'} ." ". $agent_module->{'plugin_user'};
     }
     if ($plugin->{'pass_opt'} ne "") {
-        $plugin_command = $plugin_command . " ". $plugin->{'pass_opt'} ." ". $agent_plugin->{'plugin_pass'};
+        $plugin_command = $plugin_command . " ". $plugin->{'pass_opt'} ." ". $agent_module->{'plugin_pass'};
     }
 
     # Proccess field / optional / dynamic field
-    if ($agent_plugin->{'plugin_parameter'} ne "") {
-        $plugin_command = $plugin_command . $agent_plugin->{'plugin_parameter'};
+    if ($agent_module->{'plugin_parameter'} ne "") {
+        $plugin_command = $plugin_command . " ". $agent_module->{'plugin_parameter'};
     }
-
+    logger ($pa_config, "Executing AM # $id_am plugin command '$plugin_command'", 9);
     # Final command line execution is stored at "plugin_command"
     eval {
         alarm ($timeout);
@@ -317,12 +334,18 @@ sub exec_plugin_module {
         alarm(0); # Cancel the pending alarm if plugin call returns alive
         $module_result = 0; # If comes here, this is a successfull exec
     };
+
+# print "[DEBUG] Output for $plugin_command is --$module_data-- \n";
+    # Timeout 
     if ($@ =~ /PANDORA PLUGIN SERVER TIMED OUT/) {
-        logger ($pa_config, "[ERROR] Plugin Task for module ".$agent_plugin->{'id_agente_modulo'}." causes a system timeout in exec", 1);
-        # resuming eval block...
-    } else {
-        logger ($pa_config, "[ERROR] Plugin Task for module ".$agent_plugin->{'id_agente_modulo'}." causes an unknown system error", 1);
+        logger ($pa_config, "[ERROR] Plugin Task for module ".$agent_module->{'id_agente_modulo'}." causes a system timeout in exec", 1);
+        logger ($pa_config, "Executing plugin command '$plugin_command'", 9);
+print "[DEBUG] Executing plugin TIMEOUT\n";
+    # General error, not timed-out
+    } elsif ($module_result == 1) { 
+        logger ($pa_config, "[ERROR] Plugin Task for module ".$agent_module->{'id_agente_modulo'}." causes an unknown system error", 1);
         logger ($pa_config, "[ERROR] $@", 1);
+print "[DEBUG] Executing plugin ERROR $@\n";
     }
 
     sub timed_out {
@@ -332,49 +355,63 @@ sub exec_plugin_module {
 	# Get current timestamp
 	my $timestamp = &UnixDate("today","%Y-%m-%d %H:%M:%S");
 	my $utimestamp = &UnixDate("today","%s");
-    
+
     # If module execution get a valid value
 	if ($module_result == 0) {
+print "[DEBUG] MODULERESULT = 0\n";
 		my %part;
-		$part{'name'}[0] = $agent_plugin->{'id_agent'};
+		$part{'name'}[0] = $agent_module->{'nombre'};
 		$part{'description'}[0] = "";
 		$part{'data'}[0] = $module_data;
-		my $tipo_modulo = $agent_plugin->{'id_module_type'};
+        my $tipo_modulo = dame_nombretipomodulo_idagentemodulo ($pa_config, $agent_module->{'id_tipo_modulo'}, $dbh);
 
         # 1 - generic_data
         # 2 - generic_proc
         # 3 - generic_data_string
         # 4 - generic_data_inc
+        # 19, 20 - image
 
-		if (1 == $tipo_modulo) {
+		if (1 == $agent_module->{'id_tipo_modulo'}) {
 			module_generic_data ($pa_config, \%part, $timestamp, $agent_name, $tipo_modulo, $dbh);
 		}
-		elsif (4 == $tipo_modulo) {
+		elsif (4 == $agent_module->{'id_tipo_modulo'}) {
 			module_generic_data_inc ($pa_config, \%part, $timestamp, $agent_name, $tipo_modulo, $dbh);
 		}
-		elsif (3 == $tipo_modulo) {
+		elsif (3 == $agent_module->{'id_tipo_modulo'}) {
 			module_generic_data_string ($pa_config, \%part, $timestamp, $agent_name, $tipo_modulo, $dbh);
 		}
-		elsif (2 == $tipo_modulo) {
+        # Generic_proc
+		elsif (2 == $agent_module->{'id_tipo_modulo'}) {
+print "[DEBUG FINAL]: ".$agent_module->{'nombre'}."   ".$module_data."   ".$tipo_modulo."   ".$agent_name. "  ".$timestamp;
 			module_generic_proc ($pa_config, \%part, $timestamp, $agent_name, $tipo_modulo, $dbh);
 		}
-		else {
+        elsif ( (19 == $agent_module->{'id_tipo_modulo'}) || (20 == $agent_module->{'id_tipo_modulo'}) ) {
+            module_generic_image ($pa_config, \%part, $timestamp, $agent_name, $tipo_modulo, $dbh);
+        }
+		else { # Unknown module!, this IS a problem
 			logger ($pa_config, "Plugin Server Problem with unknown module type '$tipo_modulo'", 0);
-			goto skipdb_execmod;
+print "[DEBUG] Executing plugin UNKONWN MODULE TYPE$@\n";
+            $module_result = 1;
 		}
 		# Update agent last contact
 		# Insert Pandora version as agent version
 		pandora_lastagentcontact ($pa_config, $timestamp, $agent_name,  $pa_config->{'servername'}.$pa_config->{"servermode"}, $pa_config->{'version'}, -1, $dbh);
-	} else {
+	} 
+
+    # If something went wrong in module processing...
+    if ($module_result != 0){ 
+print "[DEBUG] MODULERESULT != 0\n";
+
         # If module execution get a INVALID value
-		if ($agent_plugin->{'intervalo'} == 0){
-            $module_interval = dame_intervalo ($pa_config, $agent_plugin->{'id_agente'}, $dbh);
+		if ($agent_module->{'intervalo'} == 0){
+            $module_interval = dame_intervalo ($pa_config, $agent_module->{'id_agente'}, $dbh);
         }
+
 		# Modules who cannot connect or something go bad, update last_execution_try field
-		logger ($pa_config, "Cannot obtain exec plugin Module ".$agent_plugin->{'nombre'}." from agent $agent_name", 3);
-		my $query_act = "UPDATE tagente_estado SET current_interval = $module_interval, last_execution_try = $utimestamp WHERE id_agente_modulo = ".$agent_plugin->{'id_agente_modulo'};
+		logger ($pa_config, "Cannot obtain exec plugin Module ".$agent_module->{'nombre'}." from agent $agent_name", 2);
+		my $query_act = "UPDATE tagente_estado SET current_interval = $module_interval, last_execution_try = $utimestamp WHERE id_agente_modulo = ".$agent_module->{'id_agente_modulo'};
         $dbh->do($query_act);
 	}
-skipdb_execmod:
+
 	$exec_sql->finish(); #close tagent_plugin hash reference
 }
diff --git a/pandora_server/bin/pandora_prediction b/pandora_server/bin/pandora_prediction
new file mode 100755
index 0000000000..ce98a02242
--- /dev/null
+++ b/pandora_server/bin/pandora_prediction
@@ -0,0 +1,413 @@
+#!/usr/bin/perl
+##########################################################################
+# Pandora FMS Prediction Server
+##########################################################################
+# Copyright (c) 2008 Sancho Lerena, slerena@gmail.com
+#           (c) 2008 Artica Soluciones Tecnologicas S.L
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; version 2.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+##########################################################################
+
+# Includes list
+use strict;
+use warnings;
+
+use Date::Manip;        # Needed to manipulate DateTime formats of input, output and compare
+use Time::Local;        # DateTime basic manipulation
+use threads;
+use threads::shared;
+
+# Pandora Modules
+use PandoraFMS::Config;
+use PandoraFMS::Tools;
+use PandoraFMS::DB;
+
+# Queue management
+my @pending_task : shared;
+my %pending_task_hash : shared;
+my %current_task_hash : shared;
+my $queue_lock : shared;
+
+
+# FLUSH in each IO (only for debug, very slooow)
+# ENABLED in DEBUGMODE
+# DISABLE FOR PRODUCTION
+$| = 0;
+
+my %pa_config;
+
+$SIG{'TERM'} = 'pandora_shutdown';
+$SIG{'INT'} = 'pandora_shutdown';
+
+# Inicio del bucle principal de programa
+pandora_init(\%pa_config, "Pandora FMS Prediction Server");
+
+# Read config file for Global variables
+pandora_loadconfig (\%pa_config, 5);
+
+# Audit server starting
+pandora_audit (\%pa_config, "Pandora FMS Prediction server starting", "SYSTEM", "System");
+
+# Daemonize and put in background
+if ( $pa_config{"daemon"} eq "1" ){
+    if ($pa_config{"quiet"} eq "0"){
+        print " [*] Backgrounding Pandora FMS Prediction Server process.\n\n";
+    }
+    &pandora_daemonize ( \%pa_config);
+}
+
+# Launch now all prediction threads
+# $ax is local thread id for this server
+for (my $ax=0; $ax < $pa_config{'prediction_threads'}; $ax++){
+    threads->new( \&pandora_prediction_consumer, \%pa_config, $ax);
+}
+
+# Launch now the producer thread
+threads->new( \&pandora_prediction_producer, \%pa_config);
+
+# Last thread is the main process (this process)
+if ($pa_config{"quiet"} == 0){
+    print " [*] All threads loaded and running \n";
+}
+
+# Start Pandora FMS loggin 
+pandora_startlog (\%pa_config);
+
+my $dbhost = $pa_config{'dbhost'};
+my $dbname = $pa_config{'dbname'};
+my $dbh = DBI->connect("DBI:mysql:$dbname:$dbhost:3306",
+                        $pa_config{'dbuser'},
+                        $pa_config{'dbpass'},
+                        { RaiseError => 1, AutoCommit => 1 });
+
+# Server keepalive thread running in main thread on a infinite loop
+while (1) {
+    pandora_serverkeepaliver (\%pa_config, 5, $dbh);
+    threads->yield;
+    sleep ($pa_config{"server_threshold"});
+}
+
+#------------------------------------------------------------------------------------
+#------------------------------------------------------------------------------------
+#------------------------------------------------------------------------------------
+#---------------------  Main Perl Code below this line-----------------------
+#------------------------------------------------------------------------------------
+#------------------------------------------------------------------------------------
+#------------------------------------------------------------------------------------
+
+########################################################################################
+# pandora_shutdown ()
+# Close system on a received signal
+########################################################################################
+sub pandora_shutdown {
+	logger (\%pa_config,"Pandora FMS Prediction Server Shutdown by signal ",0);
+	print " [*] Shutting down Pandora FMS Prediction Server (received signal)...\n";
+	exit;
+}
+
+
+sub pandora_prediction_consumer ($$) {
+	my $pa_config = $_[0];
+	my $thread_id = $_[1];
+
+    if ($pa_config->{"quiet"} == 0){
+	    print " [*] Starting up Prediction Consumer Thread # $thread_id \n";
+	}
+
+	my $data_id_agent_module;
+	# Create Database handler
+	my $dbh = DBI->connect("DBI:mysql:$pa_config->{'dbname'}:$pa_config->{'dbhost'}:3306", $pa_config->{'dbuser'}, $pa_config->{'dbpass'}, { RaiseError => 1, AutoCommit => 1 });
+	my $counter =0;
+	
+	while (1) {
+		if ($counter > 10) {
+			sleep (1);
+			$counter = 0;
+		}
+		
+		# Take the first element on the shared queue
+		# Insert this element on the current task hash
+		if (scalar(@pending_task) > 0){
+			{
+				lock $queue_lock;
+				$data_id_agent_module = shift(@pending_task);
+print "[CLIENT] Pop out of queue module (pending queue) $data_id_agent_module \n";
+				delete($pending_task_hash{$data_id_agent_module});
+				$current_task_hash{$data_id_agent_module}=1;
+			}
+			
+			# Executing network task with unmanaged error trapping
+			eval {
+				# Call network execution process
+				# exec_network_module ( $pa_config, $data_id_agent_module, $dbh);
+print "[PREDICT-CLIENT] Executing module # $data_id_agent_module \n";
+                exec_prediction_module ($pa_config, $data_id_agent_module, $dbh);
+			};
+			if ($@){
+				logger ($pa_config, "[ERROR] Prediction Task for module $data_id_agent_module causes a system exception", 0);
+				logger ($pa_config, "ERROR Code: $@", 1);
+			}
+
+			# Remove from queue. If catch an error, probably data is
+			# not been processed, but has been freed from task queue
+			{
+				lock $queue_lock;
+print "[CLIENT] Removing from queue (current task) module $data_id_agent_module \n";
+				delete($current_task_hash{$data_id_agent_module});
+			}
+			$counter = 0;
+		} else {
+			$counter ++;
+		}
+	}
+}
+
+sub pandora_prediction_producer ($) {
+	my $pa_config = $_[0];
+
+	my $dbh = DBI->connect("DBI:mysql:$pa_config->{'dbname'}:$pa_config->{'dbhost'}:3306", $pa_config->{'dbuser'}, $pa_config->{'dbpass'}, { RaiseError => 1, AutoCommit => 1 });
+	
+	my $server_id = $pa_config->{'server_id'};
+
+	# Initialize variables for posterior usage
+	my $query1;
+	my @sql_data1;
+	my $data_id_agente_modulo;
+	my $data_flag;
+	my $exec_sql1;
+	
+	while (1) {
+		if ($pa_config->{"pandora_master"} != 1) {
+			# Query for normal server, not MASTER server
+			$query1 = "SELECT
+				tagente_modulo.id_agente_modulo,
+				tagente_modulo.flag
+			FROM
+				tagente, tagente_modulo, tagente_estado
+			WHERE
+				id_prediction_server = $server_id
+			AND 
+				tagente_modulo.id_agente = tagente.id_agente
+			AND
+				tagente.disabled = 0
+            AND
+                tagente_modulo.prediction_module != 0
+			AND
+				tagente_modulo.disabled = 0
+			AND
+				tagente_estado.id_agente_modulo = tagente_modulo.id_agente_modulo
+			AND (
+					(tagente_estado.last_execution_try + tagente_estado.current_interval) < UNIX_TIMESTAMP() 
+				OR 
+					tagente_modulo.flag = 1
+			)				
+			ORDER BY
+					last_execution_try ASC  ";
+		} else {
+			# Query for MASTER SERVER !
+			$query1 = "SELECT
+					DISTINCT(tagente_modulo.id_agente_modulo), tagente_modulo.flag
+				FROM
+					tagente, tagente_modulo, tagente_estado, tserver
+				WHERE
+				( 	(tagente.id_prediction_server = $server_id AND tagente_modulo.id_agente = tagente.id_agente) OR
+					(tagente.id_prediction_server != $server_id AND tagente_modulo.id_agente = tagente.id_agente AND tagente.id_prediction_server = tserver.id_server AND tserver.status = 0)
+				) AND
+					tagente.disabled = 0
+                AND 
+                    tagente_modulo.disabled = 0
+				AND
+					tagente_modulo.prediction_module != 0
+				AND
+					tagente_estado.id_agente_modulo = tagente_modulo.id_agente_modulo
+				AND
+					((tagente_estado.last_execution_try + tagente_estado.current_interval) < UNIX_TIMESTAMP() OR tagente_modulo.flag = 1 )
+				ORDER BY last_execution_try ASC";
+		}
+# print "[DEBUG] SQL is $query1 \n";
+		$exec_sql1 = $dbh->prepare($query1);
+		$exec_sql1 ->execute;
+		while (@sql_data1 = $exec_sql1->fetchrow_array()) {	
+			$data_id_agente_modulo = $sql_data1[0];
+
+			$data_flag = $sql_data1[1];
+print "[DEBUG] Procesando candidato $data_id_agente_modulo\n";
+
+			# Skip modules already queued
+			if ((!defined($pending_task_hash{$data_id_agente_modulo})) &&
+				(!defined($current_task_hash{$data_id_agente_modulo}))) {
+				if ($data_flag == 1){
+					$dbh->do("UPDATE tagente_modulo SET flag = 0 WHERE id_agente_modulo = $data_id_agente_modulo")
+				}
+				# Locking scope, do not remove redundant { }
+				{
+print "[DEBUG] Metiendo $data_id_agente_modulo en cola \n";
+					lock $queue_lock;
+					push (@pending_task, $data_id_agente_modulo);
+					$pending_task_hash {$data_id_agente_modulo}=1;
+				}
+			}
+		}
+		#logger ($pa_config, "Items in Network Pending Queue: ".scalar(@pending_task),  5);
+print "[DEBUG] Items in Network Pending Queue: ".scalar(@pending_task);
+		$exec_sql1->finish();
+		sleep($pa_config->{"server_threshold"});
+	} # Main loop
+}
+
+
+##########################################################################
+# SUB exec_prediction_module (paconfig, id_agente_modulo, dbh )
+# Execute prediction module task 
+##########################################################################
+sub exec_prediction_module {
+    my $pa_config       = $_[0];
+    my $id_am           = $_[1];
+    my $dbh             = $_[2];
+
+    # This function internal variables
+    my $i; # Internal counter for loops
+    my $n = 0; # total of real data values
+
+    # Set global variables for this sub
+	my $agent_module; # hash reference for tagente_modulo record
+    my $target_module; # hash reference for targetted tagente_modulo
+
+    # Get a full hash for agent_module record reference ($agent_module)
+	my $query_sql = "SELECT * FROM tagente_modulo WHERE id_agente_modulo = $id_am";
+	my $exec_sql = $dbh->prepare($query_sql);
+	$exec_sql ->execute;
+	$agent_module = $exec_sql->fetchrow_hashref;
+
+    # Get a full hash for target agent_module record reference ($target_module)
+    $query_sql = "SELECT * FROM tagente_modulo WHERE id_agente_modulo = " . $agent_module->{'prediction_module'};
+    $exec_sql = $dbh->prepare($query_sql);
+    $exec_sql ->execute;
+    $target_module = $exec_sql->fetchrow_hashref;
+
+    # Prediction mode explanation
+    #
+    # 0 is for target type of generic_proc. It compares latest data with current data. Needs to get
+    # data on a "middle" interval, so if interval is 300, get data to compare with 150  before 
+    # and 150 in the future. If current data is ABOVE or BELOW average +- typical_deviation 
+    # this is a BAD value (0), if not is ok (1) and written in target module as is.
+    # more interval configured for this module, more "margin" has to compare data.
+    #
+    # 1 is for target type of generic_data. It get's data in the future, using the interval given in
+    # module. It gets average from current timestamp to INTERVAL in the future and gets average
+    # value. Typical deviation is not used here. 
+
+    my $prediction_mode;
+    if ($agent_module->{'id_tipo_modulo'} == 2){
+        $prediction_mode = 0; # proc 
+    } else {
+        $prediction_mode = 1; # data
+    }
+    
+    # Initialize another global sub variables.
+	my $agent_name = dame_agente_nombre ($pa_config, $agent_module->{'id_agente'}, $dbh);
+	my $module_data = 0;    # 0 data for default
+
+	# Get current timestamp
+	my $timestamp = &UnixDate("today","%Y-%m-%d %H:%M:%S");
+	my $utimestamp = &UnixDate("today","%s");
+
+    # Get different data from each week one month ago (4 values)
+    # $agent_module->{'module_interval'} uses a margin of interval to get average data from the past
+    my @week_data;
+    my @week_utimestamp;
+
+    for ($i=0; $i<4; $i++){
+        $week_utimestamp[$i] = $utimestamp - (84600*7*($i+1));
+        # Adjust for proc prediction
+        if ($prediction_mode == 0) {
+            $week_utimestamp[$i] = $week_utimestamp[$i] - ($agent_module->{'module_interval'} / 2);
+        }
+    }
+
+    # Let's calculate statistical average using past data
+    my $average = 0;
+    my $temp1 = 0;
+    for ($i=0; $i < 4; $i++){
+print "DEBUG HASH REF ".$target_module->{'id_agente_modulo'};
+print "\n";
+        $temp1 = $week_utimestamp[$i] + $agent_module->{'module_interval'};
+        # Get data for week $i in the past
+        $query_sql = 'SELECT AVG(datos) FROM tagente_datos WHERE id_agente_modulo = '. $target_module->{'id_agente_modulo'}. ' AND utimestamp > '.$week_utimestamp[$i].' AND utimestamp < '.$temp1;
+print "DEBUG SQL - $query_sql \n";
+        $week_data[$i] = get_db_free_field ($query_sql, $dbh);
+
+        # It's possible that one of the week_data[i] values was not valid (NULL)
+        # so recheck it and relay on n=0 for "no data" values set to 0 in result
+        # Calculate total ammount of valida data for each data sample
+        if ( (is_numeric($week_data[$i])) && ($week_data[$i] > 0) ){
+            $n++;
+            # Average SUM
+            $average = $average + $week_data[$i];
+        }
+    }
+
+    # Real average value
+print "Value of n is $n \n";
+    if ($n > 0){
+        $average = $average / $n;
+    } else {
+        $average = 0;
+    }
+
+    # Calculate typical deviation
+    my $typical_deviation = 0;
+    for ($i=0; $i< $n; $i++){
+        if ( (is_numeric($week_data[$i])) && ($week_data[$i] > 0) ) {
+            $typical_deviation = $typical_deviation + (($week_data[$i] - $average)**2);
+        }
+    }
+    $typical_deviation = sqrt ($typical_deviation / ($n-1));
+
+    # (PROC) Compare with current data
+    if ($prediction_mode == 0){
+        $query_sql = 'SELECT data FROM tagente_estado WHERE id_agente_modulo = '.$target_module->{'id_agente_modulo'};
+        my $current_value = get_db_free_field ($query_sql, $dbh);
+        if ( ($current_value >= ($average - $typical_deviation)) || ($current_value <= ($average + $typical_deviation)) ){
+            $module_data = 1; # OK !!
+        } else {
+            $module_data = 0; # Out of predictions
+        }
+    } else {
+        # Prediction based on data
+        $module_data = $average;
+    }
+
+    # Build data for insertion
+	my %part;
+	$part{'name'}[0] = $agent_module->{'nombre'};
+	$part{'description'}[0] = "";
+	$part{'data'}[0] = $module_data;
+    my $tipo_modulo = dame_nombretipomodulo_idagentemodulo ($pa_config, $agent_module->{'id_tipo_modulo'}, $dbh);
+
+    # 1 - generic_data
+    # 2 - generic_proc
+	if (1 == $agent_module->{'id_tipo_modulo'}) {
+		module_generic_data ($pa_config, \%part, $timestamp, $agent_name, $tipo_modulo, $dbh);
+	}
+	elsif (2 == $agent_module->{'id_tipo_modulo'}) {
+		module_generic_data_inc ($pa_config, \%part, $timestamp, $agent_name, $tipo_modulo, $dbh);
+	}
+	else { # Unknown module!, this IS a problem
+	    logger ($pa_config, "[FATAL] Prediction Server Problem with unknown module type '$tipo_modulo'", 0);
+        print "[DEBUG] Executing Prediction UNKONWN MODULE TYPE$@\n";
+        exit;
+	}
+	# Update agent last contact
+	# Insert Pandora version as agent version
+	pandora_lastagentcontact ($pa_config, $timestamp, $agent_name,  $pa_config->{'servername'}.$pa_config->{"servermode"}, $pa_config->{'version'}, -1, $dbh);
+}
diff --git a/pandora_server/lib/PandoraFMS/Config.pm b/pandora_server/lib/PandoraFMS/Config.pm
index 371b589c2c..a2fad0d2ea 100644
--- a/pandora_server/lib/PandoraFMS/Config.pm
+++ b/pandora_server/lib/PandoraFMS/Config.pm
@@ -27,15 +27,18 @@ require Exporter;
 our @ISA = ("Exporter");
 our %EXPORT_TAGS = ( 'all' => [ qw( ) ] );
 our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
-our @EXPORT = qw( 	pandora_help_screen
-			pandora_init
-			pandora_loadconfig  );
+our @EXPORT = qw( 	
+        pandora_help_screen
+		pandora_init
+		pandora_loadconfig
+        pandora_startlog
+    );
 
 # There is no global vars, all variables (setup) passed as hash reference
 
 # version: Defines actual version of Pandora Server for this module only
 my $pandora_version = "2.0-dev";
-my $pandora_build="PS080226";
+my $pandora_build="PS080311";
 our $VERSION = $pandora_version." ".$pandora_build;
 
 # Setup hash
@@ -48,12 +51,14 @@ my %pa_config;
 ##########################################################################
 
 sub help_screen {
-	printf "\n\nSyntax: \n  pandora_server < fullpathname to pandora server configuration file > [ options ] \n\n";
+	printf "\nSyntax: \n\n  pandora_server < fullpathname to pandora server configuration file > [ options ] \n\n";
 	printf "Following options are optional : \n";
-	printf "            -v  :  Verbose mode activated, give more information in logfile \n";
-	printf "            -d  :  Debug mode activated, give extensive information in logfile \n";
-	printf "            -D  :  Daemon mode (runs in backgroup)\n";
-	printf "            -h  :  This screen, show a little help screen \n";
+	printf "      -v        :  Verbose mode activated, give more information in logfile \n";
+	printf "      -d        :  Debug mode activated, give extensive information in logfile \n";
+	printf "      -D        :  Daemon mode (runs in backgroup)\n";
+    printf "      -P <file> :  Store PID to file.\n";
+    printf "      -q        :  Quiet startup\n";
+	printf "      -h        :  This screen, show a little help screen \n";
 	printf " \n";
 	exit;
 }
@@ -67,8 +72,8 @@ sub pandora_init {
 	my $pa_config = $_[0];
 	my $init_string = $_[1];
 	printf "\n$init_string $pandora_version Build $pandora_build Copyright (c) 2004-2008 ArticaST\n";
-	printf "This program is Free Software, licensed under the terms of GPL License v2.\n";
-	printf "You can download latest versions and documentation at http://pandora.sourceforge.net. \n\n";
+	printf "This program is OpenSource, licensed under the terms of GPL License version 2.\n";
+	printf "You can download latest versions and documentation at http://pandora.sourceforge.net \n\n";
 
 	# Load config file from command line
 	if ($#ARGV == -1 ){
@@ -78,6 +83,8 @@ sub pandora_init {
 	}
    	$pa_config->{"verbosity"}=1; 	# Verbose 1 by default
 	$pa_config->{"daemon"}=0; 	# Daemon 0 by default
+    $pa_config->{'PID'}=""; # PID file not exist by default
+    $pa_config->{"quiet"}=0;   # Daemon 0 by default
 
 	# If there are not valid parameters
 	my $parametro;
@@ -90,9 +97,15 @@ sub pandora_init {
         elsif ($parametro =~ m/-v\z/i) { 
             $pa_config->{"verbosity"}=5; 
         }
+        elsif ($parametro =~ m/^-P\z/i) { 
+            $pa_config->{'PID'}= clean_blank($ARGV[$ax+1]);
+        }
         elsif ($parametro =~ m/-d\z/) { 
             $pa_config->{"verbosity"}=10; 
         }
+        elsif ($parametro =~ m/-q\z/) { 
+            $pa_config->{"quiet"}=1; 
+        }
         elsif ($parametro =~ m/-D\z/) { 
             $pa_config->{"daemon"}=1; 
         }
@@ -161,15 +174,19 @@ sub pandora_loadconfig {
     $pa_config->{"tcp_timeout"} = 20; # Introduced on 1.3.1
     $pa_config->{"snmp_proc_deadresponse"} = 0; # Introduced on 1.3.1 10 Feb08
     $pa_config->{"plugin_threads"} = 3; # Introduced on 2.0
+    $pa_config->{"prediction_threads"} = 3; # Introduced on 2.0
     $pa_config->{"plugin_timeout"} = 5; # Introduced on 2.0
     $pa_config->{"wmi_threads"} = 3; # Introduced on 2.0
     $pa_config->{"wmi_timeout"} = 5; # Introduced on 2.0
 
 	# Check for UID0
-	if ($> == 0){
-		printf " [W] Not all Pandora FMS components need to be executed as root\n";
-		printf "     please consider starting it with a non-privileged user.\n";
-	}
+    if ($pa_config->{"quiet"} != 0){
+	    if ($> == 0){
+		    printf " [W] Not all Pandora FMS components need to be executed as root\n";
+		    printf "     please consider starting it with a non-privileged user.\n";
+	    }
+    }
+
 	# Check for file
 	if ( ! -e $archivo_cfg ) {
 		printf "\n [ERROR] Cannot open configuration file at $archivo_cfg. \n";
@@ -250,6 +267,9 @@ sub pandora_loadconfig {
 		elsif ($parametro =~ m/^dataserver\s([0-9]*)/i){
 			$pa_config->{'dataserver'}= clean_blank($1);
 		}
+        elsif ($parametro =~ m/^networkserver\s([0-9]*)/i){
+            $pa_config->{'networkserver'}= clean_blank($1);
+        }
         elsif ($parametro =~ m/^pluginserver\s([0-9]*)/i){
             $pa_config->{'pluginserver'}= clean_blank($1);
         }
@@ -316,6 +336,9 @@ sub pandora_loadconfig {
         elsif ($parametro =~ m/^plugin_threads\s([0-9]*)/i) {
             $pa_config->{'plugin_threads'}= clean_blank($1); 
         }
+        elsif ($parametro =~ m/^prediction_threads\s([0-9]*)/i) {
+            $pa_config->{'prediction_threads'}= clean_blank($1); 
+        }
         elsif ($parametro =~ m/^plugin_timeout\s([0-9]*)/i) {
             $pa_config->{'plugin_timeout'}= clean_blank($1); 
         }
@@ -326,7 +349,10 @@ sub pandora_loadconfig {
     } # end of loop for parameter #
 
 
-	if ( $pa_config->{"verbosity"} > 0){
+	if (($pa_config->{"verbosity"} > 0) && ($pa_config->{"quiet"} == 0)){
+        if ($pa_config->{"PID"} ne ""){
+            print " [*] PID File is written at ".$pa_config->{'PID'}."\n";
+        }
 		print " [*] Server basepath is ".$pa_config->{'basepath'}."\n";
 		print " [*] Server logfile at ".$pa_config->{"logfile"}."\n";
 		print " [*] Server errorlogfile at ".$pa_config->{"errorlogfile"}."\n";
@@ -367,50 +393,54 @@ sub pandora_loadconfig {
         print " [ERROR] You must enable 'wmiserver' in setup file to run Pandora FMS WMI server. \n\n";
         exit;
     }
-	if ($opmode == 0){
-		print " [*] You are running Pandora FMS Data Server. \n";
-		$parametro ="Pandora FMS Data Server";
-		$pa_config->{"servermode"}="_Data";
-	}
-	if ($opmode == 1){
-		print " [*] You are running Pandora FMS Network Server. \n";
-		$parametro ="Pandora FMS Network Server";
-		$pa_config->{"servermode"}="_Net";
-	}
-	if ($opmode == 2){
-		print " [*] You are running Pandora FMS SNMP Console. \n";
-		$parametro ="Pandora FMS SNMP Console";
-		$pa_config->{"servermode"}="_SNMP";
-	}
-	if ($opmode == 3){
-		print " [*] You are running Pandora FMS Recon Server. \n";
-		$parametro ="Pandora FMS Recon Server";
-		$pa_config->{"servermode"}="_Recon";
-	}
-    if ($opmode == 4){
-        print " [*] You are running Pandora FMS Plugin Server. \n";
-        $parametro ="Pandora FMS Plugin Server";
-        $pa_config->{"servermode"}="_Plugin";
+
+    # Show some config options in startup
+    if ($pa_config->{"quiet"} == 0){
+	    if ($opmode == 0){
+		    print " [*] You are running Pandora FMS Data Server. \n";
+		    $parametro ="Pandora FMS Data Server";
+		    $pa_config->{"servermode"}="_Data";
+	    }
+	    if ($opmode == 1){
+		    print " [*] You are running Pandora FMS Network Server. \n";
+		    $parametro ="Pandora FMS Network Server";
+		    $pa_config->{"servermode"}="_Net";
+	    }
+	    if ($opmode == 2){
+		    print " [*] You are running Pandora FMS SNMP Console. \n";
+		    $parametro ="Pandora FMS SNMP Console";
+		    $pa_config->{"servermode"}="_SNMP";
+	    }
+	    if ($opmode == 3){
+		    print " [*] You are running Pandora FMS Recon Server. \n";
+		    $parametro ="Pandora FMS Recon Server";
+		    $pa_config->{"servermode"}="_Recon";
+	    }
+        if ($opmode == 4){
+            print " [*] You are running Pandora FMS Plugin Server. \n";
+            $parametro ="Pandora FMS Plugin Server";
+            $pa_config->{"servermode"}="_Plugin";
+        }
+        if ($opmode == 5){
+            print " [*] You are running Pandora FMS Prediction Server. \n";
+            $parametro ="Pandora FMS Prediction Server";
+            $pa_config->{"servermode"}="_Prediction";
+        }
+        if ($opmode == 6){
+            print " [*] You are running Pandora FMS WMI Server. \n";
+            $parametro ="Pandora FMS WMI Server";
+            $pa_config->{"servermode"}="_WMI";
+        }
+	    if ($pa_config->{"pandora_check"} == 1) {
+		    print " [*] MD5 Security enabled.\n";
+	    }
+	    if ($pa_config->{"pandora_master"} == 1) {
+		    print " [*] This server is running in MASTER mode.\n";
+	    }
     }
-    if ($opmode == 5){
-        print " [*] You are running Pandora FMS Prediction Server. \n";
-        $parametro ="Pandora FMS Prediction Server";
-        $pa_config->{"servermode"}="_Prediction";
-    }
-    if ($opmode == 6){
-        print " [*] You are running Pandora FMS WMI Server. \n";
-        $parametro ="Pandora FMS WMI Server";
-        $pa_config->{"servermode"}="_WMI";
-    }
-	if ($pa_config->{"pandora_check"} == 1) {
-		print " [*] MD5 Security enabled.\n";
-	}
-	if ($pa_config->{"pandora_master"} == 1) {
-		print " [*] This server is running in MASTER mode.\n";
-	}
 	logger ($pa_config, "Launching $parametro $pa_config->{'version'} $pa_config->{'build'}", 0);
 	my $config_options = "Logfile at ".$pa_config->{"logfile"}.", Basepath is ".$pa_config->{"basepath"}.", Checksum is ".$pa_config->{"pandora_check"}.", Master is ".$pa_config->{"pandora_master"}.", SNMP Console is ".$pa_config->{"snmpconsole"}.", Server Threshold at ".$pa_config->{"server_threshold"}." sec, verbosity at ".$pa_config->{"verbosity"}.", Alert Threshold at $pa_config->{'alert_threshold'}, ServerName is '".$pa_config->{'servername'}.$pa_config->{"servermode"}."'";
-	logger ($pa_config, "Config options: $config_options");
+	logger ($pa_config, "Config options: $config_options", 1);
 	my $dbh;
 	# Check valid Database variables and update server status
 	eval {
@@ -423,15 +453,24 @@ sub pandora_loadconfig {
 		print $@;
 		exit;
 	}
-	print " [*] Pandora FMS Server [".$pa_config->{'servername'}.$pa_config->{"servermode"}."] is running and operative \n";
+    if ($pa_config->{"quiet"} == 0){
+	    print " [*] Pandora FMS Server [".$pa_config->{'servername'}.$pa_config->{"servermode"}."] is running and operative \n";
+    }
 	$pa_config->{'server_id'} = dame_server_id ($pa_config, $pa_config->{'servername'}.$pa_config->{"servermode"}, $dbh);
-	
-	# Dump all errors to errorlog
-	open STDERR, ">>$pa_config->{'errorlogfile'}" or die " [ERROR] Pandora FMS can't write to Errorlog. Aborting : \n    $!";
-    my $time_now = &UnixDate("today","%Y/%m/%d %H:%M:%S");
-    print STDERR "$time_now - ".$pa_config->{'servername'}." Starting Pandora FMS server. Error logging activated \n";
 }
 
+
+
+sub pandora_startlog ($){
+    my $pa_config = $_[0];
+
+    # Dump all errors to errorlog
+    open STDERR, ">>$pa_config->{'errorlogfile'}" or die " [ERROR] Pandora FMS can't write to Errorlog. Aborting : \n $! \n";
+    my $time_now = &UnixDate("today","%Y/%m/%d %H:%M:%S");
+    print STDERR "$time_now - ".$pa_config->{'servername'}.$pa_config->{"servermode"}." Starting Pandora FMS Server. Error logging activated \n";
+    # This redirect ANY output to errorlog. Not a good idea for real usage !
+    # open STDOUT, ">>$pa_config->{'errorlogfile'}"
+}
 # End of function declaration
 # End of defined Code
 
diff --git a/pandora_server/lib/PandoraFMS/DB.pm b/pandora_server/lib/PandoraFMS/DB.pm
index 1c65f3b230..b38e593c83 100644
--- a/pandora_server/lib/PandoraFMS/DB.pm
+++ b/pandora_server/lib/PandoraFMS/DB.pm
@@ -33,39 +33,42 @@ require Exporter;
 our @ISA = ("Exporter");
 our %EXPORT_TAGS = ( 'all' => [ qw( ) ] );
 our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
-our @EXPORT = qw( 	crea_agente_modulo			
-			dame_server_id				
-			dame_agente_id
-			dame_agente_modulo_id
-			dame_agente_nombre
-			dame_comando_alerta
-			dame_desactivado
-			dame_grupo_agente
-			dame_id_tipo_modulo
-			dame_intervalo
-			dame_learnagente
-			dame_modulo_id
-			dame_nombreagente_agentemodulo
-			dame_nombretipomodulo_idagentemodulo
-			dame_ultimo_contacto
-			give_networkserver_status
-			pandora_updateserver
-			pandora_serverkeepaliver
-			pandora_audit
-			pandora_event
-			pandora_lastagentcontact
-			pandora_writedata
-			pandora_writestate
-			pandora_calcula_alerta
-			module_generic_proc
-			module_generic_data
-			module_generic_data_inc
-			module_generic_data_string
-			execute_alert
-			give_network_component_profile_name
-			pandora_create_incident 
-			give_db_value
-		);
+our @EXPORT = qw( 	
+        crea_agente_modulo			
+		dame_server_id				
+		dame_agente_id
+		dame_agente_modulo_id
+		dame_agente_nombre
+		dame_comando_alerta
+		dame_desactivado
+		dame_grupo_agente
+		dame_id_tipo_modulo
+		dame_intervalo
+		dame_learnagente
+		dame_modulo_id
+		dame_nombreagente_agentemodulo
+		dame_nombretipomodulo_idagentemodulo
+		dame_ultimo_contacto
+		give_networkserver_status
+		pandora_updateserver
+		pandora_serverkeepaliver
+		pandora_audit
+		pandora_event
+		pandora_lastagentcontact
+		pandora_writedata
+		pandora_writestate
+		pandora_calcula_alerta
+		module_generic_proc
+		module_generic_data
+		module_generic_data_inc
+		module_generic_data_string
+		execute_alert
+		give_network_component_profile_name
+		pandora_create_incident 
+		get_db_value
+        get_db_free_row
+        get_db_free_field
+	);
 
 # Spanish translation note:
 # 'Crea' in spanish means 'create'
@@ -374,18 +377,22 @@ sub pandora_writestate (%$$$$$$$) {
 	# now we use only local timestamp to stamp state of modules
 	my $pa_config = $_[0];
 	my $nombre_agente = $_[1];
-	my $tipo_modulo = $_[2];
+	my $tipo_modulo = $_[2]; # passed as string
 	my $nombre_modulo = $_[3];
 	my $datos = $_[4]; # Careful: Dont pass a hash, only a single value
 	my $estado = $_[5];
 	my $dbh = $_[6];
 	my $needs_update = $_[7];
-	my $timestamp = &UnixDate ("today", "%Y-%m-%d %H:%M:%S");
-	my $utimestamp; # integer version of timestamp	
-	$utimestamp = &UnixDate($timestamp,"%s"); # convert from human to integer
+	
 	my @data;
 	my $cambio = 0; 
 	my $id_grupo;
+
+    # Get current timestamp / unix numeric time
+    my $timestamp = &UnixDate ("today", "%Y-%m-%d %H:%M:%S"); # string timestamp
+    my $utimestamp = &UnixDate($timestamp,"%s"); # convert from human to integer
+
+    # Get server id
 	my $server_name = $pa_config->{'servername'}.$pa_config->{"servermode"};
 	my $id_server = dame_server_id($pa_config, $server_name, $dbh);
 
@@ -395,8 +402,9 @@ sub pandora_writestate (%$$$$$$$) {
 	my $id_agente = dame_agente_id ($pa_config, $nombre_agente, $dbh);
 	my $id_modulo = dame_modulo_id ($pa_config, $tipo_modulo, $dbh);
 	my $id_agente_modulo = dame_agente_modulo_id($pa_config, $id_agente, $id_modulo, $nombre_modulo, $dbh);
+
 	if (($id_agente ==  -1) || ($id_agente_modulo == -1)) {
-		goto fin_pandora_writestate;
+		return 0;
 	}
 
 	# Seek for agent_interval or module_interval
@@ -432,38 +440,37 @@ sub pandora_writestate (%$$$$$$$) {
 	my $query_act; # OJO que dentro de una llave solo tiene existencia en esa llave !!
 	if ($s_idages->rows == 0) { # Doesnt exist entry in table, lets make the first entry
 		logger($pa_config, "Create entry in tagente_estado for module $nombre_modulo",4);
-    		$query_act = "INSERT INTO tagente_estado (id_agente_modulo, datos, timestamp, estado, cambio, id_agente, last_try, utimestamp, current_interval, running_by, last_execution_try) VALUES ($id_agente_modulo,$datos,'$timestamp','$estado','1',$id_agente,'$timestamp',$utimestamp, $module_interval, $id_server, $utimestamp)"; # Cuando se hace un insert, siempre hay un cambio de estado
+        $query_act = "INSERT INTO tagente_estado (id_agente_modulo, datos, timestamp, estado, cambio, id_agente, last_try, utimestamp, current_interval, running_by, last_execution_try) VALUES ($id_agente_modulo,$datos,'$timestamp','$estado','1',$id_agente,'$timestamp',$utimestamp, $module_interval, $id_server, $utimestamp)"; # Cuando se hace un insert, siempre hay un cambio de estado
 	} else { # There are an entry in table already
-	        @data = $s_idages->fetchrow_array();
-	        # Se supone que $data[5](estado) ( nos daria el estado ANTERIOR
-		# For xxxx_PROC type (boolean / monitor), create an event if state has changed
-	        if (( $data[5] != $estado) && ( ($tipo_modulo =~/keep_alive/) || ($tipo_modulo =~ /proc/)) ) {
-	                # Cambio de estado detectado !
-	                $cambio = 1;
-	                # Este seria el momento oportuno de probar a saltar la alerta si estuviera definida
-			# Makes an event entry, only if previous state changes, if new state, doesnt give any alert
-			$id_grupo = dame_grupo_agente($pa_config, $id_agente,$dbh);
-			my $descripcion;
- 			if ( $estado == 0) {
- 				$descripcion = "Monitor ($nombre_modulo) goes up ";
- 			}
-			if ( $estado == 1) {
-				$descripcion = "Monitor ($nombre_modulo) goes down";
-			}
-			pandora_event ($pa_config, $descripcion, $id_grupo, $id_agente, $dbh);
-	        }
-	        if ($needs_update == 1) {
-    			$query_act = "UPDATE tagente_estado SET utimestamp = $utimestamp, datos = $datos, cambio = '$cambio', timestamp = '$timestamp', estado = '$estado', id_agente = $id_agente, last_try = '$timestamp', current_interval = '$module_interval', running_by = $id_server, last_execution_try = $utimestamp WHERE id_agente_modulo = '$id_agente_modulo'";
-    		} else { # dont update last_try field, that it's the field
-    			 # we use to check last update time in database
-    			$query_act = "UPDATE tagente_estado SET utimestamp = $utimestamp, datos = $datos, cambio = '$cambio', timestamp = '$timestamp', estado = '$estado', id_agente = $id_agente, current_interval = '$module_interval', running_by = $id_server, last_execution_try = $utimestamp WHERE id_agente_modulo = '$id_agente_modulo'";
-    		}
-    	}
+	    @data = $s_idages->fetchrow_array();
+	    # Se supone que $data[5](estado) ( nos daria el estado ANTERIOR
+	# For xxxx_PROC type (boolean / monitor), create an event if state has changed
+	    if (( $data[5] != $estado) && ( ($tipo_modulo =~/keep_alive/) || ($tipo_modulo =~ /proc/)) ) {
+	        # Cambio de estado detectado !
+	        $cambio = 1;
+	        # Este seria el momento oportuno de probar a saltar la alerta si estuviera definida
+		# Makes an event entry, only if previous state changes, if new state, doesnt give any alert
+		$id_grupo = dame_grupo_agente($pa_config, $id_agente,$dbh);
+		my $descripcion;
+        if ( $estado == 0) {
+            $descripcion = "Monitor ($nombre_modulo) goes up ";
+        }
+		if ( $estado == 1) {
+			$descripcion = "Monitor ($nombre_modulo) goes down";
+		}
+		pandora_event ($pa_config, $descripcion, $id_grupo, $id_agente, $dbh);
+	    }
+	    if ($needs_update == 1) {
+            $query_act = "UPDATE tagente_estado SET utimestamp = $utimestamp, datos = $datos, cambio = '$cambio', timestamp = '$timestamp', estado = '$estado', id_agente = $id_agente, last_try = '$timestamp', current_interval = '$module_interval', running_by = $id_server, last_execution_try = $utimestamp WHERE id_agente_modulo = $id_agente_modulo";
+        } else { # dont update last_try field, that it's the field
+                # we use to check last update time in database
+            $query_act = "UPDATE tagente_estado SET utimestamp = $utimestamp, datos = $datos, cambio = '$cambio', timestamp = '$timestamp', estado = '$estado', id_agente = $id_agente, current_interval = '$module_interval', running_by = $id_server, last_execution_try = $utimestamp WHERE id_agente_modulo = $id_agente_modulo";
+        }
+    }
 	my $a_idages = $dbh->prepare($query_act);
 	$a_idages->execute;
 	$a_idages->finish();
-    	$s_idages->finish();
-fin_pandora_writestate:
+   	$s_idages->finish();
 }
 
 ##########################################################################
@@ -528,14 +535,14 @@ sub pandora_accessupdate (%$$) {
 		        logger($pa_config,"Updating tagent_access for agent id $id_agent",9);
 	        }
 
-                # Update keepalive module (if present, if there is more than one, only updates first one!).
-                my $id_agent_module = give_db_free ("SELECT id_agente_modulo FROM tagente_modulo WHERE id_agente = $id_agent AND id_tipo_modulo = 100", $dbh);
-                if ($id_agent_module ne -1){
-                        my $agent_name = give_db_free ("SELECT nombre FROM tagente WHERE id_agente = $id_agent", $dbh);
-                        my $module_typename = "keep_alive";
-                        my $module_name = give_db_free ("SELECT nombre FROM tagente_modulo WHERE id_agente_modulo = $id_agent_module", $dbh);
-                        pandora_writestate ($pa_config, $agent_name, $module_typename, $module_name, 1, 0, $dbh, 1);
-                }
+            # Update keepalive module (if present, if there is more than one, only updates first one!).
+            my $id_agent_module = get_db_free_field ("SELECT id_agente_modulo FROM tagente_modulo WHERE id_agente = $id_agent AND id_tipo_modulo = 100", $dbh);
+            if ($id_agent_module ne -1){
+                    my $agent_name = get_db_free_field ("SELECT nombre FROM tagente WHERE id_agente = $id_agent", $dbh);
+                    my $module_typename = "keep_alive";
+                    my $module_name = get_db_free_field ("SELECT nombre FROM tagente_modulo WHERE id_agente_modulo = $id_agent_module", $dbh);
+                    pandora_writestate ($pa_config, $agent_name, $module_typename, $module_name, 1, 0, $dbh, 1);
+            }
         }
 }
 
@@ -960,8 +967,10 @@ fin_DB_insert_datos:
 ## Update server status
 ##########################################################################
 sub pandora_serverkeepaliver (%$$) {
-        my $pa_config= $_[0];
-	my $opmode = $_[1]; # 0 dataserver, 1 network server, 2 snmp console, 3 recon server
+    my $pa_config= $_[0];
+	my $opmode = $_[1]; # 0 dataserver, 1 network server, 2 snmp console
+                        # 3 recon srv, 4 plugin srv, 5 prediction srv
+                        # 6 WMI server
 	my $dbh = $_[2];
 	my $version_data;
 	my $pandorasuffix;
@@ -1024,7 +1033,7 @@ sub pandora_updateserver (%$$$) {
 	} elsif ($opmode == 4){
         $pandorasuffix = "_Plugin";
     } elsif ($opmode == 5){
-        $pandorasuffix = "_IA";
+        $pandorasuffix = "_Prediction";
     } elsif ($opmode == 6){
         $pandorasuffix = "_WMI";
     } else {
@@ -1091,7 +1100,7 @@ sub pandora_lastagentcontact (%$$$$$$) {
 	my $dbh = $_[6];
 
         my $id_agente = dame_agente_id($pa_config, $nombre_agente,$dbh);
-	pandora_accessupdate ($pa_config, $id_agente, $dbh);
+	    pandora_accessupdate ($pa_config, $id_agente, $dbh);
         my $query = ""; 
         if ($interval == -1){ # no update for interval field (some old agents doest support it) 
 		$query = "update tagente set agent_version = '$agent_version', ultimo_contacto_remoto = '$timestamp', ultimo_contacto = '$time_now', os_version = '$os_data' where id_agente = $id_agente";                	
@@ -1370,25 +1379,25 @@ sub give_group_disabled (%$$) {
 ## Return module ID, given "nombre_modulo" as module name
 ##########################################################################
 sub dame_modulo_id (%$$) {
-	my $pa_config = $_[0];
-        my $nombre_modulo = $_[1];
-	my $dbh = $_[2];
+    my $pa_config = $_[0];
+    my $nombre_modulo = $_[1];
+    my $dbh = $_[2];
 
-        my $id_modulo; my @data;
-        # Calculate agent ID using select by its name
-        my $query_idag = "select * from ttipo_modulo where nombre = '$nombre_modulo'";
-        my $s_idag = $dbh->prepare($query_idag);
-        $s_idag ->execute;
-    	if ($s_idag->rows == 0) {
-        	logger($pa_config, "ERROR dame_modulo_id(): Cannot find module called $nombre_modulo ",1);
-        	logger($pa_config, "ERROR: SQL Query is $query_idag ",2);
-        	$id_modulo = -1;
-    	} else  {    
-    		@data = $s_idag->fetchrow_array();
-    		$id_modulo = $data[0];
-    	}
-    	$s_idag->finish();
-    	return $id_modulo;
+    my $id_modulo; my @data;
+    # Calculate agent ID using select by its name
+    my $query_idag = "select * from ttipo_modulo where nombre = '$nombre_modulo'";
+    my $s_idag = $dbh->prepare($query_idag);
+    $s_idag ->execute;
+    if ($s_idag->rows == 0) {
+        logger($pa_config, "ERROR dame_modulo_id(): Cannot find module called $nombre_modulo ",1);
+        logger($pa_config, "ERROR: SQL Query is $query_idag ",2);
+        $id_modulo = 0;
+    } else  {    
+        @data = $s_idag->fetchrow_array();
+        $id_modulo = $data[0];
+    }
+    $s_idag->finish();
+    return $id_modulo;
 }
 
 ##########################################################################
@@ -1686,7 +1695,7 @@ sub crea_agente_modulo (%$$$$$$$) {
 # Generic access to a field ($field) given a table
 # give_db_value (field_name_to_be_returned, table, field_search, condition_value, dbh)
 # ---------------------------------------------------------------
-sub give_db_value ($$$$$) {
+sub get_db_value ($$$$$) {
 	my $field = $_[0];
 	my $table = $_[1];
 	my $field_search = $_[2];
@@ -1706,9 +1715,10 @@ sub give_db_value ($$$$$) {
 }
 
 # ---------------------------------------------------------------
-# Generic access to a field ($field) given a table
+# Free SQL sentence. Return first field on exit
 # ---------------------------------------------------------------
-sub give_db_free ($$) {
+
+sub get_db_free_field ($$) {
         my $condition = $_[0];
         my $dbh = $_[1];
         
@@ -1724,6 +1734,28 @@ sub give_db_free ($$) {
         return -1;
 }
 
+
+
+# ---------------------------------------------------------------
+# Free SQL sentence. Return entire hash in row
+# ---------------------------------------------------------------
+
+sub get_db_free_row ($$) {
+        my $condition = $_[0];
+        my $dbh = $_[1];
+        my $rowref;
+
+        my $query = $condition;
+        my $s_idag = $dbh->prepare($query);
+        $s_idag ->execute;
+        if ($s_idag->rows != 0) {
+                $rowref = $s_idag->fetchrow_hashref;
+                $s_idag->finish();
+                return $rowref;
+        }
+        return -1;
+}
+
 # End of function declaration
 # End of defined Code
 
diff --git a/pandora_server/lib/PandoraFMS/Tools.pm b/pandora_server/lib/PandoraFMS/Tools.pm
index c514e79280..28411b0f3c 100644
--- a/pandora_server/lib/PandoraFMS/Tools.pm
+++ b/pandora_server/lib/PandoraFMS/Tools.pm
@@ -27,15 +27,16 @@ require Exporter;
 our @ISA = ("Exporter");
 our %EXPORT_TAGS = ( 'all' => [ qw( ) ] );
 our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
-our @EXPORT = qw( 	daemonize
-			logger
-			limpia_cadena
-			md5check
-			float_equal
-			sqlWrap
-			is_numeric
-            clean_blank
-		);
+our @EXPORT = qw( 	
+        pandora_daemonize
+        logger
+        limpia_cadena
+        md5check
+        float_equal
+        sqlWrap
+        is_numeric
+        clean_blank
+    );
 
 
 ##########################################################################
@@ -43,15 +44,23 @@ our @EXPORT = qw( 	daemonize
 # Put program in background (for daemon mode)
 ##########################################################################
 
-sub daemonize {
-    chdir '/tmp'                 or die "Can't chdir to /tmp: $!";
-    open STDIN, '/dev/null'   or die "Can't read /dev/null: $!";
-    open STDOUT, '>>/dev/null' or die "Can't write to /dev/null: $!";
-    open STDERR, '>>/dev/null' or die "Can't write to /dev/null: $!";
-    defined(my $pid = fork)   or die "Can't fork: $!";
+sub pandora_daemonize {
+    my $pa_config = $_[0];
+    open STDIN, '/dev/null'     or die "Can't read /dev/null: $!";
+    open STDOUT, '>>/dev/null'  or die "Can't write to /dev/null: $!";
+    open STDERR, '>>/dev/null'  or die "Can't write to /dev/null: $!";
+    chdir '/tmp'                or die "Can't chdir to /tmp: $!";
+    defined(my $pid = fork)     or die "Can't fork: $!";
     exit if $pid;
-    setsid                    or die "Can't start a new session: $!";
+    setsid                      or die "Can't start a new session: $!";
     umask 0;
+
+    # Store PID of this process in file presented by config token
+    if ($pa_config->{'PID'} ne ""){
+        open (FILE, "> ".$pa_config->{'PID'}) or die "[FATAL] Cannot open PIDfile at ".$pa_config->{'PID'};
+        print FILE "$$";
+        close (FILE);
+    }
 }
 
 
diff --git a/pandora_server/util/pandora_dbstress.README b/pandora_server/util/pandora_dbstress.README
index e0220b7051..75c0688c21 100644
--- a/pandora_server/util/pandora_dbstress.README
+++ b/pandora_server/util/pandora_dbstress.README
@@ -1,8 +1,34 @@
-This small utility is make to test your database speed in Pandora Scheme.
+Pandora FMS DB Stress
+=====================
 
-You need to create an agent and assing modules for automated data injection with this tool. Name this modules acording this:
+This is a small tool to test your database performance. It also could be used to "pregenerate" random or periodic data (using trigonometry functions) and populate ficticious modules.
+
+You need to create an agent and assign modules for automated data injection with this tool. You need to name that modules according to this notation:
 
 random - To generate "random" data.
 curve - To generate a math curve using trigonometrical functions, useful to see interpolation working with different intervals, etc
 boolean - Generate "random" boolean data.
 
+So you could use any name that contains words "random, curve or boolean", for example:
+
+random_1 or curve_other
+
+You only could choose "data server" kind of module.
+
+Finetuning DB stress tool
+=========================
+
+Tool is preconfigured to search in all agents for modules called random, curve or boolean, and to use a interval of 300 and during 30 days.
+
+If want to modify this behaviour you should edit pandora_dbstress script and modify some variables at the top of file:
+
+ # Configure here target (AGENT_ID for Stress)
+ my $target_module = -1; # -1 for all modules of that agent
+ my $target_agent = -1;
+ my $target_interval = 300;
+ my $target_days = 30;
+
+Set there target_module (for a fixed module) or set -1 to process all matching targets
+Set there target_agent (for a specific agent).   
+Set target_interval in seconds for default module interval data periodicity. 
+Set target_days, number of days in the past from current timestamp.
diff --git a/pandora_server/util/pandora_dbstress.pl b/pandora_server/util/pandora_dbstress.pl
index b351e18517..4cbbf5234b 100755
--- a/pandora_server/util/pandora_dbstress.pl
+++ b/pandora_server/util/pandora_dbstress.pl
@@ -21,8 +21,8 @@
 
 my $target_module = -1; # -1 for all modules of that agent
 my $target_agent = -1;
-my $target_interval = 1200;
-my $target_days = 12;
+my $target_interval = 300;
+my $target_days = 30;
 
 ################################################################################
 ################################################################################