#include "lib/util/pidfile.h"
-int pidfile_path_create(const char *path, int *outfd)
+int pidfile_path_create(const char *path, int *pfd, pid_t *existing_pid)
{
struct flock lck;
char tmp[64] = { 0 };
- pid_t pid;
int fd, ret = 0;
int len;
ssize_t nwritten;
-
- pid = getpid();
+ bool retried = false;
fd = open(path, O_CREAT|O_WRONLY|O_NONBLOCK, 0644);
if (fd == -1) {
}
if (! set_close_on_exec(fd)) {
- close(fd);
- return EIO;
+ ret = errno;
+ goto fail;
}
+retry:
lck = (struct flock) {
.l_type = F_WRLCK,
.l_whence = SEEK_SET,
if (ret != 0) {
ret = errno;
- close(fd);
- return ret;
+
+ if ((ret == EACCES) || (ret == EAGAIN)) {
+ do {
+ ret = fcntl(fd, F_GETLK, &lck);
+ } while ((ret == -1) && (errno == EINTR));
+
+ if (ret == -1) {
+ ret = errno;
+ goto fail;
+ }
+
+ if (lck.l_type == F_UNLCK) {
+ if (!retried) {
+ /* Lock holder died, retry once */
+ retried = true;
+ goto retry;
+ }
+ /* Something badly wrong */
+ ret = EIO;
+ goto fail;
+ }
+
+ if (existing_pid != NULL) {
+ *existing_pid = lck.l_pid;
+ }
+ return EAGAIN;
+ }
+ goto fail;
}
/*
* PID file is locked by us so from here on we should unlink
* on failure
*/
-
- do {
- ret = ftruncate(fd, 0);
- } while ((ret == -1) && (errno == EINTR));
-
- if (ret == -1) {
- ret = EIO;
- goto fail_unlink;
- }
-
- len = snprintf(tmp, sizeof(tmp), "%u\n", pid);
+ len = snprintf(tmp, sizeof(tmp), "%u\n", getpid());
if (len < 0) {
ret = errno;
goto fail_unlink;
} while ((nwritten == -1) && (errno == EINTR));
if ((nwritten == -1) || (nwritten != len)) {
- ret = EIO;
+ ret = errno;
goto fail_unlink;
}
- if (outfd != NULL) {
- *outfd = fd;
+ do {
+ ret = ftruncate(fd, len);
+ } while ((ret == -1) && (errno == EINTR));
+
+ if (ret == -1) {
+ ret = errno;
+ goto fail_unlink;
}
+
+ *pfd = fd;
return 0;
fail_unlink:
unlink(path);
+fail:
close(fd);
return ret;
}
size_t len = strlen(piddir) + strlen(name) + 6;
char pidFile[len];
pid_t pid;
- int ret;
+ int ret, fd;
snprintf(pidFile, sizeof(pidFile), "%s/%s.pid", piddir, name);
- pid = pidfile_pid(piddir, name);
- if (pid != 0) {
+ ret = pidfile_path_create(pidFile, &fd, &pid);
+ if (ret == EAGAIN) {
DEBUG(0,("ERROR: %s is already running. File %s exists and process id %d is running.\n",
name, pidFile, (int)pid));
exit(1);
}
- ret = pidfile_path_create(pidFile, NULL);
- if (ret != 0) {
- DBG_ERR("ERROR: Failed to create PID file %s (%s)\n",
- pidFile, strerror(ret));
- exit(1);
- }
-
/* Leave pid file open & locked for the duration... */
}
/**
* @brief Create a PID file
*
- * Opens file, locks it, and writes PID. Returns EACCES or EAGAIN if
- * another process has the PID file locked. Use unlink(2) and
+ * Opens file, locks it, and writes PID. Returns EAGAIN if another
+ * process has the PID file locked. Use unlink(2) and
* pidfile_fd_close() to remove the PID file.
*
* @param[in] path PID file name
* @param[out] outfd File descriptor of open/locked PID file
+ * @param[out] existing_pid Return existing PID on EAGAIN
* @return 0 on success, errno on failure
*/
-int pidfile_path_create(const char *path, int *outfd);
+int pidfile_path_create(
+ const char *path, int *outfd, pid_t *existing_pid);
/**
* @brief Unlock and close a PID file