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 +#include +#include + #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); +} +