source: unix.c @ 6738a67

Last change on this file since 6738a67 was 6738a67, checked in by Sven Moritz Hallberg <pesco@…>, at 2008-07-16T23:22:52Z

merge in latest trunk

  • Property mode set to 100644
File size: 6.6 KB
Line 
1  /********************************************************************\
2  * BitlBee -- An IRC to other IM-networks gateway                     *
3  *                                                                    *
4  * Copyright 2002-2004 Wilmer van der Gaast and others                *
5  \********************************************************************/
6
7/* Main file (Unix specific part)                                       */
8
9/*
10  This program is free software; you can redistribute it and/or modify
11  it under the terms of the GNU General Public License as published by
12  the Free Software Foundation; either version 2 of the License, or
13  (at your option) any later version.
14
15  This program is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  GNU General Public License for more details.
19
20  You should have received a copy of the GNU General Public License with
21  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
22  if not, write to the Free Software Foundation, Inc., 59 Temple Place,
23  Suite 330, Boston, MA  02111-1307  USA
24*/
25
26#include "bitlbee.h"
27#include "commands.h"
28#include "crypting.h"
29#include "otr.h"
30#include "protocols/nogaim.h"
31#include "help.h"
32#include "ipc.h"
33#include "lib/ssl_client.h"
34#include <signal.h>
35#include <unistd.h>
36#include <sys/time.h>
37#include <sys/wait.h>
38#include <pwd.h>
39
40global_t global;        /* Against global namespace pollution */
41
42static void sighandler( int signal );
43
44int main( int argc, char *argv[] )
45{
46        int i = 0;
47        char *old_cwd = NULL;
48        struct sigaction sig, old;
49       
50        log_init();
51        global.conf_file = g_strdup( CONF_FILE_DEF );
52        global.conf = conf_load( argc, argv );
53        if( global.conf == NULL )
54                return( 1 );
55       
56        b_main_init();
57        nogaim_init();
58        /* Ugly Note: libotr and gnutls both use libgcrypt. libgcrypt
59           has a process-global config state whose initialization happpens
60           twice if libotr and gnutls are used together. libotr installs custom
61           memory management functions for libgcrypt while our gnutls module
62           uses the defaults. Therefore we initialize OTR after SSL. *sigh* */
63        ssl_init();
64        otr_init();
65       
66        srand( time( NULL ) ^ getpid() );
67        global.helpfile = g_strdup( HELP_FILE );
68       
69        if( global.conf->runmode == RUNMODE_INETD )
70        {
71                log_link( LOGLVL_ERROR, LOGOUTPUT_IRC );
72                log_link( LOGLVL_WARNING, LOGOUTPUT_IRC );
73       
74                i = bitlbee_inetd_init();
75                log_message( LOGLVL_INFO, "Bitlbee %s starting in inetd mode.", BITLBEE_VERSION );
76
77        }
78        else if( global.conf->runmode == RUNMODE_DAEMON )
79        {
80                log_link( LOGLVL_ERROR, LOGOUTPUT_SYSLOG );
81                log_link( LOGLVL_WARNING, LOGOUTPUT_SYSLOG );
82
83                i = bitlbee_daemon_init();
84                log_message( LOGLVL_INFO, "Bitlbee %s starting in daemon mode.", BITLBEE_VERSION );
85        }
86        else if( global.conf->runmode == RUNMODE_FORKDAEMON )
87        {
88                /* In case the operator requests a restart, we need this. */
89                old_cwd = g_malloc( 256 );
90                if( getcwd( old_cwd, 255 ) == NULL )
91                {
92                        log_message( LOGLVL_WARNING, "Could not save current directory: %s", strerror( errno ) );
93                        g_free( old_cwd );
94                        old_cwd = NULL;
95                }
96               
97                i = bitlbee_daemon_init();
98                log_message( LOGLVL_INFO, "Bitlbee %s starting in forking daemon mode.", BITLBEE_VERSION );
99        }
100        if( i != 0 )
101                return( i );
102       
103        if( ( global.conf->user && *global.conf->user ) &&
104            ( global.conf->runmode == RUNMODE_DAEMON || 
105              global.conf->runmode == RUNMODE_FORKDAEMON ) &&
106            ( !getuid() || !geteuid() ) )
107        {
108                struct passwd *pw = NULL;
109                pw = getpwnam( global.conf->user );
110                if( pw )
111                {
112                        setgid( pw->pw_gid );
113                        setuid( pw->pw_uid );
114                }
115        }
116
117        global.storage = storage_init( global.conf->primary_storage, global.conf->migrate_storage );
118        if( global.storage == NULL )
119        {
120                log_message( LOGLVL_ERROR, "Unable to load storage backend '%s'", global.conf->primary_storage );
121                return( 1 );
122        }
123       
124        /* Catch some signals to tell the user what's happening before quitting */
125        memset( &sig, 0, sizeof( sig ) );
126        sig.sa_handler = sighandler;
127        sigaction( SIGCHLD, &sig, &old );
128        sigaction( SIGPIPE, &sig, &old );
129        sig.sa_flags = SA_RESETHAND;
130        sigaction( SIGINT,  &sig, &old );
131        sigaction( SIGILL,  &sig, &old );
132        sigaction( SIGBUS,  &sig, &old );
133        sigaction( SIGFPE,  &sig, &old );
134        sigaction( SIGSEGV, &sig, &old );
135        sigaction( SIGTERM, &sig, &old );
136        sigaction( SIGQUIT, &sig, &old );
137        sigaction( SIGXCPU, &sig, &old );
138       
139        if( !getuid() || !geteuid() )
140                log_message( LOGLVL_WARNING, "BitlBee is running with root privileges. Why?" );
141        if( help_init( &global.help, global.helpfile ) == NULL )
142                log_message( LOGLVL_WARNING, "Error opening helpfile %s.", HELP_FILE );
143       
144        b_main_run();
145       
146        /* Mainly good for restarting, to make sure we close the help.txt fd. */
147        help_free( &global.help );
148       
149        if( global.restart )
150        {
151                char *fn = ipc_master_save_state();
152               
153                chdir( old_cwd );
154               
155                setenv( "_BITLBEE_RESTART_STATE", fn, 1 );
156                g_free( fn );
157               
158                close( global.listen_socket );
159               
160                if( execv( argv[0], argv ) == -1 )
161                        /* Apparently the execve() failed, so let's just
162                           jump back into our own/current main(). */
163                        /* Need more cleanup code to make this work. */
164                        return 1; /* main( argc, argv ); */
165        }
166       
167        return( 0 );
168}
169
170static void sighandler( int signal )
171{
172        /* FIXME: Calling log_message() here is not a very good idea! */
173       
174        if( signal == SIGTERM )
175        {
176                static int first = 1;
177               
178                if( first )
179                {
180                        /* We don't know what we were doing when this signal came in. It's not safe to touch
181                           the user data now (not to mention writing them to disk), so add a timer. */
182                       
183                        log_message( LOGLVL_ERROR, "SIGTERM received, cleaning up process." );
184                        b_timeout_add( 1, (b_event_handler) bitlbee_shutdown, NULL );
185                       
186                        first = 0;
187                }
188                else
189                {
190                        /* Well, actually, for now we'll never need this part because this signal handler
191                           will never be called more than once in a session for a non-SIGPIPE signal...
192                           But just in case we decide to change that: */
193                       
194                        log_message( LOGLVL_ERROR, "SIGTERM received twice, so long for a clean shutdown." );
195                        raise( signal );
196                }
197        }
198        else if( signal == SIGCHLD )
199        {
200                pid_t pid;
201                int st;
202               
203                while( ( pid = waitpid( 0, &st, WNOHANG ) ) > 0 )
204                {
205                        if( WIFSIGNALED( st ) )
206                                log_message( LOGLVL_INFO, "Client %d terminated normally. (status = %d)", (int) pid, WEXITSTATUS( st ) );
207                        else if( WIFEXITED( st ) )
208                                log_message( LOGLVL_INFO, "Client %d killed by signal %d.", (int) pid, WTERMSIG( st ) );
209                }
210        }
211        else if( signal != SIGPIPE )
212        {
213                log_message( LOGLVL_ERROR, "Fatal signal received: %d. That's probably a bug.", signal );
214                raise( signal );
215        }
216}
217
218double gettime()
219{
220        struct timeval time[1];
221
222        gettimeofday( time, 0 );
223        return( (double) time->tv_sec + (double) time->tv_usec / 1000000 );
224}
225
226
Note: See TracBrowser for help on using the repository browser.