summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS31
-rw-r--r--configure.ac2
-rw-r--r--doc/texinfo/Makefile.am3
-rw-r--r--doc/texinfo/programs.texi140
-rw-r--r--doc/texinfo/programs/dotlock.texi62
-rw-r--r--dotlock/dotlock.c28
-rw-r--r--include/mailutils/locker.h198
-rw-r--r--lib/manlock.c20
-rw-r--r--libmailutils/base/amd.c2
-rw-r--r--libmailutils/base/locker.c1276
-rw-r--r--libmailutils/base/spawnvp.c117
-rw-r--r--libmailutils/cli/stdcapa.c106
-rw-r--r--libmailutils/tests/lck.c126
-rw-r--r--libmailutils/tests/lock.at92
-rw-r--r--libmu_dbm/berkeley.c11
-rw-r--r--libmu_sieve/extensions/vacation.c2
-rw-r--r--libproto/dotmail/dotmail.c4
-rw-r--r--libproto/mbox/mboxrd.c4
-rw-r--r--mail/copy.c7
-rw-r--r--mda/lmtpd/lmtpd.c7
-rw-r--r--mda/mda/mda.c9
-rw-r--r--mda/putmail/putmail.c7
22 files changed, 1331 insertions, 923 deletions
diff --git a/NEWS b/NEWS
index 4f0825bf2..98bc1a233 100644
--- a/NEWS
+++ b/NEWS
@@ -1,8 +1,37 @@
-GNU mailutils NEWS -- history of user-visible changes. 2021-02-13
+GNU mailutils NEWS -- history of user-visible changes. 2021-05-01
See the end of file for copying conditions.
Please send mailutils bug reports to <bug-mailutils@gnu.org>.
+Version 3.12.90 (git)
+
+* Improved mailbox locking
+
+This fixes several bugs.
+
+* Changes in the 'locking' configuration statement.
+
+New statement 'type' configures the type of locking to use. Possible
+values are: 'default', 'dotlock', 'external', 'kernel', and 'null'.
+
+New statement 'pid-check' instructs mailutils to check if the PID of
+the process owning the lock still exists in the process table. If it
+doesn't the lock is considered stale and is removed.
+
+The 'flags' statement is deprecated. If used, an error message is
+issued along with a suggestion on what statement to use instead:
+
+ Flag Statement to use
+ --------+-------------------
+ E type external
+ R retry-count N
+ T expire-timeout N
+ P pid-check true
+
+The 'retry-timeout' statement is a misnomer and is therefore
+deprecated. Use 'retry-sleep' instead.
+
+
Version 3.12, 2021-02-13
* Fix expunging of mailboxes in mbox and dotmail format in a read-only directory
diff --git a/configure.ac b/configure.ac
index 479360a99..a6f361444 100644
--- a/configure.ac
+++ b/configure.ac
@@ -16,7 +16,7 @@ dnl You should have received a copy of the GNU General Public License along
dnl with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>.
AC_PREREQ(2.63)
-AC_INIT([GNU Mailutils], [3.12], [bug-mailutils@gnu.org], [mailutils],
+AC_INIT([GNU Mailutils], [3.12.90], [bug-mailutils@gnu.org], [mailutils],
[http://mailutils.org])
AC_CONFIG_SRCDIR([libmailutils/mailbox/mailbox.c])
AC_CONFIG_AUX_DIR([build-aux])
diff --git a/doc/texinfo/Makefile.am b/doc/texinfo/Makefile.am
index 92a3c4d5c..186415d0d 100644
--- a/doc/texinfo/Makefile.am
+++ b/doc/texinfo/Makefile.am
@@ -44,7 +44,8 @@ programs_TEXINFOS = \
programs/pop3d.texi\
programs/imap4d.texi\
programs/comsatd.texi\
- programs/mailutils.texi
+ programs/mailutils.texi\
+ programs/dotlock.texi
clean-local:
rm -rf manual
diff --git a/doc/texinfo/programs.texi b/doc/texinfo/programs.texi
index 5e4a07694..4ce1526a0 100644
--- a/doc/texinfo/programs.texi
+++ b/doc/texinfo/programs.texi
@@ -46,6 +46,7 @@ syntax.
* mh:: The MH Message Handling System.
* mailutils:: The Mailutils Multi-Purpose Tool.
+* dotlock:: The External Locker Utility.
@end menu
@node command line
@@ -1281,74 +1282,128 @@ pattern list, which contains:
@example
locking @{
# @r{Default locker flags.}
- flags @var{arg};
-
- # @r{Set timeout for acquiring the lock.}
- retry-timeout @var{arg};
+ type @code{default} | @code{dotlock} | @code{external} | @code{kernel} | @code{null};
# @r{Set the maximum number of times to retry acquiring the lock.}
retry-count @var{number};
+ # @r{Set the delay between two successive locking attempts.}
+ retry-sleep @var{arg};
+
# @r{Expire locks older than this amount of time.}
expire-timeout @var{number};
-
+
+ # @r{Check if PID of the lock owner is active, steal the lock if it not.}
+ pid-check @var{bool};
+
# @r{Use @var{prog} as external locker program.}
external-locker @var{prog};
@}
@end example
@subheading Description
-This block statement configures various parameters used when locking
+This compound statement configures various parameters used when locking
UNIX mailboxes in order to prevent simultaneous writes.
-It is important to note, that locking applies only to traditional
-UNIX mailboxes (@pxref{mbox}). All other
-mailbox types don't require locking.
+It is important to note, that locking applies only to monolithic
+mailboxes, i.e. mailboxes of @samp{mbox} and @samp{dotmail} types
+(@pxref{mbox}). Other mailbox types don't require locking.
-@deffn {Configuration} flags @var{string}
-Set locking flags. Argument is a string consisting of one or more of
-the following letters:
+@deffn {Configuration} type @var{string}
+Set locking type. Allowed arguments are:
-@table @asis
-@item E
-Use an external program to manage locks. The program is given by the
-@code{external-locker} statement (see below).
-
-@item R
-If the locking attempt failed, retry it. This is the default. The
-number of retries, and time interval between the two successive
-attempts is given by @code{retry-count} and @code{retry-timeout}
-statements, correspondingly.
-
-@item T
-If a lock file exists, check its modification time and, if it is
-older than a predefined amount of time, remove the lock. The amount
-of time is specified by @code{expire-timeout} statement.
-
-@item P
-Store the PID of the locking process in a lock file.
+@table @code
+@item default
+Default locking type. As of @command{mailutils} version
+@value{VERSION}, this is equivalent to @code{dotlock}.
+
+@item dotlock
+@anchor{dotlock locking type}
+A @samp{dotlock}-style locking. To lock a mailbox named @var{X}
+a @dfn{lock file} named @file{@var{X}.lock} is created. If
+@code{pid-check yes} is set, this file will contain the PID of the
+locking process, so that another process wishing to acquire the lock
+could verify if the lock is still in use.
+
+@item external
+@anchor{external locking type}
+Run external program to perform locking/unlocking operations. The
+name of the program is given by the @code{external-locker} statement
+(see below). If it is not given, the built-in default @samp{dotlock}
+is used.
+
+The locker program is invoked as follows:
+
+@example
+# To lock @var{mbox}:
+@var{locker} -f@var{expire_timeout} -r@var{retry_count} @var{mbox}
+# To unlock it:
+@var{locker} -u -f@var{expire_timeout} -r@var{retry_count} @var{mbox}
+@end example
+
+@noindent
+Here, @var{expire_timeout} is the value supplied with the
+@code{expire-timeout} configuration statement, and @var{retry_count}
+is the value supplied with the @code{retry-count} statement (see below).
+
+To properly interact with @command{mailutils}, the external locker
+program must use the following exit codes:
+
+@multitable @columnfractions 0.3 0.6
+@headitem Exit code @tab Meaning
+@item 0 @tab Success.
+@item 1 @tab Failed due to an error.
+@item 2 @tab Unlock requested (@option{-u}), but file is not locked.
+@item 3 @tab Lock requested, but file is already locked.
+@item 4 @tab Insufficient permissions.
+@end multitable
+
+@xref{dotlock}, for the description of the default external locker,
+shipped with mailutils.
+
+@item kernel
+Use kernel locking mechanism (@code{fcntl}(2)).
+
+@item null
+No locking at all. The statements below are silently ignored.
@end table
@end deffn
@deffn {Configuration} retry-count @var{number}
-Number of locking attempts. The @samp{P} flag must be set for this to
-take effect.
+Number of locking attempts. The default is 10.
@end deffn
-@deffn {Configuration} retry-timeout @var{seconds}
-Time interval, in seconds, between the two successive locking
-attempts. The @samp{P} flag must be set for this to take effect.
+@deffn {Configuration} retry-sleep @var{seconds}
+@deffnx {Configuration} retry-timeout @var{seconds}
+Time interval, in seconds, between two successive locking
+attempts. The default is 1 second. The @code{retry-timeout}
+statement is deprecated because of its misleading name.
@end deffn
@deffn {Configuration} expire-timeout @var{seconds}
-Remove existing lock file, if it is created more than this number of
-seconds ago. The @samp{T} flag must be set for this to take effect.
+Sets the expiration timeout. The existing lock file will be removed,
+if it was created more than this number of seconds ago. The default
+is 600.
+@end deffn
+
+@deffn {Configuration} pid-check @var{bool}
+This statement can be used if locking type is set to @code{dotlock}.
+If set to @code{true}, it instructs the locking algorithm to check
+if the PID of the lock owner is still running by the time when it
+tries to acquire the lock. This works as follows. When the lock file
+is created, the PID of the creating process is written to it. If
+another process tries to acquire the lock and sees that the lock file
+already exists, it reads the PID from the file and checks if a process
+with that PID still exists in the process table. If it does not, the
+process considers the lock file to be stale, removes it and locks the
+mailbox.
@end deffn
@deffn {Configuration} external-locker @var{string}
-Determines the external locker program to use. The @var{string}
-argument is the valid command line, starting with the full program
-name. The @samp{E} flag must be set for this to take effect.
+Sets the name of the external locker program to use, instead of the
+default @samp{dotlock}.
+
+This statement is in effect only when used together with @code{type external}.
@end deffn
@node mailer statement
@@ -2990,3 +3045,8 @@ Show payload information
@node mailutils
@section mailutils
@include programs/mailutils.texi
+
+@page
+@node dotlock
+@section dotlock
+@include programs/dotlock.texi
diff --git a/doc/texinfo/programs/dotlock.texi b/doc/texinfo/programs/dotlock.texi
new file mode 100644
index 000000000..2f7be2e8a
--- /dev/null
+++ b/doc/texinfo/programs/dotlock.texi
@@ -0,0 +1,62 @@
+@pindex dotlock
+
+A stand-alone mailbox-locking utility. It is the default program used
+by @command{mailutils} if the @code{locking.type} configuration
+statement is set to @code{external} (@pxref{external locking type}).
+
+The program usage syntax is:
+
+@example
+@group
+# To lock @var{mbox}:
+dotlock @var{options} @var{mbox}
+# To unlock it:
+dotlock -u @var{options} @var{mbox}
+@end group
+@end example
+
+By default the program implements the @samp{dotlock} locking
+(@pxref{dotlock locking type}). This can be changed either in the
+configuration file, or via the command line options.
+
+The following common configuration statements affect the behavior of
+@command{dotlock}:
+
+@multitable @columnfractions 0.3 0.6
+@headitem Statement @tab Reference
+@item debug @tab @xref{Debug Statement}.
+@item locking @tab @xref{Locking Statement}.
+@end multitable
+
+The program understands the following command line options:
+
+@table @option
+@item -d
+@itemx --debug
+Print details of failure reasons to stderr.
+
+@item -f[@var{n}]
+@itemx --force[=@var{n}]
+If a lock file exists and is more than @var{n} minutes old, forcibly
+remove it and re-lock the mailbox. Default @var{n} is 10 minutes.
+
+@item -p
+@itemx --pid-check
+Check if the PID of lock owner is still active. If not, break the
+lock.
+
+@item -r @var{n}
+@item --retry=@var{n}
+Number of times to retry acquiring the lock, if it is held by another
+process. The default is 10 times.
+
+@item -t @var{n}
+@itemx --delay=@var{n}
+Sets delay in seconds between two successive locking attempts.
+The default is 1 second.
+
+@item -u
+@itemx --unlock
+Unlock the mailbox.
+@end table
+
diff --git a/dotlock/dotlock.c b/dotlock/dotlock.c
index 1bb11590b..303f6d943 100644
--- a/dotlock/dotlock.c
+++ b/dotlock/dotlock.c
@@ -28,7 +28,6 @@
static const char *file;
static int unlock;
-static int flags;
static unsigned retries;
static unsigned force;
static int debug;
@@ -119,6 +118,7 @@ int
main (int argc, char *argv[])
{
mu_locker_t locker = 0;
+ mu_locker_hints_t hints = { .flags = 0 };
int err = 0;
pid_t usergid = getgid ();
pid_t mailgid = getegid ();
@@ -149,31 +149,27 @@ main (int argc, char *argv[])
if (force)
{
- force *= 60;
- flags |= MU_LOCKER_TIME;
+ hints.flags |= MU_LOCKER_FLAG_EXPIRE_TIME;
+ hints.expire_time = force * 60;
}
- if (retries || retry_sleep)
- flags |= MU_LOCKER_RETRY;
+ if (retries)
+ {
+ hints.flags |= MU_LOCKER_FLAG_RETRY;
+ hints.retry_count = retries;
+ hints.retry_sleep = retry_sleep;
+ }
if (pid_check)
- flags |= MU_LOCKER_PID;
+ hints.flags |= MU_LOCKER_FLAG_CHECK_PID;
- if ((err = mu_locker_create (&locker, file, flags)))
+ if ((err = mu_locker_create_ext (&locker, file, hints.flags != 0 ? &hints : NULL)))
{
if (debug)
- mu_diag_funcall (MU_DIAG_ERROR, "mu_locker_create", NULL, err);
+ mu_diag_funcall (MU_DIAG_ERROR, "mu_locker_create_ext", NULL, err);
return MU_DL_EX_ERROR;
}
- if (force != 0)
- mu_locker_set_expire_time (locker, force);
-
- if (retries)
- mu_locker_set_retries (locker, retries);
- if (retry_sleep)
- mu_locker_set_retry_sleep (locker, retry_sleep);
-
if (setegid (mailgid) < 0)
return MU_DL_EX_ERROR;
diff --git a/include/mailutils/locker.h b/include/mailutils/locker.h
index 21aed9de9..082bbd942 100644
--- a/include/mailutils/locker.h
+++ b/include/mailutils/locker.h
@@ -25,105 +25,56 @@ extern "C" {
#endif
/* lock expiry time */
-#define MU_LOCKER_EXPIRE_TIME (10 * 60)
-#define MU_LOCKER_RETRIES (10)
-#define MU_LOCKER_RETRY_SLEEP (1)
-#define MU_LOCKER_EXTERNAL_PROGRAM "dotlock"
+#define MU_LOCKER_DEFAULT_EXPIRE_TIME (10 * 60)
+#define MU_LOCKER_DEFAULT_RETRY_COUNT 10
+#define MU_LOCKER_DEFAULT_RETRY_SLEEP 1
+#define MU_LOCKER_DEFAULT_EXT_LOCKER "dotlock"
/* return codes for the external locker */
-#define MU_DL_EX_PERM 4 /* insufficient permissions */
-#define MU_DL_EX_EXIST 3 /* lock requested, but file is already locked */
-#define MU_DL_EX_NEXIST 2 /* unlock requested, but file is not locked */
-#define MU_DL_EX_ERROR 1 /* failed due to some other error */
-#define MU_DL_EX_OK 0 /* success */
-
-enum mu_locker_set_mode
+enum
{
- mu_locker_assign,
- mu_locker_set_bit,
- mu_locker_clear_bit
+ MU_DL_EX_OK = 0, /* success */
+ MU_DL_EX_ERROR = 1, /* failed due to some other error */
+ MU_DL_EX_NEXIST = 2, /* unlock requested, but file is not locked */
+ MU_DL_EX_EXIST = 3, /* lock requested, but file is already locked */
+ MU_DL_EX_PERM = 4, /* insufficient permissions */
};
-
-/* mu_locker_create() flags */
/* Locker types */
+enum
+ {
+ MU_LOCKER_TYPE_DOTLOCK = 0, /* Dotlock-style locking. The default. */
+ MU_LOCKER_TYPE_EXTERNAL = 1, /* Use external program to lock the file. */
+ MU_LOCKER_TYPE_KERNEL = 2, /* Use kernel locking (flock,lockf,ioctl) */
+ MU_LOCKER_TYPE_NULL = 3, /* No locking at all. */
+ };
-#define MU_LOCKER_TYPE_DOTLOCK 0
-#define MU_LOCKER_TYPE_EXTERNAL 1
- /* Use an external program to lock the file. This is necessary
- for programs having permission to access a file, but do not
- have write permission on the directory that contains that file. */
-#define MU_LOCKER_TYPE_KERNEL 2
- /* Use kernel locking (flock, lockf or ioctl) */
-#define MU_LOCKER_TYPE_NULL 3
- /* Special locker type: means no lock. This is to be used with
- temporary mailboxes stored in memory. */
-
-#define MU_LOCKER_TYPE_TO_FLAG(t) ((t) << 8)
-#define MU_LOCKER_FLAG_TO_TYPE(f) ((f) >> 8)
-#define MU_LOCKER_IS_TYPE(f,t) (MU_LOCKER_FLAG_TO_TYPE(f) == (t))
-#define MU_LOCKER_SET_TYPE(f,t) ((f) = MU_LOCKER_TYPE_TO_FLAG(t) | MU_LOCKER_OPTIONS(f))
-#define MU_LOCKER_TYPE_MASK 0xff00
-#define MU_LOCKER_OPTION_MASK 0x00ff
-#define MU_LOCKER_OPTIONS(f) ((f) & MU_LOCKER_OPTION_MASK)
+#define MU_LOCKER_TYPE_DEFAULT MU_LOCKER_TYPE_DOTLOCK
-#define MU_LOCKER_NULL MU_LOCKER_TYPE_TO_FLAG(MU_LOCKER_TYPE_NULL)
-#define MU_LOCKER_DOTLOCK MU_LOCKER_TYPE_TO_FLAG(MU_LOCKER_TYPE_DOTLOCK)
-#define MU_LOCKER_EXTERNAL MU_LOCKER_TYPE_TO_FLAG(MU_LOCKER_TYPE_EXTERNAL)
-#define MU_LOCKER_KERNEL MU_LOCKER_TYPE_TO_FLAG(MU_LOCKER_TYPE_KERNEL)
-
-/* Options */
-
-#define MU_LOCKER_SIMPLE 0x0000
- /* Just try and dotlock the file, not the default because its usually
- better to retry. */
-#define MU_LOCKER_RETRY 0x0001
- /* This requests that we loop retries times, sleeping retry_sleep
- seconds in between trying to obtain the lock before failing with
- MU_LOCK_CONFLICT. */
-#define MU_LOCKER_TIME 0x0002
- /* This mode checks the last update time of the lock, then removes
- it if older than MU_LOCKER_EXPIRE_TIME. If a client uses this,
- then the servers better periodically update the lock on the
- file... do they? */
-#define MU_LOCKER_PID 0x0004
- /* PID locking is only useful for programs that aren't using
- an external dotlocker, non-setgid programs will use a dotlocker,
- which locks and exits imediately. This is a protection against
- a server crashing, it's not generally useful. */
+typedef struct
+{
+ int flags;
+ int type;
+ unsigned retry_count;
+ unsigned retry_sleep;
+ unsigned expire_time;
+ char *ext_locker;
+} mu_locker_hints_t;
+
+/* Locker hint flags */
+#define MU_LOCKER_FLAG_RETRY 0x0001 /* retry_count and retry_sleep are set */
+#define MU_LOCKER_FLAG_EXPIRE_TIME 0x0002 /* expire_time is set */
+#define MU_LOCKER_FLAG_CHECK_PID 0x0004 /* check if lock owner PID is active */
+#define MU_LOCKER_FLAG_EXT_LOCKER 0x0008 /* ext_locker is set */
+#define MU_LOCKER_FLAG_TYPE 0x0010 /* type is set */
+
+#define MU_LOCKER_FLAGS_ALL (\
+ MU_LOCKER_FLAG_TYPE | \
+ MU_LOCKER_FLAG_RETRY | \
+ MU_LOCKER_FLAG_EXPIRE_TIME | \
+ MU_LOCKER_FLAG_EXT_LOCKER | \
+ MU_LOCKER_FLAG_CHECK_PID )
-#define MU_LOCKER_DEFAULT (MU_LOCKER_DOTLOCK | MU_LOCKER_RETRY)
-
-/* Use these flags for as the default locker flags (the default defaults
- * to MU_LOCKER_DEFAULT). A flags of 0 resets the flags back to the
- * the default.
- */
-extern int mu_locker_set_default_flags (int flags, enum mu_locker_set_mode mode);
-extern void mu_locker_set_default_retry_timeout (time_t to);
-extern void mu_locker_set_default_retry_count (size_t n);
-extern void mu_locker_set_default_expire_timeout (time_t t);
-extern int mu_locker_set_default_external_program (char const *path);
-
-/* A flags of 0 means that the default will be used. */
-extern int mu_locker_create (mu_locker_t *, const char *filename, int flags);
-extern void mu_locker_destroy (mu_locker_t *);
-
-/* Time is measured in seconds. */
-
-extern int mu_locker_set_flags (mu_locker_t, int);
-extern int mu_locker_mod_flags (mu_locker_t locker, int flags,
- enum mu_locker_set_mode mode);
-extern int mu_locker_set_expire_time (mu_locker_t, int);
-extern int mu_locker_set_retries (mu_locker_t, int);
-extern int mu_locker_set_retry_sleep (mu_locker_t, int);
-extern int mu_locker_set_external (mu_locker_t, const char* program);
-
-extern int mu_locker_get_flags (mu_locker_t, int*);
-extern int mu_locker_get_expire_time (mu_locker_t, int*);
-extern int mu_locker_get_retries (mu_locker_t, int*);
-extern int mu_locker_get_retry_sleep (mu_locker_t, int*);
-extern int mu_locker_get_external (mu_locker_t, char**);
-
enum mu_locker_mode
{
mu_lck_shr, /* Shared (advisory) lock */
@@ -132,12 +83,79 @@ enum mu_locker_mode
locking otherwise */
};
+#define MU_LOCKFILE_MODE 0644
+
+extern int mu_locker_create_ext (mu_locker_t *, const char *, mu_locker_hints_t *);
+extern int mu_locker_modify (mu_locker_t, mu_locker_hints_t *);
+extern void mu_locker_destroy (mu_locker_t *);
+
extern int mu_locker_lock_mode (mu_locker_t, enum mu_locker_mode);
extern int mu_locker_lock (mu_locker_t);
extern int mu_locker_touchlock (mu_locker_t);
extern int mu_locker_unlock (mu_locker_t);
extern int mu_locker_remove_lock (mu_locker_t);
+extern int mu_locker_get_hints (mu_locker_t lck, mu_locker_hints_t *hints);
+
+extern mu_locker_hints_t mu_locker_defaults;
+
+/*
+ * Deprecated defines and interfaces.
+ */
+
+/* Legacy definitions for locker defaults */
+#define MU_LOCKER_EXPIRE_TIME MU_LOCKER_DEFAULT_EXPIRE_TIME
+#define MU_LOCKER_RETRIES MU_LOCKER_DEFAULT_RETRY_COUNT
+#define MU_LOCKER_RETRY_SLEEP MU_LOCKER_DEFAULT_RETRY_SLEEP
+#define MU_LOCKER_EXTERNAL_PROGRAM MU_LOCKER_DEFAULT_EXT_LOCKER
+
+/* Legacy definitions of locker types */
+#define MU_LOCKER_DOTLOCK (MU_LOCKER_TYPE_DOTLOCK << 8)
+#define MU_LOCKER_EXTERNAL (MU_LOCKER_TYPE_EXTERNAL << 8)
+#define MU_LOCKER_KERNEL (MU_LOCKER_TYPE_KERNEL << 8)
+#define MU_LOCKER_NULL (MU_LOCKER_TYPE_NULL << 8)
+
+/* Legacy definitions of locker flags (a.k.a. options). */
+#define MU_LOCKER_SIMPLE 0x0000
+#define MU_LOCKER_RETRY MU_LOCKER_FLAG_RETRY
+#define MU_LOCKER_TIME MU_LOCKER_FLAG_EXPIRE_TIME
+#define MU_LOCKER_PID MU_LOCKER_FLAG_CHECK_PID
+
+#define MU_LOCKER_DEFAULT (MU_LOCKER_DOTLOCK | MU_LOCKER_RETRY)
+
+/* The following was used to pack/unpack flags and locker type: */
+#define MU_LOCKER_TYPE_TO_FLAG(t) ((t) << 8)
+#define MU_LOCKER_FLAG_TO_TYPE(f) ((f) >> 8)
+#define MU_LOCKER_TYPE_MASK 0xff00
+#define MU_LOCKER_OPTION_MASK 0x00ff
+
+enum mu_locker_set_mode
+ {
+ mu_locker_assign,
+ mu_locker_set_bit,
+ mu_locker_clear_bit
+ };
+
+extern int mu_locker_create (mu_locker_t *, const char *, int) MU_DEPRECATED;
+
+extern int mu_locker_set_default_flags (int, enum mu_locker_set_mode) MU_DEPRECATED;
+extern void mu_locker_set_default_retry_timeout (time_t) MU_DEPRECATED;
+extern void mu_locker_set_default_retry_count (size_t) MU_DEPRECATED;
+extern void mu_locker_set_default_expire_timeout (time_t) MU_DEPRECATED;
+extern int mu_locker_set_default_external_program (char const *) MU_DEPRECATED;
+
+extern int mu_locker_set_flags (mu_locker_t, int) MU_DEPRECATED;
+extern int mu_locker_mod_flags (mu_locker_t, int, enum mu_locker_set_mode) MU_DEPRECATED;
+extern int mu_locker_set_expire_time (mu_locker_t, int) MU_DEPRECATED;
+extern int mu_locker_set_retries (mu_locker_t, int) MU_DEPRECATED;
+extern int mu_locker_set_retry_sleep (mu_locker_t, int) MU_DEPRECATED;
+extern int mu_locker_set_external (mu_locker_t, const char *) MU_DEPRECATED;
+
+extern int mu_locker_get_flags (mu_locker_t, int *) MU_DEPRECATED;
+extern int mu_locker_get_expire_time (mu_locker_t, int *) MU_DEPRECATED;
+extern int mu_locker_get_retries (mu_locker_t, int *) MU_DEPRECATED;
+extern int mu_locker_get_retry_sleep (mu_locker_t, int *) MU_DEPRECATED;
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/manlock.c b/lib/manlock.c
index 0c32115cc..e06387807 100644
--- a/lib/manlock.c
+++ b/lib/manlock.c
@@ -128,14 +128,17 @@ mailbox_open_and_lock (mu_mailbox_t mbox, int flags)
if (lock)
{
- status = mu_locker_get_flags (lock, &flags);
+ mu_locker_hints_t hints;
+
+ hints.flags = MU_LOCKER_FLAG_TYPE;
+ status = mu_locker_get_hints (lock, &hints);
if (status)
{
- mu_diag_funcall (MU_DIAG_ERROR, "mu_locker_get_flags", urlstr,
+ mu_diag_funcall (MU_DIAG_ERROR, "mu_locker_get_hints", urlstr,
status);
return MU_ERR_FAILURE;
}
- if (flags & MU_LOCKER_NULL)
+ if (hints.type == MU_LOCKER_TYPE_NULL)
lock = NULL;
}
@@ -157,10 +160,10 @@ mailbox_open_and_lock (mu_mailbox_t mbox, int flags)
if (!fname)
return MU_ERR_FAILURE;
- status = mu_locker_create (&lock, fname, 0);
+ status = mu_locker_create_ext (&lock, fname, NULL);
if (status)
{
- mu_diag_funcall (MU_DIAG_ERROR, "mu_locker_create", fname, status);
+ mu_diag_funcall (MU_DIAG_ERROR, "mu_locker_create_ext", fname, status);
free (fname);
return MU_ERR_FAILURE;
}
@@ -245,13 +248,14 @@ manlock_lock (mu_mailbox_t mbox)
mu_locker_t lock = NULL;
const char *name;
int status;
-
+ mu_locker_hints_t hints = { .flags = MU_LOCKER_FLAG_CHECK_PID };
+
if (!manlock_mandatory_locking)
return 0;
mu_mailbox_get_url (mbox, &url);
name = mu_url_to_string (url);
- mu_mailbox_get_locker (mbox, &lock);
- mu_locker_mod_flags (lock, MU_LOCKER_PID, mu_locker_set_bit);
+ mu_mailbox_get_locker (mbox, &lock);
+ mu_locker_modify (lock, &hints);
if ((status = mu_locker_lock (lock)))
{
mu_diag_output (MU_DIAG_NOTICE, _("locking mailbox `%s' failed: %s"),
diff --git a/libmailutils/base/amd.c b/libmailutils/base/amd.c
index 349a8060a..e488da153 100644
--- a/libmailutils/base/amd.c
+++ b/libmailutils/base/amd.c
@@ -500,7 +500,7 @@ amd_open (mu_mailbox_t mailbox, int flags)
_amd_prop_create (amd);
if (mailbox->locker == NULL)
- mu_locker_create (&mailbox->locker, "/dev/null", 0);
+ mu_locker_create_ext (&mailbox->locker, "/dev/null", NULL);
return 0;
}
diff --git a/libmailutils/base/locker.c b/libmailutils/base/locker.c
index ef26fc52b..520bdca11 100644
--- a/libmailutils/base/locker.c
+++ b/libmailutils/base/locker.c
@@ -41,8 +41,6 @@
#include <mailutils/util.h>
#include <mailutils/io.h>
-#define LOCKFILE_ATTR 0644
-
/* First draft by Brian Edmond. */
/* For subsequent modifications, see the GNU mailutils ChangeLog. */
@@ -51,10 +49,11 @@ struct _mu_locker
unsigned refcnt; /* Number of times mu_locker_lock was called */
enum mu_locker_mode mode; /* Current locking mode (if refcnt > 0) */
+ int type;
char *file;
int flags;
int expire_time;
- int retries;
+ int retry_count;
int retry_sleep;
union lock_data
@@ -63,62 +62,16 @@ struct _mu_locker
{
char *dotlock;
char *nfslock;
- } dot;
+ } dot; /* MU_LOCKER_TYPE_DOTLOCK */
struct
{
char *name;
- } external;
+ } external; /* MU_LOCKER_TYPE_EXTERNAL */
- struct
- {
- int fd;
- } kernel;
+ int fd; /* MU_LOCKER_TYPE_KERNEL */
} data;
};
-
-#define MU_LOCKER_TYPE(l) MU_LOCKER_FLAG_TO_TYPE((l)->flags)
-
-struct locker_tab
-{
- int (*init) (mu_locker_t);
- void (*destroy) (mu_locker_t);
- int (*prelock) (mu_locker_t);
- int (*lock) (mu_locker_t, enum mu_locker_mode);
- int (*unlock) (mu_locker_t);
-};
-
-static int init_dotlock (mu_locker_t);
-static void destroy_dotlock (mu_locker_t);
-static int lock_dotlock (mu_locker_t, enum mu_locker_mode);
-static int unlock_dotlock (mu_locker_t);
-
-static int init_external (mu_locker_t);
-static void destroy_external (mu_locker_t);
-static int lock_external (mu_locker_t, enum mu_locker_mode);
-static int unlock_external (mu_locker_t);
-
-static int init_kernel (mu_locker_t);
-static int lock_kernel (mu_locker_t, enum mu_locker_mode);
-static int unlock_kernel (mu_locker_t);
-
-static int prelock_common (mu_locker_t);
-
-static struct locker_tab locker_tab[] = {
- /* MU_LOCKER_TYPE_DOTLOCK */
- { init_dotlock, destroy_dotlock, prelock_common,
- lock_dotlock, unlock_dotlock },
- /* MU_LOCKER_TYPE_EXTERNAL */
- { init_external, destroy_external, prelock_common,
- lock_external, unlock_external },
- /* MU_LOCKER_TYPE_KERNEL */
- { init_kernel, NULL, NULL, lock_kernel, unlock_kernel },
- /* MU_LOCKER_TYPE_NULL */
- { NULL, NULL, NULL, NULL, NULL }
-};
-
-#define MU_LOCKER_NTYPES (sizeof (locker_tab) / sizeof (locker_tab[0]))
-
static int
stat_check (const char *file, int fd, int links)
@@ -145,20 +98,17 @@ stat_check (const char *file, int fd, int links)
{
/* If the link and stat don't report the same info, or the
file is a symlink, fail the locking. */
-#define CHK(X) if(X) err = EINVAL
-
- CHK (!S_ISREG (fn_stat.st_mode));
- CHK (!S_ISREG (fd_stat.st_mode));
- CHK (fn_stat.st_nlink != links);
- CHK (fn_stat.st_dev != fd_stat.st_dev);
- CHK (fn_stat.st_ino != fd_stat.st_ino);
- CHK (fn_stat.st_mode != fd_stat.st_mode);
- CHK (fn_stat.st_nlink != fd_stat.st_nlink);
- CHK (fn_stat.st_uid != fd_stat.st_uid);
- CHK (fn_stat.st_gid != fd_stat.st_gid);
- CHK (fn_stat.st_rdev != fd_stat.st_rdev);
-
-#undef CHK
+ if (!S_ISREG (fn_stat.st_mode)
+ || !S_ISREG (fd_stat.st_mode)
+ || fn_stat.st_nlink != links
+ || fn_stat.st_dev != fd_stat.st_dev
+ || fn_stat.st_ino != fd_stat.st_ino
+ || fn_stat.st_mode != fd_stat.st_mode
+ || fn_stat.st_nlink != fd_stat.st_nlink
+ || fn_stat.st_uid != fd_stat.st_uid
+ || fn_stat.st_gid != fd_stat.st_gid
+ || fn_stat.st_rdev != fd_stat.st_rdev)
+ err = EINVAL;
}
if (localfd != -1)
close (localfd);
@@ -195,471 +145,23 @@ prelock_common (mu_locker_t locker)
of 1, that we have permission to read, etc., or don't lock it. */
return check_file_permissions (locker->file);
}
-
-
-static int mu_locker_default_flags = MU_LOCKER_DEFAULT;
-static time_t mu_locker_retry_timeout = MU_LOCKER_RETRY_SLEEP;
-static size_t mu_locker_retry_count = MU_LOCKER_RETRIES;
-static time_t mu_locker_expire_timeout = MU_LOCKER_EXPIRE_TIME;
-static char *mu_locker_external_program = NULL;
-
-int
-mu_locker_set_default_flags (int flags, enum mu_locker_set_mode mode)
-{
- switch (mode)
- {
- case mu_locker_assign:
- mu_locker_default_flags = flags;
- break;
-
- case mu_locker_set_bit:
- mu_locker_default_flags |= flags;
- break;
-
- case mu_locker_clear_bit:
- mu_locker_default_flags &= ~flags;
- break;
-
- default:
- return EINVAL;
- }
- return 0;
-}
-
-void
-mu_locker_set_default_retry_timeout (time_t to)
-{
- mu_locker_retry_timeout = to;
-}
-
-void
-mu_locker_set_default_retry_count (size_t n)
-{
- mu_locker_retry_count = n;
-}
-
-void
-mu_locker_set_default_expire_timeout (time_t t)
-{
- mu_locker_expire_timeout = t;
-}
-
-int
-mu_locker_set_default_external_program (char const *path)
-{
- char *p = strdup (path);
- if (!p)
- return ENOMEM;
- free (mu_locker_external_program);
- mu_locker_external_program = p;
- return 0;
-}
-
-int
-mu_locker_mod_flags (mu_locker_t locker, int flags,
- enum mu_locker_set_mode mode)
-{
- unsigned otype, ntype;
- int new_flags;
-
- if (!locker)
- return MU_ERR_LOCKER_NULL;
-
- switch (mode)
- {
- case mu_locker_assign:
- new_flags = flags;
- break;
-
- case mu_locker_set_bit:
- new_flags = locker->flags | flags;
- break;
-
- case mu_locker_clear_bit:
- new_flags = locker->flags & ~flags;
- break;
-
- default:
- return EINVAL;
- }
-
- otype = MU_LOCKER_TYPE (locker);
- if (otype >= MU_LOCKER_NTYPES)
- return EINVAL;
- ntype = MU_LOCKER_FLAG_TO_TYPE (new_fla