211 lines
4.8 KiB
Diff
211 lines
4.8 KiB
Diff
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
|
|
|