1 /* lock_fcntl.c -- Lock files using fcntl()
2 *
3 * Copyright (c) 1994-2008 Carnegie Mellon University. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
15 * distribution.
16 *
17 * 3. The name "Carnegie Mellon University" must not be used to
18 * endorse or promote products derived from this software without
19 * prior written permission. For permission or any legal
20 * details, please contact
21 * Carnegie Mellon University
22 * Center for Technology Transfer and Enterprise Creation
23 * 4615 Forbes Avenue
24 * Suite 302
25 * Pittsburgh, PA 15213
26 * (412) 268-7393, fax: (412) 268-7395
27 * innovation@andrew.cmu.edu
28 *
29 * 4. Redistributions of any form whatsoever must retain the following
30 * acknowledgment:
31 * "This product includes software developed by Computing Services
32 * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
33 *
34 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
35 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
36 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
37 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
38 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
39 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
40 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
41 */
42
43 #include <config.h>
44 #include <sys/types.h>
45 #include <sys/stat.h>
46 #include <unistd.h>
47 #include <fcntl.h>
48 #include <errno.h>
49
50 #include "cyr_lock.h"
51
52 #include <syslog.h>
53 #include <time.h>
54
55 EXPORTED const char lock_method_desc[] = "fcntl";
56
57 EXPORTED double debug_locks_longer_than = 0.0;
58
59 /*
60 * Block until we obtain an exclusive lock on the file descriptor 'fd',
61 * opened for reading and writing on the file named 'filename'. If
62 * 'filename' is replaced, will re-open it as 'fd' and acquire a lock
63 * on the new file.
64 *
65 * On success, returns 0. If a pointer to a struct stat is given as
66 * 'sbuf', it is filled in.
67 *
68 * On failure, returns -1 with an error code in errno. If
69 * 'failaction' is provided, it is filled in with a pointer to a fixed
70 * string naming the action that failed.
71 *
72 */
lock_reopen_ex(int fd,const char * filename,struct stat * sbuf,const char ** failaction,int * changed)73 EXPORTED int lock_reopen_ex(int fd, const char *filename,
74 struct stat *sbuf, const char **failaction,
75 int *changed)
76 {
77 int r;
78 struct flock fl;
79 struct stat sbuffile, sbufspare;
80 int newfd;
81 struct timeval starttime;
82 if (debug_locks_longer_than)
83 gettimeofday(&starttime, 0);
84
85
86 if (!sbuf) sbuf = &sbufspare;
87
88 for (;;) {
89 fl.l_type= F_WRLCK;
90 fl.l_whence = SEEK_SET;
91 fl.l_start = 0;
92 fl.l_len = 0;
93 r = fcntl(fd, F_SETLKW, &fl);
94 if (r == -1) {
95 if (errno == EINTR) continue;
96 if (failaction) *failaction = "locking";
97 return -1;
98 }
99
100 r = fstat(fd, sbuf);
101 if (!r) r = stat(filename, &sbuffile);
102 if (r == -1) {
103 if (failaction) *failaction = "stating";
104 r = lock_unlock(fd, filename);
105 return -1;
106 }
107
108 if (sbuf->st_ino == sbuffile.st_ino) {
109 if (debug_locks_longer_than) {
110 struct timeval endtime;
111 gettimeofday(&endtime, 0);
112 double locktime = (double)(endtime.tv_sec - starttime.tv_sec) +
113 (double)(endtime.tv_usec - starttime.tv_usec)/1000000.0;
114 if (locktime > debug_locks_longer_than) /* 10ms */
115 syslog(LOG_NOTICE, "locktimer: reopen %s (%0.2fs)", filename, locktime);
116 }
117 return 0;
118 }
119
120 if (changed) *changed = 1;
121
122 newfd = open(filename, O_RDWR);
123 if (newfd == -1) {
124 if (failaction) *failaction = "opening";
125 r = lock_unlock(fd, filename);
126 return -1;
127 }
128 dup2(newfd, fd);
129 close(newfd);
130 }
131 }
132
133 /*
134 * Obtain a lock on 'fd'. The lock is exclusive if 'exclusive'
135 * is true, otherwise shared. Normally blocks until a lock is
136 * obtained, but if 'nonblock' is true does not block and instead
137 * fails with errno=EWOUDBLOCK if the lock cannot be obtained.
138 *
139 * Returns 0 for success, -1 for failure, with errno set to an
140 * appropriate error code.
141 */
lock_setlock(int fd,int exclusive,int nonblock,const char * filename)142 EXPORTED int lock_setlock(int fd, int exclusive, int nonblock,
143 const char *filename)
144 {
145 int r;
146 struct flock fl;
147 int type = (exclusive ? F_WRLCK : F_RDLCK);
148 int cmd = (nonblock ? F_SETLK : F_SETLKW);
149 struct timeval starttime;
150 if (debug_locks_longer_than)
151 gettimeofday(&starttime, 0);
152
153 for (;;) {
154 fl.l_type= type;
155 fl.l_whence = SEEK_SET;
156 fl.l_start = 0;
157 fl.l_len = 0;
158 r = fcntl(fd, cmd, &fl);
159 if (r != -1) {
160 if (debug_locks_longer_than) {
161 struct timeval endtime;
162 gettimeofday(&endtime, 0);
163 double locktime = (double)(endtime.tv_sec - starttime.tv_sec) +
164 (double)(endtime.tv_usec - starttime.tv_usec)/1000000.0;
165 if (locktime > debug_locks_longer_than)
166 syslog(LOG_NOTICE, "locktimer: reopen %s (%0.2fs)", filename, locktime);
167 }
168 return 0;
169 }
170 if (errno == EINTR) continue;
171 return -1;
172 }
173 }
174
175 /*
176 * Release any lock on 'fd'. Always returns success.
177 */
lock_unlock(int fd,const char * filename)178 EXPORTED int lock_unlock(int fd, const char *filename __attribute__((unused)))
179 {
180 struct flock fl;
181 int r;
182
183 fl.l_type= F_UNLCK;
184 fl.l_whence = SEEK_SET;
185 fl.l_start = 0;
186 fl.l_len = 0;
187
188 for (;;) {
189 r = fcntl(fd, F_SETLKW, &fl);
190 if (r != -1) return 0;
191 if (errno == EINTR) continue;
192 /* xxx help! */
193 return -1;
194 }
195 }
196
197