mbox-lock.c revision 62461eb609e1d852e027cf4e07d30d51288678a2
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2002-2017 Dovecot authors, see the included COPYING file */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen#include "lib.h"
46552a931924c2d743f045e95b08c3ce6beda91aTimo Sirainen#include "eacces-error.h"
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen#include "restrict-access.h"
c5f932968281763df360b9c97cef60f5f80d5e3dTimo Sirainen#include "nfs-workarounds.h"
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include "ipwd.h"
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include "mail-index-private.h"
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include "mbox-storage.h"
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include "istream-raw-mbox.h"
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen#include "mbox-file.h"
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include "mbox-lock.h"
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
de754cb78f75e8b3b994cddafe41c9ed1467c33dTimo Sirainen#include <time.h>
f29756821a4c6b12b73e4a2a3e1c230117a43773Timo Sirainen#include <unistd.h>
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include <fcntl.h>
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include <sys/stat.h>
53dfcefa9440a49d703e49193819a79be99c9ba6Timo Sirainen
f0d93763f210ecdb85a115fdd0210a16cfc5ff5cTimo Sirainen#ifdef HAVE_FLOCK
53dfcefa9440a49d703e49193819a79be99c9ba6Timo Sirainen# include <sys/file.h>
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#endif
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen/* 0.1 .. 0.2msec */
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen#define LOCK_RANDOM_USLEEP_TIME (100000 + (unsigned int)i_rand() % 100000)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainenenum mbox_lock_type {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen MBOX_LOCK_DOTLOCK,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen MBOX_LOCK_DOTLOCK_TRY,
2e78f05b11df23ec2731afaf8f19d5b5240cb29fTimo Sirainen MBOX_LOCK_FCNTL,
2e78f05b11df23ec2731afaf8f19d5b5240cb29fTimo Sirainen MBOX_LOCK_FLOCK,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen MBOX_LOCK_LOCKF,
d1e7425048c61d71f41f737ba947687198842dc2Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen MBOX_LOCK_COUNT
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen};
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenenum mbox_dotlock_op {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen MBOX_DOTLOCK_OP_LOCK,
660b99a7059824676b2b8d6f79b8e15d47df25a2Timo Sirainen MBOX_DOTLOCK_OP_UNLOCK,
660b99a7059824676b2b8d6f79b8e15d47df25a2Timo Sirainen MBOX_DOTLOCK_OP_TOUCH
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen};
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstruct mbox_lock_context {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct mbox_mailbox *mbox;
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen bool locked_status[MBOX_LOCK_COUNT];
b9c76fe9d9ca194816606342da1ddbd9be6bc8abTimo Sirainen bool checked_file;
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen
b9c76fe9d9ca194816606342da1ddbd9be6bc8abTimo Sirainen int lock_type;
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen bool dotlock_last_stale;
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen bool fcntl_locked;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen bool using_privileges;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen};
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstruct mbox_lock_data {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen enum mbox_lock_type type;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const char *name;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen int (*func)(struct mbox_lock_context *ctx, int lock_type,
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen time_t max_wait_time);
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen};
b9c76fe9d9ca194816606342da1ddbd9be6bc8abTimo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic int mbox_lock_dotlock(struct mbox_lock_context *ctx, int lock_type,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen time_t max_wait_time);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic int mbox_lock_dotlock_try(struct mbox_lock_context *ctx, int lock_type,
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen time_t max_wait_time);
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainenstatic int mbox_lock_fcntl(struct mbox_lock_context *ctx, int lock_type,
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen time_t max_wait_time);
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen#ifdef HAVE_FLOCK
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainenstatic int mbox_lock_flock(struct mbox_lock_context *ctx, int lock_type,
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen time_t max_wait_time);
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen#else
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen# define mbox_lock_flock NULL
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen#endif
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen#ifdef HAVE_LOCKF
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainenstatic int mbox_lock_lockf(struct mbox_lock_context *ctx, int lock_type,
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen time_t max_wait_time);
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen#else
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen# define mbox_lock_lockf NULL
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen#endif
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainenstatic struct mbox_lock_data lock_data[] = {
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen { MBOX_LOCK_DOTLOCK, "dotlock", mbox_lock_dotlock },
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen { MBOX_LOCK_DOTLOCK_TRY, "dotlock_try", mbox_lock_dotlock_try },
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen { MBOX_LOCK_FCNTL, "fcntl", mbox_lock_fcntl },
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen { MBOX_LOCK_FLOCK, "flock", mbox_lock_flock },
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen { MBOX_LOCK_LOCKF, "lockf", mbox_lock_lockf },
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen { 0, NULL, NULL }
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen};
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainenstatic int ATTR_NOWARN_UNUSED_RESULT
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainenmbox_lock_list(struct mbox_lock_context *ctx, int lock_type,
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen time_t max_wait_time, int idx);
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainenstatic int ATTR_NOWARN_UNUSED_RESULT
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainenmbox_unlock_files(struct mbox_lock_context *ctx);
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainenstatic void mbox_read_lock_methods(const char *str, const char *env,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen enum mbox_lock_type *locks)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen enum mbox_lock_type type;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const char *const *lock;
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen int i, dest;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen for (lock = t_strsplit(str, " "), dest = 0; *lock != NULL; lock++) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen for (type = 0; lock_data[type].name != NULL; type++) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (strcasecmp(*lock, lock_data[type].name) == 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen type = lock_data[type].type;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen break;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (lock_data[type].name == NULL)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_fatal("%s: Invalid value %s", env, *lock);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (lock_data[type].func == NULL) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_fatal("%s: Support for lock type %s "
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen "not compiled into binary", env, *lock);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen for (i = 0; i < dest; i++) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (locks[i] == type)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_fatal("%s: Duplicated value %s", env, *lock);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* @UNSAFE */
ca843e046e98b12f4730f4b87ee2e1a659c26e78Timo Sirainen locks[dest++] = type;
ca843e046e98b12f4730f4b87ee2e1a659c26e78Timo Sirainen }
ca843e046e98b12f4730f4b87ee2e1a659c26e78Timo Sirainen locks[dest] = (enum mbox_lock_type)-1;
ca843e046e98b12f4730f4b87ee2e1a659c26e78Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic void mbox_init_lock_settings(struct mbox_storage *storage)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen enum mbox_lock_type read_locks[MBOX_LOCK_COUNT+1];
e7dd5065d21c569e5e6ddd713bd345dadd1cf51dTimo Sirainen enum mbox_lock_type write_locks[MBOX_LOCK_COUNT+1];
e7dd5065d21c569e5e6ddd713bd345dadd1cf51dTimo Sirainen int r, w;
d694a52bce62c52080c3f87a56dcf77030fd2712Timo Sirainen
d694a52bce62c52080c3f87a56dcf77030fd2712Timo Sirainen mbox_read_lock_methods(storage->set->mbox_read_locks,
009217abb57a24a4076092e8e4e165545747839eStephan Bosch "mbox_read_locks", read_locks);
009217abb57a24a4076092e8e4e165545747839eStephan Bosch mbox_read_lock_methods(storage->set->mbox_write_locks,
009217abb57a24a4076092e8e4e165545747839eStephan Bosch "mbox_write_locks", write_locks);
009217abb57a24a4076092e8e4e165545747839eStephan Bosch
009217abb57a24a4076092e8e4e165545747839eStephan Bosch /* check that read/write list orders match. write_locks must contain
009217abb57a24a4076092e8e4e165545747839eStephan Bosch at least read_locks and possibly more. */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen for (r = w = 0; write_locks[w] != (enum mbox_lock_type)-1; w++) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (read_locks[r] == (enum mbox_lock_type)-1)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen break;
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch if (read_locks[r] == write_locks[w])
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch r++;
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch }
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch if (read_locks[r] != (enum mbox_lock_type)-1) {
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch i_fatal("mbox read/write lock list settings are invalid. "
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch "Lock ordering must be the same with both, "
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch "and write locks must contain all read locks "
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch "(and possibly more)");
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch }
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch storage->read_locks = p_new(storage->storage.pool,
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch enum mbox_lock_type, MBOX_LOCK_COUNT+1);
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen memcpy(storage->read_locks, read_locks,
ab281fc992907b6cf6c730f672dc3aa4c6685015Timo Sirainen sizeof(*storage->read_locks) * (MBOX_LOCK_COUNT+1));
ab281fc992907b6cf6c730f672dc3aa4c6685015Timo Sirainen
6d24551e169c0808695db35d7a228f1970a84c75Timo Sirainen storage->write_locks = p_new(storage->storage.pool,
6d24551e169c0808695db35d7a228f1970a84c75Timo Sirainen enum mbox_lock_type, MBOX_LOCK_COUNT+1);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen memcpy(storage->write_locks, write_locks,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen sizeof(*storage->write_locks) * (MBOX_LOCK_COUNT+1));
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
1bf5c6c20f3d51f13d3240cfb46e471074c86276Timo Sirainen storage->lock_settings_initialized = TRUE;
1bf5c6c20f3d51f13d3240cfb46e471074c86276Timo Sirainen}
1bf5c6c20f3d51f13d3240cfb46e471074c86276Timo Sirainen
1bf5c6c20f3d51f13d3240cfb46e471074c86276Timo Sirainenstatic int mbox_file_open_latest(struct mbox_lock_context *ctx, int lock_type)
5a250816ffc4cc5db203f9410ea99b6601c7b91aTimo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct mbox_mailbox *mbox = ctx->mbox;
1bf5c6c20f3d51f13d3240cfb46e471074c86276Timo Sirainen struct stat st;
1bf5c6c20f3d51f13d3240cfb46e471074c86276Timo Sirainen
1bf5c6c20f3d51f13d3240cfb46e471074c86276Timo Sirainen if (ctx->checked_file || lock_type == F_UNLCK)
1bf5c6c20f3d51f13d3240cfb46e471074c86276Timo Sirainen return 0;
8ce3071e80b9973230048ecadfcb073fb82cc69fTimo Sirainen
8ce3071e80b9973230048ecadfcb073fb82cc69fTimo Sirainen if (mbox->mbox_fd != -1) {
8ce3071e80b9973230048ecadfcb073fb82cc69fTimo Sirainen /* we could flush NFS file handle cache here if we wanted to
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen be sure that the file is latest, but mbox files get rarely
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen deleted and the flushing might cause errors (e.g. EBUSY for
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen trying to flush a /var/mail mountpoint) */
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen if (nfs_safe_stat(mailbox_get_path(&mbox->box), &st) < 0) {
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen if (errno == ENOENT)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mailbox_set_deleted(&mbox->box);
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk else
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mbox_set_syscall_error(mbox, "stat()");
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen return -1;
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen }
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen if (st.st_ino != mbox->mbox_ino ||
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen !CMP_DEV_T(st.st_dev, mbox->mbox_dev))
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen mbox_file_close(mbox);
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen }
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen if (mbox->mbox_fd == -1) {
2e2a1d720ed53490e8e5c5031e773d395bd5683dTimo Sirainen if (mbox_file_open(mbox) < 0)
5a250816ffc4cc5db203f9410ea99b6601c7b91aTimo Sirainen return -1;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen ctx->checked_file = TRUE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return 0;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic bool dotlock_callback(unsigned int secs_left, bool stale, void *context)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct mbox_lock_context *ctx = context;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen enum mbox_lock_type *lock_types;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen int i;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (ctx->using_privileges)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen restrict_access_drop_priv_gid();
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (stale && !ctx->dotlock_last_stale) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* get next index we wish to try locking. it's the one after
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen dotlocking. */
b8afdaa1bffe2f27cd4b02bf3bfbd2d297c8e648Timo Sirainen lock_types = ctx->lock_type == F_WRLCK ||
b8afdaa1bffe2f27cd4b02bf3bfbd2d297c8e648Timo Sirainen (ctx->lock_type == F_UNLCK &&
b8afdaa1bffe2f27cd4b02bf3bfbd2d297c8e648Timo Sirainen ctx->mbox->mbox_lock_type == F_WRLCK) ?
b8afdaa1bffe2f27cd4b02bf3bfbd2d297c8e648Timo Sirainen ctx->mbox->storage->write_locks :
b8afdaa1bffe2f27cd4b02bf3bfbd2d297c8e648Timo Sirainen ctx->mbox->storage->read_locks;
b8afdaa1bffe2f27cd4b02bf3bfbd2d297c8e648Timo Sirainen
b8afdaa1bffe2f27cd4b02bf3bfbd2d297c8e648Timo Sirainen for (i = 0; lock_types[i] != (enum mbox_lock_type)-1; i++) {
b8afdaa1bffe2f27cd4b02bf3bfbd2d297c8e648Timo Sirainen if (lock_types[i] == MBOX_LOCK_DOTLOCK)
b8afdaa1bffe2f27cd4b02bf3bfbd2d297c8e648Timo Sirainen break;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (lock_types[i] != (enum mbox_lock_type)-1 &&
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen lock_types[i+1] != (enum mbox_lock_type)-1) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i++;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (mbox_lock_list(ctx, ctx->lock_type, 0, i) <= 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* we couldn't get fd lock -
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen it's really locked */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen ctx->dotlock_last_stale = TRUE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return FALSE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mbox_lock_list(ctx, F_UNLCK, 0, i);
ec23e16ed879e289d12c6e1a5f9745dd3979004aTimo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen ctx->dotlock_last_stale = stale;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen index_storage_lock_notify(&ctx->mbox->box, stale ?
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen MAILBOX_LOCK_NOTIFY_MAILBOX_OVERRIDE :
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen MAILBOX_LOCK_NOTIFY_MAILBOX_ABORT,
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen secs_left);
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen if (ctx->using_privileges) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (restrict_access_use_priv_gid() < 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* shouldn't get here */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return FALSE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return TRUE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic int ATTR_NULL(2) ATTR_NOWARN_UNUSED_RESULT
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenmbox_dotlock_privileged_op(struct mbox_mailbox *mbox,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct dotlock_settings *set,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen enum mbox_dotlock_op op)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const char *box_path, *dir, *fname;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen int ret = -1, orig_dir_fd, orig_errno;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen orig_dir_fd = open(".", O_RDONLY);
cbaac1e9a69099a2c25e09b1db19bcbf9037e342Timo Sirainen if (orig_dir_fd == -1) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mail_storage_set_critical(&mbox->storage->storage,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen "open(.) failed: %m");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return -1;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen /* allow dotlocks to be created only for files we can read while we're
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen unprivileged. to make sure there are no race conditions we first
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen have to chdir to the mbox file's directory and then use relative
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen paths. unless this is done, users could:
de754cb78f75e8b3b994cddafe41c9ed1467c33dTimo Sirainen - create *.lock files to any directory writable by the
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen privileged group
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen - DoS other users by dotlocking their mailboxes infinitely
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen box_path = mailbox_get_path(&mbox->box);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen fname = strrchr(box_path, '/');
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (fname == NULL) {
660b99a7059824676b2b8d6f79b8e15d47df25a2Timo Sirainen /* already relative */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen fname = box_path;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen } else {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen dir = t_strdup_until(box_path, fname);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (chdir(dir) < 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mail_storage_set_critical(&mbox->storage->storage,
e911b23f3e05308df9b98b1a3fdaf72e4302d8fdTimo Sirainen "chdir(%s) failed: %m", dir);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_close_fd(&orig_dir_fd);
77f1da4b5e2b800197d8db548235497d5e9d6a4fTimo Sirainen return -1;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen fname++;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (op == MBOX_DOTLOCK_OP_LOCK) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (access(fname, R_OK) < 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mail_storage_set_critical(&mbox->storage->storage,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen "access(%s) failed: %m", box_path);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_close_fd(&orig_dir_fd);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return -1;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (restrict_access_use_priv_gid() < 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_close_fd(&orig_dir_fd);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return -1;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen switch (op) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen case MBOX_DOTLOCK_OP_LOCK:
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* we're now privileged - avoid doing as much as possible */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen ret = file_dotlock_create(set, fname, 0, &mbox->mbox_dotlock);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (ret > 0)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mbox->mbox_used_privileges = TRUE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen else if (ret < 0 && errno == EACCES) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const char *errmsg =
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen eacces_error_get_creating("file_dotlock_create",
18f1bbf05980d3c53ecae81b62574212f0891522Timo Sirainen fname);
77f1da4b5e2b800197d8db548235497d5e9d6a4fTimo Sirainen mail_storage_set_critical(&mbox->storage->storage,
75e46142d8fbac811df8f2ca58d9a2f48a75d65fTimo Sirainen "%s", errmsg);
77f1da4b5e2b800197d8db548235497d5e9d6a4fTimo Sirainen } else {
18f1bbf05980d3c53ecae81b62574212f0891522Timo Sirainen mbox_set_syscall_error(mbox, "file_dotlock_create()");
75e46142d8fbac811df8f2ca58d9a2f48a75d65fTimo Sirainen }
75e46142d8fbac811df8f2ca58d9a2f48a75d65fTimo Sirainen break;
c5f932968281763df360b9c97cef60f5f80d5e3dTimo Sirainen case MBOX_DOTLOCK_OP_UNLOCK:
18f1bbf05980d3c53ecae81b62574212f0891522Timo Sirainen /* we're now privileged - avoid doing as much as possible */
18f1bbf05980d3c53ecae81b62574212f0891522Timo Sirainen ret = file_dotlock_delete(&mbox->mbox_dotlock);
18f1bbf05980d3c53ecae81b62574212f0891522Timo Sirainen if (ret < 0)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mbox_set_syscall_error(mbox, "file_dotlock_delete()");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mbox->mbox_used_privileges = FALSE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen break;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen case MBOX_DOTLOCK_OP_TOUCH:
e911b23f3e05308df9b98b1a3fdaf72e4302d8fdTimo Sirainen ret = file_dotlock_touch(mbox->mbox_dotlock);
e911b23f3e05308df9b98b1a3fdaf72e4302d8fdTimo Sirainen if (ret < 0)
e911b23f3e05308df9b98b1a3fdaf72e4302d8fdTimo Sirainen mbox_set_syscall_error(mbox, "file_dotlock_touch()");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen break;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen orig_errno = errno;
e911b23f3e05308df9b98b1a3fdaf72e4302d8fdTimo Sirainen restrict_access_drop_priv_gid();
e911b23f3e05308df9b98b1a3fdaf72e4302d8fdTimo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (fchdir(orig_dir_fd) < 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mail_storage_set_critical(&mbox->storage->storage,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen "fchdir() failed: %m");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_close_fd(&orig_dir_fd);
2598b2f36365b52d9754b9348a5be29569293e46Timo Sirainen errno = orig_errno;
de754cb78f75e8b3b994cddafe41c9ed1467c33dTimo Sirainen return ret;
2598b2f36365b52d9754b9348a5be29569293e46Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic void
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainenmbox_dotlock_log_eacces_error(struct mbox_mailbox *mbox, const char *path)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen const char *dir, *errmsg, *name;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct stat st;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct group group;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen int orig_errno = errno;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen errmsg = eacces_error_get_creating("file_dotlock_create", path);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen dir = strrchr(path, '/');
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen dir = dir == NULL ? "." : t_strdup_until(path, dir);
04b7dc631f33bf61f273138c679da9bd0910fb6dTimo Sirainen /* allow privileged locking for
04b7dc631f33bf61f273138c679da9bd0910fb6dTimo Sirainen a) user's own INBOX,
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen b) another user's shared INBOX, and
04b7dc631f33bf61f273138c679da9bd0910fb6dTimo Sirainen c) anything called INBOX (in inbox=no namespace) */
04b7dc631f33bf61f273138c679da9bd0910fb6dTimo Sirainen if (!mbox->box.inbox_any && strcmp(mbox->box.name, "INBOX") != 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mail_storage_set_critical(&mbox->storage->storage,
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen "%s (not INBOX -> no privileged locking)", errmsg);
de754cb78f75e8b3b994cddafe41c9ed1467c33dTimo Sirainen } else if (!mbox->mbox_privileged_locking) {
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen dir = mailbox_list_get_root_forced(mbox->box.list,
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen MAILBOX_LIST_PATH_TYPE_DIR);
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen mail_storage_set_critical(&mbox->storage->storage,
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen "%s (under root dir %s -> no privileged locking)",
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen errmsg, dir);
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen } else if (stat(dir, &st) == 0 &&
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen (st.st_mode & 02) == 0 && /* not world-writable */
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen (st.st_mode & 020) != 0) { /* group-writable */
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen if (i_getgrgid(st.st_gid, &group) <= 0)
de754cb78f75e8b3b994cddafe41c9ed1467c33dTimo Sirainen name = dec2str(st.st_gid);
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen else
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen name = group.gr_name;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mail_storage_set_critical(&mbox->storage->storage,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen "%s (set mail_privileged_group=%s)", errmsg, name);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen } else {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mail_storage_set_critical(&mbox->storage->storage,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen "%s (nonstandard permissions in %s)", errmsg, dir);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen errno = orig_errno;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic int
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainenmbox_lock_dotlock_int(struct mbox_lock_context *ctx, int lock_type, bool try)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct mbox_mailbox *mbox = ctx->mbox;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct dotlock_settings set;
2598b2f36365b52d9754b9348a5be29569293e46Timo Sirainen int ret;
2598b2f36365b52d9754b9348a5be29569293e46Timo Sirainen
e7dd5065d21c569e5e6ddd713bd345dadd1cf51dTimo Sirainen if (lock_type == F_UNLCK) {
e7dd5065d21c569e5e6ddd713bd345dadd1cf51dTimo Sirainen if (!mbox->mbox_dotlocked)
e7dd5065d21c569e5e6ddd713bd345dadd1cf51dTimo Sirainen return 1;
c51644e9e04effbbc9c415cadcfbcb4d9465855cTimo Sirainen
c51644e9e04effbbc9c415cadcfbcb4d9465855cTimo Sirainen if (!mbox->mbox_used_privileges) {
c51644e9e04effbbc9c415cadcfbcb4d9465855cTimo Sirainen if (file_dotlock_delete(&mbox->mbox_dotlock) <= 0) {
c51644e9e04effbbc9c415cadcfbcb4d9465855cTimo Sirainen mbox_set_syscall_error(mbox,
c51644e9e04effbbc9c415cadcfbcb4d9465855cTimo Sirainen "file_dotlock_delete()");
c51644e9e04effbbc9c415cadcfbcb4d9465855cTimo Sirainen }
c51644e9e04effbbc9c415cadcfbcb4d9465855cTimo Sirainen } else {
c51644e9e04effbbc9c415cadcfbcb4d9465855cTimo Sirainen ctx->using_privileges = TRUE;
c51644e9e04effbbc9c415cadcfbcb4d9465855cTimo Sirainen mbox_dotlock_privileged_op(mbox, NULL,
2598b2f36365b52d9754b9348a5be29569293e46Timo Sirainen MBOX_DOTLOCK_OP_UNLOCK);
2598b2f36365b52d9754b9348a5be29569293e46Timo Sirainen ctx->using_privileges = FALSE;
f0d93763f210ecdb85a115fdd0210a16cfc5ff5cTimo Sirainen }
f0d93763f210ecdb85a115fdd0210a16cfc5ff5cTimo Sirainen mbox->mbox_dotlocked = FALSE;
6303191abcb37164f435ccdc56e9dbddf1288851Timo Sirainen return 1;
2598b2f36365b52d9754b9348a5be29569293e46Timo Sirainen }
2598b2f36365b52d9754b9348a5be29569293e46Timo Sirainen
2ef0e8ee48c9683f7bd6698798efa3328e4322d1Timo Sirainen if (mbox->mbox_dotlocked)
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen return 1;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen ctx->dotlock_last_stale = TRUE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen i_zero(&set);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen set.use_excl_lock = mbox->storage->storage.set->dotlock_use_excl;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen set.nfs_flush = mbox->storage->storage.set->mail_nfs_storage;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen set.timeout = mail_storage_get_lock_timeout(&mbox->storage->storage,
ab281fc992907b6cf6c730f672dc3aa4c6685015Timo Sirainen mbox->storage->set->mbox_lock_timeout);
6d24551e169c0808695db35d7a228f1970a84c75Timo Sirainen set.stale_timeout = mbox->storage->set->mbox_dotlock_change_timeout;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen set.callback = dotlock_callback;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen set.context = ctx;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen ret = file_dotlock_create(&set, mailbox_get_path(&mbox->box), 0,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen &mbox->mbox_dotlock);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (ret >= 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* success / timeout */
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen } else if (errno == EACCES && restrict_access_have_priv_gid() &&
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen mbox->mbox_privileged_locking) {
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen /* try again, this time with extra privileges */
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen ret = mbox_dotlock_privileged_op(mbox, &set,
280503e88a6b2f72a32a8fbe363794abaaa845d6Timo Sirainen MBOX_DOTLOCK_OP_LOCK);
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen } else if (errno == EACCES)
280503e88a6b2f72a32a8fbe363794abaaa845d6Timo Sirainen mbox_dotlock_log_eacces_error(mbox, mailbox_get_path(&mbox->box));
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen else
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen mbox_set_syscall_error(mbox, "file_dotlock_create()");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (ret < 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if ((ENOSPACE(errno) || errno == EACCES) && try)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return 1;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return -1;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (ret == 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mail_storage_set_error(&mbox->storage->storage,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen MAIL_ERROR_TEMP, MAIL_ERRSTR_LOCK_TIMEOUT);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return 0;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mbox->mbox_dotlocked = TRUE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
660b99a7059824676b2b8d6f79b8e15d47df25a2Timo Sirainen if (mbox_file_open_latest(ctx, lock_type) < 0)
42fcc708268a89aa9640693e71d13a2bb76e19c8Timo Sirainen return -1;
42fcc708268a89aa9640693e71d13a2bb76e19c8Timo Sirainen return 1;
42fcc708268a89aa9640693e71d13a2bb76e19c8Timo Sirainen}
42fcc708268a89aa9640693e71d13a2bb76e19c8Timo Sirainen
42fcc708268a89aa9640693e71d13a2bb76e19c8Timo Sirainenstatic int mbox_lock_dotlock(struct mbox_lock_context *ctx, int lock_type,
42fcc708268a89aa9640693e71d13a2bb76e19c8Timo Sirainen time_t max_wait_time ATTR_UNUSED)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return mbox_lock_dotlock_int(ctx, lock_type, FALSE);
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen}
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainenstatic int mbox_lock_dotlock_try(struct mbox_lock_context *ctx, int lock_type,
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen time_t max_wait_time ATTR_UNUSED)
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen{
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen return mbox_lock_dotlock_int(ctx, lock_type, TRUE);
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen}
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen#ifdef HAVE_FLOCK
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainenstatic int mbox_lock_flock(struct mbox_lock_context *ctx, int lock_type,
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen time_t max_wait_time)
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen{
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen time_t now;
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen unsigned int next_alarm;
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen if (mbox_file_open_latest(ctx, lock_type) < 0)
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen return -1;
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen if (lock_type == F_UNLCK && ctx->mbox->mbox_fd == -1)
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen return 1;
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen if (lock_type == F_WRLCK)
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen lock_type = LOCK_EX;
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen else if (lock_type == F_RDLCK)
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen lock_type = LOCK_SH;
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen else
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen lock_type = LOCK_UN;
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen if (max_wait_time == 0) {
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen /* usually we're waiting here, but if we came from
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen mbox_lock_dotlock(), we just want to try locking */
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen lock_type |= LOCK_NB;
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen } else {
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen now = time(NULL);
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen if (now >= max_wait_time)
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen alarm(1);
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen else
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen alarm(I_MIN(max_wait_time - now, 5));
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen }
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen while (flock(ctx->mbox->mbox_fd, lock_type) < 0) {
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen if (errno != EINTR) {
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen if (errno == EWOULDBLOCK && max_wait_time == 0) {
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen /* non-blocking lock trying failed */
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen return 0;
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen }
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen alarm(0);
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen mbox_set_syscall_error(ctx->mbox, "flock()");
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen return -1;
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen }
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen now = time(NULL);
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen if (now >= max_wait_time) {
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen alarm(0);
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen return 0;
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen }
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen /* notify locks once every 5 seconds.
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen try to use rounded values. */
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen next_alarm = (max_wait_time - now) % 5;
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen if (next_alarm == 0)
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen next_alarm = 5;
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen alarm(next_alarm);
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen index_storage_lock_notify(&ctx->mbox->box,
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen MAILBOX_LOCK_NOTIFY_MAILBOX_ABORT,
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen max_wait_time - now);
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen }
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen alarm(0);
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen return 1;
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen}
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen#endif
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#ifdef HAVE_LOCKF
decb23442f9e6cd5c4845a9cb162029b8c6d5f0fTimo Sirainenstatic int mbox_lock_lockf(struct mbox_lock_context *ctx, int lock_type,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen time_t max_wait_time)
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen{
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen time_t now;
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen unsigned int next_alarm;
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen
3858a7a5da361c35f1e6e50c8e3214dc0cf379d6Phil Carmody if (mbox_file_open_latest(ctx, lock_type) < 0)
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen return -1;
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen if (lock_type == F_UNLCK && ctx->mbox->mbox_fd == -1)
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen return 1;
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen if (lock_type == F_UNLCK)
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen lock_type = F_ULOCK;
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen else if (max_wait_time == 0) {
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen /* usually we're waiting here, but if we came from
decb23442f9e6cd5c4845a9cb162029b8c6d5f0fTimo Sirainen mbox_lock_dotlock(), we just want to try locking */
decb23442f9e6cd5c4845a9cb162029b8c6d5f0fTimo Sirainen lock_type = F_TLOCK;
7fa573e6ea36024f618492e7d3649a69c1b41028Timo Sirainen } else {
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen now = time(NULL);
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen if (now >= max_wait_time)
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen alarm(1);
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen else
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen alarm(I_MIN(max_wait_time - now, 5));
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen lock_type = F_LOCK;
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen }
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen while (lockf(ctx->mbox->mbox_fd, lock_type, 0) < 0) {
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen if (errno != EINTR) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if ((errno == EACCES || errno == EAGAIN) &&
f0339f522dc9c8e2e8a29ef9a3f937c431c6bd1bTimo Sirainen max_wait_time == 0) {
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen /* non-blocking lock trying failed */
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen return 0;
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen }
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen alarm(0);
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen mbox_set_syscall_error(ctx->mbox, "lockf()");
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen return -1;
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen }
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen now = time(NULL);
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen if (now >= max_wait_time) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen alarm(0);
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen return 0;
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen }
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen /* notify locks once every 5 seconds.
46ec792dd4ccf6c34706c4774228301fafde6aa9Timo Sirainen try to use rounded values. */
46ec792dd4ccf6c34706c4774228301fafde6aa9Timo Sirainen next_alarm = (max_wait_time - now) % 5;
46ec792dd4ccf6c34706c4774228301fafde6aa9Timo Sirainen if (next_alarm == 0)
46ec792dd4ccf6c34706c4774228301fafde6aa9Timo Sirainen next_alarm = 5;
ab90f702ceedb7ba445a9a592be0b213b27cbafaStephan Bosch alarm(next_alarm);
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen index_storage_lock_notify(&ctx->mbox->box,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen MAILBOX_LOCK_NOTIFY_MAILBOX_ABORT,
46ec792dd4ccf6c34706c4774228301fafde6aa9Timo Sirainen max_wait_time - now);
4c6ddf2491104f917d00e6900e833e80ea02c7b6Timo Sirainen }
4c6ddf2491104f917d00e6900e833e80ea02c7b6Timo Sirainen
4c6ddf2491104f917d00e6900e833e80ea02c7b6Timo Sirainen alarm(0);
4c6ddf2491104f917d00e6900e833e80ea02c7b6Timo Sirainen return 1;
4c6ddf2491104f917d00e6900e833e80ea02c7b6Timo Sirainen}
4c6ddf2491104f917d00e6900e833e80ea02c7b6Timo Sirainen#endif
4c6ddf2491104f917d00e6900e833e80ea02c7b6Timo Sirainen
4c6ddf2491104f917d00e6900e833e80ea02c7b6Timo Sirainenstatic int mbox_lock_fcntl(struct mbox_lock_context *ctx, int lock_type,
4c6ddf2491104f917d00e6900e833e80ea02c7b6Timo Sirainen time_t max_wait_time)
4c6ddf2491104f917d00e6900e833e80ea02c7b6Timo Sirainen{
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen struct flock fl;
4c6ddf2491104f917d00e6900e833e80ea02c7b6Timo Sirainen time_t now;
4c6ddf2491104f917d00e6900e833e80ea02c7b6Timo Sirainen unsigned int next_alarm;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen int wait_type;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (mbox_file_open_latest(ctx, lock_type) < 0)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return -1;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (lock_type == F_UNLCK && ctx->mbox->mbox_fd == -1)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return 1;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_zero(&fl);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen fl.l_type = lock_type;
6b107c647b2120d3906ff7d368f8a16900f6833fTimo Sirainen fl.l_whence = SEEK_SET;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen fl.l_start = 0;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen fl.l_len = 0;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (max_wait_time == 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* usually we're waiting here, but if we came from
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen mbox_lock_dotlock(), we just want to try locking */
fd3d068169c6ec587c9c446f2ee45560a444334aTimo Sirainen wait_type = F_SETLK;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen } else {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen wait_type = F_SETLKW;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen now = time(NULL);
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen if (now >= max_wait_time)
6b107c647b2120d3906ff7d368f8a16900f6833fTimo Sirainen alarm(1);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen else
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen alarm(I_MIN(max_wait_time - now, 5));
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen while (fcntl(ctx->mbox->mbox_fd, wait_type, &fl) < 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (errno != EINTR) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if ((errno == EACCES || errno == EAGAIN) &&
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen wait_type == F_SETLK) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* non-blocking lock trying failed */
fd3d068169c6ec587c9c446f2ee45560a444334aTimo Sirainen return 0;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen alarm(0);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (errno != EACCES) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mbox_set_syscall_error(ctx->mbox, "fcntl()");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return -1;
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen }
6b107c647b2120d3906ff7d368f8a16900f6833fTimo Sirainen mail_storage_set_critical(&ctx->mbox->storage->storage,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen "fcntl() failed with mbox file %s: "
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen "File is locked by another process (EACCES)",
6b107c647b2120d3906ff7d368f8a16900f6833fTimo Sirainen mailbox_get_path(&ctx->mbox->box));
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen return -1;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen
6b107c647b2120d3906ff7d368f8a16900f6833fTimo Sirainen now = time(NULL);
63e376747537cb2dfaa0e36d1bafd19df1443a4eTimo Sirainen if (now >= max_wait_time) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen alarm(0);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return 0;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
660b99a7059824676b2b8d6f79b8e15d47df25a2Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* notify locks once every 5 seconds.
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen try to use rounded values. */
7a23d586f07ec376e28e8f6f3f3392a4ac8b83bbTimo Sirainen next_alarm = (max_wait_time - now) % 5;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (next_alarm == 0)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen next_alarm = 5;
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen alarm(next_alarm);
6b107c647b2120d3906ff7d368f8a16900f6833fTimo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen index_storage_lock_notify(&ctx->mbox->box,
7a23d586f07ec376e28e8f6f3f3392a4ac8b83bbTimo Sirainen MAILBOX_LOCK_NOTIFY_MAILBOX_ABORT,
0348172a5278d1f5aa2440f30346c390ddc17318Timo Sirainen max_wait_time - now);
0348172a5278d1f5aa2440f30346c390ddc17318Timo Sirainen }
cb2c44f33d9d48f58e4c5e42ba2526a0c100218aTimo Sirainen
0348172a5278d1f5aa2440f30346c390ddc17318Timo Sirainen alarm(0);
0348172a5278d1f5aa2440f30346c390ddc17318Timo Sirainen ctx->fcntl_locked = TRUE;
7a23d586f07ec376e28e8f6f3f3392a4ac8b83bbTimo Sirainen return 1;
7a23d586f07ec376e28e8f6f3f3392a4ac8b83bbTimo Sirainen}
7a23d586f07ec376e28e8f6f3f3392a4ac8b83bbTimo Sirainen
7a23d586f07ec376e28e8f6f3f3392a4ac8b83bbTimo Sirainenstatic int ATTR_NOWARN_UNUSED_RESULT
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainenmbox_lock_list(struct mbox_lock_context *ctx, int lock_type,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen time_t max_wait_time, int idx)
ab90f702ceedb7ba445a9a592be0b213b27cbafaStephan Bosch{
46ec792dd4ccf6c34706c4774228301fafde6aa9Timo Sirainen enum mbox_lock_type *lock_types;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen enum mbox_lock_type type;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen int i, ret = 0;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen bool locked_status;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
decb23442f9e6cd5c4845a9cb162029b8c6d5f0fTimo Sirainen ctx->lock_type = lock_type;
decb23442f9e6cd5c4845a9cb162029b8c6d5f0fTimo Sirainen
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen lock_types = lock_type == F_WRLCK ||
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen (lock_type == F_UNLCK && ctx->mbox->mbox_lock_type == F_WRLCK) ?
6998ca95b4947c90647ac5d4794ebd6311acada2Timo Sirainen ctx->mbox->storage->write_locks :
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen ctx->mbox->storage->read_locks;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen for (i = idx; lock_types[i] != (enum mbox_lock_type)-1; i++) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen type = lock_types[i];
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen locked_status = lock_type != F_UNLCK;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (ctx->locked_status[type] == locked_status)
b66d803de86bfb411165b3465b0d9ef64ecfe2a1Timo Sirainen continue;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen ctx->locked_status[type] = locked_status;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen ret = lock_data[type].func(ctx, lock_type, max_wait_time);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (ret <= 0)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen break;
f29756821a4c6b12b73e4a2a3e1c230117a43773Timo Sirainen }
b11269887905780bc8cb7762bbb157aa59961cacTimo Sirainen return ret;
d3a7d023b47d2a137f01109e7b38702dca3f11d3Timo Sirainen}
d3a7d023b47d2a137f01109e7b38702dca3f11d3Timo Sirainen
d3a7d023b47d2a137f01109e7b38702dca3f11d3Timo Sirainenstatic int mbox_update_locking(struct mbox_mailbox *mbox, int lock_type,
d3a7d023b47d2a137f01109e7b38702dca3f11d3Timo Sirainen bool *fcntl_locked_r)
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen{
d3a7d023b47d2a137f01109e7b38702dca3f11d3Timo Sirainen struct mbox_lock_context ctx;
d3a7d023b47d2a137f01109e7b38702dca3f11d3Timo Sirainen time_t max_wait_time;
d3a7d023b47d2a137f01109e7b38702dca3f11d3Timo Sirainen int ret, i;
d3a7d023b47d2a137f01109e7b38702dca3f11d3Timo Sirainen bool drop_locks;
d3a7d023b47d2a137f01109e7b38702dca3f11d3Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen *fcntl_locked_r = FALSE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
5a250816ffc4cc5db203f9410ea99b6601c7b91aTimo Sirainen index_storage_lock_notify_reset(&mbox->box);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (!mbox->storage->lock_settings_initialized)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mbox_init_lock_settings(mbox->storage);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (mbox->mbox_fd == -1 && mbox->mbox_file_stream != NULL) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* read-only mbox stream. no need to lock. */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_assert(mbox_is_backend_readonly(mbox));
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mbox->mbox_lock_type = lock_type;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return 1;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen max_wait_time = time(NULL) +
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mail_storage_get_lock_timeout(&mbox->storage->storage,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mbox->storage->set->mbox_lock_timeout);
e2ce85866a669d1881d2d31791619d2e7c63c253Timo Sirainen
e2ce85866a669d1881d2d31791619d2e7c63c253Timo Sirainen i_zero(&ctx);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen ctx.mbox = mbox;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
b11269887905780bc8cb7762bbb157aa59961cacTimo Sirainen if (mbox->mbox_lock_type == F_WRLCK) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* dropping to shared lock. first drop those that we
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen don't remove completely. */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const enum mbox_lock_type *read_locks =
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mbox->storage->read_locks;
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen for (i = 0; i < MBOX_LOCK_COUNT; i++)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen ctx.locked_status[i] = TRUE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen for (i = 0; read_locks[i] != (enum mbox_lock_type)-1; i++)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen ctx.locked_status[read_locks[i]] = FALSE;
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen drop_locks = TRUE;
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen } else {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen drop_locks = FALSE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mbox->mbox_lock_type = lock_type;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen ret = mbox_lock_list(&ctx, lock_type, max_wait_time, 0);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (ret <= 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (!drop_locks)
80e461e945dd4d5b0d08535413176cf1756e8523Timo Sirainen mbox_unlock_files(&ctx);
80e461e945dd4d5b0d08535413176cf1756e8523Timo Sirainen if (ret == 0) {
80e461e945dd4d5b0d08535413176cf1756e8523Timo Sirainen mail_storage_set_error(&mbox->storage->storage,
80e461e945dd4d5b0d08535413176cf1756e8523Timo Sirainen MAIL_ERROR_TEMP, MAIL_ERRSTR_LOCK_TIMEOUT);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return ret;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen if (drop_locks) {
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen /* dropping to shared lock: drop the locks that are only
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen in write list */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const enum mbox_lock_type *read_locks =
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mbox->storage->read_locks;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const enum mbox_lock_type *write_locks =
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mbox->storage->write_locks;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
memset(ctx.locked_status, 0, sizeof(ctx.locked_status));
for (i = 0; write_locks[i] != (enum mbox_lock_type)-1; i++)
ctx.locked_status[write_locks[i]] = TRUE;
for (i = 0; read_locks[i] != (enum mbox_lock_type)-1; i++)
ctx.locked_status[read_locks[i]] = FALSE;
mbox->mbox_lock_type = F_WRLCK;
mbox_lock_list(&ctx, F_UNLCK, 0, 0);
mbox->mbox_lock_type = F_RDLCK;
}
*fcntl_locked_r = ctx.fcntl_locked;
return 1;
}
int mbox_lock(struct mbox_mailbox *mbox, int lock_type,
unsigned int *lock_id_r)
{
const char *path = mailbox_get_path(&mbox->box);
int mbox_fd = mbox->mbox_fd;
bool fcntl_locked;
int ret;
if (lock_type == F_RDLCK && mbox->external_transactions > 0 &&
mbox->mbox_lock_type != F_RDLCK) {
/* we have a transaction open that is going to save mails
and apparently also wants to read from the same mailbox
(copy, move, catenate). we need to write lock the mailbox,
since we can't later upgrade a read lock to write lock. */
lock_type = F_WRLCK;
}
/* allow only unlock -> shared/exclusive or exclusive -> shared */
i_assert(lock_type == F_RDLCK || lock_type == F_WRLCK);
i_assert(lock_type == F_RDLCK || mbox->mbox_lock_type != F_RDLCK);
if (mbox->mbox_lock_type == F_UNLCK) {
ret = mbox_update_locking(mbox, lock_type, &fcntl_locked);
if (ret <= 0)
return ret;
if (mbox->storage->storage.set->mail_nfs_storage) {
if (fcntl_locked) {
nfs_flush_attr_cache_fd_locked(path, mbox_fd);
nfs_flush_read_cache_locked(path, mbox_fd);
} else {
nfs_flush_attr_cache_unlocked(path);
nfs_flush_read_cache_unlocked(path, mbox_fd);
}
}
mbox->mbox_lock_id += 2;
}
if (lock_type == F_RDLCK) {
mbox->mbox_shared_locks++;
*lock_id_r = mbox->mbox_lock_id;
} else {
mbox->mbox_excl_locks++;
*lock_id_r = mbox->mbox_lock_id + 1;
}
if (mbox->mbox_stream != NULL)
istream_raw_mbox_set_locked(mbox->mbox_stream);
return 1;
}
static int mbox_unlock_files(struct mbox_lock_context *ctx)
{
int ret = 0;
if (mbox_lock_list(ctx, F_UNLCK, 0, 0) < 0)
ret = -1;
ctx->mbox->mbox_lock_id += 2;
ctx->mbox->mbox_lock_type = F_UNLCK;
return ret;
}
int mbox_unlock(struct mbox_mailbox *mbox, unsigned int lock_id)
{
struct mbox_lock_context ctx;
bool fcntl_locked;
int i;
i_assert(mbox->mbox_lock_id == (lock_id & ~1));
if ((lock_id & 1) != 0) {
/* dropping exclusive lock */
i_assert(mbox->mbox_excl_locks > 0);
if (--mbox->mbox_excl_locks > 0)
return 0;
if (mbox->mbox_shared_locks > 0) {
/* drop to shared lock */
if (mbox_update_locking(mbox, F_RDLCK,
&fcntl_locked) < 0)
return -1;
return 0;
}
} else {
/* dropping shared lock */
i_assert(mbox->mbox_shared_locks > 0);
if (--mbox->mbox_shared_locks > 0)
return 0;
if (mbox->mbox_excl_locks > 0)
return 0;
}
/* all locks gone */
/* make sure we don't read the stream while unlocked */
if (mbox->mbox_stream != NULL)
istream_raw_mbox_set_unlocked(mbox->mbox_stream);
i_zero(&ctx);
ctx.mbox = mbox;
for (i = 0; i < MBOX_LOCK_COUNT; i++)
ctx.locked_status[i] = TRUE;
return mbox_unlock_files(&ctx);
}
unsigned int mbox_get_cur_lock_id(struct mbox_mailbox *mbox)
{
return mbox->mbox_lock_id +
(mbox->mbox_excl_locks > 0 ? 1 : 0);
}
void mbox_dotlock_touch(struct mbox_mailbox *mbox)
{
if (mbox->mbox_dotlock == NULL)
return;
if (!mbox->mbox_used_privileges)
(void)file_dotlock_touch(mbox->mbox_dotlock);
else {
mbox_dotlock_privileged_op(mbox, NULL,
MBOX_DOTLOCK_OP_TOUCH);
}
}