diff --git a/contrib/bfha/bfha-debian.pl b/contrib/bfha/bfha-debian.pl new file mode 100644 index 0000000..5ba5056 --- /dev/null +++ b/contrib/bfha/bfha-debian.pl @@ -0,0 +1,575 @@ +#!/usr/bin/perl + +# +# bfha -- binkleyforce history analyzer +# +# Copyright (C) 2000 Serge N. Pokhodyaev +# +# E-mail: snp@ru.ru +# Fido: 2:5020/1838 +# +# +# 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. +# +# +# $Id$ +# + +# +# çÅÎÅÒÉÔ ÓÔÁÔÉÓÔÉËÕ ÚÁ ÐÒÅÄÙÄÕÝÉÊ ÄÅÎØ +# + +# +# TODO: +# +# 1. õÞÅÓÔØ ÓÌÕÞÁÊ, ËÏÇÄÁ ÌÏÇ ÐÏ×£ÒÎÕÔ logrotate'ÏÍ +# +# Known bugs: +# +# 1. HÅÐÒÁ×ÉÌØÎÏ ÓÞÉÔÁÅÔ cps (ÚÁ×ÙÛÁÅÔ) ÅÓÌÉ ÔÒÁÆÉË × ÏÂÅ ÓÔÏÒÏÎÙ +# + +use strict; +use Time::Local; +use POSIX qw(strftime); + +my $PROGNAME = 'bfha'; +my $VERSION = '$Revision$ '; + +######## Configurable part ################################################### + +#my $inews = "/usr/bin/inews -h -O -S"; + +#my $log = "/var/log/fido/history"; + +#my $rep_newsgroups = "ftn.1838.stat"; +#my $rep_from = "\"Statistics generator\" "; +#my $rep1_subj = "Sessions history"; +#my $rep2_subj = "Sessions history"; +#my $rep3_subj = "Links statistics"; + +my $count_failed = 1; + +#my %line_names = ( +# "ttyS1" => "Modem", +# "tcpip" => "IP" +#); + +############################################################################## + +my $devel = 0; + +my (%st, %lines, %nodes, @nodes_sorted); +my @tm; +my $time; + +die "Usage: $PROGNAME [-d]\n" if (!((0 == $#ARGV) && ($ARGV[0] eq '-d')) && !(-1 == $#ARGV)); +$devel = 1 if ((0 == $#ARGV) && ($ARGV[0] eq '-d')); + +$log = "./history" if ($devel); + +# Make version string +# +$VERSION =~ s/(\$Rev)ision:\s([\d.]+).*/$PROGNAME\/$2/; + +# Get time of 0:00:00 of yesterday +# +@tm = localtime(time - 86400); +$tm[0] = 0; # sec +$tm[1] = 0; # min +$tm[2] = 0; # hours +$time = timelocal(@tm); + +# At first read logs +# +undef %st; +undef %lines; +undef %nodes; +die "Log reading error\n" if (0 != log_read($time)); + +@nodes_sorted = sort(node_cmp keys(%nodes)); + +# Now generate statistics +# +out_close(); +#rep1(); +rep2(); +rep3(); + + +sub log_read + { + my $i; + my $t; + my @l; + + die if (0 != $#_); + + $t = $_[0]; + + open(LOG, "< $log") || die("Can't open $log: $!\n"); + while () + { + chomp; + @l = split(/,/); + return 1 if ($#l != 11); + return 1 if (! ($l[4] =~ /[IO]/)); + + # Check date + # + next if ($l[2] < $t); + last if ($l[2] >= ($t + 86400)); + + # Entries without address + # + if ($l[1] eq '') + { + next if (0 == $count_failed); + $l[1] = 'failed' if (0 != $count_failed); + } + + # Remove domain + # + $l[1] =~ s/@.*$//; + + # Add statistics + # + $i = $#{$st{beg}} + 1; + + $lines{$l[0]}[$#{$lines{$l[0]}} + 1] = $i; + $nodes{$l[1]}[$#{$nodes{$l[1]}} + 1] = $i; + + $st{beg}[$i] = $l[2]; + $st{len}[$i] = $l[3]; + $st{addr}[$i] = $l[1]; + $st{line}[$i] = $l[0]; + $st{rc}[$i] = $l[5]; + $st{snt_nm}[$i] = $l[6]; + $st{snt_am}[$i] = $l[7]; + $st{snt_f}[$i] = $l[8]; + $st{rcv_nm}[$i] = $l[9]; + $st{rcv_am}[$i] = $l[10]; + $st{rcv_f}[$i] = $l[11]; + $st{islst}[$i] = 0; + $st{islst}[$i] = 1 if ($l[4] =~ /L/); + $st{isprot}[$i] = 0; + $st{isprot}[$i] = 1 if ($l[4] =~ /P/); + $st{type}[$i] = 'I' if ($l[4] =~ /I/); + $st{type}[$i] = 'O' if ($l[4] =~ /O/); + } + } + +######## rep1 ################################################################ + +sub rep1 + { + my ($i, $j); + my (%se, %se_t); + my $node; + + out_open($rep1_subj); + printf "Date: %s\n\n", strftime("%a, %e %b %Y", localtime($time)); + + $~ = "rep1_header"; + write; + + $~ = "rep1_body"; + $se_t{num_in} = 0; + $se_t{num_out} = 0; + $se_t{snt} = 0; + $se_t{rcv} = 0; + $se_t{len} = 0; + foreach $node (@nodes_sorted) + { + $se{num_in} = 0; + $se{num_out} = 0; + $se{snt} = 0; + $se{rcv} = 0; + $se{len} = 0; + for ($i = 0; $i <= $#{$nodes{$node}}; ++$i) + { + $j = $nodes{$node}[$i]; + ++$se{num_in} if ($st{type}[$j] eq 'I'); + ++$se{num_out} if ($st{type}[$j] eq 'O'); + $se{snt} += $st{snt_am}[$j] + $st{snt_nm}[$j] + $st{snt_f}[$j]; + $se{rcv} += $st{rcv_am}[$j] + $st{rcv_nm}[$j] + $st{rcv_f}[$j]; + $se{len} += $st{len}[$j]; + } + $se{time} = time_int2str($se{len}); + # FIXME (cps) + $se{cps} = div_int(($se{snt} + $se{rcv}), $se{len}); + write; + + $se_t{num_in} += $se{num_in}; + $se_t{num_out} += $se{num_out}; + $se_t{snt} += $se{snt}; + $se_t{rcv} += $se{rcv}; + $se_t{len} += $se{len}; + } + + $~ = "rep1_footer"; + $se_t{time} = time_int2str($se_t{len}); + # FIXME (cps) + $se_t{cps} = div_int(($se_t{snt} + $se_t{rcv}), $se_t{len}); + write; + + print "\n"; + out_close(); + + +format rep1_header = +¥                 ¶          ¶           ¶            ¶           ¶       š +¡ System  Sessions  Sent  Received  Time  CPS ¡ +¡ address  in out  bytes  bytes  online  ¡ +±                 Œ          Œ           Œ            Œ           Œ       µ +. + +format rep1_body = +¡ @<<<<<<<<<<<<<<  @>> @>>  @>>>>>>>>  @>>>>>>>>>  @>>>>>>>>  @>>>> ¡ +$node, $se{num_in}, $se{num_out}, $se{snt}, $se{rcv}, $se{time}, $se{cps} +. + +format rep1_footer = +°€€€€€€€€€€€€€€€€€Š€€€€€€€€€€Š€€€€€€€€€€€Š€€€€€€€€€€€€Š€€€€€€€€€€€Š€€€€€€€Ž +¡ TOTAL  @>> @>>  @>>>>>>>>  @>>>>>>>>>  @>>>>>>>>  @>>>> ¡ +$se_t{num_in}, $se_t{num_out}, $se_t{snt}, $se_t{rcv}, $se_t{time}, $se_t{cps} +«                 ¹          ¹           ¹            ¹           ¹       ® +. + } + +######## rep2 ################################################################ + +sub rep2 + { + my ($i, $j); + my @t; + my ($t1, $t2, $str, $lv); + my $node; + my %se; + + out_open($rep2_subj); + printf "Date: %s\n\n", strftime("%a, %e %b %Y", localtime($time)); + + $~ = "rep2_header"; + write; + + $~ = "rep2_body"; + foreach $node (@nodes_sorted) + { + $se{snt} = 0; + $se{rcv} = 0; + $se{len} = 0; + for ($i = 0; $i <= 95; ++$i) + { + $t[$i] = 0; + } + for ($i = 0; $i <= $#{$nodes{$node}}; ++$i) + { + $j = $nodes{$node}[$i]; + + # Fill array + # + $t1 = $st{beg}[$j] - $time; + $t2 = $t1 + $st{len}[$j]; + $t2 = 86399 if ($t2 > 86399); + $t1 = div_int($t1, 900); + $t2 = div_int($t2, 900); + while ($t1 <= $t2) + { + $t[$t1++] = 1; + } + + $se{snt} += $st{snt_am}[$j] + $st{snt_nm}[$j] + $st{snt_f}[$j]; + $se{rcv} += $st{rcv_am}[$j] + $st{rcv_nm}[$j] + $st{rcv_f}[$j]; + $se{len} += $st{len}[$j]; + } + $se{time} = time_int2str($se{len}); + # FIXME (cps) + $se{cps} = div_int(($se{snt} + $se{rcv}), $se{len}); + + # Visualize + # + $i = 0; + $str = ""; + if ($t[$i++]) + { + $str = $str . ""; + } + else + { + $str = $str . ""; + } + while ($i < $#t) + { + $lv = 0; + $lv += 1 if ($t[$i++]); + $lv += 2 if ($t[$i++]); + + if (0 == $lv) + { + if (div_rest(($i - 1), 8) == 0) + { + $str = $str . ""; + } + else + { + $str = $str . " "; + } + } + elsif (1 == $lv) + { + $str = $str . "Ž"; + } + elsif (2 == $lv) + { + $str = $str . ""; + } + elsif (3 == $lv) + { + $str = $str . ""; + } + } + if ($t[$i]) + { + $str = $str . "Ž"; + } + else + { + $str = $str . ""; + } + + write; + } + + $~ = "rep2_footer"; + write; + + out_close(); + + +format rep2_header = + 0 2 4 6 8 10 12 14 16 18 20 22 24 + †€‰€Š€‰€Š€‰€Š€‰€Š€‰€Š€‰€Š€‰€Š€‰€Š€‰€Š€‰€Š€‰€Š€‰€‡ +. + +format rep2_body = +@<<<<<<<<<<<<<<@|||||||||||||||||||||||||||||||||||||||||||||||| +$node, $str +. + +format rep2_footer = + †€ˆ€Š€ˆ€Š€ˆ€Š€ˆ€Š€ˆ€Š€ˆ€Š€ˆ€Š€ˆ€Š€ˆ€Š€ˆ€Š€ˆ€Š€ˆ€‡ + 0 2 4 6 8 10 12 14 16 18 20 22 24 +. + } + +######## rep3 ################################################################ + +sub rep3 + { + my $node; + my (%se, %se_t); + my ($i, $j); + + out_open($rep3_subj); + printf "Date: %s\n\n", strftime("%a, %e %b %Y", localtime($time)); + + $~ = "rep3_header"; + write; + + $~ = "rep3_body"; + $se_t{num_in} = 0; + $se_t{num_out} = 0; + $se_t{time_in} = 0; + $se_t{time_out} = 0; + $se_t{snt} = 0; + $se_t{rcv} = 0; + $se_t{time} = 0; + foreach $node (@nodes_sorted) + { + $se{num_in} = 0; + $se{num_out} = 0; + $se{time_in} = 0; + $se{time_out} = 0; + $se{snt} = 0; + $se{rcv} = 0; + $se{time} = 0; + for ($i = 0; $i <= $#{$nodes{$node}}; ++$i) + { + $j = $nodes{$node}[$i]; + ++$se{num_in} if ($st{type}[$j] eq 'I'); + ++$se{num_out} if ($st{type}[$j] eq 'O'); + $se{time_in} += $st{len}[$j] if ($st{type}[$j] eq 'I'); + $se{time_out} += $st{len}[$j] if ($st{type}[$j] eq 'O'); + $se{snt} += $st{snt_am}[$j] + $st{snt_nm}[$j] + $st{snt_f}[$j]; + $se{rcv} += $st{rcv_am}[$j] + $st{rcv_nm}[$j] + $st{rcv_f}[$j]; + $se{time} += $st{len}[$j]; + } + + # Total counters + # + $se_t{num_in} += $se{num_in}; + $se_t{num_out} += $se{num_out}; + $se_t{snt} += $se{snt}; + $se_t{rcv} += $se{rcv}; + $se_t{time} += $se{time}; + $se_t{time_out} += $se{time_out}; + $se_t{time_in} += $se{time_in}; + + # Output string + # + # FIXME (cps) + $se{cps} = dash_if_zero(div_int(($se{snt} + $se{rcv}), $se{time})); + $se{time} = time_int2str($se{time}); + $se{time_in} = time_int2str($se{time_in}); + $se{time_out} = time_int2str($se{time_out}); + $se{num_in} = dash_if_zero($se{num_in}); + $se{num_out} = dash_if_zero($se{num_out}); + $se{rcv} = shrink_size(dash_if_zero($se{rcv})); + $se{snt} = shrink_size(dash_if_zero($se{snt})); + write; + } + + $~ = "rep3_footer"; + # FIXME (cps) + $se_t{cps} = dash_if_zero(div_int(($se_t{snt} + $se_t{rcv}), $se_t{time})); + $se_t{time} = time_int2str($se_t{time}); + $se_t{time_in} = time_int2str($se_t{time_in}); + $se_t{time_out} = time_int2str($se_t{time_out}); + $se_t{num_in} = dash_if_zero($se_t{num_in}); + $se_t{num_out} = dash_if_zero($se_t{num_out}); + $se_t{rcv} = shrink_size(dash_if_zero($se_t{rcv})); + $se_t{snt} = shrink_size(dash_if_zero($se_t{snt})); + $~ = "rep3_footer"; + write; + + print "\n"; + out_close(); + + +format rep3_header = +¥                ž                           ž          ž             ž       š +¡ ¡ Sessions/Online ¡ Time ¡ Traffic ¡ ¡ +¡ Address ±             ž             µ online ±      ž      µ CPS ¡ +¡ ¡ Incoming ¡ Outgoing ¡ ¡ Rcvd ¡ Sent ¡ ¡ +±                Ÿ   ¶         Ÿ   ¶         Ÿ          Ÿ      Ÿ      Ÿ       µ +. + +format rep3_body = +¡ @<<<<<<<<<<<<<<¡@>>@>>>>>>> ¡@>>@>>>>>>> ¡@>>>>>>>> ¡@>>>>>¡@>>>>>¡@>>>>> ¡ +$node, $se{num_in}, $se{time_in}, $se{num_out}, $se{time_out}, $se{time}, $se{rcv}, $se{snt}, $se{cps} +. + +format rep3_footer = +°€€€€€€€€€€€€€€€€œ€€€Š€€€€€€€€€œ€€€Š€€€€€€€€€œ€€€€€€€€€€œ€€€€€€œ€€€€€€œ€€€€€€€Ž +¡ TOTAL ¡@>>@>>>>>>> ¡@>>@>>>>>>> ¡@>>>>>>>> ¡@>>>>>¡@>>>>>¡@>>>>> ¡ +$se_t{num_in}, $se_t{time_in}, $se_t{num_out}, $se_t{time_out}, $se_t{time}, $se_t{rcv}, $se_t{snt}, $se_t{cps} +«                »   ¹         »   ¹         »          »      »      »       ® +. + } + +############################################################################## + +sub shrink_size + { + die if (0 != $#_); + + return $_[0] if ($_[0] < 1024); + return sprintf("%.1fk", $_[0] / 1024) if ($_[0] < 1048576); + return sprintf("%.1fM", $_[0] / 1048576); + } + +sub dash_if_zero + { + die if (0 != $#_); + + return "-" if (0 == $_[0]); + return $_[0]; + } + +sub time_int2str + { + my $time; + my $h; + my $m; + my $s; + + die if (0 != $#_); + die if (86399 < $time); + + return "-:--:--" if (0 == $_[0]); + + $time = $_[0]; + $h = div_int($time, 3600); + $time = div_rest($time, 3600); + $m = div_int($time, 60); + $s = div_rest($time, 60); + + return sprintf("%d:%2.2d:%2.2d", $h, $m, $s); + } + +# ãÅÌÏÞÉÓÌÅÎÎÏÅ ÄÅÌÅÎÉÅ +sub div_int + { + use integer; + + die if (1 != $#_); + + return 0 if ($_[1] == 0); + return $_[0] / $_[1]; + } + + +# ïÓÔÁÔÏË ÏÔ ÃÅÌÏÞÉÓÌÅÎÎÏÇÏ ÄÅÌÅÎÉÑ +sub div_rest + { + die if (1 != $#_); + + return 0 if ($_[1] == 0); + return $_[0] - (div_int($_[0], $_[1]) * $_[1]); + } + +sub out_open + { + die if (0 != $#_); + + open(STDOUT, "| $inews") || die("Can't pipe to inews: $!\n") if (! $devel); + printf "Newsgroups: %s\n", $rep_newsgroups; + printf "From: %s\n", $rep_from; + printf "Subject: %s\n", $_[0]; + printf "X-FTN-Tearline: %s\n\n", $VERSION; + } + +sub out_close + { + close(STDOUT) if (! $devel); + } + +sub node_cmp + { + my (@na, @nb); + + @na = split('[:/.]', $::a); + @nb = split('[:/.]', $::b); + + # zone + return -1 if ($na[0] < $nb[0]); + return 1 if ($na[0] > $nb[0]); + + # net + return -1 if ($na[1] < $nb[1]); + return 1 if ($na[1] > $nb[1]); + + # node + return -1 if ($na[2] < $nb[2]); + return 1 if ($na[2] > $nb[2]); + + #point + return -1 if ($na[3] < $nb[3]); + return 1 if ($na[3] > $nb[3]); + + return 0; + }