]> arthur.barton.de Git - ngircd-alex.git/blob - src/ngircd/ngircd.c
- Sourcen auf weitere Module fuer IRC-Befehle aufgesplitted.
[ngircd-alex.git] / src / ngircd / ngircd.c
1 /*
2  * ngIRCd -- The Next Generation IRC Daemon
3  * Copyright (c)2001,2002 by Alexander Barton (alex@barton.de)
4  *
5  * Dieses Programm ist freie Software. Sie koennen es unter den Bedingungen
6  * der GNU General Public License (GPL), wie von der Free Software Foundation
7  * herausgegeben, weitergeben und/oder modifizieren, entweder unter Version 2
8  * der Lizenz oder (wenn Sie es wuenschen) jeder spaeteren Version.
9  * Naehere Informationen entnehmen Sie bitter der Datei COPYING. Eine Liste
10  * der an ngIRCd beteiligten Autoren finden Sie in der Datei AUTHORS.
11  *
12  * $Id: ngircd.c,v 1.28 2002/02/27 23:24:29 alex Exp $
13  *
14  * ngircd.c: Hier beginnt alles ;-)
15  *
16  * $Log: ngircd.c,v $
17  * Revision 1.28  2002/02/27 23:24:29  alex
18  * - ueberfluessige Init- und Exit-Funktionen entfernt.
19  *
20  * Revision 1.27  2002/02/25 11:42:47  alex
21  * - wenn ein System sigaction() nicht kennt, so wird nun signal() verwendet.
22  *
23  * Revision 1.26  2002/02/23 19:06:47  alex
24  * - fuer SIGCHLD wird nun auch SA_NOCLDWAIT gesetzt, wenn vorhanden.
25  *
26  * Revision 1.25  2002/02/19 20:30:47  alex
27  * - SA_RESTART wird fuer Signale nur noch gesetzt, wenn es definiert ist.
28  *
29  * Revision 1.24  2002/02/19 20:08:24  alex
30  * - "Passive-Mode" implementiert: kein Auto-Conect zu anderen Servern.
31  * - NGIRCd_DebugLevel wird (fuer VERSION-Befehl) ermittelt.
32  *
33  * Revision 1.23  2002/02/17 23:40:21  alex
34  * - neue Funktion NGIRCd_VersionAddition(). NGIRCd_Version() aufgespaltet.
35  *
36  * Revision 1.22  2002/01/22 17:15:39  alex
37  * - die Fehlermeldung "interrupted system call" sollte nicht mehr auftreten.
38  *
39  * Revision 1.21  2002/01/21 00:02:11  alex
40  * - Hilfetexte korrigiert und ergaenzt (Sniffer).
41  *
42  * Revision 1.20  2002/01/18 11:12:11  alex
43  * - der Sniffer wird nun nur noch aktiviert, wenn auf Kommandozeile angegeben.
44  *
45  * Revision 1.19  2002/01/12 00:17:28  alex
46  * - ngIRCd wandelt sich nun selber in einen Daemon (Hintergrundprozess) um.
47  *
48  * Revision 1.18  2002/01/11 14:45:18  alex
49  * - Kommandozeilen-Parser implementiert: Debug- und No-Daemon-Modus, Hilfe.
50  *
51  * Revision 1.17  2002/01/02 02:51:16  alex
52  * - Signal-Handler fuer SIGCHLD: so sollten Zombies nicht mehr vorkommen.
53  *
54  * Revision 1.15  2001/12/31 02:18:51  alex
55  * - viele neue Befehle (WHOIS, ISON, OPER, DIE, RESTART),
56  * - neuen Header "defines.h" mit (fast) allen Konstanten.
57  * - Code Cleanups und viele "kleine" Aenderungen & Bugfixes.
58  *
59  * Revision 1.14  2001/12/30 19:26:12  alex
60  * - Unterstuetzung fuer die Konfigurationsdatei eingebaut.
61  *
62  * Revision 1.13  2001/12/30 11:42:00  alex
63  * - der Server meldet nun eine ordentliche "Start-Zeit".
64  *
65  * Revision 1.12  2001/12/29 03:07:36  alex
66  * - einige Loglevel geaendert.
67  *
68  * Revision 1.11  2001/12/26 14:45:37  alex
69  * - "Code Cleanups".
70  *
71  * Revision 1.10  2001/12/24 01:34:38  alex
72  * - Signal-Handler aufgeraeumt; u.a. SIGPIPE wird nun korrekt ignoriert.
73  *
74  * Revision 1.9  2001/12/21 22:24:50  alex
75  * - neues Modul "parse" wird initialisiert und abgemeldet.
76  *
77  * Revision 1.8  2001/12/14 08:15:26  alex
78  * - neue Module (irc, client, channel) werden an- und abgemeldet.
79  * - zweiter Listen-Socket wird zu Testzwecken konfiguriert.
80  *
81  * Revision 1.7  2001/12/13 01:31:46  alex
82  * - Conn_Handler() wird nun mit einem Timeout aufgerufen.
83  *
84  * Revision 1.6  2001/12/12 23:30:42  alex
85  * - Log-Meldungen an syslog angepasst.
86  * - NGIRCd_Quit ist nun das Flag zum Beenden des ngircd.
87  *
88  * Revision 1.5  2001/12/12 17:21:21  alex
89  * - mehr Unterfunktionen eingebaut, Modul besser strukturiert & dokumentiert.
90  * - Anpassungen an neue Module.
91  *
92  * Revision 1.4  2001/12/12 01:58:53  alex
93  * - Test auf socklen_t verbessert.
94  *
95  * Revision 1.3  2001/12/12 01:40:39  alex
96  * - ein paar mehr Kommentare; Variablennamen verstaendlicher gemacht.
97  * - fehlenden Header <arpa/inet.h> ergaenz.
98  * - SIGINT und SIGQUIT werden nun ebenfalls behandelt.
99  *
100  * Revision 1.2  2001/12/11 22:04:21  alex
101  * - Test auf stdint.h (HAVE_STDINT_H) hinzugefuegt.
102  *
103  * Revision 1.1.1.1  2001/12/11 21:53:04  alex
104  * - Imported sources to CVS.
105  */
106
107
108 #define PORTAB_CHECK_TYPES              /* Prueffunktion einbinden, s.u. */
109
110
111 #include <portab.h>
112 #include "global.h"
113
114 #include <imp.h>
115
116 #include <assert.h>
117 #include <errno.h>
118 #include <stdio.h>
119 #include <signal.h>
120 #include <string.h>
121 #include <unistd.h>
122 #include <sys/types.h>
123 #include <sys/wait.h>
124 #include <time.h>
125
126 #include "channel.h"
127 #include "client.h"
128 #include "conf.h"
129 #include "conn.h"
130 #include "irc.h"
131 #include "log.h"
132 #include "parse.h"
133
134 #include <exp.h>
135 #include "ngircd.h"
136
137
138 LOCAL VOID Initialize_Signal_Handler( VOID );
139 LOCAL VOID Signal_Handler( INT Signal );
140
141 LOCAL VOID Initialize_Listen_Ports( VOID );
142
143 LOCAL VOID Show_Version( VOID );
144 LOCAL VOID Show_Help( VOID );
145
146
147 GLOBAL INT main( INT argc, CONST CHAR *argv[] )
148 {
149         BOOLEAN ok;
150         INT pid, i, n;
151
152         /* Datentypen der portab-Library ueberpruefen */
153         portab_check_types( );
154
155         NGIRCd_Restart = FALSE;
156         NGIRCd_Quit = FALSE;
157         NGIRCd_NoDaemon = FALSE;
158         NGIRCd_Passive = FALSE;
159 #ifdef DEBUG
160         NGIRCd_Debug = FALSE;
161 #endif
162 #ifdef SNIFFER
163         NGIRCd_Sniffer = FALSE;
164 #endif
165
166         /* Kommandozeile parsen */
167         for( i = 1; i < argc; i++ )
168         {
169                 ok = FALSE;
170                 if(( argv[i][0] == '-' ) && ( argv[i][1] == '-' ))
171                 {
172                         /* Lange Option */
173
174 #ifdef DEBUG
175                         if( strcmp( argv[i], "--debug" ) == 0 )
176                         {
177                                 NGIRCd_Debug = TRUE;
178                                 ok = TRUE;
179                         }
180 #endif
181                         if( strcmp( argv[i], "--help" ) == 0 )
182                         {
183                                 Show_Version( ); puts( "" );
184                                 Show_Help( ); puts( "" );
185                                 exit( 1 );
186                         }
187                         if( strcmp( argv[i], "--nodaemon" ) == 0 )
188                         {
189                                 NGIRCd_NoDaemon = TRUE;
190                                 ok = TRUE;
191                         }
192                         if( strcmp( argv[i], "--passive" ) == 0 )
193                         {
194                                 NGIRCd_Passive = TRUE;
195                                 ok = TRUE;
196                         }
197 #ifdef SNIFFER
198                         if( strcmp( argv[i], "--sniffer" ) == 0 )
199                         {
200                                 NGIRCd_Sniffer = TRUE;
201                                 ok = TRUE;
202                         }
203 #endif
204                         if( strcmp( argv[i], "--version" ) == 0 )
205                         {
206                                 Show_Version( );
207                                 exit( 1 );
208                         }
209                 }
210                 else if(( argv[i][0] == '-' ) && ( argv[i][1] != '-' ))
211                 {
212                         /* Kurze Option */
213                         
214                         for( n = 1; n < strlen( argv[i] ); n++ )
215                         {
216                                 ok = FALSE;
217 #ifdef DEBUG
218                                 if( argv[i][n] == 'd' )
219                                 {
220                                         NGIRCd_Debug = TRUE;
221                                         ok = TRUE;
222                                 }
223 #endif
224                                 if( argv[i][n] == 'n' )
225                                 {
226                                         NGIRCd_NoDaemon = TRUE;
227                                         ok = TRUE;
228                                 }
229                                 if( argv[i][n] == 'p' )
230                                 {
231                                         NGIRCd_Passive = TRUE;
232                                         ok = TRUE;
233                                 }
234 #ifdef SNIFFER
235                                 if( argv[i][n] == 's' )
236                                 {
237                                         NGIRCd_Sniffer = TRUE;
238                                         ok = TRUE;
239                                 }
240 #endif
241
242                                 if( ! ok )
243                                 {
244                                         printf( PACKAGE": invalid option \"-%c\"!\n", argv[i][n] );
245                                         puts( "Try \""PACKAGE" --help\" for more information." );
246                                         exit( 1 );
247                                 }
248                         }
249
250                 }
251                 if( ! ok )
252                 {
253                         printf( PACKAGE": invalid option \"%s\"!\n", argv[i] );
254                         puts( "Try \""PACKAGE" --help\" for more information." );
255                         exit( 1 );
256                 }
257         }
258
259         /* Debug-Level (fuer IRC-Befehl "VERSION") ermitteln */
260         strcpy( NGIRCd_DebugLevel, "" );
261 #ifdef DEBUG
262         if( NGIRCd_Debug ) strcpy( NGIRCd_DebugLevel, "1" );
263 #endif
264 #ifdef SNIFFER
265         if( NGIRCd_Sniffer ) strcpy( NGIRCd_DebugLevel, "2" );
266 #endif
267         
268         while( ! NGIRCd_Quit )
269         {
270                 /* In der Regel wird ein Sub-Prozess ge-fork()'t, der
271                  * nicht mehr mit dem Terminal verbunden ist. Mit der
272                  * Option "--nodaemon" kann dies (z.B. zum Debuggen)
273                  * verhindert werden. */
274                 if( ! NGIRCd_NoDaemon )
275                 {
276                         /* Daemon im Hintergrund erzeugen */
277                         pid = fork( );
278                         if( pid > 0 )
279                         {
280                                 /* "alter" Prozess */
281                                 exit( 0 );
282                         }
283                         if( pid < 0 )
284                         {
285                                 /* Fehler */
286                                 printf( PACKAGE": Can't fork: %s!\nFatal error, exiting now ...", strerror( errno ));
287                                 exit( 1 );
288                         }
289                         setsid( );
290                         chdir( "/" );
291                 }
292         
293                 /* Globale Variablen initialisieren */
294                 NGIRCd_Start = time( NULL );
295                 strftime( NGIRCd_StartStr, 64, "%a %b %d %Y at %H:%M:%S (%Z)", localtime( &NGIRCd_Start ));
296                 NGIRCd_Restart = FALSE;
297                 NGIRCd_Quit = FALSE;
298
299                 /* Module initialisieren */
300                 Log_Init( );
301                 Conf_Init( );
302                 Channel_Init( );
303                 Client_Init( );
304                 Conn_Init( );
305
306                 /* Signal-Handler initialisieren */
307                 Initialize_Signal_Handler( );
308
309                 /* Listen-Ports initialisieren */
310                 Initialize_Listen_Ports( );
311
312                 /* Hauptschleife */
313                 while( TRUE )
314                 {
315                         if( NGIRCd_Quit || NGIRCd_Restart ) break;
316                         Conn_Handler( 5 );
317                 }
318
319                 /* Alles abmelden */
320                 Conn_Exit( );
321                 Client_Exit( );
322                 Channel_Exit( );
323                 Conf_Exit( );
324                 Log_Exit( );
325         }
326         return 0;
327 } /* main */
328
329
330 GLOBAL CHAR *NGIRCd_Version( VOID )
331 {
332         STATIC CHAR version[126];
333
334         sprintf( version, PACKAGE" version "VERSION"-%s", NGIRCd_VersionAddition( ));
335         return version;
336 } /* NGIRCd_Version */
337
338
339 GLOBAL CHAR *NGIRCd_VersionAddition( VOID )
340 {
341         STATIC CHAR txt[64];
342
343         strcpy( txt, "" );
344
345 #ifdef USE_SYSLOG
346         if( txt[0] ) strcat( txt, "+" );
347         strcat( txt, "SYSLOG" );
348 #endif
349 #ifdef STRICT_RFC
350         if( txt[0] ) strcat( txt, "+" );
351         strcat( txt, "RFC" );
352 #endif
353 #ifdef DEBUG
354         if( txt[0] ) strcat( txt, "+" );
355         strcat( txt, "DEBUG" );
356 #endif
357 #ifdef SNIFFER
358         if( txt[0] ) strcat( txt, "+" );
359         strcat( txt, "SNIFFER" );
360 #endif
361
362         if( txt[0] ) strcat( txt, "-" );
363         strcat( txt, P_OSNAME"/"P_ARCHNAME );
364
365         return txt;
366 } /* NGIRCd_VersionAddition */
367
368
369 LOCAL VOID Initialize_Signal_Handler( VOID )
370 {
371         /* Signal-Handler initialisieren: einige Signale
372          * werden ignoriert, andere speziell behandelt. */
373
374 #ifdef HAVE_SIGACTION
375         /* sigaction() ist vorhanden */
376
377         struct sigaction saction;
378
379         /* Signal-Struktur initialisieren */
380         memset( &saction, 0, sizeof( saction ));
381         saction.sa_handler = Signal_Handler;
382 #ifdef SA_RESTART
383         saction.sa_flags |= SA_RESTART;
384 #endif
385 #ifdef SA_NOCLDWAIT
386         saction.sa_flags |= SA_NOCLDWAIT;
387 #endif
388
389         /* Signal-Handler einhaengen */
390         sigaction( SIGINT, &saction, NULL );
391         sigaction( SIGQUIT, &saction, NULL );
392         sigaction( SIGTERM, &saction, NULL);
393         sigaction( SIGHUP, &saction, NULL);
394         sigaction( SIGCHLD, &saction, NULL);
395
396         /* einige Signale ignorieren */
397         saction.sa_handler = SIG_IGN;
398         sigaction( SIGPIPE, &saction, NULL );
399 #else
400         /* kein sigaction() vorhanden */
401
402         /* Signal-Handler einhaengen */
403         signal( SIGINT, Signal_Handler );
404         signal( SIGQUIT, Signal_Handler );
405         signal( SIGTERM, Signal_Handler );
406         signal( SIGHUP, Signal_Handler );
407         signal( SIGCHLD, Signal_Handler );
408
409         /* einige Signale ignorieren */
410         signal( SIGPIPE, SIG_IGN );
411 #endif
412 } /* Initialize_Signal_Handler */
413
414
415 LOCAL VOID Signal_Handler( INT Signal )
416 {
417         /* Signal-Handler. Dieser wird aufgerufen, wenn eines der Signale eintrifft,
418          * fuer das wir uns registriert haben (vgl. Initialize_Signal_Handler). Die
419          * Nummer des eingetroffenen Signals wird der Funktion uebergeben. */
420
421         switch( Signal )
422         {
423                 case SIGTERM:
424                 case SIGINT:
425                 case SIGQUIT:
426                         /* wir soll(t)en uns wohl beenden ... */
427                         if( Signal == SIGTERM ) Log( LOG_WARNING, "Got TERM signal, terminating now ..." );
428                         else if( Signal == SIGINT ) Log( LOG_WARNING, "Got INT signal, terminating now ..." );
429                         else if( Signal == SIGQUIT ) Log( LOG_WARNING, "Got QUIT signal, terminating now ..." );
430                         NGIRCd_Quit = TRUE;
431                         break;
432                 case SIGHUP:
433                         /* neu starten */
434                         Log( LOG_WARNING, "Got HUP signal, restarting now ..." );
435                         NGIRCd_Restart = TRUE;
436                         break;
437                 case SIGCHLD:
438                         /* Child-Prozess wurde beendet. Zombies vermeiden: */
439                         while( waitpid( -1, NULL, WNOHANG ) > 0);
440                         break;
441                 default:
442                         /* unbekanntes bzw. unbehandeltes Signal */
443                         Log( LOG_NOTICE, "Got signal %d! Ignored.", Signal );
444         }
445 } /* Signal_Handler */
446
447
448 LOCAL VOID Initialize_Listen_Ports( VOID )
449 {
450         /* Ports, auf denen der Server Verbindungen entgegennehmen
451          * soll, initialisieren */
452         
453         INT created, i;
454
455         created = 0;
456         for( i = 0; i < Conf_ListenPorts_Count; i++ )
457         {
458                 if( Conn_NewListener( Conf_ListenPorts[i] )) created++;
459                 else Log( LOG_ERR, "Can't listen on port %d!", Conf_ListenPorts[i] );
460         }
461
462         if( created < 1 )
463         {
464                 Log( LOG_ALERT, "Server isn't listening on a single port!" );
465                 Log( LOG_ALERT, PACKAGE" exiting due to fatal errors!" );
466                 exit( 1 );
467         }
468 } /* Initialize_Listen_Ports */
469
470
471 LOCAL VOID Show_Version( VOID )
472 {
473         puts( NGIRCd_Version( ));
474         puts( "Copyright (c)2001,2002 by Alexander Barton (alex@barton.de).\n" );
475         puts( "This is free software; see the source for copying conditions. There is NO" );
476         puts( "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." );
477 } /* Show_Version */
478
479
480 LOCAL VOID Show_Help( VOID )
481 {
482 #ifdef DEBUG
483         puts( "  -d, --debug       log extra debug messages" );
484 #endif
485         puts( "  -n, --nodaemon    don't fork and don't detatch from controlling terminal" );
486         puts( "  -p, --passive     disable automatic connections to other servers" );
487 #ifdef SNIFFER
488         puts( "  -s, --sniffer     enable network sniffer and display all IRC traffic" );
489 #endif
490         puts( "      --version     output version information and exit" );
491         puts( "      --help        display this help and exit" );
492 } /* Show_Help */
493
494
495 /* -eof- */