summaryrefslogtreecommitdiffstats
path: root/src/util/maildirlock.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/maildirlock.c')
-rw-r--r--src/util/maildirlock.c106
1 files changed, 106 insertions, 0 deletions
diff --git a/src/util/maildirlock.c b/src/util/maildirlock.c
new file mode 100644
index 0000000..89fbacc
--- /dev/null
+++ b/src/util/maildirlock.c
@@ -0,0 +1,106 @@
+/* Copyright (c) 2008-2018 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "lib-signals.h"
+#include "ioloop.h"
+#include "write-full.h"
+#include "file-dotlock.h"
+#include "index/maildir/maildir-uidlist.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+
+static struct dotlock_settings dotlock_settings = {
+ .stale_timeout = MAILDIR_UIDLIST_LOCK_STALE_TIMEOUT,
+ .use_io_notify = TRUE
+};
+
+static struct ioloop *ioloop;
+
+static void sig_die(const siginfo_t *si ATTR_UNUSED, void *context ATTR_UNUSED)
+{
+ io_loop_stop(ioloop);
+}
+
+static int maildir_lock(const char *path, unsigned int timeout,
+ struct dotlock **dotlock_r)
+{
+ dotlock_settings.timeout = timeout;
+ dotlock_settings.use_excl_lock = getenv("DOTLOCK_USE_EXCL") != NULL;
+ dotlock_settings.nfs_flush = getenv("MAIL_NFS_STORAGE") != NULL;
+
+ path = t_strconcat(path, "/" MAILDIR_UIDLIST_NAME, NULL);
+ return file_dotlock_create(&dotlock_settings, path, 0, dotlock_r);
+}
+
+int main(int argc, const char *argv[])
+{
+ struct dotlock *dotlock;
+ unsigned int timeout;
+ pid_t pid;
+ int fd[2], ret;
+ char c;
+
+ if (argc != 3) {
+ fprintf(stderr, "Usage: maildirlock <path> <timeout>\n"
+ " - SIGTERM will release the lock.\n");
+ return 1;
+ }
+ if (pipe(fd) != 0) {
+ fprintf(stderr, "pipe() failed: %s", strerror(errno));
+ return 1;
+ }
+
+ pid = fork();
+ if (pid == (pid_t)-1) {
+ fprintf(stderr, "fork() failed: %s", strerror(errno));
+ return 1;
+ }
+
+ /* call lib_init() only after fork so that PID gets set correctly */
+ lib_init();
+ lib_signals_init();
+ ioloop = io_loop_create();
+ lib_signals_set_handler(SIGINT, LIBSIG_FLAG_DELAYED, sig_die, NULL);
+ lib_signals_set_handler(SIGTERM, LIBSIG_FLAG_DELAYED, sig_die, NULL);
+
+ if (pid != 0) {
+ i_close_fd(&fd[1]);
+ ret = read(fd[0], &c, 1);
+ if (ret < 0) {
+ i_error("read(pipe) failed: %m");
+ return 1;
+ }
+ if (ret != 1) {
+ /* locking timed out */
+ return 1;
+ }
+
+ printf("%s", dec2str(pid));
+ return 0;
+ }
+
+ /* child process - stdout has to be closed so that caller knows when
+ to stop reading it. */
+ if (dup2(STDERR_FILENO, STDOUT_FILENO) < 0)
+ i_fatal("dup2() failed: %m");
+
+ if (str_to_uint(argv[2], &timeout) < 0)
+ i_fatal("Invalid timeout value: %s", argv[2]);
+ if (maildir_lock(argv[1], timeout, &dotlock) <= 0)
+ return 1;
+
+ /* locked - send a byte */
+ if (write_full(fd[1], "", 1) < 0)
+ i_fatal("write(pipe) failed: %m");
+
+ io_loop_run(ioloop);
+
+ file_dotlock_delete(&dotlock);
+ lib_signals_deinit();
+
+ io_loop_destroy(&ioloop);
+ lib_deinit();
+ return 0;
+}