mbox-lock.c revision 35077ff71c0082c1370d9c296abce3153f645958
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen/* Copyright (c) 2002-2009 Dovecot authors, see the included COPYING file */
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen/* 0.1 .. 0.2msec */
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen#define LOCK_RANDOM_USLEEP_TIME (100000 + (unsigned int)rand() % 100000)
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen/* lock methods to use in wanted order */
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen#define DEFAULT_WRITE_LOCK_METHODS "dotlock fcntl"
dac0b2e5e0f38c6d95ef1a842d891480db580236Timo Sirainen/* lock timeout */
797de45dcf6e24642ab347d5033beb92034b779dTimo Sirainen/* assume stale dotlock if mbox file hasn't changed for n seconds */
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen int (*func)(struct mbox_lock_context *ctx, int lock_type,
8d59f06c9422fa49b538e23ffb06eddb23c6add2Timo Sirainenstatic int mbox_lock_dotlock(struct mbox_lock_context *ctx, int lock_type,
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainenstatic int mbox_lock_dotlock_try(struct mbox_lock_context *ctx, int lock_type,
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainenstatic int mbox_lock_fcntl(struct mbox_lock_context *ctx, int lock_type,
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainenstatic int mbox_lock_flock(struct mbox_lock_context *ctx, int lock_type,
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainenstatic int mbox_lock_lockf(struct mbox_lock_context *ctx, int lock_type,
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen { MBOX_LOCK_DOTLOCK, "dotlock", mbox_lock_dotlock },
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen { MBOX_LOCK_DOTLOCK_TRY, "dotlock_try", mbox_lock_dotlock_try },
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen { MBOX_LOCK_FCNTL, "fcntl", mbox_lock_fcntl },
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen { MBOX_LOCK_FLOCK, "flock", mbox_lock_flock },
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen { MBOX_LOCK_LOCKF, "lockf", mbox_lock_lockf },
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainenstatic enum mbox_lock_type read_locks[MBOX_LOCK_COUNT+1];
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainenstatic enum mbox_lock_type write_locks[MBOX_LOCK_COUNT+1];
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainenstatic int lock_timeout, dotlock_change_timeout;
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainenstatic int mbox_lock_list(struct mbox_lock_context *ctx, int lock_type,
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainenstatic int mbox_unlock_files(struct mbox_lock_context *ctx);
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainenstatic void mbox_read_lock_methods(const char *str, const char *env,
08f24237ccc177f5b3a09b24d8a725fa47e1ee32Timo Sirainen const char *const *lock;
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen for (lock = t_strsplit(str, " "), dest = 0; *lock != NULL; lock++) {
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen for (type = 0; lock_data[type].name != NULL; type++) {
debb28d107fa06d26fd194fdac523cfb32809199Timo Sirainen if (strcasecmp(*lock, lock_data[type].name) == 0) {
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen for (i = 0; i < dest; i++) {
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen i_fatal("%s: Duplicated value %s", env, *lock);
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen /* @UNSAFE */
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen const char *str;
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen if (str == NULL) str = DEFAULT_READ_LOCK_METHODS;
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen mbox_read_lock_methods(str, "MBOX_READ_LOCKS", read_locks);
745f2c7424d88e368eff0a3a7650b352a9d1f0ddTimo Sirainen if (str == NULL) str = DEFAULT_WRITE_LOCK_METHODS;
745f2c7424d88e368eff0a3a7650b352a9d1f0ddTimo Sirainen mbox_read_lock_methods(str, "MBOX_WRITE_LOCKS", write_locks);
745f2c7424d88e368eff0a3a7650b352a9d1f0ddTimo Sirainen /* check that read/write list orders match. write_locks must contain
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen at least read_locks and possibly more. */
745f2c7424d88e368eff0a3a7650b352a9d1f0ddTimo Sirainen for (r = w = 0; write_locks[w] != (enum mbox_lock_type)-1; w++) {
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen if (read_locks[r] != (enum mbox_lock_type)-1) {
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen i_fatal("mbox read/write lock list settings are invalid. "
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen "Lock ordering must be the same with both, "
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen "and write locks must contain all read locks "
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen "(and possibly more)");
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen lock_timeout = str == NULL ? MBOX_DEFAULT_LOCK_TIMEOUT : atoi(str);
dba5754de32284b3149ddd5c9bb1701b05707752Timo Sirainenstatic int mbox_file_open_latest(struct mbox_lock_context *ctx, int lock_type)
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen if (ctx->checked_file || lock_type == F_UNLCK)
eff0f02f2c8320c1bd4df72a281a92051d78b2b1Timo Sirainen /* we could flush NFS file handle cache here if we wanted to
eff0f02f2c8320c1bd4df72a281a92051d78b2b1Timo Sirainen be sure that the file is latest, but mbox files get rarely
eff0f02f2c8320c1bd4df72a281a92051d78b2b1Timo Sirainen deleted and the flushing might cause errors (e.g. EBUSY for
eff0f02f2c8320c1bd4df72a281a92051d78b2b1Timo Sirainen trying to flush a /var/mail mountpoint) */
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainenstatic bool dotlock_callback(unsigned int secs_left, bool stale, void *context)
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen /* get next index we wish to try locking. it's the one after
b9a13c136b7c5803a8271878fcbbf5328f6e7f2aTimo Sirainen dotlocking. */
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen for (i = 0; lock_types[i] != (enum mbox_lock_type)-1; i++) {
return FALSE;
if (restrict_access_use_priv_gid() < 0) {
return FALSE;
return TRUE;
fname++;
if (restrict_access_use_priv_gid() < 0) {
switch (op) {
case MBOX_DOTLOCK_OP_LOCK:
if (ret > 0)
case MBOX_DOTLOCK_OP_UNLOCK:
case MBOX_DOTLOCK_OP_TOUCH:
return ret;
int ret;
if (ret <= 0) {
if (ret < 0) {
if (ret == 0) {
#ifdef HAVE_FLOCK
unsigned int next_alarm;
if (max_wait_time == 0) {
last_notify = 0;
alarm(0);
alarm(0);
if (next_alarm == 0)
alarm(0);
#ifdef HAVE_LOCKF
unsigned int next_alarm;
else if (max_wait_time == 0) {
last_notify = 0;
max_wait_time == 0) {
alarm(0);
alarm(0);
if (next_alarm == 0)
alarm(0);
unsigned int next_alarm;
int wait_type;
if (max_wait_time == 0) {
alarm(0);
alarm(0);
if (next_alarm == 0)
alarm(0);
if (ret <= 0)
return ret;
bool *fcntl_locked_r)
int ret, i;
bool drop_locks;
for (i = 0; i < MBOX_LOCK_COUNT; i++)
if (ret <= 0) {
if (!drop_locks)
if (ret == 0) {
return ret;
if (drop_locks) {
unsigned int *lock_id_r)
bool fcntl_locked;
int ret;
if (ret <= 0)
return ret;
MAIL_STORAGE_FLAG_NFS_FLUSH_STORAGE) != 0) {
if (fcntl_locked) {
int ret = 0;
return ret;
bool fcntl_locked;
&fcntl_locked) < 0)
for (i = 0; i < MBOX_LOCK_COUNT; i++)