Store PID before daemonizing

This commit is contained in:
Petr Písař 2012-04-12 15:58:28 +02:00
parent cca9be20b1
commit 8e9d1c3480
3 changed files with 296 additions and 3 deletions

View File

@ -0,0 +1,210 @@
From 9c0bb4965a916955bfec1c7702e25beb46157a5f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20P=C3=ADsa=C5=99?= <ppisar@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

View File

@ -0,0 +1,66 @@
From 1cda2ef33f505be34e690d1b7a1e5eac632819af Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20P=C3=ADsa=C5=99?= <ppisar@redhat.com>
Date: Wed, 11 Apr 2012 13:52:24 +0200
Subject: [PATCH] Use pkg-config to discover libdaemon
---
Makefile.am | 6 +++++-
README | 2 ++
configure.ac | 6 +-----
3 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/Makefile.am b/Makefile.am
index 4b76a97..04b834b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -59,8 +59,12 @@ EXTRA_radvd_SOURCES = \
netlink.h \
privsep-linux.c
+radvd_CPPFLAGS = \
+ @DAEMON_CFLAGS@
+
radvd_LDADD = \
- @CONDITIONAL_SOURCES@
+ @CONDITIONAL_SOURCES@ \
+ @DAEMON_LIBS@
radvd_DEPENDENCIES = \
@CONDITIONAL_SOURCES@
diff --git a/README b/README
index 5192c52..efa3154 100644
--- a/README
+++ b/README
@@ -2,6 +2,8 @@
Installation:
=============
+Install 'pkg-config' and 'libdaemon'.
+
Run configure, e.g.
./configure --prefix=/usr/local --sysconfdir=/etc --mandir=/usr/share/man
diff --git a/configure.ac b/configure.ac
index b3f0a19..3ab6667 100644
--- a/configure.ac
+++ b/configure.ac
@@ -137,15 +137,11 @@ 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])
-)
+PKG_CHECK_MODULES([DAEMON], libdaemon)
dnl Checks for header files.
AC_HEADER_STDC
AC_CHECK_HEADERS( \
- libdaemon/dfork.h \
- libdaemon/dpid.h \
getopt.h \
ifaddrs.h \
machine/limits.h \
--
1.7.7.6

View File

@ -1,7 +1,7 @@
Summary: A Router Advertisement daemon
Name: radvd
Version: 1.8.5
Release: 2%{?dist}
Release: 3%{?dist}
# The code includes the advertising clause, so it's GPL-incompatible
License: BSD with advertising
Group: System Environment/Daemons
@ -9,12 +9,23 @@ URL: http://www.litech.org/radvd/
Source: %{url}dist/%{name}-%{version}.tar.gz
Source2: radvd-tmpfs.conf
Source3: radvd.service
# Bug #811997, fixed in upstream after 1.8.5
Patch0: radvd-1.8.5-Use-libdaemon-for-daemonization.patch
# Bug #811997, fixed in upstream after 1.8.5
Patch1: radvd-1.8.5-Use-pkg-config-to-discover-libdaemon.patch
# autoconf needed for Use-libdaemon-for-daemonization and
# Use-pkg-config-to-discover-libdaemon patches
BuildRequires: autoconf
BuildRequires: byacc
BuildRequires: flex
BuildRequires: flex-static
BuildRequires: libdaemon-devel
BuildRequires: pkgconfig
BuildRequires: systemd-units
Requires(postun): systemd-units
Requires(preun): systemd-units
Requires(post): systemd-units
Requires(pre): shadow-utils
BuildRequires: systemd-units
BuildRequires: flex, flex-static, byacc
%description
radvd is the router advertisement daemon for IPv6. It listens to router
@ -29,6 +40,9 @@ services.
%prep
%setup -q
%patch0 -p1 -b .libdaemon
%patch1 -p1 -b .pkgconfig
autoreconf -is
for F in CHANGES; do
iconv -f iso-8859-1 -t utf-8 < "$F" > "${F}.new"
touch -r "$F" "${F}.new"
@ -97,6 +111,9 @@ exit 0
%{_sbindir}/radvdump
%changelog
* Thu Apr 12 2012 Petr Pisar <ppisar@redhat.com> - 1.8.5-3
- Store PID before daemonizing (bug #811997)
* Tue Apr 03 2012 Petr Pisar <ppisar@redhat.com> - 1.8.5-2
- Clean up spec file
- Remove System V init support