From cda69874ef4c7bc9289ad428e079718847f8cc8f Mon Sep 17 00:00:00 2001 From: ache Date: Sun, 10 Aug 1997 18:42:39 +0000 Subject: Implement canonical locking protocol Suggested by: joerg --- lib/libutil/libutil.h | 6 ++- lib/libutil/uucplock.3 | 18 +++++--- lib/libutil/uucplock.c | 121 +++++++++++++++++++++++++++---------------------- 3 files changed, 83 insertions(+), 62 deletions(-) (limited to 'lib/libutil') diff --git a/lib/libutil/libutil.h b/lib/libutil/libutil.h index 5404a1f..d6bb5de 100644 --- a/lib/libutil/libutil.h +++ b/lib/libutil/libutil.h @@ -18,7 +18,7 @@ * 5. Modifications may be freely made to this file providing the above * conditions are met. * - * $Id: libutil.h,v 1.8 1997/05/12 10:36:13 brian Exp $ + * $Id: libutil.h,v 1.9 1997/05/19 10:04:15 peter Exp $ */ #ifndef _LIBUTIL_H_ @@ -51,7 +51,9 @@ __END_DECLS #define UU_LOCK_OK (0) #define UU_LOCK_OPEN_ERR (-1) #define UU_LOCK_READ_ERR (-2) -#define UU_LOCK_SEEK_ERR (-3) +#define UU_LOCK_CREAT_ERR (-3) #define UU_LOCK_WRITE_ERR (-4) +#define UU_LOCK_LINK_ERR (-5) +#define UU_LOCK_TRY_ERR (-6) #endif /* !_LIBUTIL_H_ */ diff --git a/lib/libutil/uucplock.3 b/lib/libutil/uucplock.3 index 7f93aa0..5be50a3 100644 --- a/lib/libutil/uucplock.3 +++ b/lib/libutil/uucplock.3 @@ -23,7 +23,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $Id: uucplock.3,v 1.6 1997/05/11 08:50:33 davidn Exp $ +.\" $Id: uucplock.3,v 1.7 1997/05/12 10:36:14 brian Exp $ .\" " .Dd March 30, 1997 .Os @@ -99,17 +99,21 @@ The lock file could not be opened via The lock file could not be read via .Xr read 2 . .Pp -.Dv UU_LOCK_SEEK_ERR: -The lock file was -.Dq stale , -but the call to -.Xr lseek 2 -necessary to write the current process id failed. +.Dv UU_LOCK_CREAT_ERR: +Can't create temporary lock file via +.Xr creat 2 . .Pp .Dv UU_LOCK_WRITE_ERR: The current process id could not be written to the lock file via a call to .Xr write 2 . .Pp +.Dv UU_LOCK_LINK_ERR: +Can't link temporary lock file via +.Xr link 2 . +.Pp +.Dv UU_LOCK_TRY_ERR: +Locking attempts are failed after 5 tries. +.Pp If a value of .Dv UU_LOCK_OK is passed to diff --git a/lib/libutil/uucplock.c b/lib/libutil/uucplock.c index 837558a..8e037e4 100644 --- a/lib/libutil/uucplock.c +++ b/lib/libutil/uucplock.c @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: uucplock.c,v 1.6 1997/05/12 10:36:14 brian Exp $ + * $Id: uucplock.c,v 1.7 1997/08/05 12:58:02 ache Exp $ * */ @@ -50,72 +50,81 @@ static const char sccsid[] = "@(#)uucplock.c 8.1 (Berkeley) 6/6/93"; #include #include "libutil.h" +#define MAXTRIES 5 + +#define LOCKTMP "LCKTMP..%d" #define LOCKFMT "LCK..%s" +#define GORET(level, val) { err = errno; uuerr = (val); \ + goto __CONCAT(ret, level); } + /* Forward declarations */ static int put_pid (int fd, pid_t pid); static pid_t get_pid (int fd,int *err); /* * uucp style locking routines - * return: 0 - success - * -1 - failure */ int uu_lock (const char *ttyname) { - int fd; + int fd, tmpfd, i; pid_t pid; - char tbuf[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN]; - int err; - - (void)snprintf(tbuf, sizeof(tbuf), _PATH_UUCPLOCK LOCKFMT, ttyname); - fd = open(tbuf, O_RDWR|O_CREAT|O_EXCL|O_EXLOCK, 0660); - if (fd < 0) { - /* - * file is already locked - * check to see if the process holding the lock still exists - */ - fd = open(tbuf, O_RDWR|O_SHLOCK); - if (fd < 0) - return UU_LOCK_OPEN_ERR; - - if ((pid = get_pid (fd, &err)) == -1) { - (void)close(fd); - errno = err; - return UU_LOCK_READ_ERR; - } + char lckname[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN], + lcktmpname[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN]; + int err, uuerr; - if (kill(pid, 0) == 0 || errno != ESRCH) { - (void)close(fd); /* process is still running */ - return UU_LOCK_INUSE; - } - /* - * The process that locked the file isn't running, so - * we'll lock it ourselves - */ - if (lseek(fd, (off_t) 0, L_SET) < 0) { - err = errno; - (void)close(fd); - errno = err; - return UU_LOCK_SEEK_ERR; - } - if (flock(fd, LOCK_EX|LOCK_NB) < 0) { - (void)close(fd); - return UU_LOCK_INUSE; - } - /* fall out and finish the locking process */ - } pid = getpid(); - if (!put_pid (fd, pid)) { - err = errno; - (void)unlink(tbuf); - (void)close(fd); - errno = err; - return UU_LOCK_WRITE_ERR; + (void)snprintf(lcktmpname, sizeof(lcktmpname), _PATH_UUCPLOCK LOCKTMP, + pid); + (void)snprintf(lckname, sizeof(lckname), _PATH_UUCPLOCK LOCKFMT, + ttyname); + if ((tmpfd = creat(lcktmpname, 0664)) < 0) + GORET(0, UU_LOCK_CREAT_ERR); + + for (i = 0; i < MAXTRIES; i++) { + if (link (lcktmpname, lckname) < 0) { + if (errno != EEXIST) + GORET(1, UU_LOCK_LINK_ERR); + /* + * file is already locked + * check to see if the process holding the lock + * still exists + */ + if ((fd = open(lckname, O_RDONLY)) < 0) + GORET(1, UU_LOCK_OPEN_ERR); + + if ((pid = get_pid (fd, &err)) == -1) + GORET(2, UU_LOCK_READ_ERR); + + close(fd); + + if (kill(pid, 0) == 0 || errno != ESRCH) + GORET(1, UU_LOCK_INUSE); + /* + * The process that locked the file isn't running, so + * we'll lock it ourselves + */ + (void)unlink(lckname); + } else { + if (!put_pid (tmpfd, pid)) + GORET(3, UU_LOCK_WRITE_ERR); + break; + } } + GORET(1, (i >= MAXTRIES) ? UU_LOCK_TRY_ERR : UU_LOCK_OK); + +ret3: + (void)unlink(lckname); + goto ret1; +ret2: (void)close(fd); - return UU_LOCK_OK; +ret1: + (void)close(tmpfd); + (void)unlink(lcktmpname); +ret0: + errno = err; + return uuerr; } int uu_unlock (const char *ttyname) @@ -142,12 +151,18 @@ const char *uu_lockerr (int uu_lockresult) case UU_LOCK_READ_ERR: fmt = "read error: %s"; break; - case UU_LOCK_SEEK_ERR: - fmt = "seek error: %s"; + case UU_LOCK_CREAT_ERR: + fmt = "creat error: %s"; break; case UU_LOCK_WRITE_ERR: fmt = "write error: %s"; break; + case UU_LOCK_LINK_ERR: + fmt = "link error: %s"; + break; + case UU_LOCK_TRY_ERR: + fmt = "too many tries: %s"; + break; default: fmt = "undefined error: %s"; break; @@ -166,7 +181,7 @@ static int put_pid (int fd, pid_t pid) return write (fd, buf, len) == len; } -static pid_t get_pid (int fd,int *err) +static pid_t get_pid (int fd, int *err) { int bytes_read; char buf[32]; -- cgit v1.1