2005-04-05 21:17:33 +00:00
#!/usr/bin/perl
# +------------------------------------+
# | Inspire Internet Relay Chat Daemon |
# +------------------------------------+
#
2008-10-31 00:11:48 +00:00
# InspIRCd: (C) 2002-2008 InspIRCd Development Team
# See: http://www.inspircd.org/wiki/index.php/Credits
2005-04-05 21:17:33 +00:00
#
# This program is free but copyrighted software; see
2008-10-31 00:11:48 +00:00
# the file COPYING for details.
2005-04-05 21:17:33 +00:00
#
# ---------------------------------------------------
2008-10-31 00:11:48 +00:00
#
2007-02-04 22:52:06 +00:00
use POSIX ;
2005-04-05 21:17:33 +00:00
2006-12-04 17:03:10 +00:00
my $basepath = " @BASE_DIR@ " ;
my $confpath = " @CONFIG_DIR@/ " ;
my $binpath = " @BINARY_DIR@ " ;
my $libpath = " @LIBRARY_DIR@ " ;
2008-10-27 19:08:31 +00:00
my $valgrindlogpath = " $basepath /valgrindlogs " ;
2006-12-04 17:03:10 +00:00
my $executable = " @EXECUTABLE@ " ;
my $version = " @VERSION@ " ;
2005-05-29 22:07:33 +00:00
my @ filesparsed ;
2007-02-04 22:52:06 +00:00
my @ filechecked ;
2005-04-05 21:17:33 +00:00
# Lets see what they want to do.. Set the variable (Cause i'm a lazy coder)
my $arg = $ARGV [ 0 ];
2005-05-29 22:07:33 +00:00
getpidfile ( $confpath . " inspircd.conf " );
2005-04-05 21:17:33 +00:00
if ( $arg eq " start " ) { start (); exit (); }
2005-04-21 13:22:15 +00:00
if ( $arg eq " debug " ) { debug (); exit (); }
2006-05-07 10:10:53 +00:00
if ( $arg eq " screendebug " ) { screendebug (); exit () }
if ( $arg eq " valdebug " ) { valdebug (); exit (); }
2008-10-27 19:08:31 +00:00
if ( $arg eq " valdebug-unattended " ) { valdebugunattended (); exit (); }
2006-05-07 10:10:53 +00:00
if ( $arg eq " screenvaldebug " ) { screenvaldebug (); exit (); }
2005-04-05 21:17:33 +00:00
if ( $arg eq " stop " ) { stop (); exit (); }
if ( $arg eq " status " ) {
2007-02-04 22:52:06 +00:00
if ( getstatus () == 1 ) {
2005-04-05 21:17:33 +00:00
my $pid = getprocessid ();
print " InspIRCd is running (PID: $pid ) \n " ;
exit ();
} else {
print " InspIRCd is not running. (Or PID File not found) \n " ;
exit ();
}
}
if ( $arg eq " rehash " ) {
if ( getstatus () == 1 ) {
my $pid = getprocessid ();
2007-02-04 22:52:06 +00:00
system ( " kill -HUP $pid >/dev/null 2>&1 " );
2006-12-24 13:38:32 +00:00
print " InspIRCd rehashed (pid: $pid ). \n " ;
2005-04-05 21:17:33 +00:00
exit ();
} else {
print " InspIRCd is not running. (Or PID File not found) \n " ;
exit ();
}
}
if ( $arg eq " cron " ) {
2005-04-05 21:24:01 +00:00
if ( getstatus () == 0 ) { start (); }
exit ();
2005-04-05 21:17:33 +00:00
}
2006-12-04 17:03:10 +00:00
if ( $arg eq " version " ) {
print " InspIRCd version: $version\n " ;
exit ();
}
2005-04-05 21:17:33 +00:00
if ( $arg eq " restart " ) {
stop ();
2006-06-22 10:26:33 +00:00
unlink ( $pidfile ) if ( - e $pidfile );
2005-04-05 21:17:33 +00:00
start ();
# kthxbye();
exit ();
}
2007-02-04 22:52:06 +00:00
if ( $arg eq " checkconf " ) {
checkconf ();
exit ();
}
2005-04-05 21:17:33 +00:00
if ( $arg eq " Cheese-Sandwich " ) {
print " Creating Cheese Sandwich.. \n " ;
print " Done. \n " ;
exit ();
}
###
# If we get here.. bad / no parameters.
###
print " Invalid Argument: $arg\n " ;
2007-02-04 22:52:06 +00:00
print " Usage: inspircd (start|stop|restart|rehash|status|cron|checkconf|version) \n " ;
2008-10-27 19:08:31 +00:00
print " Developer arguments: (debug|screendebug|valdebug|valdebug-unattended|screenvaldebug) \n " ;
2005-04-05 21:17:33 +00:00
exit ();
###
# Generic Helper Functions.
###
sub start {
2007-02-04 22:52:06 +00:00
# Check to see its not 'running' already.
if ( getstatus () == 1 ) { print " InspIRCd is already running. \n " ; return 0 ; }
# If we are still alive here.. Try starting the IRCd..
2006-08-12 13:43:42 +00:00
print " $binpath / $executable doesn't exist \n " and return 0 unless ( - e " $binpath / $executable " );
2008-10-23 14:45:58 +00:00
print " $binpath / $executable is not executable \n " and return 0 unless ( - f " $binpath / $executable " && - x " $binpath / $executable " );
2006-08-12 13:43:42 +00:00
2007-02-04 22:52:06 +00:00
system ( " $binpath / $executable " );
return 1 ;
2005-04-05 21:17:33 +00:00
}
2005-04-21 13:22:15 +00:00
sub debug {
2006-05-07 10:10:53 +00:00
# Check to see its not 'running' already.
if ( getstatus () == 1 ) { print " InspIRCd is already running. \n " ; return 0 ; }
2007-02-04 22:52:06 +00:00
2006-08-12 13:43:42 +00:00
print " $binpath / $executable doesn't exist \n " and return 0 unless ( - e " $binpath / $executable " );
2008-10-23 14:45:58 +00:00
print " $binpath / $executable is not executable \n " and return 0 unless ( - f " $binpath / $executable " && - x " $binpath / $executable " );
2007-02-04 22:52:06 +00:00
2006-05-07 10:10:53 +00:00
# Check we have gdb
checkgdb ();
2007-02-04 22:52:06 +00:00
2006-05-07 10:10:53 +00:00
# If we are still alive here.. Try starting the IRCd..
2008-04-12 17:55:47 +00:00
system ( " gdb --command= $basepath /.gdbargs --args $binpath / $executable -nofork -debug " );
2005-04-21 13:22:15 +00:00
}
2006-05-07 10:10:53 +00:00
sub screendebug
{
# Check to see its not 'running' already.
if ( getstatus () == 1 ) { print " InspIRCd is already running. \n " ; return 0 ; }
2007-02-04 22:52:06 +00:00
2006-08-12 13:43:42 +00:00
print " $binpath / $executable doesn't exist \n " and return 0 unless ( - e " $binpath / $executable " );
2006-05-07 10:10:53 +00:00
#Check we have gdb
checkgdb ();
checkscreen ();
2007-02-04 22:52:06 +00:00
2006-05-07 10:10:53 +00:00
# If we are still alive here.. Try starting the IRCd..
print " Starting InspIRCd in `screen`, type `screen -r` when the ircd crashes to view the gdb output and get a backtrace. \n " ;
print " Once you're inside the screen session press ^C + d to re-detach from the session \n " ;
2006-08-06 22:26:18 +00:00
system ( " screen -m -d gdb --command= $basepath /.gdbargs --args $binpath / $executable -nofork -debug -nolog " );
2006-05-07 10:10:53 +00:00
}
sub valdebug
{
# Check to see its not 'running' already.
if ( getstatus () == 1 ) { print " InspIRCd is already running. \n " ; return 0 ; }
2006-08-12 13:43:42 +00:00
print " $binpath / $executable doesn't exist \n " and return 0 unless ( - e " $binpath / $executable " );
2008-10-23 14:45:58 +00:00
print " $binpath / $executable is not executable \n " and return 0 unless ( - f " $binpath / $executable " && - x " $binpath / $executable " );
2006-08-12 13:43:42 +00:00
2006-05-07 10:10:53 +00:00
# Check we have valgrind and gdb
checkvalgrind ();
checkgdb ();
2007-02-04 22:52:06 +00:00
2006-05-07 10:10:53 +00:00
# If we are still alive here.. Try starting the IRCd..
# May want to do something with these args at some point: --suppressions=.inspircd.sup --gen-suppressions=yes
# Could be useful when we want to stop it complaining about things we're sure aren't issues.
system ( " valgrind -v --tool=memcheck --leak-check=yes --db-attach=yes --num-callers=10 $binpath / $executable -nofork -debug -nolog " );
}
2008-10-27 19:08:31 +00:00
sub valdebugunattended
{
# NOTE: To make sure valgrind generates coredumps, set soft core limit in /etc/security/limits.conf to unlimited
# Check to see its not 'running' already.
if ( getstatus () == 1 ) { print " InspIRCd is already running. \n " ; return 0 ; }
print " $binpath / $executable doesn't exist \n " and return 0 unless ( - e " $binpath / $executable " );
print " $binpath / $executable is not executable \n " and return 0 unless ( - f " $binpath / $executable " && - x " $binpath / $executable " );
# Check we have valgrind and gdb
checkvalgrind ();
checkgdb ();
# If we are still alive here.. Try starting the IRCd..
# May want to do something with these args at some point: --suppressions=.inspircd.sup --gen-suppressions=yes
# Could be useful when we want to stop it complaining about things we're sure aren't issues.
#
# NOTE: Saving the debug log (redirected stdout), while useful, is a potential security risk AND one hell of a spacehog. DO NOT SAVE THIS WHERE EVERYONE HAS ACCESS!
# Redirect stdout to /dev/null if you're worried about the security.
#
2008-10-27 20:15:53 +00:00
my $pid = fork ;
if ( $pid == 0 ) {
POSIX :: setsid ();
2008-10-27 22:19:43 +00:00
umask 022 ;
open STDERR , '>' , " $valgrindlogpath /valdebug. $ $ " or die $ ! ;
2008-10-27 20:15:53 +00:00
umask 066 ;
open STDIN , '/dev/null' or die $ ! ;
open STDOUT , '>' , " $valgrindlogpath /out. $ $ " or die $ ! ;
2008-10-27 22:19:43 +00:00
exec " valgrind -v --tool=memcheck --leak-check=yes --num-callers=10 --time-stamp=yes --log-fd=2 $binpath / $executable -nofork -debug -nolog " ;
2008-10-27 20:15:53 +00:00
exit 1 ;
}
2008-10-27 19:08:31 +00:00
}
2006-05-07 10:10:53 +00:00
sub screenvaldebug
{
# Check to see its not 'running' already.
if ( getstatus () == 1 ) { print " InspIRCd is already running. \n " ; return 0 ; }
2007-02-04 22:52:06 +00:00
2006-08-12 13:43:42 +00:00
print " $binpath / $executable doesn't exist \n " and return 0 unless ( - e " $binpath / $executable " );
2008-10-23 14:45:58 +00:00
print " $binpath / $executable is not executable \n " and return 0 unless ( - f " $binpath / $executable " && - x " $binpath / $executable " );
2006-08-12 13:43:42 +00:00
2006-05-07 10:10:53 +00:00
#Check we have gdb
checkvalgrind ();
checkgdb ();
checkscreen ();
2007-02-04 22:52:06 +00:00
2006-05-07 10:10:53 +00:00
# If we are still alive here.. Try starting the IRCd..
print " Starting InspIRCd in `screen`, type `screen -r` when the ircd crashes to view the valgrind and gdb output and get a backtrace. \n " ;
print " Once you're inside the screen session press ^C + d to re-detach from the session \n " ;
system ( " screen -m -d valgrind -v --tool=memcheck --leak-check=yes --db-attach=yes --num-callers=10 $binpath / $executable -nofork -debug -nolog " );
}
2005-04-21 13:22:15 +00:00
2005-04-05 21:17:33 +00:00
sub stop {
2007-02-04 22:52:06 +00:00
if ( getstatus () == 0 ) { print " InspIRCd is not running. (Or PID File not found) \n " ; return 0 ; }
# Get to here, we have something to kill.
my $pid = getprocessid ();
2006-12-24 13:38:32 +00:00
print " Stopping InspIRCd (pid: $pid )... \n " ;
2008-10-28 18:29:40 +00:00
my $maxwait = ( `ps -o command $pid` =~ / valgrind / i ) ? 30 : 5 ;
kill TERM => $pid ;
for ( 1. . $maxwait ) {
sleep 1 ;
if ( getstatus () == 1 ) {
print " InspIRCd Stopped. \n " ;
return ;
}
2005-04-08 23:03:18 +00:00
}
2008-10-28 18:29:40 +00:00
print " InspIRCd not dying quietly -- forcing kill \n " ;
kill KILL => $pid ;
2005-04-05 21:17:33 +00:00
}
2005-05-29 22:07:33 +00:00
# GetPidfile Version 2 - Now With Include Support..
2007-02-04 22:52:06 +00:00
# I beg for months for include support in insp, then..
2005-05-29 22:07:33 +00:00
# when it is added, it comes around and BITES ME IN THE ASS,
# because i then have to code support into this script.. Evil.
2005-04-05 21:17:33 +00:00
2006-12-24 13:38:32 +00:00
# Craig got bitten in the ass again --
# in 1.1 beta the include file is manditory, therefore
# if we cant find it, default to %conf%/inspircd.pid.
# Note, this also contains a fix for when the pid file is
# defined, but defined in a comment (line starts with #)
# -- Brain
2005-04-05 21:17:33 +00:00
sub getpidfile {
2005-05-29 22:07:33 +00:00
my ( $file ) = @ _ ;
# Before we start, do we have a PID already? (Should never occur)
if ( $pid ne " " ) {
return ;
}
# Are We using a relative path?
if ( $file !~ /^ \ //) {
# Convert it to a full path..
$file = $confpath . $file ;
}
# Have we checked this file before?
for ( my $i = 0 ; $i < $filesparsed ; $i ++ ) {
if ( $filesparsed [ $i ] eq $file ) {
# Already Parsed, Possible recursive loop..
return ;
}
}
2007-02-04 22:52:06 +00:00
2005-05-29 22:07:33 +00:00
# If we get here, Mark as 'Read'
$filesparsed [ $filesparsed ] = $file ;
# Open the File..
2006-12-24 13:38:32 +00:00
open INFILE , " < $file " or die " Unable to open file $file\n " ;
2005-05-29 22:07:33 +00:00
# Grab entire file contents..
my ( @ lines ) = < INFILE > ;
# Close the file
close INFILE ;
2007-01-08 04:13:23 +00:00
# remove trailing spaces
2005-05-29 22:07:33 +00:00
chomp ( @ lines );
foreach $i ( @ lines ) {
2007-01-08 04:13:23 +00:00
# clean it up
2005-05-29 22:07:33 +00:00
$i =~ s / [ ^= ] += \s ( .* ) / \1 / ;
2007-01-08 04:13:23 +00:00
# Does this file have a pid?
if (( $i =~ /< pid file = \ " ( \ S+) \" >/i) && ( $i !~ /^#/))
{
# Set the PID file and return.
$pidfile = $ 1 ;
return ;
}
2005-05-29 22:07:33 +00:00
}
2007-01-08 04:13:23 +00:00
# If we get here, NO PID FILE! -- Check for includes
foreach $i ( @ lines ) {
$i =~ s / [ ^= ] += \s ( .* ) / \1 / ;
if (( $i =~ s / \ < include file = \ " (.+?) \" \ >//i) && ( $i !~ /^#/))
2005-05-29 22:07:33 +00:00
{
# Decend into that file, and check for PIDs.. (that sounds like an STD ;/)
getpidfile ( $ 1 );
# Was a PID found?
if ( $pidfile ne " " ) {
2007-02-04 22:52:06 +00:00
# Yes, Return.
return ;
2005-05-29 22:07:33 +00:00
}
}
}
2007-01-08 04:13:23 +00:00
# End of includes / No includes found. Using default.
$pidfile = $confpath . " inspircd.pid " ;
2005-04-05 21:17:33 +00:00
}
sub getstatus {
2007-02-04 22:52:06 +00:00
my $pid = getprocessid ();
2008-10-28 18:29:40 +00:00
return 0 if $pid == 0 ;
return kill 0 , $pid ;
2005-04-05 21:17:33 +00:00
}
sub getprocessid {
my $pid ;
2005-04-05 21:21:04 +00:00
open PIDFILE , " < $pidfile " or return 0 ;
2005-04-05 21:17:33 +00:00
while ( $i = < PIDFILE > )
{
$pid = $i ;
}
close PIDFILE ;
return $pid ;
}
2006-05-07 10:10:53 +00:00
sub checkvalgrind
{
unless ( `valgrind --version` )
{
print " Couldn't start valgrind: $ ! \n " ;
exit ;
}
}
sub checkgdb
{
unless ( `gdb --version` )
{
print " Couldn't start gdb: $ ! \n " ;
exit ;
}
}
sub checkscreen
{
unless ( `screen --version` )
{
print " Couldn't start screen: $ ! \n " ;
exit ;
}
}
2007-02-04 22:52:06 +00:00
sub checkxmllint
{
open ( FH , " xmllint| " ) or die " Couldn't start xmllint: $ ! \n " ;
}
sub checkconf
{
checkxmllint ();
validateconf ( $confpath . " inspircd.conf " );
print " Config check complete \n " ;
}
sub validateconf
{
my ( $file ) = @ _ ;
# Are We using a relative path?
if ( $file !~ /^ \ //) {
# Convert it to a full path..
$file = $confpath . $file ;
}
# Have we checked this file before?
for ( my $i = 0 ; $i < $filechecked ; $i ++ ) {
if ( $filechecked [ $i ] eq $file ) {
# Already Parsed, Possible recursive loop..
return ;
}
}
# If we get here, Mark as 'Read'
$filechecked [ $filechecked ] = $file ;
# Open the File..
open INFILE , " < $file " or die " Unable to open file $file\n " ;
# Grab entire file contents..
my ( @ lines ) = < INFILE > ;
# Close the file
close INFILE ;
# remove trailing spaces
chomp ( @ lines );
my @ newlines = ();
my @ blanks = ();
my $conline ;
push @ newlines , " <?xml version= \" 1.0 \" encoding= \" ISO-8859-1 \" ?> " ;
# push @newlines, "<!DOCTYPE config SYSTEM \"".$confpath."inspircd.dtd\">";
push @ newlines , " <config> " ;
2007-02-05 18:26:59 +00:00
foreach $i ( @ lines )
{
2007-02-04 22:52:06 +00:00
# remove trailing newlines
chomp ( $i );
# convert tabs to spaces
$i =~ s / \t / / g ;
# remove leading spaces
$i =~ s /^ *// ;
# remove comments
$i =~ s /^ #.*//;
# remove trailing #s
$i =~ s / ( .* ) #$/\1/;
2007-02-05 18:26:59 +00:00
# remove trailing comments
my $line = " " ;
my $quote = 0 ;
for ( my $j = 0 ; $j < length ( $i ); $j ++ )
{
if ( substr ( $i , $j , 1 ) eq '"' ) { $quote = ( $quote ) ? 0 : 1 ; } elsif ( substr ( $i , $j , 1 ) eq " # " && ! $quote ) { last ; }
$line .= substr ( $i , $j , 1 );
}
$i = $line ;
2007-02-04 22:52:06 +00:00
# remove trailing spaces
$i =~ s / * $ //;
2007-02-10 21:26:32 +00:00
# setup incf for include check and clean it up, since this breaks parsing use local var
my $incf = $i ;
$incf =~ s / [ ^= ] += \s ( .* ) / \1 / ;
2007-02-04 22:52:06 +00:00
# include file?
2007-02-10 21:26:32 +00:00
if (( $incf =~ s / \ < include file = \ " (.+?) \" \ >//i) && ( $incf !~ /^#/))
2007-02-04 22:52:06 +00:00
{
# yes, process it
validateconf ( $ 1 );
}
if ( $i =~ /^<.*/ && $conline =~ /^<.*/ )
{
push @ newlines , $conline ;
push @ newlines , @ blanks ;
$conline = $i ;
}
if ( $i =~ /^<.*> $ / )
{
$i =~ s / ( .* ) > $ / \1 \ />/ ;
push @ newlines , $i ;
}
elsif ( $i =~ /.*> $ / )
{
$conline .= " $i " ;
$conline =~ s / ( .* ) > $ / \1 \ />/ ;
push @ blanks , " " ;
push @ newlines , $conline ;
push @ newlines , @ blanks ;
$conline = " " ;
undef @ blanks ;
}
elsif ( $i =~ /^<.*/ )
{
$conline = $i ;
}
elsif ( $conline =~ /^<.*/ && $i )
{
$conline .= " $i " ;
push @ blanks , " " ;
}
else
{
if ( $conline )
{
push @ blanks , $i ;
}
else
{
push @ newlines , $i ;
}
}
}
if ( $conline )
{
push @ newlines , $conline ;
push @ newlines , @ blanks ;
}
push @ newlines , " </config> " ;
my $tmpfile ;
do
{
$tmpfile = tmpnam ();
} until sysopen ( TF , $tmpfile , O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW , 0700 );
foreach $n ( @ newlines )
{
print TF " $n\n " ;
}
close TF ;
my @ result = `xmllint -noout $tmpfile 2>&1` ;
chomp ( @ result );
my $skip = 0 ;
foreach $n ( @ result )
{
if ( $skip )
{
$skip = 0 ;
next ;
}
$n =~ s / $tmpfile\ : \d * \ : *// g ;
if ( $n =~ /.* config >.*/ )
{
$n = " " ;
$skip = 1 ;
}
if ( $n && ! $skip )
{
if ( $n =~ / line \d */ )
{
my $lineno = $n ;
$lineno =~ s /.* line ( \d * ) .*/ \1 / ;
$lineno = $lineno - 2 ;
$n =~ s / line ( \d * ) / line $lineno / ;
}
print " $file : $n\n " ;
}
}
unlink ( $tmpfile );
}