#!/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=".." \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($_=); @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 () { 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 () { 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=; close (LCK); unlink ("$lock") if $$ == "$pid" or "$pid" eq ""; } # remove temporary conf file if ($awconf =~ /\.[0-9]*$/) { unlink ("$awconf"); } exit (0); }