Changeset 1d2e3c2


Ignore:
Timestamp:
2006-02-02T13:59:14Z (19 years ago)
Author:
Wilmer van der Gaast <wilmer@…>
Branches:
master
Children:
ec3e411
Parents:
34b17d9 (diff), a49dcd5 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Added RESTART command for easier upgrades without losing IPC connections.
(Obviously only works well for forking daemon mode.)

Files:
7 edited

Legend:

Unmodified
Added
Removed
  • bitlbee.c

    r34b17d9 r1d2e3c2  
    105105                else if( i != 0 )
    106106                        exit( 0 );
    107                 close( 0 );
    108                 close( 1 );
    109                 close( 2 );
     107               
    110108                chdir( "/" );
     109               
     110                /* Sometimes std* are already closed (for example when we're in a RESTARTed
     111                   BitlBee process. So let's only close TTY-fds. */
     112                if( isatty( 0 ) ) close( 0 );
     113                if( isatty( 0 ) ) close( 1 );
     114                if( isatty( 0 ) ) close( 2 );
    111115        }
    112116#endif
     117       
     118        if( global.conf->runmode == RUNMODE_FORKDAEMON )
     119                ipc_master_load_state();
    113120       
    114121        if( ( fp = fopen( global.conf->pidfile, "w" ) ) )
     
    246253        int new_socket = accept( global.listen_socket, (struct sockaddr *) &conn_info, &size );
    247254        pid_t client_pid = 0;
     255       
     256        if( new_socket == -1 )
     257        {
     258                log_message( LOGLVL_WARNING, "Could not accept new connection: %s", strerror( errno ) );
     259                return TRUE;
     260        }
    248261       
    249262        if( global.conf->runmode == RUNMODE_FORKDAEMON )
  • bitlbee.h

    r34b17d9 r1d2e3c2  
    121121        char *helpfile;
    122122        GMainLoop *loop;
     123        int restart;
    123124} global_t;
    124125
  • conf.c

    r34b17d9 r1d2e3c2  
    3232#include "ini.h"
    3333#include "url.h"
     34#include "ipc.h"
    3435
    3536#include "protocols/proxy.h"
     
    7879        }
    7980       
    80         while( argc > 0 && ( opt = getopt( argc, argv, "i:p:P:nvIDFc:d:h" ) ) >= 0 )
     81        while( argc > 0 && ( opt = getopt( argc, argv, "i:p:P:nvIDFc:d:hR:" ) ) >= 0 )
    8182        /*     ^^^^ Just to make sure we skip this step from the REHASH handler. */
    8283        {
     
    147148                                "  -h  Show this help page.\n" );
    148149                        return( NULL );
     150                }
     151                else if( opt == 'R' )
     152                {
     153                        /* We can't load the statefile yet (and should make very sure we do this
     154                           only once), so set the filename here and load the state information
     155                           when initializing ForkDaemon. (This option only makes sense in that
     156                           mode anyway!) */
     157                        ipc_master_set_statefile( optarg );
    149158                }
    150159        }
  • ipc.c

    r34b17d9 r1d2e3c2  
    22  * BitlBee -- An IRC to other IM-networks gateway                     *
    33  *                                                                    *
    4   * Copyright 2002-2004 Wilmer van der Gaast and others                *
     4  * Copyright 2002-2006 Wilmer van der Gaast and others                *
    55  \********************************************************************/
    66
     
    3030
    3131GSList *child_list = NULL;
    32 
     32static char *statefile = NULL;
    3333
    3434static void ipc_master_cmd_client( irc_t *data, char **cmd )
     
    3636        struct bitlbee_child *child = (void*) data;
    3737       
    38         if( child )
     38        if( child && cmd[1] )
    3939        {
    4040                child->host = g_strdup( cmd[1] );
     
    4343        }
    4444       
    45         ipc_to_children_str( "OPERMSG :Client connecting (PID=%d): %s@%s (%s)\r\n",
    46                              child ? child->pid : -1, cmd[2], cmd[1], cmd[3] );
     45        if( g_strcasecmp( cmd[0], "CLIENT" ) == 0 )
     46                ipc_to_children_str( "OPERMSG :Client connecting (PID=%d): %s@%s (%s)\r\n",
     47                                     child ? child->pid : -1, cmd[2], cmd[1], cmd[3] );
    4748}
    4849
     
    7475}
    7576
     77void ipc_master_cmd_restart( irc_t *data, char **cmd )
     78{
     79        struct bitlbee_child *child = (void*) data;
     80       
     81        if( global.conf->runmode != RUNMODE_FORKDAEMON )
     82        {
     83                /* Tell child that this is unsupported. */
     84                return;
     85        }
     86       
     87        global.restart = -1;
     88        bitlbee_shutdown( NULL );
     89}
     90
    7691static const command_t ipc_master_commands[] = {
    7792        { "client",     3, ipc_master_cmd_client,     0 },
     93        { "hello",      0, ipc_master_cmd_client,     0 },
    7894        { "die",        0, ipc_master_cmd_die,        0 },
    7995        { "wallops",    1, NULL,                      IPC_CMD_TO_CHILDREN },
     
    8298        { "rehash",     0, ipc_master_cmd_rehash,     0 },
    8399        { "kill",       2, NULL,                      IPC_CMD_TO_CHILDREN },
     100        { "restart",    0, ipc_master_cmd_restart,    0 },
    84101        { NULL }
    85102};
     
    140157        irc_write( irc, ":%s!%s@%s KILL %s :%s", irc->mynick, irc->mynick, irc->myhost, irc->nick, cmd[2] );
    141158        irc_abort( irc, 0, "Killed by operator: %s", cmd[2] );
     159}
     160
     161static void ipc_child_cmd_hello( irc_t *irc, char **cmd )
     162{
     163        if( irc->status < USTATUS_LOGGED_IN )
     164                ipc_to_master_str( "HELLO\r\n" );
     165        else
     166                ipc_to_master_str( "HELLO %s %s :%s\r\n", irc->host, irc->nick, irc->realname );
    142167}
    143168
     
    149174        { "rehash",     0, ipc_child_cmd_rehash,      0 },
    150175        { "kill",       2, ipc_child_cmd_kill,        0 },
     176        { "hello",      0, ipc_child_cmd_hello,       0 },
    151177        { NULL }
    152178};
     
    385411        child_list = NULL;
    386412}
     413
     414char *ipc_master_save_state()
     415{
     416        char *fn = g_strdup( "/tmp/bee-restart.XXXXXX" );
     417        int fd = mkstemp( fn );
     418        GSList *l;
     419        FILE *fp;
     420        int i;
     421       
     422        if( fd == -1 )
     423        {
     424                log_message( LOGLVL_ERROR, "Could not create temporary file: %s", strerror( errno ) );
     425                g_free( fn );
     426                return NULL;
     427        }
     428       
     429        /* This is more convenient now. */
     430        fp = fdopen( fd, "w" );
     431       
     432        for( l = child_list, i = 0; l; l = l->next )
     433                i ++;
     434       
     435        /* Number of client processes. */
     436        fprintf( fp, "%d\n", i );
     437       
     438        for( l = child_list; l; l = l->next )
     439                fprintf( fp, "%d %d\n", ((struct bitlbee_child*)l->data)->pid,
     440                                        ((struct bitlbee_child*)l->data)->ipc_fd );
     441       
     442        if( fclose( fp ) == 0 )
     443        {
     444                return fn;
     445        }
     446        else
     447        {
     448                unlink( fn );
     449                g_free( fn );
     450                return NULL;
     451        }
     452}
     453
     454void ipc_master_set_statefile( char *fn )
     455{
     456        statefile = g_strdup( fn );
     457}
     458
     459int ipc_master_load_state()
     460{
     461        struct bitlbee_child *child;
     462        FILE *fp;
     463        int i, n;
     464       
     465        if( statefile == NULL )
     466                return 0;
     467        fp = fopen( statefile, "r" );
     468        unlink( statefile );    /* Why do it later? :-) */
     469        if( fp == NULL )
     470                return 0;
     471       
     472        if( fscanf( fp, "%d", &n ) != 1 )
     473        {
     474                log_message( LOGLVL_WARNING, "Could not import state information for child processes." );
     475                fclose( fp );
     476                return 0;
     477        }
     478       
     479        log_message( LOGLVL_INFO, "Importing information for %d child processes.", n );
     480        for( i = 0; i < n; i ++ )
     481        {
     482                child = g_new0( struct bitlbee_child, 1 );
     483               
     484                if( fscanf( fp, "%d %d", &child->pid, &child->ipc_fd ) != 2 )
     485                {
     486                        log_message( LOGLVL_WARNING, "Unexpected end of file: Only processed %d clients.", i );
     487                        g_free( child );
     488                        fclose( fp );
     489                        return 0;
     490                }
     491                child->ipc_inpa = gaim_input_add( child->ipc_fd, GAIM_INPUT_READ, ipc_master_read, child );
     492               
     493                child_list = g_slist_append( child_list, child );
     494        }
     495       
     496        ipc_to_children_str( "HELLO\r\n" );
     497        ipc_to_children_str( "OPERMSG :New BitlBee master process started (version " BITLBEE_VERSION ")\r\n" );
     498       
     499        return 1;
     500}
  • ipc.h

    r34b17d9 r1d2e3c2  
    5454void ipc_master_cmd_rehash( irc_t *data, char **cmd );
    5555
     56char *ipc_master_save_state();
     57void ipc_master_set_statefile( char *fn );
     58int ipc_master_load_state();
     59
    5660
    5761extern GSList *child_list;
  • irc_commands.c

    r34b17d9 r1d2e3c2  
    573573        { "lilo",        1, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
    574574        { "rehash",      0, irc_cmd_rehash,      IRC_CMD_OPER_ONLY },
     575        { "restart",     0, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
    575576        { "kill",        2, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
    576577        { NULL }
  • unix.c

    r34b17d9 r1d2e3c2  
    2929#include "protocols/nogaim.h"
    3030#include "help.h"
     31#include "ipc.h"
    3132#include <signal.h>
    3233#include <unistd.h>
     
    3839static void sighandler( int signal );
    3940
    40 int main( int argc, char *argv[] )
     41int main( int argc, char *argv[], char **envp )
    4142{
    4243        int i = 0;
     44        char *old_cwd;
    4345        struct sigaction sig, old;
    4446       
     
    7375        else if( global.conf->runmode == RUNMODE_FORKDAEMON )
    7476        {
     77                /* In case the operator requests a restart, we need this. */
     78                old_cwd = g_malloc( 256 );
     79                if( getcwd( old_cwd, 255 ) == NULL )
     80                {
     81                        log_message( LOGLVL_WARNING, "Could not save current directory: %s", strerror( errno ) );
     82                        g_free( old_cwd );
     83                        old_cwd = NULL;
     84                }
     85               
    7586                i = bitlbee_daemon_init();
    7687                log_message( LOGLVL_INFO, "Bitlbee %s starting in forking daemon mode.", BITLBEE_VERSION );
     
    108119        g_main_run( global.loop );
    109120       
     121        if( global.restart )
     122        {
     123                char *fn = ipc_master_save_state();
     124                char **args;
     125                int n, i;
     126               
     127                chdir( old_cwd );
     128               
     129                n = 0;
     130                args = g_new0( char *, argc + 3 );
     131                args[n++] = argv[0];
     132                if( fn )
     133                {
     134                        args[n++] = "-R";
     135                        args[n++] = fn;
     136                }
     137                for( i = 1; argv[i] && i < argc; i ++ )
     138                {
     139                        if( strcmp( argv[i], "-R" ) == 0 )
     140                                i += 2;
     141                       
     142                        args[n++] = argv[i];
     143                }
     144               
     145                close( global.listen_socket );
     146               
     147                execve( args[0], args, envp );
     148        }
     149       
    110150        return( 0 );
    111151}
Note: See TracChangeset for help on using the changeset viewer.