#!/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::part_export::sqlradius; #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( "%%%FREESIDE_LOG%%%/sqlradius-radacctd-log.". $FS::UID::datasrc ); daemonize2(); #-- my @part_export = FS::part_export::sqlradius->all_sqlradius_withaccounting(); die "no sqlradius, sqlradius_withdomain, radiator or phone_sqlradius 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(); 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 following fields in svc_acct (see L) for each account: last_login, last_logout, seconds, upbytes, downbytes, totalbytes. Runs as a daemon and updates the database in real-time. B is a username added by freeside-adduser. =head1 RADIUS DATABASE CHANGES In 1.7.4+, freeside-upgrade should have taken care of these changes already. 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;