Unlink the control socket on clean shutdown
Previously, the behaviour was to unlink any control socket sat where we wanted to open ours. This would make us lose control of running servers if we happened to collide accidentally. With this patch, the new process will abort() if there is a control socket squatting on the path we want, and unlink it when it closes. This means that an unclean shutdown will leave a dangling, unattached control socket which will block a restart, but that's a better option than intentionally cutting off running servers.
This commit is contained in:
@@ -172,12 +172,12 @@ int open_control_socket( const char * socket_name )
|
|||||||
bind_address.sun_family = AF_UNIX;
|
bind_address.sun_family = AF_UNIX;
|
||||||
strncpy(bind_address.sun_path, socket_name, sizeof(bind_address.sun_path)-1);
|
strncpy(bind_address.sun_path, socket_name, sizeof(bind_address.sun_path)-1);
|
||||||
|
|
||||||
unlink(socket_name); /* ignore failure */
|
//unlink(socket_name); /* ignore failure */
|
||||||
|
|
||||||
FATAL_IF_NEGATIVE(
|
FATAL_IF_NEGATIVE(
|
||||||
bind(control_fd , &bind_address, sizeof(bind_address)),
|
bind(control_fd , &bind_address, sizeof(bind_address)),
|
||||||
"Couldn't bind control socket to %s",
|
"Couldn't bind control socket to %s: %s",
|
||||||
socket_name
|
socket_name, strerror( errno )
|
||||||
);
|
);
|
||||||
|
|
||||||
FATAL_IF_NEGATIVE(
|
FATAL_IF_NEGATIVE(
|
||||||
@@ -203,13 +203,27 @@ void control_serve( struct control * control )
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void control_cleanup(
|
||||||
|
struct control * control,
|
||||||
|
int fatal __attribute__((unused)) )
|
||||||
|
{
|
||||||
|
NULLCHECK( control );
|
||||||
|
unlink( control->socket_name );
|
||||||
|
close( control->control_fd );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void * control_runner( void * control_uncast )
|
void * control_runner( void * control_uncast )
|
||||||
{
|
{
|
||||||
debug("Control thread");
|
debug("Control thread");
|
||||||
NULLCHECK( control_uncast );
|
NULLCHECK( control_uncast );
|
||||||
struct control * control = (struct control *)control_uncast;
|
struct control * control = (struct control *)control_uncast;
|
||||||
|
|
||||||
|
error_set_handler( (cleanup_handler*)control_cleanup, control );
|
||||||
|
|
||||||
control_serve( control );
|
control_serve( control );
|
||||||
|
|
||||||
|
control_cleanup( control, 0 );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -390,7 +404,7 @@ int control_status(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void control_cleanup(struct control_client* client,
|
void control_client_cleanup(struct control_client* client,
|
||||||
int fatal __attribute__ ((unused)) )
|
int fatal __attribute__ ((unused)) )
|
||||||
{
|
{
|
||||||
if (client->socket) { close(client->socket); }
|
if (client->socket) { close(client->socket); }
|
||||||
@@ -408,7 +422,7 @@ void control_respond(struct control_client * client)
|
|||||||
{
|
{
|
||||||
char **lines = NULL;
|
char **lines = NULL;
|
||||||
|
|
||||||
error_set_handler((cleanup_handler*) control_cleanup, client);
|
error_set_handler((cleanup_handler*) control_client_cleanup, client);
|
||||||
|
|
||||||
int i, linesc;
|
int i, linesc;
|
||||||
linesc = read_lines_until_blankline(client->socket, 256, &lines);
|
linesc = read_lines_until_blankline(client->socket, 256, &lines);
|
||||||
@@ -445,7 +459,7 @@ void control_respond(struct control_client * client)
|
|||||||
}
|
}
|
||||||
free(lines);
|
free(lines);
|
||||||
|
|
||||||
control_cleanup(client, 0);
|
control_client_cleanup(client, 0);
|
||||||
debug("control command handled" );
|
debug("control command handled" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
15
src/util.c
15
src/util.c
@@ -18,18 +18,17 @@ void error_init(void)
|
|||||||
pthread_key_create(&cleanup_handler_key, free);
|
pthread_key_create(&cleanup_handler_key, free);
|
||||||
}
|
}
|
||||||
|
|
||||||
void error_handler(int fatal __attribute__ ((unused)) )
|
void error_handler(int fatal)
|
||||||
{
|
{
|
||||||
DECLARE_ERROR_CONTEXT(context);
|
DECLARE_ERROR_CONTEXT(context);
|
||||||
|
|
||||||
if (!context) {
|
if (context) {
|
||||||
/* FIXME: This can't be right - by default we exit()
|
|
||||||
* with a status of 0 in this case.
|
|
||||||
*/
|
|
||||||
pthread_exit((void*) 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
longjmp(context->jmp, fatal ? 1 : 2 );
|
longjmp(context->jmp, fatal ? 1 : 2 );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if ( fatal ) { abort(); }
|
||||||
|
else { pthread_exit((void*) 1); }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user