]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - .inspircd.inc
- These two need to be generated by configure.exe (someone smack me if I'm wrong...
[user/henk/code/inspircd.git] / .inspircd.inc
1 #!/usr/bin/perl
2 #       +------------------------------------+
3 #       | Inspire Internet Relay Chat Daemon |
4 #       +------------------------------------+
5 #
6 #  Inspire is copyright (C) 2002-2004 ChatSpike-Dev.
7 #                       E-mail:
8 #                <brain@chatspike.net>
9 #                <Craig@chatspike.net>
10 #
11 # Written by Craig Edwards, Craig McLure, and others.
12 # This program is free but copyrighted software; see
13 #            the file COPYING for details.
14 #
15 #               I HATE PERL.. kthxbye
16 # ---------------------------------------------------
17 use POSIX;
18
19 my $basepath    =       "@BASE_DIR@";
20 my $confpath    =       "@CONFIG_DIR@/";
21 my $binpath     =       "@BINARY_DIR@";
22 my $libpath     =       "@LIBRARY_DIR@";
23 my $executable  =       "@EXECUTABLE@";
24 my $version     =       "@VERSION@";
25 my @filesparsed;
26 my @filechecked;
27
28 # Lets see what they want to do.. Set the variable (Cause i'm a lazy coder)
29 my $arg = $ARGV[0];
30 getpidfile($confpath."inspircd.conf");
31
32 if ($arg eq "start") { start(); exit(); }
33 if ($arg eq "debug") { debug(); exit(); }
34 if ($arg eq "screendebug") { screendebug(); exit() }
35 if ($arg eq "valdebug") { valdebug(); exit(); }
36 if ($arg eq "screenvaldebug") { screenvaldebug(); exit(); }
37 if ($arg eq "stop") { stop(); exit(); }
38 if ($arg eq "status") {
39         if (getstatus() == 1) {
40                 my $pid = getprocessid();
41                 print "InspIRCd is running (PID: $pid)\n";
42                 exit();
43         } else {
44                 print "InspIRCd is not running. (Or PID File not found)\n";
45                 exit();
46         }
47 }
48 if ($arg eq "rehash") {
49         if (getstatus() == 1) {
50                 my $pid = getprocessid();
51                 system("kill -HUP $pid >/dev/null 2>&1");
52                 print "InspIRCd rehashed (pid: $pid).\n";
53                 exit();
54         } else {
55                 print "InspIRCd is not running. (Or PID File not found)\n";
56                 exit();
57         }
58 }
59
60 if ($arg eq "cron") {
61         if (getstatus() == 0) { start(); }
62         exit();
63 }
64
65 if ($arg eq "version") {
66         print "InspIRCd version: $version\n";
67         exit();
68 }
69
70 if ($arg eq "restart") {
71         stop();
72         unlink($pidfile) if (-e $pidfile);
73         start();
74         # kthxbye();
75         exit();
76 }
77
78 if ($arg eq "checkconf") {
79         checkconf();
80         exit();
81 }
82
83 if ($arg eq "Cheese-Sandwich") {
84         print "Creating Cheese Sandwich..\n";
85         print "Done.\n";
86         exit();
87 }
88
89 ###
90 # If we get here.. bad / no parameters.
91 ###
92 print "Invalid Argument: $arg\n";
93 print "Usage: inspircd (start|stop|restart|rehash|status|cron|checkconf|version)\n";
94 exit();
95
96 ###
97 # Generic Helper Functions.
98 ###
99
100 sub start {
101         # Check to see its not 'running' already.
102         if (getstatus() == 1) { print "InspIRCd is already running.\n"; return 0; }
103         # If we are still alive here.. Try starting the IRCd..
104         print "$binpath/$executable doesn't exist\n" and return 0 unless(-e "$binpath/$executable");
105
106         system("$binpath/$executable");
107         return 1;
108 }
109
110 sub debug {
111         # Check to see its not 'running' already.
112         if (getstatus() == 1) { print "InspIRCd is already running.\n"; return 0; }
113
114         print "$binpath/$executable doesn't exist\n" and return 0 unless(-e "$binpath/$executable");
115
116         # Check we have gdb
117         checkgdb();
118
119         # If we are still alive here.. Try starting the IRCd..
120         system("gdb --command=$basepath/.gdbargs --args $binpath/$executable -nofork -debug -nolog");
121 }
122
123 sub screendebug
124 {
125         # Check to see its not 'running' already.
126         if (getstatus() == 1) { print "InspIRCd is already running.\n"; return 0; }
127
128         print "$binpath/$executable doesn't exist\n" and return 0 unless(-e "$binpath/$executable");
129
130         #Check we have gdb
131         checkgdb();
132         checkscreen();
133
134         # If we are still alive here.. Try starting the IRCd..
135         print "Starting InspIRCd in `screen`, type `screen -r` when the ircd crashes to view the gdb output and get a backtrace.\n";
136         print "Once you're inside the screen session press ^C + d to re-detach from the session\n";
137         system("screen -m -d gdb --command=$basepath/.gdbargs --args $binpath/$executable -nofork -debug -nolog");
138 }
139
140 sub valdebug
141 {
142         # Check to see its not 'running' already.
143         if (getstatus() == 1) { print "InspIRCd is already running.\n"; return 0; }
144
145         print "$binpath/$executable doesn't exist\n" and return 0 unless(-e "$binpath/$executable");
146
147         # Check we have valgrind and gdb
148         checkvalgrind();
149         checkgdb();
150
151         # If we are still alive here.. Try starting the IRCd..
152         # May want to do something with these args at some point: --suppressions=.inspircd.sup --gen-suppressions=yes
153         # Could be useful when we want to stop it complaining about things we're sure aren't issues.
154         system("valgrind -v --tool=memcheck --leak-check=yes --db-attach=yes --num-callers=10 $binpath/$executable -nofork -debug -nolog");
155 }
156
157 sub screenvaldebug
158 {
159         # Check to see its not 'running' already.
160         if (getstatus() == 1) { print "InspIRCd is already running.\n"; return 0; }
161
162         print "$binpath/$executable doesn't exist\n" and return 0 unless(-e "$binpath/$executable");
163
164         #Check we have gdb
165         checkvalgrind();
166         checkgdb();
167         checkscreen();
168
169         # If we are still alive here.. Try starting the IRCd..
170         print "Starting InspIRCd in `screen`, type `screen -r` when the ircd crashes to view the valgrind and gdb output and get a backtrace.\n";
171         print "Once you're inside the screen session press ^C + d to re-detach from the session\n";
172         system("screen -m -d valgrind -v --tool=memcheck --leak-check=yes --db-attach=yes --num-callers=10 $binpath/$executable -nofork -debug -nolog");
173 }
174
175 sub stop {
176         if (getstatus() == 0) { print "InspIRCd is not running. (Or PID File not found)\n"; return 0; }
177         # Get to here, we have something to kill.
178         my $pid = getprocessid();
179         print "Stopping InspIRCd (pid: $pid)...\n";
180         system("kill -TERM $pid >/dev/null 2>&1");
181         # Give it a second to exit
182         sleep(1);
183         if (getstatus() == 1)
184         {
185                 print "InspIRCd not dying quietly -- forcing kill\n";
186                 system("kill -9 $pid >/dev/null 2>&1");
187         }
188         print "InspIRCd Stopped.\n";
189 }
190
191 # GetPidfile Version 2 - Now With Include Support..
192 # I beg for months for include support in insp, then..
193 # when it is added, it comes around and BITES ME IN THE ASS,
194 # because i then have to code support into this script.. Evil.
195
196 # Craig got bitten in the ass again --
197 # in 1.1 beta the include file is manditory, therefore
198 # if we cant find it, default to %conf%/inspircd.pid.
199 # Note, this also contains a fix for when the pid file is
200 # defined, but defined in a comment (line starts with #)
201 # -- Brain
202
203 sub getpidfile {
204   my ($file) = @_;
205   # Before we start, do we have a PID already? (Should never occur)
206   if ($pid ne "") {
207     return;
208   }
209   # Are We using a relative path?
210   if ($file !~ /^\//) {
211     # Convert it to a full path..
212     $file = $confpath . $file;
213   }
214
215   # Have we checked this file before?
216   for (my $i = 0; $i < $filesparsed; $i++) {
217     if ($filesparsed[$i] eq $file) {
218       # Already Parsed, Possible recursive loop..
219       return;
220     }
221   }
222
223   # If we get here, Mark as 'Read'
224   $filesparsed[$filesparsed] = $file;
225
226   # Open the File..
227   open INFILE, "< $file" or die "Unable to open file $file\n";
228   # Grab entire file contents..
229   my(@lines) = <INFILE>;
230   # Close the file
231   close INFILE;
232
233   # remove trailing spaces
234   chomp(@lines);
235   foreach $i (@lines) {
236     # clean it up
237     $i =~ s/[^=]+=\s(.*)/\1/;
238     # Does this file have a pid?
239     if (($i =~ /<pid file=\"(\S+)\">/i) && ($i !~ /^#/))
240     {
241       # Set the PID file and return.
242       $pidfile = $1;
243       return;
244     }
245   }
246
247   # If we get here, NO PID FILE! -- Check for includes
248   foreach $i (@lines) {
249     $i =~ s/[^=]+=\s(.*)/\1/;
250     if (($i =~ s/\<include file=\"(.+?)\"\>//i) && ($i !~ /^#/))
251     {
252       # Decend into that file, and check for PIDs.. (that sounds like an STD ;/)
253       getpidfile($1);
254       # Was a PID found?
255       if ($pidfile ne "") {
256         # Yes, Return.
257         return;
258       }
259     }
260   }
261
262   # End of includes / No includes found. Using default.
263   $pidfile = $confpath . "inspircd.pid";
264 }
265
266 sub getstatus {
267         my $pid = getprocessid();
268         if ($pid == 0) { return 0; }
269         $status = system("kill -0 $pid >/dev/null 2>&1") / 256;
270         if ($status == 0) { return 1; }
271         else { return 0; }
272 }
273
274
275 sub getprocessid {
276         my $pid;
277         open PIDFILE, "< $pidfile" or return 0;
278         while($i = <PIDFILE>)
279         {
280                 $pid = $i;
281         }
282         close PIDFILE;
283         return $pid;
284 }
285
286 sub checkvalgrind
287 {
288         unless(`valgrind --version`)
289         {
290                 print "Couldn't start valgrind: $!\n";
291                 exit;
292         }
293 }
294
295 sub checkgdb
296 {
297         unless(`gdb --version`)
298         {
299                 print "Couldn't start gdb: $!\n";
300                 exit;
301         }
302 }
303
304 sub checkscreen
305 {
306         unless(`screen --version`)
307         {
308                 print "Couldn't start screen: $!\n";
309                 exit;
310         }
311 }
312
313 sub checkxmllint
314 {
315         open(FH, "xmllint|") or die "Couldn't start xmllint: $!\n";
316 }
317
318 sub checkconf
319 {
320         checkxmllint();
321         validateconf($confpath."inspircd.conf");
322         print "Config check complete\n";
323 }
324
325 sub validateconf
326 {
327         my ($file) = @_;
328
329         # Are We using a relative path?
330         if ($file !~ /^\//) {
331                 # Convert it to a full path..
332                 $file = $confpath . $file;
333         }
334
335         # Have we checked this file before?
336         for (my $i = 0; $i < $filechecked; $i++) {
337                 if ($filechecked[$i] eq $file) {
338                         # Already Parsed, Possible recursive loop..
339                         return;
340                 }
341         }
342
343         # If we get here, Mark as 'Read'
344         $filechecked[$filechecked] = $file;
345
346         # Open the File..
347         open INFILE, "< $file" or die "Unable to open file $file\n";
348         # Grab entire file contents..
349         my(@lines) = <INFILE>;
350         # Close the file
351         close INFILE;
352
353         # remove trailing spaces
354         chomp(@lines);
355
356         my @newlines = ();
357         my @blanks = ();
358         my $conline;
359
360         push @newlines, "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>";
361 #       push @newlines, "<!DOCTYPE config SYSTEM \"".$confpath."inspircd.dtd\">";
362         push @newlines, "<config>";
363
364         foreach $i (@lines)
365         {
366                 # remove trailing newlines
367                 chomp($i);
368
369                 # convert tabs to spaces
370                 $i =~ s/\t/ /g;
371
372                 # remove leading spaces
373                 $i =~ s/^ *//;
374
375                 # remove comments
376                 $i =~ s/^#.*//;
377
378                 # remove trailing #s
379                 $i =~ s/(.*)#$/\1/;
380
381                 # remove trailing comments
382                 my $line = "";
383                 my $quote = 0;
384                 for (my $j = 0; $j < length($i); $j++)
385                 {
386                         if (substr($i,$j, 1) eq '"') { $quote = ($quote) ? 0 : 1; } elsif (substr($i,$j, 1) eq "#" && !$quote) { last; }
387                         $line .= substr($i,$j, 1);
388                 }
389                 $i = $line;
390
391                 # remove trailing spaces
392                 $i =~ s/ *$//;
393
394                 # setup incf for include check and clean it up, since this breaks parsing use local var
395                 my $incf = $i;
396                 $incf =~ s/[^=]+=\s(.*)/\1/;
397
398                 # include file?
399                 if (($incf =~ s/\<include file=\"(.+?)\"\>//i) && ($incf !~ /^#/))
400                 {
401                         # yes, process it
402                         validateconf($1);
403                 }
404
405                 if ($i =~ /^<.*/ && $conline =~ /^<.*/)
406                 {
407                         push @newlines, $conline;
408                         push @newlines, @blanks;
409                         $conline = $i;
410                 }
411
412                 if ($i =~ /^<.*>$/)
413                 {
414                         $i =~ s/(.*)>$/\1 \/>/;
415                         push @newlines, $i;
416                 }
417                 elsif ($i =~ /.*>$/)
418                 {
419                         $conline .= " $i";
420                         $conline =~ s/(.*)>$/\1 \/>/;
421                         push @blanks, "";
422                         push @newlines, $conline;
423                         push @newlines, @blanks;
424                         $conline = "";
425                         undef @blanks;
426                 }
427                 elsif ($i =~ /^<.*/)
428                 {
429                         $conline = $i;
430                 }
431                 elsif ($conline =~ /^<.*/ && $i)
432                 {
433                         $conline .= " $i";
434                         push @blanks, "";
435                 }
436                 else
437                 {
438                         if ($conline)
439                         {
440                                 push @blanks, $i;
441                         }
442                         else
443                         {
444                                 push @newlines, $i;
445                         }
446                 }
447         }
448         if ($conline)
449         {
450                 push @newlines, $conline;
451                 push @newlines, @blanks;
452         }
453
454         push @newlines, "</config>";
455
456         my $tmpfile;
457         do
458         {
459                 $tmpfile = tmpnam();
460         } until sysopen(TF, $tmpfile, O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW, 0700);
461
462         foreach $n (@newlines)
463         {
464                 print TF "$n\n";
465         }
466         close TF;
467
468         my @result = `xmllint -noout $tmpfile 2>&1`;
469         chomp(@result);
470
471         my $skip = 0;
472         foreach $n (@result)
473         {
474                 if ($skip)
475                 {
476                         $skip = 0;
477                         next;
478                 }
479                 $n =~ s/$tmpfile\:\d*\: *//g;
480                 if ($n =~ /.*config>.*/)
481                 {
482                         $n = "";
483                         $skip = 1;
484                 }
485
486                 if ($n && !$skip)
487                 {
488                         if ($n =~ /line \d*/)
489                         {
490                                 my $lineno = $n;
491                                 $lineno =~ s/.*line (\d*).*/\1/;
492                                 $lineno = $lineno-2;
493                                 $n =~ s/line (\d*)/line $lineno/;
494                         }
495                         print "$file : $n\n";
496                 }
497         }
498         unlink($tmpfile);
499 }