#!/usr/bin/perl

# cpanel - autofixer/check_bwdaily                Copyright(c) 2009 cPanel, Inc.
#                                                           All rights Reserved.
# copyright@cpanel.net                                         http://cpanel.net
# This code is subject to the cPanel license. Unauthorized copying is prohibited

use strict;
use warnings;

use Getopt::Long;

my $dir  = '/var/cpanel/bandwidth';
my $type = 'http';
my $sum  = 'hour';
my ( $all, $quiet );
GetOptions(
    'dir=s'     => \$dir,
    'type=s'    => \$type,
    'summary=s' => \$sum,
    'all'       => \$all,
    'quiet'     => \$quiet,
) or usage();

die "$type is not a valid type.\n" unless grep { $type eq $_ } qw(http ftp imap pop3 smtp all);
die "$dir is not a valid directory.\n" unless -d $dir;
die "$sum is not a valid summary type.\n" unless grep { $sum eq $_ } qw(hour 5min);

if ($all) {
    opendir my $dh, $dir or die "Unable to read directory $dir\n";
    my @files = grep { !/^\.\.?$/ and !/\.(?:rrd|hour|5min|xml|remainder)$/ and -f "$dir/$_" } readdir $dh;
    closedir $dh;

    my $numbad = 0;
    foreach my $prefix (@files) {
        print "Checking: $prefix\n" unless $quiet;
        eval { ++$numbad if process_domain_or_user($prefix); };
        warn $@ if $@;
    }
    if ($quiet) {
        print "$numbad files with inconsistencies found out of ", scalar(@files), "\n";
    }
}
else {
    my $prefix = shift;
    unless ( defined $prefix ) {
        print "Missing required user or domain name.\n";
        usage();
    }
    process_domain_or_user($prefix);
}

sub process_domain_or_user {
    my ($prefix)    = @_;
    my $daily_file  = "$dir/$prefix";
    my $hourly_file = "$dir/$prefix.$sum";

    die "No daily file found for $prefix.\n"  unless -f $daily_file;
    die "No hourly file found for $prefix.\n" unless -f $hourly_file;

    my $daily  = get_daily_data($daily_file);
    my $hdaily = summarize_hourly_data($hourly_file);

    my $errs = 0;
    for my $d ( sort keys %{$hdaily} ) {
        unless ( defined $daily->{$d} ) {
            print "$d: summary shows $hdaily->{$d}, no daily entry.\n" unless $quiet;
            ++$errs;
        }
        unless ( $daily->{$d} == $hdaily->{$d} ) {
            print "$d: $daily->{$d} != $hdaily->{$d} (", ( $daily->{$d} / $hdaily->{$d} ), ")\n" unless $quiet;
            ++$errs;
        }
    }

    unless ($quiet) {
        print "$errs inconsistencies found.\n" if $errs;
        print scalar( keys %{$hdaily} ), " days checked.\n";
    }
    return $errs != 0;
}

sub get_daily_data {
    my ($file) = @_;

    my %h;
    open( my $fh, '<', $file ) or die "Cannot open daily file '$file'\n";
    while (<$fh>) {
        next unless /^(\d+)\.(\d+)\.(\d\d\d\d)-http=(\d+)/;
        $h{ sprintf '%4d.%02d.%02d', $3, $1, $2 } = $4;
    }
    return \%h;
}

sub summarize_hourly_data {
    my ($file) = @_;

    my %h;
    open( my $fh, '<', $file ) or die "Cannot open hourly file '$file'\n";
    while (<$fh>) {
        next unless /^(\d\d\d\d)\.(\d+)\.(\d+)(?:T\d+(?::\d+)?)?-http=(\d+)/;
        $h{ sprintf '%4d.%02d.%02d', $1, $2, $3 } += $4;
    }
    return \%h;
}

sub usage {
    print <<"EOU";
Usage:
    $0 [options] domainname
    $0 [options] username
    $0 [options] --all

Where
    --type t  specify bandwidth type to check: http, all, ftp, smtp, pop3, imap
              defaults to http.
    --summary s  compare daily against 'hour' or '5min'
    --all     process all domains and users in specified directory
    --quiet   do not print information for each file processed, just print
              a final summary.
EOU
    exit;
}

