", ?) AS data_source_path, GROUP_CONCAT(DISTINCT dtr.data_source_name) AS data_source_names, GROUP_CONCAT(DISTINCT dtd.rrd_step) AS rrd_step, GROUP_CONCAT(DISTINCT dtr.rrd_heartbeat) AS rrd_heartbeat, dsp.heartbeat AS profile_heartbeat, dsp.step AS profile_step FROM data_template_data AS dtd INNER JOIN data_template_rrd AS dtr ON dtr.local_data_id = dtd.local_data_id INNER JOIN graph_templates_item AS gti ON dtr.id = gti.task_item_id INNER JOIN data_source_profiles AS dsp ON dtd.data_source_profile_id = dsp.id LEFT JOIN graph_local AS gl ON gl.id = gti.local_graph_id LEFT JOIN host as h ON h.id = gl.host_id WHERE dtd.local_data_id != 0 AND h.disabled != "on" GROUP BY dtd.local_data_id', array(CACTI_PATH_RRA)); if ($max_threads == 1) { $newrows[0] = $rows; return $rows; } else { $newrows = array_chunk($rows, ceil(cacti_sizeof($rows) / $max_threads)); if (isset($newrows[$thread_id - 1])) { return $newrows[$thread_id - 1]; } else { return array(); } } } /** * rrdcheck_debug - this simple routine prints a standard message to the console * when running in debug mode. * * @param $message - (string) The message to display * * @return - NULL */ function rrdcheck_debug($message) { global $debug; if ($debug) { print 'rrdcheck: ' . $message . PHP_EOL; } } /** * do_rrdcheck - this routine is a generic routine that * check all RRDfiles (missing files, ...) and stored information (NaN) * * @param $thread_id - (int) the rrdcheck parallel thread id * * @return - NULL */ function do_rrdcheck($thread_id = 1) { global $config, $type; global $total_user, $total_system, $total_real, $total_dsses; global $user_time, $system_time, $real_time, $rrd_files; $user_time = 0; $system_time = 0; $real_time = 0; $dsses = 0; $poller_interval = read_config_option('poller_interval'); rrdcheck_debug(sprintf('Processing %s for Thread', $thread_id)); $max_threads = read_config_option('rrdcheck_parallel'); if (empty($max_threads)) { $max_threads = 1; set_config_option('rrdcheck_parallel', '1'); } $profiles = array_rekey( db_fetch_assoc('SELECT step, data_source_profile_id AS id, MIN(steps) AS steps, `rows` FROM data_source_profiles AS dsp INNER JOIN data_source_profiles_rra AS dspr ON dsp.id = dspr.data_source_profile_id GROUP BY data_source_profile_id'), 'id', array('step', 'steps', 'rows') ); $rrdfiles = get_rrdfiles($thread_id, $max_threads); $stats = array(); $rrd_files += cacti_sizeof($rrdfiles); $use_proxy = (read_config_option('storage_location') ? true : false); if ($use_proxy) { $rrdtool_pipe = rrd_init(false); } else { $process_pipes = rrdcheck_rrdtool_init(); $process = $process_pipes[0]; $pipes = $process_pipes[1]; } if (cacti_sizeof($rrdfiles)) { $now = time(); foreach ($rrdfiles as $rrdval) { $local_data_id = $rrdval['local_data_id']; $data_sources = array(); // Rekey the Data Sources key $sources = explode(',', $rrdval['data_source_names']); foreach ($sources as $s) { $data_sources[$s] = $s; } // The first RRA may have less than 24 hours of samples $duration = $profiles[$rrdval['data_source_profile_id']]['step'] * ($profiles[$rrdval['data_source_profile_id']]['rows'] - 1); $step = $profiles[$rrdval['data_source_profile_id']]['step']; $end = $now; $start = $end - $duration; $file = $rrdval['data_source_path']; if ($use_proxy) { $file_exists = rrdtool_execute("file_exists $file", true, RRDTOOL_OUTPUT_BOOLEAN, false, 'RRDCHECK'); } else { clearstatcache(); $file_exists = file_exists($file); } // don't attempt to get information if the file does not exist if ($file_exists) { if (!is_resource_writable($file)) { db_execute_prepared('INSERT INTO rrdcheck (local_data_id, test_date, message) VALUES (?,NOW(),?)', array( $local_data_id, "RRDfile is not writable - $file" ) ); } if (time() > (filemtime($file) + 3600)) { db_execute_prepared('INSERT INTO rrdcheck (local_data_id, test_date, message) VALUES (?,NOW(),?)', array( $local_data_id, "RRDfile modify time older than hour - $file" ) ); } if ($rrdval['profile_step'] != $rrdval['rrd_step']) { // Fix the RRD Data Template Data Step db_execute_prepared('UPDATE data_template_data SET rrd_step = ? WHERE local_data_id = ?', array( $rrdval['profile_step'], $local_data_id ) ); } if ($rrdval['rrd_heartbeat'] != $rrdval['profile_heartbeat']) { // Fix the RRD Data Template Data Step db_execute_prepared('UPDATE data_template_rrd SET rrd_heartbeat = ? WHERE local_data_id = ?', array($rrdval['profile_heartbeat'], $rrdval['local_data_id'])); } if ($use_proxy) { $output = rrdtool_execute("info $file", false, RRDTOOL_OUTPUT_STDOUT, false, 'RRDCHECK'); } else { $output = rrdcheck_rrdtool_execute("info $file", $pipes); } $matches = array(); $rrd_info = array(); $output = explode("\n", $output); $last_update = false; $rrd_step = false; // Process the RRDfile information into an array foreach ($output as $line) { $line = trim($line); if ($line == '') { continue; } if (!$last_update) { if (preg_match('/^last_update = (\S+)$/', $line, $matches)) { $last_update = $matches[1]; } } if (!$rrd_step) { if (preg_match('/^step = (\S+)$/', $line, $matches)) { $rrd_step = $matches[1]; } } if (preg_match('/^ds\[(\S+)\]\.(\S+) = (\S+)$/', $line, $matches)) { $rrd_info[$matches[1]][$matches[2]] = trim($matches[3], '"'); } } if ($rrd_step != $rrdval['profile_step']) { db_execute_prepared('INSERT INTO rrdcheck (local_data_id, test_date, message) VALUES (?, NOW(), ?)', array( $local_data_id, "The RRDfile step of {$step} does not match the Data Source Profile step {$rrdval['profile_step']}. File '$file'." ) ); } if ($last_update < (time() - 3600)) { db_execute_prepared('INSERT INTO rrdcheck (local_data_id, test_date, message) VALUES (?, NOW(), ?)', array( $local_data_id, "Last update value in RRDfile is older than 1 hour. File '$file'." ) ); } // Not really an issue that we should be calling out till we can fix if (cacti_sizeof($data_sources) > cacti_sizeof($rrd_info)) { db_execute_prepared('INSERT INTO rrdcheck (local_data_id, test_date, message) VALUES (?, NOW(), ?)', array( $local_data_id, "There are more Data Sources in the database than in the RRDfile, please investigate. File '$file'." ) ); } if (cacti_sizeof($data_sources) < cacti_sizeof($rrd_info)) { db_execute_prepared('INSERT INTO rrdcheck (local_data_id, test_date, message) VALUES (?, NOW(), ?)', array( $local_data_id, "There are less Data Sources in the database than in the RRDfile, please investigate. File '$file'." ) ); } $output = ''; $matches = array(); foreach ($rrd_info as $info_key => $info_array) { if (!isset($data_sources[$info_key])) { db_execute_prepared('INSERT INTO rrdcheck (local_data_id, test_date, message) VALUES (?, NOW(), ?)', array( $local_data_id, "The Data Source '$info_key' exists in RRDfile, but not in database. File '$file'." ) ); continue; } if ($info_array['minimal_heartbeat'] <= $poller_interval) { db_execute_prepared('INSERT INTO rrdcheck (local_data_id, test_date, message) VALUES (?, NOW(), ?)', array( $local_data_id, "The RRDfile Minimal Heart for Data Source '{$info_key}' is lower than polling interval. This will causes gaps in Graphs. File '$file.'" ) ); } if ($info_array['minimal_heartbeat'] < $rrdval['profile_heartbeat']) { db_execute_prepared('INSERT INTO rrdcheck (local_data_id, test_date, message) VALUES (?, NOW(), ?)', array( $local_data_id, "The RRDfile minimal heartbeat for Data Source '{$info_key}' should be '{$rrdval['profile_heartbeat']}' and is currently '{$info_array['minimal_heartbeat']}'. File '$file'." ) ); } } // test if ds in db == ds in rra foreach ($data_sources as $dsname) { if (!array_key_exists($dsname, $rrd_info)) { db_execute_prepared('INSERT INTO rrdcheck (local_data_id, test_date, message) VALUES (?, NOW(), ?)', array( $local_data_id, "Data Source name '$dsname' exists in the Database, but not in RRDfile. File '$file'." ) ); } // Should never happend if (empty($dsname)) { db_execute_prepared('INSERT INTO rrdcheck (local_data_id, test_date, message) VALUES (?, NOW(), ?)', array( $local_data_id, "Database Data Source name is empty for local data id '$local_data_id'. File '$file'." ) ); } } // test stale data $pstart = $start - $step; $pend = $end - $step; $one_hour_limit = ($duration - 3600) / $step; if ($use_proxy) { $info_array = rrdtool_execute("fetch $file LAST -s $pstart -e $pend ", false, RRDTOOL_OUTPUT_STDOUT, false, 'RRDCHECK'); } else { $info_array = rrdcheck_rrdtool_execute("fetch $file LAST -s $pstart -e $pend", $pipes); } /* don't do anything if RRDfile did not return data */ $info_array = explode("\n", $info_array); if (cacti_sizeof($info_array)) { $first = true; $lines_24 = 0; $lines_1 = 0; $nan_24 = array(); $nan_1 = array(); foreach ($info_array as $line) { $line = trim($line); // remove line - OK u:0.03 s:0.12 r:0.33 if (substr($line, 0, 2) == 'OK') { continue; } if ($line == '') { continue; } if ($first) { /* get the data source names */ $data_source_names = preg_split('/\s+/', $line); foreach ($data_source_names as $index => $name) { $nan_24[$index] = 0; $nan_1[$index] = 0; } $dsses += cacti_sizeof($data_source_names); $first = false; } else { $parts = explode(':', $line); $data = explode(' ', trim($parts[1])); foreach ($data as $index=>$number) { if ($index == 0) { // only onetime for each row $lines_24++; if ($lines_24 > $one_hour_limit) { // last hour $lines_1++; } } if (strtolower($number) == 'nan' || strtolower($number) == '-nan') { $nan_24[$index]++; if ($lines_24 > $one_hour_limit) { $nan_1[$index]++; } } } } } $notified = false; // 24 hour statistics foreach ($nan_24 as $index=>$count) { if ($lines_24 > 0) { $ratio = $count / $lines_24; } else { $ratio = 0; db_execute_prepared('INSERT INTO rrdcheck (local_data_id, test_date, message) VALUES (?,NOW(),?)', array( $local_data_id, "No data returned, maybe corrupted Data Source '{$data_source_names[$index]}'. File '$file'." ) ); } if ($ratio == 1) { db_execute_prepared('INSERT INTO rrdcheck (local_data_id, test_date, message) VALUES (?,NOW(),?)', array( $local_data_id, "Stale values for last 24 hours, Data Source '{$data_source_names[$index]}'. File '$file'." ) ); $notified = true; } elseif ($ratio > 0.5) { db_execute_prepared('INSERT INTO rrdcheck (local_data_id, test_date, message) VALUES (?,NOW(),?)', array( $local_data_id, "More than 50% ($count/$lines_24) values are NaN in last 24 hours, Data Source '{$data_source_names[$index]}'. File '$file'." ) ); } } // 1 hour statistics foreach ($nan_1 as $index=>$count) { if ($notified) { // 24hour notified, skipping continue; } if ($lines_1 > 0) { $ratio = $count / $lines_1; } else { $ratio = 0; db_execute_prepared('INSERT INTO rrdcheck (local_data_id, test_date, message) VALUES (?,NOW(),?)', array( $local_data_id, "No data returned, maybe corrupted Data Source '{$data_source_names[$index]}'. File '$file'." ) ); } if ($ratio == 1) { db_execute_prepared('INSERT INTO rrdcheck (local_data_id, test_date, message) VALUES (?,NOW(),?)', array( $local_data_id, "Stale values for last hour, Data Source '{$data_source_names[$index]}'. File '$file'." ) ); } elseif ($ratio > 0.5) { db_execute_prepared('INSERT INTO rrdcheck (local_data_id, test_date, message) VALUES (?,NOW(),?)', array( $local_data_id, "More than 50% ($count/$lines_1) values are NaN in last hour, Data Source '{$data_source_names[$index]}'. File '$file'." ) ); } } } else { cacti_log("WARNING: RRDcheck - no rrd data returned - '$file'", false, 'RRDCHECK'); } } else { // rrdfile does not exist db_execute_prepared('INSERT INTO rrdcheck (local_data_id, test_date, message) VALUES (?,NOW(),?)', array($local_data_id, "RRDfile does not exist - '$file'")); } } } if ($use_proxy) { rrd_close($rrdtool_pipe); } else { rrdcheck_rrdtool_close($process); } if (!empty($type)) { $total_user += $user_time; $total_system += $system_time; $total_real += $real_time; $total_dsses += $dsses; set_config_option('rrdcheck_rrd_system_' . $type . '_' . $thread_id, $total_system); set_config_option('rrdcheck_rrd_user_' . $type . '_' . $thread_id, $total_user); set_config_option('rrdcheck_rrd_real_' . $type . '_' . $thread_id, $total_real); set_config_option('rrdcheck_total_rrds_' . $type . '_' . $thread_id, $rrd_files); set_config_option('rrdcheck_total_dsses_' . $type . '_' . $thread_id, $total_dsses); } } /** * rrdcheck_log_statistics - provides generic timing message to both the Cacti log and the settings * table so that the statistcs can be graphed as well. * * @param $type - (string) the type of statistics to log, either 'HOURLY', 'BOOST'. * * @return - NULL */ function rrdcheck_log_statistics($type) { global $start; rrdcheck_debug($type); if ($type == 'BOOST') { $sub_type = 'bchild'; } else { $sub_type = ''; } /* take time and log performance data */ $end = microtime(true); if ($sub_type != '') { $rrd_user = db_fetch_cell_prepared('SELECT SUM(value) FROM settings WHERE name LIKE ?', array('rrdcheck_rrd_user_%' . $sub_type . '%')); $rrd_system = db_fetch_cell_prepared('SELECT SUM(value) FROM settings WHERE name LIKE ?', array('rrdcheck_rrd_system_%' . $sub_type . '%')); $rrd_real = db_fetch_cell_prepared('SELECT SUM(value) FROM settings WHERE name LIKE ?', array('rrdcheck_rrd_real_%' . $sub_type . '%')); $rrd_files = db_fetch_cell_prepared('SELECT SUM(value) FROM settings WHERE name LIKE ?', array('rrdcheck_total_rrds_%' . $sub_type . '%')); $dsses = db_fetch_cell_prepared('SELECT SUM(value) FROM settings WHERE name LIKE ?', array('rrdcheck_total_dsses_%' . $sub_type . '%')); $processes = read_config_option('rrdcheck_parallel'); $cacti_stats = sprintf('Time:%01.2f Type:%s Threads:%s RRDfiles:%s DSSes:%s RRDUser:%01.2f RRDSystem:%01.2f RRDReal:%01.2f', $end - $start, $type, $processes, $rrd_files, $dsses, $rrd_user, $rrd_system, $rrd_real); db_execute("DELETE FROM settings WHERE name LIKE 'rrdcheck_rrd_%$sub_type%' OR name LIKE 'rrdcheck_total_rrds_%$sub_type%' OR name LIKE 'rrdcheck_total_dsses_%$sub_type%'"); } else { $cacti_stats = sprintf('Time:%01.2f Type:%s', $end - $start, $type); } /* take time and log performance data */ $start = microtime(true); /* log to the database */ set_config_option('stats_rrdcheck_' . $type, $cacti_stats); /* log to the logfile */ cacti_log('RRDCHECK STATS: ' . $cacti_stats , true, 'SYSTEM'); } /** * rrdcheck_log_child_stats - logs rrdcheck child process information * * @param $type - (string) The type of child, MAJOR, DAILY, BOOST * @param $thread_id - (int) The parallel thread id * @param $total_time - (int) The total time to collect date * * @return - NULL */ function rrdcheck_log_child_stats($type, $thread_id, $total_time) { $rrd_user = db_fetch_cell_prepared('SELECT SUM(value) FROM settings WHERE name LIKE ?', array('rrdcheck_rrd_user_%' . $type . '_' . $thread_id . '%')); $rrd_system = db_fetch_cell_prepared('SELECT SUM(value) FROM settings WHERE name LIKE ?', array('rrdcheck_rrd_system_%' . $type . '_' . $thread_id . '%')); $rrd_real = db_fetch_cell_prepared('SELECT SUM(value) FROM settings WHERE name LIKE ?', array('rrdcheck_rrd_real_%' . $type . '_' . $thread_id . '%')); $rrd_files = db_fetch_cell_prepared('SELECT SUM(value) FROM settings WHERE name LIKE ?', array('rrdcheck_total_rrds_%' . $type . '_' . $thread_id . '%')); $dsses = db_fetch_cell_prepared('SELECT SUM(value) FROM settings WHERE name LIKE ?', array('rrdcheck_total_dsses_%' . $type . '_' . $thread_id . '%')); $cacti_stats = sprintf('Time:%01.2f Type:%s ProcessNumber:%s RRDfiles:%s DSSes:%s RRDUser:%01.2f RRDSystem:%01.2f RRDReal:%01.2f', $total_time, strtoupper($type), $thread_id, $rrd_files, $dsses, $rrd_user, $rrd_system, $rrd_real); cacti_log('RRDCHECK CHILD STATS: ' . $cacti_stats, true, 'SYSTEM'); } /** * rrdcheck_error_handler - this routine logs all PHP error transactions * to make sure they are properly logged. * * @param $errno - (int) The errornum reported by the system * @param $errmsg - (string) The error message provides by the error * @param $filename - (string) The filename that encountered the error * @param $linenum - (int) The line number where the error occurred * @param $vars - (mixed) The current state of PHP variables. * * @returns - (bool) always returns true for some reason */ function rrdcheck_error_handler($errno, $errmsg, $filename, $linenum, $vars = array()) { if (read_config_option('log_verbosity') >= POLLER_VERBOSITY_DEBUG) { /* define all error types */ $errortype = array( E_ERROR => 'Error', E_WARNING => 'Warning', E_PARSE => 'Parsing Error', E_NOTICE => 'Notice', E_CORE_ERROR => 'Core Error', E_CORE_WARNING => 'Core Warning', E_COMPILE_ERROR => 'Compile Error', E_COMPILE_WARNING => 'Compile Warning', E_USER_ERROR => 'User Error', E_USER_WARNING => 'User Warning', E_USER_NOTICE => 'User Notice', E_STRICT => 'Runtime Notice' ); if (defined('E_RECOVERABLE_ERROR')) { $errortype[E_RECOVERABLE_ERROR] = 'Catchable Fatal Error'; } /* create an error string for the log */ $err = "ERRNO:'" . $errno . "' TYPE:'" . $errortype[$errno] . "' MESSAGE:'" . $errmsg . "' IN FILE:'" . $filename . "' LINE NO:'" . $linenum . "'"; /* let's ignore some lesser issues */ if (substr_count($errmsg, 'date_default_timezone')) { return; } if (substr_count($errmsg, 'Only variables')) { return; } /* log the error to the Cacti log */ cacti_log('PROGERR: ' . $err, false, 'RRDCHECK'); } return; } /** * rrdcheck_boost_bottom - this routine accomodates rrdcheck after the boost process * has completed. The use of boost will require boost version 2.5 or above. The idea * if that rrdcheck will be started on the boost cycle. * * @return - NULL */ function rrdcheck_boost_bottom() { global $config; if (read_config_option('rrdcheck_enable') == 'on') { include_once(CACTI_PATH_LIBRARY . '/rrd.php'); /* run the daily stats. log to database to prevent secondary runs */ set_config_option('rrdcheck_last_run_time', time()); /* run the daily stats */ rrdcheck_launch_children('bmaster'); /* Wait for all processes to continue */ while ($running = rrdcheck_processes_running('bmaster')) { rrdcheck_debug(sprintf('%s Processes Running, Sleeping for 2 seconds.', $running)); sleep(2); } rrdcheck_log_statistics('BOOST'); } } /** * rrdcheck_poller_bottom - this routine launches the main rrdcheck poller. * It is forked independently * to the Cacti poller after all polling has finished. * * @return - NULL */ function rrdcheck_poller_bottom() { global $config; if (read_config_option('rrdcheck_enable') == 'on') { include_once(CACTI_PATH_LIBRARY . '/poller.php'); chdir(CACTI_PATH_BASE); $command_string = read_config_option('path_php_binary'); if (read_config_option('path_rrdcheck_log') != '') { if ($config['cacti_server_os'] == 'unix') { $extra_args = '-q ' . CACTI_PATH_BASE . '/poller_rrdcheck.php >> ' . read_config_option('path_rrdcheck_log') . ' 2>&1'; } else { $extra_args = '-q ' . CACTI_PATH_BASE . '/poller_rrdcheck.php >> ' . read_config_option('path_rrdcheck_log'); } } else { $extra_args = '-q ' . CACTI_PATH_BASE . '/poller_rrdcheck.php'; } exec_background($command_string, $extra_args); } } /** * rrdcheck_rrdtool_init - this routine provides a bi-directional socket based connection to RRDtool. * it provides a high speed connection to rrdfile in the case where the traditional Cacti call does * not when performing fetch type calls. * * @return - (mixed) An array that includes both the process resource and the pipes to communicate * with RRDtool. */ function rrdcheck_rrdtool_init() { global $config; if ($config['cacti_server_os'] == 'unix') { $fds = array( 0 => array('pipe', 'r'), // stdin 1 => array('pipe', 'w'), // stdout 2 => array('file', '/dev/null', 'a') // stderr ); } else { $fds = array( 0 => array('pipe', 'r'), // stdin 1 => array('pipe', 'w'), // stdout 2 => array('file', 'nul', 'a') // stderr ); } /* set the rrdtool default font */ if (read_config_option('path_rrdtool_default_font')) { putenv('RRD_DEFAULT_FONT=' . read_config_option('path_rrdtool_default_font')); } $command = read_config_option('path_rrdtool') . ' - '; $process = proc_open($command, $fds, $pipes); /* make stdin/stdout/stderr non-blocking */ stream_set_blocking($pipes[0], 0); stream_set_blocking($pipes[1], 0); return array($process, $pipes); } /** * rrdcheck_rrdtool_execute - this routine passes commands to RRDtool and returns the information * back to rrdcheck. It is important to note here that RRDtool needs to provide an either 'OK' * or 'ERROR' response accross the pipe as it does not provide EOF characters to key upon. * This may not be the best method and may be changed after I have a conversation with a few * developers. * * @param $command - (string) The rrdtool command to execute * @param $pipes - (array) An array of stdin and stdout pipes to read and write data from * * @returns - (string) The output from RRDtool */ function rrdcheck_rrdtool_execute($command, &$pipes) { static $broken = false; $stdout = ''; if ($command == '') { return; } $command .= "\r\n"; $return_code = fwrite($pipes[0], $command); if (is_resource($pipes[1])) { while (!feof($pipes[1])) { $stdout .= fgets($pipes[1], 4096); if (substr_count($stdout, 'OK')) { break; } if (substr_count($stdout, 'ERROR')) { break; } } } elseif (!$broken) { cacti_log('ERROR: RRDtool was unable to fork. Likely RRDtool can not be found or system out of resources. Blocking subsequent messages.', false, 'POLLER'); $broken = true; } if (strlen($stdout)) { return $stdout; } } /** * rrdcheck_rrdtool_close - this routine closes the RRDtool process thus also * closing the pipes. * * @return - NULL * @param mixed $process */ function rrdcheck_rrdtool_close($process) { proc_close($process); } /** * rrdcheck_launch_children - this function will launch collector children based upon * the maximum number of threads and the process type * * @param $type - (string) The process type * * @return - NULL */ function rrdcheck_launch_children($type) { global $config, $debug; $processes = read_config_option('rrdcheck_parallel'); if (empty($processes)) { $processes = 1; } $php_binary = read_config_option('path_php_binary'); rrdcheck_debug("About to launch $processes processes."); $sub_type = rrdcheck_get_subtype($type); for ($i = 1; $i <= $processes; $i++) { rrdcheck_debug(sprintf('Launching rrdcheck Process Number %s for Type %s', $i, $type)); cacti_log(sprintf('NOTE: Launching rrdcheck Process Number %s for Type %s', $i, $type), false, 'BOOST', POLLER_VERBOSITY_MEDIUM); exec_background($php_binary, CACTI_PATH_BASE . "/poller_rrdcheck.php --type=$sub_type --child=$i" . ($debug ? ' --debug':'')); } sleep(2); } /** * rrdcheck_get_subtype - this function determine the applicable * sub-type (child name) and return if based upon a type * * @param $type - (string) The process type * * @return - (string) The sub type */ function rrdcheck_get_subtype($type) { switch($type) { case 'master': case 'pmaster': return 'child'; break; case 'bmaster': return 'bchild'; break; } } /** * rrdcheck_kill_running_processes - this function is part of an interrupt * handler to kill children processes when the parent is killed * * @return - NULL */ function rrdcheck_kill_running_processes() { global $type; if ($type == 'bmaster') { $processes = db_fetch_assoc_prepared('SELECT * FROM processes WHERE tasktype = "rrdcheck" AND taskname = "bchild" AND pid != ?', array(getmypid())); } else { $processes = db_fetch_assoc_prepared('SELECT * FROM processes WHERE tasktype = "rrdcheck" AND taskname = "child" AND pid != ?', array(getmypid())); } if (cacti_sizeof($processes)) { foreach ($processes as $p) { cacti_log(sprintf('WARNING: Killing rrdcheck %s PID %d due to another due to signal or overrun.', ucfirst($p['taskname']), $p['pid']), false, 'BOOST'); posix_kill($p['pid'], SIGTERM); unregister_process($p['tasktype'], $p['taskname'], $p['taskid'], $p['pid']); } } } /** * rrdcheck_processes_running - given a type, determine the number * of sub-type or children that are currently running * * @param $type - (string) The process type * * @return - (int) The number of running processes */ function rrdcheck_processes_running($type) { $sub_type = rrdcheck_get_subtype($type); $running = db_fetch_cell_prepared('SELECT COUNT(*) FROM processes WHERE tasktype = "rrdcheck" AND taskname = ?', array($sub_type)); if ($running == 0) { return 0; } return $running; }