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);