[radvd-devel-l] [PATCH] Use libdaemon for daemonization

Petr Písař ppisar at redhat.com
Thu Apr 5 09:50:55 EDT 2012


The libc daemon(3) function suffers from race bewtween exiting parent
and saving PID into a file.

Using libdaemon library one can avoid this race and can simplify PID
file manipulation.

The only difference against older implementation is, the PID file will
be inspected, created, and removed only if daemonization is requested.
---
 configure.ac |    6 +++
 radvd.c      |  109 +++++++++++++++++++++++++--------------------------------
 2 files changed, 54 insertions(+), 61 deletions(-)

diff --git a/configure.ac b/configure.ac
index 0a6fe0d..2e001bf 100644
--- a/configure.ac
+++ b/configure.ac
@@ -137,9 +137,15 @@ AC_CHECK_LIB(c, inet_ntop,,
 # prevent caching
 unset ac_cv_lib_inet6_inet_ntop
 
+AC_CHECK_LIB([daemon], [daemon_fork], ,
+ AC_MSG_ERROR([Could not use libdaemon library])
+)
+
 dnl Checks for header files.
 AC_HEADER_STDC
 AC_CHECK_HEADERS( \
+	libdaemon/dfork.h \
+	libdaemon/dpid.h \
 	getopt.h \
 	ifaddrs.h \
 	machine/limits.h \
diff --git a/radvd.c b/radvd.c
index 111c21c..ec37157 100644
--- a/radvd.c
+++ b/radvd.c
@@ -23,6 +23,8 @@
 #endif
 
 #include <poll.h>
+#include <libdaemon/dfork.h>
+#include <libdaemon/dpid.h>
 
 struct Interface *IfaceList = NULL;
 
@@ -72,6 +74,7 @@ char usage_str[] =
 extern FILE *yyin;
 
 char *conf_file = NULL;
+char *pidfile = NULL;
 char *pname;
 int sock = -1;
 
@@ -93,15 +96,14 @@ void usage(void);
 int drop_root_privileges(const char *);
 int readin_config(char *);
 int check_conffile_perm(const char *, const char *);
-pid_t strtopid(char const * pidstr);
-void write_pid_file(char const *);
+const char *get_pidfile(void);
 void main_loop(void);
 
 int
 main(int argc, char *argv[])
 {
 	int c, log_method;
-	char *logfile, *pidfile;
+	char *logfile;
 	int facility;
 	char *username = NULL;
 	char *chrootdir = NULL;
@@ -110,6 +112,7 @@ main(int argc, char *argv[])
 #ifdef HAVE_GETOPT_LONG
 	int opt_idx;
 #endif
+	pid_t pid;
 
 	pname = ((pname=strrchr(argv[0],'/')) != NULL)?pname+1:argv[0];
 
@@ -290,16 +293,45 @@ main(int argc, char *argv[])
 	 * lets fork now...
 	 */
 
-	if (get_debuglevel() == 0) {
+	if (get_debuglevel() > 0) {
+		daemonize = 0;
+	}
 
-		if (daemonize) {
-			/* Detach from controlling terminal */
-			if (daemon(0, 0) < 0)
-				perror("daemon");
+	if (daemonize) {
+		if (daemon_retval_init()) {
+			flog(LOG_ERR, "Could not initialize daemon IPC.");
+			exit(1);
+		}
+
+		pid = daemon_fork();
+		if (-1 == pid) {
+			flog(LOG_ERR, "Could not fork: %s", strerror(errno));
+			daemon_retval_done();
+			exit(1);
 		}
-	}
 
-	write_pid_file(pidfile);
+		if (0 < pid) {
+			if (daemon_retval_wait(0)) {
+				flog(LOG_ERR, "Could not daemonize.");
+				exit(1);
+			}
+			exit(0);
+		}
+
+		daemon_pid_file_proc = get_pidfile;
+		if (daemon_pid_file_is_running() >= 0) {
+			flog(LOG_ERR, "radvd already running, terminating.");
+			daemon_retval_send(1);
+			exit(1);
+		}
+		if (daemon_pid_file_create()) {
+			flog(LOG_ERR, "Cannot create radvd PID file, terminating: %s",
+					strerror(errno));
+			daemon_retval_send(2);
+			exit(1);
+		}
+		daemon_retval_send(0);
+	}
 
 	/*
 	 *	config signal handlers
@@ -314,62 +346,17 @@ main(int argc, char *argv[])
 	main_loop();
 	flog(LOG_INFO, "sending stop adverts", pidfile);
 	stop_adverts();
-	flog(LOG_INFO, "removing %s", pidfile);
-	unlink(pidfile);
+	if (daemonize) {
+		flog(LOG_INFO, "removing %s", pidfile);
+		unlink(pidfile);
+	}
 
 	return 0;
 }
 
 
-pid_t strtopid(char const * pidstr)
-{
-	return atol(pidstr);
-}
-
-void write_pid_file(char const * pidfile)
-{
-	int fd, ret;
-	char pidstr[32];
-
-	if ((fd = open(pidfile, O_RDONLY, 0)) > 0)
-	{
-		ret = read(fd, pidstr, sizeof(pidstr) - 1);
-		if (ret < 0)
-		{
-			flog(LOG_ERR, "cannot read radvd pid file, terminating: %s", strerror(errno));
-			exit(1);
-		}
-		if (ret > 0) {
-				pid_t pid;
-				pidstr[ret] = '\0';
-				pid = strtopid(pidstr);
-				if (pid > 0 && !kill(pid, 0)) {
-					flog(LOG_ERR, "radvd already running, terminating.");
-					exit(1);
-				}
-		}
-		close(fd);
-		fd = open(pidfile, O_CREAT|O_TRUNC|O_WRONLY, 0644);
-	}
-	else	/* FIXME: not atomic if pidfile is on an NFS mounted volume */
-		fd = open(pidfile, O_CREAT|O_EXCL|O_WRONLY, 0644);
-
-	if (fd < 0)
-	{
-		flog(LOG_ERR, "cannot create radvd pid file, terminating: %s", strerror(errno));
-		exit(1);
-	}
-
-	snprintf(pidstr, sizeof(pidstr), "%ld\n", (long)getpid());
-
-	ret = write(fd, pidstr, strlen(pidstr));
-	if (ret != strlen(pidstr))
-	{
-		flog(LOG_ERR, "cannot write radvd pid file, terminating: %s", strerror(errno));
-		exit(1);
-	}
-
-	close(fd);
+const char *get_pidfile(void) {
+	return pidfile;
 }
 
 void main_loop(void)
-- 
1.7.7.6




More information about the radvd-devel-l mailing list