3
+-------------------------------------------------------------------------+
4
| Copyright (C) 2004-2013 The Cacti Group |
6
| This program is free software; you can redistribute it and/or |
7
| modify it under the terms of the GNU General Public License |
8
| as published by the Free Software Foundation; either version 2 |
9
| of the License, or (at your option) any later version. |
11
| This program is distributed in the hope that it will be useful, |
12
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
13
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14
| GNU General Public License for more details. |
15
+-------------------------------------------------------------------------+
16
| Cacti: The Complete RRDTool-based Graphing Solution |
17
+-------------------------------------------------------------------------+
18
| This code is designed, written, and maintained by the Cacti Group. See |
19
| about.php and/or the AUTHORS file for specific developer information. |
20
+-------------------------------------------------------------------------+
21
| http://www.cacti.net/ |
22
+-------------------------------------------------------------------------+
25
define("RRD_NL", " \\\n");
26
define("MAX_FETCH_CACHE_SIZE", 5);
28
function escape_command($command) {
29
return $command; # we escape every single argument now, no need for "special" escaping
30
#return preg_replace("/(\\\$|`)/", "", $command); # current cacti code
31
#TODO return preg_replace((\\\$(?=\w+|\*|\@|\#|\?|\-|\\\$|\!|\_|[0-9]|\(.*\))|`(?=.*(?=`)))","$2", $command); #suggested by ldevantier to allow for a single $
34
function rrd_init($output_to_term = TRUE) {
37
/* set the rrdtool default font */
38
if (read_config_option("path_rrdtool_default_font")) {
39
putenv("RRD_DEFAULT_FONT=" . read_config_option("path_rrdtool_default_font"));
42
if ($output_to_term) {
43
$command = read_config_option("path_rrdtool") . " - ";
45
if ($config["cacti_server_os"] == "win32") {
46
$command = read_config_option("path_rrdtool") . " - > nul";
48
$command = read_config_option("path_rrdtool") . " - > /dev/null 2>&1";
52
return popen($command, "w");
55
function rrd_close($rrdtool_pipe) {
56
/* close the rrdtool file descriptor */
57
if (is_resource($rrdtool_pipe)) {
58
pclose($rrdtool_pipe);
62
function rrdtool_execute($command_line, $log_to_stdout, $output_flag, $rrdtool_pipe = "", $logopt = "WEBLOG") {
67
if (!is_numeric($output_flag)) {
68
$output_flag = RRDTOOL_OUTPUT_STDOUT;
71
/* WIN32: before sending this command off to rrdtool, get rid
72
of all of the '\' characters. Unix does not care; win32 does.
73
Also make sure to replace all of the fancy \'s at the end of the line,
74
but make sure not to get rid of the "\n"'s that are supposed to be
75
in there (text format) */
76
$command_line = str_replace("\\\n", " ", $command_line);
78
/* output information to the log file if appropriate */
79
if (read_config_option("log_verbosity") >= POLLER_VERBOSITY_DEBUG) {
80
cacti_log("CACTI2RRD: " . read_config_option("path_rrdtool") . " $command_line", $log_to_stdout, $logopt);
83
/* if we want to see the error output from rrdtool; make sure to specify this */
84
if (($output_flag == RRDTOOL_OUTPUT_STDERR) && (!is_resource($rrdtool_pipe))) {
85
$command_line .= " 2>&1";
88
/* use popen to eliminate the zombie issue */
89
if ($config["cacti_server_os"] == "unix") {
95
/* an empty $rrdtool_pipe array means no fp is available */
96
if (!is_resource($rrdtool_pipe)) {
97
session_write_close();
98
$fp = popen(read_config_option("path_rrdtool") . escape_command(" $command_line"), $pipe_mode);
99
if (!is_resource($fp)) {
105
if (fwrite($rrdtool_pipe, escape_command(" $command_line") . "\r\n") === false) {
106
cacti_log("ERROR: Detected RRDtool Crash on '$command_line'. Last command was '$last_command'");
108
/* close the invalid pipe */
109
rrd_close($rrdtool_pipe);
111
/* open a new rrdtool process */
112
$rrdtool_pipe = rrd_init();
115
cacti_log("FATAL: RRDtool Restart Attempts Exceeded. Giving up on '$command_line'.");
124
fflush($rrdtool_pipe);
131
/* store the last command to provide rrdtool segfault diagnostics */
132
$last_command = $command_line;
134
switch ($output_flag) {
135
case RRDTOOL_OUTPUT_NULL:
137
case RRDTOOL_OUTPUT_STDOUT:
138
if (isset($fp) && is_resource($fp)) {
141
$line .= fgets($fp, 4096);
150
case RRDTOOL_OUTPUT_STDERR:
151
if (isset($fp) && is_resource($fp)) {
152
$output = fgets($fp, 1000000);
156
if (substr($output, 1, 3) == "PNG") {
160
if (substr($output, 0, 5) == "GIF87") {
168
case RRDTOOL_OUTPUT_GRAPH_DATA:
169
if (isset($fp) && is_resource($fp)) {
172
$line .= fgets($fp, 4096);
184
function rrdtool_function_create($local_data_id, $show_source, $rrdtool_pipe = "") {
187
include ($config["include_path"] . "/global_arrays.php");
189
$data_source_path = get_data_source_path($local_data_id, true);
191
/* ok, if that passes lets check to make sure an rra does not already
192
exist, the last thing we want to do is overright data! */
193
if ($show_source != true) {
194
if (file_exists($data_source_path) == true) {
199
/* the first thing we must do is make sure there is at least one
200
rra associated with this data source... *
201
UPDATE: As of version 0.6.6, we are splitting this up into two
202
SQL strings because of the multiple DS per RRD support. This is
203
not a big deal however since this function gets called once per
206
$rras = db_fetch_assoc("select
207
data_template_data.rrd_step,
211
rra_cf.consolidation_function_id,
212
(rra.rows*rra.steps) as rra_order
213
from data_template_data
214
left join data_template_data_rra on (data_template_data.id=data_template_data_rra.data_template_data_id)
215
left join rra on (data_template_data_rra.rra_id=rra.id)
216
left join rra_cf on (rra.id=rra_cf.rra_id)
217
where data_template_data.local_data_id=$local_data_id
218
and (rra.steps is not null or rra.rows is not null)
219
order by rra_cf.consolidation_function_id,rra_order");
221
/* if we find that this DS has no RRA associated; get out */
222
if (sizeof($rras) <= 0) {
223
cacti_log("ERROR: There are no RRA's assigned to local_data_id: $local_data_id.");
227
/* create the "--step" line */
228
$create_ds = RRD_NL . "--step ". $rras[0]["rrd_step"] . " " . RRD_NL;
230
/* query the data sources to be used in this .rrd file */
231
$data_sources = db_fetch_assoc("SELECT
232
data_template_rrd.id,
233
data_template_rrd.rrd_heartbeat,
234
data_template_rrd.rrd_minimum,
235
data_template_rrd.rrd_maximum,
236
data_template_rrd.data_source_type_id
237
FROM data_template_rrd
238
WHERE data_template_rrd.local_data_id=$local_data_id
239
ORDER BY local_data_template_rrd_id");
241
/* ONLY make a new DS entry if:
242
- There is multiple data sources and this item is not the main one.
243
- There is only one data source (then use it) */
245
if (sizeof($data_sources) > 0) {
246
foreach ($data_sources as $data_source) {
247
/* use the cacti ds name by default or the user defined one, if entered */
248
$data_source_name = get_data_source_item_name($data_source["id"]);
250
if (empty($data_source["rrd_maximum"])) {
251
/* in case no maximum is given, use "Undef" value */
252
$data_source["rrd_maximum"] = "U";
253
} elseif (strpos($data_source["rrd_maximum"], "|query_") !== false) {
254
/* in case a query variable is given, evaluate it */
255
$data_local = db_fetch_row("SELECT * FROM data_local WHERE id=" . $local_data_id);
256
if ($data_source["rrd_maximum"] == "|query_ifSpeed|" || $data_source["rrd_maximum"] == "|query_ifHighSpeed|") {
257
$highSpeed = db_fetch_cell("SELECT field_value
259
WHERE host_id=" . $data_local["host_id"] . "
260
AND snmp_query_id=" . $data_local["snmp_query_id"] . "
261
AND snmp_index='" . $data_local["snmp_index"] . "'
262
AND field_name='ifHighSpeed'");
264
if (!empty($highSpeed)) {
265
$data_source["rrd_maximum"] = $highSpeed * 1000000;
267
$data_source["rrd_maximum"] = substitute_snmp_query_data("|query_ifSpeed|",$data_local["host_id"], $data_local["snmp_query_id"], $data_local["snmp_index"]);
270
$data_source["rrd_maximum"] = substitute_snmp_query_data($data_source["rrd_maximum"],$data_local["host_id"], $data_local["snmp_query_id"], $data_local["snmp_index"]);
272
} elseif (($data_source["rrd_maximum"] != "U") && (int)$data_source["rrd_maximum"]<=(int)$data_source["rrd_minimum"]) {
273
/* max > min required, but take care of an "Undef" value */
274
$data_source["rrd_maximum"] = (int)$data_source["rrd_minimum"]+1;
277
/* min==max==0 won't work with rrdtool */
278
if ($data_source["rrd_minimum"] == 0 && $data_source["rrd_maximum"] == 0) {
279
$data_source["rrd_maximum"] = "U";
282
$create_ds .= "DS:$data_source_name:" . $data_source_types{$data_source["data_source_type_id"]} . ":" . $data_source["rrd_heartbeat"] . ":" . $data_source["rrd_minimum"] . ":" . $data_source["rrd_maximum"] . RRD_NL;
287
/* loop through each available RRA for this DS */
288
foreach ($rras as $rra) {
289
$create_rra .= "RRA:" . $consolidation_functions{$rra["consolidation_function_id"]} . ":" . $rra["x_files_factor"] . ":" . $rra["steps"] . ":" . $rra["rows"] . RRD_NL;
292
/* check for structured path configuration, if in place verify directory
293
exists and if not create it.
295
if (read_config_option("extended_paths") == "on") {
296
if (!is_dir(dirname($data_source_path))) {
297
if (mkdir(dirname($data_source_path), 0775)) {
298
if ($config["cacti_server_os"] != "win32") {
299
$owner_id = fileowner($config["rra_path"]);
300
$group_id = filegroup($config["rra_path"]);
302
if ((chown(dirname($data_source_path), $owner_id)) &&
303
(chgrp(dirname($data_source_path), $group_id))) {
304
/* permissions set ok */
306
cacti_log("ERROR: Unable to set directory permissions for '" . dirname($data_source_path) . "'", FALSE);
310
cacti_log("ERROR: Unable to create directory '" . dirname($data_source_path) . "'", FALSE);
315
if ($show_source == true) {
316
return read_config_option("path_rrdtool") . " create" . RRD_NL . "$data_source_path$create_ds$create_rra";
318
rrdtool_execute("create $data_source_path $create_ds$create_rra", true, RRDTOOL_OUTPUT_STDOUT, $rrdtool_pipe, "POLLER");
322
function rrdtool_function_update($update_cache_array, $rrdtool_pipe = "") {
323
/* lets count the number of rrd files processed */
326
while (list($rrd_path, $rrd_fields) = each($update_cache_array)) {
327
$create_rrd_file = false;
329
/* create the rrd if one does not already exist */
330
if (!file_exists($rrd_path)) {
331
rrdtool_function_create($rrd_fields["local_data_id"], false, $rrdtool_pipe);
333
$create_rrd_file = true;
336
if ((is_array($rrd_fields["times"])) && (sizeof($rrd_fields["times"]) > 0)) {
337
ksort($rrd_fields["times"]);
339
while (list($update_time, $field_array) = each($rrd_fields["times"])) {
340
if (empty($update_time)) {
341
/* default the rrdupdate time to now */
342
$current_rrd_update_time = "N";
343
}else if ($create_rrd_file == true) {
344
/* for some reason rrdtool will not let you update using times less than the
346
$current_rrd_update_time = "N";
348
$current_rrd_update_time = $update_time;
351
$i = 0; $rrd_update_template = ""; $rrd_update_values = $current_rrd_update_time . ":";
352
while (list($field_name, $value) = each($field_array)) {
353
$rrd_update_template .= $field_name;
355
/* if we have "invalid data", give rrdtool an Unknown (U) */
356
if ((!isset($value)) || (!is_numeric($value))) {
360
$rrd_update_values .= $value;
362
if (($i+1) < count($field_array)) {
363
$rrd_update_template .= ":";
364
$rrd_update_values .= ":";
370
rrdtool_execute("update $rrd_path --template $rrd_update_template $rrd_update_values", true, RRDTOOL_OUTPUT_STDOUT, $rrdtool_pipe, "POLLER");
376
return $rrds_processed;
379
function rrdtool_function_tune($rrd_tune_array) {
382
include($config["include_path"] . "/global_arrays.php");
384
$data_source_name = get_data_source_item_name($rrd_tune_array["data_source_id"]);
385
$data_source_type = $data_source_types{$rrd_tune_array["data-source-type"]};
386
$data_source_path = get_data_source_path($rrd_tune_array["data_source_id"], true);
388
if ($rrd_tune_array["heartbeat"] != "") {
389
$rrd_tune .= " --heartbeat $data_source_name:" . $rrd_tune_array["heartbeat"];
392
if ($rrd_tune_array["minimum"] != "") {
393
$rrd_tune .= " --minimum $data_source_name:" . $rrd_tune_array["minimum"];
396
if ($rrd_tune_array["maximum"] != "") {
397
$rrd_tune .= " --maximum $data_source_name:" . $rrd_tune_array["maximum"];
400
if ($rrd_tune_array["data-source-type"] != "") {
401
$rrd_tune .= " --data-source-type $data_source_name:" . $data_source_type;
404
if ($rrd_tune_array["data-source-rename"] != "") {
405
$rrd_tune .= " --data-source-rename $data_source_name:" . $rrd_tune_array["data-source-rename"];
408
if ($rrd_tune != "") {
409
if (file_exists($data_source_path) == true) {
410
$fp = popen(read_config_option("path_rrdtool") . " tune $data_source_path $rrd_tune", "r");
413
if (read_config_option("log_verbosity") >= POLLER_VERBOSITY_DEBUG) {
414
cacti_log("CACTI2RRD: " . read_config_option("path_rrdtool") . " tune $data_source_path $rrd_tune");
420
$rrd_fetch_cache = array();
422
/* rrdtool_function_fetch - given a data source, return all of its data in an array
423
@arg $local_data_id - the data source to fetch data for
424
@arg $start_time - the start time to use for the data calculation. this value can
425
either be absolute (unix timestamp) or relative (to now)
426
@arg $end_time - the end time to use for the data calculation. this value can
427
either be absolute (unix timestamp) or relative (to now)
428
@arg $resolution - the accuracy of the data measured in seconds
429
@arg $show_unknown - Show unknown 'NAN' values in the output as 'U'
430
@returns - (array) an array containing all data in this data source broken down
431
by each data source item. the maximum of all data source items is included in
432
an item called 'ninety_fifth_percentile_maximum' */
433
function rrdtool_function_fetch($local_data_id, $start_time, $end_time, $resolution = 0, $show_unknown = false, $rrdtool_file = null) {
434
global $rrd_fetch_cache;
436
/* validate local data id */
437
if (empty($local_data_id) && is_null($rrdtool_file)) {
441
/* the cache hash is used to identify unique items in the cache */
442
$current_hash_cache = md5($local_data_id . $start_time . $end_time . $resolution . $show_unknown . $rrdtool_file);
444
/* return the cached entry if available */
445
if (isset($rrd_fetch_cache[$current_hash_cache])) {
446
return $rrd_fetch_cache[$current_hash_cache];
449
/* initialize fetch array */
450
$fetch_array = array();
452
/* check if we have been passed a file instead of lodal data source to look up */
453
if (is_null($rrdtool_file)) {
454
$data_source_path = get_data_source_path($local_data_id, true);
456
$data_source_path = $rrdtool_file;
459
/* update the rrdfile if performing a fetch */
460
api_plugin_hook_function('rrdtool_function_fetch_cache_check', $local_data_id);
462
/* build and run the rrdtool fetch command with all of our data */
463
$cmd_line = "fetch $data_source_path AVERAGE -s $start_time -e $end_time";
464
if ($resolution > 0) {
465
$cmd_line .= " -r $resolution";
467
$output = rrdtool_execute($cmd_line, false, RRDTOOL_OUTPUT_STDOUT);
469
/* grab the first line of the output which contains a list of data sources in this rrd output */
470
$line_one_eol = strpos($output, "\n");
471
$line_one = substr($output, 0, $line_one_eol);
472
$output = substr($output, $line_one_eol);
474
/* split the output into an array */
475
$output = preg_split('/[\r\n]{1,2}/', $output, null, PREG_SPLIT_NO_EMPTY);
477
/* find the data sources in the rrdtool output */
478
if (preg_match_all('/\S+/', $line_one, $data_source_names)) {
479
/* version 1.0.49 changed the output slightly, remove the timestamp label if present */
480
if (preg_match('/^timestamp/', $line_one)) {
481
array_shift($data_source_names[0]);
483
$fetch_array["data_source_names"] = $data_source_names[0];
485
/* build a regular expression to match each data source value in the rrdtool output line */
486
$regex = '/[0-9]+:\s+';
487
for ($i=0; $i < count($fetch_array["data_source_names"]); $i++) {
488
$regex .= '([\-]?[0-9]{1}[.,][0-9]+e[\+-][0-9]{2,3}|-?[Nn][Aa][Nn])';
490
if ($i < count($fetch_array["data_source_names"]) - 1) {
497
/* loop through each line of the output */
498
$fetch_array["values"] = array();
499
for ($j = 0; $j < count($output); $j++) {
501
$max_array = array();
502
/* match the output line */
503
if (preg_match($regex, $output[$j], $matches)) {
504
/* only process the output line if we have the correct number of matches */
505
if (count($matches) - 1 == count($fetch_array["data_source_names"])) {
506
/* get all values from the line and set them to the appropriate data source */
507
for ($i=1; $i <= count($fetch_array["data_source_names"]); $i++) {
508
if (! isset($fetch_array["values"][$i - 1])) {
509
$fetch_array["values"][$i - 1] = array();
511
if ((strtolower($matches[$i]) == "nan") || (strtolower($matches[$i]) == "-nan")) {
513
$fetch_array["values"][$i - 1][$j] = "U";
516
list($mantisa, $exponent) = explode('e', $matches[$i]);
517
$mantisa = str_replace(",",".",$mantisa);
518
$value = ($mantisa * (pow(10, (float)$exponent)));
519
$mantisa = str_replace(",",".",$mantisa);
520
$fetch_array["values"][$i - 1][$j] = ($value * 1);
521
$max_array[$i - 1] = $value;
524
/* get max value for values on the line */
525
if (count($max_array) > 0) {
526
$fetch_array["values"][count($fetch_array["data_source_names"])][$j] = max($max_array);
531
/* add nth percentile maximum data source */
532
if (isset($fetch_array["values"][count($fetch_array["data_source_names"])])) {
533
$fetch_array["data_source_names"][count($fetch_array["data_source_names"])] = "nth_percentile_maximum";
536
/* clear the cache if it gets too big */
537
if (sizeof($rrd_fetch_cache) >= MAX_FETCH_CACHE_SIZE) {
538
$rrd_fetch_cache = array();
541
/* update the cache */
542
if (MAX_FETCH_CACHE_SIZE > 0) {
543
$rrd_fetch_cache[$current_hash_cache] = $fetch_array;
549
function rrdtool_function_graph($local_graph_id, $rra_id, $graph_data_array, $rrdtool_pipe = "") {
550
global $config, $consolidation_functions;
552
include_once($config["library_path"] . "/cdef.php");
553
include_once($config["library_path"] . "/graph_variables.php");
554
include($config["include_path"] . "/global_arrays.php");
557
/* prevent command injection
558
* This function prepares an rrdtool graph statement to be executed by the web server.
559
* We have to take care, that the attacker does not insert shell code.
560
* As some rrdtool parameters accept "Cacti variables", we have to perform the
561
* variable substitution prior to vulnerability checks.
562
* We will enclose all parameters in quotes and substitute quotation marks within
566
/* rrdtool fetches the default font from it's execution environment
567
* you won't find that default font on the rrdtool statement itself!
568
* set the rrdtool default font via environment variable */
569
if (read_config_option("path_rrdtool_default_font")) {
570
putenv("RRD_DEFAULT_FONT=" . read_config_option("path_rrdtool_default_font"));
573
/* before we do anything; make sure the user has permission to view this graph,
574
if not then get out */
575
if ((read_config_option("auth_method") != 0) && (isset($_SESSION["sess_user_id"]))) {
576
$access_denied = !(is_graph_allowed($local_graph_id));
578
if ($access_denied == true) {
579
return "GRAPH ACCESS DENIED";
583
$data = api_plugin_hook_function('rrdtool_function_graph_cache_check', array('local_graph_id' => $local_graph_id,'rra_id' => $rra_id,'rrd_struc' => $rrdtool_pipe,'graph_data_array' => $graph_data_array, 'return' => false));
584
if (isset($data['return']) && $data['return'] != false)
585
return $data['return'];
587
/* find the step and how often this graph is updated with new data */
588
$ds_step = db_fetch_cell("select
589
data_template_data.rrd_step
590
from (data_template_data,data_template_rrd,graph_templates_item)
591
where graph_templates_item.task_item_id=data_template_rrd.id
592
and data_template_rrd.local_data_id=data_template_data.local_data_id
593
and graph_templates_item.local_graph_id=$local_graph_id
595
$ds_step = empty($ds_step) ? 300 : $ds_step;
597
/* if no rra was specified, we need to figure out which one RRDTool will choose using
598
* "best-fit" resolution fit algorithm */
599
if (empty($rra_id)) {
600
if ((empty($graph_data_array["graph_start"])) || (empty($graph_data_array["graph_end"]))) {
603
$rra["timespan"] = 86400;
605
/* get a list of RRAs related to this graph */
606
$rras = get_associated_rras($local_graph_id);
608
if (sizeof($rras) > 0) {
609
foreach ($rras as $unchosen_rra) {
610
/* the timespan specified in the RRA "timespan" field may not be accurate */
611
$real_timespan = ($ds_step * $unchosen_rra["steps"] * $unchosen_rra["rows"]);
613
/* make sure the current start/end times fit within each RRA's timespan */
614
if ( (($graph_data_array["graph_end"] - $graph_data_array["graph_start"]) <= $real_timespan) && ((time() - $graph_data_array["graph_start"]) <= $real_timespan) ) {
615
/* is this RRA better than the already chosen one? */
616
if ((isset($rra)) && ($unchosen_rra["steps"] < $rra["steps"])) {
617
$rra = $unchosen_rra;
618
}else if (!isset($rra)) {
619
$rra = $unchosen_rra;
631
$rra = db_fetch_row("select timespan,rows,steps from rra where id=$rra_id");
634
$seconds_between_graph_updates = ($ds_step * $rra["steps"]);
636
$graph = db_fetch_row("select
637
graph_local.id AS local_graph_id,
639
graph_local.snmp_query_id,
640
graph_local.snmp_index,
641
graph_templates_graph.title_cache,
642
graph_templates_graph.vertical_label,
643
graph_templates_graph.slope_mode,
644
graph_templates_graph.auto_scale,
645
graph_templates_graph.auto_scale_opts,
646
graph_templates_graph.auto_scale_log,
647
graph_templates_graph.scale_log_units,
648
graph_templates_graph.auto_scale_rigid,
649
graph_templates_graph.auto_padding,
650
graph_templates_graph.base_value,
651
graph_templates_graph.upper_limit,
652
graph_templates_graph.lower_limit,
653
graph_templates_graph.height,
654
graph_templates_graph.width,
655
graph_templates_graph.image_format_id,
656
graph_templates_graph.unit_value,
657
graph_templates_graph.unit_exponent_value,
658
graph_templates_graph.export
659
from (graph_templates_graph,graph_local)
660
where graph_local.id=graph_templates_graph.local_graph_id
661
and graph_templates_graph.local_graph_id=$local_graph_id");
663
/* lets make that sql query... */
664
$graph_items = db_fetch_assoc("select
665
graph_templates_item.id as graph_templates_item_id,
666
graph_templates_item.cdef_id,
667
graph_templates_item.text_format,
668
graph_templates_item.value,
669
graph_templates_item.hard_return,
670
graph_templates_item.consolidation_function_id,
671
graph_templates_item.graph_type_id,
672
graph_templates_gprint.gprint_text,
674
graph_templates_item.alpha,
675
data_template_rrd.id as data_template_rrd_id,
676
data_template_rrd.local_data_id,
677
data_template_rrd.rrd_minimum,
678
data_template_rrd.rrd_maximum,
679
data_template_rrd.data_source_name,
680
data_template_rrd.local_data_template_rrd_id
681
from graph_templates_item
682
left join data_template_rrd on (graph_templates_item.task_item_id=data_template_rrd.id)
683
left join colors on (graph_templates_item.color_id=colors.id)
684
left join graph_templates_gprint on (graph_templates_item.gprint_id=graph_templates_gprint.id)
685
where graph_templates_item.local_graph_id=$local_graph_id
686
order by graph_templates_item.sequence");
688
/* +++++++++++++++++++++++ GRAPH OPTIONS +++++++++++++++++++++++ */
690
/* define some variables */
694
$unit_exponent_value = "";
697
$txt_graph_items = "";
699
$greatest_text_format = 0;
700
$last_graph_type = "";
702
if ($graph["auto_scale"] == "on") {
703
switch ($graph["auto_scale_opts"]) {
704
case "1": /* autoscale ignores lower, upper limit */
705
$scale = "--alt-autoscale" . RRD_NL;
707
case "2": /* autoscale-max, accepts a given lower limit */
708
$scale = "--alt-autoscale-max" . RRD_NL;
709
if ( is_numeric($graph["lower_limit"])) {
710
$scale .= "--lower-limit=" . cacti_escapeshellarg($graph["lower_limit"]) . RRD_NL;
713
case "3": /* autoscale-min, accepts a given upper limit */
714
if (read_config_option("rrdtool_version") != "rrd-1.0.x") {
715
$scale = "--alt-autoscale-min" . RRD_NL;
716
if ( is_numeric($graph["upper_limit"])) {
717
$scale .= "--upper-limit=" . cacti_escapeshellarg($graph["upper_limit"]) . RRD_NL;
721
case "4": /* auto_scale with limits */
722
$scale = "--alt-autoscale" . RRD_NL;
723
if ( is_numeric($graph["upper_limit"])) {
724
$scale .= "--upper-limit=" . cacti_escapeshellarg($graph["upper_limit"]) . RRD_NL;
726
if ( is_numeric($graph["lower_limit"])) {
727
$scale .= "--lower-limit=" . cacti_escapeshellarg($graph["lower_limit"]) . RRD_NL;
732
if (strlen($graph["upper_limit"])) {
733
$scale = "--upper-limit=" . cacti_escapeshellarg($graph["upper_limit"]) . RRD_NL;
735
if (strlen($graph["lower_limit"])) {
736
$scale .= "--lower-limit=" . cacti_escapeshellarg($graph["lower_limit"]) . RRD_NL;
740
if ($graph["auto_scale_log"] == "on") {
741
$scale .= "--logarithmic" . RRD_NL;
744
/* --units=si only defined for logarithmic y-axis scaling, even if it doesn't hurt on linear graphs */
745
if (($graph["scale_log_units"] == "on") &&
746
($graph["auto_scale_log"] == "on")) {
747
$scale .= "--units=si" . RRD_NL;
750
if ($graph["auto_scale_rigid"] == "on") {
751
$rigid = "--rigid" . RRD_NL;
754
if (!empty($graph["unit_value"])) {
755
if (read_config_option("rrdtool_version") != "rrd-1.0.x") {
756
$unit_value = "--y-grid=" . cacti_escapeshellarg($graph["unit_value"]) . RRD_NL;
758
$unit_value = "--unit=" . cacti_escapeshellarg($graph["unit_value"]) . RRD_NL;
762
if (preg_match("/^[0-9]+$/", $graph["unit_exponent_value"])) {
763
$unit_exponent_value = "--units-exponent=" . cacti_escapeshellarg($graph["unit_exponent_value"]) . RRD_NL;
767
* optionally you can specify and array that overrides some of the db's values, lets set
771
/* override: graph start time */
772
if ((!isset($graph_data_array["graph_start"])) || ($graph_data_array["graph_start"] == "0")) {
773
$graph_start = -($rra["timespan"]);
775
$graph_start = $graph_data_array["graph_start"];
778
/* override: graph end time */
779
if ((!isset($graph_data_array["graph_end"])) || ($graph_data_array["graph_end"] == "0")) {
780
$graph_end = -($seconds_between_graph_updates);
782
$graph_end = $graph_data_array["graph_end"];
785
/* override: graph height (in pixels) */
786
if (isset($graph_data_array["graph_height"])) {
787
$graph_height = $graph_data_array["graph_height"];
789
$graph_height = $graph["height"];
792
/* override: graph width (in pixels) */
793
if (isset($graph_data_array["graph_width"])) {
794
$graph_width = $graph_data_array["graph_width"];
796
$graph_width = $graph["width"];
799
/* override: skip drawing the legend? */
800
if (isset($graph_data_array["graph_nolegend"])) {
801
$graph_legend = "--no-legend" . RRD_NL;
807
if (isset($graph_data_array["export"])) {
808
$graph_opts = read_config_option("path_html_export") . "/" . $graph_data_array["export_filename"] . RRD_NL;
810
if (empty($graph_data_array["output_filename"])) {
811
$graph_opts = "-" . RRD_NL;
813
$graph_opts = $graph_data_array["output_filename"] . RRD_NL;
817
/* setup date format */
818
$date_fmt = read_graph_config_option("default_date_format");
819
$datechar = read_graph_config_option("default_datechar");
821
if ($datechar == GDC_HYPHEN) {
829
$graph_date = "m" . $datechar . "d" . $datechar . "Y H:i:s";
832
$graph_date = "M" . $datechar . "d" . $datechar . "Y H:i:s";
835
$graph_date = "d" . $datechar . "m" . $datechar . "Y H:i:s";
838
$graph_date = "d" . $datechar . "M" . $datechar . "Y H:i:s";
841
$graph_date = "Y" . $datechar . "m" . $datechar . "d H:i:s";
844
$graph_date = "Y" . $datechar . "M" . $datechar . "d H:i:s";
848
/* display the timespan for zoomed graphs */
849
if ((isset($graph_data_array["graph_start"])) && (isset($graph_data_array["graph_end"]))) {
850
if (($graph_data_array["graph_start"] < 0) && ($graph_data_array["graph_end"] < 0)) {
851
if (read_config_option("rrdtool_version") != "rrd-1.0.x") {
852
$graph_legend .= "COMMENT:\"From " . str_replace(":", "\:", date($graph_date, time()+$graph_data_array["graph_start"])) . " To " . str_replace(":", "\:", date($graph_date, time()+$graph_data_array["graph_end"])) . "\\c\"" . RRD_NL . "COMMENT:\" \\n\"" . RRD_NL;
854
$graph_legend .= "COMMENT:\"From " . date($graph_date, time()+$graph_data_array["graph_start"]) . " To " . date($graph_date, time()+$graph_data_array["graph_end"]) . "\\c\"" . RRD_NL . "COMMENT:\" \\n\"" . RRD_NL;
856
}else if (($graph_data_array["graph_start"] >= 0) && ($graph_data_array["graph_end"] >= 0)) {
857
if (read_config_option("rrdtool_version") != "rrd-1.0.x") {
858
$graph_legend .= "COMMENT:\"From " . str_replace(":", "\:", date($graph_date, $graph_data_array["graph_start"])) . " To " . str_replace(":", "\:", date($graph_date, $graph_data_array["graph_end"])) . "\\c\"" . RRD_NL . "COMMENT:\" \\n\"" . RRD_NL;
860
$graph_legend .= "COMMENT:\"From " . date($graph_date, $graph_data_array["graph_start"]) . " To " . date($graph_date, $graph_data_array["graph_end"]) . "\\c\"" . RRD_NL . "COMMENT:\" \\n\"" . RRD_NL;
865
/* basic graph options */
867
"--imgformat=" . $image_types{$graph["image_format_id"]} . RRD_NL .
868
"--start=" . cacti_escapeshellarg($graph_start) . RRD_NL .
869
"--end=" . cacti_escapeshellarg($graph_end) . RRD_NL .
870
"--title=" . cacti_escapeshellarg($graph["title_cache"]) . RRD_NL .
872
"--base=" . cacti_escapeshellarg($graph["base_value"]) . RRD_NL .
873
"--height=" . cacti_escapeshellarg($graph_height) . RRD_NL .
874
"--width=" . cacti_escapeshellarg($graph_width) . RRD_NL .
877
"$unit_exponent_value" .
879
"--vertical-label=" . cacti_escapeshellarg($graph["vertical_label"]) . RRD_NL;
881
/* rrdtool 1.2.x does not provide smooth lines, let's force it */
882
if (read_config_option("rrdtool_version") != "rrd-1.0.x") {
883
if ($graph["slope_mode"] == "on") {
884
$graph_opts .= "--slope-mode" . RRD_NL;
888
/* rrdtool 1.2 font options */
889
if (read_config_option("rrdtool_version") != "rrd-1.0.x") {
891
$graph_opts .= rrdtool_set_font("title", ((!empty($graph_data_array["graph_nolegend"])) ? $graph_data_array["graph_nolegend"] : ""));
894
$graph_opts .= rrdtool_set_font("axis");
897
$graph_opts .= rrdtool_set_font("legend");
900
$graph_opts .= rrdtool_set_font("unit");
904
$last_graph_cf = array();
905
if (sizeof($graph_items) > 0) {
907
/* we need to add a new column "cf_reference", so unless PHP 5 is used, this foreach syntax is required */
908
foreach ($graph_items as $key => $graph_item) {
909
/* mimic the old behavior: LINE[123], AREA and STACK items use the CF specified in the graph item */
910
if (($graph_item["graph_type_id"] == GRAPH_ITEM_TYPE_LINE1) ||
911
($graph_item["graph_type_id"] == GRAPH_ITEM_TYPE_LINE2) ||
912
($graph_item["graph_type_id"] == GRAPH_ITEM_TYPE_LINE3) ||
913
($graph_item["graph_type_id"] == GRAPH_ITEM_TYPE_AREA) ||
914
($graph_item["graph_type_id"] == GRAPH_ITEM_TYPE_STACK)) {
915
$graph_cf = $graph_item["consolidation_function_id"];
916
/* remember the last CF for this data source for use with GPRINT
917
* if e.g. an AREA/AVERAGE and a LINE/MAX is used
918
* we will have AVERAGE first and then MAX, depending on GPRINT sequence */
919
$last_graph_cf["data_source_name"]["local_data_template_rrd_id"] = $graph_cf;
920
/* remember this for second foreach loop */
921
$graph_items[$key]["cf_reference"] = $graph_cf;
922
}elseif ($graph_item["graph_type_id"] == GRAPH_ITEM_TYPE_GPRINT) {
924
* the "CF" given on graph_item edit screen for GPRINT is indeed NOT a real "CF",
925
* but an aggregation function
926
* see "man rrdgraph_data" for the correct VDEF based notation
927
* so our task now is to "guess" the very graph_item, this GPRINT is related to
928
* and to use that graph_item's CF */
929
if (isset($last_graph_cf["data_source_name"]["local_data_template_rrd_id"])) {
930
$graph_cf = $last_graph_cf["data_source_name"]["local_data_template_rrd_id"];
931
/* remember this for second foreach loop */
932
$graph_items[$key]["cf_reference"] = $graph_cf;
934
$graph_cf = generate_graph_best_cf($graph_item["local_data_id"], $graph_item["consolidation_function_id"]);
935
/* remember this for second foreach loop */
936
$graph_items[$key]["cf_reference"] = $graph_cf;
939
/* all other types are based on the best matching CF */
940
$graph_cf = generate_graph_best_cf($graph_item["local_data_id"], $graph_item["consolidation_function_id"]);
941
/* remember this for second foreach loop */
942
$graph_items[$key]["cf_reference"] = $graph_cf;
945
if ((!empty($graph_item["local_data_id"])) && (!isset($cf_ds_cache{$graph_item["data_template_rrd_id"]}[$graph_cf]))) {
946
/* use a user-specified ds path if one is entered */
947
$data_source_path = get_data_source_path($graph_item["local_data_id"], true);
949
/* FOR WIN32: Escape all colon for drive letters (ex. D\:/path/to/rra) */
950
$data_source_path = str_replace(":", "\:", $data_source_path);
952
if (!empty($data_source_path)) {
953
/* NOTE: (Update) Data source DEF names are created using the graph_item_id; then passed
954
to a function that matches the digits with letters. rrdtool likes letters instead
955
of numbers in DEF names; especially with CDEF's. cdef's are created
956
the same way, except a 'cdef' is put on the beginning of the hash */
957
$graph_defs .= "DEF:" . generate_graph_def_name(strval($i)) . "=" . cacti_escapeshellarg($data_source_path) . ":" . cacti_escapeshellarg($graph_item["data_source_name"], true) . ":" . $consolidation_functions[$graph_cf] . RRD_NL;
959
$cf_ds_cache{$graph_item["data_template_rrd_id"]}[$graph_cf] = "$i";
965
/* cache cdef value here to support data query variables in the cdef string */
966
if (empty($graph_item["cdef_id"])) {
967
$graph_item["cdef_cache"] = "";
968
$graph_items[$j]["cdef_cache"] = "";
970
$graph_item["cdef_cache"] = get_cdef($graph_item["cdef_id"]);
971
$graph_items[$j]["cdef_cache"] = get_cdef($graph_item["cdef_id"]);
974
/* +++++++++++++++++++++++ LEGEND: TEXT SUBSTITUTION (<>'s) +++++++++++++++++++++++ */
976
/* note the current item_id for easy access */
977
$graph_item_id = $graph_item["graph_templates_item_id"];
979
/* the following fields will be searched for graph variables */
980
$variable_fields = array(
981
"text_format" => array(
982
"process_no_legend" => false
985
"process_no_legend" => true
987
"cdef_cache" => array(
988
"process_no_legend" => true
992
/* loop through each field that we want to substitute values for:
993
currently: text format and value */
994
while (list($field_name, $field_array) = each($variable_fields)) {
995
/* certain fields do not require values when the legend is not to be shown */
996
if (($field_array["process_no_legend"] == false) && (isset($graph_data_array["graph_nolegend"]))) {
1000
$graph_variables[$field_name][$graph_item_id] = $graph_item[$field_name];
1002
/* date/time substitution */
1003
if (strstr($graph_variables[$field_name][$graph_item_id], "|date_time|")) {
1004
$graph_variables[$field_name][$graph_item_id] = str_replace("|date_time|", date('D d M H:i:s T Y', strtotime(db_fetch_cell("select value from settings where name='date'"))), $graph_variables[$field_name][$graph_item_id]);
1007
/* data source title substitution */
1008
if (strstr($graph_variables[$field_name][$graph_item_id], "|data_source_title|")) {
1009
$graph_variables[$field_name][$graph_item_id] = str_replace("|data_source_title|", get_data_source_title($graph_item["local_data_id"]), $graph_variables[$field_name][$graph_item_id]);
1012
/* data query variables */
1013
$graph_variables[$field_name][$graph_item_id] = rrd_substitute_host_query_data($graph_variables[$field_name][$graph_item_id], $graph, $graph_item);
1015
/* Nth percentile */
1016
if (preg_match_all("/\|([0-9]{1,2}):(bits|bytes):(\d):(current|total|max|total_peak|all_max_current|all_max_peak|aggregate_max|aggregate_sum|aggregate_current|aggregate):(\d)?\|/", $graph_variables[$field_name][$graph_item_id], $matches, PREG_SET_ORDER)) {
1017
foreach ($matches as $match) {
1018
$graph_variables[$field_name][$graph_item_id] = str_replace($match[0], variable_nth_percentile($match, $graph_item, $graph_items, $graph_start, $graph_end), $graph_variables[$field_name][$graph_item_id]);
1022
/* bandwidth summation */
1023
if (preg_match_all("/\|sum:(\d|auto):(current|total|atomic):(\d):(\d+|auto)\|/", $graph_variables[$field_name][$graph_item_id], $matches, PREG_SET_ORDER)) {
1024
foreach ($matches as $match) {
1025
$graph_variables[$field_name][$graph_item_id] = str_replace($match[0], variable_bandwidth_summation($match, $graph_item, $graph_items, $graph_start, $graph_end, $rra["steps"], $ds_step), $graph_variables[$field_name][$graph_item_id]);
1030
/* if we are not displaying a legend there is no point in us even processing the auto padding,
1031
text format stuff. */
1032
if (!isset($graph_data_array["graph_nolegend"])) {
1033
/* set hard return variable if selected (\n) */
1034
if ($graph_item["hard_return"] == "on") {
1035
$hardreturn[$graph_item_id] = "\\n";
1037
$hardreturn[$graph_item_id] = "";
1040
/* +++++++++++++++++++++++ LEGEND: AUTO PADDING (<>'s) +++++++++++++++++++++++ */
1042
/* PADDING: remember this is not perfect! its main use is for the basic graph setup of:
1043
AREA - GPRINT-CURRENT - GPRINT-AVERAGE - GPRINT-MAXIMUM \n
1044
of course it can be used in other situations, however may not work as intended.
1045
If you have any additions to this small peice of code, feel free to send them to me. */
1046
if ($graph["auto_padding"] == "on") {
1047
/* only applies to AREA, STACK and LINEs */
1048
if (preg_match("/(AREA|STACK|LINE[123])/", $graph_item_types{$graph_item["graph_type_id"]})) {
1049
$text_format_length = mb_strlen($graph_variables["text_format"][$graph_item_id], 'UTF-8');
1051
if ($text_format_length > $greatest_text_format) {
1052
$greatest_text_format = $text_format_length;
1062
/* +++++++++++++++++++++++ GRAPH ITEMS: CDEF's +++++++++++++++++++++++ */
1065
reset($graph_items);
1067
/* hack for rrdtool 1.2.x support */
1068
$graph_item_stack_type = "";
1070
if (sizeof($graph_items) > 0) {
1071
foreach ($graph_items as $graph_item) {
1072
/* first we need to check if there is a DEF for the current data source/cf combination. if so,
1074
if (isset($cf_ds_cache{$graph_item["data_template_rrd_id"]}{$graph_item["consolidation_function_id"]})) {
1075
$cf_id = $graph_item["consolidation_function_id"];
1077
/* if there is not a DEF defined for the current data source/cf combination, then we will have to
1078
improvise. choose the first available cf in the following order: AVERAGE, MAX, MIN, LAST */
1079
if (isset($cf_ds_cache{$graph_item["data_template_rrd_id"]}[1])) {
1080
$cf_id = 1; /* CF: AVERAGE */
1081
}elseif (isset($cf_ds_cache{$graph_item["data_template_rrd_id"]}[3])) {
1082
$cf_id = 3; /* CF: MAX */
1083
}elseif (isset($cf_ds_cache{$graph_item["data_template_rrd_id"]}[2])) {
1084
$cf_id = 2; /* CF: MIN */
1085
}elseif (isset($cf_ds_cache{$graph_item["data_template_rrd_id"]}[4])) {
1086
$cf_id = 4; /* CF: LAST */
1088
$cf_id = 1; /* CF: AVERAGE */
1091
/* now remember the correct CF reference */
1092
$cf_id = $graph_item["cf_reference"];
1094
/* make cdef string here; a note about CDEF's in cacti. A CDEF is neither unique to a
1095
data source of global cdef, but is unique when those two variables combine. */
1096
$cdef_graph_defs = "";
1098
if ((!empty($graph_item["cdef_id"])) && (!isset($cdef_cache{$graph_item["cdef_id"]}{$graph_item["data_template_rrd_id"]}[$cf_id]))) {
1100
$cdef_string = $graph_variables["cdef_cache"]{$graph_item["graph_templates_item_id"]};
1101
$magic_item = array();
1102
$already_seen = array();
1103
$sources_seen = array();
1104
$count_all_ds_dups = 0;
1105
$count_all_ds_nodups = 0;
1106
$count_similar_ds_dups = 0;
1107
$count_similar_ds_nodups = 0;
1109
/* if any of those magic variables are requested ... */
1110
if (preg_match("/(ALL_DATA_SOURCES_(NO)?DUPS|SIMILAR_DATA_SOURCES_(NO)?DUPS)/", $cdef_string) ||
1111
preg_match("/(COUNT_ALL_DS_(NO)?DUPS|COUNT_SIMILAR_DS_(NO)?DUPS)/", $cdef_string)) {
1113
/* now walk through each case to initialize array*/
1114
if (preg_match("/ALL_DATA_SOURCES_DUPS/", $cdef_string)) {
1115
$magic_item["ALL_DATA_SOURCES_DUPS"] = "";
1117
if (preg_match("/ALL_DATA_SOURCES_NODUPS/", $cdef_string)) {
1118
$magic_item["ALL_DATA_SOURCES_NODUPS"] = "";
1120
if (preg_match("/SIMILAR_DATA_SOURCES_DUPS/", $cdef_string)) {
1121
$magic_item["SIMILAR_DATA_SOURCES_DUPS"] = "";
1123
if (preg_match("/SIMILAR_DATA_SOURCES_NODUPS/", $cdef_string)) {
1124
$magic_item["SIMILAR_DATA_SOURCES_NODUPS"] = "";
1126
if (preg_match("/COUNT_ALL_DS_DUPS/", $cdef_string)) {
1127
$magic_item["COUNT_ALL_DS_DUPS"] = "";
1129
if (preg_match("/COUNT_ALL_DS_NODUPS/", $cdef_string)) {
1130
$magic_item["COUNT_ALL_DS_NODUPS"] = "";
1132
if (preg_match("/COUNT_SIMILAR_DS_DUPS/", $cdef_string)) {
1133
$magic_item["COUNT_SIMILAR_DS_DUPS"] = "";
1135
if (preg_match("/COUNT_SIMILAR_DS_NODUPS/", $cdef_string)) {
1136
$magic_item["COUNT_SIMILAR_DS_NODUPS"] = "";
1139
/* loop over all graph items */
1140
for ($t=0;($t<count($graph_items));$t++) {
1142
/* only work on graph items, omit GRPINTs, COMMENTs and stuff */
1143
if ((preg_match("/(AREA|STACK|LINE[123])/", $graph_item_types{$graph_items[$t]["graph_type_id"]})) && (!empty($graph_items[$t]["data_template_rrd_id"]))) {
1144
/* if the user screws up CF settings, PHP will generate warnings if left unchecked */
1146
/* matching consolidation function? */
1147
if (isset($cf_ds_cache{$graph_items[$t]["data_template_rrd_id"]}[$cf_id])) {
1148
$def_name = generate_graph_def_name(strval($cf_ds_cache{$graph_items[$t]["data_template_rrd_id"]}[$cf_id]));
1150
/* do we need ALL_DATA_SOURCES_DUPS? */
1151
if (isset($magic_item["ALL_DATA_SOURCES_DUPS"])) {
1152
$magic_item["ALL_DATA_SOURCES_DUPS"] .= ($count_all_ds_dups == 0 ? "" : ",") . "TIME," . (time() - $seconds_between_graph_updates) . ",GT,$def_name,$def_name,UN,0,$def_name,IF,IF"; /* convert unknowns to '0' first */
1155
/* do we need COUNT_ALL_DS_DUPS? */
1156
if (isset($magic_item["COUNT_ALL_DS_DUPS"])) {
1157
$magic_item["COUNT_ALL_DS_DUPS"] .= ($count_all_ds_dups == 0 ? "" : ",") . "TIME," . (time() - $seconds_between_graph_updates) . ",GT,1,$def_name,UN,0,1,IF,IF"; /* convert unknowns to '0' first */
1160
$count_all_ds_dups++;
1162
/* check if this item also qualifies for NODUPS */
1163
if(!isset($already_seen[$def_name])) {
1164
if (isset($magic_item["ALL_DATA_SOURCES_NODUPS"])) {
1165
$magic_item["ALL_DATA_SOURCES_NODUPS"] .= ($count_all_ds_nodups == 0 ? "" : ",") . "TIME," . (time() - $seconds_between_graph_updates) . ",GT,$def_name,$def_name,UN,0,$def_name,IF,IF"; /* convert unknowns to '0' first */
1167
if (isset($magic_item["COUNT_ALL_DS_NODUPS"])) {
1168
$magic_item["COUNT_ALL_DS_NODUPS"] .= ($count_all_ds_nodups == 0 ? "" : ",") . "TIME," . (time() - $seconds_between_graph_updates) . ",GT,1,$def_name,UN,0,1,IF,IF"; /* convert unknowns to '0' first */
1170
$count_all_ds_nodups++;
1171
$already_seen[$def_name]=TRUE;
1174
/* check for SIMILAR data sources */
1175
if ($graph_item["data_source_name"] == $graph_items[$t]["data_source_name"]) {
1177
/* do we need SIMILAR_DATA_SOURCES_DUPS? */
1178
if (isset($magic_item["SIMILAR_DATA_SOURCES_DUPS"]) && ($graph_item["data_source_name"] == $graph_items[$t]["data_source_name"])) {
1179
$magic_item["SIMILAR_DATA_SOURCES_DUPS"] .= ($count_similar_ds_dups == 0 ? "" : ",") . "TIME," . (time() - $seconds_between_graph_updates) . ",GT,$def_name,$def_name,UN,0,$def_name,IF,IF"; /* convert unknowns to '0' first */
1182
/* do we need COUNT_SIMILAR_DS_DUPS? */
1183
if (isset($magic_item["COUNT_SIMILAR_DS_DUPS"]) && ($graph_item["data_source_name"] == $graph_items[$t]["data_source_name"])) {
1184
$magic_item["COUNT_SIMILAR_DS_DUPS"] .= ($count_similar_ds_dups == 0 ? "" : ",") . "TIME," . (time() - $seconds_between_graph_updates) . ",GT,1,$def_name,UN,0,1,IF,IF"; /* convert unknowns to '0' first */
1187
$count_similar_ds_dups++;
1189
/* check if this item also qualifies for NODUPS */
1190
if(!isset($sources_seen{$graph_items[$t]["data_template_rrd_id"]})) {
1191
if (isset($magic_item["SIMILAR_DATA_SOURCES_NODUPS"])) {
1192
$magic_item["SIMILAR_DATA_SOURCES_NODUPS"] .= ($count_similar_ds_nodups == 0 ? "" : ",") . "TIME," . (time() - $seconds_between_graph_updates) . ",GT,$def_name,$def_name,UN,0,$def_name,IF,IF"; /* convert unknowns to '0' first */
1194
if (isset($magic_item["COUNT_SIMILAR_DS_NODUPS"]) && ($graph_item["data_source_name"] == $graph_items[$t]["data_source_name"])) {
1195
$magic_item["COUNT_SIMILAR_DS_NODUPS"] .= ($count_similar_ds_nodups == 0 ? "" : ",") . "TIME," . (time() - $seconds_between_graph_updates) . ",GT,1,$def_name,UN,0,1,IF,IF"; /* convert unknowns to '0' first */
1197
$count_similar_ds_nodups++;
1198
$sources_seen{$graph_items[$t]["data_template_rrd_id"]} = TRUE;
1200
} # SIMILAR data sources
1201
} # matching consolidation function?
1202
} # only work on graph items, omit GRPINTs, COMMENTs and stuff
1203
} # loop over all graph items
1205
/* if there is only one item to total, don't even bother with the summation.
1206
* Otherwise cdef=a,b,c,+,+ is fine. */
1207
if ($count_all_ds_dups > 1 && isset($magic_item["ALL_DATA_SOURCES_DUPS"])) {
1208
$magic_item["ALL_DATA_SOURCES_DUPS"] .= str_repeat(",+", ($count_all_ds_dups - 2)) . ",+";
1210
if ($count_all_ds_nodups > 1 && isset($magic_item["ALL_DATA_SOURCES_NODUPS"])) {
1211
$magic_item["ALL_DATA_SOURCES_NODUPS"] .= str_repeat(",+", ($count_all_ds_nodups - 2)) . ",+";
1213
if ($count_similar_ds_dups > 1 && isset($magic_item["SIMILAR_DATA_SOURCES_DUPS"])) {
1214
$magic_item["SIMILAR_DATA_SOURCES_DUPS"] .= str_repeat(",+", ($count_similar_ds_dups - 2)) . ",+";
1216
if ($count_similar_ds_nodups > 1 && isset($magic_item["SIMILAR_DATA_SOURCES_NODUPS"])) {
1217
$magic_item["SIMILAR_DATA_SOURCES_NODUPS"] .= str_repeat(",+", ($count_similar_ds_nodups - 2)) . ",+";
1219
if ($count_all_ds_dups > 1 && isset($magic_item["COUNT_ALL_DS_DUPS"])) {
1220
$magic_item["COUNT_ALL_DS_DUPS"] .= str_repeat(",+", ($count_all_ds_dups - 2)) . ",+";
1222
if ($count_all_ds_nodups > 1 && isset($magic_item["COUNT_ALL_DS_NODUPS"])) {
1223
$magic_item["COUNT_ALL_DS_NODUPS"] .= str_repeat(",+", ($count_all_ds_nodups - 2)) . ",+";
1225
if ($count_similar_ds_dups > 1 && isset($magic_item["COUNT_SIMILAR_DS_DUPS"])) {
1226
$magic_item["COUNT_SIMILAR_DS_DUPS"] .= str_repeat(",+", ($count_similar_ds_dups - 2)) . ",+";
1228
if ($count_similar_ds_nodups > 1 && isset($magic_item["COUNT_SIMILAR_DS_NODUPS"])) {
1229
$magic_item["COUNT_SIMILAR_DS_NODUPS"] .= str_repeat(",+", ($count_similar_ds_nodups - 2)) . ",+";
1233
$cdef_string = str_replace("CURRENT_DATA_SOURCE", generate_graph_def_name(strval((isset($cf_ds_cache{$graph_item["data_template_rrd_id"]}[$cf_id]) ? $cf_ds_cache{$graph_item["data_template_rrd_id"]}[$cf_id] : "0"))), $cdef_string);
1235
/* ALL|SIMILAR_DATA_SOURCES(NO)?DUPS are to be replaced here */
1236
if (isset($magic_item["ALL_DATA_SOURCES_DUPS"])) {
1237
$cdef_string = str_replace("ALL_DATA_SOURCES_DUPS", $magic_item["ALL_DATA_SOURCES_DUPS"], $cdef_string);
1239
if (isset($magic_item["ALL_DATA_SOURCES_NODUPS"])) {
1240
$cdef_string = str_replace("ALL_DATA_SOURCES_NODUPS", $magic_item["ALL_DATA_SOURCES_NODUPS"], $cdef_string);
1242
if (isset($magic_item["SIMILAR_DATA_SOURCES_DUPS"])) {
1243
$cdef_string = str_replace("SIMILAR_DATA_SOURCES_DUPS", $magic_item["SIMILAR_DATA_SOURCES_DUPS"], $cdef_string);
1245
if (isset($magic_item["SIMILAR_DATA_SOURCES_NODUPS"])) {
1246
$cdef_string = str_replace("SIMILAR_DATA_SOURCES_NODUPS", $magic_item["SIMILAR_DATA_SOURCES_NODUPS"], $cdef_string);
1249
/* COUNT_ALL|SIMILAR_DATA_SOURCES(NO)?DUPS are to be replaced here */
1250
if (isset($magic_item["COUNT_ALL_DS_DUPS"])) {
1251
$cdef_string = str_replace("COUNT_ALL_DS_DUPS", $magic_item["COUNT_ALL_DS_DUPS"], $cdef_string);
1253
if (isset($magic_item["COUNT_ALL_DS_NODUPS"])) {
1254
$cdef_string = str_replace("COUNT_ALL_DS_NODUPS", $magic_item["COUNT_ALL_DS_NODUPS"], $cdef_string);
1256
if (isset($magic_item["COUNT_SIMILAR_DS_DUPS"])) {
1257
$cdef_string = str_replace("COUNT_SIMILAR_DS_DUPS", $magic_item["COUNT_SIMILAR_DS_DUPS"], $cdef_string);
1259
if (isset($magic_item["COUNT_SIMILAR_DS_NODUPS"])) {
1260
$cdef_string = str_replace("COUNT_SIMILAR_DS_NODUPS", $magic_item["COUNT_SIMILAR_DS_NODUPS"], $cdef_string);
1263
/* data source item variables */
1264
$cdef_string = str_replace("CURRENT_DS_MINIMUM_VALUE", (empty($graph_item["rrd_minimum"]) ? "0" : $graph_item["rrd_minimum"]), $cdef_string);
1265
$cdef_string = str_replace("CURRENT_DS_MAXIMUM_VALUE", (empty($graph_item["rrd_maximum"]) ? "0" : $graph_item["rrd_maximum"]), $cdef_string);
1266
$cdef_string = str_replace("CURRENT_GRAPH_MINIMUM_VALUE", (empty($graph["lower_limit"]) ? "0" : $graph["lower_limit"]), $cdef_string);
1267
$cdef_string = str_replace("CURRENT_GRAPH_MAXIMUM_VALUE", (empty($graph["upper_limit"]) ? "0" : $graph["upper_limit"]), $cdef_string);
1269
/* replace query variables in cdefs */
1270
$cdef_string = rrd_substitute_host_query_data($cdef_string, $graph, $graph_item);
1272
/* make the initial "virtual" cdef name: 'cdef' + [a,b,c,d...] */
1273
$cdef_graph_defs .= "CDEF:cdef" . generate_graph_def_name(strval($i)) . "=";
1274
/* prohibit command injection and provide platform specific quoting */
1275
$cdef_graph_defs .= cacti_escapeshellarg(sanitize_cdef($cdef_string), true);
1276
$cdef_graph_defs .= " \\\n";
1278
/* the CDEF cache is so we do not create duplicate CDEF's on a graph */
1279
$cdef_cache{$graph_item["cdef_id"]}{$graph_item["data_template_rrd_id"]}[$cf_id] = "$i";
1282
/* add the cdef string to the end of the def string */
1283
$graph_defs .= $cdef_graph_defs;
1285
/* note the current item_id for easy access */
1286
$graph_item_id = $graph_item["graph_templates_item_id"];
1288
/* if we are not displaying a legend there is no point in us even processing the auto padding,
1289
text format stuff. */
1290
if ((!isset($graph_data_array["graph_nolegend"])) && ($graph["auto_padding"] == "on")) {
1291
/* only applies to AREA, STACK and LINEs */
1292
if (preg_match("/(AREA|STACK|LINE[123])/", $graph_item_types{$graph_item["graph_type_id"]})) {
1293
$text_format_length = mb_strlen($graph_variables["text_format"][$graph_item_id], 'UTF-8');
1295
/* we are basing how much to pad on area and stack text format,
1296
not gprint. but of course the padding has to be displayed in gprint,
1299
$pad_number = ($greatest_text_format - $text_format_length);
1300
//cacti_log("MAX: $greatest_text_format, CURR: $text_format_lengths[$item_dsid], DSID: $item_dsid");
1301
$text_padding = str_pad("", $pad_number);
1303
/* two GPRINT's in a row screws up the padding, lets not do that */
1304
} else if (($graph_item_types{$graph_item["graph_type_id"]} == "GPRINT") && ($last_graph_type == "GPRINT")) {
1308
$last_graph_type = $graph_item_types{$graph_item["graph_type_id"]};
1311
/* we put this in a variable so it can be manipulated before mainly used
1312
if we want to skip it, like below */
1313
$current_graph_item_type = $graph_item_types{$graph_item["graph_type_id"]};
1315
/* IF this graph item has a data source... get a DEF name for it, or the cdef if that applies
1316
to this graph item */
1317
if ($graph_item["cdef_id"] == "0") {
1318
if (isset($cf_ds_cache{$graph_item["data_template_rrd_id"]}[$cf_id])) {
1319
$data_source_name = generate_graph_def_name(strval($cf_ds_cache{$graph_item["data_template_rrd_id"]}[$cf_id]));
1321
$data_source_name = "";
1324
$data_source_name = "cdef" . generate_graph_def_name(strval($cdef_cache{$graph_item["cdef_id"]}{$graph_item["data_template_rrd_id"]}[$cf_id]));
1327
/* to make things easier... if there is no text format set; set blank text */
1328
if (!isset($graph_variables["text_format"][$graph_item_id])) {
1329
$graph_variables["text_format"][$graph_item_id] = "";
1331
$graph_variables["text_format"][$graph_item_id] = str_replace('"', '\"', $graph_variables["text_format"][$graph_item_id]); /* escape doublequotes */
1334
if (!isset($hardreturn[$graph_item_id])) {
1335
$hardreturn[$graph_item_id] = "";
1338
/* +++++++++++++++++++++++ GRAPH ITEMS +++++++++++++++++++++++ */
1340
/* most of the calculations have been done above. now we have for print everything out
1341
in an RRDTool-friendly fashion */
1343
$need_rrd_nl = TRUE;
1345
if ($graph_item_types{$graph_item["graph_type_id"]} == "COMMENT") {
1346
# perform variable substitution first (in case this will yield an empty results or brings command injection problems)
1347
$comment_arg = rrd_substitute_host_query_data($graph_variables["text_format"][$graph_item_id], $graph, $graph_item);
1348
# next, compute the argument of the COMMENT statement and perform injection counter measures
1349
if (trim($comment_arg) == '') { # an empty COMMENT must be treated with care
1350
$comment_arg = cacti_escapeshellarg(' ' . $hardreturn[$graph_item_id]);
1352
$comment_arg = cacti_escapeshellarg($comment_arg . $hardreturn[$graph_item_id]);
1355
# create rrdtool specific command line
1356
if (read_config_option("rrdtool_version") != "rrd-1.0.x") {
1357
$txt_graph_items .= $graph_item_types{$graph_item["graph_type_id"]} . ":" . str_replace(":", "\:", $comment_arg) . " ";
1359
$txt_graph_items .= $graph_item_types{$graph_item["graph_type_id"]} . ":" . $comment_arg . " ";
1361
}elseif (($graph_item_types{$graph_item["graph_type_id"]} == "GPRINT") && (!isset($graph_data_array["graph_nolegend"]))) {
1362
$graph_variables["text_format"][$graph_item_id] = str_replace(":", "\:", $graph_variables["text_format"][$graph_item_id]); /* escape colons */
1363
$txt_graph_items .= $graph_item_types{$graph_item["graph_type_id"]} . ":" . $data_source_name . ":" . $consolidation_functions{$graph_item["consolidation_function_id"]} . ":" . cacti_escapeshellarg($text_padding . $graph_variables["text_format"][$graph_item_id] . $graph_item["gprint_text"] . $hardreturn[$graph_item_id]) . " ";
1364
}elseif (preg_match("/^(AREA|LINE[123]|STACK|HRULE|VRULE)$/", $graph_item_types{$graph_item["graph_type_id"]})) {
1366
/* initialize any color syntax for graph item */
1367
if (empty($graph_item["hex"])) {
1368
$graph_item_color_code = "";
1370
$graph_item_color_code = "#" . $graph_item["hex"];
1371
if (read_config_option("rrdtool_version") != "rrd-1.0.x") {
1372
$graph_item_color_code .= $graph_item["alpha"];
1376
if (preg_match("/^(AREA|LINE[123])$/", $graph_item_types{$graph_item["graph_type_id"]})) {
1377
$graph_item_stack_type = $graph_item_types{$graph_item["graph_type_id"]};
1378
$graph_variables["text_format"][$graph_item_id] = str_replace(":", "\:", $graph_variables["text_format"][$graph_item_id]); /* escape colons */
1379
$txt_graph_items .= $graph_item_types{$graph_item["graph_type_id"]} . ":" . $data_source_name . $graph_item_color_code . ":" . cacti_escapeshellarg($graph_variables["text_format"][$graph_item_id] . $hardreturn[$graph_item_id]) . " ";
1380
}elseif ($graph_item_types{$graph_item["graph_type_id"]} == "STACK") {
1381
if (read_config_option("rrdtool_version") != "rrd-1.0.x") {
1382
$graph_variables["text_format"][$graph_item_id] = str_replace(":", "\:", $graph_variables["text_format"][$graph_item_id]); /* escape colons */
1383
$txt_graph_items .= $graph_item_stack_type . ":" . $data_source_name . $graph_item_color_code . ":" . cacti_escapeshellarg($graph_variables["text_format"][$graph_item_id] . $hardreturn[$graph_item_id]) . ":STACK";
1385
$graph_variables["text_format"][$graph_item_id] = str_replace(":", "\:", $graph_variables["text_format"][$graph_item_id]); /* escape colons */
1386
$txt_graph_items .= $graph_item_types{$graph_item["graph_type_id"]} . ":" . $data_source_name . $graph_item_color_code . ":" . cacti_escapeshellarg($graph_variables["text_format"][$graph_item_id] . $hardreturn[$graph_item_id]) . " ";
1388
}elseif ($graph_item_types{$graph_item["graph_type_id"]} == "HRULE") {
1389
$graph_variables["text_format"][$graph_item_id] = str_replace(":", "\:", $graph_variables["text_format"][$graph_item_id]); /* escape colons */
1390
$graph_variables["value"][$graph_item_id] = str_replace(":", "\:", $graph_variables["value"][$graph_item_id]); /* escape colons */
1391
/* perform variable substitution; if this does not return a number, rrdtool will FAIL! */
1392
$substitute = rrd_substitute_host_query_data($graph_variables["value"][$graph_item_id], $graph, $graph_item);
1393
if (is_numeric($substitute)) {
1394
$graph_variables["value"][$graph_item_id] = $substitute;
1396
$txt_graph_items .= $graph_item_types{$graph_item["graph_type_id"]} . ":" . $graph_variables["value"][$graph_item_id] . $graph_item_color_code . ":" . cacti_escapeshellarg($graph_variables["text_format"][$graph_item_id] . $hardreturn[$graph_item_id]) . " ";
1397
}elseif ($graph_item_types{$graph_item["graph_type_id"]} == "VRULE") {
1398
$graph_variables["text_format"][$graph_item_id] = str_replace(":", "\:", $graph_variables["text_format"][$graph_item_id]); /* escape colons */
1400
if (substr_count($graph_item["value"], ":")) {
1401
$value_array = explode(":", $graph_item["value"]);
1403
if ($value_array[0] < 0) {
1404
$value = date("U") - (-3600 * $value_array[0]) - 60 * $value_array[1];
1406
$value = date("U", mktime($value_array[0],$value_array[1],0));
1408
}else if (is_numeric($graph_item["value"])) {
1409
$value = $graph_item["value"];
1412
$txt_graph_items .= $graph_item_types{$graph_item["graph_type_id"]} . ":" . $value . $graph_item_color_code . ":" . cacti_escapeshellarg($graph_variables["text_format"][$graph_item_id] . $hardreturn[$graph_item_id]) . " ";
1415
$need_rrd_nl = FALSE;
1420
if (($i < sizeof($graph_items)) && ($need_rrd_nl)) {
1421
$txt_graph_items .= RRD_NL;
1426
$graph_array = api_plugin_hook_function('rrd_graph_graph_options', array('graph_opts' => $graph_opts, 'graph_defs' => $graph_defs, 'txt_graph_items' => $txt_graph_items, 'graph_id' => $local_graph_id, 'start' => $graph_start, 'end' => $graph_end));
1427
if (!empty($graph_array)) {
1428
$graph_defs = $graph_array['graph_defs'];
1429
$txt_graph_items = $graph_array['txt_graph_items'];
1430
$graph_opts = $graph_array['graph_opts'];
1433
/* either print out the source or pass the source onto rrdtool to get us a nice PNG */
1434
if (isset($graph_data_array["print_source"])) {
1435
print "<PRE>" . htmlspecialchars(read_config_option("path_rrdtool") . " graph " . $graph_opts . $graph_defs . $txt_graph_items) . "</PRE>";
1437
if (isset($graph_data_array["export"])) {
1438
rrdtool_execute("graph $graph_opts$graph_defs$txt_graph_items", false, RRDTOOL_OUTPUT_NULL, $rrdtool_pipe);
1441
$graph_data_array = api_plugin_hook_function('prep_graph_array', $graph_data_array);
1443
if (isset($graph_data_array["output_flag"])) {
1444
$output_flag = $graph_data_array["output_flag"];
1446
$output_flag = RRDTOOL_OUTPUT_GRAPH_DATA;
1449
$output = rrdtool_execute("graph $graph_opts$graph_defs$txt_graph_items", false, $output_flag, $rrdtool_pipe);
1451
api_plugin_hook_function('rrdtool_function_graph_set_file', array('output' => $output, 'local_graph_id' => $local_graph_id, 'rra_id' => $rra_id));
1458
function rrdtool_function_xport($local_graph_id, $rra_id, $xport_data_array, &$xport_meta) {
1459
global $config, $consolidation_functions;
1461
include_once($config["library_path"] . "/cdef.php");
1462
include_once($config["library_path"] . "/graph_variables.php");
1463
include_once($config["library_path"] . "/xml.php");
1464
include($config["include_path"] . "/global_arrays.php");
1466
/* before we do anything; make sure the user has permission to view this graph,
1467
if not then get out */
1468
if ((read_config_option("auth_method") != 0) && (isset($_SESSION["sess_user_id"]))) {
1469
$access_denied = !(is_graph_allowed($local_graph_id));
1471
if ($access_denied == true) {
1472
return "GRAPH ACCESS DENIED";
1476
/* find the step and how often this graph is updated with new data */
1477
$ds_step = db_fetch_cell("select
1478
data_template_data.rrd_step
1479
from (data_template_data,data_template_rrd,graph_templates_item)
1480
where graph_templates_item.task_item_id=data_template_rrd.id
1481
and data_template_rrd.local_data_id=data_template_data.local_data_id
1482
and graph_templates_item.local_graph_id=$local_graph_id
1484
$ds_step = empty($ds_step) ? 300 : $ds_step;
1486
/* if no rra was specified, we need to figure out which one RRDTool will choose using
1487
* "best-fit" resolution fit algorithm */
1488
if (empty($rra_id)) {
1489
if ((empty($xport_data_array["graph_start"])) || (empty($xport_data_array["graph_end"]))) {
1492
$rra["timespan"] = 86400;
1494
/* get a list of RRAs related to this graph */
1495
$rras = get_associated_rras($local_graph_id);
1497
if (sizeof($rras) > 0) {
1498
foreach ($rras as $unchosen_rra) {
1499
/* the timespan specified in the RRA "timespan" field may not be accurate */
1500
$real_timespan = ($ds_step * $unchosen_rra["steps"] * $unchosen_rra["rows"]);
1502
/* make sure the current start/end times fit within each RRA's timespan */
1503
if ( (($xport_data_array["graph_end"] - $xport_data_array["graph_start"]) <= $real_timespan) && ((time() - $xport_data_array["graph_start"]) <= $real_timespan) ) {
1504
/* is this RRA better than the already chosen one? */
1505
if ((isset($rra)) && ($unchosen_rra["steps"] < $rra["steps"])) {
1506
$rra = $unchosen_rra;
1507
}else if (!isset($rra)) {
1508
$rra = $unchosen_rra;
1520
$rra = db_fetch_row("select timespan,rows,steps from rra where id=$rra_id");
1523
$seconds_between_graph_updates = ($ds_step * $rra["steps"]);
1525
/* override: graph start time */
1526
if ((!isset($xport_data_array["graph_start"])) || ($xport_data_array["graph_start"] == "0")) {
1527
$graph_start = -($rra["timespan"]);
1529
$graph_start = $xport_data_array["graph_start"];
1532
/* override: graph end time */
1533
if ((!isset($xport_data_array["graph_end"])) || ($xport_data_array["graph_end"] == "0")) {
1534
$graph_end = -($seconds_between_graph_updates);
1536
$graph_end = $xport_data_array["graph_end"];
1539
$graph = db_fetch_row("select
1540
graph_local.id AS local_graph_id,
1541
graph_local.host_id,
1542
graph_local.snmp_query_id,
1543
graph_local.snmp_index,
1544
graph_templates_graph.title_cache,
1545
graph_templates_graph.vertical_label,
1546
graph_templates_graph.slope_mode,
1547
graph_templates_graph.auto_scale,
1548
graph_templates_graph.auto_scale_opts,
1549
graph_templates_graph.auto_scale_log,
1550
graph_templates_graph.scale_log_units,
1551
graph_templates_graph.auto_scale_rigid,
1552
graph_templates_graph.auto_padding,
1553
graph_templates_graph.base_value,
1554
graph_templates_graph.upper_limit,
1555
graph_templates_graph.lower_limit,
1556
graph_templates_graph.height,
1557
graph_templates_graph.width,
1558
graph_templates_graph.image_format_id,
1559
graph_templates_graph.unit_value,
1560
graph_templates_graph.unit_exponent_value,
1561
graph_templates_graph.export
1562
from (graph_templates_graph,graph_local)
1563
where graph_local.id=graph_templates_graph.local_graph_id
1564
and graph_templates_graph.local_graph_id=$local_graph_id");
1566
/* lets make that sql query... */
1567
$xport_items = db_fetch_assoc("select
1568
graph_templates_item.id as graph_templates_item_id,
1569
graph_templates_item.cdef_id,
1570
graph_templates_item.text_format,
1571
graph_templates_item.value,
1572
graph_templates_item.hard_return,
1573
graph_templates_item.consolidation_function_id,
1574
graph_templates_item.graph_type_id,
1575
graph_templates_gprint.gprint_text,
1577
graph_templates_item.alpha,
1578
data_template_rrd.id as data_template_rrd_id,
1579
data_template_rrd.local_data_id,
1580
data_template_rrd.rrd_minimum,
1581
data_template_rrd.rrd_maximum,
1582
data_template_rrd.data_source_name,
1583
data_template_rrd.local_data_template_rrd_id
1584
from graph_templates_item
1585
left join data_template_rrd on (graph_templates_item.task_item_id=data_template_rrd.id)
1586
left join colors on (graph_templates_item.color_id=colors.id)
1587
left join graph_templates_gprint on (graph_templates_item.gprint_id=graph_templates_gprint.id)
1588
where graph_templates_item.local_graph_id=$local_graph_id
1589
order by graph_templates_item.sequence");
1591
/* +++++++++++++++++++++++ XPORT OPTIONS +++++++++++++++++++++++ */
1593
/* override: graph start time */
1594
if ((!isset($xport_data_array["graph_start"])) || ($xport_data_array["graph_start"] == "0")) {
1595
$xport_start = -($rra["timespan"]);
1597
$xport_start = $xport_data_array["graph_start"];
1600
/* override: graph end time */
1601
if ((!isset($xport_data_array["graph_end"])) || ($xport_data_array["graph_end"] == "0")) {
1602
$xport_end = -($seconds_between_graph_updates);
1604
$xport_end = $xport_data_array["graph_end"];
1607
/* basic export options */
1609
"--start=" . cacti_escapeshellarg($xport_start) . RRD_NL .
1610
"--end=" . cacti_escapeshellarg($xport_end) . RRD_NL .
1611
"--maxrows=10000" . RRD_NL;
1617
if (sizeof($xport_items) > 0) {
1618
/* we need to add a new column "cf_reference", so unless PHP 5 is used, this foreach syntax is required */
1619
foreach ($xport_items as $key => $xport_item) {
1620
/* mimic the old behavior: LINE[123], AREA, STACK and GPRINT items use the CF specified in the graph item */
1621
if (($xport_item["graph_type_id"] == GRAPH_ITEM_TYPE_LINE1) ||
1622
($xport_item["graph_type_id"] == GRAPH_ITEM_TYPE_LINE2) ||
1623
($xport_item["graph_type_id"] == GRAPH_ITEM_TYPE_LINE3) ||
1624
($xport_item["graph_type_id"] == GRAPH_ITEM_TYPE_AREA) ||
1625
($xport_item["graph_type_id"] == GRAPH_ITEM_TYPE_STACK)) {
1626
$xport_cf = $xport_item["consolidation_function_id"];
1627
$last_xport_cf["data_source_name"]["local_data_template_rrd_id"] = $xport_cf;
1628
/* remember this for second foreach loop */
1629
$xport_items[$key]["cf_reference"] = $xport_cf;
1630
}elseif ($xport_item["graph_type_id"] == GRAPH_ITEM_TYPE_GPRINT) {
1632
* the "CF" given on graph_item edit screen for GPRINT is indeed NOT a real "CF",
1633
* but an aggregation function
1634
* see "man rrdgraph_data" for the correct VDEF based notation
1635
* so our task now is to "guess" the very graph_item, this GPRINT is related to
1636
* and to use that graph_item's CF */
1637
if (isset($last_xport_cf["data_source_name"]["local_data_template_rrd_id"])) {
1638
$xport_cf = $last_xport_cf["data_source_name"]["local_data_template_rrd_id"];
1639
/* remember this for second foreach loop */
1640
$xport_items[$key]["cf_reference"] = $xport_cf;
1642
$xport_cf = generate_graph_best_cf($xport_item["local_data_id"], $xport_item["consolidation_function_id"]);
1643
/* remember this for second foreach loop */
1644
$xport_items[$key]["cf_reference"] = $xport_cf;
1647
/* all other types are based on the best matching CF */
1648
$xport_cf = generate_graph_best_cf($xport_item["local_data_id"], $xport_item["consolidation_function_id"]);
1649
/* remember this for second foreach loop */
1650
$xport_items[$key]["cf_reference"] = $xport_cf;
1653
if ((!empty($xport_item["local_data_id"])) &&
1654
(!isset($cf_ds_cache{$xport_item["data_template_rrd_id"]}[$xport_cf]))) {
1655
/* use a user-specified ds path if one is entered */
1656
$data_source_path = get_data_source_path($xport_item["local_data_id"], true);
1658
/* FOR WIN32: Escape all colon for drive letters (ex. D\:/path/to/rra) */
1659
$data_source_path = str_replace(":", "\:", $data_source_path);
1661
if (!empty($data_source_path)) {
1662
/* NOTE: (Update) Data source DEF names are created using the graph_item_id; then passed
1663
to a function that matches the digits with letters. rrdtool likes letters instead
1664
of numbers in DEF names; especially with CDEF's. cdef's are created
1665
the same way, except a 'cdef' is put on the beginning of the hash */
1666
$xport_defs .= "DEF:" . generate_graph_def_name(strval($i)) . "=" . cacti_escapeshellarg($data_source_path) . ":" . cacti_escapeshellarg($xport_item["data_source_name"], true) . ":" . $consolidation_functions[$xport_cf] . RRD_NL;
1668
$cf_ds_cache{$xport_item["data_template_rrd_id"]}[$xport_cf] = "$i";
1674
/* cache cdef value here to support data query variables in the cdef string */
1675
if (empty($xport_item["cdef_id"])) {
1676
$xport_item["cdef_cache"] = "";
1677
$xport_items[$j]["cdef_cache"] = "";
1679
$xport_item["cdef_cache"] = get_cdef($xport_item["cdef_id"]);
1680
$xport_items[$j]["cdef_cache"] = get_cdef($xport_item["cdef_id"]);
1683
/* +++++++++++++++++++++++ LEGEND: TEXT SUBSTITUTION (<>'s) +++++++++++++++++++++++ */
1685
/* note the current item_id for easy access */
1686
$xport_item_id = $xport_item["graph_templates_item_id"];
1688
/* the following fields will be searched for graph variables */
1689
$variable_fields = array(
1690
"text_format" => array(
1691
"process_no_legend" => false
1694
"process_no_legend" => true
1696
"cdef_cache" => array(
1697
"process_no_legend" => true
1701
/* loop through each field that we want to substitute values for:
1702
currently: text format and value */
1703
while (list($field_name, $field_array) = each($variable_fields)) {
1704
/* certain fields do not require values when the legend is not to be shown */
1705
if (($field_array["process_no_legend"] == false) && (isset($xport_data_array["graph_nolegend"]))) {
1709
$xport_variables[$field_name][$xport_item_id] = $xport_item[$field_name];
1711
/* date/time substitution */
1712
if (strstr($xport_variables[$field_name][$xport_item_id], "|date_time|")) {
1713
$xport_variables[$field_name][$xport_item_id] = str_replace("|date_time|", date('D d M H:i:s T Y', strtotime(db_fetch_cell("select value from settings where name='date'"))), $xport_variables[$field_name][$xport_item_id]);
1716
/* data query variables */
1717
$xport_variables[$field_name][$xport_item_id] = rrd_substitute_host_query_data($xport_variables[$field_name][$xport_item_id], $graph, $xport_item);
1719
/* Nth percentile */
1720
if (preg_match_all("/\|([0-9]{1,2}):(bits|bytes):(\d):(current|total|max|total_peak|all_max_current|all_max_peak|aggregate_max|aggregate_sum|aggregate_current|aggregate):(\d)?\|/", $xport_variables[$field_name][$xport_item_id], $matches, PREG_SET_ORDER)) {
1721
foreach ($matches as $match) {
1722
if ($field_name == "value") {
1723
$xport_meta["NthPercentile"][$nth]["format"] = $match[0];
1724
$xport_meta["NthPercentile"][$nth]["value"] = str_replace($match[0], variable_nth_percentile($match, $xport_item, $xport_items, $graph_start, $graph_end), $xport_variables[$field_name][$xport_item_id]);
1730
/* bandwidth summation */
1731
if (preg_match_all("/\|sum:(\d|auto):(current|total|atomic):(\d):(\d+|auto)\|/", $xport_variables[$field_name][$xport_item_id], $matches, PREG_SET_ORDER)) {
1732
foreach ($matches as $match) {
1733
if ($field_name == "text_format") {
1734
$xport_meta["Summation"][$sum]["format"] = $match[0];
1735
$xport_meta["Summation"][$sum]["value"] = str_replace($match[0], variable_bandwidth_summation($match, $xport_item, $xport_items, $graph_start, $graph_end, $rra["steps"], $ds_step), $xport_variables[$field_name][$xport_item_id]);
1746
/* +++++++++++++++++++++++ CDEF's +++++++++++++++++++++++ */
1750
reset($xport_items);
1752
$xport_item_stack_type = "";
1753
$txt_xport_items = "";
1754
$stacked_columns = array();
1756
if (sizeof($xport_items) > 0) {
1757
foreach ($xport_items as $xport_item) {
1758
/* first we need to check if there is a DEF for the current data source/cf combination. if so,
1760
if (isset($cf_ds_cache{$xport_item["data_template_rrd_id"]}{$xport_item["consolidation_function_id"]})) {
1761
$cf_id = $xport_item["consolidation_function_id"];
1763
/* if there is not a DEF defined for the current data source/cf combination, then we will have to
1764
improvise. choose the first available cf in the following order: AVERAGE, MAX, MIN, LAST */
1765
if (isset($cf_ds_cache{$xport_item["data_template_rrd_id"]}[1])) {
1766
$cf_id = 1; /* CF: AVERAGE */
1767
}elseif (isset($cf_ds_cache{$xport_item["data_template_rrd_id"]}[3])) {
1768
$cf_id = 3; /* CF: MAX */
1769
}elseif (isset($cf_ds_cache{$xport_item["data_template_rrd_id"]}[2])) {
1770
$cf_id = 2; /* CF: MIN */
1771
}elseif (isset($cf_ds_cache{$xport_item["data_template_rrd_id"]}[4])) {
1772
$cf_id = 4; /* CF: LAST */
1774
$cf_id = 1; /* CF: AVERAGE */
1777
/* now remember the correct CF reference */
1778
$cf_id = $xport_item["cf_reference"];
1780
/* make cdef string here; a note about CDEF's in cacti. A CDEF is neither unique to a
1781
data source of global cdef, but is unique when those two variables combine. */
1782
$cdef_xport_defs = ""; $cdef_all_ds_dups = ""; $cdef_similar_ds_dups = "";
1783
$cdef_similar_ds_nodups = ""; $cdef_all_ds_nodups = "";
1785
if ((!empty($xport_item["cdef_id"])) && (!isset($cdef_cache{$xport_item["cdef_id"]}{$xport_item["data_template_rrd_id"]}[$cf_id]))) {
1787
$cdef_string = $xport_variables["cdef_cache"]{$xport_item["graph_templates_item_id"]};
1788
$magic_item = array();
1789
$already_seen = array();
1790
$sources_seen = array();
1791
$count_all_ds_dups = 0;
1792
$count_all_ds_nodups = 0;
1793
$count_similar_ds_dups = 0;
1794
$count_similar_ds_nodups = 0;
1796
/* if any of those magic variables are requested ... */
1797
if (preg_match("/(ALL_DATA_SOURCES_(NO)?DUPS|SIMILAR_DATA_SOURCES_(NO)?DUPS)/", $cdef_string) ||
1798
preg_match("/(COUNT_ALL_DS_(NO)?DUPS|COUNT_SIMILAR_DS_(NO)?DUPS)/", $cdef_string)) {
1800
/* now walk through each case to initialize array*/
1801
if (preg_match("/ALL_DATA_SOURCES_DUPS/", $cdef_string)) {
1802
$magic_item["ALL_DATA_SOURCES_DUPS"] = "";
1804
if (preg_match("/ALL_DATA_SOURCES_NODUPS/", $cdef_string)) {
1805
$magic_item["ALL_DATA_SOURCES_NODUPS"] = "";
1807
if (preg_match("/SIMILAR_DATA_SOURCES_DUPS/", $cdef_string)) {
1808
$magic_item["SIMILAR_DATA_SOURCES_DUPS"] = "";
1810
if (preg_match("/SIMILAR_DATA_SOURCES_NODUPS/", $cdef_string)) {
1811
$magic_item["SIMILAR_DATA_SOURCES_NODUPS"] = "";
1813
if (preg_match("/COUNT_ALL_DS_DUPS/", $cdef_string)) {
1814
$magic_item["COUNT_ALL_DS_DUPS"] = "";
1816
if (preg_match("/COUNT_ALL_DS_NODUPS/", $cdef_string)) {
1817
$magic_item["COUNT_ALL_DS_NODUPS"] = "";
1819
if (preg_match("/COUNT_SIMILAR_DS_DUPS/", $cdef_string)) {
1820
$magic_item["COUNT_SIMILAR_DS_DUPS"] = "";
1822
if (preg_match("/COUNT_SIMILAR_DS_NODUPS/", $cdef_string)) {
1823
$magic_item["COUNT_SIMILAR_DS_NODUPS"] = "";
1826
/* loop over all graph items */
1827
for ($t=0;($t<count($xport_items));$t++) {
1829
/* only work on graph items, omit GRPINTs, COMMENTs and stuff */
1830
if ((preg_match("/(AREA|STACK|LINE[123])/", $graph_item_types{$xport_items[$t]["graph_type_id"]})) && (!empty($xport_items[$t]["data_template_rrd_id"]))) {
1831
/* if the user screws up CF settings, PHP will generate warnings if left unchecked */
1833
/* matching consolidation function? */
1834
if (isset($cf_ds_cache{$xport_items[$t]["data_template_rrd_id"]}[$cf_id])) {
1835
$def_name = generate_graph_def_name(strval($cf_ds_cache{$xport_items[$t]["data_template_rrd_id"]}[$cf_id]));
1837
/* do we need ALL_DATA_SOURCES_DUPS? */
1838
if (isset($magic_item["ALL_DATA_SOURCES_DUPS"])) {
1839
$magic_item["ALL_DATA_SOURCES_DUPS"] .= ($count_all_ds_dups == 0 ? "" : ",") . "TIME," . (time() - $seconds_between_graph_updates) . ",GT,$def_name,$def_name,UN,0,$def_name,IF,IF"; /* convert unknowns to '0' first */
1842
/* do we need COUNT_ALL_DS_DUPS? */
1843
if (isset($magic_item["COUNT_ALL_DS_DUPS"])) {
1844
$magic_item["COUNT_ALL_DS_DUPS"] .= ($count_all_ds_dups == 0 ? "" : ",") . "TIME," . (time() - $seconds_between_graph_updates) . ",GT,1,$def_name,UN,0,1,IF,IF"; /* convert unknowns to '0' first */
1847
$count_all_ds_dups++;
1849
/* check if this item also qualifies for NODUPS */
1850
if(!isset($already_seen[$def_name])) {
1851
if (isset($magic_item["ALL_DATA_SOURCES_NODUPS"])) {
1852
$magic_item["ALL_DATA_SOURCES_NODUPS"] .= ($count_all_ds_nodups == 0 ? "" : ",") . "TIME," . (time() - $seconds_between_graph_updates) . ",GT,$def_name,$def_name,UN,0,$def_name,IF,IF"; /* convert unknowns to '0' first */
1854
if (isset($magic_item["COUNT_ALL_DS_NODUPS"])) {
1855
$magic_item["COUNT_ALL_DS_NODUPS"] .= ($count_all_ds_nodups == 0 ? "" : ",") . "TIME," . (time() - $seconds_between_graph_updates) . ",GT,1,$def_name,UN,0,1,IF,IF"; /* convert unknowns to '0' first */
1857
$count_all_ds_nodups++;
1858
$already_seen[$def_name]=TRUE;
1861
/* check for SIMILAR data sources */
1862
if ($xport_item["data_source_name"] == $xport_items[$t]["data_source_name"]) {
1864
/* do we need SIMILAR_DATA_SOURCES_DUPS? */
1865
if (isset($magic_item["SIMILAR_DATA_SOURCES_DUPS"]) && ($xport_item["data_source_name"] == $xport_items[$t]["data_source_name"])) {
1866
$magic_item["SIMILAR_DATA_SOURCES_DUPS"] .= ($count_similar_ds_dups == 0 ? "" : ",") . "TIME," . (time() - $seconds_between_graph_updates) . ",GT,$def_name,$def_name,UN,0,$def_name,IF,IF"; /* convert unknowns to '0' first */
1869
/* do we need COUNT_SIMILAR_DS_DUPS? */
1870
if (isset($magic_item["COUNT_SIMILAR_DS_DUPS"]) && ($xport_item["data_source_name"] == $xport_items[$t]["data_source_name"])) {
1871
$magic_item["COUNT_SIMILAR_DS_DUPS"] .= ($count_similar_ds_dups == 0 ? "" : ",") . "TIME," . (time() - $seconds_between_graph_updates) . ",GT,1,$def_name,UN,0,1,IF,IF"; /* convert unknowns to '0' first */
1874
$count_similar_ds_dups++;
1876
/* check if this item also qualifies for NODUPS */
1877
if(!isset($sources_seen{$xport_items[$t]["data_template_rrd_id"]})) {
1878
if (isset($magic_item["SIMILAR_DATA_SOURCES_NODUPS"])) {
1879
$magic_item["SIMILAR_DATA_SOURCES_NODUPS"] .= ($count_similar_ds_nodups == 0 ? "" : ",") . "TIME," . (time() - $seconds_between_graph_updates) . ",GT,$def_name,$def_name,UN,0,$def_name,IF,IF"; /* convert unknowns to '0' first */
1881
if (isset($magic_item["COUNT_SIMILAR_DS_NODUPS"]) && ($xport_item["data_source_name"] == $xport_items[$t]["data_source_name"])) {
1882
$magic_item["COUNT_SIMILAR_DS_NODUPS"] .= ($count_similar_ds_nodups == 0 ? "" : ",") . "TIME," . (time() - $seconds_between_graph_updates) . ",GT,1,$def_name,UN,0,1,IF,IF"; /* convert unknowns to '0' first */
1884
$count_similar_ds_nodups++;
1885
$sources_seen{$xport_items[$t]["data_template_rrd_id"]} = TRUE;
1887
} # SIMILAR data sources
1888
} # matching consolidation function?
1889
} # only work on graph items, omit GRPINTs, COMMENTs and stuff
1890
} # loop over all graph items
1892
/* if there is only one item to total, don't even bother with the summation.
1893
* Otherwise cdef=a,b,c,+,+ is fine. */
1894
if ($count_all_ds_dups > 1 && isset($magic_item["ALL_DATA_SOURCES_DUPS"])) {
1895
$magic_item["ALL_DATA_SOURCES_DUPS"] .= str_repeat(",+", ($count_all_ds_dups - 2)) . ",+";
1897
if ($count_all_ds_nodups > 1 && isset($magic_item["ALL_DATA_SOURCES_NODUPS"])) {
1898
$magic_item["ALL_DATA_SOURCES_NODUPS"] .= str_repeat(",+", ($count_all_ds_nodups - 2)) . ",+";
1900
if ($count_similar_ds_dups > 1 && isset($magic_item["SIMILAR_DATA_SOURCES_DUPS"])) {
1901
$magic_item["SIMILAR_DATA_SOURCES_DUPS"] .= str_repeat(",+", ($count_similar_ds_dups - 2)) . ",+";
1903
if ($count_similar_ds_nodups > 1 && isset($magic_item["SIMILAR_DATA_SOURCES_NODUPS"])) {
1904
$magic_item["SIMILAR_DATA_SOURCES_NODUPS"] .= str_repeat(",+", ($count_similar_ds_nodups - 2)) . ",+";
1906
if ($count_all_ds_dups > 1 && isset($magic_item["COUNT_ALL_DS_DUPS"])) {
1907
$magic_item["COUNT_ALL_DS_DUPS"] .= str_repeat(",+", ($count_all_ds_dups - 2)) . ",+";
1909
if ($count_all_ds_nodups > 1 && isset($magic_item["COUNT_ALL_DS_NODUPS"])) {
1910
$magic_item["COUNT_ALL_DS_NODUPS"] .= str_repeat(",+", ($count_all_ds_nodups - 2)) . ",+";
1912
if ($count_similar_ds_dups > 1 && isset($magic_item["COUNT_SIMILAR_DS_DUPS"])) {
1913
$magic_item["COUNT_SIMILAR_DS_DUPS"] .= str_repeat(",+", ($count_similar_ds_dups - 2)) . ",+";
1915
if ($count_similar_ds_nodups > 1 && isset($magic_item["COUNT_SIMILAR_DS_NODUPS"])) {
1916
$magic_item["COUNT_SIMILAR_DS_NODUPS"] .= str_repeat(",+", ($count_similar_ds_nodups - 2)) . ",+";
1920
$cdef_string = str_replace("CURRENT_DATA_SOURCE", generate_graph_def_name(strval((isset($cf_ds_cache{$xport_item["data_template_rrd_id"]}[$cf_id]) ? $cf_ds_cache{$xport_item["data_template_rrd_id"]}[$cf_id] : "0"))), $cdef_string);
1922
/* ALL|SIMILAR_DATA_SOURCES(NO)?DUPS are to be replaced here */
1923
if (isset($magic_item["ALL_DATA_SOURCES_DUPS"])) {
1924
$cdef_string = str_replace("ALL_DATA_SOURCES_DUPS", $magic_item["ALL_DATA_SOURCES_DUPS"], $cdef_string);
1926
if (isset($magic_item["ALL_DATA_SOURCES_NODUPS"])) {
1927
$cdef_string = str_replace("ALL_DATA_SOURCES_NODUPS", $magic_item["ALL_DATA_SOURCES_NODUPS"], $cdef_string);
1929
if (isset($magic_item["SIMILAR_DATA_SOURCES_DUPS"])) {
1930
$cdef_string = str_replace("SIMILAR_DATA_SOURCES_DUPS", $magic_item["SIMILAR_DATA_SOURCES_DUPS"], $cdef_string);
1932
if (isset($magic_item["SIMILAR_DATA_SOURCES_NODUPS"])) {
1933
$cdef_string = str_replace("SIMILAR_DATA_SOURCES_NODUPS", $magic_item["SIMILAR_DATA_SOURCES_NODUPS"], $cdef_string);
1936
/* COUNT_ALL|SIMILAR_DATA_SOURCES(NO)?DUPS are to be replaced here */
1937
if (isset($magic_item["COUNT_ALL_DS_DUPS"])) {
1938
$cdef_string = str_replace("COUNT_ALL_DS_DUPS", $magic_item["COUNT_ALL_DS_DUPS"], $cdef_string);
1940
if (isset($magic_item["COUNT_ALL_DS_NODUPS"])) {
1941
$cdef_string = str_replace("COUNT_ALL_DS_NODUPS", $magic_item["COUNT_ALL_DS_NODUPS"], $cdef_string);
1943
if (isset($magic_item["COUNT_SIMILAR_DS_DUPS"])) {
1944
$cdef_string = str_replace("COUNT_SIMILAR_DS_DUPS", $magic_item["COUNT_SIMILAR_DS_DUPS"], $cdef_string);
1946
if (isset($magic_item["COUNT_SIMILAR_DS_NODUPS"])) {
1947
$cdef_string = str_replace("COUNT_SIMILAR_DS_NODUPS", $magic_item["COUNT_SIMILAR_DS_NODUPS"], $cdef_string);
1950
/* data source item variables */
1951
$cdef_string = str_replace("CURRENT_DS_MINIMUM_VALUE", (empty($xport_item["rrd_minimum"]) ? "0" : $xport_item["rrd_minimum"]), $cdef_string);
1952
$cdef_string = str_replace("CURRENT_DS_MAXIMUM_VALUE", (empty($xport_item["rrd_maximum"]) ? "0" : $xport_item["rrd_maximum"]), $cdef_string);
1953
$cdef_string = str_replace("CURRENT_GRAPH_MINIMUM_VALUE", (empty($graph["lower_limit"]) ? "0" : $graph["lower_limit"]), $cdef_string);
1954
$cdef_string = str_replace("CURRENT_GRAPH_MAXIMUM_VALUE", (empty($graph["upper_limit"]) ? "0" : $graph["upper_limit"]), $cdef_string);
1956
/* replace query variables in cdefs */
1957
$cdef_string = rrd_substitute_host_query_data($cdef_string, $graph, $xport_item);
1959
/* make the initial "virtual" cdef name: 'cdef' + [a,b,c,d...] */
1960
$cdef_xport_defs .= "CDEF:cdef" . generate_graph_def_name(strval($i)) . "=";
1961
/* prohibit command injection and provide platform specific quoting */
1962
$cdef_xport_defs .= cacti_escapeshellarg(sanitize_cdef($cdef_string), true);
1963
$cdef_xport_defs .= " \\\n";
1965
/* the CDEF cache is so we do not create duplicate CDEF's on a graph */
1966
$cdef_cache{$xport_item["cdef_id"]}{$xport_item["data_template_rrd_id"]}[$cf_id] = "$i";
1969
/* add the cdef string to the end of the def string */
1970
$xport_defs .= $cdef_xport_defs;
1972
/* note the current item_id for easy access */
1973
$xport_item_id = $xport_item["graph_templates_item_id"];
1975
/* IF this graph item has a data source... get a DEF name for it, or the cdef if that applies
1976
to this graph item */
1977
if ($xport_item["cdef_id"] == "0") {
1978
if (isset($cf_ds_cache{$xport_item["data_template_rrd_id"]}[$cf_id])) {
1979
$data_source_name = generate_graph_def_name(strval($cf_ds_cache{$xport_item["data_template_rrd_id"]}[$cf_id]));
1981
$data_source_name = "";
1984
$data_source_name = "cdef" . generate_graph_def_name(strval($cdef_cache{$xport_item["cdef_id"]}{$xport_item["data_template_rrd_id"]}[$cf_id]));
1987
/* +++++++++++++++++++++++ XPORT ITEMS +++++++++++++++++++++++ */
1989
$need_rrd_nl = TRUE;
1990
if (preg_match("/^(AREA|LINE[123]|STACK)$/", $graph_item_types{$xport_item["graph_type_id"]})) {
1991
/* give all export items a name */
1992
if (trim($xport_variables["text_format"][$xport_item_id]) == "") {
1993
$legend_name = "col" . $j . "-" . $data_source_name;
1995
$legend_name = $xport_variables["text_format"][$xport_item_id];
1997
$stacked_columns["col" . $j] = ($graph_item_types{$xport_item["graph_type_id"]} == "STACK") ? 1 : 0;
2000
$txt_xport_items .= "XPORT:" . cacti_escapeshellarg($data_source_name) . ":" . str_replace(":", "", cacti_escapeshellarg($legend_name)) ;
2002
$need_rrd_nl = FALSE;
2007
if (($i < sizeof($xport_items)) && ($need_rrd_nl)) {
2008
$txt_xport_items .= RRD_NL;
2013
$output_flag = RRDTOOL_OUTPUT_STDOUT;
2015
$xport_array = rrdxport2array(rrdtool_execute("xport $xport_opts$xport_defs$txt_xport_items", false, $output_flag));
2017
/* add host and graph information */
2018
$xport_array["meta"]["stacked_columns"]= $stacked_columns;
2019
$xport_array["meta"]["title_cache"] = cacti_escapeshellarg($graph["title_cache"]);
2020
$xport_array["meta"]["vertical_label"] = cacti_escapeshellarg($graph["vertical_label"]);
2021
$xport_array["meta"]["local_graph_id"] = $local_graph_id;
2022
$xport_array["meta"]["host_id"] = $graph["host_id"];
2024
return $xport_array;
2027
function rrdtool_set_font($type, $no_legend = "") {
2030
if (read_graph_config_option("custom_fonts") == "on") {
2031
$font = read_graph_config_option($type . "_font");
2032
$size = read_graph_config_option($type . "_size");
2034
$font = read_config_option($type . "_font");
2035
$size = read_config_option($type . "_size");
2039
/* do some simple checks */
2040
if (read_config_option("rrdtool_version") == "rrd-1.0.x" ||
2041
read_config_option("rrdtool_version") == "rrd-1.2.x") { # rrdtool 1.0 and 1.2 use font files
2042
if (!is_file($font)) {
2045
} else { # rrdtool 1.3+ use fontconfig
2046
/* verifying all possible pango font params is too complex to be tested here
2047
* so we only escape the font
2049
$font = cacti_escapeshellarg($font);
2053
if ($type == "title") {
2054
if (!empty($no_legend)) {
2055
$size = $size * .70;
2056
}elseif (($size <= 4) || ($size == "")) {
2059
}else if (($size <= 4) || ($size == "")) {
2063
return "--font " . strtoupper($type) . ":" . $size . ":" . $font . RRD_NL;
2066
function rrd_substitute_host_query_data($txt_graph_item, $graph, $graph_item) {
2067
/* replace host variables in graph elements */
2069
if (empty($graph["host_id"])) {
2070
/* if graph has no associated host determine host_id from graph item data source */
2071
if (!empty($graph_item["local_data_id"])) {
2072
$host_id = db_fetch_cell("select host_id from data_local where id='" . $graph_item["local_data_id"] . "'");
2075
$host_id = $graph["host_id"];
2077
$txt_graph_item = substitute_host_data($txt_graph_item, '|','|', $host_id);
2079
/* replace query variables in graph elements */
2080
if (preg_match("/\|query_[a-zA-Z0-9_]+\|/", $txt_graph_item)) {
2081
/* default to the graph data query information from the graph */
2082
if (empty($graph_item["local_data_id"])) {
2083
$txt_graph_item = substitute_snmp_query_data($txt_graph_item, $graph["host_id"], $graph["snmp_query_id"], $graph["snmp_index"]);
2084
/* use the data query information from the data source if possible */
2086
$data_local = db_fetch_row("select snmp_index,snmp_query_id,host_id from data_local where id='" . $graph_item["local_data_id"] . "'");
2087
$txt_graph_item = substitute_snmp_query_data($txt_graph_item, $data_local["host_id"], $data_local["snmp_query_id"], $data_local["snmp_index"]);
2091
/* replace query variables in graph elements */
2092
if (preg_match("/\|input_[a-zA-Z0-9_]+\|/", $txt_graph_item)) {
2093
return substitute_data_input_data($txt_graph_item, $graph, $graph_item["local_data_id"]);
2096
return $txt_graph_item;