Blob Blame History Raw
diff --git a/radvd.c b/radvd.c
index 82efe0b..508abd1 100644
--- a/radvd.c
+++ b/radvd.c
@@ -17,6 +17,10 @@
 #include "includes.h"
 #include "radvd.h"
 #include "pathnames.h"
+#include <libgen.h>
+#include <sys/file.h>
+#include <stdio.h>
+
 
 #ifdef HAVE_NETLINK
 #include "netlink.h"
@@ -99,6 +103,9 @@ int readin_config(char *);
 int check_conffile_perm(const char *, const char *);
 const char *get_pidfile(void);
 void main_loop(void);
+static int write_pid_file(char const *daemon_pid_file_ident, pid_t pid);
+static int open_and_lock_pid_file(char const *daemon_pid_file_ident);
+static void check_pid_file(char const *daemon_pid_file_ident);
 
 int
 main(int argc, char *argv[])
@@ -110,6 +117,7 @@ main(int argc, char *argv[])
 	char *chrootdir = NULL;
 	int configtest = 0;
 	int daemonize = 1;
+       int pidfd = 0;
 #ifdef HAVE_GETOPT_LONG
 	int opt_idx;
 #endif
@@ -332,6 +340,14 @@ main(int argc, char *argv[])
 			exit(1);
 		}
 		daemon_retval_send(0);
+	} else {
+		pidfd = open_and_lock_pid_file(pidfile);
+		if (0 != write_pid_file(pidfile, getpid())) {
+			flog(LOG_ERR, "failure writing pid file detected");
+			exit(-1);
+		}
+		check_pid_file(pidfile);
+
 	}
 
 	/*
@@ -347,11 +363,11 @@ main(int argc, char *argv[])
 	main_loop();
 	flog(LOG_INFO, "sending stop adverts", pidfile);
 	stop_adverts();
-	if (daemonize) {
-		flog(LOG_INFO, "removing %s", pidfile);
-		unlink(pidfile);
+	if (!daemonize){
+		close(pidfd);
 	}
-
+	flog(LOG_INFO, "removing %s", pidfile);
+	unlink(pidfile);
 	return 0;
 }
 
@@ -841,3 +857,105 @@ usage(void)
 	exit(1);
 }
 
+static int open_pid_file(char const *daemon_pid_file_ident)
+{
+	int pidfd = open(daemon_pid_file_ident, O_SYNC | O_CREAT | O_RDWR, 0644);
+	if (-1 == pidfd) {
+	        flog(LOG_ERR, "unable to open pid file, %s: %s", daemon_pid_file_ident, strerror(errno));
+		exit(-1);
+	} else {
+	        dlog(LOG_DEBUG, 5, "opened pid file %s", daemon_pid_file_ident);
+	}
+       return pidfd;
+}
+
+static int open_and_lock_pid_file(char const *daemon_pid_file_ident)
+{
+	dlog(LOG_DEBUG, 3, "radvd startup PID is %d", getpid());
+
+	int pidfd = open_pid_file(daemon_pid_file_ident);
+
+	int lock = flock(pidfd, LOCK_EX | LOCK_NB);
+	if (0 != lock) {
+		flog(LOG_ERR, "unable to lock pid file, %s: %s", daemon_pid_file_ident, strerror(errno));
+		exit(-1);
+	} else {
+		dlog(LOG_DEBUG, 4, "locked pid file %s", daemon_pid_file_ident);
+	}
+
+	return pidfd;
+}
+
+
+static int write_pid_file(char const *daemon_pid_file_ident, pid_t pid)
+{
+ 	int pidfd = open_pid_file(daemon_pid_file_ident);
+	char pid_str[20] = {""};
+	sprintf(pid_str, "%d", pid);
+	dlog(LOG_DEBUG, 3, "radvd PID is %s", pid_str);
+	size_t len = strlen(pid_str);
+	int rc = write(pidfd, pid_str, len);
+        if (rc != (int)len) {
+	        return -1;
+	}
+        char newline[] = {"\n"};
+	len = strlen(newline);
+	rc = write(pidfd, newline, len);
+	if (rc != (int)len) {
+               close(pidfd);
+		return -1;
+	}
+        rc = fsync(pidfd);
+	if (rc != 0) {
+		dlog(LOG_DEBUG, 4, "failed to fsync pid file: %s", daemon_pid_file_ident);
+	}
+	rc = close(pidfd);
+        if (rc != 0) {
+                dlog(LOG_DEBUG, 4, "failed to close pid file: %s", daemon_pid_file_ident);
+        }
+        char *dirstrcopy = strdup(daemon_pid_file_ident);
+        char *dirstr = dirname(dirstrcopy);
+        int dirfd = open(dirstr, O_RDONLY);
+        if (dirfd == -1){
+           dlog(LOG_DEBUG, 4, "Failed to open directory: %s", dirstr);
+        }
+        rc = fsync(dirfd);
+        if (rc != 0) {
+                dlog(LOG_DEBUG, 4, "failed to fsync pid dir: %s", dirstr);
+        }
+        rc = close(dirfd);
+        if (rc != 0) {
+                dlog(LOG_DEBUG, 4, "failed to close pid dir: %s", dirstr);
+        }
+        free(dirstrcopy);
+        dlog(LOG_DEBUG, 4, "wrote pid %d to pid file: %s", pid, daemon_pid_file_ident);
+        return rc;
+}
+
+
+static void check_pid_file(char const *daemon_pid_file_ident)
+{
+	FILE *pidfile = fopen(daemon_pid_file_ident, "r");
+
+	if (!pidfile) {
+		flog(LOG_ERR, "unable to open pid file, %s: %s", daemon_pid_file_ident, strerror(errno));
+		exit(-1);
+	}
+
+	pid_t pid = -1;
+
+	int rc = fscanf(pidfile, "%d", &pid);
+	fclose(pidfile);
+
+	if (rc != 1) {
+		flog(LOG_ERR, "unable to read pid from pid file: %s", daemon_pid_file_ident);
+		exit(-1);
+	}
+
+	if (pid != getpid()) {
+		flog(LOG_ERR, "pid in file, %s, doesn't match getpid(): %d != %d", daemon_pid_file_ident, pid, getpid());
+		exit(-1);
+	}
+	dlog(LOG_DEBUG, 4, "validated pid file, %s: %d", daemon_pid_file_ident, pid);
+}
+