Changeset 54879ab


Ignore:
Timestamp:
2006-01-21T22:31:10Z (18 years ago)
Author:
Wilmer van der Gaast <wilmer@…>
Branches:
master
Children:
57c4fc0
Parents:
f73b969 (diff), f1d38f2 (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 (only for ForkDaemon mode) for easier upgrades.

Files:
7 edited

Legend:

Unmodified
Added
Removed
  • bitlbee.c

    rf73b969 r54879ab  
    111111#endif
    112112       
     113        if( global.conf->runmode == RUNMODE_FORKDAEMON )
     114                ipc_master_load_state();
     115       
    113116        return( 0 );
    114117}
  • bitlbee.h

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

    rf73b969 r54879ab  
    3232#include "ini.h"
    3333#include "url.h"
     34#include "ipc.h"
    3435
    3536#include "protocols/proxy.h"
     
    7778        }
    7879       
    79         while( argc > 0 && ( opt = getopt( argc, argv, "i:p:nvIDFc:d:h" ) ) >= 0 )
     80        while( argc > 0 && ( opt = getopt( argc, argv, "i:p:nvIDFc:d:hR:" ) ) >= 0 )
    8081        /*     ^^^^ Just to make sure we skip this step from the REHASH handler. */
    8182        {
     
    141142                                "  -h  Show this help page.\n" );
    142143                        return( NULL );
     144                }
     145                else if( opt == 'R' )
     146                {
     147                        /* We can't load the statefile yet (and should make very sure we do this
     148                           only once), so set the filename here and load the state information
     149                           when initializing ForkDaemon. (This option only makes sense in that
     150                           mode anyway!) */
     151                        ipc_master_set_statefile( optarg );
    143152                }
    144153        }
  • ipc.c

    rf73b969 r54879ab  
    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};
     
    155181static void ipc_command_exec( void *data, char **cmd, const command_t *commands )
    156182{
    157         int i;
     183        int i, j;
    158184       
    159185        if( !cmd[0] )
     
    163189                if( g_strcasecmp( commands[i].command, cmd[0] ) == 0 )
    164190                {
     191                        /* There is no typo in this line: */
     192                        for( j = 1; cmd[j]; j ++ ); j --;
     193                       
     194                        if( j < commands[i].required_parameters )
     195                                break;
     196                       
    165197                        if( commands[i].flags & IPC_CMD_TO_CHILDREN )
    166198                                ipc_to_children( cmd );
     
    168200                                commands[i].execute( data, cmd );
    169201                       
    170                         return;
     202                        break;
    171203                }
    172204}
     
    379411        child_list = NULL;
    380412}
     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

    rf73b969 r54879ab  
    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

    rf73b969 r54879ab  
    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 }
     
    579580void irc_exec( irc_t *irc, char *cmd[] )
    580581{       
    581         int i;
     582        int i, n_arg;
    582583       
    583584        if( !cmd[0] )
     
    587588                if( g_strcasecmp( irc_commands[i].command, cmd[0] ) == 0 )
    588589                {
     590                        /* There should be no typo in the next line: */
     591                        for( n_arg = 0; cmd[n_arg]; n_arg ++ ); n_arg --;
     592                       
    589593                        if( irc_commands[i].flags & IRC_CMD_PRE_LOGIN && irc->status >= USTATUS_LOGGED_IN )
    590594                        {
     
    599603                                irc_reply( irc, 481, ":Permission denied - You're not an IRC operator" );
    600604                        }
    601                         else if( !cmd[irc_commands[i].required_parameters] )
     605                        else if( n_arg < irc_commands[i].required_parameters )
    602606                        {
    603607                                irc_reply( irc, 461, "%s :Need more parameters", cmd[0] );
  • unix.c

    rf73b969 r54879ab  
    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.