diff options
| -rw-r--r-- | bitlbee.c | 30 | ||||
| -rw-r--r-- | bitlbee.h | 1 | ||||
| -rw-r--r-- | conf.c | 22 | ||||
| -rw-r--r-- | conf.h | 1 | ||||
| -rwxr-xr-x | configure | 5 | ||||
| -rw-r--r-- | ipc.c | 124 | ||||
| -rw-r--r-- | ipc.h | 4 | ||||
| -rw-r--r-- | irc_commands.c | 1 | ||||
| -rw-r--r-- | protocols/msn/msn.c | 4 | ||||
| -rw-r--r-- | protocols/msn/sb.c | 5 | ||||
| -rw-r--r-- | root_commands.c | 3 | ||||
| -rw-r--r-- | unix.c | 42 | 
12 files changed, 229 insertions, 13 deletions
| @@ -44,6 +44,7 @@ int bitlbee_daemon_init()  #endif  	int i;  	GIOChannel *ch; +	FILE *fp;  	log_link( LOGLVL_ERROR, LOGOUTPUT_SYSLOG );  	log_link( LOGLVL_WARNING, LOGOUTPUT_SYSLOG ); @@ -103,13 +104,30 @@ int bitlbee_daemon_init()  		}  		else if( i != 0 )   			exit( 0 ); -		close( 0 ); -		close( 1 ); -		close( 2 ); +		  		chdir( "/" ); +		 +		/* Sometimes std* are already closed (for example when we're in a RESTARTed +		   BitlBee process. So let's only close TTY-fds. */ +		if( isatty( 0 ) ) close( 0 ); +		if( isatty( 0 ) ) close( 1 ); +		if( isatty( 0 ) ) close( 2 );  	}  #endif +	if( global.conf->runmode == RUNMODE_FORKDAEMON ) +		ipc_master_load_state(); +	 +	if( ( fp = fopen( global.conf->pidfile, "w" ) ) ) +	{ +		fprintf( fp, "%d\n", (int) getpid() ); +		fclose( fp ); +	} +	else +	{ +		log_message( LOGLVL_WARNING, "Warning: Couldn't write PID to `%s'", global.conf->pidfile ); +	} +	  	return( 0 );  } @@ -235,6 +253,12 @@ gboolean bitlbee_io_new_client( GIOChannel *source, GIOCondition condition, gpoi  	int new_socket = accept( global.listen_socket, (struct sockaddr *) &conn_info, &size );  	pid_t client_pid = 0; +	if( new_socket == -1 ) +	{ +		log_message( LOGLVL_WARNING, "Could not accept new connection: %s", strerror( errno ) ); +		return TRUE; +	} +	  	if( global.conf->runmode == RUNMODE_FORKDAEMON )  	{  		int fds[2]; @@ -120,6 +120,7 @@ typedef struct global {  	GList *storage; /* The first backend in the list will be used for saving */  	char *helpfile;  	GMainLoop *loop; +	int restart;  } global_t;  int bitlbee_daemon_init( void ); @@ -31,6 +31,7 @@  #include "conf.h"  #include "ini.h"  #include "url.h" +#include "ipc.h"  #include "protocols/proxy.h" @@ -60,6 +61,7 @@ conf_t *conf_load( int argc, char *argv[] )  	conf->oper_pass = NULL;  	conf->configdir = g_strdup( CONFIG );  	conf->plugindir = g_strdup( PLUGINDIR ); +	conf->pidfile = g_strdup( "/var/run/bitlbee.pid" );  	conf->motdfile = g_strdup( ETCDIR "/motd.txt" );  	conf->ping_interval = 180;  	conf->ping_timeout = 300; @@ -76,7 +78,7 @@ conf_t *conf_load( int argc, char *argv[] )  		fprintf( stderr, "Warning: Unable to read configuration file `%s'.\n", CONF_FILE );  	} -	while( argc > 0 && ( opt = getopt( argc, argv, "i:p:nvIDFc:d:h" ) ) >= 0 ) +	while( argc > 0 && ( opt = getopt( argc, argv, "i:p:P:nvIDFc:d:hR:" ) ) >= 0 )  	/*     ^^^^ Just to make sure we skip this step from the REHASH handler. */  	{  		if( opt == 'i' ) @@ -92,6 +94,11 @@ conf_t *conf_load( int argc, char *argv[] )  			}  			conf->port = i;  		} +		else if( opt == 'p' ) +		{ +			g_free( conf->pidfile ); +			conf->pidfile = g_strdup( optarg ); +		}  		else if( opt == 'n' )  			conf->nofork = 1;  		else if( opt == 'v' ) @@ -141,6 +148,14 @@ conf_t *conf_load( int argc, char *argv[] )  			        "  -h  Show this help page.\n" );  			return( NULL );  		} +		else if( opt == 'R' ) +		{ +			/* We can't load the statefile yet (and should make very sure we do this +			   only once), so set the filename here and load the state information +			   when initializing ForkDaemon. (This option only makes sense in that +			   mode anyway!) */ +			ipc_master_set_statefile( optarg ); +		}  	}  	if( conf->configdir[strlen(conf->configdir)-1] != '/' ) @@ -175,6 +190,11 @@ static int conf_loadini( conf_t *conf, char *file )  				else  					conf->runmode = RUNMODE_INETD;  			} +			else if( g_strcasecmp( ini->key, "pidfile" ) == 0 ) +			{ +				g_free( conf->pidfile ); +				conf->pidfile = g_strdup( ini->value ); +			}  			else if( g_strcasecmp( ini->key, "daemoninterface" ) == 0 )  			{  				conf->iface = g_strdup( ini->value ); @@ -42,6 +42,7 @@ typedef struct conf  	char *hostname;  	char *configdir;  	char *plugindir; +	char *pidfile;  	char *motdfile;  	char *primary_storage;  	char **migrate_storage; @@ -13,6 +13,7 @@ etcdir='$prefix/etc/bitlbee/'  mandir='$prefix/share/man/'  datadir='$prefix/share/bitlbee/'  config='/var/lib/bitlbee/' +pidfile='/var/run/bitlbee.pid'  plugindir='$prefix/lib/bitlbee'  msn=1 @@ -45,6 +46,7 @@ Option		Description				Default  --mandir=...						$mandir  --datadir=...						$datadir  --plugindir=...						$plugindir +--pidfile=...						$pidfile  --config=...						$config  --msn=0/1	Disable/enable MSN part			$msn @@ -73,6 +75,7 @@ mandir=`eval echo "$mandir/" | sed 's/\/\{1,\}/\//g'`  datadir=`eval echo "$datadir/" | sed 's/\/\{1,\}/\//g'`  config=`eval echo "$config/" | sed 's/\/\{1,\}/\//g'`  plugindir=`eval echo "$plugindir/" | sed 's/\/\{1,\}/\//g'` +pidfile=`eval echo "$pidfile/" | sed 's/\/\{1,\}/\//g'`  cat<<EOF>Makefile.settings  ## BitlBee settings, generated by configure @@ -82,6 +85,7 @@ ETCDIR=$etcdir  MANDIR=$mandir  DATADIR=$datadir  PLUGINDIR=$plugindir +PIDFILE=$pidfile  CONFIG=$config  ARCH=$arch @@ -103,6 +107,7 @@ cat<<EOF>config.h  #define ETCDIR "$etcdir"  #define VARDIR "$datadir"  #define PLUGINDIR "$plugindir" +#define PIDFILE "$pidfile"  #define ARCH "$arch"  #define CPU "$cpu"  EOF @@ -1,7 +1,7 @@    /********************************************************************\    * BitlBee -- An IRC to other IM-networks gateway                     *    *                                                                    * -  * Copyright 2002-2004 Wilmer van der Gaast and others                * +  * Copyright 2002-2006 Wilmer van der Gaast and others                *    \********************************************************************/  /* IPC - communication between BitlBee processes                        */ @@ -29,21 +29,22 @@  #include "commands.h"  GSList *child_list = NULL; - +static char *statefile = NULL;  static void ipc_master_cmd_client( irc_t *data, char **cmd )  {  	struct bitlbee_child *child = (void*) data; -	if( child ) +	if( child && cmd[1] )  	{  		child->host = g_strdup( cmd[1] );  		child->nick = g_strdup( cmd[2] );  		child->realname = g_strdup( cmd[3] );  	} -	ipc_to_children_str( "OPERMSG :Client connecting (PID=%d): %s@%s (%s)\r\n", -	                     child ? child->pid : -1, cmd[2], cmd[1], cmd[3] ); +	if( g_strcasecmp( cmd[0], "CLIENT" ) == 0 ) +		ipc_to_children_str( "OPERMSG :Client connecting (PID=%d): %s@%s (%s)\r\n", +		                     child ? child->pid : -1, cmd[2], cmd[1], cmd[3] );  }  static void ipc_master_cmd_die( irc_t *data, char **cmd ) @@ -73,14 +74,30 @@ void ipc_master_cmd_rehash( irc_t *data, char **cmd )  		ipc_to_children( cmd );  } +void ipc_master_cmd_restart( irc_t *data, char **cmd ) +{ +	struct bitlbee_child *child = (void*) data; +	 +	if( global.conf->runmode != RUNMODE_FORKDAEMON ) +	{ +		/* Tell child that this is unsupported. */ +		return; +	} +	 +	global.restart = -1; +	bitlbee_shutdown( NULL ); +} +  static const command_t ipc_master_commands[] = {  	{ "client",     3, ipc_master_cmd_client,     0 }, +	{ "hello",      0, ipc_master_cmd_client,     0 },  	{ "die",        0, ipc_master_cmd_die,        0 },  	{ "wallops",    1, NULL,                      IPC_CMD_TO_CHILDREN },  	{ "lilo",       1, NULL,                      IPC_CMD_TO_CHILDREN },  	{ "opermsg",    1, NULL,                      IPC_CMD_TO_CHILDREN },  	{ "rehash",     0, ipc_master_cmd_rehash,     0 },  	{ "kill",       2, NULL,                      IPC_CMD_TO_CHILDREN }, +	{ "restart",    0, ipc_master_cmd_restart,    0 },  	{ NULL }  }; @@ -141,6 +158,14 @@ static void ipc_child_cmd_kill( irc_t *irc, char **cmd )  	irc_abort( irc, 0, "Killed by operator: %s", cmd[2] );  } +static void ipc_child_cmd_hello( irc_t *irc, char **cmd ) +{ +	if( irc->status < USTATUS_LOGGED_IN ) +		ipc_to_master_str( "HELLO\r\n" ); +	else +		ipc_to_master_str( "HELLO %s %s :%s\r\n", irc->host, irc->nick, irc->realname ); +} +  static const command_t ipc_child_commands[] = {  	{ "die",        0, ipc_child_cmd_die,         0 },  	{ "wallops",    1, ipc_child_cmd_wallops,     0 }, @@ -148,6 +173,7 @@ static const command_t ipc_child_commands[] = {  	{ "opermsg",    1, ipc_child_cmd_opermsg,     0 },  	{ "rehash",     0, ipc_child_cmd_rehash,      0 },  	{ "kill",       2, ipc_child_cmd_kill,        0 }, +	{ "hello",      0, ipc_child_cmd_hello,       0 },  	{ NULL }  }; @@ -384,3 +410,91 @@ void ipc_master_free_all()  	g_slist_free( child_list );  	child_list = NULL;  } + +char *ipc_master_save_state() +{ +	char *fn = g_strdup( "/tmp/bee-restart.XXXXXX" ); +	int fd = mkstemp( fn ); +	GSList *l; +	FILE *fp; +	int i; +	 +	if( fd == -1 ) +	{ +		log_message( LOGLVL_ERROR, "Could not create temporary file: %s", strerror( errno ) ); +		g_free( fn ); +		return NULL; +	} +	 +	/* This is more convenient now. */ +	fp = fdopen( fd, "w" ); +	 +	for( l = child_list, i = 0; l; l = l->next ) +		i ++; +	 +	/* Number of client processes. */ +	fprintf( fp, "%d\n", i ); +	 +	for( l = child_list; l; l = l->next ) +		fprintf( fp, "%d %d\n", ((struct bitlbee_child*)l->data)->pid, +		                        ((struct bitlbee_child*)l->data)->ipc_fd ); +	 +	if( fclose( fp ) == 0 ) +	{ +		return fn; +	} +	else +	{ +		unlink( fn ); +		g_free( fn ); +		return NULL; +	} +} + +void ipc_master_set_statefile( char *fn ) +{ +	statefile = g_strdup( fn ); +} + +int ipc_master_load_state() +{ +	struct bitlbee_child *child; +	FILE *fp; +	int i, n; +	 +	if( statefile == NULL ) +		return 0; +	fp = fopen( statefile, "r" ); +	unlink( statefile );	/* Why do it later? :-) */ +	if( fp == NULL ) +		return 0; +	 +	if( fscanf( fp, "%d", &n ) != 1 ) +	{ +		log_message( LOGLVL_WARNING, "Could not import state information for child processes." ); +		fclose( fp ); +		return 0; +	} +	 +	log_message( LOGLVL_INFO, "Importing information for %d child processes.", n ); +	for( i = 0; i < n; i ++ ) +	{ +		child = g_new0( struct bitlbee_child, 1 ); +		 +		if( fscanf( fp, "%d %d", &child->pid, &child->ipc_fd ) != 2 ) +		{ +			log_message( LOGLVL_WARNING, "Unexpected end of file: Only processed %d clients.", i ); +			g_free( child ); +			fclose( fp ); +			return 0; +		} +		child->ipc_inpa = gaim_input_add( child->ipc_fd, GAIM_INPUT_READ, ipc_master_read, child ); +		 +		child_list = g_slist_append( child_list, child ); +	} +	 +	ipc_to_children_str( "HELLO\r\n" ); +	ipc_to_children_str( "OPERMSG :New BitlBee master process started (version " BITLBEE_VERSION ")\r\n" ); +	 +	return 1; +} @@ -53,5 +53,9 @@ void ipc_to_children_str( char *format, ... );  /* We need this function in inetd mode, so let's just make it non-static. */  void ipc_master_cmd_rehash( irc_t *data, char **cmd ); +char *ipc_master_save_state(); +void ipc_master_set_statefile( char *fn ); +int ipc_master_load_state(); +  extern GSList *child_list; diff --git a/irc_commands.c b/irc_commands.c index 66c39bc5..f2c7a645 100644 --- a/irc_commands.c +++ b/irc_commands.c @@ -572,6 +572,7 @@ static const command_t irc_commands[] = {  	{ "wallops",     1, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },  	{ "lilo",        1, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },  	{ "rehash",      0, irc_cmd_rehash,      IRC_CMD_OPER_ONLY }, +	{ "restart",     0, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },  	{ "kill",        2, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },  	{ NULL }  }; diff --git a/protocols/msn/msn.c b/protocols/msn/msn.c index b03c898e..3c7064f8 100644 --- a/protocols/msn/msn.c +++ b/protocols/msn/msn.c @@ -83,13 +83,13 @@ static void msn_close( struct gaim_connection *gc )  		for( l = md->msgq; l; l = l->next )  		{  			m = l->data; +		 +			serv_got_crap( gc, "Warning: Closing down MSN connection with unsent message to %s, you'll have to resend it.", m->who );  			g_free( m->who );  			g_free( m->text );  			g_free( m );  		}  		g_slist_free( md->msgq ); -		 -		serv_got_crap( gc, "Warning: Closing down MSN connection with unsent message(s), you'll have to resend them." );  	}  	for( l = gc->permit; l; l = l->next ) diff --git a/protocols/msn/sb.c b/protocols/msn/sb.c index 9e7ef841..deaceba1 100644 --- a/protocols/msn/sb.c +++ b/protocols/msn/sb.c @@ -212,13 +212,16 @@ void msn_sb_destroy( struct msn_switchboard *sb )  		for( l = sb->msgq; l; l = l->next )  		{  			m = l->data; +  			g_free( m->who );  			g_free( m->text );  			g_free( m );  		}  		g_slist_free( sb->msgq ); -		serv_got_crap( gc, "Warning: Closing down MSN switchboard connection with unsent message(s), you'll have to resend them." ); +		serv_got_crap( gc, "Warning: Closing down MSN switchboard connection with " +		                   "unsent message to %s, you'll have to resend it.", +		                   m->who ? m->who : "(unknown)" );  	}  	if( sb->chat ) diff --git a/root_commands.c b/root_commands.c index 426cf6e8..f69442d3 100644 --- a/root_commands.c +++ b/root_commands.c @@ -600,6 +600,9 @@ static void cmd_set( irc_t *irc, char **cmd )  	if( cmd[1] && cmd[2] )  	{  		set_setstr( irc, cmd[1], cmd[2] ); +		 +		if( ( strcmp( cmd[2], "=" ) ) == 0 && cmd[3] ) +			irc_usermsg( irc, "Warning: Correct syntax: \002set <variable> <value>\002 (without =)" );  	}  	if( cmd[1] ) /* else 'forgotten' on purpose.. Must show new value after changing */  	{ @@ -28,6 +28,7 @@  #include "crypting.h"  #include "protocols/nogaim.h"  #include "help.h" +#include "ipc.h"  #include <signal.h>  #include <unistd.h>  #include <sys/time.h> @@ -37,9 +38,10 @@ global_t global;	/* Against global namespace pollution */  static void sighandler( int signal ); -int main( int argc, char *argv[] ) +int main( int argc, char *argv[], char **envp )  {  	int i = 0; +	char *old_cwd;  	struct sigaction sig, old;  	memset( &global, 0, sizeof( global_t ) ); @@ -72,6 +74,15 @@ int main( int argc, char *argv[] )  	}  	else if( global.conf->runmode == RUNMODE_FORKDAEMON )  	{ +		/* In case the operator requests a restart, we need this. */ +		old_cwd = g_malloc( 256 ); +		if( getcwd( old_cwd, 255 ) == NULL ) +		{ +			log_message( LOGLVL_WARNING, "Could not save current directory: %s", strerror( errno ) ); +			g_free( old_cwd ); +			old_cwd = NULL; +		} +		  		i = bitlbee_daemon_init();  		log_message( LOGLVL_INFO, "Bitlbee %s starting in forking daemon mode.", BITLBEE_VERSION );  	} @@ -107,6 +118,35 @@ int main( int argc, char *argv[] )  	g_main_run( global.loop ); +	if( global.restart ) +	{ +		char *fn = ipc_master_save_state(); +		char **args; +		int n, i; +		 +		chdir( old_cwd ); +		 +		n = 0; +		args = g_new0( char *, argc + 3 ); +		args[n++] = argv[0]; +		if( fn ) +		{ +			args[n++] = "-R"; +			args[n++] = fn; +		} +		for( i = 1; argv[i] && i < argc; i ++ ) +		{ +			if( strcmp( argv[i], "-R" ) == 0 ) +				i += 2; +			 +			args[n++] = argv[i]; +		} +		 +		close( global.listen_socket ); +		 +		execve( args[0], args, envp ); +	} +	  	return( 0 );  } | 
