diff --git a/keepalived/core/main.c b/keepalived/core/main.c index 703b89b425..9f34d99990 100644 --- a/keepalived/core/main.c +++ b/keepalived/core/main.c @@ -169,6 +169,7 @@ const char *snmp_socket; /* Socket to use for SNMP agent */ #endif static const char *syslog_ident; /* syslog ident if not default */ bool use_pid_dir; /* Put pid files in /run/keepalived or @localstatedir@/run/keepalived */ +bool children_started; /* Set once children have been run first time */ unsigned os_major; /* Kernel version */ unsigned os_minor; @@ -560,6 +561,8 @@ start_keepalived(__attribute__((unused)) thread_ref_t thread) pidfile_rm(&bfd_pidfile); #endif + children_started = true; + #ifndef _ONE_PROCESS_DEBUG_ /* Do we have a reload file to monitor */ if (global_data->reload_time_file) diff --git a/keepalived/core/pidfile.c b/keepalived/core/pidfile.c index cf49aee98f..8e2214d86d 100644 --- a/keepalived/core/pidfile.c +++ b/keepalived/core/pidfile.c @@ -151,18 +151,6 @@ close_other_pidfiles(void) #endif } -/* Create the running daemon pidfile */ -bool -pidfile_write(const pidfile_t *pidf) -{ - if (pidf->fd == -1) - return false; - - dprintf(pidf->fd, "%d\n", getpid()); - - return true; -} - /* return the daemon running state */ static bool create_pidfile(pidfile_t *pidf) @@ -226,7 +214,7 @@ create_pidfile(pidfile_t *pidf) break; } - /* pid file is now openned, locked and 0 length */ + /* pid file is now opened, locked and 0 length */ return false; } @@ -258,3 +246,54 @@ keepalived_running(unsigned long mode) #endif return false; } + +/* Create the running daemon pidfile */ +bool +pidfile_write(pidfile_t *pidf) +{ + int ret; + + if (pidf->fd == -1) + return false; + + if (children_started) { + struct stat statb, fstatb; + + /* There could be more error handling, but that will just + * complicate the code for minimal benefit. */ + if (stat(pidf->path, &statb)) { + /* pidfile no longer exists */ + close(pidf->fd); + create_pidfile(pidf); + } else { + if (fstat(pidf->fd, &fstatb) || + statb.st_dev != fstatb.st_dev || + statb.st_ino != fstatb.st_ino) { + /* The pidfile has been deleted and recreated. Open the new one. */ + close(pidf->fd); + while ((pidf->fd = open(pidf->path, O_NOFOLLOW | O_WRONLY | O_NONBLOCK)) == -1 && errno == EINTR); + + if (pidf->fd == -1) + return false; + } + + /* Since we have already written to the pid file, + * we need to reset the file offset and truncate the file. */ + off_t offs = lseek(pidf->fd, 0, SEEK_CUR); + if (offs) { + lseek(pidf->fd, 0, SEEK_SET); + if (ftruncate(pidf->fd, 0)) + log_message(LOG_INFO, "ftruncate error %d - %m", errno); + } + } + } + + ret = dprintf(pidf->fd, "%d\n", getpid()); + + if (ret < 0) + log_message(LOG_INFO, "pidfile_write returned %d, errno %d - %m", ret, errno); + else + log_message(LOG_INFO, "pidfile_write returned %d", ret); + + return true; +} diff --git a/keepalived/include/main.h b/keepalived/include/main.h index b0c6bd49b7..14caac0cf9 100644 --- a/keepalived/include/main.h +++ b/keepalived/include/main.h @@ -79,6 +79,7 @@ extern bool snmp_option; /* Enable SNMP support */ extern const char *snmp_socket; /* Socket to use for SNMP agent */ #endif extern bool use_pid_dir; /* pid files in /run/keepalived */ +extern bool children_started; /* Set once children have been run first time */ extern unsigned os_major; /* Kernel version */ extern unsigned os_minor; extern unsigned os_release; diff --git a/keepalived/include/pidfile.h b/keepalived/include/pidfile.h index 068a1db983..b8b595f984 100644 --- a/keepalived/include/pidfile.h +++ b/keepalived/include/pidfile.h @@ -58,7 +58,7 @@ extern void create_pid_dir(void); extern void remove_pid_dir(void); extern char *make_pidfile_name(const char *, const char *, const char *); extern void pidfile_close(pidfile_t *, bool); -extern bool pidfile_write(const pidfile_t *); +extern bool pidfile_write(pidfile_t *); extern void pidfile_rm(pidfile_t *); extern void close_other_pidfiles(void); extern bool keepalived_running(unsigned long);