From: David Levine Date: Thu, 10 Apr 2014 00:19:26 +0000 (-0500) Subject: Merge remote-tracking branch 'origin/fix-locking' X-Git-Url: https://diplodocus.org/git/nmh/commitdiff_plain/19bf8698eeb0ab3d7694232af115fa3f007d5c7b?hp=6e947201b6ff99371295c3b84b69066cba91549e Merge remote-tracking branch 'origin/fix-locking' --- diff --git a/h/prototypes.h b/h/prototypes.h index 7a4f8a38..da5231ba 100644 --- a/h/prototypes.h +++ b/h/prototypes.h @@ -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 *); diff --git a/sbr/context_read.c b/sbr/context_read.c index 164f6794..8f63fedf 100644 --- a/sbr/context_read.c +++ b/sbr/context_read.c @@ -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); } diff --git a/sbr/context_save.c b/sbr/context_save.c index 9105a596..70809595 100644 --- a/sbr/context_save.c +++ b/sbr/context_save.c @@ -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); diff --git a/sbr/folder_read.c b/sbr/folder_read.c index 5c52abde..73ffe431 100644 --- a/sbr/folder_read.c +++ b/sbr/folder_read.c @@ -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; } diff --git a/sbr/lock_file.c b/sbr/lock_file.c index 1a562f9b..f4d3902b 100644 --- a/sbr/lock_file.c +++ b/sbr/lock_file.c @@ -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 */ diff --git a/sbr/seq_read.c b/sbr/seq_read.c index aeb76fc1..9b071a4e 100644 --- a/sbr/seq_read.c +++ b/sbr/seq_read.c @@ -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; } diff --git a/sbr/seq_save.c b/sbr/seq_save.c index 5b06dcdf..5148f745 100644 --- a/sbr/seq_save.c +++ b/sbr/seq_save.c @@ -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; } diff --git a/uip/annosbr.c b/uip/annosbr.c index 88c90f44..a73c8277 100644 --- a/uip/annosbr.c +++ b/uip/annosbr.c @@ -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; diff --git a/uip/dropsbr.c b/uip/dropsbr.c index da2752d1..915e71e6 100644 --- a/uip/dropsbr.c +++ b/uip/dropsbr.c @@ -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 */ diff --git a/uip/mhcachesbr.c b/uip/mhcachesbr.c index 7e684e1f..7814d6ee 100644 --- a/uip/mhcachesbr.c +++ b/uip/mhcachesbr.c @@ -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 (;;) { diff --git a/uip/msh.c b/uip/msh.c index e91924c3..86855a4f 100644 --- 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); diff --git a/uip/new.c b/uip/new.c index 6f998252..8d235b17 100644 --- 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 */ diff --git a/uip/slocal.c b/uip/slocal.c index fb21c880..ff3cabf8 100644 --- a/uip/slocal.c +++ b/uip/slocal.c @@ -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);