]> diplodocus.org Git - nmh/blobdiff - sbr/lock_file.c
m_getfld: Shuffle `delim' assignments slightly.
[nmh] / sbr / lock_file.c
index 0e83ac829487c671995f30202d4b9db1b44d1898..9fbcbd78d94dec5320177858f89a58066394dd7e 100644 (file)
@@ -48,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
@@ -85,20 +85,20 @@ 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 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);
@@ -115,7 +115,7 @@ 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");
@@ -130,7 +130,7 @@ lkopendata(const char *file, int access, mode_t mode)
        datalockinit = 1;
     }
 
-    return lkopen(file, access, mode, datalocktype);
+    return lkopen(file, access, mode, datalocktype, failed_to_lock);
 }
 
 
@@ -138,7 +138,7 @@ 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);
@@ -146,7 +146,7 @@ int lkopenspool(const char *file, int access, mode_t mode)
        spoollockinit = 1;
     }
 
-    return lkopen(file, access, mode, spoollocktype);
+    return lkopen(file, access, mode, spoollocktype, failed_to_lock);
 }
 
 
@@ -155,7 +155,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);
@@ -166,7 +166,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) {
@@ -182,6 +182,7 @@ lkfopenspool(const char *file, const char *mode)
 {
     FILE *fp;
     int oflags = str2accbits(mode);
+    int failed_to_lock = 0;
     int fd;
 
     if (oflags == -1) {
@@ -189,7 +190,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) {
@@ -275,20 +276,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;
 }
 
 /*
@@ -296,24 +296,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:
@@ -335,7 +336,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 */
@@ -348,7 +349,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;
@@ -375,17 +376,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;
 
@@ -409,17 +412,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;
 
@@ -461,6 +465,7 @@ lkopen_lockf(const char *file, int access, mode_t mode)
        sleep(1);
     }
 
+    *failed_to_lock = 1;
     errno = saved_errno;
     return -1;
 }
@@ -471,7 +476,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;
@@ -489,46 +494,50 @@ 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);
        }
+
+        *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 */
 }
 
@@ -542,17 +551,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) {
+        advise(NULL, "unable to create temporary file in %s", li->tmplock);
        return -1;
+    }
 
 #if 0
     /* write our process id into lock file */
@@ -566,8 +576,8 @@ 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);
 }
@@ -647,14 +657,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) {
@@ -662,7 +668,6 @@ timerON (char *curlock, int fd)
        SIGNAL (SIGALRM, alrmser);
        alarm (NSECS);
     }
-
     l_top = lp;
 }
 
@@ -741,23 +746,25 @@ init_locktype(const char *lockname)
 {
     if (strcasecmp(lockname, "fcntl") == 0) {
        return FCNTL_LOCKING;
-    } else if (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 (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 (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;
 }