mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-24 02:43:03 +01:00
shutdown fbserver when fbguard receives TERM or INT signal
This commit is contained in:
parent
c9a0da0c0e
commit
e9816e87af
@ -37,6 +37,8 @@
|
|||||||
|
|
||||||
#ifdef HAVE_ERRNO_H
|
#ifdef HAVE_ERRNO_H
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#else
|
||||||
|
int errno = -1;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "../jrd/common.h"
|
#include "../jrd/common.h"
|
||||||
@ -57,6 +59,15 @@ const char* INTERBASE_USER = "interbase";
|
|||||||
const char* FIREBIRD_USER = "firebird";
|
const char* FIREBIRD_USER = "firebird";
|
||||||
const char* INTERBASE_USER_SHORT= "interbas";
|
const char* INTERBASE_USER_SHORT= "interbas";
|
||||||
|
|
||||||
|
volatile sig_atomic_t shutting_down;
|
||||||
|
|
||||||
|
|
||||||
|
void shutdown_handler(int)
|
||||||
|
{
|
||||||
|
shutting_down = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int CLIB_ROUTINE main( int argc, char **argv)
|
int CLIB_ROUTINE main( int argc, char **argv)
|
||||||
{
|
{
|
||||||
/**************************************
|
/**************************************
|
||||||
@ -77,6 +88,7 @@ int CLIB_ROUTINE main( int argc, char **argv)
|
|||||||
bool done = true;
|
bool done = true;
|
||||||
const TEXT* prog_name = argv[0];
|
const TEXT* prog_name = argv[0];
|
||||||
const TEXT* pidfilename = 0;
|
const TEXT* pidfilename = 0;
|
||||||
|
int guard_exit_code = 0;
|
||||||
|
|
||||||
const TEXT* const* const end = argc + argv;
|
const TEXT* const* const end = argc + argv;
|
||||||
argv++;
|
argv++;
|
||||||
@ -141,25 +153,43 @@ int CLIB_ROUTINE main( int argc, char **argv)
|
|||||||
|
|
||||||
/* move the server name into the argument to be passed */
|
/* move the server name into the argument to be passed */
|
||||||
TEXT process_name[1024];
|
TEXT process_name[1024];
|
||||||
|
process_name[0] = '\0';
|
||||||
TEXT* server_args[2];
|
TEXT* server_args[2];
|
||||||
server_args[0] = process_name;
|
server_args[0] = process_name;
|
||||||
server_args[1] = NULL;
|
server_args[1] = NULL;
|
||||||
|
|
||||||
|
shutting_down = 0;
|
||||||
|
if (UTIL_set_handler(SIGTERM, shutdown_handler, false) < 0) {
|
||||||
|
fprintf(stderr, "%s: Cannot set signal handler (error %d).\n",
|
||||||
|
prog_name, errno);
|
||||||
|
exit(-5);
|
||||||
|
}
|
||||||
|
if (UTIL_set_handler(SIGINT, shutdown_handler, false) < 0) {
|
||||||
|
fprintf(stderr, "%s: Cannot set signal handler (error %d).\n",
|
||||||
|
prog_name, errno);
|
||||||
|
exit(-5);
|
||||||
|
}
|
||||||
|
|
||||||
// detach from controlling tty
|
// detach from controlling tty
|
||||||
divorce_terminal(0);
|
divorce_terminal(0);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
int ret_code;
|
int ret_code;
|
||||||
|
|
||||||
|
if (shutting_down) {
|
||||||
|
// don't start a child
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
gds__log("%s: guardian starting %s\n",
|
gds__log("%s: guardian starting %s\n",
|
||||||
prog_name, SUPER_SERVER_BINARY);
|
prog_name, SUPER_SERVER_BINARY);
|
||||||
pid_t child_pid = UTIL_start_process(SUPER_SERVER_BINARY, server_args);
|
pid_t child_pid = UTIL_start_process(SUPER_SERVER_BINARY, server_args);
|
||||||
if (child_pid == -1) {
|
if (child_pid == -1) {
|
||||||
/* could not fork the server */
|
/* could not fork the server */
|
||||||
gds__log("%s: guardian could not start %s\n", prog_name,
|
gds__log("%s: guardian could not start %s\n",
|
||||||
server_args[1] ? server_args[1] : SUPER_SERVER_BINARY);
|
prog_name, process_name);
|
||||||
fprintf(stderr, "%s: Could not start %s\n", prog_name,
|
fprintf(stderr, "%s: Could not start %s\n",
|
||||||
server_args[1] ? server_args[1] : SUPER_SERVER_BINARY);
|
prog_name, process_name);
|
||||||
UTIL_ex_unlock(fd_guard);
|
UTIL_ex_unlock(fd_guard);
|
||||||
exit(-4);
|
exit(-4);
|
||||||
}
|
}
|
||||||
@ -172,51 +202,74 @@ int CLIB_ROUTINE main( int argc, char **argv)
|
|||||||
fclose(pf);
|
fclose(pf);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
#ifndef HAVE_ERRNO_H
|
|
||||||
int errno = -1;
|
|
||||||
#endif
|
|
||||||
gds__log("%s: guardian could not open %s for writing, error %d\n",
|
gds__log("%s: guardian could not open %s for writing, error %d\n",
|
||||||
prog_name, pidfilename, errno);
|
prog_name, pidfilename, errno);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* wait for child to die, and evaluate exit status */
|
/* wait for child to die, and evaluate exit status */
|
||||||
ret_code = UTIL_wait_for_child(child_pid);
|
bool shutdown_child = true;
|
||||||
|
if (!shutting_down) {
|
||||||
|
ret_code = UTIL_wait_for_child(child_pid, shutting_down);
|
||||||
|
shutdown_child = (ret_code == -2);
|
||||||
|
}
|
||||||
|
if (shutting_down) {
|
||||||
|
if (shutdown_child) {
|
||||||
|
ret_code = UTIL_shutdown_child(child_pid, 3, 1);
|
||||||
|
if (ret_code < 0) {
|
||||||
|
gds__log(
|
||||||
|
"%s: error while shutting down %s (%d)\n",
|
||||||
|
prog_name, process_name, errno);
|
||||||
|
guard_exit_code = -6;
|
||||||
|
}
|
||||||
|
else if (ret_code == 1) {
|
||||||
|
gds__log(
|
||||||
|
"%s: %s killed (did not terminate)\n",
|
||||||
|
prog_name, process_name);
|
||||||
|
}
|
||||||
|
else if (ret_code == 2) {
|
||||||
|
gds__log(
|
||||||
|
"%s: unable to shutdown %s\n",
|
||||||
|
prog_name, process_name);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gds__log(
|
||||||
|
"%s: %s terminated\n",
|
||||||
|
prog_name, process_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (ret_code != NORMAL_EXIT) {
|
if (ret_code != NORMAL_EXIT) {
|
||||||
/* check for startup error */
|
/* check for startup error */
|
||||||
if (ret_code == STARTUP_ERROR) {
|
if (ret_code == STARTUP_ERROR) {
|
||||||
gds__log("%s: %s terminated due to startup error (%d)\n",
|
gds__log("%s: %s terminated due to startup error (%d)\n",
|
||||||
prog_name, server_args[1] ? server_args[1] :
|
prog_name, process_name, ret_code);
|
||||||
SUPER_SERVER_BINARY, ret_code);
|
|
||||||
if (option == IGNORE) {
|
if (option == IGNORE) {
|
||||||
gds__log
|
gds__log
|
||||||
("%s: %s terminated due to startup error (%d)\n Trying again\n",
|
("%s: %s terminated due to startup error (%d)\n Trying again\n",
|
||||||
prog_name,
|
prog_name, process_name, ret_code);
|
||||||
server_args[1] ? server_args[1] :
|
|
||||||
SUPER_SERVER_BINARY, ret_code);
|
|
||||||
|
|
||||||
done = false; /* Try it again, Sam (even if it is a startup error) FSG 8.11.2000 */
|
done = false; /* Try it again, Sam (even if it is a startup error) FSG 8.11.2000 */
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
gds__log("%s: %s terminated due to startup error (%d)\n",
|
gds__log("%s: %s terminated due to startup error (%d)\n",
|
||||||
prog_name, server_args[1] ? server_args[1] :
|
prog_name, process_name, ret_code);
|
||||||
SUPER_SERVER_BINARY, ret_code);
|
|
||||||
|
|
||||||
done = true; /* do not restart we have a startup problem */
|
done = true; /* do not restart we have a startup problem */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
gds__log("%s: %s terminated abnormally (%d)\n", prog_name,
|
gds__log("%s: %s terminated abnormally (%d)\n",
|
||||||
server_args[1] ? server_args[1] :
|
prog_name, process_name, ret_code);
|
||||||
SUPER_SERVER_BINARY, ret_code);
|
|
||||||
if (option == FOREVER || option == IGNORE)
|
if (option == FOREVER || option == IGNORE)
|
||||||
done = false;
|
done = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* Normal shutdown - eg: via ibmgr - don't restart the server */
|
/* Normal shutdown - eg: via ibmgr - don't restart the server */
|
||||||
gds__log("%s: %s normal shutdown.\n", prog_name,
|
gds__log("%s: %s normal shutdown.\n",
|
||||||
server_args[1] ? server_args[1] : SUPER_SERVER_BINARY);
|
prog_name, process_name);
|
||||||
done = true;
|
done = true;
|
||||||
}
|
}
|
||||||
} while (!done);
|
} while (!done);
|
||||||
@ -225,5 +278,5 @@ int CLIB_ROUTINE main( int argc, char **argv)
|
|||||||
remove(pidfilename);
|
remove(pidfilename);
|
||||||
}
|
}
|
||||||
UTIL_ex_unlock(fd_guard);
|
UTIL_ex_unlock(fd_guard);
|
||||||
exit(0);
|
exit(guard_exit_code);
|
||||||
} /* main */
|
} /* main */
|
||||||
|
@ -120,7 +120,7 @@ pid_t UTIL_start_process(const char* process, char** argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int UTIL_wait_for_child( pid_t child_pid)
|
int UTIL_wait_for_child(pid_t child_pid, const volatile sig_atomic_t& shutting_down)
|
||||||
{
|
{
|
||||||
/**************************************
|
/**************************************
|
||||||
*
|
*
|
||||||
@ -135,6 +135,7 @@ int UTIL_wait_for_child( pid_t child_pid)
|
|||||||
* Return code:
|
* Return code:
|
||||||
* 0 Normal exit
|
* 0 Normal exit
|
||||||
* -1 Abnormal exit - unknown reason.
|
* -1 Abnormal exit - unknown reason.
|
||||||
|
* -2 TERM signal caught
|
||||||
* Other Abnormal exit - process error code returned.
|
* Other Abnormal exit - process error code returned.
|
||||||
*
|
*
|
||||||
**************************************/
|
**************************************/
|
||||||
@ -145,10 +146,14 @@ int UTIL_wait_for_child( pid_t child_pid)
|
|||||||
/* wait for the child process with child_pid to exit */
|
/* wait for the child process with child_pid to exit */
|
||||||
|
|
||||||
while (waitpid(child_pid, &child_exit_status, 0) == -1)
|
while (waitpid(child_pid, &child_exit_status, 0) == -1)
|
||||||
if (SYSCALL_INTERRUPTED(errno))
|
if (SYSCALL_INTERRUPTED(errno)) {
|
||||||
continue;
|
if (shutting_down)
|
||||||
else
|
return -2;
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
return (errno);
|
return (errno);
|
||||||
|
}
|
||||||
|
|
||||||
/* Check for very specific conditions before we assume the child
|
/* Check for very specific conditions before we assume the child
|
||||||
did a normal exit. */
|
did a normal exit. */
|
||||||
@ -169,6 +174,65 @@ int UTIL_wait_for_child( pid_t child_pid)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void alrm_handler(int)
|
||||||
|
{
|
||||||
|
// handler for SIGALRM
|
||||||
|
// doesn't do anything, just interrupts a syscall
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int UTIL_shutdown_child(pid_t child_pid,
|
||||||
|
unsigned timeout_term, unsigned timeout_kill)
|
||||||
|
{
|
||||||
|
/**************************************
|
||||||
|
*
|
||||||
|
* U T I L _ s h u t d o w n _ c h i l d
|
||||||
|
*
|
||||||
|
**************************************
|
||||||
|
*
|
||||||
|
* Functional description
|
||||||
|
*
|
||||||
|
* Terminates child using TERM signal, then KILL if it does not finish
|
||||||
|
* within specified timeout
|
||||||
|
*
|
||||||
|
* Return code:
|
||||||
|
* 0 Child finished cleanly (TERM)
|
||||||
|
* 1 Child killed (KILL)
|
||||||
|
* 2 Child not killed by KILL
|
||||||
|
* -1 Syscall failed
|
||||||
|
*
|
||||||
|
**************************************/
|
||||||
|
|
||||||
|
int R;
|
||||||
|
int child_status;
|
||||||
|
|
||||||
|
R = kill(child_pid, SIGTERM);
|
||||||
|
if (R < 0)
|
||||||
|
return ((errno == ESRCH) ? 0 : -1);
|
||||||
|
|
||||||
|
if (UTIL_set_handler(SIGALRM, alrm_handler, false) < 0)
|
||||||
|
return -1;
|
||||||
|
alarm(timeout_term);
|
||||||
|
R = waitpid(child_pid, &child_status, 0);
|
||||||
|
if ((R < 0) && !SYSCALL_INTERRUPTED(errno))
|
||||||
|
return -1;
|
||||||
|
if (R == child_pid)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
R = kill(child_pid, SIGKILL);
|
||||||
|
if (R < 0)
|
||||||
|
return ((errno == ESRCH) ? 0 : -1);
|
||||||
|
alarm(timeout_kill);
|
||||||
|
R = waitpid(child_pid, &child_status, 0);
|
||||||
|
if ((R < 0) && !SYSCALL_INTERRUPTED(errno))
|
||||||
|
return -1;
|
||||||
|
if (R == child_pid)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int UTIL_ex_lock(const TEXT* file)
|
int UTIL_ex_lock(const TEXT* file)
|
||||||
{
|
{
|
||||||
/**************************************
|
/**************************************
|
||||||
@ -254,3 +318,37 @@ void UTIL_ex_unlock( int fd_file)
|
|||||||
close(fd_file);
|
close(fd_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int UTIL_set_handler(int sig, sighandler_t handler, bool restart)
|
||||||
|
{
|
||||||
|
/**************************************
|
||||||
|
*
|
||||||
|
* U T I L _ s e t _ h a n d l e r
|
||||||
|
*
|
||||||
|
**************************************
|
||||||
|
*
|
||||||
|
* Functional description
|
||||||
|
*
|
||||||
|
* This function sets signal handler
|
||||||
|
*
|
||||||
|
**************************************/
|
||||||
|
|
||||||
|
#if defined(HAVE_SIGACTION)
|
||||||
|
struct sigaction sig_action;
|
||||||
|
if (sigaction(sig, NULL, &sig_action) < 0)
|
||||||
|
return -1;
|
||||||
|
sig_action.sa_handler = handler;
|
||||||
|
if (restart)
|
||||||
|
sig_action.sa_flags |= SA_RESTART;
|
||||||
|
else
|
||||||
|
sig_action.sa_flags &= ~SA_RESTART;
|
||||||
|
if (sigaction(sig, &sig_action, NULL) < 0)
|
||||||
|
return -1;
|
||||||
|
#else
|
||||||
|
sighandler_t old_handler = signal(SIGTERM, TERM_handler);
|
||||||
|
if (old_handler == SIG_ERR)
|
||||||
|
return -1;
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -24,10 +24,19 @@
|
|||||||
#ifndef UTIL_PROTO_H
|
#ifndef UTIL_PROTO_H
|
||||||
#define UTIL_PROTO_H
|
#define UTIL_PROTO_H
|
||||||
|
|
||||||
|
#ifdef HAVE_SIGNAL_H
|
||||||
|
#include <signal.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
pid_t UTIL_start_process(const char* process, char** argv);
|
pid_t UTIL_start_process(const char* process, char** argv);
|
||||||
int UTIL_wait_for_child(pid_t child_pid);
|
int UTIL_wait_for_child(pid_t child_pid,
|
||||||
|
const volatile sig_atomic_t& shutting_down);
|
||||||
|
int UTIL_shutdown_child(pid_t child_pid,
|
||||||
|
unsigned timeout_term, unsigned timeout_kill);
|
||||||
int UTIL_ex_lock(const char* file);
|
int UTIL_ex_lock(const char* file);
|
||||||
void UTIL_ex_unlock(int fd_file);
|
void UTIL_ex_unlock(int fd_file);
|
||||||
|
int UTIL_set_handler(int sig, sighandler_t handler, bool restart);
|
||||||
|
|
||||||
#endif // UTIL_PROTO_H
|
#endif // UTIL_PROTO_H
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user