*
* 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 *);
* 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 *);
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
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);
}
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)
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);
/*
* 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;
}
/*
* Number of tries to retry locking
*/
-#define LOCK_RETRIES 5
+#define LOCK_RETRIES 60
/*
* Amount of time to wait before
/* 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);
*/
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");
datalockinit = 1;
}
- return lkopen(file, access, mode, datalocktype);
+ return lkopen(file, access, mode, datalocktype, failed_to_lock);
}
* 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);
spoollockinit = 1;
}
- return lkopen(file, access, mode, spoollocktype);
+ return lkopen(file, access, mode, spoollocktype, failed_to_lock);
}
*/
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);
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) {
{
FILE *fp;
int oflags = str2accbits(mode);
+ int failed_to_lock = 0;
int fd;
if (oflags == -1) {
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) {
*/
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:
*/
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;
sleep(1);
}
+ *failed_to_lock = 1;
errno = saved_errno;
return -1;
}
*/
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;
sleep(1);
}
+ *failed_to_lock = 1;
errno = saved_errno;
return -1;
}
*/
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;
sleep(1);
}
+ *failed_to_lock = 1;
errno = saved_errno;
return -1;
}
*/
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;
#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 */
} 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) {
}
else {
close(fd);
+ *failed_to_lock = 1;
return -1;
}
#endif /* HAVE_LIBLOCKFILE */
* 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 *);
* 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.
/* 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;
}
* 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];
* 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 (;;) {
} else {
lkfclosedata (fp, seqfile);
}
+
+ return OK;
}
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
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;
}
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;
/* 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 */
int mask, usemap;
char mapfile[BUFSIZ], mapname[BUFSIZ];
FILE *fp;
+ int failed_to_lock = 0;
static int partno, pid;
static time_t clock = 0;
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);
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 (;;) {
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)
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);
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 */
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 */
rewind (in);
for (;;) {
+ int failed_to_lock = 0;
int bufsz = sizeof buf;
state = m_getfld (&gstate, name, buf, &bufsz, in);
switch (state) {
* 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);