[Raw Msg Headers][Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
V7 mailbox locking for mailbox
Here is some code to use V7 mailbox locking. We needed this because
we wanted zmailer to work correctly with vendor-supplied MUAs.
To use it, define V7LOCK= in your hostenv/* files.
*** 1.8 1993/02/21 23:10:10
--- mailbox.c 1993/03/03 19:39:59
***************
*** 205,210 ****
--- 205,212 ----
#define MAXPATHLEN 1024
#endif
+ char myhostname[MAXHOSTNAMELEN+1];
+
int
main(argc, argv)
int argc;
***************
*** 285,290 ****
--- 287,294 ----
maildirs[1] = NULL;
}
+ (void) getmyhostname(myhostname, sizeof myhostname);
+
if (logfile != NULL) {
if ((fd = open(logfile, O_CREAT|O_APPEND|O_WRONLY, 0644)) < 0)
(void) fprintf(stderr,
***************
*** 549,567 ****
}
if ((st.st_mode & S_IFMT) != S_IFREG)
/* don't lock non-files */;
! else
! #ifdef USE_NFSMBOX
! if (lock(file) != 0)
! #else /* !USE_NFSMBOX */
#ifdef USE_LOCKF
! if (lockf(fdmail, F_LOCK, 0) < 0)
#else /* !USE_LOCKF */
! if (flock(fdmail, LOCK_EX) < 0)
#endif /* USE_LOCKF */
! #endif /* USE_NFSMBOX */
! {
! DIAGNOSTIC(rp, EX_TEMPFAIL, "can't lock \"%s\"", file);
! return;
}
#if defined(BIFF) || defined(RBIFF)
if (nbp != NULL)
--- 553,573 ----
}
if ((st.st_mode & S_IFMT) != S_IFREG)
/* don't lock non-files */;
! else {
! if (lock(file) != 0)
! {
! DIAGNOSTIC(rp, EX_TEMPFAIL, "can't lock \"%s\"", file);
! return;
! }
#ifdef USE_LOCKF
! if (lockf(fdmail, F_LOCK, 0) < 0)
#else /* !USE_LOCKF */
! if (flock(fdmail, LOCK_EX) < 0)
#endif /* USE_LOCKF */
! {
! DIAGNOSTIC(rp, EX_TEMPFAIL, "can't lock \"%s\"", file);
! return;
! }
}
#if defined(BIFF) || defined(RBIFF)
if (nbp != NULL)
***************
*** 568,583 ****
nbp->offset = lseek(fdmail, 0L, L_XTND);
#endif /* BIFF || RBIFF */
fp = putmail(rp, fdmail, messagefd, timestring, file, dp);
! if ((st.st_mode & S_IFMT) == S_IFREG)
! #ifdef USE_NFSMBOX
! (void) unlock(file);
! #else /* !USE_NFSMBOX */
#ifdef USE_LOCKF
(void) lockf(fdmail, F_ULOCK, 0);/* XX: does this really work?*/
#else /* !USE_LOCKF */
(void) flock(fdmail, LOCK_UN);
#endif /* USE_LOCKF */
! #endif /* USE_NFSMBOX */
setrootuid(rp);
if (fp != NULL) {
(void) fclose(fp); /* this closes fdmail */
--- 574,587 ----
nbp->offset = lseek(fdmail, 0L, L_XTND);
#endif /* BIFF || RBIFF */
fp = putmail(rp, fdmail, messagefd, timestring, file, dp);
! if ((st.st_mode & S_IFMT) == S_IFREG) {
#ifdef USE_LOCKF
(void) lockf(fdmail, F_ULOCK, 0);/* XX: does this really work?*/
#else /* !USE_LOCKF */
(void) flock(fdmail, LOCK_UN);
#endif /* USE_LOCKF */
! (void) unlock(file);
! }
setrootuid(rp);
if (fp != NULL) {
(void) fclose(fp); /* this closes fdmail */
*** 1.1 1993/03/03 18:36:24
--- lock.c 1993/03/11 21:58:51
***************
*** 2,5 ****
--- 2,259 ----
#ifdef USE_NFSMBOX
#include "../../support/nfslock/nfslock.c"
+ #define GOT_LOCK
#endif /* USE_NFSMBOX */
+
+ #ifdef USE_V7LOCK
+ #define GOT_LOCK
+
+ /*
+ * V7 locking code adapted from the Deliver program,
+ * by Chip Salzenberg <chip@tct.com>
+ */
+
+ #include "hostenv.h"
+ #include <sys/stat.h>
+ #include <stdio.h>
+ #include <errno.h>
+ #include NDIR_H
+
+ extern int errno;
+
+ extern char *emalloc();
+ extern char myhostname[];
+
+ /*
+ * Local functions.
+ */
+
+ static char *dotlock_name();
+
+ /*
+ * Local data.
+ */
+
+ #define MIN_NAMESIZE 8 /* Minimum reasonable filename size limit. */
+
+ /*
+ * Lock a mailbox by name.
+ */
+
+ int
+ lock(name)
+ char *name;
+ {
+ char *dotlock;
+
+ if ((dotlock = dotlock_name(name)) == NULL
+ || create_lockfile(dotlock) < 0)
+ return -1;
+
+ return 0;
+ }
+
+ /*
+ * Unlock a mailbox by name.
+ */
+
+ int
+ unlock(name)
+ char *name;
+ {
+ char *dotlock;
+
+ if ((dotlock = dotlock_name(name)) == NULL
+ || remove_lockfile(dotlock) < 0)
+ return -1;
+
+ return 0;
+ }
+
+ /*
+ * Return the name of the appropriate ".lock" file for a mailbox.
+ */
+
+ static char *
+ dotlock_name(name)
+ char *name;
+ {
+ static char *lname = NULL;
+ static unsigned lsize = 0;
+ char *p;
+ char *basename();
+ unsigned n, maxlen;
+
+ n = strlen(name);
+ if (lsize < n + 8)
+ {
+ if (lname)
+ free(lname);
+ lsize = n + 32;
+ lname = emalloc(lsize);
+ }
+
+ /* Figure maximum filename length in the given directory. */
+
+ maxlen = MAXNAMLEN;
+
+
+ /* We want as much of `basename.lock' as will fit in maxlen characters. */
+
+ (void) strcpy(lname, name);
+ p = basename(lname);
+ if ((n = strlen(p)) > (maxlen - 5))
+ n = maxlen - 5;
+ (void) strcpy(p + n, ".lock");
+
+ return lname;
+ }
+
+ /*
+ * Create a lockfile.
+ */
+
+ int
+ create_lockfile(name)
+ char *name;
+ {
+ static char *othername;
+ struct stat st1, st2;
+ int fd, tries, errno_save;
+ char *unique();
+
+ if (othername)
+ free(othername);
+ if ((othername = unique(name)) == NULL)
+ return -1;
+ if ((fd = creat(othername, 0)) == -1)
+ return -1;
+ (void) close(fd);
+
+ for (tries = 0; tries < 10; ++tries)
+ {
+ if (tries)
+ sleep(3);
+
+ /*
+ * KLUDGE ALERT
+ * NFS can report failure on successful operations if those
+ * operations are unrepeatable. Such is link(). Therefore,
+ * we ignore the error status and check identities.
+ */
+
+ (void) link(othername, name);
+
+ if (stat(othername, &st1) == 0
+ && stat(name, &st2) == 0
+ && st1.st_nlink == 2
+ && st2.st_nlink == 2
+ && st1.st_dev == st2.st_dev
+ && st1.st_ino == st2.st_ino)
+ {
+ (void) unlink(othername);
+ return 0;
+ }
+
+ /* We can't trust errno; so, assume the most benign error. */
+
+ errno_save = EEXIST;
+ }
+
+ unlink(othername);
+
+ errno = errno_save;
+ return -1;
+ }
+
+ /*
+ * Remove a lockfile.
+ */
+
+ int
+ remove_lockfile(name)
+ char *name;
+ {
+ if (unlink(name) == -1)
+ return -1;
+
+ return 0;
+ }
+
+ /*
+ * Return the last component of the given pathname.
+ */
+
+ char *
+ basename(name)
+ char *name;
+ {
+ char *b;
+
+ if ((b = strrchr(name, '/')) != NULL)
+ ++b;
+ else
+ b = name;
+
+ return (b);
+ }
+
+ /*
+ * Return an allocated string containing the name of a (probably)
+ * unique temporary file in the same directory as the given file.
+ */
+
+ char *
+ unique(path)
+ char *path;
+ {
+ static int uhostlen = 6;
+ char *upath, *ubase;
+ char *basename();
+ unsigned sequence, pid4;
+ int i;
+
+ upath = emalloc(strlen(path) + 20);
+ (void) strcpy(upath, path);
+ ubase = basename(upath);
+
+ sequence = 0;
+ if (strlen(myhostname) > (unsigned)uhostlen)
+ {
+ /*
+ * Use extra characters of hostname to randomize sequence.
+ * (The magic "33" is brought to you courtesy of Chris Torek.)
+ */
+
+ for (i = uhostlen; myhostname[i]; ++i)
+ sequence = (sequence * 33) + myhostname[i];
+ }
+
+ pid4 = (unsigned)getpid() & (unsigned)0xFFFF;
+
+ for (i = 0; i < 32; ++i)
+ {
+ struct stat st;
+
+ ++sequence;
+ (void) sprintf(ubase, "_%02X%04X.%.*s",
+ sequence & 0xFF, pid4, uhostlen, myhostname);
+
+ if (stat(upath, &st) == -1)
+ {
+ if (errno == ENOENT)
+ return upath;
+
+ break;
+ }
+ }
+
+ free(upath);
+ return NULL;
+ }
+ #endif /* V7LOCK */
+
+ #ifndef GOT_LOCK
+ lock() { return 0; }
+ unlock() { return 0; }
+ #endif /* GOT_LOCK */