/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "istream.h"
#include "file-lock.h"
#include "file-dotlock.h"
#include "time-util.h"
#include <time.h>
#ifdef HAVE_FLOCK
#endif
struct file_lock {
int fd;
char *path;
int lock_type;
bool unlink_on_free;
bool close_on_free;
};
{
else
return FALSE;
return TRUE;
}
{
switch (method) {
case FILE_LOCK_METHOD_FCNTL:
return "fcntl";
case FILE_LOCK_METHOD_FLOCK:
return "flock";
case FILE_LOCK_METHOD_DOTLOCK:
return "dotlock";
}
i_unreached();
}
enum file_lock_method lock_method,
{
}
enum file_lock_method lock_method,
{
}
static const char *
{
return "";
return t_strdup_printf(" (%s lock held by pid %ld)",
}
static const char *
{
/* do anything except Linux support this? don't bother trying it for
OSes we don't know about. */
#ifdef __linux__
int fd;
if (!have_proc_locks)
return NULL;
return "";
if (fd == -1) {
return "";
}
major:minor:inode region-start region-end */
; /* don't continue from within a T_BEGIN {...} T_END */
"READ" : "WRITE";
pid = 0;
}
} T_END;
if (pid == 0) {
/* not found */
return "";
}
return " (BUG: lock is held by our own process)";
#else
return "";
#endif
}
int lock_type)
{
const char *ret;
if (lock_method == FILE_LOCK_METHOD_FCNTL) {
if (ret[0] != '\0')
return ret;
}
return file_lock_find_proc_locks(lock_fd);
}
{
/* if EINTR took at least timeout_secs-1 number of seconds,
assume it was the alarm. otherwise log EINTR failure.
(We most likely don't want to retry EINTR since a signal
means somebody wants us to stop blocking). */
}
enum file_lock_method lock_method,
unsigned int timeout_secs, const char **error_r)
{
const char *lock_type_str;
int ret;
if (timeout_secs != 0) {
}
switch (lock_method) {
case FILE_LOCK_METHOD_FCNTL: {
#ifndef HAVE_FCNTL
"Can't lock file %s: fcntl() locks not supported", path);
return -1;
#else
if (timeout_secs != 0) {
alarm(0);
}
if (ret == 0)
break;
if (timeout_secs == 0 &&
/* locked by another process */
"fcntl(%s, %s, F_SETLK) locking failed: %m "
return 0;
}
"fcntl(%s, %s, F_SETLKW) locking failed: "
"Timed out after %u seconds%s",
return 0;
}
return -1;
#endif
}
case FILE_LOCK_METHOD_FLOCK: {
#ifndef HAVE_FLOCK
"Can't lock file %s: flock() not supported", path);
return -1;
#else
switch (lock_type) {
case F_RDLCK:
break;
case F_WRLCK:
break;
case F_UNLCK:
break;
}
if (timeout_secs != 0) {
alarm(0);
}
if (ret == 0)
break;
/* locked by another process */
"flock(%s, %s) failed: %m "
return 0;
}
"Timed out after %u seconds%s",
return 0;
}
return -1;
#endif
}
case FILE_LOCK_METHOD_DOTLOCK:
/* we shouldn't get here */
i_unreached();
}
return 1;
}
enum file_lock_method lock_method,
unsigned int timeout_secs,
{
const char *error;
int ret;
if (ret < 0)
return ret;
}
enum file_lock_method lock_method,
unsigned int timeout_secs,
{
int ret;
if (ret <= 0)
return ret;
i_fatal("gettimeofday() failed: %m");
return 1;
}
{
const char *error;
int ret;
if (ret <= 0)
return ret;
return 1;
}
{
}
{
}
{
i_fatal("gettimeofday() failed: %m");
return lock;
}
{
const char *error;
/* this shouldn't happen */
}
}
{
/* unlocking is unnecessary when the file is unlinked. or alternatively
the unlink() must be done before unlocking, because otherwise it
could be deleting the new lock. */
}
{
const char *error;
int ret;
if (ret < 0) {
i_error("file_lock_free(): Unexpectedly failed to retry locking %s: %s",
} else if (ret == 0) {
/* already locked by someone else */
/* not expected to happen */
/* lock file was recreated already - don't delete it */
} else {
/* nobody was waiting on the lock - unlink it */
}
}
{
return;
if (lock->unlink_on_free)
if (lock->close_on_free)
}
{
}
{
}
}
void file_lock_wait_start(void)
{
i_fatal("gettimeofday() failed: %m");
}
static void file_lock_wait_init_warning(void)
{
const char *value;
file_lock_slow_warning_usecs > 0) {
file_lock_slow_warning_usecs *= 1000;
} else {
i_error("FILE_LOCK_SLOW_WARNING_MSECS: "
"Invalid value '%s' - ignoring", value);
}
}
{
if (file_lock_slow_warning_usecs < 0)
if (file_lock_slow_warning_usecs == LLONG_MAX) {
/* slowness checking is disabled */
return;
}
/* some shared locks can legitimately be kept for a long time.
don't warn about them. */
return;
}
i_fatal("gettimeofday() failed: %m");
}
}
{
i_fatal("gettimeofday() failed: %m");
if (diff > file_lock_slow_warning_usecs) {
if (file_lock_slow_warning_usecs < 0)
if (diff > file_lock_slow_warning_usecs) {
}
}
lock_wait_start.tv_sec = 0;
}
{
return file_lock_wait_usecs;
}