diff options
Diffstat (limited to 'FS/bin/freeside-sqlradius-radacctd')
-rw-r--r-- | FS/bin/freeside-sqlradius-radacctd | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/FS/bin/freeside-sqlradius-radacctd b/FS/bin/freeside-sqlradius-radacctd new file mode 100644 index 000000000..e98eaa015 --- /dev/null +++ b/FS/bin/freeside-sqlradius-radacctd @@ -0,0 +1,150 @@ +#!/usr/bin/perl -w + +use strict; +use vars qw( @part_export ); +use subs qw(myshutdown); +use POSIX qw(:sys_wait_h); +#use IO::File; +use FS::Daemon qw(daemonize1 drop_root logfile daemonize2 sigint sigterm); +use FS::UID qw(adminsuidsetup); #forksuidsetup driver_name dbh myconnect); +use FS::Record qw(qsearch); # qsearchs); +use FS::part_export; +#use FS::svc_acct; +#use FS::cust_svc; + +my $user = shift or die &usage; + +#daemonize1('freeside-sqlradius-radacctd', $user); #keep unique pid files w/multi installs +daemonize1('freeside-sqlradius-radacctd'); + +drop_root(); + +#$ENV{HOME} = (getpwuid($>))[7]; #for ssh + +adminsuidsetup $user; + +logfile( "/usr/local/etc/freeside/sqlradius-radacctd-log.". $FS::UID::datasrc ); + +daemonize2(); + +#-- + +#don't just look for ->can('usage_sessions'), we're sqlradius-specific +# (radiator is supposed to be setup with a radacct table) + +@part_export = + qsearch('part_export', { 'exporttype' => 'sqlradius' } ); +push @part_export, + qsearch('part_export', { 'exporttype' => 'sqlradius_withdomain' } ); +push @part_export, + qsearch('part_export', { 'exporttype' => 'radiator' } ); + +@part_export = grep { ! $_->option('ignore_accounting') } @part_export; + +die "no sqlradius, sqlradius_withdomain or radiator exports without". + " ignore_accounting" + unless @part_export; + +while (1) { + + #fork off one kid per export (machine) + # _>{'_radacct_kid'} is an evil kludge + foreach my $part_export ( grep ! $_->{'_radacct_kid'}, @part_export ) { + + defined( my $pid = fork ) or do { + warn "WARNING: can't fork to spawn child for ". $part_export->machine; + next; + }; + + if ( $pid ) { + $part_export->{'_radacct_kid'} = $pid; + warn "child $pid spawned for ". $part_export->machine; + } else { #kid time + + adminsuidsetup($user); #get our own db handle + + until ( sigint || sigterm ) { + $part_export->update_svc_acct(); + sleep 1; + } + + warn "child for ". $part_export->machine. " done"; + exit; + + } #eo kid + + } + + #reap up any kids that died... + &reap_kids; + + myshutdown() if sigterm() || sigint(); + + sleep 5; +} + +#-- + +sub myshutdown { + &reap_kids; + + #kill all the kids + kill 'TERM', $_ foreach grep $_, map $_->{'_radacct_kid'}, @part_export; + + my $wait = 12; #wait up to 1 minute + while ( ( grep $_->{'_radacct_kid'}, @part_export ) && $wait-- ) { + warn "waiting for children to terminate"; + sleep 5; + &reap_kids; + } + warn "abandoning children" if grep $_->{'_radacct_kid'}, @part_export; + die "exiting"; +} + +sub reap_kids { + #warn "reaping kids\n"; + foreach my $part_export ( grep $_->{'_radacct_kid'}, @part_export ) { + my $pid = $part_export->{'_radacct_kid'}; + my $kid = waitpid($pid, WNOHANG); + if ( $kid > 0 ) { + $part_export->{'_radacct_kid'} = ''; + } + } + #warn "done reaping\n"; +} + +sub usage { + die "Usage:\n\n freeside-sqlradius-radacctd user\n"; +} + +=head1 NAME + +freeside-sqlradius-radacctd - Real-time radacct import daemon + +=head1 SYNOPSIS + + freeside-sqlradius-radacctd username + +=head1 DESCRIPTION + +Imports records from an the SQL radacct tables of all sqlradius, +sqlradius_withdomain and radiator exports (except those with the +ignore_accounting flag) and updates the svc_acct.seconds for each account. +Runs as a daemon and updates the database in real-time. + +B<username> is a username added by freeside-adduser. + +=head1 RADIUS DATABASE CHANGES + +ALTER TABLE radacct ADD COLUMN FreesideStatus varchar(32) NULL; + +If you want to ignore the existing accountg records, also do: + +UPDATE radacct SET FreesideStatus = 'done' WHERE FreesideStatus IS NULL; + +=head1 SEE ALSO + +=cut + +1; + |