285 lines
8.8 KiB
Plaintext
285 lines
8.8 KiB
Plaintext
|
#!/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);
|
||
|
}
|