]> diplodocus.org Git - nmh/commitdiff
Merge remote-tracking branch 'origin/fix-locking'
authorDavid Levine <levinedl@acm.org>
Thu, 10 Apr 2014 00:19:26 +0000 (19:19 -0500)
committerDavid Levine <levinedl@acm.org>
Thu, 10 Apr 2014 00:19:26 +0000 (19:19 -0500)
13 files changed:
h/prototypes.h
sbr/context_read.c
sbr/context_save.c
sbr/folder_read.c
sbr/lock_file.c
sbr/seq_read.c
sbr/seq_save.c
uip/annosbr.c
uip/dropsbr.c
uip/mhcachesbr.c
uip/msh.c
uip/new.c
uip/slocal.c

index 7a4f8a3..da5231b 100644 (file)
@@ -178,16 +178,17 @@ int get_term_numcap(char *capability);
  *
  * Files opened for reading are locked with a read lock (if possible by
  * the underlying lock mechanism), files opened for writing are locked
- * using an exclusive lock.
+ * using an exclusive lock.  The int * argument is used to indicate failure
+ * to acquire a lock.
  */
 int lkclosedata(int, const char *);
 int lkclosespool(int, const char *);
 int lkfclosedata(FILE *, const char *);
 int lkfclosespool(FILE *, const char *);
-FILE *lkfopendata(const char *, const char *);
-int lkopendata(const char *, int, mode_t);
+FILE *lkfopendata(const char *, const char *, int *);
+int lkopendata(const char *, int, mode_t, int *);
 FILE *lkfopenspool(const char *, const char *);
-int lkopenspool(const char *, int, mode_t);
+int lkopenspool(const char *, int, mode_t, int *);
 int m_atoi (char *);
 char *m_backup (char *);
 int m_convert (struct msgs *, char *);
@@ -297,8 +298,12 @@ void seq_printall (struct msgs *);
  *               and a pointer to the filehandle will be stored in
  *               folder structure, where it will later be used by
  *               seq_save().
+ *
+ * Return values:
+ *     OK       - successfully read the sequence files, or they don't exist
+ *     NOTOK    - failed to lock sequence file
  */
-void seq_read (struct msgs * mp, int lockflag);
+int seq_read (struct msgs * mp, int lockflag);
 void seq_save (struct msgs *);
 void seq_setcur (struct msgs *, int);
 void seq_setprev (struct msgs *);
index 164f679..8f63fed 100644 (file)
@@ -34,6 +34,7 @@ context_read (void)
     struct     stat            st;             /* stat() results */
     register   struct  passwd  *pw;            /* getpwuid() results */
     register   FILE            *ib;            /* profile and context file pointer */
+    int failed_to_lock = 0;
 
     /*
      *  If this routine _is_ called again (despite the wanings in the
@@ -135,7 +136,7 @@ context_read (void)
     
     ctxpath = getcpy (m_maildir (cp));
 
-    if ((ib = lkfopendata (ctxpath, "r"))) {
+    if ((ib = lkfopendata (ctxpath, "r", &failed_to_lock))) {
        readconfig ((struct node **) 0, ib, cp, 1);
        lkfclosedata (ib, ctxpath);
     }
index 9105a59..7080959 100644 (file)
@@ -23,6 +23,7 @@ context_save (void)
     register struct node *np;
     FILE *out;
     sigset_t set, oset;
+    int failed_to_lock = 0;
     
     /* No context in use -- silently ignore any changes! */
     if (!ctxpath)
@@ -43,8 +44,13 @@ context_save (void)
     sigaddset (&set, SIGTERM);
     sigprocmask (SIG_BLOCK, &set, &oset);
 
-    if (!(out = lkfopendata (ctxpath, "w")))
-       adios (ctxpath, "unable to write");
+    if (!(out = lkfopendata (ctxpath, "w", &failed_to_lock))) {
+       if (failed_to_lock) {
+           adios (ctxpath, "failed to lock");
+       } else {
+           adios (ctxpath, "unable to write");
+       }
+    }
     for (np = m_defs; np; np = np->n_next)
        if (np->n_context)
            fprintf (out, "%s: %s\n", np->n_name, np->n_field);
index 5c52abd..73ffe43 100644 (file)
@@ -165,7 +165,15 @@ folder_read (char *name, int lockflag)
     /*
      * Read and initialize the sequence information.
      */
-    seq_read (mp, lockflag);
+    if (seq_read (mp, lockflag) == NOTOK) {
+        char seqfile[PATH_MAX];
+
+        /* Failed to lock sequence file. */
+        snprintf (seqfile, sizeof(seqfile), "%s/%s", mp->foldpath, mh_seq);
+        advise (seqfile, "failed to lock");
+
+        return NULL;
+    }
 
     return mp;
 }
index 1a562f9..f4d3902 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) {
@@ -296,24 +297,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:
@@ -348,7 +350,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,6 +377,7 @@ lkopen_fcntl(const char *file, int access, mode_t mode)
        sleep(1);
     }
 
+    *failed_to_lock = 1;
     errno = saved_errno;
     return -1;
 }
@@ -386,7 +389,7 @@ lkopen_fcntl(const char *file, int access, mode_t mode)
  */
 
 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;
 
@@ -410,6 +413,7 @@ lkopen_flock(const char *file, int access, mode_t mode)
        sleep(1);
     }
 
+    *failed_to_lock = 1;
     errno = saved_errno;
     return -1;
 }
@@ -420,7 +424,7 @@ lkopen_flock(const char *file, int access, mode_t mode)
  */
 
 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;
 
@@ -462,6 +466,7 @@ lkopen_lockf(const char *file, int access, mode_t mode)
        sleep(1);
     }
 
+    *failed_to_lock = 1;
     errno = saved_errno;
     return -1;
 }
@@ -472,7 +477,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;
@@ -490,7 +495,7 @@ 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) {
            /* attempt to create lock file */
            if (lockit (&lkinfo) == 0) {
                /* if successful, turn on timer and return */
@@ -499,27 +504,30 @@ lkopen_dot (const char *file, int access, mode_t mode)
            } else {
                /*
                 * Abort locking, if we fail to lock after 5 attempts
-                * and are never able to stat the lock file.
+                * 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).
                 */
                struct stat st;
                if (stat (lkinfo.curlock, &st) == -1) {
-                   if (i++ > 5)
-                       return -1;
-                   sleep (5);
+                   if (i++ > 5) break;
+                   sleep (1);
                } else {
                    time_t curtime;
-                   i = 0;
                    time (&curtime);
                    
                    /* check for stale lockfile, else sleep */
                    if (curtime > st.st_ctime + RSECS)
                        (void) m_unlink (lkinfo.curlock);
                    else
-                       sleep (5);
+                       sleep (1);
                }
                lockname (file, &lkinfo, 1);
            }
        }
+
+        *failed_to_lock = 1;
+        return -1;
     }
 #else
     if (lockfile_create(lkinfo.curlock, 5, 0) == L_SUCCESS) {
@@ -528,6 +536,7 @@ lkopen_dot (const char *file, int access, mode_t mode)
     }
     else {
         close(fd);
+       *failed_to_lock = 1;
         return -1;
     }
 #endif /* HAVE_LIBLOCKFILE */
index aeb76fc..9b071a4 100644 (file)
@@ -15,7 +15,7 @@
  * static prototypes
  */
 static int seq_init (struct msgs *, char *, char *);
-static void seq_public (struct msgs *, int);
+static int seq_public (struct msgs *, int, int *);
 static void seq_private (struct msgs *);
 
 
@@ -25,9 +25,11 @@ static void seq_private (struct msgs *);
  * or context file (for private sequences).
  */
 
-void
+int
 seq_read (struct msgs *mp, int lockflag)
 {
+    int failed_to_lock = 0;
+
     /*
      * Initialize the list of sequence names.  Go ahead and
      * add the "cur" sequence to the list of sequences.
@@ -37,13 +39,17 @@ seq_read (struct msgs *mp, int lockflag)
 
     /* If folder is empty, don't scan for sequence information */
     if (mp->nummsg == 0)
-       return;
+       return OK;
 
     /* Initialize the public sequences */
-    seq_public (mp, lockflag);
+    if (seq_public (mp, lockflag, &failed_to_lock) == NOTOK) {
+       if (failed_to_lock) return NOTOK;
+    }
 
     /* Initialize the private sequences */
     seq_private (mp);
+
+    return OK;
 }
 
 
@@ -51,8 +57,8 @@ seq_read (struct msgs *mp, int lockflag)
  * read folder's sequences file for public sequences
  */
 
-static void
-seq_public (struct msgs *mp, int lockflag)
+static int
+seq_public (struct msgs *mp, int lockflag, int *failed_to_lock)
 {
     int state;
     char *cp, seqfile[PATH_MAX];
@@ -66,13 +72,14 @@ seq_public (struct msgs *mp, int lockflag)
      * then just return, and do not initialize any public sequences.
      */
     if (mh_seq == NULL || *mh_seq == '\0')
-       return;
+       return OK;
 
     /* get filename of sequence file */
     snprintf (seqfile, sizeof(seqfile), "%s/%s", mp->foldpath, mh_seq);
 
-    if ((fp = lkfopendata (seqfile, lockflag ? "r+" : "r")) == NULL)
-       return;
+    if ((fp = lkfopendata (seqfile, lockflag ? "r+" : "r", failed_to_lock))
+       == NULL)
+       return NOTOK;
 
     /* Use m_getfld to scan sequence file */
     for (;;) {
@@ -116,6 +123,8 @@ seq_public (struct msgs *mp, int lockflag)
     } else {
        lkfclosedata (fp, seqfile);
     }
+
+    return OK;
 }
 
 
index 5b06dcd..5148f74 100644 (file)
@@ -77,6 +77,8 @@ priv:
            context_del (attr);                 /* delete sequence from context */
 
            if (!fp) {
+               int failed_to_lock = 0;
+
                /*
                 * Attempt to open file for public sequences.
                 * If that fails (probably because folder is
@@ -90,10 +92,16 @@ priv:
                    mp->seqname = NULL;
                    rewind(fp);
                    ftruncate(fileno(fp), 0);
-               } else if ((fp = lkfopendata (seqfile, "w")) == NULL
+               } else if ((fp = lkfopendata (seqfile, "w", &failed_to_lock))
+                          == NULL
                        && (m_unlink (seqfile) == -1 ||
-                           (fp = lkfopendata (seqfile, "w")) == NULL)) {
-                   admonish (attr, "unable to write");
+                           (fp = lkfopendata (seqfile, "w", &failed_to_lock))
+                           == NULL)) {
+                   if (failed_to_lock) {
+                       admonish (attr, "unable to lock");
+                   } else {
+                       admonish (attr, "unable to write");
+                   }
                    goto priv;
                }
 
index 88c90f4..a73c827 100644 (file)
@@ -32,15 +32,20 @@ annotate (char *file, char *comp, char *text, int inplace, int datesw, int delet
     int                        i, fd;
     struct utimbuf     b;
     struct stat                s;
+    int                        failed_to_lock = 0;
 
     /* open and lock the file to be annotated */
-    if ((fd = lkopendata (file, O_RDWR, 0)) == NOTOK) {
+    if ((fd = lkopendata (file, O_RDWR, 0, &failed_to_lock)) == NOTOK) {
        switch (errno) {
            case ENOENT:
                break;
 
            default:
-               admonish (file, "unable to lock and open");
+               if (failed_to_lock) {
+                   admonish (file, "unable to lock");
+               } else {
+                   admonish (file, "unable to open");
+               }
                break;
        }
        return 1;
index da2752d..915e71e 100644 (file)
@@ -47,26 +47,16 @@ mbx_open (char *file, int mbx_style, uid_t uid, gid_t gid, mode_t mode)
 
     /* attempt to open and lock file */
     for (count = 4; count > 0; count--) {
+        int failed_to_lock = 0;
        if ((fd = lkopenspool (file, O_RDWR | O_CREAT |
-                              O_NONBLOCK, mode)) == NOTOK) {
-           switch (errno) {
-#if defined(FCNTL_LOCKING) || defined(LOCKF_LOCKING)
-               case EACCES:
-               case EAGAIN:
-#endif
-
-#ifdef FLOCK_LOCKING
-               case EWOULDBLOCK:
-#endif
-               case ETXTBSY: 
-                   j = errno;
-                   sleep (5);
-                   continue;
-
-               default: 
-                   /* just return error */
-                   return NOTOK;
-           }
+                              O_NONBLOCK, mode, &failed_to_lock)) == NOTOK) {
+            if (failed_to_lock) {
+                j = errno;
+                sleep (5);
+                continue;
+            } else {
+                return NOTOK;
+            }
        }
 
        /* good file descriptor */
index 7e684e1..7814d6e 100644 (file)
@@ -279,6 +279,7 @@ find_cache_aux (int writing, char *directory, char *id,
     int        mask, usemap;
     char mapfile[BUFSIZ], mapname[BUFSIZ];
     FILE *fp;
+    int failed_to_lock = 0;
     static int partno, pid;
     static time_t clock = 0;
 
@@ -333,12 +334,15 @@ use_raw:
 
     make_intermediates (mapfile);
     mask = umask (writing == 2 ? 0077 : 0);
-    if (!(fp = lkfopendata (mapfile, "a")) && errno == ENOENT) {
+    if (!(fp = lkfopendata (mapfile, "a", &failed_to_lock)) && errno == ENOENT) {
        int fd;
 
        if ((fd = creat (mapfile, 0666)) != NOTOK) {
            close (fd);
-           fp = lkfopendata (mapfile, "a");
+           fp = lkfopendata (mapfile, "a", &failed_to_lock);
+            if (failed_to_lock) {
+               adios (mapfile, "failed to lock");
+            }
        }
     }
     umask (mask);
@@ -366,8 +370,9 @@ find_cache_aux2 (char *mapfile, char *id, char *mapname, int namelen)
     char buf[BUFSIZ], name[NAMESZ];
     FILE *fp;
     m_getfld_state_t gstate = 0;
+    int failed_to_lock = 0;
 
-    if (!(fp = lkfopendata (mapfile, "r")))
+    if (!(fp = lkfopendata (mapfile, "r", &failed_to_lock)))
        return NOTOK;
 
     for (;;) {
index e91924c..86855a4 100644 (file)
--- a/uip/msh.c
+++ b/uip/msh.c
@@ -1079,6 +1079,7 @@ quit (void)
     char map1[BUFSIZ], map2[BUFSIZ];
     struct stat st;
     FILE *dp;
+    int failed_to_lock = 0;
 
     if (!(mp->msgflags & MODIFIED) || is_readonly(mp) || fmsh) {
            if (vmh)
@@ -1089,7 +1090,7 @@ quit (void)
     if (vmh) 
        ttyNaux (NULLCMD, "FAST");
     cp = NULL;
-    if ((dp = lkfopendata (mp->foldpath, "r")) == NULL) {
+    if ((dp = lkfopendata (mp->foldpath, "r", &failed_to_lock)) == NULL) {
        advise (mp->foldpath, "unable to lock");
        if (vmh) {
            ttyR (NULLCMD);
index 6f99825..8d235b1 100644 (file)
--- a/uip/new.c
+++ b/uip/new.c
@@ -95,6 +95,7 @@ get_msgnums(char *folder, char *sequences[])
     char name[NAMESZ], field[BUFSIZ];
     char *cp;
     char *msgnums = NULL, *this_msgnums, *old_msgnums;
+    int failed_to_lock = 0;
     m_getfld_state_t gstate = 0;
 
     /* copied from seq_read.c:seq_public */
@@ -112,9 +113,14 @@ get_msgnums(char *folder, char *sequences[])
     if (seqfile == NULL)
        return NULL;
 
-    if ((fp = lkfopendata (seqfile, "r")) == NULL) {
+    if ((fp = lkfopendata (seqfile, "r", & failed_to_lock)) == NULL) {
        free(seqfile);
-       return NULL;
+
+       if (failed_to_lock) {
+           adios (seqfile, "failed to lock");
+       } else {
+           return NULL;
+       }
     }
 
     /* Use m_getfld to scan sequence file */
index fb21c88..ff3cabf 100644 (file)
@@ -1414,6 +1414,7 @@ suppress_duplicates (int fd, char *file)
     rewind (in);
 
     for (;;) {
+        int failed_to_lock = 0;
        int bufsz = sizeof buf;
        state = m_getfld (&gstate, name, buf, &bufsz, in);
        switch (state) {
@@ -1451,7 +1452,8 @@ suppress_duplicates (int fd, char *file)
                 * This will fail if your Maildelivery file doesn't
                 * exist.
                 */
-               if ((lockfd = lkopendata(file, O_RDWR, 0)) == -1) {
+               if ((lockfd = lkopendata(file, O_RDWR, 0, &failed_to_lock))
+                   == -1) {
                    advise (file, "unable to perform file locking on");
                    free (cp);
                    fclose (in);