Module: sip-router
Branch: master
Commit: 9167c186505abdc122d221dd43f10a261a1b3845
URL:
http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=9167c18…
Author: Marius Zbihlei <marius.zbihlei(a)1and1.ro>
Committer: Marius Zbihlei <marius.zbihlei(a)1and1.ro>
Date: Wed Apr 21 12:35:16 2010 +0300
core: The patch allows ser started in daemonize mode to return the proper error code.
If for example the listen address is not local or a DB connection uses an invalid
password, then the command
"ser" would return 0 (OK) anyway (even if it fails to start).This occurs
because all those checking
(socket, DB connections...) are performed *after* invoking daemonize() so the parent
process (which
could be invoked by "/etc/init.d/ser start") returns 0 knowing nothing about
those errors. This caused some
management tools like HeartBeat to work badly.
The patch is simple: the master process opens a pipe, and reads from one end. The
forked main process,
after the correct initialization of components, will write some bytes to the writting
end. In case of error,
no data is written to the pipe.
The master process waits for 10 seconds, or else it considers the main process blocked
and exits with a different
error code( -2 ). In this case, it is left for the user to ensure that all ser
children are killed correctly.
Patch initially from Iñaki Baz Castillo.
---
daemonize.c | 10 +++++---
daemonize.h | 2 +-
main.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
3 files changed, 65 insertions(+), 7 deletions(-)
diff --git a/daemonize.c b/daemonize.c
index dee40ee..d39cbb3 100644
--- a/daemonize.c
+++ b/daemonize.c
@@ -82,7 +82,7 @@
(normally it shouldn't be bigger than 3) */
/*! \brief daemon init, return 0 on success, -1 on error */
-int daemonize(char* name)
+int daemonize(char* name, int daemon_status_fd_input)
{
FILE *pid_stream;
pid_t pid;
@@ -113,8 +113,8 @@ int daemonize(char* name)
LOG(L_CRIT, "Cannot fork:%s\n", strerror(errno));
goto error;
}else if (pid!=0){
- /*parent process => exit */
- exit(0);
+ /*parent process => return 0 */
+ return 0;
}
/* become session leader to drop the ctrl. terminal */
if (setsid()<0){
@@ -211,9 +211,11 @@ int daemonize(char* name)
/* continue, leave it open */
};
- /* close any open file descriptors */
+ /* close all but the daemon_status_fd_input as the main process
+ must still write into it to tell the parent to exit with 0 */
closelog();
for (r=3;r<MAX_FD; r++){
+ if(r != daemon_status_fd_input)
close(r);
}
diff --git a/daemonize.h b/daemonize.h
index d1964d2..af71a1b 100644
--- a/daemonize.h
+++ b/daemonize.h
@@ -30,7 +30,7 @@
#ifndef _daemonize_h
#define _daemonize_h
-int daemonize(char* name);
+int daemonize(char* name, int daemon_status_fd_input);
int do_suid();
int increase_open_fds(int target);
int set_core_dump(int enable, int size);
diff --git a/main.c b/main.c
index 23db569..7d28bcd 100644
--- a/main.c
+++ b/main.c
@@ -73,6 +73,9 @@
* 2008-08-08 sctp support (andrei)
* 2008-08-19 -l support for mmultihomed addresses/addresses lists
* (e.g. -l (eth0, 1.2.3.4, foo.bar) ) (andrei)
+ * 2010-04-19 added daemon_status_fd pipe to communicate the parent process with
+ the main process in daemonize mode, so the parent process can return
+ the proper exit status code (ibc)
*/
/*!
@@ -254,6 +257,10 @@ Options:\n\
#endif
;
+/*! pipe to communicate the parent and main processes when daemonizing in order
+ to get the proper exit status code */
+int daemon_status_fd[2];
+
/* print compile-time constants */
void print_ct_constants()
{
@@ -1565,7 +1572,14 @@ int main_loop()
}
#endif
DBG("Expect maximum %d open fds\n", get_max_open_fds());
-
+ /* in daemonize mode write into daemon_status_fd[1] so the parent process
+ will exit with 0 */
+ if (!dont_fork){
+ if (write(daemon_status_fd[1], "go", 2)<0){
+ LM_CRIT("error writing into daemon_status_fd[1]\n");
+ goto error;
+ }
+ }
for(;;){
handle_sigs();
pause();
@@ -1634,6 +1648,13 @@ int main(int argc, char** argv)
int dont_fork_cnt;
struct name_lst* n_lst;
+ /* variables to control the master process exit status */
+ int fd_nbytes;
+ char fd_readbuffer[5];
+ struct timeval tval;
+ fd_set fds;
+ int res;
+
/*init*/
time(&up_since);
creator_pid = getpid();
@@ -1827,6 +1848,7 @@ try_again:
debug_save = default_core_cfg.debug;
if ((yyparse()!=0)||(cfg_errors)){
fprintf(stderr, "ERROR: bad config file (%d errors)\n", cfg_errors);
+
goto error;
}
if (cfg_warnings){
@@ -2170,7 +2192,41 @@ try_again:
#endif /* USE_SCTP */
/* init_daemon? */
if (!dont_fork){
- if ( daemonize((log_name==0)?argv[0]:log_name) <0 ) goto error;
+ if (pipe(daemon_status_fd)<0){
+ LM_CRIT("could not create pipe(daemon_status_fd), exiting...\n");
+ goto error;
+ }
+ if (daemonize((log_name==0)?argv[0]:log_name, daemon_status_fd[1]) < 0)
+ goto error;
+ /* parent process? then wait the main process to write into the pipe */
+ if (getpid() == creator_pid) {
+ /* close the output side of the pipe */
+ close(daemon_status_fd[1]);
+#define MASTER_MAX_SLEEP 10
+try_select_again: tval.tv_usec = 0;
+ tval.tv_sec = MASTER_MAX_SLEEP;/* 10 seconds */
+ FD_ZERO(&fds);
+ FD_SET(daemon_status_fd[0], &fds);
+ res = select(daemon_status_fd[0]+1, &fds, NULL, NULL, &tval);
+ if(res == -1 && errno == EINTR && time(NULL)-up_since <
2*MASTER_MAX_SLEEP)
+ goto try_select_again;
+
+ switch(res){
+ case -1: /* error on select*/ LOG(L_ERR, "Error in select in master
process\n");exit(-1);
+ case 0: /* timeout */ LOG(L_ERR, "timeout in select in master
process\n");exit(-2);
+ default:{
+ fd_nbytes = read(daemon_status_fd[0], fd_readbuffer, 5);
+ /* something read, ok, exit with 0 */
+ if (fd_nbytes > 0)
+ exit(0);
+ /* nothing read, error */
+ else{
+ LOG(L_ERR, "Main process exited before writing to pipe\n");
+ exit(-1);
+ }
+ }
+ }
+ }
}
if (install_sigs() != 0){
fprintf(stderr, "ERROR: could not install the signal handlers\n");