1 /********************************************************************\
2 * BitlBee -- An IRC to other IM-networks gateway *
4 * Copyright 2002-2010 Wilmer van der Gaast and others *
5 \********************************************************************/
7 /* IPC - communication between BitlBee processes */
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.
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.
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
35 GSList
*child_list
= NULL
;
36 static int ipc_child_recv_fd
= -1;
38 static void ipc_master_takeover_fail( struct bitlbee_child
*child
, gboolean both
);
39 static gboolean
ipc_send_fd( int fd
, int send_fd
);
41 /* On Solaris and possibly other systems passing FDs between processes is
42 * not possible (or at least not using the method used in this file.
43 * Just disable that code, the functionality is not that important. */
44 #if defined(NO_FD_PASSING) && !defined(CMSG_SPACE)
45 #define CMSG_SPACE(len) 1
48 static void ipc_master_cmd_client( irc_t
*data
, char **cmd
)
50 /* Normally data points at an irc_t block, but for the IPC master
51 this is different. We think this scary cast is better than
52 creating a new command_t structure, just to make the compiler
54 struct bitlbee_child
*child
= (void*) data
;
58 child
->host
= g_strdup( cmd
[1] );
59 child
->nick
= g_strdup( cmd
[2] );
60 child
->realname
= g_strdup( cmd
[3] );
63 /* CLIENT == On initial connects, HELLO is after /RESTARTs. */
64 if( g_strcasecmp( cmd
[0], "CLIENT" ) == 0 )
65 ipc_to_children_str( "OPERMSG :Client connecting (PID=%d): %s@%s (%s)\r\n",
66 (int) ( child
? child
->pid
: -1 ), cmd
[2], cmd
[1], cmd
[3] );
69 static void ipc_master_cmd_nick( irc_t
*data
, char **cmd
)
71 struct bitlbee_child
*child
= (void*) data
;
75 g_free( child
->nick
);
76 child
->nick
= g_strdup( cmd
[1] );
80 static void ipc_master_cmd_die( irc_t
*data
, char **cmd
)
82 if( global
.conf
->runmode
== RUNMODE_FORKDAEMON
)
83 ipc_to_children_str( "DIE\r\n" );
85 bitlbee_shutdown( NULL
, -1, 0 );
88 static void ipc_master_cmd_deaf( irc_t
*data
, char **cmd
)
90 if( global
.conf
->runmode
== RUNMODE_DAEMON
)
92 b_event_remove( global
.listen_watch_source_id
);
93 close( global
.listen_socket
);
95 global
.listen_socket
= global
.listen_watch_source_id
= -1;
97 ipc_to_children_str( "OPERMSG :Closed listening socket, waiting "
98 "for all users to disconnect." );
102 ipc_to_children_str( "OPERMSG :The DEAF command only works in "
103 "normal daemon mode. Try DIE instead." );
107 void ipc_master_cmd_rehash( irc_t
*data
, char **cmd
)
111 oldmode
= global
.conf
->runmode
;
113 g_free( global
.conf
);
114 global
.conf
= conf_load( 0, NULL
);
116 if( global
.conf
->runmode
!= oldmode
)
118 log_message( LOGLVL_WARNING
, "Can't change RunMode setting at runtime, restoring original setting" );
119 global
.conf
->runmode
= oldmode
;
122 if( global
.conf
->runmode
== RUNMODE_FORKDAEMON
)
123 ipc_to_children( cmd
);
126 void ipc_master_cmd_restart( irc_t
*data
, char **cmd
)
128 if( global
.conf
->runmode
!= RUNMODE_FORKDAEMON
)
130 /* Tell child that this is unsupported. */
135 bitlbee_shutdown( NULL
, -1, 0 );
138 void ipc_master_cmd_identify( irc_t
*data
, char **cmd
)
140 struct bitlbee_child
*child
= (void*) data
, *old
= NULL
;
144 if( !child
|| !child
->nick
|| strcmp( child
->nick
, cmd
[1] ) != 0 )
147 g_free( child
->password
);
148 child
->password
= g_strdup( cmd
[2] );
150 for( l
= child_list
; l
; l
= l
->next
)
154 old
->nick
&& nick_cmp( old
->nick
, child
->nick
) == 0 &&
155 old
->password
&& strcmp( old
->password
, child
->password
) == 0 )
159 if( l
&& !child
->to_child
&& !old
->to_child
)
161 resp
= "TAKEOVER INIT\r\n";
162 child
->to_child
= old
;
163 old
->to_child
= child
;
167 /* Won't need the fd since we can't send it anywhere. */
168 closesocket( child
->to_fd
);
170 resp
= "TAKEOVER NO\r\n";
173 if( write( child
->ipc_fd
, resp
, strlen( resp
) ) != strlen( resp
) )
174 ipc_master_free_one( child
);
178 void ipc_master_cmd_takeover( irc_t
*data
, char **cmd
)
180 struct bitlbee_child
*child
= (void*) data
;
183 /* Normal daemon mode doesn't keep these and has simplified code for
188 if( child
->to_child
== NULL
||
189 g_slist_find( child_list
, child
->to_child
) == NULL
)
190 return ipc_master_takeover_fail( child
, FALSE
);
192 if( strcmp( cmd
[1], "AUTH" ) == 0 )
194 /* New connection -> Master */
195 if( child
->to_child
&&
196 child
->nick
&& child
->to_child
->nick
&& cmd
[2] &&
197 child
->password
&& child
->to_child
->password
&& cmd
[3] &&
198 strcmp( child
->nick
, child
->to_child
->nick
) == 0 &&
199 strcmp( child
->nick
, cmd
[2] ) == 0 &&
200 strcmp( child
->password
, child
->to_child
->password
) == 0 &&
201 strcmp( child
->password
, cmd
[3] ) == 0 )
203 ipc_send_fd( child
->to_child
->ipc_fd
, child
->to_fd
);
205 fwd
= irc_build_line( cmd
);
206 if( write( child
->to_child
->ipc_fd
, fwd
, strlen( fwd
) ) != strlen( fwd
) )
207 ipc_master_free_one( child
);
211 return ipc_master_takeover_fail( child
, TRUE
);
213 else if( strcmp( cmd
[1], "DONE" ) == 0 || strcmp( cmd
[1], "FAIL" ) == 0 )
215 /* Old connection -> Master */
218 /* The copy was successful (or not), we don't need it anymore. */
219 closesocket( child
->to_fd
);
222 /* Pass it through to the other party, and flush all state. */
223 fwd
= irc_build_line( cmd
);
224 fd
= child
->to_child
->ipc_fd
;
225 child
->to_child
->to_child
= NULL
;
226 child
->to_child
= NULL
;
227 if( write( fd
, fwd
, strlen( fwd
) ) != strlen( fwd
) )
228 ipc_master_free_one( child
);
233 static const command_t ipc_master_commands
[] = {
234 { "client", 3, ipc_master_cmd_client
, 0 },
235 { "hello", 0, ipc_master_cmd_client
, 0 },
236 { "nick", 1, ipc_master_cmd_nick
, 0 },
237 { "die", 0, ipc_master_cmd_die
, 0 },
238 { "deaf", 0, ipc_master_cmd_deaf
, 0 },
239 { "wallops", 1, NULL
, IPC_CMD_TO_CHILDREN
},
240 { "wall", 1, NULL
, IPC_CMD_TO_CHILDREN
},
241 { "opermsg", 1, NULL
, IPC_CMD_TO_CHILDREN
},
242 { "rehash", 0, ipc_master_cmd_rehash
, 0 },
243 { "kill", 2, NULL
, IPC_CMD_TO_CHILDREN
},
244 { "restart", 0, ipc_master_cmd_restart
, 0 },
245 { "identify", 2, ipc_master_cmd_identify
, 0 },
246 { "takeover", 1, ipc_master_cmd_takeover
, 0 },
251 static void ipc_child_cmd_die( irc_t
*irc
, char **cmd
)
253 irc_abort( irc
, 0, "Shutdown requested by operator" );
256 static void ipc_child_cmd_wallops( irc_t
*irc
, char **cmd
)
258 if( !( irc
->status
& USTATUS_LOGGED_IN
) )
261 if( strchr( irc
->umode
, 'w' ) )
262 irc_write( irc
, ":%s WALLOPS :%s", irc
->root
->host
, cmd
[1] );
265 static void ipc_child_cmd_wall( irc_t
*irc
, char **cmd
)
267 if( !( irc
->status
& USTATUS_LOGGED_IN
) )
270 if( strchr( irc
->umode
, 's' ) )
271 irc_write( irc
, ":%s NOTICE %s :%s", irc
->root
->host
, irc
->user
->nick
, cmd
[1] );
274 static void ipc_child_cmd_opermsg( irc_t
*irc
, char **cmd
)
276 if( !( irc
->status
& USTATUS_LOGGED_IN
) )
279 if( strchr( irc
->umode
, 'o' ) )
280 irc_write( irc
, ":%s NOTICE %s :*** OperMsg *** %s", irc
->root
->host
, irc
->user
->nick
, cmd
[1] );
283 static void ipc_child_cmd_rehash( irc_t
*irc
, char **cmd
)
287 oldmode
= global
.conf
->runmode
;
289 g_free( global
.conf
);
290 global
.conf
= conf_load( 0, NULL
);
292 global
.conf
->runmode
= oldmode
;
295 static void ipc_child_cmd_kill( irc_t
*irc
, char **cmd
)
297 if( !( irc
->status
& USTATUS_LOGGED_IN
) )
300 if( nick_cmp( cmd
[1], irc
->user
->nick
) != 0 )
301 return; /* It's not for us. */
303 irc_write( irc
, ":%s!%s@%s KILL %s :%s", irc
->root
->nick
, irc
->root
->nick
, irc
->root
->host
, irc
->user
->nick
, cmd
[2] );
304 irc_abort( irc
, 0, "Killed by operator: %s", cmd
[2] );
307 static void ipc_child_cmd_hello( irc_t
*irc
, char **cmd
)
309 if( !( irc
->status
& USTATUS_LOGGED_IN
) )
310 ipc_to_master_str( "HELLO\r\n" );
312 ipc_to_master_str( "HELLO %s %s :%s\r\n", irc
->user
->host
, irc
->user
->nick
, irc
->user
->fullname
);
315 static void ipc_child_cmd_takeover_yes( void *data
);
316 static void ipc_child_cmd_takeover_no( void *data
);
318 static void ipc_child_cmd_takeover( irc_t
*irc
, char **cmd
)
320 if( strcmp( cmd
[1], "NO" ) == 0 )
322 /* Master->New connection */
323 /* No takeover, finish the login. */
325 else if( strcmp( cmd
[1], "INIT" ) == 0 )
327 /* Master->New connection */
328 if( !set_getbool( &irc
->b
->set
, "allow_takeover" ) )
330 ipc_child_cmd_takeover_no( irc
);
334 /* Offer to take over the old session, unless for some reason
335 we're already logging into IM connections. */
336 if( irc
->login_source_id
!= -1 )
337 query_add( irc
, NULL
,
338 "You're already connected to this server. "
339 "Would you like to take over this session?",
340 ipc_child_cmd_takeover_yes
,
341 ipc_child_cmd_takeover_no
, NULL
, irc
);
343 /* This one's going to connect to accounts, avoid that. */
344 b_event_remove( irc
->login_source_id
);
345 irc
->login_source_id
= -1;
347 else if( strcmp( cmd
[1], "AUTH" ) == 0 )
349 /* Master->Old connection */
350 if( irc
->password
&& cmd
[2] && cmd
[3] &&
351 ipc_child_recv_fd
!= -1 &&
352 strcmp( irc
->user
->nick
, cmd
[2] ) == 0 &&
353 strcmp( irc
->password
, cmd
[3] ) == 0 &&
354 set_getbool( &irc
->b
->set
, "allow_takeover" ) )
356 irc_switch_fd( irc
, ipc_child_recv_fd
);
358 irc_rootmsg( irc
, "You've successfully taken over your old session" );
359 ipc_child_recv_fd
= -1;
361 ipc_to_master_str( "TAKEOVER DONE\r\n" );
365 ipc_to_master_str( "TAKEOVER FAIL\r\n" );
368 else if( strcmp( cmd
[1], "DONE" ) == 0 )
370 /* Master->New connection (now taken over by old process) */
373 else if( strcmp( cmd
[1], "FAIL" ) == 0 )
375 /* Master->New connection */
376 irc_rootmsg( irc
, "Could not take over old session" );
380 static void ipc_child_cmd_takeover_yes( void *data
)
382 irc_t
*irc
= data
, *old
= NULL
;
383 char *to_auth
[] = { "TAKEOVER", "AUTH", irc
->user
->nick
, irc
->password
, NULL
};
385 /* Master->New connection */
386 ipc_to_master_str( "TAKEOVER AUTH %s :%s\r\n",
387 irc
->user
->nick
, irc
->password
);
389 if( global
.conf
->runmode
== RUNMODE_DAEMON
)
393 for( l
= irc_connection_list
; l
; l
= l
->next
)
398 irc
->user
->nick
&& old
->user
->nick
&&
399 irc
->password
&& old
->password
&&
400 strcmp( irc
->user
->nick
, old
->user
->nick
) == 0 &&
401 strcmp( irc
->password
, old
->password
) == 0 )
407 ipc_child_cmd_takeover( irc
, to_auth
);
412 /* Drop credentials, we'll shut down soon and shouldn't overwrite
414 irc_rootmsg( irc
, "Trying to take over existing session" );
420 ipc_child_recv_fd
= dup( irc
->fd
);
421 ipc_child_cmd_takeover( old
, to_auth
);
424 /* TODO: irc_setpass() should do all of this. */
425 irc_setpass( irc
, NULL
);
426 irc
->status
&= ~USTATUS_IDENTIFIED
;
427 irc_umode_set( irc
, "-R", 1 );
430 irc_abort( irc
, FALSE
, NULL
);
433 static void ipc_child_cmd_takeover_no( void *data
)
435 ipc_to_master_str( "TAKEOVER NO\r\n" );
436 cmd_identify_finish( data
, 0, 0 );
439 static const command_t ipc_child_commands
[] = {
440 { "die", 0, ipc_child_cmd_die
, 0 },
441 { "wallops", 1, ipc_child_cmd_wallops
, 0 },
442 { "wall", 1, ipc_child_cmd_wall
, 0 },
443 { "opermsg", 1, ipc_child_cmd_opermsg
, 0 },
444 { "rehash", 0, ipc_child_cmd_rehash
, 0 },
445 { "kill", 2, ipc_child_cmd_kill
, 0 },
446 { "hello", 0, ipc_child_cmd_hello
, 0 },
447 { "takeover", 1, ipc_child_cmd_takeover
, 0 },
451 gboolean
ipc_child_identify( irc_t
*irc
)
453 if( global
.conf
->runmode
== RUNMODE_FORKDAEMON
)
455 #ifndef NO_FD_PASSING
456 if( !ipc_send_fd( global
.listen_socket
, irc
->fd
) )
459 ipc_to_master_str( "IDENTIFY %s :%s\r\n", irc
->user
->nick
, irc
->password
);
464 else if( global
.conf
->runmode
== RUNMODE_DAEMON
)
468 char *to_init
[] = { "TAKEOVER", "INIT", NULL
};
470 for( l
= irc_connection_list
; l
; l
= l
->next
)
475 irc
->user
->nick
&& old
->user
->nick
&&
476 irc
->password
&& old
->password
&&
477 strcmp( irc
->user
->nick
, old
->user
->nick
) == 0 &&
478 strcmp( irc
->password
, old
->password
) == 0 )
482 !set_getbool( &irc
->b
->set
, "allow_takeover" ) ||
483 !set_getbool( &old
->b
->set
, "allow_takeover" ) )
486 ipc_child_cmd_takeover( irc
, to_init
);
494 static void ipc_master_takeover_fail( struct bitlbee_child
*child
, gboolean both
)
496 if( child
== NULL
|| g_slist_find( child_list
, child
) == NULL
)
499 if( both
&& child
->to_child
!= NULL
)
500 ipc_master_takeover_fail( child
->to_child
, FALSE
);
502 if( child
->to_fd
> -1 )
504 /* Send this error only to the new connection, which can be
505 recognised by to_fd being set. */
506 if( write( child
->ipc_fd
, "TAKEOVER FAIL\r\n", 15 ) != 15 )
508 ipc_master_free_one( child
);
511 close( child
->to_fd
);
514 child
->to_child
= NULL
;
517 static void ipc_command_exec( void *data
, char **cmd
, const command_t
*commands
)
524 for( i
= 0; commands
[i
].command
; i
++ )
525 if( g_strcasecmp( commands
[i
].command
, cmd
[0] ) == 0 )
527 /* There is no typo in this line: */
528 for( j
= 1; cmd
[j
]; j
++ ); j
--;
530 if( j
< commands
[i
].required_parameters
)
533 if( commands
[i
].flags
& IPC_CMD_TO_CHILDREN
)
534 ipc_to_children( cmd
);
536 commands
[i
].execute( data
, cmd
);
542 /* Return just one line. Returns NULL if something broke, an empty string
543 on temporary "errors" (EAGAIN and friends). */
544 static char *ipc_readline( int fd
, int *recv_fd
)
548 char ccmsg
[CMSG_SPACE(sizeof(recv_fd
))];
549 struct cmsghdr
*cmsg
;
553 /* Because this is internal communication, it should be pretty safe
554 to just peek at the message, find its length (by searching for the
555 end-of-line) and then just read that message. With internal
556 sockets and limites message length, messages should always be
557 complete. Saves us quite a lot of code and buffering. */
558 size
= recv( fd
, buf
, sizeof( buf
) - 1, MSG_PEEK
);
559 if( size
== 0 || ( size
< 0 && !sockerr_again() ) )
561 else if( size
< 0 ) /* && sockerr_again() */
562 return( g_strdup( "" ) );
566 if( ( eol
= strstr( buf
, "\r\n" ) ) == NULL
)
569 size
= eol
- buf
+ 2;
574 memset( &msg
, 0, sizeof( msg
) );
577 #ifndef NO_FD_PASSING
578 msg
.msg_control
= ccmsg
;
579 msg
.msg_controllen
= sizeof( ccmsg
);
582 if( recvmsg( fd
, &msg
, 0 ) != size
)
585 #ifndef NO_FD_PASSING
587 for( cmsg
= CMSG_FIRSTHDR( &msg
); cmsg
; cmsg
= CMSG_NXTHDR( &msg
, cmsg
) )
588 if( cmsg
->cmsg_level
== SOL_SOCKET
&& cmsg
->cmsg_type
== SCM_RIGHTS
)
590 /* Getting more than one shouldn't happen but if it does,
591 make sure we don't leave them around. */
595 *recv_fd
= *(int*) CMSG_DATA( cmsg
);
597 fprintf( stderr, "pid %d received fd %d\n", (int) getpid(), *recv_fd );
603 fprintf( stderr, "pid %d received: %s", (int) getpid(), buf );
605 return g_strndup( buf
, size
- 2 );
608 gboolean
ipc_master_read( gpointer data
, gint source
, b_input_condition cond
)
610 struct bitlbee_child
*child
= data
;
613 if( ( buf
= ipc_readline( source
, &child
->to_fd
) ) )
615 cmd
= irc_parse_line( buf
);
618 ipc_command_exec( child
, cmd
, ipc_master_commands
);
625 ipc_master_free_fd( source
);
631 gboolean
ipc_child_read( gpointer data
, gint source
, b_input_condition cond
)
635 if( ( buf
= ipc_readline( source
, &ipc_child_recv_fd
) ) )
637 cmd
= irc_parse_line( buf
);
640 ipc_command_exec( data
, cmd
, ipc_child_commands
);
653 void ipc_to_master( char **cmd
)
655 if( global
.conf
->runmode
== RUNMODE_FORKDAEMON
)
657 char *s
= irc_build_line( cmd
);
658 ipc_to_master_str( "%s", s
);
661 else if( global
.conf
->runmode
== RUNMODE_DAEMON
)
663 ipc_command_exec( NULL
, cmd
, ipc_master_commands
);
667 void ipc_to_master_str( char *format
, ... )
672 va_start( params
, format
);
673 msg_buf
= g_strdup_vprintf( format
, params
);
676 if( strlen( msg_buf
) > 512 )
678 /* Don't send it, it's too long... */
680 else if( global
.conf
->runmode
== RUNMODE_FORKDAEMON
)
682 if( global
.listen_socket
>= 0 )
683 if( write( global
.listen_socket
, msg_buf
, strlen( msg_buf
) ) <= 0 )
686 else if( global
.conf
->runmode
== RUNMODE_DAEMON
)
690 if( ( s
= strchr( msg_buf
, '\r' ) ) )
693 cmd
= irc_parse_line( msg_buf
);
694 ipc_command_exec( NULL
, cmd
, ipc_master_commands
);
701 void ipc_to_children( char **cmd
)
703 if( global
.conf
->runmode
== RUNMODE_FORKDAEMON
)
705 char *msg_buf
= irc_build_line( cmd
);
706 ipc_to_children_str( "%s", msg_buf
);
709 else if( global
.conf
->runmode
== RUNMODE_DAEMON
)
713 for( l
= irc_connection_list
; l
; l
= l
->next
)
714 ipc_command_exec( l
->data
, cmd
, ipc_child_commands
);
718 void ipc_to_children_str( char *format
, ... )
723 va_start( params
, format
);
724 msg_buf
= g_strdup_vprintf( format
, params
);
727 if( strlen( msg_buf
) > 512 )
729 /* Don't send it, it's too long... */
731 else if( global
.conf
->runmode
== RUNMODE_FORKDAEMON
)
733 int msg_len
= strlen( msg_buf
);
736 for( l
= child_list
; l
; l
= next
)
738 struct bitlbee_child
*c
= l
->data
;
741 if( write( c
->ipc_fd
, msg_buf
, msg_len
) <= 0 )
742 ipc_master_free_one( c
);
745 else if( global
.conf
->runmode
== RUNMODE_DAEMON
)
749 if( ( s
= strchr( msg_buf
, '\r' ) ) )
752 cmd
= irc_parse_line( msg_buf
);
753 ipc_to_children( cmd
);
760 static gboolean
ipc_send_fd( int fd
, int send_fd
)
764 char ccmsg
[CMSG_SPACE(sizeof(fd
))];
765 struct cmsghdr
*cmsg
;
767 memset( &msg
, 0, sizeof( msg
) );
768 iov
.iov_base
= "0x90\r\n"; /* Ja, noppes */
773 #ifndef NO_FD_PASSING
774 msg
.msg_control
= ccmsg
;
775 msg
.msg_controllen
= sizeof( ccmsg
);
776 cmsg
= CMSG_FIRSTHDR( &msg
);
777 cmsg
->cmsg_level
= SOL_SOCKET
;
778 cmsg
->cmsg_type
= SCM_RIGHTS
;
779 cmsg
->cmsg_len
= CMSG_LEN( sizeof( send_fd
) );
780 *(int*)CMSG_DATA( cmsg
) = send_fd
;
781 msg
.msg_controllen
= cmsg
->cmsg_len
;
784 return sendmsg( fd
, &msg
, 0 ) == 6;
787 void ipc_master_free_one( struct bitlbee_child
*c
)
791 b_event_remove( c
->ipc_inpa
);
792 closesocket( c
->ipc_fd
);
799 g_free( c
->realname
);
800 g_free( c
->password
);
803 child_list
= g_slist_remove( child_list
, c
);
805 /* Also, if any child has a reference to this one, remove it. */
806 for( l
= child_list
; l
; l
= l
->next
)
808 struct bitlbee_child
*oc
= l
->data
;
810 if( oc
->to_child
== c
)
811 ipc_master_takeover_fail( oc
, FALSE
);
815 void ipc_master_free_fd( int fd
)
818 struct bitlbee_child
*c
;
820 for( l
= child_list
; l
; l
= l
->next
)
823 if( c
->ipc_fd
== fd
)
825 ipc_master_free_one( c
);
831 void ipc_master_free_all()
834 ipc_master_free_one( child_list
->data
);
837 void ipc_child_disable()
839 b_event_remove( global
.listen_watch_source_id
);
840 close( global
.listen_socket
);
842 global
.listen_socket
= -1;
846 char *ipc_master_save_state()
848 char *fn
= g_strdup( "/tmp/bee-restart.XXXXXX" );
849 int fd
= mkstemp( fn
);
856 log_message( LOGLVL_ERROR
, "Could not create temporary file: %s", strerror( errno
) );
861 /* This is more convenient now. */
862 fp
= fdopen( fd
, "w" );
864 for( l
= child_list
, i
= 0; l
; l
= l
->next
)
867 /* Number of client processes. */
868 fprintf( fp
, "%d\n", i
);
870 for( l
= child_list
; l
; l
= l
->next
)
871 fprintf( fp
, "%d %d\n", (int) ((struct bitlbee_child
*)l
->data
)->pid
,
872 ((struct bitlbee_child
*)l
->data
)->ipc_fd
);
874 if( fclose( fp
) == 0 )
887 static gboolean
new_ipc_client( gpointer data
, gint serversock
, b_input_condition cond
)
889 struct bitlbee_child
*child
= g_new0( struct bitlbee_child
, 1 );
892 child
->ipc_fd
= accept( serversock
, NULL
, 0 );
893 if( child
->ipc_fd
== -1 )
895 log_message( LOGLVL_WARNING
, "Unable to accept connection on UNIX domain socket: %s", strerror(errno
) );
899 child
->ipc_inpa
= b_input_add( child
->ipc_fd
, B_EV_IO_READ
, ipc_master_read
, child
);
901 child_list
= g_slist_prepend( child_list
, child
);
906 int ipc_master_listen_socket()
908 struct sockaddr_un un_addr
;
911 if (!IPCSOCKET
|| !*IPCSOCKET
)
914 /* Clean up old socket files that were hanging around.. */
915 if (unlink(IPCSOCKET
) == -1 && errno
!= ENOENT
) {
916 log_message( LOGLVL_ERROR
, "Could not remove old IPC socket at %s: %s", IPCSOCKET
, strerror(errno
) );
920 un_addr
.sun_family
= AF_UNIX
;
921 strcpy(un_addr
.sun_path
, IPCSOCKET
);
923 serversock
= socket(AF_UNIX
, SOCK_STREAM
, PF_UNIX
);
925 if (serversock
== -1) {
926 log_message( LOGLVL_WARNING
, "Unable to create UNIX socket: %s", strerror(errno
) );
930 if (bind(serversock
, (struct sockaddr
*)&un_addr
, sizeof(un_addr
)) == -1) {
931 log_message( LOGLVL_WARNING
, "Unable to bind UNIX socket to %s: %s", IPCSOCKET
, strerror(errno
) );
935 if (listen(serversock
, 5) == -1) {
936 log_message( LOGLVL_WARNING
, "Unable to listen on UNIX socket: %s", strerror(errno
) );
940 b_input_add( serversock
, B_EV_IO_READ
, new_ipc_client
, NULL
);
945 int ipc_master_listen_socket()
947 /* FIXME: Open named pipe \\.\BITLBEE */
952 int ipc_master_load_state( char *statefile
)
954 struct bitlbee_child
*child
;
958 if( statefile
== NULL
)
961 fp
= fopen( statefile
, "r" );
962 unlink( statefile
); /* Why do it later? :-) */
966 if( fscanf( fp
, "%d", &n
) != 1 )
968 log_message( LOGLVL_WARNING
, "Could not import state information for child processes." );
973 log_message( LOGLVL_INFO
, "Importing information for %d child processes.", n
);
974 for( i
= 0; i
< n
; i
++ )
976 child
= g_new0( struct bitlbee_child
, 1 );
978 if( fscanf( fp
, "%d %d", (int *) &child
->pid
, &child
->ipc_fd
) != 2 )
980 log_message( LOGLVL_WARNING
, "Unexpected end of file: Only processed %d clients.", i
);
985 child
->ipc_inpa
= b_input_add( child
->ipc_fd
, B_EV_IO_READ
, ipc_master_read
, child
);
988 child_list
= g_slist_prepend( child_list
, child
);
991 ipc_to_children_str( "HELLO\r\n" );
992 ipc_to_children_str( "OPERMSG :New %s master process started (version %s)\r\n", PACKAGE
, BITLBEE_VERSION
);