summaryrefslogtreecommitdiffstats
path: root/lib/libutil
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2007-10-12 10:38:05 +0000
committerkib <kib@FreeBSD.org>2007-10-12 10:38:05 +0000
commit6a0967dff6cbd8b9dfcc745c9c459c8c78529f99 (patch)
treed893a286d761307a588d2b5c946c7fe53cff1c76 /lib/libutil
parent85b25716404c150d0f292db0bda855948181eb55 (diff)
downloadFreeBSD-src-6a0967dff6cbd8b9dfcc745c9c459c8c78529f99.zip
FreeBSD-src-6a0967dff6cbd8b9dfcc745c9c459c8c78529f99.tar.gz
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
Diffstat (limited to 'lib/libutil')
-rw-r--r--lib/libutil/pidfile.34
-rw-r--r--lib/libutil/pidfile.c16
2 files changed, 19 insertions, 1 deletions
diff --git a/lib/libutil/pidfile.3 b/lib/libutil/pidfile.3
index 64f77b0..3eaa7cf 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 983d103..ecf0fac 100644
--- a/lib/libutil/pidfile.c
+++ b/lib/libutil/pidfile.c
@@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$");
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
+#include <time.h>
#include <err.h>
#include <errno.h>
#include <libutil.h>
@@ -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);
OpenPOWER on IntegriCloud