summaryrefslogtreecommitdiffstats
path: root/src/global/dot_lockfile.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/global/dot_lockfile.c173
1 files changed, 173 insertions, 0 deletions
diff --git a/src/global/dot_lockfile.c b/src/global/dot_lockfile.c
new file mode 100644
index 0000000..89a977a
--- /dev/null
+++ b/src/global/dot_lockfile.c
@@ -0,0 +1,173 @@
+/*++
+/* NAME
+/* dot_lockfile 3
+/* SUMMARY
+/* dotlock file management
+/* SYNOPSIS
+/* #include <dot_lockfile.h>
+/*
+/* int dot_lockfile(path, why)
+/* const char *path;
+/* VSTRING *why;
+/*
+/* void dot_unlockfile(path)
+/* const char *path;
+/* DESCRIPTION
+/* dot_lockfile() constructs a lock file name by appending ".lock" to
+/* \fIpath\fR and creates the named file exclusively. It tries several
+/* times and attempts to break stale locks. A negative result value
+/* means no lock file could be created.
+/*
+/* dot_unlockfile() attempts to remove the lock file created by
+/* dot_lockfile(). The operation always succeeds, and therefore
+/* it preserves the errno value.
+/*
+/* Arguments:
+/* .IP path
+/* Name of the file to be locked or unlocked.
+/* .IP why
+/* A null pointer, or storage for the reason why a lock file could
+/* not be created.
+/* DIAGNOSTICS
+/* dot_lockfile() returns 0 upon success. In case of failure, the
+/* result is -1, and the errno variable is set appropriately:
+/* EEXIST when a "fresh" lock file already exists; other values as
+/* appropriate.
+/* CONFIGURATION PARAMETERS
+/* deliver_lock_attempts, how many times to try to create a lock
+/* deliver_lock_delay, how long to wait between attempts
+/* stale_lock_time, when to break a stale lock
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include "sys_defs.h"
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <time.h>
+
+/* Utility library. */
+
+#include <vstring.h>
+#include <stringops.h>
+#include <mymalloc.h>
+#include <iostuff.h>
+#include <warn_stat.h>
+
+/* Global library. */
+
+#include "mail_params.h"
+#include "dot_lockfile.h"
+
+/* Application-specific. */
+
+#define MILLION 1000000
+
+/* dot_lockfile - create user.lock file */
+
+int dot_lockfile(const char *path, VSTRING *why)
+{
+ char *lock_file;
+ int count;
+ struct stat st;
+ int fd;
+ int status = -1;
+
+ lock_file = concatenate(path, ".lock", (char *) 0);
+
+ for (count = 1; /* void */ ; count++) {
+
+ /*
+ * Attempt to create the lock. This code relies on O_EXCL | O_CREAT
+ * to not follow symlinks. With NFS file systems this operation can
+ * at the same time succeed and fail with errno of EEXIST.
+ */
+ if ((fd = open(lock_file, O_WRONLY | O_EXCL | O_CREAT, 0)) >= 0) {
+ close(fd);
+ status = 0;
+ break;
+ }
+ if (count >= var_flock_tries)
+ break;
+
+ /*
+ * We can deal only with "file exists" errors. Any other error means
+ * we better give up trying.
+ */
+ if (errno != EEXIST)
+ break;
+
+ /*
+ * Break the lock when it is too old. Give up when we are unable to
+ * remove a stale lock.
+ */
+ if (stat(lock_file, &st) == 0)
+ if (time((time_t *) 0) > st.st_ctime + var_flock_stale)
+ if (unlink(lock_file) < 0)
+ if (errno != ENOENT)
+ break;
+
+ rand_sleep(var_flock_delay * MILLION, var_flock_delay * MILLION / 2);
+ }
+ if (status && why)
+ vstring_sprintf(why, "unable to create lock file %s: %m", lock_file);
+
+ myfree(lock_file);
+ return (status);
+}
+
+/* dot_unlockfile - remove .lock file */
+
+void dot_unlockfile(const char *path)
+{
+ char *lock_file;
+ int saved_errno = errno;
+
+ lock_file = concatenate(path, ".lock", (char *) 0);
+ (void) unlink(lock_file);
+ myfree(lock_file);
+ errno = saved_errno;
+}
+
+#ifdef TEST
+
+ /*
+ * Test program for setting a .lock file.
+ *
+ * Usage: dot_lockfile filename
+ *
+ * Creates filename.lock and removes it.
+ */
+#include <msg.h>
+#include <vstream.h>
+#include <msg_vstream.h>
+#include <mail_conf.h>
+
+int main(int argc, char **argv)
+{
+ VSTRING *why = vstring_alloc(100);
+
+ msg_vstream_init(argv[0], VSTREAM_ERR);
+ if (argc != 2)
+ msg_fatal("usage: %s file-to-be-locked", argv[0]);
+ mail_conf_read();
+ if (dot_lockfile(argv[1], why) < 0)
+ msg_fatal("%s", vstring_str(why));
+ dot_unlockfile(argv[1]);
+ vstring_free(why);
+ return (0);
+}
+
+#endif