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