#!/usr/bin/perl
+# Copyright (C) 2008-2011 Florian Forster
+# Copyright (C) 2011 noris network AG
+#
+# 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.
+#
+# Authors:
+# Florian "octo" Forster <octo at collectd.org>
+
use strict;
use warnings;
-use lib ('../lib');
+use utf8;
+use vars (qw($BASE_DIR));
+
+BEGIN
+{
+ if (defined $ENV{'SCRIPT_FILENAME'})
+ {
+ if ($ENV{'SCRIPT_FILENAME'} =~ m{^(/.+)/bin/[^/]+$})
+ {
+ $::BASE_DIR = $1;
+ unshift (@::INC, "$::BASE_DIR/lib");
+ }
+ }
+}
-use FindBin ('$RealBin');
use Carp (qw(confess cluck));
use CGI (':cgi');
use RRDs ();
+use File::Temp (':POSIX');
use Collectd::Graph::Config (qw(gc_read_config gc_get_scalar));
use Collectd::Graph::TypeLoader (qw(tl_load_type));
epoch_to_rfc1123 flush_files));
use Collectd::Graph::Type ();
-our $Debug = param ('debug');
-our $Begin = param ('begin');
-our $End = param ('end');
-our $GraphWidth = param ('width');
-our $OutputFormat = 'PNG';
-our $ContentType = 'image/png';
-
-if (param ('format'))
+sub base_dir
{
- my $temp = param ('format') || '';
- $temp = uc ($temp);
+ if (defined $::BASE_DIR)
+ {
+ return ($::BASE_DIR);
+ }
- if ($temp =~ m/^(PNG|SVG|EPS|PDF)$/)
+ if (!defined ($ENV{'SCRIPT_FILENAME'}))
{
- $OutputFormat = $temp;
+ return;
+ }
- if ($OutputFormat eq 'SVG') { $ContentType = 'image/svg+xml'; }
- elsif ($OutputFormat eq 'EPS') { $ContentType = 'image/eps'; }
- elsif ($OutputFormat eq 'PDF') { $ContentType = 'application/pdf'; }
+ if ($ENV{'SCRIPT_FILENAME'} =~ m{^(/.+)/bin/[^/]+$})
+ {
+ $::BASE_DIR = $1;
+ return ($::BASE_DIR);
}
+
+ return;
}
-if ($Debug)
+sub lib_dir
{
- print <<HTTP;
-Content-Type: text/plain
+ my $base = base_dir ();
-HTTP
+ if ($base)
+ {
+ return "$base/lib";
+ }
+ else
+ {
+ return "../lib";
+ }
}
-gc_read_config ("$RealBin/../etc/collection.conf");
-
-if ($GraphWidth)
+sub sysconf_dir
{
- $GraphWidth =~ s/\D//g;
+ my $base = base_dir ();
+
+ if ($base)
+ {
+ return "$base/etc";
+ }
+ else
+ {
+ return "../etc";
+ }
}
-if (!$GraphWidth)
+sub init
{
- $GraphWidth = gc_get_scalar ('GraphWidth', 400);
+ my $lib_dir = lib_dir ();
+ my $sysconf_dir = sysconf_dir ();
+
+ if (!grep { $lib_dir eq $_ } (@::INC))
+ {
+ unshift (@::INC, $lib_dir);
+ }
+
+ gc_read_config ("$sysconf_dir/collection.conf");
}
-{ # Sanitize begin and end times
- $End ||= 0;
- $Begin ||= 0;
+sub main
+{
+ my $Begin = param ('begin');
+ my $End = param ('end');
+ my $GraphWidth = param ('width');
+ my $GraphHeight = param ('height');
+ my $Index = param ('index') || 0;
+ my $OutputFormat = 'PNG';
+ my $ContentType = 'image/png';
+
+ init ();
- if ($End =~ m/\D/)
+ if (param ('format'))
{
- $End = 0;
+ my $temp = param ('format') || '';
+ $temp = uc ($temp);
+
+ if ($temp =~ m/^(PNG|SVG|EPS|PDF)$/)
+ {
+ $OutputFormat = $temp;
+
+ if ($OutputFormat eq 'SVG') { $ContentType = 'image/svg+xml'; }
+ elsif ($OutputFormat eq 'EPS') { $ContentType = 'image/eps'; }
+ elsif ($OutputFormat eq 'PDF') { $ContentType = 'application/pdf'; }
+ }
}
- if (!$Begin || !($Begin =~ m/^-?([1-9][0-9]*)$/))
+ if (param ('debug'))
{
- $Begin = -86400;
+ print <<HTTP;
+Content-Type: text/plain
+
+HTTP
+ $ContentType = 'text/plain';
}
- if ($Begin < 0)
+ if ($GraphWidth)
{
- if ($End)
- {
- $Begin = $End + $Begin;
- }
- else
- {
- $Begin = time () + $Begin;
- }
+ $GraphWidth =~ s/\D//g;
}
- if ($Begin < 0)
+ if (!$GraphWidth)
{
- $Begin = time () - 86400;
+ $GraphWidth = gc_get_scalar ('GraphWidth', 400);
}
- if (($End > 0) && ($Begin > $End))
+ if ($GraphHeight)
{
- my $temp = $End;
- $End = $Begin;
- $Begin = $temp;
+ $GraphHeight =~ s/\D//g;
}
-}
-my $type = param ('type') or die;
-my $obj;
+ if (!$GraphHeight)
+ {
+ $GraphHeight = gc_get_scalar ('GraphHeight', 100);
+ }
-$obj = tl_load_type ($type);
-if (!$obj)
-{
- confess ("tl_load_type ($type) failed");
-}
+ { # Sanitize begin and end times
+ $End ||= 0;
+ $Begin ||= 0;
-$type = ucfirst (lc ($type));
-$type =~ s/_([A-Za-z])/\U$1\E/g;
-$type = sanitize_type ($type);
+ if ($End =~ m/\D/)
+ {
+ $End = 0;
+ }
-my $files = get_selected_files ();
-if ($Debug)
-{
- require Data::Dumper;
- print STDOUT Data::Dumper->Dump ([$files], ['files']);
-}
-for (@$files)
-{
- $obj->addFiles ($_);
-}
+ if (!$Begin || !($Begin =~ m/^-?([1-9][0-9]*)$/))
+ {
+ $Begin = -86400;
+ }
-my $expires = time ();
-# IF (End is `now')
-# OR (Begin is before `now' AND End is after `now')
-if (($End == 0) || (($Begin <= $expires) && ($End >= $expires)))
-{
- # 400 == width in pixels
- my $timespan;
+ if ($Begin < 0)
+ {
+ if ($End)
+ {
+ $Begin = $End + $Begin;
+ }
+ else
+ {
+ $Begin = time () + $Begin;
+ }
+ }
+
+ if ($Begin < 0)
+ {
+ $Begin = time () - 86400;
+ }
+
+ if (($End > 0) && ($Begin > $End))
+ {
+ my $temp = $End;
+ $End = $Begin;
+ $Begin = $temp;
+ }
+ }
- if ($End == 0)
+ my $type = param ('type') or die;
+ my $obj;
+
+ $obj = tl_load_type ($type);
+ if (!$obj)
{
- $timespan = $expires - $Begin;
+ confess ("tl_load_type ($type) failed");
}
- else
+
+ $type = ucfirst (lc ($type));
+ $type =~ s/_([A-Za-z])/\U$1\E/g;
+ $type = sanitize_type ($type);
+
+ my $files = get_selected_files ();
+ if (param ('debug'))
{
- $timespan = $End - $Begin;
+ require Data::Dumper;
+ print Data::Dumper->Dump ([$files], ['files']);
+ }
+ for (@$files)
+ {
+ $obj->addFiles ($_);
+ }
+
+ my $expires = time ();
+# IF (End is `now')
+# OR (Begin is before `now' AND End is after `now')
+ if (($End == 0) || (($Begin <= $expires) && ($End >= $expires)))
+ {
+ # 400 == width in pixels
+ my $timespan;
+
+ if ($End == 0)
+ {
+ $timespan = $expires - $Begin;
+ }
+ else
+ {
+ $timespan = $End - $Begin;
+ }
+ $expires += int ($timespan / 400.0);
}
- $expires += int ($timespan / 400.0);
-}
# IF (End is not `now')
# AND (End is before `now')
# ==> Graph will never change again!
-elsif (($End > 0) && ($End < $expires))
-{
- $expires += (366 * 86400);
-}
-elsif ($Begin > $expires)
-{
- $expires = $Begin;
-}
+ elsif (($End > 0) && ($End < $expires))
+ {
+ $expires += (366 * 86400);
+ }
+ elsif ($Begin > $expires)
+ {
+ $expires = $Begin;
+ }
# Send FLUSH command to the daemon if necessary and possible.
-flush_files ($files,
+ flush_files ($files,
begin => $Begin,
end => $End,
addr => gc_get_scalar ('UnixSockAddr', undef),
interval => gc_get_scalar ('Interval', 10));
-print STDOUT header (-Content_type => $ContentType,
- -Last_Modified => epoch_to_rfc1123 ($obj->getLastModified ()),
- -Expires => epoch_to_rfc1123 ($expires));
-
-if ($Debug)
-{
- print "\$expires = $expires;\n";
-}
+ print header (-Content_type => $ContentType,
+ -Last_Modified => epoch_to_rfc1123 ($obj->getLastModified ()),
+ -Expires => epoch_to_rfc1123 ($expires));
-my $args = $obj->getRRDArgs (0);
-
-if ($Debug)
-{
- require Data::Dumper;
- print STDOUT Data::Dumper->Dump ([$obj], ['obj']);
- print STDOUT join (",\n", @$args) . "\n";
- print STDOUT "Last-Modified: " . epoch_to_rfc1123 ($obj->getLastModified ()) . "\n";
-}
-else
-{
- my @timesel = ();
+ if (param ('debug'))
+ {
+ print "\$expires = $expires;\n";
+ }
- if ($End) # $Begin is always true
+ my $args = $obj->getRRDArgs (0 + $Index);
+ if (param ('debug'))
{
- @timesel = ('-s', $Begin, '-e', $End);
+ require Data::Dumper;
+ print Data::Dumper->Dump ([$obj], ['obj']);
+ print join (",\n", @$args) . "\n";
+ print "Last-Modified: " . epoch_to_rfc1123 ($obj->getLastModified ()) . "\n";
}
else
{
- @timesel = ('-s', $Begin); # End is implicitely `now'.
- }
+ my @timesel = ();
+ my $tmpfile = tmpnam ();
+ my $status;
- $| = 1;
- RRDs::graph ('-', '-a', $OutputFormat, '--width', $GraphWidth, @timesel, @$args);
- if (my $err = RRDs::error ())
- {
- print STDERR "RRDs::graph failed: $err\n";
- exit (1);
+ if ($End) # $Begin is always true
+ {
+ @timesel = ('-s', $Begin, '-e', $End);
+ }
+ else
+ {
+ @timesel = ('-s', $Begin); # End is implicitely `now'.
+ }
+
+ if (-S "/var/run/rrdcached.sock" && -w "/var/run/rrdcached.sock")
+ {
+ $ENV{"RRDCACHED_ADDRESS"} = "/var/run/rrdcached.sock";
+ }
+ unlink ($tmpfile);
+ RRDs::graph ($tmpfile, '-a', $OutputFormat, '--width', $GraphWidth, '--height', $GraphHeight, @timesel, @$args);
+ if (my $err = RRDs::error ())
+ {
+ print STDERR "RRDs::graph failed: $err\n";
+ exit (1);
+ }
+
+ $status = open (IMG, '<', $tmpfile) or die ("open ($tmpfile): $!");
+ if (!$status)
+ {
+ print STDERR "graph.cgi: Unable to open temporary file \"$tmpfile\" for reading: $!\n";
+ }
+ else
+ {
+ local $/ = undef;
+ while (my $data = <IMG>)
+ {
+ print STDOUT $data;
+ }
+
+ close (IMG);
+ unlink ($tmpfile);
+ }
}
-}
+} # sub main
-exit (0);
+main ();
# vim: set shiftwidth=2 softtabstop=2 tabstop=8 :