Initial import from FreeBSD RELENG_4:
[games.git] / share / examples / isdn / contrib / isdnd_acct.pl
1 #!/usr/bin/perl
2 #
3 #ich habe zwei vielleicht n?tzliche Erweiterungen an isdn_pacct
4 #gemacht:
5 #
6 #        1) Man kann den Namen der Accounting-Datei angeben. Ich
7 #           habe Accounting-Files nach Telekom-Rechnung aufgeteilt
8 #           und kann diese so sehr sch?n nachvollziehen.
9 #
10 #        2) Die Abrechnung wird nach Einheitenl?ngen aufgelistet.
11 #           Leider wird zur Zeit immer Nahzone verwendet (isdnd.rates
12 #           wird ausgelesen), und Feiertage stehen als erstes auf
13 #           der TODO-Liste. Wenn man dieses Feature durch einen
14 #           Switch anschaltet, kann man es sogar unauff?llig in die
15 #           Distribution aufnehmen.
16 #
17 #           Mir hilft diese Abrechnung, an mir zu arbeite und mehr
18 #           Tests und Zug?nge nachts durchzuf?hren... Aber die meisten
19 #           Einheiten werden immer noch im 90s-Takt verbraucht :-(
20 #
21 # $FreeBSD: src/share/examples/isdn/contrib/isdnd_acct.pl,v 1.1.2.1 2001/08/10 14:59:48 obrien Exp $
22 #
23 #---------------------------------------------------------------------------
24 #
25 # Copyright (c) 1994, 1996 Hellmuth Michaelis. All rights reserved.
26 #
27 # Redistribution and use in source and binary forms, with or without
28 # modification, are permitted provided that the following conditions
29 # are met:
30 # 1. Redistributions of source code must retain the above copyright
31 #    notice, this list of conditions and the following disclaimer.
32 # 2. Redistributions in binary form must reproduce the above copyright
33 #    notice, this list of conditions and the following disclaimer in the
34 #    documentation and/or other materials provided with the distribution.
35 # 3. All advertising materials mentioning features or use of this software
36 #    must display the following acknowledgement:
37 #       This product includes software developed by Hellmuth Michaelis
38 # 4. Neither the name of the author nor the names of any co-contributors
39 #    may be used to endorse or promote products derived from this software
40 #    without specific prior written permission.
41 #
42 # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
43 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45 # ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
46 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
48 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
50 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
51 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
52 # SUCH DAMAGE.
53 #
54 #---------------------------------------------------------------------------
55 #
56 #       accounting script for the isdn daemon accounting info
57 #       -----------------------------------------------------
58 #
59 #       last edit-date: [Fri May 25 15:22:26 2001]
60 #
61 #       -hm     my first perl program :-)
62 #       -hm     sorting the output
63 #       -hm     adding grand total
64 #
65 #---------------------------------------------------------------------------
66
67 sub wday {
68         local ($y, $m, $d) = @_;
69         local ($nday, @mon);
70
71         @mon = (0, 31, 61, 92, 122, 153, 184, 214, 245, 275, 306, 337);
72 #               M  A   M   J   J    A    S    O    N    D    J    F
73
74         if ($m > 2) {
75                 $m -= 3;
76         } else {
77                 $m += 9;
78                 $y--;
79         }
80         if ($y < 1600) {
81                 return -1;
82         }
83         $y -= 1600;
84         $nday = $y * 365 + $mon[$m] + $d +
85                 int($y / 4) - int($y / 100) + int($y / 400);
86         ($nday + 2) % 7;
87 }
88
89 # where the isdnd accounting file resides
90 if ($#ARGV == 0) {
91         $ACCT_FILE = $ARGV[0];
92 } else {
93         $ACCT_FILE = "/var/log/isdnd.acct";
94 }
95
96 # $PERIOD_FILE = "/usr/local/etc/isdnd.periods";
97 # # read periods that need to be separately listed
98 # if (open(IN, $PERIOD_FILE)) {
99 #       while (<IN>) {
100 #               chop;
101 #               ($start, $end) = split(/ /);
102 #               push(@p_start, $start);
103 #               push(@p_end, $end);
104 #       }
105 #       close(IN);
106 # }
107
108 $RATES_FILE = "/etc/isdn/isdnd.rates";
109 if (open(IN, $RATES_FILE)) {
110         while(<IN>) {
111                 chop;
112                 if (! /^ra0/) {
113                         next;
114                 }
115                 ($ra0, $day, $rest) = split(/[ \t]+/, $_, 3);
116                 @periods = split(/[ \t]+/, $rest);
117                 foreach $period (@periods) {
118                         ($h_start, $m_start, $h_end, $m_end, $secs) = 
119                                 $period =~ /(.+)\.(.+)-(.+)\.(.+):(.+)/;
120                         for ($h = int($h_start); $h < $h_end; $h++) {
121                                 $secs{$day, $h} = $secs;
122                         }
123                 }
124         }
125         close(IN);
126 }
127
128 # the charge for a unit, currently 0,12 DM
129 $UNIT_PRICE = 0.12;
130
131 # open accounting file
132 open(IN, $ACCT_FILE) ||
133         die "ERROR, cannot open $ACCT_FILE !\n";
134
135 # set first thru flag
136 $first = 1;
137
138 # process file line by line
139 while (<IN>)
140 {
141         # remove ( and ) from length and bytecounts
142         tr/()//d;
143
144         # split line into pieces
145         ($from_d, $from_h, $dash, $to_d, $to_h, $name, $units, $secs, $byte)
146                 = split(/ /, $_);
147
148         # get starting date
149         if($first)
150         {
151                 $from = "$from_d $from_h";
152                 $first = 0;
153         }
154
155         # split bytecount
156         ($inb, $outb) = split(/\//, $byte);
157
158         # if user wants to account time periods, put this to the right
159         # slot(s)
160         ($hour, $minute, $second) = split(/:/, $from_h);
161         ($day, $mon, $year) = split(/\./, $from_d);
162         $day = &wday('19' . $year, $mon, $day);
163         if ($secs{$day, int($hour)}) {
164                 $secs = $secs{$day, int($hour)};
165                 # process fields
166                 $p_secs{$name, $secs} += $secs;
167                 $p_calls{$name, $secs}++;
168                 $p_units{$name, $secs} += $units;
169                 $p_charge{$name, $secs} += $units * $UNIT_PRICE;
170                 $p_inbytes{$name, $secs} += $inb;
171                 $p_outbytes{$name, $secs} += $outb;
172                 $p_bytes{$name, $secs} = $p_bytes{$name, $secs} + $inb + $outb;
173         }
174
175         # process fields
176         $a_secs{$name} += $secs;
177         $a_calls{$name}++;
178         $a_units{$name} += $units;
179         $a_charge{$name} += $units * $UNIT_PRICE;
180         $a_inbytes{$name} += $inb;
181         $a_outbytes{$name} += $outb;
182         $a_bytes{$name} = $a_bytes{$name} + $inb + $outb;
183 }
184
185 # close accouting file
186 close(IN);
187
188 # write header
189 print "\n";
190 print "     ISDN Accounting Report   ($from -> $to_d $to_h)\n";
191 print "     =================================================================\n";
192
193 #write the sum for each interface/name
194 foreach $n (sort(keys %a_secs))
195 {
196         $o_secs = $a_secs{$n};
197         $gt_secs += $o_secs;
198         $o_calls = $a_calls{$n};
199         $gt_calls += $o_calls;
200         $o_units = $a_units{$n};
201         $gt_units += $o_units;
202         $o_charge = $a_charge{$n};
203         $gt_charge += $o_charge;
204         $o_inbytes = $a_inbytes{$n};
205         $gt_inbytes += $o_inbytes;
206         $o_outbytes = $a_outbytes{$n};
207         $gt_outbytes += $o_outbytes;
208         $o_bytes = $a_bytes{$n};
209         $gt_bytes = $o_bytes;
210         $name = $n;
211         write;
212
213         foreach $i (keys %p_secs) {
214                 ($nam, $secs) = split(/$;/, $i);
215                 if ($nam ne $n) {
216                         next;
217                 }
218                 $o_secs = $p_secs{$i};
219                 $o_calls = $p_calls{$i};
220                 $o_units = $p_units{$i};
221                 $o_charge = $p_charge{$i};
222                 $o_inbytes = $p_inbytes{$i};
223                 $o_outbytes = $p_outbytes{$i};
224                 $o_bytes = $p_bytes{$i};
225                 $name = sprintf(' %5.1fs', $secs / 10);
226                 write;
227         }
228 }
229
230 $o_secs = $gt_secs;
231 $o_calls = $gt_calls;
232 $o_units = $gt_units;
233 $o_charge = $gt_charge;
234 $o_inbytes = $gt_inbytes;
235 $o_outbytes = $gt_outbytes;
236 $o_bytes = $gt_bytes;
237 $name = "Total";
238
239 print "======= ====== ===== ===== ======== ============ ============ ============\n";
240 write;
241
242 print "\n\n";
243 exit;
244
245 # top of page header
246 format top =
247
248 Name    charge units calls     secs      inbytes     outbytes        bytes
249 ------- ------ ----- ----- -------- ------------ ------------ ------------
250 .
251
252 # record template
253 format STDOUT =
254 @<<<<<< @##.## @#### @#### @####### @########### @########### @###########
255 $name,  $o_charge, $o_units, $o_calls, $o_secs, $o_inbytes, $o_outbytes, $o_bytes
256 .
257
258 # EOF