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

Petr Pisar ppisar at redhat.com
Tue Apr 10 03:14:42 EDT 2012


On Fri, Apr 06, 2012 at 11:03:58AM -0700, Reuben Hawkins wrote:
> On Thu, Apr 5, 2012 at 9:21 AM, Petr Pisar <ppisar at redhat.com> wrote:
> > On Thu, Apr 05, 2012 at 08:42:57AM -0700, Reuben Hawkins wrote:
> >> 2012/4/5 Petr Písař <ppisar at redhat.com>:
> >> > 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.
> >>
> >>
> >> Hi Y'all,
> >>
> >> I'm having a problem with gmail forcing the patch inline in the message.
> >>  This makes it difficult to use the patch.  The mail header doesn't seem
> >> to have one of these: Content-Disposition: inline; filename=
> >>
> > Well, this is simple plain text email where the body is the patch. But if
> > you have difficulties, I can resend it as attachment.
> >
> >> Does anybody know how to get gmail to not inline patches?
> >>
> > I have no idea. Some people told me that it's not possible to get it from
> > Gmail web interface and recommended to use IMAP.
> >
> 
> Yes, please send the patch gzip'ed or something.
> 
There it is as a MIME part with non-in-line diposition. You should think more
about your mailbox provider. I think you can get the in-line patch from
this mailing list archive.

I have few comments to the patch:

libdaemon provides pkg-config file to provide proper CFLAGS and LDFLAGS. I did
not use it not to drag pkg-config into radvd configure-time dependencies.
However using pkg-config would be more clean solution.

I think the libdaemon dependency should be documented somewhere in the
README. I did not do that.

I replaced the daemon() call with the libdaemon code. It could be made
optional.

The libdaemon functions can do some low-level logging which I did not
harness because I do not know if it's possible to patch them properly to radvd
logging mechanism.

-- Petr
-------------- next part --------------
From 9c0bb4965a916955bfec1c7702e25beb46157a5f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20P=C3=ADsa=C5=99?= <ppisar at redhat.com>
Date: Thu, 5 Apr 2012 15:24:22 +0200
Subject: [PATCH] Use libdaemon for daemonization

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

-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 230 bytes
Desc: not available
URL: <http://lists.litech.org/pipermail/radvd-devel-l/attachments/20120410/e37df74b/attachment.pgp>


More information about the radvd-devel-l mailing list