file-dotlock.c revision 4ea21f54bb97c0204539760f74eb08323ecde63a
45312f52ff3a3d4c137447be4c7556500c2f8bf2Timo Sirainen/* Copyright (C) 2003 Timo Sirainen */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "lib.h"
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen#include "hostpid.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "write-full.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "file-dotlock.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include <stdlib.h>
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include <signal.h>
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include <time.h>
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include <sys/stat.h>
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen/* 0.1 .. 0.2msec */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#define LOCK_RANDOM_USLEEP_TIME (100000 + (unsigned int)rand() % 100000)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstruct lock_info {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen const char *path, *lock_path;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen unsigned int stale_timeout;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen dev_t dev;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen ino_t ino;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen off_t size;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen time_t mtime;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen off_t last_size;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen time_t last_mtime;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen time_t last_change;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen pid_t pid;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen time_t last_pid_check;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen};
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic pid_t read_local_pid(const char *lock_path)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen{
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen char buf[512], *host;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen int fd;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen ssize_t ret;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen fd = open(lock_path, O_RDONLY);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (fd == -1)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return -1; /* ignore the actual error */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* read line */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen ret = read(fd, buf, sizeof(buf)-1);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen (void)close(fd);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (ret <= 0)
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen return -1;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* fix the string */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (buf[ret-1] == '\n')
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen ret--;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen buf[ret] = '\0';
7569ab8537418b7fc369265f26595b0ef9e4cb35Timo Sirainen
7569ab8537418b7fc369265f26595b0ef9e4cb35Timo Sirainen /* it should contain pid:host */
7569ab8537418b7fc369265f26595b0ef9e4cb35Timo Sirainen host = strchr(buf, ':');
7569ab8537418b7fc369265f26595b0ef9e4cb35Timo Sirainen if (host == NULL)
7569ab8537418b7fc369265f26595b0ef9e4cb35Timo Sirainen return -1;
7569ab8537418b7fc369265f26595b0ef9e4cb35Timo Sirainen *host++ = '\0';
7569ab8537418b7fc369265f26595b0ef9e4cb35Timo Sirainen
7569ab8537418b7fc369265f26595b0ef9e4cb35Timo Sirainen /* host must be ours */
7569ab8537418b7fc369265f26595b0ef9e4cb35Timo Sirainen if (strcmp(host, my_hostname) != 0)
7569ab8537418b7fc369265f26595b0ef9e4cb35Timo Sirainen return -1;
7569ab8537418b7fc369265f26595b0ef9e4cb35Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (!is_numeric(buf, '\0'))
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return -1;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return (pid_t)strtoul(buf, NULL, 0);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen}
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
798cfe56c9871262770384da1239162b3800cce1Timo Sirainenstatic int check_lock(time_t now, struct lock_info *lock_info)
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen{
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen struct stat st;
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen if (lstat(lock_info->lock_path, &st) < 0) {
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen if (errno != ENOENT) {
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen i_error("lstat(%s) failed: %m", lock_info->lock_path);
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen return -1;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen }
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return 1;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen }
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen if (lock_info->ino != st.st_ino ||
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen !CMP_DEV_T(lock_info->dev, st.st_dev) ||
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen lock_info->mtime != st.st_mtime ||
47bb4a7615c85f212f061499f04f121d6d625387Timo Sirainen lock_info->size != st.st_size) {
47bb4a7615c85f212f061499f04f121d6d625387Timo Sirainen /* either our first check or someone else got the lock file.
47bb4a7615c85f212f061499f04f121d6d625387Timo Sirainen check if it contains a pid whose existence we can verify */
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen lock_info->dev = st.st_dev;
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen lock_info->ino = st.st_ino;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen lock_info->mtime = st.st_mtime;
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen lock_info->size = st.st_size;
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen lock_info->pid = read_local_pid(lock_info->lock_path);
fc8d5f0ac909cca77840538e8beef98a8d40c21cTimo Sirainen
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen lock_info->last_change = now;
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen }
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen if (lock_info->pid != -1) {
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen /* we've local PID. Check if it exists. */
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen if (lock_info->last_pid_check == now)
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen return 0;
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen if (kill(lock_info->pid, 0) == 0 || errno != ESRCH)
fc8d5f0ac909cca77840538e8beef98a8d40c21cTimo Sirainen return 0;
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen
fc8d5f0ac909cca77840538e8beef98a8d40c21cTimo Sirainen /* doesn't exist - go ahead and delete */
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen if (unlink(lock_info->lock_path) < 0 && errno != ENOENT) {
fc8d5f0ac909cca77840538e8beef98a8d40c21cTimo Sirainen i_error("unlink(%s) failed: %m", lock_info->lock_path);
33dd58ab84a020c4f061d2f6031eb6d4c168df1bTimo Sirainen return -1;
33dd58ab84a020c4f061d2f6031eb6d4c168df1bTimo Sirainen }
33dd58ab84a020c4f061d2f6031eb6d4c168df1bTimo Sirainen return 1;
33dd58ab84a020c4f061d2f6031eb6d4c168df1bTimo Sirainen }
33dd58ab84a020c4f061d2f6031eb6d4c168df1bTimo Sirainen
5d4855d7b4dcffb6975ed8e3c9c376dac74e5c8aTimo Sirainen /* see if the file we're locking is being modified */
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen if (stat(lock_info->path, &st) < 0) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (errno == ENOENT) {
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen /* file doesn't exist. treat it as if
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen it hasn't changed */
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen } else {
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen i_error("stat(%s) failed: %m", lock_info->path);
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen return -1;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen }
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen } else if (lock_info->last_size != st.st_size ||
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen lock_info->last_mtime != st.st_mtime) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen lock_info->last_change = now;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen lock_info->last_size = st.st_size;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen lock_info->last_mtime = st.st_mtime;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen }
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen if (now > lock_info->last_change + (time_t)lock_info->stale_timeout) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* no changes for a while, assume stale lock */
8eb94c5190ba09bb6f6f068eec7bf96750f08d1dTimo Sirainen if (unlink(lock_info->lock_path) < 0 && errno != ENOENT) {
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen i_error("unlink(%s) failed: %m", lock_info->lock_path);
8eb94c5190ba09bb6f6f068eec7bf96750f08d1dTimo Sirainen return -1;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen }
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen return 1;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen }
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen return 0;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen}
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic int try_create_lock(const char *lock_path, struct dotlock *dotlock_r)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen{
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen const char *str;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen struct stat st;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen int fd;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen fd = open(lock_path, O_WRONLY | O_EXCL | O_CREAT, 0644);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (fd == -1)
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen return -1;
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen /* got it, save the inode info */
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen if (fstat(fd, &st) < 0) {
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen i_error("fstat(%s) failed: %m", lock_path);
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen (void)close(fd);
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen return -1;
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen }
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen dotlock_r->dev = st.st_dev;
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen dotlock_r->ino = st.st_ino;
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen dotlock_r->mtime = st.st_mtime;
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen /* write our pid and host, if possible */
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen str = t_strdup_printf("%s:%s", my_pid, my_hostname);
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen if (write_full(fd, str, strlen(str)) < 0) {
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen /* failed, leave it empty then */
8eb94c5190ba09bb6f6f068eec7bf96750f08d1dTimo Sirainen if (ftruncate(fd, 0) < 0) {
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen i_error("ftruncate(%s) failed: %m", lock_path);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen (void)unlink(lock_path);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen (void)close(fd);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen return -1;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen }
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen }
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen
b321df9603081896b70ec44635af96d674a9839aTimo Sirainen if (close(fd) < 0) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen i_error("close(%s) failed: %m", lock_path);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen (void)unlink(lock_path);
f968e62caa52a8924bd05ebf76ff515b5c18e17bTimo Sirainen return -1;
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen }
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen return 1;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen}
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenint file_lock_dotlock(const char *path, int checkonly,
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen unsigned int timeout, unsigned int stale_timeout,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen int (*callback)(unsigned int secs_left, int stale,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen void *context),
47bb4a7615c85f212f061499f04f121d6d625387Timo Sirainen void *context, struct dotlock *dotlock_r)
47bb4a7615c85f212f061499f04f121d6d625387Timo Sirainen{
47bb4a7615c85f212f061499f04f121d6d625387Timo Sirainen const char *lock_path;
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen struct lock_info lock_info;
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen unsigned int stale_notify_threshold;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen time_t now, max_wait_time, last_notify;
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen now = time(NULL);
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen lock_path = t_strconcat(path, ".lock", NULL);
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen stale_notify_threshold = stale_timeout / 2;
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen max_wait_time = now + timeout;
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen /* There's two ways to do this:
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen a) Rely on O_EXCL. Historically this hasn't always worked with NFS.
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen b) Create temp file and link() it to the file we want.
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen We now use a). It's easier to do and it never leaves temporary files
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen lying around. Also Postfix relies on it too, so I guess it's safe
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen enough nowadays.
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen */
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen
4376643cd2c7110e752c09f838f2c4eee6ed8ac6Timo Sirainen memset(&lock_info, 0, sizeof(lock_info));
938835576b218f6bb9498d829cef9514f8609c6fTimo Sirainen lock_info.path = path;
938835576b218f6bb9498d829cef9514f8609c6fTimo Sirainen lock_info.lock_path = lock_path;
938835576b218f6bb9498d829cef9514f8609c6fTimo Sirainen lock_info.stale_timeout = stale_timeout;
938835576b218f6bb9498d829cef9514f8609c6fTimo Sirainen lock_info.last_change = now;
938835576b218f6bb9498d829cef9514f8609c6fTimo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen last_notify = 0;
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen do {
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen switch (check_lock(now, &lock_info)) {
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen case -1:
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen return -1;
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen case 0:
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen if (last_notify != now && callback != NULL) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen unsigned int change_secs;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen unsigned int wait_left;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen last_notify = now;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen change_secs = now - lock_info.last_change;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen wait_left = max_wait_time - now;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (change_secs >= stale_notify_threshold &&
a8e132559a7ebe54c8269d79ce29fa3338c76199Timo Sirainen change_secs <= wait_left) {
e2a700d0628e395d64cbcef4b5b4510816bf51c4Timo Sirainen if (!callback(stale_timeout -
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen change_secs,
e2a700d0628e395d64cbcef4b5b4510816bf51c4Timo Sirainen TRUE, context)) {
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen /* we don't want to override */
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen lock_info.last_change = now;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen }
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen } else {
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen (void)callback(wait_left, FALSE,
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen context);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen }
a8e132559a7ebe54c8269d79ce29fa3338c76199Timo Sirainen }
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen usleep(LOCK_RANDOM_USLEEP_TIME);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen break;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen default:
a8e132559a7ebe54c8269d79ce29fa3338c76199Timo Sirainen if (checkonly ||
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen try_create_lock(lock_path, dotlock_r) > 0)
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen return 1;
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen if (errno != EEXIST) {
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen i_error("open(%s) failed: %m", lock_path);
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen return -1;
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen }
e2a700d0628e395d64cbcef4b5b4510816bf51c4Timo Sirainen break;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen }
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen
e2a700d0628e395d64cbcef4b5b4510816bf51c4Timo Sirainen now = time(NULL);
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen } while (now < max_wait_time);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen errno = EAGAIN;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen return 0;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen}
43358fffb1d9f3091fd94895e0ac4643c50e2388Timo Sirainen
43358fffb1d9f3091fd94895e0ac4643c50e2388Timo Sirainenint file_unlock_dotlock(const char *path, const struct dotlock *dotlock)
43358fffb1d9f3091fd94895e0ac4643c50e2388Timo Sirainen{
43358fffb1d9f3091fd94895e0ac4643c50e2388Timo Sirainen const char *lock_path;
43358fffb1d9f3091fd94895e0ac4643c50e2388Timo Sirainen struct stat st;
43358fffb1d9f3091fd94895e0ac4643c50e2388Timo Sirainen
430c0b0c370bebeeceba2e206be76bc134742f41Timo Sirainen lock_path = t_strconcat(path, ".lock", NULL);
25ee72451d16374ed27fdbf829f4ec756c778352Timo Sirainen
a3dd97fb6d92a89c3de0597fed2d4b044c7aeb84Timo Sirainen if (lstat(lock_path, &st) < 0) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (errno == ENOENT) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen i_warning("Our dotlock file %s was deleted", lock_path);
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen return 0;
484e12acec34f16e5a8adc001e23ae48f1dda8c7Timo Sirainen }
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen i_error("lstat(%s) failed: %m", lock_path);
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen return -1;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen }
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen if (dotlock->ino != st.st_ino ||
484e12acec34f16e5a8adc001e23ae48f1dda8c7Timo Sirainen !CMP_DEV_T(dotlock->dev, st.st_dev)) {
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen i_warning("Our dotlock file %s was overridden", lock_path);
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen return 0;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen }
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen if (dotlock->mtime != st.st_mtime) {
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen i_warning("Our dotlock file %s was modified (%s vs %s), "
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen "assuming it wasn't overridden", lock_path,
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen dec2str(dotlock->mtime), dec2str(st.st_mtime));
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen }
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen if (unlink(lock_path) < 0) {
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen if (errno == ENOENT) {
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen i_warning("Our dotlock file %s was deleted", lock_path);
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen return 0;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen }
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen i_error("unlink(%s) failed: %m", lock_path);
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen return -1;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen }
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen return 1;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen}
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen