* lock.c -- routines to lock/unlock files
*
* $Id$
+ *
+ * This code is Copyright (c) 2002, by the authors of nmh. See the
+ * COPYRIGHT file in the root directory of the nmh distribution for
+ * complete copyright information.
*/
+/* Modified by Ruud de Rooij to support Miquel van Smoorenburg's liblockfile
+ *
+ * Since liblockfile locking shares most of its code with dot locking, it
+ * is enabled by defining both DOT_LOCKING and HAVE_LIBLOCKFILE.
+ *
+ * Ruud de Rooij <ruud@debian.org> Sun, 28 Mar 1999 15:34:03 +0200
+ */
+
#include <h/mh.h>
#include <h/signals.h>
+#include <h/utils.h>
+
+#ifdef TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# ifdef TM_IN_SYS_TIME
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
#ifdef HAVE_ERRNO_H
# include <errno.h>
#endif
-#ifdef MMDFONLY
-# include <mmdfonly.h>
-# include <lockonly.h>
-#endif /* MMDFONLY */
-
#ifdef HAVE_FCNTL_H
# include <fcntl.h>
#else
#include <signal.h>
-extern int errno;
+#if defined(HAVE_LIBLOCKFILE)
+#include <lockfile.h>
+#endif
#ifdef LOCKDIR
char *lockdir = LOCKDIR;
/* struct for getting name of lock file to create */
struct lockinfo {
char curlock[BUFSIZ];
+#if !defined(HAVE_LIBLOCKFILE)
char tmplock[BUFSIZ];
+#endif
};
/*
*/
#define NSECS 20
+#if !defined(HAVE_LIBLOCKFILE)
/*
* How old does a lock file need to be
* before we remove it.
*/
#define RSECS 180
+#endif /* HAVE_LIBLOCKFILE */
/* struct for recording and updating locks */
struct lock {
#ifdef DOT_LOCKING
static int lkopen_dot (char *, int, mode_t);
-static int lockit (struct lockinfo *);
static void lockname (char *, struct lockinfo *, int);
static void timerON (char *, int);
static void timerOFF (int);
static RETSIGTYPE alrmser (int);
#endif
+#if !defined(HAVE_LIBLOCKFILE)
+static int lockit (struct lockinfo *);
+#endif
/*
* Base routine to open and lock a file,
#ifdef DOT_LOCKING
lockname (file, &lkinfo, 0); /* get name of lock file */
+#if !defined(HAVE_LIBLOCKFILE)
unlink (lkinfo.curlock); /* remove lock file */
+#else
+ lockfile_remove(lkinfo.curlock);
+#endif /* HAVE_LIBLOCKFILE */
timerOFF (fd); /* turn off lock timer */
-#endif
+#endif /* DOT_LOCKING */
return (close (fd));
}
if (strcmp (mode, "r") == 0)
access = O_RDONLY;
- else
+ else if (strcmp (mode, "r+") == 0)
access = O_RDWR;
+ else if (strcmp (mode, "w") == 0)
+ access = O_WRONLY | O_CREAT | O_TRUNC;
+ else if (strcmp (mode, "w+") == 0)
+ access = O_RDWR | O_CREAT | O_TRUNC;
+ else if (strcmp (mode, "a") == 0)
+ access = O_WRONLY | O_CREAT | O_APPEND;
+ else if (strcmp (mode, "a+") == 0)
+ access = O_RDWR | O_CREAT | O_APPEND;
+ else {
+ errno = EINVAL;
+ return NULL;
+ }
- if ((fd = lkopen (file, access, 0)) == -1)
+ if ((fd = lkopen (file, access, 0666)) == -1)
return NULL;
if ((fp = fdopen (fd, mode)) == NULL) {
#ifdef DOT_LOCKING
lockname (file, &lkinfo, 0); /* get name of lock file */
+#if !defined(HAVE_LIBLOCKFILE)
unlink (lkinfo.curlock); /* remove lock file */
+#else
+ lockfile_remove(lkinfo.curlock);
+#endif /* HAVE_LIBLOCKFILE */
timerOFF (fileno(fp)); /* turn off lock timer */
-#endif
+#endif /* DOT_LOCKING */
return (fclose (fp));
}
# endif
# ifdef FLOCK_LOCKING
- if (flock (fd, LOCK_EX | LOCK_NB) != -1)
+ if (flock (fd, (((access & 03) == O_RDONLY) ? LOCK_SH : LOCK_EX)
+ | LOCK_NB) != -1)
return fd;
# endif
static int
lkopen_dot (char *file, int access, mode_t mode)
{
- int i, fd;
- time_t curtime;
+ int fd;
struct lockinfo lkinfo;
- struct stat st;
/* open the file */
if ((fd = open (file, access, mode)) == -1)
*/
lockname (file, &lkinfo, 1);
- for (i = 0;;) {
- /* attempt to create lock file */
- if (lockit (&lkinfo) == 0) {
- /* if successful, turn on timer and return */
- timerON (lkinfo.curlock, fd);
- return fd;
- } else {
- /*
- * Abort locking, if we fail to lock after 5 attempts
- * and are never able to stat the lock file.
- */
- if (stat (lkinfo.curlock, &st) == -1) {
- if (i++ > 5)
- return -1;
- sleep (5);
+#if !defined(HAVE_LIBLOCKFILE)
+ {
+ int i;
+ for (i = 0;;) {
+ /* attempt to create lock file */
+ if (lockit (&lkinfo) == 0) {
+ /* if successful, turn on timer and return */
+ timerON (lkinfo.curlock, fd);
+ return fd;
} else {
- i = 0;
- time (&curtime);
-
- /* check for stale lockfile, else sleep */
- if (curtime > st.st_ctime + RSECS)
- unlink (lkinfo.curlock);
- else
+ /*
+ * Abort locking, if we fail to lock after 5 attempts
+ * and are never able to stat the lock file.
+ */
+ struct stat st;
+ if (stat (lkinfo.curlock, &st) == -1) {
+ if (i++ > 5)
+ return -1;
sleep (5);
+ } else {
+ time_t curtime;
+ i = 0;
+ time (&curtime);
+
+ /* check for stale lockfile, else sleep */
+ if (curtime > st.st_ctime + RSECS)
+ unlink (lkinfo.curlock);
+ else
+ sleep (5);
+ }
+ lockname (file, &lkinfo, 1);
}
}
}
+#else
+ if (lockfile_create(lkinfo.curlock, 5, 0) == L_SUCCESS) {
+ timerON(lkinfo.curlock, fd);
+ return fd;
+ }
+ else {
+ close(fd);
+ return -1;
+ }
+#endif /* HAVE_LIBLOCKFILE */
}
+#if !defined(HAVE_LIBLOCKFILE)
/*
* Routine that actually tries to create
* the lock file.
curlock = li->curlock;
tmplock = li->tmplock;
+#ifdef HAVE_MKSTEMP
+ if ((fd = mkstemp(tmplock)) == -1)
+ return -1;
+#else
+ if (mktemp(tmplock) == NULL)
+ return -1;
+ if (unlink(tmplock) == -1 && errno != ENOENT)
+ return -1;
/* create the temporary lock file */
if ((fd = creat(tmplock, 0600)) == -1)
return -1;
+#endif
#if 0
/* write our process id into lock file */
return (fd == -1 ? -1 : 0);
}
+#endif /* HAVE_LIBLOCKFILE */
/*
* Get name of lock file, and temporary lock file
bplen += tmplen;
#else
if (cp != file) {
- snprintf (bp, sizeof(li->curlock), "%.*s", cp - file, file);
+ snprintf (bp, sizeof(li->curlock), "%.*s", (int)(cp - file), file);
tmplen = strlen (bp);
bp += tmplen;
bplen += tmplen;
snprintf (bp, sizeof(li->curlock) - bplen, "%s.lock", cp);
+#if !defined(HAVE_LIBLOCKFILE)
/*
* If this is for a new lock, create a name for
* the temporary lock file for lockit()
strncpy (li->tmplock, ",LCK.XXXXXX", sizeof(li->tmplock));
else
snprintf (li->tmplock, sizeof(li->tmplock), "%.*s,LCK.XXXXXX",
- cp - li->curlock, li->curlock);
-/*
- Mkstemp work postponed until later -Doug
-#ifdef HAVE_MKSTEMP
- mkstemp (li->tmplock);
-#else
-*/
- mktemp (li->tmplock);
-/*
-#endif
-*/
-
- unlink (li->tmplock); /* remove any stray */
+ (int)(cp - li->curlock), li->curlock);
}
+#endif
}
struct lock *lp;
size_t len;
- if (!(lp = (struct lock *) malloc (sizeof(*lp))))
- return;
+ lp = (struct lock *) mh_xmalloc (sizeof(*lp));
len = strlen(curlock) + 1;
lp->l_fd = fd;
- if (!(lp->l_lock = malloc (len))) {
- free ((char *) lp);
- return;
- }
+ lp->l_lock = mh_xmalloc (len);
memcpy (lp->l_lock, curlock, len);
lp->l_next = l_top;
static RETSIGTYPE
alrmser (int sig)
{
- int j;
char *lockfile;
struct lock *lp;
/* update the ctime of all the lock files */
for (lp = l_top; lp; lp = lp->l_next) {
lockfile = lp->l_lock;
- if (*lockfile && (j = creat (lockfile, 0600)) != -1)
- close (j);
+#if !defined(HAVE_LIBLOCKFILE)
+ {
+ int j;
+ if (*lockfile && (j = creat (lockfile, 0600)) != -1)
+ close (j);
+ }
+#else
+ lockfile_touch(lockfile);
+#endif
}
/* restart the alarm */