Mercurial > hg > Applications > mh
view zotnet/mts/lock.c @ 17:76d91e545ea8 default tip
addrsbr and dtimep fix
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Mon, 24 Nov 2014 14:49:25 +0900 |
parents | 07f8972434be |
children |
line wrap: on
line source
/* lock.c - universal locking routines */ #ifndef lint static char ident[] = "@(#)$Id: lock.c,v 1.2 2006/12/05 18:18:14 kono Exp $"; #endif /* compile-time priority: * MAILLOCK or LIBLOCKFILE use if defined * LOCKF use if defined * FCNTL use if SYS5 defined and LOCKF not defined * FLOCK use if BSD42 defined and LOCKF and SYS5 not defined */ #ifdef MMDFONLY #define LOCKONLY #endif #include "../h/mh.h" #include <stdio.h> #ifndef LOCKONLY #include "../h/strings.h" #include "mts.h" #else /* LOCKONLY */ #include "strings.h" #ifdef MMDFONLY #include "mmdfonly.h" #include "mts.h" #else /* not MMDFONLY */ #include "lockonly.h" #endif /* not MMDFONLY */ #endif /* LOCKONLY */ #include <sys/types.h> #include <sys/stat.h> #ifdef SVR4 #ifndef LOCKF #define LOCKF #endif #include <unistd.h> #endif /* SVR4 */ #ifdef LOCKF #include <sys/errno.h> #include <sys/file.h> #ifndef F_ULOCK #ifdef UNISTD #include <unistd.h> #else /* UNISTD */ #include <sys/fcntl.h> #endif /* UNISTD */ #endif #endif /* LOCKF */ #if defined(_AIX) || defined(AUX) #include <sys/file.h> #endif #if defined(__386BSD__) || defined(BSD44) #include <fcntl.h> #endif #ifdef _AIX #include <sys/time.h> #include <time.h> #else #ifdef BSD42 #include <sys/time.h> #else /* BSD42 */ #include <time.h> #endif /* BSD42 */ #endif #ifdef SYS5 #define u_short ushort #define u_long ulong #endif #if defined(SYS5) && !defined(_AIX) #define index strchr #define rindex strrchr #endif #ifdef BSD42 #define FLOCK /* LOCKF will override this, if defined */ #endif #include <errno.h> #include <unistd.h> #ifdef LOCKONLY #ifndef MMDFONLY char *lockldir = "/usr/spool/locks"; #endif /* not MMDFONLY */ #endif /* LOCKONLY */ #ifdef MAILLOCK /* Both "mts.h" and <maillock.h> defines MAILDIR */ #undef MAILDIR #include <maillock.h> static int is_default_spool(); #undef LIBLOCKFILE #else /* MAILLOCK */ #ifdef LIBLOCKFILE #define LOCK_LIBLOCKFILE 1 #define LOCK_B_LKOPEN 2 char *lockname_from_fd(); #endif #endif /* MAILLOCK */ static int b_lkopen(), lockit(), f_lkopen(); static void lockname(), timerON(), timerOFF(); time_t time (); char *mktemp (); /* */ extern void mts_init (const char *); int lkopen (file, access) register char *file; register int access; { mts_init ("mts"); switch (lockstyle) { case LOK_UNIX: #ifdef MAILLOCK if (is_default_spool (file)) return f_lkopen (file, access); /* else fall */ #else /* MAILLOCK */ #if defined(FLOCK) || defined(LOCKF) || defined(FCNTL) || defined(LIBLOCKFILE) return f_lkopen (file, access); #endif #endif /* MAILLOCK */ default: return b_lkopen (file, access); } } /* */ static int b_lkopen (file, access) register char *file; register int access; { register int i, j; time_t curtime; char curlock[BUFSIZ], tmplock[BUFSIZ]; struct stat st; if (stat (file, &st) == NOTOK) return NOTOK; lockname (curlock, tmplock, file, (int) st.st_dev, (int) st.st_ino); for (i = 0;;) switch (lockit (tmplock, curlock)) { case OK: if ((i = open (file, access)) == NOTOK) { j = errno; (void) unlink (curlock); errno = j; } #ifdef LIBLOCKFILE timerON (curlock, i, LOCK_B_LKOPEN); #else timerON (curlock, i); #endif return i; case NOTOK: if (stat (curlock, &st) == NOTOK) { if (i++ > 5) return NOTOK; sleep (5); break; } i = 0; (void) time (&curtime); if (curtime < st.st_ctime + 60L) sleep (5); else (void) unlink (curlock); break; } } static int lockit (tmp, file) register char *tmp, *file; { register int fd; if ((fd = creat (tmp, 0400)) == NOTOK) return NOTOK; #if defined(hpux) || defined(ncr) write(fd, "MH lock\n",8); #endif /* hpux */ (void) close (fd); fd = link (tmp, file); (void) unlink (tmp); return (fd != NOTOK ? OK : NOTOK); } /* */ static void lockname (curlock, tmplock, file, dev, ino) register char *curlock, *tmplock, *file; register int dev, ino; { register char *bp, *cp; bp = curlock; if ((cp = rindex (file, '/')) == NULL || *++cp == 0) cp = file; if (lockldir == NULL || *lockldir == 0) { if (cp != file) { (void) sprintf (bp, "%.*s", (int)(cp - file), file); bp += strlen (bp); } } else { (void) sprintf (bp, "%s/", lockldir); bp += strlen (bp); } switch (lockstyle) { case LOK_BELL: default: (void) sprintf (bp, "%s.lock", cp); break; case LOK_MMDF: (void) sprintf (bp, "LCK%05d.%05d", dev, ino); break; } if (tmplock) { if ((cp = rindex (curlock, '/')) == NULL || *++cp == 0) (void) strcpy (tmplock, ",LCK.XXXXXX"); else (void) sprintf (tmplock, "%.*s,LCK.XXXXXX", (int)(cp - curlock), curlock); (void) unlink (mktemp (tmplock)); } } /* */ #if defined(BSD42) || defined(SVR4) #include <sys/file.h> #if defined(SUN40) || defined(SVR4) #include <sys/fcntl.h> #endif #else #ifdef FCNTL #include <fcntl.h> #endif #endif #ifdef MAILLOCK static int f_lkopen (file, access) register char *file; register int access; { register int fd; if (maillock (getusr (), 5) == L_SUCCESS) { if ((fd = open (file, access | O_NDELAY)) == NOTOK) return NOTOK; return fd; } return NOTOK; } #else /* not MAILLOCK */ #ifdef LIBLOCKFILE #include <lockfile.h> #include <limits.h> static int f_lkopen (file, access) register char *file; register int access; { int r, fd; char mlockfile[PATH_MAX]; snprintf(mlockfile, PATH_MAX, "%s.lock", file); r = lockfile_create(mlockfile, 5, 0); if (r != 0) return NOTOK; fd = open(file, access | O_NDELAY); if (fd == -1) return NOTOK; /* we have to set up a timer so we can touch the lockfile occasionally */ timerON(mlockfile, fd, LOCK_LIBLOCKFILE); /* NB: it's OK to pass mlockfile as timerON immediately copies it * and we then use the copy in all lockfile_foo() operations. */ return fd; } #else /* not LIBLOCKFILE */ #if defined(FLOCK) || defined(LOCKF) || defined(FCNTL) static int f_lkopen (file, access) register char *file; register int access; { register int fd, i, j; #ifdef FCNTL struct flock buf; #endif /* FCNTL */ for (i = 0; i < 5; i++) { #if defined(LOCKF) || defined(FCNTL) j = access; access &= ~O_APPEND; /* make sure we open at the beginning */ if ((access & 03) == O_RDONLY) { /* We MUST have write permission or lockf/fcntl() won't work */ /* (Stupid eh?) */ access &= ~O_RDONLY; access |= O_RDWR; } #endif /* LOCKF || FCNTL */ if ((fd = open (file, access | O_NDELAY)) == NOTOK) return NOTOK; #ifndef LOCKF #ifndef FLOCK #ifndef FCNTL /* should be an error? */ #else /* FCNTL */ buf.l_type = F_WRLCK; buf.l_whence = 0; buf.l_start = 0; buf.l_len = 0; if (fcntl (fd, F_SETLK, &buf) != NOTOK) return fd; #endif #else /* FLOCK */ if (flock (fd, LOCK_EX | LOCK_NB) != NOTOK) return fd; #endif #else /* LOCKF */ if (lockf (fd, F_TLOCK, 0L) != NOTOK) { /* see if we should be at the end */ if (j & O_APPEND) #ifdef SVR4 lseek (fd, (off_t)0, SEEK_END); #else lseek (fd, (off_t)0, L_XTND); #endif return fd; } /* Fix errno - lockf screws it */ if (errno == EACCES) errno = EWOULDBLOCK; #endif j = errno; (void) close (fd); sleep (5); } (void) close (fd); errno = j; return NOTOK; } #endif /* FLOCK || LOCKF || FCNTL */ #endif /* not LIBLOCKFILE */ #endif /* not MAILLOCK */ /* */ /* ARGSUSED */ int lkclose (fd, file) register int fd; register char *file; { char curlock[BUFSIZ]; struct stat st; #ifdef FCNTL struct flock buf; #endif if (fd == NOTOK) return OK; switch (lockstyle) { case LOK_UNIX: #ifndef MAILLOCK #ifndef LIBLOCKFILE #ifndef LOCKF #ifndef FLOCK #ifndef FCNTL /* should be an error? */ #else /* FCNTL */ buf.l_type = F_UNLCK; buf.l_whence = 0; buf.l_start = 0; buf.l_len = 0; fcntl(fd, F_SETLK, &buf); break; #endif #else /* FLOCK */ flock (fd, LOCK_UN); break; #endif #else /* LOCKF */ lseek (fd, (off_t)0, L_SET); /* make sure we unlock the whole thing */ lockf (fd, F_ULOCK, 0L); break; #endif #else /* LIBLOCKFILE */ { char *n = lockname_from_fd(fd); if (!n) /* shouldn't happen: would be program bug */ return NOTOK; lockfile_remove(n); timerOFF(fd); break; } #endif #else /* MAILLOCK */ if (is_default_spool (file)) { mailunlock (); break; } /* else fall */ #endif default: if (fstat (fd, &st) != NOTOK) { lockname (curlock, NULLCP, file, (int) st.st_dev, (int) st.st_ino); (void) unlink (curlock); timerOFF (fd); } } return (close (fd)); } /* */ FILE *lkfopen (file, mode) register char *file, *mode; { register int fd; register FILE *fp; if ((fd = lkopen (file, strcmp (mode, "r") ? 2 : 0)) == NOTOK) return NULL; if ((fp = fdopen (fd, mode)) == NULL) { (void) close (fd); return NULL; } return fp; } /* ARGSUSED */ int lkfclose (fp, file) register FILE *fp; register char *file; { char curlock[BUFSIZ]; struct stat st; #ifdef FCNTL struct flock buf; #endif if (fp == NULL) return OK; switch (lockstyle) { case LOK_UNIX: #ifndef MAILLOCK #ifndef LIBLOCKFILE #ifndef LOCKF #ifndef FLOCK #ifndef FCNTL /* should be an error? */ #else /* FCNTL */ buf.l_type = F_UNLCK; buf.l_whence = 0; buf.l_start = 0; buf.l_len = 0; fcntl(fileno(fp), F_SETLK, &buf); break; #endif #else /* FLOCK */ flock (fileno(fp), LOCK_UN); break; #endif #else /* LOCKF */ fseek (fp, 0L, 0); /* make sure we unlock the whole thing */ lockf (fileno(fp), F_ULOCK, 0L); break; #endif #else /* LIBLOCKFILE */ { char *n = lockname_from_fd(fileno(fp)); if (!n) /* shouldn't happen */ return NOTOK; lockfile_remove(n); timerOFF(fileno(fp)); break; } #endif #else /* MAILLOCK */ if (is_default_spool (file)) { mailunlock (); break; } /* else fall */ #endif default: if (fstat (fileno (fp), &st) != NOTOK) { lockname (curlock, NULLCP, file, (int) st.st_dev, (int) st.st_ino); (void) unlink (curlock); #ifdef LIBLOCKFILE /* shouldn't we timerOFF(fileno(fp))? We do in lkclose() -- PMM */ #else timerOFF (fileno (fp)); #endif } } return (fclose (fp)); } /* */ #include <signal.h> #define NSECS ((unsigned) 20) struct lock { #ifdef LIBLOCKFILE int l_locktype; #endif int l_fd; char *l_lock; struct lock *l_next; }; #define NULLP ((struct lock *) 0) static struct lock *l_top = NULLP; #ifdef MAILLOCK static int is_default_spool (file) register char *file; { static char *default_spool = NULLCP; if (! default_spool) default_spool = concat (MAILDIR, getusr (), NULLCP); return strcmp(file, default_spool) == 0; } #else /* MAILLOCK */ #ifdef LIBLOCKFILE /* simple routine to allow us to get the filename given an fd. * Returns NULL if the fd isn't valid. */ char *lockname_from_fd(fd) int fd; { struct lock *pp; for (pp = l_top; pp; pp = pp -> l_next) if (pp->l_fd == fd) return pp->l_lock; return NULL; } #endif /* LIBLOCKFILE */ #endif /* MAILLOCK */ /* ARGSUSED */ static TYPESIG alrmser (sig) int sig; { register int j; register char *cp; register struct lock *lp; #ifndef BSD42 (void) signal (SIGALRM, alrmser); #endif /* BSD42 */ for (lp = l_top; lp; lp = lp -> l_next) #ifdef LIBLOCKFILE if (lp->l_locktype == LOCK_LIBLOCKFILE) lockfile_touch(lp->l_lock); else #endif if (*(cp = lp -> l_lock) && (j = creat (cp, 0400)) != NOTOK) (void) close (j); (void) alarm (NSECS); } /* */ #ifdef LIBLOCKFILE static void timerON (lock, fd, ltype) int ltype; #else static void timerON (lock, fd) #endif char *lock; int fd; { register struct lock *lp; if ((lp = (struct lock *) malloc ((unsigned) (sizeof *lp))) == NULLP) return; /* XXX */ lp -> l_fd = fd; #ifdef LIBLOCKFILE lp -> l_locktype = ltype; #endif if ((lp -> l_lock = malloc ((unsigned) (strlen (lock) + 1))) == NULLCP) { free ((char *) lp); return; /* XXX */ } (void) strcpy (lp -> l_lock, lock); lp -> l_next = NULLP; if (l_top) lp -> l_next = l_top; else { (void) signal (SIGALRM, alrmser);/* perhaps SIGT{STP,TIN,TOU} */ (void) alarm (NSECS); } l_top = lp; } static void timerOFF (fd) int fd; { register struct lock *pp, *lp; (void) alarm (0); if (l_top) { for (pp = lp = l_top; lp; pp = lp, lp = lp -> l_next) if (lp -> l_fd == fd) break; if (lp) { if (lp == l_top) l_top = lp -> l_next; else pp -> l_next = lp -> l_next; free (lp -> l_lock); free ((char *) lp); } } if (l_top) (void) alarm (NSECS); }