#!/usr/bin/env perl # # Monitorix - A lightweight system monitoring tool. # # Copyright (C) 2005-2013 by Jordi Sanfeliu # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # require 5.006; use strict; use warnings; use FindBin qw($Bin); use lib $Bin . "/lib", "/usr/lib/monitorix"; use Monitorix; use HTTPServer; use POSIX qw(WNOHANG LC_TIME setlocale uname pause setsid); use Config::General; use Getopt::Std; use Cwd qw(abs_path); # Force a standard locale $ENV{LANG} = ""; setlocale(LC_TIME, "C"); $SIG{'INT' } = 'INT_handler'; $SIG{'ABRT'} = 'INT_handler'; $SIG{'QUIT'} = 'INT_handler'; $SIG{'TRAP'} = 'INT_handler'; $SIG{'STOP'} = 'INT_handler'; $SIG{'TERM'} = 'INT_handler'; $SIG{'CHLD'} = 'CHLD_handler'; $SIG{'HUP' } = 'HUP_handler'; $SIG{'ALRM'} = 'ALRM_handler'; use constant VERSION => "3.1.93"; use constant RELDATE => "09-May-2013"; my @suppsys = ("Linux", "FreeBSD", "OpenBSD", "NetBSD"); our %config; our %options; sub INT_handler { my ($signal) = @_; logger("SIG$signal caught."); flush_accounting_rules(\%config, $options{d}); if(lc($config{httpd_builtin}->{enabled} eq "y")) { kill(15, $config{httpd_pid}); } logger("Exiting."); exit(0); } sub CHLD_handler { my $pid = waitpid(-1, WNOHANG); } sub HUP_handler { my ($signal) = @_; my $myself = (caller(0))[3]; my (undef, undef, $uid) = getpwnam($config{httpd_builtin}->{user}); my (undef, undef, $gid) = getgrnam($config{httpd_builtin}->{group}); logger("SIG$signal caught."); # upon receiving a SIGHUP signal the logfile is re-opened close(STDOUT); close(STDERR); open(STDOUT, ">> $config{log_file}") || logger("Can't write to LOG: $!"); open(STDERR, ">> $config{log_file}") || logger("Can't write to LOG: $!"); logger("$myself: reopening log file."); # create the HTTPd logfile open(OUT, "> " . $config{httpd_builtin}->{log_file}); close(OUT); chown($uid, $gid, $config{httpd_builtin}->{log_file}); } sub ALRM_handler { my $myself = (caller(0))[3]; my ($sec, $min, $hour, $mday) = localtime(time); # call all enabled graphs on every minute if($sec == 0) { foreach my $f (@{$config{func_update}}) { my $update = $f . "_update"; my $d = $f; logger("$myself: calling $update()") unless !$options{d}; undef($d) if(!grep {trim($_) eq $d} (@{$config{debug}})); if(defined($options{d}) && $options{d} eq "all") { $d = $f; } { no strict "refs"; eval { &$update($f, \%config, $d); }; if($@) { logger("$myself: $update(): $@"); } } } if(lc($config{traffacct}->{enabled}) eq "y" && lc($config{traffacct}->{reports}->{enabled}) eq "y") { my $d = "traffacct"; undef($d) if(!grep {trim($_) eq $d} (@{$config{debug}})); # at 00:00h if($min == 0 && $hour == 0) { # collect traffic accounting every day eval { traffacct::traffacct_getcounters(\%config, $d); }; if($@) { logger("$myself: traffacct::traffacct_getcounters(): $@"); } # send reports every first day of a month if($mday == 1) { eval { traffacct::traffacct_sendreports(\%config, $d); }; if($@) { logger("$myself: traffacct::traffacct_sendreports(): $@"); } } } } } alarm(1); } sub daemonize { chdir("/") || die "Can't chdir to /: $!"; open(STDIN, "< /dev/null") || die "Can't read /dev/null: $!"; open(STDOUT, ">> $config{log_file}") || die "Can't write to LOG: $!"; umask(022) || die "Unable to umask 022: $!"; exit if fork(); # parent exits (setsid() != -1) || die "Can't start a new session: $!"; open(STDERR, ">> $config{log_file}") || die "Can't write to LOG: $!"; } sub usage { print(STDERR << "EOF"); Usage: monitorix -c configfile [-p pidfile] [-d none | graph[,graph] | all ] [-v] EOF exit(1); } sub create_index { my $myself = (caller(0))[3]; my $n; my $gname; my $theme = $config{theme}; my $bgcolor; my $table_back_color; my $title_back_color; my $title_fore_color; # force to only one trailing slash (my $base_url = $config{base_url}) =~ s/\/*$/\//; (my $base_cgi = $config{base_cgi}) =~ s/\/*$/\//; if($theme eq "black") { $bgcolor = $config{$theme}->{main_bg}; $table_back_color = $config{$theme}->{graph_bg}; $title_back_color = $config{$theme}->{title_bg}; $title_fore_color = $config{$theme}->{title_fg}; } elsif(!$theme || $theme eq "white") { $bgcolor = "#ffffff"; $table_back_color = "#CCCCCC"; $title_back_color = "#777777"; $title_fore_color = "#CCCC00"; } else { logger("$myself: ERROR: invalid value in 'theme' option") unless !$options{d}; } if(!open(OUT, "> $config{base_dir}/index.html")) { die "unable to create '${config{base_dir}}index.html': $!"; } print(OUT < $config{title}


v@{[VERSION]}

EOF print(OUT " \n"); print(OUT " \n"); print(OUT <
 Hostname   Graph 
\n"); print(OUT " \n"); print(OUT " \n"); print(OUT " \n"); print(OUT "

Daily  Weekly  Monthly  Yearly 

EOF close(OUT); } # Main # ---------------------------------------------------------------------------- getopts("d:vc:p:", \%options) || usage(); if($options{v}) { print("Monitorix version " . VERSION . " (" . RELDATE . ")\n"); print("by Jordi Sanfeliu \n"); print("http://www.monitorix.org/\n\n"); exit(0); } if(!$options{c}) { usage(); exit(1); } $options{c} = abs_path($options{c}) unless $^V lt 5.6.2; if(!stat($options{c})) { die "can't open file '$options{c}': $!"; } # load configuration file my $conf = new Config::General( -ConfigFile => $options{c}, ); %config = $conf->getall; $config{debug} = (); $config{func_update} = (); # get the current OS and kernel version and check its support my $release; ($config{os}, undef, $release) = uname(); my ($major, $minor) = split('\.', $release); $minor =~ m/^(\d+)/; $config{kernel} = $major . "." . $1; if(!grep {$_ eq $config{os}} @suppsys) { die "FATAL: your operating system ($config{os}) is not supported."; } if(grep {$_ eq $config{os}} ("FreeBSD", "OpenBSD", "NetBSD")) { $SIG{'CHLD'} = 'DEFAULT'; } $0 = sprintf("%s %s%s%s%s", $^V lt 5.6.2 ? "monitorix" : abs_path($0), $options{c} ? "-c $options{c}" : "", $options{p} ? " -p $options{p}" : "", $options{d} ? " -d $options{d}" : "", $options{v} ? " -v" : ""); daemonize(); logger("Starting Monitorix version " . VERSION . " (pid $$)."); if($options{p}) { $options{p} = abs_path($options{p}); open(OUT, "> $options{p}") || die "could not open '$options{p}' for writing: $!"; print(OUT "$$"); close(OUT); } # change to a safety directory unless(chdir("/tmp")) { die "can't chdir to /tmp: $!"; } if($options{d}) { if($options{d} ne "none" && $options{d} ne "all") { @{$config{debug}} = split(',', $options{d}); foreach my $t (@{$config{debug}}) { if(!grep {trim($_) eq $t} (split(',', $config{graph_name} . ", traffacct"))) { die "Invalid debug key '$t'"; } } } logger("Entering in debug mode."); logger("Changed process name to '$0'."); } # save the path of the configuration file if(open(OUT, "> " . $config{base_dir} . "/cgi/monitorix.conf.path")) { print(OUT "$options{c}\n"); close(OUT); } else { logger("Unable to create the file '$config{base_dir}/cgi/monitorix.conf.path'."); } flush_accounting_rules(\%config, $options{d}); logger("Initializing graphs.") unless !$options{d}; foreach (split(',', $config{graph_name} . ", traffacct")) { my $g = trim($_); my $e = "n"; if($g eq "traffacct") { $e = lc($config{$g}->{enabled}); } else { $e = lc($config{graph_enable}->{$g}); } if($e eq "y") { my $init = $g . "_init"; my $d = $g; undef($d) if(!grep {trim($_) eq $d} (@{$config{debug}})); if(defined($options{d}) && $options{d} eq "all") { $d = $g; } eval "use $g qw(" . $init . " " . $g . "_update)"; if($@) { logger("WARNING: unable to find module '$g'"); next; } { no strict "refs"; eval { &$init($g, \%config, $d); }; } logger("WARNING: unexpected errors in function $init()") if($@); } } if(!scalar($config{func_update})) { logger("nothing to do, exiting."); exit(0); } logger("Generating the 'index.html' file.") unless !$options{d}; create_index(); if(lc($config{httpd_builtin}->{enabled} eq "y")) { httpd_setup(\%config, $options{d}); logger("Built-in HTTP server pid is '$config{httpd_pid}'.") if (defined($config{httpd_pid})); } logger("Ok, done.") unless !$options{d}; alarm(1); while(1) { pause(); }