b78bed3aff06648d1db6f066699006edcd613d51
[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.32 2002/03/12 14:37:52 alex Exp $
13  *
14  * ngircd.c: Hier beginnt alles ;-)
15  */
16
17
18 #include "portab.h"
19
20 #include "imp.h"
21 #include <assert.h>
22 #include <errno.h>
23 #include <stdio.h>
24 #include <signal.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <sys/types.h>
28 #include <sys/wait.h>
29 #include <time.h>
30
31 #include "channel.h"
32 #include "client.h"
33 #include "conf.h"
34 #include "conn.h"
35 #include "defines.h"
36 #include "irc.h"
37 #include "log.h"
38 #include "parse.h"
39
40 #include "exp.h"
41 #include "ngircd.h"
42
43
44 LOCAL VOID Initialize_Signal_Handler( VOID );
45 LOCAL VOID Signal_Handler( INT Signal );
46
47 LOCAL VOID Initialize_Listen_Ports( VOID );
48
49 LOCAL VOID Show_Version( VOID );
50 LOCAL VOID Show_Help( VOID );
51
52
53 GLOBAL INT main( INT argc, CONST CHAR *argv[] )
54 {
55         BOOLEAN ok;
56         INT pid, i, n;
57
58         NGIRCd_Restart = FALSE;
59         NGIRCd_Quit = FALSE;
60         NGIRCd_NoDaemon = FALSE;
61         NGIRCd_Passive = FALSE;
62 #ifdef DEBUG
63         NGIRCd_Debug = FALSE;
64 #endif
65 #ifdef SNIFFER
66         NGIRCd_Sniffer = FALSE;
67 #endif
68
69         /* Kommandozeile parsen */
70         for( i = 1; i < argc; i++ )
71         {
72                 ok = FALSE;
73                 if(( argv[i][0] == '-' ) && ( argv[i][1] == '-' ))
74                 {
75                         /* Lange Option */
76
77 #ifdef DEBUG
78                         if( strcmp( argv[i], "--debug" ) == 0 )
79                         {
80                                 NGIRCd_Debug = TRUE;
81                                 ok = TRUE;
82                         }
83 #endif
84                         if( strcmp( argv[i], "--help" ) == 0 )
85                         {
86                                 Show_Version( ); puts( "" );
87                                 Show_Help( ); puts( "" );
88                                 exit( 1 );
89                         }
90                         if( strcmp( argv[i], "--nodaemon" ) == 0 )
91                         {
92                                 NGIRCd_NoDaemon = TRUE;
93                                 ok = TRUE;
94                         }
95                         if( strcmp( argv[i], "--passive" ) == 0 )
96                         {
97                                 NGIRCd_Passive = TRUE;
98                                 ok = TRUE;
99                         }
100 #ifdef SNIFFER
101                         if( strcmp( argv[i], "--sniffer" ) == 0 )
102                         {
103                                 NGIRCd_Sniffer = TRUE;
104                                 ok = TRUE;
105                         }
106 #endif
107                         if( strcmp( argv[i], "--version" ) == 0 )
108                         {
109                                 Show_Version( );
110                                 exit( 1 );
111                         }
112                 }
113                 else if(( argv[i][0] == '-' ) && ( argv[i][1] != '-' ))
114                 {
115                         /* Kurze Option */
116                         
117                         for( n = 1; n < strlen( argv[i] ); n++ )
118                         {
119                                 ok = FALSE;
120 #ifdef DEBUG
121                                 if( argv[i][n] == 'd' )
122                                 {
123                                         NGIRCd_Debug = TRUE;
124                                         ok = TRUE;
125                                 }
126 #endif
127                                 if( argv[i][n] == 'n' )
128                                 {
129                                         NGIRCd_NoDaemon = TRUE;
130                                         ok = TRUE;
131                                 }
132                                 if( argv[i][n] == 'p' )
133                                 {
134                                         NGIRCd_Passive = TRUE;
135                                         ok = TRUE;
136                                 }
137 #ifdef SNIFFER
138                                 if( argv[i][n] == 's' )
139                                 {
140                                         NGIRCd_Sniffer = TRUE;
141                                         ok = TRUE;
142                                 }
143 #endif
144
145                                 if( ! ok )
146                                 {
147                                         printf( PACKAGE": invalid option \"-%c\"!\n", argv[i][n] );
148                                         puts( "Try \""PACKAGE" --help\" for more information." );
149                                         exit( 1 );
150                                 }
151                         }
152
153                 }
154                 if( ! ok )
155                 {
156                         printf( PACKAGE": invalid option \"%s\"!\n", argv[i] );
157                         puts( "Try \""PACKAGE" --help\" for more information." );
158                         exit( 1 );
159                 }
160         }
161
162         /* Debug-Level (fuer IRC-Befehl "VERSION") ermitteln */
163         strcpy( NGIRCd_DebugLevel, "" );
164 #ifdef DEBUG
165         if( NGIRCd_Debug ) strcpy( NGIRCd_DebugLevel, "1" );
166 #endif
167 #ifdef SNIFFER
168         if( NGIRCd_Sniffer ) strcpy( NGIRCd_DebugLevel, "2" );
169 #endif
170         
171         while( ! NGIRCd_Quit )
172         {
173                 /* In der Regel wird ein Sub-Prozess ge-fork()'t, der
174                  * nicht mehr mit dem Terminal verbunden ist. Mit der
175                  * Option "--nodaemon" kann dies (z.B. zum Debuggen)
176                  * verhindert werden. */
177                 if( ! NGIRCd_NoDaemon )
178                 {
179                         /* Daemon im Hintergrund erzeugen */
180                         pid = fork( );
181                         if( pid > 0 )
182                         {
183                                 /* "alter" Prozess */
184                                 exit( 0 );
185                         }
186                         if( pid < 0 )
187                         {
188                                 /* Fehler */
189                                 printf( PACKAGE": Can't fork: %s!\nFatal error, exiting now ...", strerror( errno ));
190                                 exit( 1 );
191                         }
192
193                         /* Child-Prozess initialisieren */
194                         setsid( );
195                         chdir( "/" );
196                 }
197         
198                 /* Globale Variablen initialisieren */
199                 NGIRCd_Start = time( NULL );
200                 strftime( NGIRCd_StartStr, 64, "%a %b %d %Y at %H:%M:%S (%Z)", localtime( &NGIRCd_Start ));
201                 NGIRCd_Restart = FALSE;
202                 NGIRCd_Quit = FALSE;
203
204                 /* Module initialisieren */
205                 Log_Init( );
206                 Conf_Init( );
207                 Channel_Init( );
208                 Client_Init( );
209                 Conn_Init( );
210
211                 /* Signal-Handler initialisieren */
212                 Initialize_Signal_Handler( );
213
214                 /* Listen-Ports initialisieren */
215                 Initialize_Listen_Ports( );
216
217                 /* Hauptschleife */
218                 while( TRUE )
219                 {
220                         if( NGIRCd_Quit || NGIRCd_Restart ) break;
221                         Conn_Handler( 5 );
222                 }
223
224                 /* Alles abmelden */
225                 Conn_Exit( );
226                 Client_Exit( );
227                 Channel_Exit( );
228                 Conf_Exit( );
229                 Log_Exit( );
230         }
231
232 #ifndef DEBUG
233         /* aufraeumen */
234         if( unlink( ERROR_FILE ) != 0 ) Log( LOG_ERR, "Can't delete \""ERROR_FILE"\": %s", strerror( errno ));
235 #endif
236
237         return 0;
238 } /* main */
239
240
241 GLOBAL CHAR *NGIRCd_Version( VOID )
242 {
243         STATIC CHAR version[126];
244
245         sprintf( version, PACKAGE" version "VERSION"-%s", NGIRCd_VersionAddition( ));
246         return version;
247 } /* NGIRCd_Version */
248
249
250 GLOBAL CHAR *NGIRCd_VersionAddition( VOID )
251 {
252         STATIC CHAR txt[64];
253
254         strcpy( txt, "" );
255
256 #ifdef USE_SYSLOG
257         if( txt[0] ) strcat( txt, "+" );
258         strcat( txt, "SYSLOG" );
259 #endif
260 #ifdef STRICT_RFC
261         if( txt[0] ) strcat( txt, "+" );
262         strcat( txt, "RFC" );
263 #endif
264 #ifdef DEBUG
265         if( txt[0] ) strcat( txt, "+" );
266         strcat( txt, "DEBUG" );
267 #endif
268 #ifdef SNIFFER
269         if( txt[0] ) strcat( txt, "+" );
270         strcat( txt, "SNIFFER" );
271 #endif
272
273         if( txt[0] ) strcat( txt, "-" );
274         strcat( txt, P_OSNAME"/"P_ARCHNAME );
275
276         return txt;
277 } /* NGIRCd_VersionAddition */
278
279
280 LOCAL VOID Initialize_Signal_Handler( VOID )
281 {
282         /* Signal-Handler initialisieren: einige Signale
283          * werden ignoriert, andere speziell behandelt. */
284
285 #ifdef HAVE_SIGACTION
286         /* sigaction() ist vorhanden */
287
288         struct sigaction saction;
289
290         /* Signal-Struktur initialisieren */
291         memset( &saction, 0, sizeof( saction ));
292         saction.sa_handler = Signal_Handler;
293 #ifdef SA_RESTART
294         saction.sa_flags |= SA_RESTART;
295 #endif
296 #ifdef SA_NOCLDWAIT
297         saction.sa_flags |= SA_NOCLDWAIT;
298 #endif
299
300         /* Signal-Handler einhaengen */
301         sigaction( SIGINT, &saction, NULL );
302         sigaction( SIGQUIT, &saction, NULL );
303         sigaction( SIGTERM, &saction, NULL);
304         sigaction( SIGHUP, &saction, NULL);
305         sigaction( SIGCHLD, &saction, NULL);
306
307         /* einige Signale ignorieren */
308         saction.sa_handler = SIG_IGN;
309         sigaction( SIGPIPE, &saction, NULL );
310 #else
311         /* kein sigaction() vorhanden */
312
313         /* Signal-Handler einhaengen */
314         signal( SIGINT, Signal_Handler );
315         signal( SIGQUIT, Signal_Handler );
316         signal( SIGTERM, Signal_Handler );
317         signal( SIGHUP, Signal_Handler );
318         signal( SIGCHLD, Signal_Handler );
319
320         /* einige Signale ignorieren */
321         signal( SIGPIPE, SIG_IGN );
322 #endif
323 } /* Initialize_Signal_Handler */
324
325
326 LOCAL VOID Signal_Handler( INT Signal )
327 {
328         /* Signal-Handler. Dieser wird aufgerufen, wenn eines der Signale eintrifft,
329          * fuer das wir uns registriert haben (vgl. Initialize_Signal_Handler). Die
330          * Nummer des eingetroffenen Signals wird der Funktion uebergeben. */
331
332         switch( Signal )
333         {
334                 case SIGTERM:
335                 case SIGINT:
336                 case SIGQUIT:
337                         /* wir soll(t)en uns wohl beenden ... */
338                         if( Signal == SIGTERM ) Log( LOG_WARNING, "Got TERM signal, terminating now ..." );
339                         else if( Signal == SIGINT ) Log( LOG_WARNING, "Got INT signal, terminating now ..." );
340                         else if( Signal == SIGQUIT ) Log( LOG_WARNING, "Got QUIT signal, terminating now ..." );
341                         NGIRCd_Quit = TRUE;
342                         break;
343                 case SIGHUP:
344                         /* neu starten */
345                         Log( LOG_WARNING, "Got HUP signal, restarting now ..." );
346                         NGIRCd_Restart = TRUE;
347                         break;
348                 case SIGCHLD:
349                         /* Child-Prozess wurde beendet. Zombies vermeiden: */
350                         while( waitpid( -1, NULL, WNOHANG ) > 0);
351                         break;
352                 default:
353                         /* unbekanntes bzw. unbehandeltes Signal */
354                         Log( LOG_NOTICE, "Got signal %d! Ignored.", Signal );
355         }
356 } /* Signal_Handler */
357
358
359 LOCAL VOID Initialize_Listen_Ports( VOID )
360 {
361         /* Ports, auf denen der Server Verbindungen entgegennehmen
362          * soll, initialisieren */
363         
364         INT created, i;
365
366         created = 0;
367         for( i = 0; i < Conf_ListenPorts_Count; i++ )
368         {
369                 if( Conn_NewListener( Conf_ListenPorts[i] )) created++;
370                 else Log( LOG_ERR, "Can't listen on port %d!", Conf_ListenPorts[i] );
371         }
372
373         if( created < 1 )
374         {
375                 Log( LOG_ALERT, "Server isn't listening on a single port!" );
376                 Log( LOG_ALERT, PACKAGE" exiting due to fatal errors!" );
377                 exit( 1 );
378         }
379 } /* Initialize_Listen_Ports */
380
381
382 LOCAL VOID Show_Version( VOID )
383 {
384         puts( NGIRCd_Version( ));
385         puts( "Copyright (c)2001,2002 by Alexander Barton (alex@barton.de).\n" );
386         puts( "This is free software; see the source for copying conditions. There is NO" );
387         puts( "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." );
388 } /* Show_Version */
389
390
391 LOCAL VOID Show_Help( VOID )
392 {
393         puts( "Compile-time defaults:\n" );
394         puts( "  - configuration: "CONFIG_FILE );
395         puts( "  - MOTD file: "MOTD_FILE );
396         puts( "  - server error log: "ERROR_FILE"\n" );
397         puts( "Run-time options:\n" );
398 #ifdef DEBUG
399         puts( "  -d, --debug       log extra debug messages" );
400 #endif
401         puts( "  -n, --nodaemon    don't fork and don't detatch from controlling terminal" );
402         puts( "  -p, --passive     disable automatic connections to other servers" );
403 #ifdef SNIFFER
404         puts( "  -s, --sniffer     enable network sniffer and display all IRC traffic" );
405 #endif
406         puts( "      --version     output version information and exit" );
407         puts( "      --help        display this help and exit" );
408 } /* Show_Help */
409
410
411 /* -eof- */