[sr-dev] git:master: core: The patch allows ser started in daemonize mode to return the proper error code .

Marius Zbihlei marius.zbihlei at 1and1.ro
Wed Apr 21 11:37:43 CEST 2010


Module: sip-router
Branch: master
Commit: 9167c186505abdc122d221dd43f10a261a1b3845
URL:    http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=9167c186505abdc122d221dd43f10a261a1b3845

Author: Marius Zbihlei <marius.zbihlei at 1and1.ro>
Committer: Marius Zbihlei <marius.zbihlei at 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");




More information about the sr-dev mailing list