diff options
-rw-r--r-- | NEWS | 31 | ||||
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | doc/texinfo/Makefile.am | 3 | ||||
-rw-r--r-- | doc/texinfo/programs.texi | 140 | ||||
-rw-r--r-- | doc/texinfo/programs/dotlock.texi | 62 | ||||
-rw-r--r-- | dotlock/dotlock.c | 28 | ||||
-rw-r--r-- | include/mailutils/locker.h | 198 | ||||
-rw-r--r-- | lib/manlock.c | 20 | ||||
-rw-r--r-- | libmailutils/base/amd.c | 2 | ||||
-rw-r--r-- | libmailutils/base/locker.c | 1276 | ||||
-rw-r--r-- | libmailutils/base/spawnvp.c | 117 | ||||
-rw-r--r-- | libmailutils/cli/stdcapa.c | 106 | ||||
-rw-r--r-- | libmailutils/tests/lck.c | 126 | ||||
-rw-r--r-- | libmailutils/tests/lock.at | 92 | ||||
-rw-r--r-- | libmu_dbm/berkeley.c | 11 | ||||
-rw-r--r-- | libmu_sieve/extensions/vacation.c | 2 | ||||
-rw-r--r-- | libproto/dotmail/dotmail.c | 4 | ||||
-rw-r--r-- | libproto/mbox/mboxrd.c | 4 | ||||
-rw-r--r-- | mail/copy.c | 7 | ||||
-rw-r--r-- | mda/lmtpd/lmtpd.c | 7 | ||||
-rw-r--r-- | mda/mda/mda.c | 9 | ||||
-rw-r--r-- | mda/putmail/putmail.c | 7 |
22 files changed, 1331 insertions, 923 deletions
@@ -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 |