pick up freeside-sqlradius-radacctd again after all these years, now it just needs...
[freeside.git] / FS / bin / freeside-sqlradius-radacctd
1 #!/usr/bin/perl -Tw
2
3 use strict;
4 use vars qw( @part_export );
5 use subs qw(myshutdown);
6 use POSIX qw(:sys_wait_h);
7 use IO::File;
8 use FS::Daemon qw(daemonize1 drop_root logfile daemonize2 sigint sigterm);
9 use FS::UID qw(adminsuidsetup); #forksuidsetup driver_name dbh myconnect);
10 use FS::Record qw(qsearch); # qsearchs);
11 use FS::part_export;
12 #use FS::svc_acct;
13 #use FS::cust_svc;
14
15 my $user = shift or die &usage;
16
17 #daemonize1('freeside-sqlradius-radacctd', $user); #keep unique pid files w/multi installs
18 daemonize1('freeside-sqlradius-radacctd');
19
20 drop_root();
21
22 #$ENV{HOME} = (getpwuid($>))[7]; #for ssh
23
24 adminsuidsetup $user;
25
26 logfile( "/usr/local/etc/freeside/sqlradius-radacctd-log.". $FS::UID::datasrc );
27
28 daemonize2();
29
30 #--
31
32 @part_export =
33   qsearch('part_export', { 'exporttype' => 'sqlradius' } );
34 push @part_export,
35   qsearch('part_export', { 'exporttype' => 'sqlradius_withdomain' } );
36
37 @part_export = grep { ! $_->option('ignore_accounting') } @part_export;
38
39 die "no sqlradius or sqlradius_withdomain exports without ignore_accounting"
40   unless @part_export;
41
42 while (1) {
43
44   #fork off one kid per export (machine)
45   # _>{'_radacct_kid'} is an evil kludge
46   foreach my $part_export ( grep ! $_->{'_radacct_kid'}, @part_export ) {
47  
48     defined( my $pid = fork ) or do {
49       warn "WARNING: can't fork to spawn child for ". $part_export->machine;
50       next;
51     };
52
53     if ( $pid ) {
54       $part_export->{'_radacct_kid'} = $pid;
55       warn "child $pid spawned for ". $part_export->machine;
56     } else { #kid time
57
58       adminsuidsetup($user); #get our own db handle
59
60       until ( sigint || sigterm ) {
61         $part_export->update_svc_acct();
62         sleep 1;
63       }
64
65       warn "child for ". $part_export->machine. " done";
66       exit;
67
68     } #eo kid
69
70   }
71
72   #reap up any kids that died...
73   &reap_kids;
74
75   myshutdown() if sigterm() || sigint();
76
77   sleep 5;
78 }
79
80 #-- 
81
82 sub myshutdown {
83   &reap_kids;
84
85   #kill all the kids
86   kill 'TERM', $_ foreach grep $_, map $_->{'_radacct_kid'}, @part_export;
87
88   my $wait = 12; #wait up to 1 minute
89   while ( ( grep $_->{'_radacct_kid'}, @part_export ) && $wait-- ) {
90     warn "waiting for children to terminate";
91     sleep 5;
92     &reap_kids;
93   }
94   warn "abandoning children" if grep $_->{'_radacct_kid'}, @part_export;
95   die "exiting";
96 }
97
98 sub reap_kids {
99   #warn "reaping kids\n";
100   foreach my $part_export ( grep $_->{'_radacct_kid'}, @part_export ) {
101     my $pid = $part_export->{'_radacct_kid'};
102     my $kid = waitpid($pid, WNOHANG);
103     if ( $kid > 0 ) {
104       $part_export->{'_radacct_kid'} = '';
105     }
106   }
107   #warn "done reaping\n";
108 }
109
110 sub usage {
111   die "Usage:\n\n  freeside-sqlradius-radacctd user\n";
112 }
113
114 =head1 NAME
115
116 freeside-sqlradius-radacctd - Real-time radacct import daemon
117
118 =head1 SYNOPSIS
119
120   freeside-sqlradius-radacctd username
121
122 =head1 DESCRIPTION
123
124 Imports records from an the SQL radacct tables of all sqlradius and
125 sqlradius_withdomain exports (except those with the ignore_accounting flag) and
126 updates the svc_acct.seconds for each account.  Runs as a daemon and updates
127 the database in real-time.
128
129 B<username> is a username added by freeside-adduser.
130
131 =head1 RADIUS DATABASE CHANGES
132
133 ALTER TABLE radacct ADD COLUMN FreesideStatus varchar(32) NULL;
134
135 If you want to ignore the existing accountg records, also do:
136
137 UPDATE TABLE radacct SET FreesideStatus = 'done' WHERE FreesideStatus IS NULL;
138
139 =head1 SEE ALSO
140
141 =cut
142
143 1;
144