summaryrefslogtreecommitdiffstats
path: root/src/util/myflock.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 12:06:34 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 12:06:34 +0000
commit5e61585d76ae77fd5e9e96ebabb57afa4d74880d (patch)
tree2b467823aaeebc7ef8bc9e3cabe8074eaef1666d /src/util/myflock.c
parentInitial commit. (diff)
downloadpostfix-5b7b6342ca8708be5ee306c089f8c5b3d3d122d8.tar.xz
postfix-5b7b6342ca8708be5ee306c089f8c5b3d3d122d8.zip
Adding upstream version 3.5.24.upstream/3.5.24upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/util/myflock.c')
-rw-r--r--src/util/myflock.c152
1 files changed, 152 insertions, 0 deletions
diff --git a/src/util/myflock.c b/src/util/myflock.c
new file mode 100644
index 0000000..bd903ee
--- /dev/null
+++ b/src/util/myflock.c
@@ -0,0 +1,152 @@
+/*++
+/* NAME
+/* myflock 3
+/* SUMMARY
+/* lock open file
+/* SYNOPSIS
+/* #include <myflock.h>
+/*
+/* int myflock(fd, lock_style, operation)
+/* int fd;
+/* int lock_style;
+/* int operation;
+/* DESCRIPTION
+/* myflock() locks or unlocks an entire open file.
+/*
+/* In the case of a blocking request, a call that fails due to
+/* foreseeable transient problems is retried once per second.
+/*
+/* Arguments:
+/* .IP fd
+/* The open file to be locked/unlocked.
+/* .IP lock_style
+/* One of the following values:
+/* .RS
+/* .IP MYFLOCK_STYLE_FLOCK
+/* Use BSD-style flock() locking.
+/* .IP MYFLOCK_STYLE_FCNTL
+/* Use POSIX-style fcntl() locking.
+/* .RE
+/* .IP operation
+/* One of the following values:
+/* .RS
+/* .IP MYFLOCK_OP_NONE
+/* Release any locks the process has on the specified open file.
+/* .IP MYFLOCK_OP_SHARED
+/* Attempt to acquire a shared lock on the specified open file.
+/* This is appropriate for read-only access.
+/* .IP MYFLOCK_OP_EXCLUSIVE
+/* Attempt to acquire an exclusive lock on the specified open
+/* file. This is appropriate for write access.
+/* .PP
+/* In addition, setting the MYFLOCK_OP_NOWAIT bit causes the
+/* call to return immediately when the requested lock cannot
+/* be acquired.
+/* .RE
+/* DIAGNOSTICS
+/* myflock() returns 0 in case of success, -1 in case of failure.
+/* A problem description is returned via the global \fIerrno\fR
+/* variable. In the case of a non-blocking lock request the value
+/* EAGAIN means that a lock is claimed by someone else.
+/*
+/* Panic: attempts to use an unsupported file locking method or
+/* to implement an unsupported operation.
+/* 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 <errno.h>
+#include <unistd.h>
+
+#ifdef HAS_FCNTL_LOCK
+#include <fcntl.h>
+#include <string.h>
+#endif
+
+#ifdef HAS_FLOCK_LOCK
+#include <sys/file.h>
+#endif
+
+/* Utility library. */
+
+#include "msg.h"
+#include "myflock.h"
+
+/* myflock - lock/unlock entire open file */
+
+int myflock(int fd, int lock_style, int operation)
+{
+ int status;
+
+ /*
+ * Sanity check.
+ */
+ if ((operation & (MYFLOCK_OP_BITS)) != operation)
+ msg_panic("myflock: improper operation type: 0x%x", operation);
+
+ switch (lock_style) {
+
+ /*
+ * flock() does exactly what we need. Too bad it is not standard.
+ */
+#ifdef HAS_FLOCK_LOCK
+ case MYFLOCK_STYLE_FLOCK:
+ {
+ static int lock_ops[] = {
+ LOCK_UN, LOCK_SH, LOCK_EX, -1,
+ -1, LOCK_SH | LOCK_NB, LOCK_EX | LOCK_NB, -1
+ };
+
+ while ((status = flock(fd, lock_ops[operation])) < 0
+ && errno == EINTR)
+ sleep(1);
+ break;
+ }
+#endif
+
+ /*
+ * fcntl() is standard and does more than we need, but we can handle
+ * it.
+ */
+#ifdef HAS_FCNTL_LOCK
+ case MYFLOCK_STYLE_FCNTL:
+ {
+ struct flock lock;
+ int request;
+ static int lock_ops[] = {
+ F_UNLCK, F_RDLCK, F_WRLCK
+ };
+
+ memset((void *) &lock, 0, sizeof(lock));
+ lock.l_type = lock_ops[operation & ~MYFLOCK_OP_NOWAIT];
+ request = (operation & MYFLOCK_OP_NOWAIT) ? F_SETLK : F_SETLKW;
+ while ((status = fcntl(fd, request, &lock)) < 0
+ && errno == EINTR)
+ sleep(1);
+ break;
+ }
+#endif
+ default:
+ msg_panic("myflock: unsupported lock style: 0x%x", lock_style);
+ }
+
+ /*
+ * Return a consistent result. Some systems return EACCES when a lock is
+ * taken by someone else, and that would complicate error processing.
+ */
+ if (status < 0 && (operation & MYFLOCK_OP_NOWAIT) != 0)
+ if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EACCES)
+ errno = EAGAIN;
+
+ return (status);
+}