Security fix: unauthorized access (#10091)

* Security fix: unauthorized access
Affects nginx users:
Moved php files outside of public html directory (Apache was protected by .htaccess)

Affects all users:
Some files did not check for authentication and could disclose some info.
Better checks before including files from user input

* git mv html/includes/ includes/html
git mv html/pages/ includes/html/
This commit is contained in:
Tony Murray
2019-04-11 23:26:42 -05:00
committed by GitHub
parent b81af32ed2
commit 36431dd296
1301 changed files with 1443 additions and 1439 deletions

View File

@@ -0,0 +1,129 @@
<?php
/**
* CollectdColor.php
*
* Color functions class for Collectd
*
* 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, either version 3 of the License, or
* (at your option) any later version.
*
* 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, see <http://www.gnu.org/licenses/>.
*
* @package LibreNMS
* @link http://librenms.org
*/
namespace LibreNMS;
class CollectdColor
{
private $r = 0;
private $g = 0;
private $b = 0;
public function __construct($value = null)
{
if (is_null($value)) {
} else {
if (is_array($value)) {
if (isset($value['r'])) {
$this->r = $value['r'] > 0 ? ($value['r'] > 1 ? 1 : $value['r']) : 0;
}
if (isset($value['g'])) {
$this->g = $value['g'] > 0 ? ($value['g'] > 1 ? 1 : $value['g']) : 0;
}
if (isset($value['b'])) {
$this->b = $value['b'] > 0 ? ($value['b'] > 1 ? 1 : $value['b']) : 0;
}
} else {
if (is_string($value)) {
$matches = array();
if ($value == 'random') {
$this->randomize();
} else {
if (preg_match(
'/([0-9A-Fa-f][0-9A-Fa-f])([0-9A-Fa-f][0-9A-Fa-f])([0-9A-Fa-f][0-9A-Fa-f])/',
$value,
$matches
)) {
$this->r = (hexdec('0x' . $matches[1]) / 255.0);
$this->g = (hexdec('0x' . $matches[2]) / 255.0);
$this->b = (hexdec('0x' . $matches[3]) / 255.0);
}
}
} else {
if (is_a($value, 'CollectdColor') ||
is_a($value, 'LibreNMS\CollectdColor')) {
$this->r = $value->r;
$this->g = $value->g;
$this->b = $value->b;
}
}
}
}//end if
}//end __construct()
public function randomize()
{
$this->r = (rand(0, 255) / 255.0);
$this->g = (rand(0, 255) / 255.0);
$this->b = 0.0;
$min = 0.0;
$max = 1.0;
if (($this->r + $this->g) < 1.0) {
$min = (1.0 - ($this->r + $this->g));
} else {
$max = (2.0 - ($this->r + $this->g));
}
$this->b = ($min + ((rand(0, 255) / 255.0) * ($max - $min)));
}//end randomize()
public function fade($bkgnd = null, $alpha = 0.25)
{
if (is_null($bkgnd) || !is_a($bkgnd, 'CollectdColor')) {
$bg_r = 1.0;
$bg_g = 1.0;
$bg_b = 1.0;
} else {
$bg_r = $bkgnd->r;
$bg_g = $bkgnd->g;
$bg_b = $bkgnd->b;
}
$this->r = ($alpha * $this->r + ((1.0 - $alpha) * $bg_r));
$this->g = ($alpha * $this->g + ((1.0 - $alpha) * $bg_g));
$this->b = ($alpha * $this->b + ((1.0 - $alpha) * $bg_b));
}//end fade()
public function toArray()
{
return array(
'r' => $this->r,
'g' => $this->g,
'b' => $this->b,
);
}//end as_array()
public function toString()
{
$r = (int)($this->r * 255);
$g = (int)($this->g * 255);
$b = (int)($this->b * 255);
return sprintf('%02x%02x%02x', $r > 255 ? 255 : $r, $g > 255 ? 255 : $g, $b > 255 ? 255 : $b);
}
}

View File

@@ -0,0 +1,101 @@
<?php
/**
* Configuration file for Collectd graph browser
*/
if (isset($config['rrdgraph_def_text'])) {
$config['rrdgraph_def_text'] = str_replace(' ', ' ', $config['rrdgraph_def_text']);
$config['rrd_opts_array'] = explode(' ', trim($config['rrdgraph_def_text']));
}
// Array of paths when collectd's rrdtool plugin writes RRDs
$config['datadirs'] = array($config['collectd_dir']);
// Width of graph to be generated by rrdgraph
if (isset($_GET['width'])) {
$config['rrd_width'] = $_GET['width'];
} else {
$config['rrd_width'] = 270;
}
// Height of graph to be generated by rrdgraph
if (isset($_GET['height'])) {
$config['rrd_height'] = $_GET['height'];
} else {
$config['rrd_height'] = 120;
}
// List of supported timespans (used for period drop-down list)
$config['timespan'] = array(
array(
'name' => 'hour',
'label' => 'past hour',
'seconds' => 3600,
),
array(
'name' => 'day',
'label' => 'past day',
'seconds' => 86400,
),
array(
'name' => 'week',
'label' => 'past week',
'seconds' => 604800,
),
array(
'name' => 'month',
'label' => 'past month',
'seconds' => 2678400,
),
array(
'name' => 'year',
'label' => 'past year',
'seconds' => 31622400,
),
);
// Interval at which values are collectd (currently ignored)
$config['rrd_interval'] = 10;
// Average rows/rra (currently ignored)
$config['rrd_rows'] = 2400;
// Additional options to pass to rrdgraph
// $config['rrd_opts'] = (isset($config['rrdgraph_defaults']) ? $config['rrdgraph_defaults'] : '');
// $config['rrd_opts'] = array('-E', "-c", "SHADEA#a5a5a5", "-c", "SHADEB#a5a5a5", "-c", "FONT#000000", "-c", "CANVAS#FFFFFF", "-c", "GRID#aaaaaa",
// "-c", "MGRID#FFAAAA", "-c", "FRAME#3e3e3e", "-c", "ARROW#5e5e5e", "-R", "normal");
// Predefined set of colors for use by collectd_draw_rrd()
$config['rrd_colors'] = array(
'h_1' => 'F7B7B7',
'f_1' => 'FF0000', // Red
'h_2' => 'B7EFB7',
'f_2' => '00E000', // Green
'h_3' => 'B7B7F7',
'f_3' => '0000FF', // Blue
'h_4' => 'F3DFB7',
'f_4' => 'F0A000', // Yellow
'h_5' => 'B7DFF7',
'f_5' => '00A0FF', // Cyan
'h_6' => 'DFB7F7',
'f_6' => 'A000FF', // Magenta
'h_7' => 'FFC782',
'f_7' => 'FF8C00', // Orange
'h_8' => 'DCFF96',
'f_8' => 'AAFF00', // Lime
'h_9' => '83FFCD',
'f_9' => '00FF99',
'h_10' => '81D9FF',
'f_10' => '00B2FF',
'h_11' => 'FF89F5',
'f_11' => 'FF00EA',
'h_12' => 'FF89AE',
'f_12' => 'FF0051',
'h_13' => 'BBBBBB',
'f_13' => '555555',
);
/*
* Path to TTF font file to use in error images
* (fallback when file does not exist is GD fixed font)
*/
$config['error_font'] = '/usr/share/fonts/corefonts/arial.ttf';
/*
* Constant defining full path to rrdtool
*/
define('RRDTOOL', $config['rrdtool']);

View File

@@ -0,0 +1,82 @@
<?php // vim:fenc=utf-8:filetype=php:ts=4
/*
* Copyright (C) 2009 Bruno Prémont <bonbons AT linux-vserver.org>
*
* 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; only version 2 of the License is applicable.
*
* 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.
*/
function load_graph_definitions_local($logarithmic = false, $tinylegend = false)
{
global $GraphDefs, $MetaGraphDefs;
// Define 1-rrd Graph definitions here
$GraphDefs['local_type'] = array(
'-v', 'Commits',
'DEF:avg={file}:value:AVERAGE',
'DEF:min={file}:value:MIN',
'DEF:max={file}:value:MAX',
"AREA:max#B7B7F7",
"AREA:min#FFFFFF",
"LINE1:avg#0000FF:Commits",
'GPRINT:min:MIN:%6.1lf Min,',
'GPRINT:avg:AVERAGE:%6.1lf Avg,',
'GPRINT:max:MAX:%6.1lf Max,',
'GPRINT:avg:LAST:%6.1lf Last\l');
// Define MetaGraph definition type -> function mappings here
$MetaGraphDefs['local_meta'] = 'meta_graph_local';
}
function meta_graph_local($host, $plugin, $plugin_instance, $type, $type_instances, $opts = array())
{
global $config;
$sources = array();
$title = "$host/$plugin".(!is_null($plugin_instance) ? "-$plugin_instance" : '')."/$type";
if (!isset($opts['title'])) {
$opts['title'] = $title;
}
$opts['rrd_opts'] = array('-v', 'Events');
$files = array();
/* $opts['colors'] = array(
'ham' => '00e000',
'spam' => '0000ff',
'malware' => '990000',
'sent' => '00e000',
'deferred' => 'a0e000',
'reject' => 'ff0000',
'bounced' => 'a00050'
);
$type_instances = array('ham', 'spam', 'malware', 'sent', 'deferred', 'reject', 'bounced'); */
foreach ($type_instances as $inst) {
$file = '';
foreach ($config['datadirs'] as $datadir) {
if (is_file($datadir.'/'.$title.'-'.$inst.'.rrd')) {
$file = $datadir.'/'.$title.'-'.$inst.'.rrd';
break;
}
}
if ($file == '') {
continue;
}
$sources[] = array('name'=>$inst, 'file'=>$file);
}
// return collectd_draw_meta_stack($opts, $sources);
return collectd_draw_meta_line($opts, $sources);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,972 @@
<?php
/*
* Copyright (C) 2009 Bruno Prémont <bonbons AT linux-vserver.org>
*
* 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; only version 2 of the License is applicable.
*
* 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.
*/
require 'includes/html/collectd/CollectdColor.php';
use LibreNMS\CollectdColor;
define('REGEXP_HOST', '/^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/');
define('REGEXP_PLUGIN', '/^[a-zA-Z0-9_.-]+$/');
/*
* Read input variable from GET, POST or COOKIE taking
* care of magic quotes
*
* @param string $name Name of value to return
* @param array $array User-input array ($_GET, $_POST or $_COOKIE)
* @param string $default Default value
* @return string $default if name in unknown in $array, otherwise
* input value with magic quotes stripped off
*/
function read_var($name, &$array, $default = null)
{
if (isset($array[$name])) {
if (is_array($array[$name])) {
if (get_magic_quotes_gpc()) {
$ret = array();
while (list($k, $v) = each($array[$name])) {
$ret[stripslashes($k)] = stripslashes($v);
}
return $ret;
} else {
return $array[$name];
}
} elseif (is_string($array[$name]) && get_magic_quotes_gpc()) {
return stripslashes($array[$name]);
} else {
return $array[$name];
}
} else {
return $default;
}
}//end read_var()
/*
* Alphabetically compare host names, comparing label
* from tld to node name
*/
function collectd_compare_host($a, $b)
{
$ea = explode('.', $a);
$eb = explode('.', $b);
$i = (count($ea) - 1);
$j = (count($eb) - 1);
while ($i >= 0 && $j >= 0) {
if (($r = strcmp($ea[$i--], $eb[$j--])) != 0) {
return $r;
}
}
return 0;
}//end collectd_compare_host()
/**
* Fetch list of hosts found in collectd's datadirs.
* @return array Sorted list of hosts (sorted by label from rigth to left)
*/
function collectd_list_hosts()
{
global $config;
$hosts = array();
foreach ($config['datadirs'] as $datadir) {
if ($d = @opendir($datadir)) {
while (($dent = readdir($d)) !== false) {
if ($dent != '.' && $dent != '..' && is_dir($datadir.'/'.$dent) && preg_match(REGEXP_HOST, $dent)) {
$hosts[] = $dent;
}
}
closedir($d);
} else {
error_log('Failed to open datadir: '.$datadir);
}
}
$hosts = array_unique($hosts);
usort($hosts, 'collectd_compare_host');
return $hosts;
}
/**
* Fetch list of plugins found in collectd's datadirs for given host.
*
* @param string $arg_host Name of host for which to return plugins
* @return array Sorted list of plugins (sorted alphabetically)
*/
function collectd_list_plugins($arg_host)
{
global $config;
$plugins = array();
foreach ($config['datadirs'] as $datadir) {
if (preg_match(REGEXP_HOST, $arg_host) && ($d = @opendir($datadir.'/'.$arg_host))) {
while (($dent = readdir($d)) !== false) {
if ($dent != '.' && $dent != '..' && is_dir($datadir.'/'.$arg_host.'/'.$dent)) {
if ($i = strpos($dent, '-')) {
$plugins[] = substr($dent, 0, $i);
} else {
$plugins[] = $dent;
}
}
}
closedir($d);
}
}
$plugins = array_unique($plugins);
sort($plugins);
return $plugins;
}//end collectd_list_plugins()
/**
* Fetch list of plugin instances found in collectd's datadirs for given host+plugin
*
* @param string $arg_host Name of host
* @param string $arg_plugin Name of plugin
* @return array Sorted list of plugin instances (sorted alphabetically)
*/
function collectd_list_pinsts($arg_host, $arg_plugin)
{
global $config;
$pinsts = array();
foreach ($config['datadirs'] as $datadir) {
if (preg_match(REGEXP_HOST, $arg_host) && ($d = opendir($datadir.'/'.$arg_host))) {
while (($dent = readdir($d)) !== false) {
if ($dent != '.' && $dent != '..' && is_dir($datadir.'/'.$arg_host.'/'.$dent)) {
if ($i = strpos($dent, '-')) {
$plugin = substr($dent, 0, $i);
$pinst = substr($dent, ($i + 1));
} else {
$plugin = $dent;
$pinst = '';
}
if ($plugin == $arg_plugin) {
$pinsts[] = $pinst;
}
}
}
closedir($d);
}
}//end foreach
$pinsts = array_unique($pinsts);
sort($pinsts);
return $pinsts;
}//end collectd_list_pinsts()
/**
* Fetch list of types found in collectd's datadirs for given host+plugin+instance
* @arg_host Name of host
* @arg_plugin Name of plugin
* @arg_pinst Plugin instance
* @return array Sorted list of types (sorted alphabetically)
*/
function collectd_list_types($arg_host, $arg_plugin, $arg_pinst)
{
global $config;
$types = array();
$my_plugin = $arg_plugin.(strlen($arg_pinst) ? '-'.$arg_pinst : '');
if (!preg_match(REGEXP_PLUGIN, $my_plugin)) {
return $types;
}
foreach ($config['datadirs'] as $datadir) {
if (preg_match(REGEXP_HOST, $arg_host) && ($d = @opendir($datadir.'/'.$arg_host.'/'.$my_plugin))) {
while (($dent = readdir($d)) !== false) {
if ($dent != '.' && $dent != '..' && is_file($datadir.'/'.$arg_host.'/'.$my_plugin.'/'.$dent) && substr($dent, (strlen($dent) - 4)) == '.rrd') {
$dent = substr($dent, 0, (strlen($dent) - 4));
if ($i = strpos($dent, '-')) {
$types[] = substr($dent, 0, $i);
} else {
$types[] = $dent;
}
}
}
closedir($d);
}
}
$types = array_unique($types);
sort($types);
return $types;
}//end collectd_list_types()
/**
* Fetch list of type instances found in collectd's datadirs for given host+plugin+instance+type
* @arg_host Name of host
* @arg_plugin Name of plugin
* @arg_pinst Plugin instance
* @arg_type Type
* @return array Sorted list of type instances (sorted alphabetically)
*/
function collectd_list_tinsts($arg_host, $arg_plugin, $arg_pinst, $arg_type)
{
global $config;
$tinsts = array();
$my_plugin = $arg_plugin.(strlen($arg_pinst) ? '-'.$arg_pinst : '');
if (!preg_match(REGEXP_PLUGIN, $my_plugin)) {
return $tinsts;
}
foreach ($config['datadirs'] as $datadir) {
if (preg_match(REGEXP_HOST, $arg_host) && ($d = @opendir($datadir.'/'.$arg_host.'/'.$my_plugin))) {
while (($dent = readdir($d)) !== false) {
if ($dent != '.' && $dent != '..' && is_file($datadir.'/'.$arg_host.'/'.$my_plugin.'/'.$dent) && substr($dent, (strlen($dent) - 4)) == '.rrd') {
$dent = substr($dent, 0, (strlen($dent) - 4));
if ($i = strpos($dent, '-')) {
$type = substr($dent, 0, $i);
$tinst = substr($dent, ($i + 1));
} else {
$type = $dent;
$tinst = '';
}
if ($type == $arg_type) {
$tinsts[] = $tinst;
}
}
}
closedir($d);
}
}//end foreach
$tinsts = array_unique($tinsts);
sort($tinsts);
return $tinsts;
}//end collectd_list_tinsts()
/**
* Parse symlinks in order to get an identifier that collectd understands
* (e.g. virtualisation is collected on host for individual VMs and can be
* symlinked to the VM's hostname, support FLUSH for these by flushing
* on the host-identifier instead of VM-identifier)
*
* @param string $host Hostname
* @param string $plugin Plugin name
* @param string $type
* @param string $pinst Plugin instance
* @param string $tinst Type instance
* @return string Identifier that collectd's FLUSH command understands
*/
function collectd_identifier($host, $plugin, $type, $pinst, $tinst)
{
global $config;
$rrd_realpath = null;
$orig_identifier = sprintf('%s/%s%s%s/%s%s%s', $host, $plugin, strlen($pinst) ? '-' : '', $pinst, $type, strlen($tinst) ? '-' : '', $tinst);
$identifier = null;
foreach ($config['datadirs'] as $datadir) {
if (is_file($datadir.'/'.$orig_identifier.'.rrd')) {
$rrd_realpath = realpath($datadir.'/'.$orig_identifier.'.rrd');
break;
}
}
if ($rrd_realpath) {
$identifier = basename($rrd_realpath);
$identifier = substr($identifier, 0, (strlen($identifier) - 4));
$rrd_realpath = dirname($rrd_realpath);
$identifier = basename($rrd_realpath).'/'.$identifier;
$rrd_realpath = dirname($rrd_realpath);
$identifier = basename($rrd_realpath).'/'.$identifier;
}
if (is_null($identifier)) {
return $orig_identifier;
} else {
return $identifier;
}
}//end collectd_identifier()
/**
* Tell collectd that it should FLUSH all data it has regarding the
* graph we are about to generate.
*
* @param string $identifier
* @return bool
*/
function collectd_flush($identifier)
{
global $config;
if (!$config['collectd_sock']) {
return false;
}
if (is_null($identifier) || (is_array($identifier) && count($identifier) == 0) || !(is_string($identifier) || is_array($identifier))) {
return false;
}
$u_errno = 0;
$u_errmsg = '';
if ($socket = @fsockopen($config['collectd_sock'], 0, $u_errno, $u_errmsg)) {
$cmd = 'FLUSH plugin=rrdtool';
if (is_array($identifier)) {
foreach ($identifier as $val) {
$cmd .= sprintf(' identifier="%s"', $val);
}
} else {
$cmd .= sprintf(' identifier="%s"', $identifier);
}
$cmd .= "\n";
$r = fwrite($socket, $cmd, strlen($cmd));
if ($r === false || $r != strlen($cmd)) {
error_log(sprintf('graph.php: Failed to write whole command to unix-socket: %d out of %d written', $r === false ? (-1) : $r, strlen($cmd)));
}
$resp = fgets($socket);
if ($resp === false) {
error_log(sprintf('graph.php: Failed to read response from collectd for command: %s', trim($cmd)));
}
$n = (int) $resp;
while ($n-- > 0) {
fgets($socket);
}
fclose($socket);
} //end if
else {
error_log(sprintf('graph.php: Failed to open unix-socket to collectd: %d: %s', $u_errno, $u_errmsg));
}
return true;
}//end collectd_flush()
/**
* Helper function to strip quotes from RRD output
*
* @param string $str RRD-Info generated string
* @return string String with one surrounding pair of quotes stripped
*/
function rrd_strip_quotes($str)
{
if ($str[0] == '"' && $str[(strlen($str) - 1)] == '"') {
return substr($str, 1, (strlen($str) - 2));
} else {
return $str;
}
}//end rrd_strip_quotes()
/**
* Determine useful information about RRD file
*
* @param string $file Name of RRD file to analyse
* @return array Array describing the RRD file
*/
function _rrd_info($file)
{
$info = array('filename' => $file);
$rrd = popen(RRDTOOL.' info '.escapeshellarg($file), 'r');
if ($rrd) {
while (($s = fgets($rrd)) !== false) {
$p = strpos($s, '=');
if ($p === false) {
continue;
}
$key = trim(substr($s, 0, $p));
$value = trim(substr($s, ($p + 1)));
if (strncmp($key, 'ds[', 3) == 0) {
// DS definition
$p = strpos($key, ']');
$ds = substr($key, 3, ($p - 3));
if (!isset($info['DS'])) {
$info['DS'] = array();
}
$ds_key = substr($key, ($p + 2));
if (strpos($ds_key, '[') === false) {
if (!isset($info['DS']["$ds"])) {
$info['DS']["$ds"] = array();
}
$info['DS']["$ds"]["$ds_key"] = rrd_strip_quotes($value);
}
} elseif (strncmp($key, 'rra[', 4) == 0) {
// RRD definition
$p = strpos($key, ']');
$rra = substr($key, 4, ($p - 4));
if (!isset($info['RRA'])) {
$info['RRA'] = array();
}
$rra_key = substr($key, ($p + 2));
if (strpos($rra_key, '[') === false) {
if (!isset($info['RRA']["$rra"])) {
$info['RRA']["$rra"] = array();
}
$info['RRA']["$rra"]["$rra_key"] = rrd_strip_quotes($value);
}
} elseif (strpos($key, '[') === false) {
$info[$key] = rrd_strip_quotes($value);
}//end if
}//end while
pclose($rrd);
}//end if
return $info;
}//end _rrd_info()
function rrd_get_color($code, $line = true)
{
global $config;
$name = ($line ? 'f_' : 'h_').$code;
if (!isset($config['rrd_colors'][$name])) {
$c_f = new CollectdColor('random');
$c_h = new CollectdColor($c_f);
$c_h->fade();
$config['rrd_colors']['f_'.$code] = $c_f->toString();
$config['rrd_colors']['h_'.$code] = $c_h->toString();
}
return $config['rrd_colors'][$name];
}//end rrd_get_color()
/**
* Draw RRD file based on it's structure
*
* @param $host
* @param $plugin
* @param $type
* @param null $pinst
* @param null $tinst
* @param array $opts
* @return string|false Commandline to call RRDGraph in order to generate the final graph* @internal param $
*/
function collectd_draw_rrd($host, $plugin, $type, $pinst = null, $tinst = null, $opts = array())
{
global $config;
$timespan_def = null;
if (!isset($opts['timespan'])) {
$timespan_def = reset($config['timespan']);
} else {
foreach ($config['timespan'] as &$ts) {
if ($ts['name'] == $opts['timespan']) {
$timespan_def = $ts;
}
}
}
if (!isset($opts['rrd_opts'])) {
$opts['rrd_opts'] = array();
}
if (isset($opts['logarithmic']) && $opts['logarithmic']) {
array_unshift($opts['rrd_opts'], '-o');
}
$rrdinfo = null;
$rrdfile = sprintf('%s/%s%s%s/%s%s%s', $host, $plugin, is_null($pinst) ? '' : '-', $pinst, $type, is_null($tinst) ? '' : '-', $tinst);
foreach ($config['datadirs'] as $datadir) {
if (is_file($datadir.'/'.$rrdfile.'.rrd')) {
$rrdinfo = _rrd_info($datadir.'/'.$rrdfile.'.rrd');
if (isset($rrdinfo['RRA']) && is_array($rrdinfo['RRA'])) {
break;
} else {
$rrdinfo = null;
}
}
}
if (is_null($rrdinfo)) {
return false;
}
$graph = array();
$has_avg = false;
$has_max = false;
$has_min = false;
reset($rrdinfo['RRA']);
$l_max = 0;
while (list($k, $v) = each($rrdinfo['RRA'])) {
if ($v['cf'] == 'MAX') {
$has_max = true;
} elseif ($v['cf'] == 'AVERAGE') {
$has_avg = true;
} elseif ($v['cf'] == 'MIN') {
$has_min = true;
}
}
// Build legend. This may not work for all RRDs, i don't know :)
if ($has_avg) {
$graph[] = 'COMMENT: Last';
}
if ($has_min) {
$graph[] = 'COMMENT: Min';
}
if ($has_max) {
$graph[] = 'COMMENT: Max';
}
if ($has_avg) {
$graph[] = "COMMENT: Avg\\n";
}
reset($rrdinfo['DS']);
while (list($k, $v) = each($rrdinfo['DS'])) {
if (strlen($k) > $l_max) {
$l_max = strlen($k);
}
if ($has_min) {
$graph[] = sprintf('DEF:%s_min=%s:%s:MIN', $k, $rrdinfo['filename'], $k);
}
if ($has_avg) {
$graph[] = sprintf('DEF:%s_avg=%s:%s:AVERAGE', $k, $rrdinfo['filename'], $k);
}
if ($has_max) {
$graph[] = sprintf('DEF:%s_max=%s:%s:MAX', $k, $rrdinfo['filename'], $k);
}
}
if ($has_min && $has_max || $has_min && $has_avg || $has_avg && $has_max) {
$n = 1;
reset($rrdinfo['DS']);
while (list($k, $v) = each($rrdinfo['DS'])) {
$graph[] = sprintf('LINE:%s_%s', $k, $has_min ? 'min' : 'avg');
$graph[] = sprintf('CDEF:%s_var=%s_%s,%s_%s,-', $k, $k, $has_max ? 'max' : 'avg', $k, $has_min ? 'min' : 'avg');
$graph[] = sprintf('AREA:%s_var#%s::STACK', $k, rrd_get_color($n++, false));
}
}
reset($rrdinfo['DS']);
$n = 1;
while (list($k, $v) = each($rrdinfo['DS'])) {
$graph[] = sprintf('LINE1:%s_avg#%s:%s ', $k, rrd_get_color($n++, true), $k.substr(' ', 0, ($l_max - strlen($k))));
if (isset($opts['tinylegend']) && $opts['tinylegend']) {
continue;
}
if ($has_avg) {
$graph[] = sprintf('GPRINT:%s_avg:AVERAGE:%%5.1lf%%s', $k, $has_max || $has_min || $has_avg ? ',' : '\\l');
}
if ($has_min) {
$graph[] = sprintf('GPRINT:%s_min:MIN:%%5.1lf%%s', $k, $has_max || $has_avg ? ',' : '\\l');
}
if ($has_max) {
$graph[] = sprintf('GPRINT:%s_max:MAX:%%5.1lf%%s', $k, $has_avg ? ',' : '\\l');
}
if ($has_avg) {
$graph[] = sprintf('GPRINT:%s_avg:LAST:%%5.1lf%%s\\l', $k);
}
}//end while
// $rrd_cmd = array(RRDTOOL, 'graph', '-', '-E', '-a', 'PNG', '-w', $config['rrd_width'], '-h', $config['rrd_height'], '-t', $rrdfile);
$rrd_cmd = array(
RRDTOOL,
'graph',
'-',
'-E',
'-a',
'PNG',
'-w',
$config['rrd_width'],
'-h',
$config['rrd_height'],
);
if ($config['rrd_width'] <= '300') {
$small_opts = array(
'--font',
'LEGEND:7:mono',
'--font',
'AXIS:6:mono',
'--font-render-mode',
'normal',
);
$rrd_cmd = array_merge($rrd_cmd, $small_opts);
}
$rrd_cmd = array_merge($rrd_cmd, $config['rrd_opts_array'], $opts['rrd_opts'], $graph);
$cmd = RRDTOOL;
$count_rrd_cmd = count($rrd_cmd);
for ($i = 1; $i < $count_rrd_cmd; $i++) {
$cmd .= ' '.escapeshellarg($rrd_cmd[$i]);
}
return $cmd;
}//end collectd_draw_rrd()
/**
* Draw RRD file based on it's structure
*
* @param $timespan
* @param $host
* @param $plugin
* @param $type
* @param null $pinst
* @param null $tinst
* @return false|string Commandline to call RRDGraph in order to generate the final graph* @internal param $
*/
function collectd_draw_generic($timespan, $host, $plugin, $type, $pinst = null, $tinst = null)
{
global $config, $GraphDefs;
$timespan_def = null;
foreach ($config['timespan'] as &$ts) {
if ($ts['name'] == $timespan) {
$timespan_def = $ts;
}
}
if (is_null($timespan_def)) {
$timespan_def = reset($config['timespan']);
}
if (!isset($GraphDefs[$type])) {
return false;
}
$rrd_file = sprintf('%s/%s%s%s/%s%s%s', $host, $plugin, is_null($pinst) ? '' : '-', $pinst, $type, is_null($tinst) ? '' : '-', $tinst);
// $rrd_cmd = array(RRDTOOL, 'graph', '-', '-E', '-a', 'PNG', '-w', $config['rrd_width'], '-h', $config['rrd_height'], '-t', $rrd_file);
$rrd_cmd = array(
RRDTOOL,
'graph',
'-',
'-E',
'-a',
'PNG',
'-w',
$config['rrd_width'],
'-h',
$config['rrd_height'],
);
if ($config['rrd_width'] <= '300') {
$small_opts = array(
'--font',
'LEGEND:7:mono',
'--font',
'AXIS:6:mono',
'--font-render-mode',
'normal',
);
$rrd_cmd = array_merge($rrd_cmd, $small_opts);
}
$rrd_cmd = array_merge($rrd_cmd, $config['rrd_opts_array']);
$rrd_args = $GraphDefs[$type];
foreach ($config['datadirs'] as $datadir) {
$file = $datadir.'/'.$rrd_file.'.rrd';
if (!is_file($file)) {
continue;
}
$file = str_replace(':', '\\:', $file);
$rrd_args = str_replace('{file}', $file, $rrd_args);
$rrdgraph = array_merge($rrd_cmd, $rrd_args);
$cmd = RRDTOOL;
$count_rrdgraph = count($rrdgraph);
for ($i = 1; $i < $count_rrdgraph; $i++) {
$cmd .= ' '.escapeshellarg($rrdgraph[$i]);
}
return $cmd;
}
return false;
}//end collectd_draw_generic()
/**
* Draw stack-graph for set of RRD files
* @param array $opts Graph options like colors
* @param array $sources List of array(name, file, ds)
* @return string Commandline to call RRDGraph in order to generate the final graph
*/
function collectd_draw_meta_stack(&$opts, &$sources)
{
global $config;
$timespan_def = null;
if (!isset($opts['timespan'])) {
$timespan_def = reset($config['timespan']);
} else {
foreach ($config['timespan'] as &$ts) {
if ($ts['name'] == $opts['timespan']) {
$timespan_def = $ts;
}
}
}
if (!isset($opts['title'])) {
$opts['title'] = 'Unknown title';
}
if (!isset($opts['rrd_opts'])) {
$opts['rrd_opts'] = array();
}
if (!isset($opts['colors'])) {
$opts['colors'] = array();
}
if (isset($opts['logarithmic']) && $opts['logarithmic']) {
array_unshift($opts['rrd_opts'], '-o');
}
// $cmd = array(RRDTOOL, 'graph', '-', '-E', '-a', 'PNG', '-w', $config['rrd_width'], '-h', $config['rrd_height'],
// '-t', $opts['title']);
$cmd = array(
RRDTOOL,
'graph',
'-',
'-E',
'-a',
'PNG',
'-w',
$config['rrd_width'],
'-h',
$config['rrd_height'],
);
if ($config['rrd_width'] <= '300') {
$small_opts = array(
'--font',
'LEGEND:7:mono',
'--font',
'AXIS:6:mono',
'--font-render-mode',
'normal',
);
$cmd = array_merge($cmd, $small_opts);
}
$cmd = array_merge($cmd, $config['rrd_opts_array'], $opts['rrd_opts']);
$max_inst_name = 0;
foreach ($sources as &$inst_data) {
$inst_name = $inst_data['name'];
$file = $inst_data['file'];
$ds = isset($inst_data['ds']) ? $inst_data['ds'] : 'value';
if (strlen($inst_name) > $max_inst_name) {
$max_inst_name = strlen($inst_name);
}
if (!is_file($file)) {
continue;
}
$cmd[] = 'DEF:'.$inst_name.'_min='.$file.':'.$ds.':MIN';
$cmd[] = 'DEF:'.$inst_name.'_avg='.$file.':'.$ds.':AVERAGE';
$cmd[] = 'DEF:'.$inst_name.'_max='.$file.':'.$ds.':MAX';
$cmd[] = 'CDEF:'.$inst_name.'_nnl='.$inst_name.'_avg,UN,0,'.$inst_name.'_avg,IF';
}
$inst_data = end($sources);
$inst_name = $inst_data['name'];
$cmd[] = 'CDEF:'.$inst_name.'_stk='.$inst_name.'_nnl';
$inst_data1 = end($sources);
while (($inst_data0 = prev($sources)) !== false) {
$inst_name0 = $inst_data0['name'];
$inst_name1 = $inst_data1['name'];
$cmd[] = 'CDEF:'.$inst_name0.'_stk='.$inst_name0.'_nnl,'.$inst_name1.'_stk,+';
$inst_data1 = $inst_data0;
}
foreach ($sources as &$inst_data) {
$inst_name = $inst_data['name'];
// $legend = sprintf('%s', $inst_name);
$legend = $inst_name;
while (strlen($legend) < $max_inst_name) {
$legend .= ' ';
}
$number_format = isset($opts['number_format']) ? $opts['number_format'] : '%6.1lf';
if (isset($opts['colors'][$inst_name])) {
$line_color = new CollectdColor($opts['colors'][$inst_name]);
} else {
$line_color = new CollectdColor('random');
}
$area_color = new CollectdColor($line_color);
$area_color->fade();
$cmd[] = 'AREA:'.$inst_name.'_stk#'.$area_color->toString();
$cmd[] = 'LINE1:'.$inst_name.'_stk#'.$line_color->toString().':'.$legend;
if (!(isset($opts['tinylegend']) && $opts['tinylegend'])) {
$cmd[] = 'GPRINT:'.$inst_name.'_avg:LAST:'.$number_format.'';
$cmd[] = 'GPRINT:'.$inst_name.'_avg:AVERAGE:'.$number_format.'';
$cmd[] = 'GPRINT:'.$inst_name.'_min:MIN:'.$number_format.'';
$cmd[] = 'GPRINT:'.$inst_name.'_max:MAX:'.$number_format.'\\l';
}
}//end foreach
$rrdcmd = RRDTOOL;
$count_cmd = count($cmd);
for ($i = 1; $i < $count_cmd; $i++) {
$rrdcmd .= ' '.escapeshellarg($cmd[$i]);
}
return $rrdcmd;
}//end collectd_draw_meta_stack()
/**
* Draw stack-graph for set of RRD files
* @param array $opts Graph options like colors
* @param array $sources List of array(name, file, ds)
* @return string Commandline to call RRDGraph in order to generate the final graph
*/
function collectd_draw_meta_line(&$opts, &$sources)
{
global $config;
$timespan_def = null;
if (!isset($opts['timespan'])) {
$timespan_def = reset($config['timespan']);
} else {
foreach ($config['timespan'] as &$ts) {
if ($ts['name'] == $opts['timespan']) {
$timespan_def = $ts;
}
}
}
if (!isset($opts['title'])) {
$opts['title'] = 'Unknown title';
}
if (!isset($opts['rrd_opts'])) {
$opts['rrd_opts'] = array();
}
if (!isset($opts['colors'])) {
$opts['colors'] = array();
}
if (isset($opts['logarithmic']) && $opts['logarithmic']) {
array_unshift($opts['rrd_opts'], '-o');
}
// $cmd = array(RRDTOOL, 'graph', '-', '-E', '-a', 'PNG', '-w', $config['rrd_width'], '-h', $config['rrd_height'], '-t', $opts['title']);
// $cmd = array_merge($cmd, $config['rrd_opts_array'], $opts['rrd_opts']);
$cmd = array(
RRDTOOL,
'graph',
'-',
'-E',
'-a',
'PNG',
'-w',
$config['rrd_width'],
'-h',
$config['rrd_height'],
);
if ($config['rrd_width'] <= '300') {
$small_opts = array(
'--font',
'LEGEND:7:mono',
'--font',
'AXIS:6:mono',
'--font-render-mode',
'normal',
);
$cmd = array_merge($cmd, $small_opts);
}
$max_inst_name = 0;
foreach ($sources as &$inst_data) {
$inst_name = $inst_data['name'];
$file = $inst_data['file'];
$ds = isset($inst_data['ds']) ? $inst_data['ds'] : 'value';
if (strlen($inst_name) > $max_inst_name) {
$max_inst_name = strlen($inst_name);
}
if (!is_file($file)) {
continue;
}
$cmd[] = 'DEF:'.$inst_name.'_min='.$file.':'.$ds.':MIN';
$cmd[] = 'DEF:'.$inst_name.'_avg='.$file.':'.$ds.':AVERAGE';
$cmd[] = 'DEF:'.$inst_name.'_max='.$file.':'.$ds.':MAX';
}
foreach ($sources as &$inst_data) {
$inst_name = $inst_data['name'];
$legend = sprintf('%s', $inst_name);
while (strlen($legend) < $max_inst_name) {
$legend .= ' ';
}
$number_format = isset($opts['number_format']) ? $opts['number_format'] : '%6.1lf';
if (isset($opts['colors'][$inst_name])) {
$line_color = new CollectdColor($opts['colors'][$inst_name]);
} else {
$line_color = new CollectdColor('random');
}
$cmd[] = 'LINE1:'.$inst_name.'_avg#'.$line_color->toString().':'.$legend;
if (!(isset($opts['tinylegend']) && $opts['tinylegend'])) {
$cmd[] = 'GPRINT:'.$inst_name.'_min:MIN:'.$number_format.'';
$cmd[] = 'GPRINT:'.$inst_name.'_avg:AVERAGE:'.$number_format.'';
$cmd[] = 'GPRINT:'.$inst_name.'_max:MAX:'.$number_format.'';
$cmd[] = 'GPRINT:'.$inst_name.'_avg:LAST:'.$number_format.'\\l';
}
}//end foreach
$rrdcmd = RRDTOOL;
$count_cmd = count($cmd);
for ($i = 1; $i < $count_cmd; $i++) {
$rrdcmd .= ' '.escapeshellarg($cmd[$i]);
}
return $rrdcmd;
}//end collectd_draw_meta_line()