1/*++ 2/* NAME 3/* myflock 3 4/* SUMMARY 5/* lock open file 6/* SYNOPSIS 7/* #include <myflock.h> 8/* 9/* int myflock(fd, lock_style, operation) 10/* int fd; 11/* int lock_style; 12/* int operation; 13/* DESCRIPTION 14/* myflock() locks or unlocks an entire open file. 15/* 16/* In the case of a blocking request, a call that fails due to 17/* forseeable transient problems is retried once per second. 18/* 19/* Arguments: 20/* .IP fd 21/* The open file to be locked/unlocked. 22/* .IP lock_style 23/* One of the following values: 24/* .RS 25/* .IP MYFLOCK_STYLE_FLOCK 26/* Use BSD-style flock() locking. 27/* .IP MYFLOCK_STYLE_FCNTL 28/* Use POSIX-style fcntl() locking. 29/* .RE 30/* .IP operation 31/* One of the following values: 32/* .RS 33/* .IP MYFLOCK_OP_NONE 34/* Release any locks the process has on the specified open file. 35/* .IP MYFLOCK_OP_SHARED 36/* Attempt to acquire a shared lock on the specified open file. 37/* This is appropriate for read-only access. 38/* .IP MYFLOCK_OP_EXCLUSIVE 39/* Attempt to acquire an exclusive lock on the specified open 40/* file. This is appropriate for write access. 41/* .PP 42/* In addition, setting the MYFLOCK_OP_NOWAIT bit causes the 43/* call to return immediately when the requested lock cannot 44/* be acquired. 45/* .RE 46/* DIAGNOSTICS 47/* myflock() returns 0 in case of success, -1 in case of failure. 48/* A problem description is returned via the global \fIerrno\fR 49/* variable. In the case of a non-blocking lock request the value 50/* EAGAIN means that a lock is claimed by someone else. 51/* 52/* Panic: attempts to use an unsupported file locking method or 53/* to implement an unsupported operation. 54/* LICENSE 55/* .ad 56/* .fi 57/* The Secure Mailer license must be distributed with this software. 58/* AUTHOR(S) 59/* Wietse Venema 60/* IBM T.J. Watson Research 61/* P.O. Box 704 62/* Yorktown Heights, NY 10598, USA 63/*--*/ 64 65/* System library. */ 66 67#include "sys_defs.h" 68#include <errno.h> 69#include <unistd.h> 70 71#ifdef HAS_FCNTL_LOCK 72#include <fcntl.h> 73#include <string.h> 74#endif 75 76#ifdef HAS_FLOCK_LOCK 77#include <sys/file.h> 78#endif 79 80/* Utility library. */ 81 82#include "msg.h" 83#include "myflock.h" 84 85/* myflock - lock/unlock entire open file */ 86 87int myflock(int fd, int lock_style, int operation) 88{ 89 int status; 90 91 /* 92 * Sanity check. 93 */ 94 if ((operation & (MYFLOCK_OP_BITS)) != operation) 95 msg_panic("myflock: improper operation type: 0x%x", operation); 96 97 switch (lock_style) { 98 99 /* 100 * flock() does exactly what we need. Too bad it is not standard. 101 */ 102#ifdef HAS_FLOCK_LOCK 103 case MYFLOCK_STYLE_FLOCK: 104 { 105 static int lock_ops[] = { 106 LOCK_UN, LOCK_SH, LOCK_EX, -1, 107 -1, LOCK_SH | LOCK_NB, LOCK_EX | LOCK_NB, -1 108 }; 109 110 while ((status = flock(fd, lock_ops[operation])) < 0 111 && errno == EINTR) 112 sleep(1); 113 break; 114 } 115#endif 116 117 /* 118 * fcntl() is standard and does more than we need, but we can handle 119 * it. 120 */ 121#ifdef HAS_FCNTL_LOCK 122 case MYFLOCK_STYLE_FCNTL: 123 { 124 struct flock lock; 125 int request; 126 static int lock_ops[] = { 127 F_UNLCK, F_RDLCK, F_WRLCK 128 }; 129 130 memset((char *) &lock, 0, sizeof(lock)); 131 lock.l_type = lock_ops[operation & ~MYFLOCK_OP_NOWAIT]; 132 request = (operation & MYFLOCK_OP_NOWAIT) ? F_SETLK : F_SETLKW; 133 while ((status = fcntl(fd, request, &lock)) < 0 134 && errno == EINTR) 135 sleep(1); 136 break; 137 } 138#endif 139 default: 140 msg_panic("myflock: unsupported lock style: 0x%x", lock_style); 141 } 142 143 /* 144 * Return a consistent result. Some systems return EACCES when a lock is 145 * taken by someone else, and that would complicate error processing. 146 */ 147 if (status < 0 && (operation & MYFLOCK_OP_NOWAIT) != 0) 148 if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EACCES) 149 errno = EAGAIN; 150 151 return (status); 152} 153