From fefc6803cf08cdda7416d62e41b54d59dabfdad5 Mon Sep 17 00:00:00 2001 From: Konstantin Belousov Date: Fri, 12 Oct 2007 10:38:05 +0000 Subject: [PATCH] When pidfile is already locked and has zero length, do not return success and zero pid from pidfile_read(). Return EAGAIN instead. Sleep up to three times for 5 ms while waiting for pidfile to be written. mount(8) does the kill(mountpid, SIGHUP). If mountd pidfile is truncated, that would result in the SIGHUP delivered to the mount' process group instead of the mountd. Found and analyzed by: Peter Holm Tested by: Peter Holm, kris Reviewed by: pjd MFC after: 1 week --- lib/libutil/pidfile.3 | 4 ++++ lib/libutil/pidfile.c | 16 +++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/lib/libutil/pidfile.3 b/lib/libutil/pidfile.3 index 64f77b05e92d..3eaa7cf010e5 100644 --- a/lib/libutil/pidfile.3 +++ b/lib/libutil/pidfile.3 @@ -168,6 +168,10 @@ Specified pidfile's name is too long. .It Bq Er EINVAL Some process already holds the lock on the given pidfile, but PID read from there is invalid. +.It Bq Er EAGAIN +Some process already holds the lock on the given pidfile, but the file +is truncated. Most likely, the existing daemon is writing new PID into +the file. .El .Pp The diff --git a/lib/libutil/pidfile.c b/lib/libutil/pidfile.c index 983d103b9ae1..ecf0fac48f1a 100644 --- a/lib/libutil/pidfile.c +++ b/lib/libutil/pidfile.c @@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -74,6 +75,8 @@ pidfile_read(const char *path, pid_t *pidptr) close(fd); if (i == -1) return (error); + else if (i == 0) + return (EAGAIN); buf[i] = '\0'; *pidptr = strtol(buf, &endptr, 10); @@ -88,7 +91,8 @@ pidfile_open(const char *path, mode_t mode, pid_t *pidptr) { struct pidfh *pfh; struct stat sb; - int error, fd, len; + int error, fd, len, count; + struct timespec rqtp; pfh = malloc(sizeof(*pfh)); if (pfh == NULL) @@ -115,10 +119,20 @@ pidfile_open(const char *path, mode_t mode, pid_t *pidptr) fd = flopen(pfh->pf_path, O_WRONLY | O_CREAT | O_TRUNC | O_NONBLOCK, mode); if (fd == -1) { + count = 0; + rqtp.tv_sec = 0; + rqtp.tv_nsec = 5000000; if (errno == EWOULDBLOCK && pidptr != NULL) { + again: errno = pidfile_read(pfh->pf_path, pidptr); if (errno == 0) errno = EEXIST; + else if (errno == EAGAIN) { + if (++count <= 3) { + nanosleep(&rqtp, 0); + goto again; + } + } } free(pfh); return (NULL);