1
0
mirror of https://github.com/samba-team/samba.git synced 2025-02-23 09:57:40 +03:00

lib: Make pidfile_path_create() return the existing PID on conflict

Use F_GETLK to get the lock holder PID, this is more accurate than
reading the file contents: A conflicting process might not have
written its PID yet. Also, F_GETLK easily allows to do a retry if the
lock holder just died.

Signed-off-by: Volker Lendecke <vl@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
This commit is contained in:
Volker Lendecke 2021-02-15 11:38:18 +01:00 committed by Jeremy Allison
parent 9614273aa3
commit cf43f331be
3 changed files with 54 additions and 36 deletions

View File

@ -54,7 +54,7 @@ int pidfile_context_create(TALLOC_CTX *mem_ctx, const char *pidfile,
pid_ctx->pid = getpid();
ret = pidfile_path_create(pid_ctx->pidfile, &fd);
ret = pidfile_path_create(pid_ctx->pidfile, &fd, NULL);
if (ret != 0) {
return ret;
}

View File

@ -27,16 +27,14 @@
#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) {
@ -44,10 +42,11 @@ int pidfile_path_create(const char *path, int *outfd)
}
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,
@ -59,25 +58,41 @@ int pidfile_path_create(const char *path, int *outfd)
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;
@ -92,17 +107,25 @@ int pidfile_path_create(const char *path, int *outfd)
} 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;
}
@ -185,24 +208,17 @@ void pidfile_create(const char *piddir, const char *name)
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... */
}

View File

@ -29,15 +29,17 @@
/**
* @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