|
1 | 1 | /********************************************************************\ |
2 | 2 | * BitlBee -- An IRC to other IM-networks gateway * |
3 | 3 | * * |
4 | | - * Copyright 2002-2004 Wilmer van der Gaast and others * |
| 4 | + * Copyright 2002-2006 Wilmer van der Gaast and others * |
5 | 5 | \********************************************************************/ |
6 | 6 |
|
7 | 7 | /* IPC - communication between BitlBee processes */ |
|
29 | 29 | #include "commands.h" |
30 | 30 |
|
31 | 31 | GSList *child_list = NULL; |
32 | | - |
| 32 | +static char *statefile = NULL; |
33 | 33 |
|
34 | 34 | static void ipc_master_cmd_client( irc_t *data, char **cmd ) |
35 | 35 | { |
36 | 36 | struct bitlbee_child *child = (void*) data; |
37 | 37 |
|
38 | | - if( child ) |
| 38 | + if( child && cmd[1] ) |
39 | 39 | { |
40 | 40 | child->host = g_strdup( cmd[1] ); |
41 | 41 | child->nick = g_strdup( cmd[2] ); |
42 | 42 | child->realname = g_strdup( cmd[3] ); |
43 | 43 | } |
44 | 44 |
|
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] ); |
47 | 48 | } |
48 | 49 |
|
49 | 50 | 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 ) |
73 | 74 | ipc_to_children( cmd ); |
74 | 75 | } |
75 | 76 |
|
| 77 | +void 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 | + |
76 | 91 | static const command_t ipc_master_commands[] = { |
77 | 92 | { "client", 3, ipc_master_cmd_client, 0 }, |
| 93 | + { "hello", 0, ipc_master_cmd_client, 0 }, |
78 | 94 | { "die", 0, ipc_master_cmd_die, 0 }, |
79 | 95 | { "wallops", 1, NULL, IPC_CMD_TO_CHILDREN }, |
80 | 96 | { "lilo", 1, NULL, IPC_CMD_TO_CHILDREN }, |
81 | 97 | { "opermsg", 1, NULL, IPC_CMD_TO_CHILDREN }, |
82 | 98 | { "rehash", 0, ipc_master_cmd_rehash, 0 }, |
83 | 99 | { "kill", 2, NULL, IPC_CMD_TO_CHILDREN }, |
| 100 | + { "restart", 0, ipc_master_cmd_restart, 0 }, |
84 | 101 | { NULL } |
85 | 102 | }; |
86 | 103 |
|
@@ -141,33 +158,48 @@ static void ipc_child_cmd_kill( irc_t *irc, char **cmd ) |
141 | 158 | irc_abort( irc, 0, "Killed by operator: %s", cmd[2] ); |
142 | 159 | } |
143 | 160 |
|
| 161 | +static 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 ); |
| 167 | +} |
| 168 | + |
144 | 169 | static const command_t ipc_child_commands[] = { |
145 | 170 | { "die", 0, ipc_child_cmd_die, 0 }, |
146 | 171 | { "wallops", 1, ipc_child_cmd_wallops, 0 }, |
147 | 172 | { "lilo", 1, ipc_child_cmd_lilo, 0 }, |
148 | 173 | { "opermsg", 1, ipc_child_cmd_opermsg, 0 }, |
149 | 174 | { "rehash", 0, ipc_child_cmd_rehash, 0 }, |
150 | 175 | { "kill", 2, ipc_child_cmd_kill, 0 }, |
| 176 | + { "hello", 0, ipc_child_cmd_hello, 0 }, |
151 | 177 | { NULL } |
152 | 178 | }; |
153 | 179 |
|
154 | 180 |
|
155 | 181 | static void ipc_command_exec( void *data, char **cmd, const command_t *commands ) |
156 | 182 | { |
157 | | - int i; |
| 183 | + int i, j; |
158 | 184 |
|
159 | 185 | if( !cmd[0] ) |
160 | 186 | return; |
161 | 187 |
|
162 | 188 | for( i = 0; commands[i].command; i ++ ) |
163 | 189 | if( g_strcasecmp( commands[i].command, cmd[0] ) == 0 ) |
164 | 190 | { |
| 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 | + |
165 | 197 | if( commands[i].flags & IPC_CMD_TO_CHILDREN ) |
166 | 198 | ipc_to_children( cmd ); |
167 | 199 | else |
168 | 200 | commands[i].execute( data, cmd ); |
169 | 201 |
|
170 | | - return; |
| 202 | + break; |
171 | 203 | } |
172 | 204 | } |
173 | 205 |
|
@@ -378,3 +410,91 @@ void ipc_master_free_all() |
378 | 410 | g_slist_free( child_list ); |
379 | 411 | child_list = NULL; |
380 | 412 | } |
| 413 | + |
| 414 | +char *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 | + |
| 454 | +void ipc_master_set_statefile( char *fn ) |
| 455 | +{ |
| 456 | + statefile = g_strdup( fn ); |
| 457 | +} |
| 458 | + |
| 459 | +int 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 | +} |
0 commit comments