smeserver-awstats/root/sbin/e-smith/awstats-pp

285 lines
8.8 KiB
Perl

#!/usr/bin/perl -w
# copyright (C) 2001 neddix, stuttgart
#
# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
#
# This program is part of the AWstats package for the e-smith Server and Gateway
#
use strict;
use Symbol;
use esmith::config;
use esmith::util;
use esmith::db;
sub fileinfo($);
sub write_runstat ($);
sub cleanup();
my $start_time=time();
my $httpdlog="/var/log/httpd";
my $awconfpath="/etc/e-smith/web/panels/manager/cgi-bin/.awstats";
my $awconf="$awconfpath/awstats.conf";
my $dirdata="/home/e-smith/files/users/admin/home/awstats";
my $lock="/var/lock/awstats";
my $logrotate_detected=0;
my $readlines=0;
my ($silent, $debug, $novoid);
(undef,undef,my $admin_uid)=getpwnam('admin');
(undef,undef,my $root_gid)=getgrnam('root');
my %conf;
tie %conf, 'esmith::config';
my $status=db_get_prop(\%conf, "AWStats", "status");
exit (0) if not defined $status || $status ne "enabled";
$debug=((db_get_prop(\%conf, "AWStats", "Debug") ||"no") eq "yes");
# primitive command line options parsing
foreach (@ARGV) {
$silent=1 if /-s/;
$debug=1 if /-d/; # enter debug mode
$novoid=1 if /-n/; # stop execution, if no new logs available
if (/^-c/) {
($awconf=$_) =~ s/^-c//;
}
}
print "using configuration file $awconf\n" if $debug;
# check lock
if (-f "$lock") {
open (LCK, "$lock");
print "Another instance of AWStats is already running at pid=".<LCK>." \n" if $debug or not $silent;
close (LCK);
exit(1);
}
$SIG{TERM}='cleanup';
$SIG{KILL}='cleanup';
$SIG{INT}='cleanup';
END{cleanup()};
# set lock
open (LCK, ">$lock") or die "Could not create $lock\n";
print LCK "$$";
print "Set lock. pid=$$\n" if $debug;
close (LCK);
write_runstat ("Currently running. Please be patient. (pid=$$)");
my $log="$httpdlog/access_log";
my $log_1="$httpdlog/access_log.1";
my $cur_log; # filename of the current logfile
my $awpos="$httpdlog/awstats_pos";
my (@fstat_cur, @fstat_log, @fstat_log_1); # file status information of log files
die "Fatal error: Apache logfile $log not found\nIs Apache running?\n" if not -f $log;
# read file status information
@fstat_log=fileinfo("$log"); # current apache log file
@fstat_log_1=fileinfo("$log_1"); # logrotated apache log file
# read current log file information
if (-f "$awpos") {
open (AWPOS,"$awpos") or die "Could not open file $awpos\n";
chomp($_=<AWPOS>);
@fstat_cur = split (":");
close (AWPOS);
} else {
@fstat_cur=@fstat_log; # use current log file
$fstat_cur[2]=-1; # size
print "$awpos not found.\n" if $debug;
}
# check if information from $awpos is outdated:
# dev/inode pair must point to an Apache logfile
if ( ($fstat_cur[0]!=$fstat_log[0] || $fstat_cur[1]!=$fstat_log[1]) &&
($fstat_cur[0]!=$fstat_log_1[0] || $fstat_cur[1]!=$fstat_log_1[1]) ) {
@fstat_cur=@fstat_log; # use current log file
$fstat_cur[2]=-1; # size
}
# find the filename and write size of logfile to current fstat
if ($fstat_cur[0]==$fstat_log[0] && $fstat_cur[1]==$fstat_log[1]) {
$cur_log=$log; # use current Apache log
$fstat_cur[2]=$fstat_log[2];
} elsif ($fstat_cur[0]==$fstat_log_1[0] && $fstat_cur[1]==$fstat_log_1[1]) {
$cur_log=$log_1; # use logrotated Apache log
$fstat_cur[2]=$fstat_log_1[2];
$logrotate_detected=1; # Flag: remove $awpos at exit
} else {
die "Fatal error: No Apache logfile found.\nIs Apache running?\n";
}
print "fstat=$fstat_cur[0]:$fstat_cur[1]:$fstat_cur[2]:$fstat_cur[3]\n" if $debug;
print "Current log filename: $cur_log\n" if $debug;
print "logrotated: " . ($logrotate_detected==1 ? "yes\n" : "no\n") if $debug;
mkdir ("$dirdata");
# check if anybody played with dirdata permissions, i.e. e-smith upgrade
{
(undef,undef,my $mode,undef,my $uid,my $gid)=stat($dirdata);
if (($mode &= 0777) != 0770 || $uid != $admin_uid || $gid != $root_gid) {
print "setting recursivly correct permissions for $dirdata\n" if $debug;
my @list=<$dirdata $dirdata/* $dirdata/*/*>;
chown ($admin_uid, $root_gid, @list);
chmod (0770, $root_gid, @list);
}
}
if ($fstat_cur[2]==$fstat_cur[3] && $novoid) {
print "Nix zu tun.\n" if $debug;
exit(0);
}
my $key;
my $value;
my %Domains;
# split main log into log for each domain
mkdir ("$httpdlog/awstats");
open (LOG, "$cur_log") or die "Could not open $cur_log\n";
seek (LOG, $fstat_cur[3], 0) or die "seek failed\n";
while (<LOG>) {
my $line=$_;
$line=~s/(^.*?) (.*)/$2/;
my $key=$1;
if (not defined $Domains{$key}) {
$Domains{$key}=gensym();
open ($Domains{$key}, ">$httpdlog/awstats/$key") or die "Could not open $httpdlog/awstats/$key\n";
}
# write in Apaches combined log format
print {$Domains{$key}} $line;
$readlines++;
}
print " startoffset=$fstat_cur[3]\n" if $debug;
$fstat_cur[3]=tell(LOG); # save the file offset
print " endoffset=$fstat_cur[3]\n" if $debug;
print " read $readlines lines\n" if $debug;
close (LOG);
# close log files for virt domains
while (($key,$value) = each %Domains) {
close ($Domains{$key});
}
# generate domain specific conf files for both
# newly scanned and historical ones
# must be done every run, since they could be deleted
# or default config might have been modified
my %ConfDomains=%Domains;
opendir (DIR, "$dirdata");
while (defined (my $d=readdir(DIR))) {
next if $d =~ /^\.\.?$/;
$ConfDomains{$d}=gensym() if not defined $ConfDomains{$d};
}
closedir (DIR);
while (($key,$value) = each %ConfDomains) {
# read default config file (built by using e-smith template mechanism)
open ($ConfDomains{$key}, ">$awconfpath/awstats.$key.conf") or die "Could not open $awconfpath/awstats.$key.conf\n";
# write domain specific config file
open (CONF, "$awconf") or die "Could not open $awconf\n";
while (<CONF>) {
if (/^DirData=/) {
mkdir ("$dirdata/$key"); # make dir for AWStats historical data
chown ($admin_uid,$root_gid, "$dirdata/$key");
chmod (0770,"$dirdata/$key");
$_="DirData=\"$dirdata/$key\"\n"; # path to history dir
}
if (/^SiteDomain=/) {
$_="SiteDomain=\"$key\"";
}
$_ =~ s/LogFile="\/var\/log\/httpd\/access_log"/LogFile="-"/;
print {$ConfDomains{$key}} $_;
}
close (CONF);
close ($ConfDomains{$key});
}
# launch AWStats for each domain, which has new logs
while (($key,$value) = each %Domains) {
my $ret;
my $cmd="/etc/e-smith/web/panels/manager/cgi-bin/.awstats/awstats.pl -config=$key < $httpdlog/awstats/$key > /dev/null";
print "Launching AWStats with logfile $httpdlog/awstats/$key (len="
.(-s "$httpdlog/awstats/$key") . " bytes)\n" if $debug;
$ret=system ("$cmd");
print "Command was: $cmd\n" if $ret!=0;
}
# save the status of the Apache log for the next run
open (AWPOS,">$awpos") or die "Could not open file $awpos for writing\n";
print AWPOS $fstat_cur[0].":".$fstat_cur[1].":".$fstat_cur[2].":".$fstat_cur[3]."\n";
print AWPOS "# THIS FILE IS NEEDED BY AWSTATS. DO NOT DELETE!\n";
close (AWPOS);
print "$awpos: $fstat_cur[0]:$fstat_cur[1]:$fstat_cur[2]:$fstat_cur[3]\n" if $debug;
exit (0);
# get dev, inode and size information of a file
sub fileinfo($) {
my ($file)=@_;
return (0,0,0,0) if not -f $file;
my @info; # 0-> device, 1-> inode, 2->size
($info[0],$info[1],undef,undef,undef,undef,undef,$info[2])=stat($file);;
$info[3]="0"; # default file pos offset
print "$file: $info[0]:$info[1]:$info[2]:$info[3]\n" if $debug;
return @info;
}
sub write_runstat ($) {
open (ST, ">$httpdlog/awstats_lr") or die "Could not open file $httpdlog/awstats_lr for writing\n";
print ST $_[0];
close (ST);
}
# invoked at exit, SIGTERM, SIGKILL and SIGINT
sub cleanup () {
my ($xtime, $min, $hour, $day, $month, $year);
(undef, $min, $hour, $day, $month, $year)=localtime($start_time);
$xtime=(time()-$start_time);
print "Program execution time: $xtime sec\n" if $debug;
print "Cleanup.\n" if $debug;
if (not $debug) {
while (($key,$value) = each %Domains) {
unlink ("$httpdlog/awstats/$key");
}
rmdir ("$httpdlog/awstats");
}
if ($logrotate_detected==1) {
unlink ("$awpos");
print "Logfile rotate detected. $awpos removed. Next run will process the new logfile\n" if $debug;
}
write_runstat (sprintf ("Updated on %02d/%02d/%d at %02d:%02d in %d secs. %d new logs processed.",
$month+1,$day,$year+1900,$hour,$min,$xtime, $readlines));
if (-f "$lock") {
open (LCK, "$lock");
my $pid=<LCK>;
close (LCK);
unlink ("$lock") if $$ == "$pid" or "$pid" eq "";
}
# remove temporary conf file
if ($awconf =~ /\.[0-9]*$/) {
unlink ("$awconf");
}
exit (0);
}