]> diplodocus.org Git - nmh/blobdiff - sbr/lock_file.c
Fix invalid pointer arithmetic.
[nmh] / sbr / lock_file.c
index 987b922ced9076b12879a6a65dd56db825b03909..2c8b1c7531ae9ea286de318e1bd52c88d119c894 100644 (file)
@@ -1,6 +1,4 @@
-
-/*
- * lock.c -- routines to lock/unlock files
+/* lock_file.c -- routines to lock/unlock files
  *
  * This code is Copyright (c) 2002, by the authors of nmh.  See the
  * COPYRIGHT file in the root directory of the nmh distribution for
 #include <h/signals.h>
 #include <h/utils.h>
 #include <h/mts.h>
+#include "lock_file.h"
+#include "m_mktemp.h"
 
 #ifdef HAVE_SYS_TIME_H
 # include <sys/time.h>
 #endif
 #include <time.h>
-#include <errno.h>
 #include <fcntl.h>
 #ifdef HAVE_FLOCK
 # include <sys/file.h>
 #endif
-#ifdef HAVE_LOCKF
-# include <unistd.h>
-#endif
-
-#include <signal.h>
 
 #if defined(HAVE_LIBLOCKFILE)
-#include <lockfile.h>
+# include <lockfile.h>
 #endif
 
 #ifdef LOCKDIR
@@ -54,7 +48,7 @@ struct lockinfo {
 /*
  * Number of tries to retry locking
  */
-#define LOCK_RETRIES 5
+#define LOCK_RETRIES 60
 
 /*
  * Amount of time to wait before
@@ -79,32 +73,26 @@ struct lock {
 
 enum locktype { FCNTL_LOCKING, FLOCK_LOCKING, LOCKF_LOCKING, DOT_LOCKING };
 
-/*
- * Flags to indicate whether we've initialized the lock types, and
- * our saved lock types
- */
-static int datalockinit = 0;
-static int spoollockinit = 0;
+/* Our saved lock types. */
 static enum locktype datalocktype, spoollocktype;
 
-
 /* top of list containing all open locks */
 static struct lock *l_top = NULL;
 
-static int lkopen(const char *, int, mode_t, enum locktype);
+static int lkopen(const char *, int, mode_t, enum locktype, int *);
 static int str2accbits(const char *);
 
-static int lkopen_fcntl (const char *, int, mode_t);
+static int lkopen_fcntl (const char *, int, mode_t, int *);
 #ifdef HAVE_LOCKF
-static int lkopen_lockf (const char *, int, mode_t);
+static int lkopen_lockf (const char *, int, mode_t, int *);
 #endif /* HAVE_LOCKF */
 #ifdef HAVE_FLOCK
-static int lkopen_flock (const char *, int, mode_t);
+static int lkopen_flock (const char *, int, mode_t, int *);
 #endif /* HAVE_FLOCK */
 
-static enum locktype init_locktype(const char *);
+static enum locktype init_locktype(const char *) PURE;
 
-static int lkopen_dot (const char *, int, mode_t);
+static int lkopen_dot (const char *, int, mode_t, int *);
 static void lkclose_dot (int, const char *);
 static void lockname (const char *, struct lockinfo *, int);
 static void timerON (char *, int);
@@ -121,22 +109,23 @@ static int lockit (struct lockinfo *);
  */
 
 int
-lkopendata(const char *file, int access, mode_t mode)
+lkopendata(const char *file, int access, mode_t mode, int *failed_to_lock)
 {
-    if (! datalockinit) {
-       char *cp = context_find("datalocking");
+    static bool deja_vu;
+
+    if (!deja_vu) {
+        char *dl;
 
-       if (cp) {
-           datalocktype = init_locktype(cp);
+        deja_vu = true;
+       if ((dl = context_find("datalocking"))) {
+           datalocktype = init_locktype(dl);
        } else {
            /* We default to fcntl locking for data files */
            datalocktype = FCNTL_LOCKING;
        }
-
-       datalockinit = 1;
     }
 
-    return lkopen(file, access, mode, datalocktype);
+    return lkopen(file, access, mode, datalocktype, failed_to_lock);
 }
 
 
@@ -144,15 +133,16 @@ lkopendata(const char *file, int access, mode_t mode)
  * Locking using the spool locking algorithm
  */
 
-int lkopenspool(const char *file, int access, mode_t mode)
+int lkopenspool(const char *file, int access, mode_t mode, int *failed_to_lock)
 {
-    if (! spoollockinit) {
-       spoollocktype = init_locktype(spoollocking);
+    static bool deja_vu;
 
-       spoollockinit = 1;
+    if (!deja_vu) {
+       deja_vu = true;
+        spoollocktype = init_locktype(spoollocking);
     }
 
-    return lkopen(file, access, mode, spoollocktype);
+    return lkopen(file, access, mode, spoollocktype, failed_to_lock);
 }
 
 
@@ -161,7 +151,7 @@ int lkopenspool(const char *file, int access, mode_t mode)
  */
 
 FILE *
-lkfopendata(const char *file, const char *mode)
+lkfopendata(const char *file, const char *mode, int *failed_to_lock)
 {
     FILE *fp;
     int oflags = str2accbits(mode);
@@ -172,7 +162,7 @@ lkfopendata(const char *file, const char *mode)
        return NULL;
     }
 
-    if ((fd = lkopendata(file, oflags, 0666)) == -1)
+    if ((fd = lkopendata(file, oflags, 0666, failed_to_lock)) == -1)
        return NULL;
 
     if ((fp = fdopen (fd, mode)) == NULL) {
@@ -188,6 +178,7 @@ lkfopenspool(const char *file, const char *mode)
 {
     FILE *fp;
     int oflags = str2accbits(mode);
+    int failed_to_lock = 0;
     int fd;
 
     if (oflags == -1) {
@@ -195,7 +186,7 @@ lkfopenspool(const char *file, const char *mode)
        return NULL;
     }
 
-    if ((fd = lkopenspool(file, oflags, 0666)) == -1)
+    if ((fd = lkopenspool(file, oflags, 0666, &failed_to_lock)) == -1)
        return NULL;
 
     if ((fp = fdopen (fd, mode)) == NULL) {
@@ -281,20 +272,19 @@ str2accbits(const char *mode)
 {
     if (strcmp (mode, "r") == 0)
        return O_RDONLY;
-    else if (strcmp (mode, "r+") == 0)
+    if (strcmp (mode, "r+") == 0)
        return O_RDWR;
-    else if (strcmp (mode, "w") == 0)
+    if (strcmp (mode, "w") == 0)
        return O_WRONLY | O_CREAT | O_TRUNC;
-    else if (strcmp (mode, "w+") == 0)
+    if (strcmp (mode, "w+") == 0)
        return O_RDWR | O_CREAT | O_TRUNC;
-    else if (strcmp (mode, "a") == 0)
+    if (strcmp (mode, "a") == 0)
        return O_WRONLY | O_CREAT | O_APPEND;
-    else if (strcmp (mode, "a+") == 0)
+    if (strcmp (mode, "a+") == 0)
        return O_RDWR | O_CREAT | O_APPEND;
-    else {
-       errno = EINVAL;
-       return -1;
-    }
+
+    errno = EINVAL;
+    return -1;
 }
 
 /*
@@ -302,24 +292,25 @@ str2accbits(const char *mode)
  */
 
 static int
-lkopen (const char *file, int access, mode_t mode, enum locktype ltype)
+lkopen (const char *file, int access, mode_t mode, enum locktype ltype,
+        int *failed_to_lock)
 {
     switch (ltype) {
 
     case FCNTL_LOCKING:
-       return lkopen_fcntl(file, access, mode);
+       return lkopen_fcntl(file, access, mode, failed_to_lock);
 
     case DOT_LOCKING:
-       return lkopen_dot(file, access, mode);
+       return lkopen_dot(file, access, mode, failed_to_lock);
 
 #ifdef HAVE_FLOCK
     case FLOCK_LOCKING:
-       return lkopen_flock(file, access, mode);
+       return lkopen_flock(file, access, mode, failed_to_lock);
 #endif /* HAVE_FLOCK */
 
 #ifdef HAVE_LOCKF
     case LOCKF_LOCKING:
-       return lkopen_lockf(file, access, mode);
+       return lkopen_lockf(file, access, mode, failed_to_lock);
 #endif /* HAVE_FLOCK */
 
     default:
@@ -341,7 +332,7 @@ lkclose_dot (int fd, const char *file)
 
     lockname (file, &lkinfo, 0);       /* get name of lock file */
 #if !defined(HAVE_LIBLOCKFILE)
-    unlink (lkinfo.curlock);           /* remove lock file      */
+    (void) m_unlink (lkinfo.curlock);  /* remove lock file      */
 #else
     lockfile_remove(lkinfo.curlock);
 #endif /* HAVE_LIBLOCKFILE */
@@ -354,7 +345,7 @@ lkclose_dot (int fd, const char *file)
  */
 
 static int
-lkopen_fcntl(const char *file, int access, mode_t mode)
+lkopen_fcntl(const char *file, int access, mode_t mode, int *failed_to_lock)
 {
     int fd, i, saved_errno;
     struct flock flk;
@@ -381,17 +372,19 @@ lkopen_fcntl(const char *file, int access, mode_t mode)
        sleep(1);
     }
 
+    *failed_to_lock = 1;
     errno = saved_errno;
     return -1;
 }
 
 
+#ifdef HAVE_FLOCK
 /*
  * Open and lock a file, using flock locking
  */
 
 static int
-lkopen_flock(const char *file, int access, mode_t mode)
+lkopen_flock(const char *file, int access, mode_t mode, int *failed_to_lock)
 {
     int fd, i, saved_errno, locktype;
 
@@ -415,17 +408,18 @@ lkopen_flock(const char *file, int access, mode_t mode)
        sleep(1);
     }
 
+    *failed_to_lock = 1;
     errno = saved_errno;
     return -1;
 }
-
+#endif /* HAVE_FLOCK */
 
 /*
  * Open and lock a file, using lockf locking
  */
 
 static int
-lkopen_lockf(const char *file, int access, mode_t mode)
+lkopen_lockf(const char *file, int access, mode_t mode, int *failed_to_lock)
 {
     int fd, i, saved_errno, saved_access;
 
@@ -467,6 +461,7 @@ lkopen_lockf(const char *file, int access, mode_t mode)
        sleep(1);
     }
 
+    *failed_to_lock = 1;
     errno = saved_errno;
     return -1;
 }
@@ -477,7 +472,7 @@ lkopen_lockf(const char *file, int access, mode_t mode)
  */
 
 static int
-lkopen_dot (const char *file, int access, mode_t mode)
+lkopen_dot (const char *file, int access, mode_t mode, int *failed_to_lock)
 {
     int fd;
     struct lockinfo lkinfo;
@@ -495,46 +490,51 @@ lkopen_dot (const char *file, int access, mode_t mode)
 #if !defined(HAVE_LIBLOCKFILE)
     {
        int i;
-       for (i = 0;;) {
+       for (i = 0; i < LOCK_RETRIES; ++i) {
+            struct stat st;
+
            /* 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.
-                */
-               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);
            }
+
+            /*
+             * Abort locking, if we fail to lock after 5 attempts
+             * and are never able to stat the lock file.  Or, if
+             * we can stat the lockfile but exceed LOCK_RETRIES
+             * seconds waiting for it (by falling out of the loop).
+             */
+            if (stat (lkinfo.curlock, &st) == -1) {
+                if (i++ > 5) break;
+                sleep (1);
+            } else {
+                time_t curtime;
+                time (&curtime);
+                
+                /* check for stale lockfile, else sleep */
+                if (curtime > st.st_ctime + RSECS)
+                    (void) m_unlink (lkinfo.curlock);
+                else
+                    sleep (1);
+            }
+            lockname (file, &lkinfo, 1);
        }
+
+        close(fd);
+        *failed_to_lock = 1;
+        return -1;
     }
 #else
     if (lockfile_create(lkinfo.curlock, 5, 0) == L_SUCCESS) {
         timerON(lkinfo.curlock, fd);
         return fd;
     }
-    else {
-        close(fd);
-        return -1;
-    }
+
+    close(fd);
+    *failed_to_lock = 1;
+    return -1;
 #endif /* HAVE_LIBLOCKFILE */
 }
 
@@ -548,17 +548,18 @@ static int
 lockit (struct lockinfo *li)
 {
     int fd;
-    char *curlock, *tmplock;
+    char *curlock, *tmpfile;
 
 #if 0
     char buffer[128];
 #endif
 
     curlock = li->curlock;
-    tmplock = li->tmplock;
 
-    if ((fd = mkstemp(tmplock)) == -1)
+    if ((tmpfile = m_mktemp(li->tmplock, &fd, NULL)) == NULL) {
+        inform("unable to create temporary file in %s", li->tmplock);
        return -1;
+    }
 
 #if 0
     /* write our process id into lock file */
@@ -572,10 +573,10 @@ lockit (struct lockinfo *li)
      * Now try to create the real lock file
      * by linking to the temporary file.
      */
-    fd = link(tmplock, curlock);
-    unlink(tmplock);
+    fd = link(tmpfile, curlock);
+    (void) m_unlink(tmpfile);
 
-    return (fd == -1 ? -1 : 0);
+    return fd == -1 ? -1 : 0;
 }
 #endif /* HAVE_LIBLOCKFILE */
 
@@ -628,7 +629,9 @@ lockname (const char *file, struct lockinfo *li, int isnewlock)
 
     snprintf (bp, sizeof(li->curlock) - bplen, "%s.lock", cp);
 
-#if !defined(HAVE_LIBLOCKFILE)
+#if defined(HAVE_LIBLOCKFILE)
+    NMH_UNUSED(isnewlock);
+#else
     /*
      * If this is for a new lock, create a name for
      * the temporary lock file for lockit()
@@ -653,14 +656,10 @@ static void
 timerON (char *curlock, int fd)
 {
     struct lock *lp;
-    size_t len;
-
-    lp = (struct lock *) mh_xmalloc (sizeof(*lp));
 
-    len = strlen(curlock) + 1;
+    NEW(lp);
+    lp->l_lock = mh_xstrdup(curlock);
     lp->l_fd = fd;
-    lp->l_lock = mh_xmalloc (len);
-    memcpy (lp->l_lock, curlock, len);
     lp->l_next = l_top;
 
     if (!l_top) {
@@ -668,7 +667,6 @@ timerON (char *curlock, int fd)
        SIGNAL (SIGALRM, alrmser);
        alarm (NSECS);
     }
-
     l_top = lp;
 }
 
@@ -745,25 +743,27 @@ alrmser (int sig)
 static enum locktype
 init_locktype(const char *lockname)
 {
-    if (mh_strcasecmp(lockname, "fcntl") == 0) {
+    if (strcasecmp(lockname, "fcntl") == 0) {
        return FCNTL_LOCKING;
-    } else if (mh_strcasecmp(lockname, "lockf") == 0) {
+    }
+    if (strcasecmp(lockname, "lockf") == 0) {
 #ifdef HAVE_LOCKF
        return LOCKF_LOCKING;
 #else /* ! HAVE_LOCKF */
        adios(NULL, "lockf not supported on this system");
 #endif /* HAVE_LOCKF */
-    } else if (mh_strcasecmp(lockname, "flock") == 0) {
+    }
+    if (strcasecmp(lockname, "flock") == 0) {
 #ifdef HAVE_FLOCK
        return FLOCK_LOCKING;
 #else /* ! HAVE_FLOCK */
        adios(NULL, "flock not supported on this system");
 #endif /* HAVE_FLOCK */
-    } else if (mh_strcasecmp(lockname, "dot") == 0) {
+    }
+    if (strcasecmp(lockname, "dot") == 0) {
        return DOT_LOCKING;
-    } else {
-       adios(NULL, "Unknown lock type: \"%s\"", lockname);
-       /* NOTREACHED */
-       return 0;
     }
+    adios(NULL, "Unknown lock type: \"%s\"", lockname);
+    /* NOTREACHED */
+    return 0;
 }