1 /* lock_flock.c -- Lock files using flock()
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/file.h>
45 #include <sys/stat.h>
46 #include <fcntl.h>
47 #include <errno.h>
48 #ifdef HAVE_UNISTD_H
49 #include <unistd.h>
50 #endif
51
52 #include "cyr_lock.h"
53
54 EXPORTED const char *lock_method_desc = "flock";
55
56 /*
57 * Block until we obtain an exclusive lock on the file descriptor 'fd',
58 * opened for reading and writing on the file named 'filename'. If
59 * 'filename' is replaced, will re-open it as 'fd' and acquire a lock
60 * on the new file.
61 *
62 * On success, returns 0. If a pointer to a struct stat is given as
63 * 'sbuf', it is filled in.
64 *
65 * On failure, returns -1 with an error code in errno. If
66 * 'failaction' is provided, it is filled in with a pointer to a fixed
67 * string naming the action that failed.
68 *
69 */
lock_reopen_ex(int fd,const char * filename,struct stat * sbuf,const char ** failaction,int * changed)70 EXPORTED int lock_reopen_ex(int fd, const char *filename,
71 struct stat *sbuf, const char **failaction,
72 int *changed)
73 {
74 int r;
75 struct stat sbuffile, sbufspare;
76 int newfd;
77
78 if (!sbuf) sbuf = &sbufspare;
79
80 for (;;) {
81 r = flock(fd, LOCK_EX);
82 if (r == -1) {
83 if (errno == EINTR) continue;
84 if (failaction) *failaction = "locking";
85 return -1;
86 }
87
88 r = fstat(fd, sbuf);
89 if (!r) r = stat(filename, &sbuffile);
90 if (r == -1) {
91 if (failaction) *failaction = "stating";
92 lock_unlock(fd, filename);
93 return -1;
94 }
95
96 if (sbuf->st_ino == sbuffile.st_ino) return 0;
97
98 if (changed) *changed = 1;
99
100 newfd = open(filename, O_RDWR);
101 if (newfd == -1) {
102 if (failaction) *failaction = "opening";
103 lock_unlock(fd, filename);
104 return -1;
105 }
106 dup2(newfd, fd);
107 close(newfd);
108 }
109 }
110
111 /*
112 * Obtain a lock on 'fd'. The lock is exclusive if 'exclusive'
113 * is true, otherwise shared. Normally blocks until a lock is
114 * obtained, but if 'nonblock' is true does not block and instead
115 * fails with errno=EWOUDBLOCK if the lock cannot be obtained.
116 *
117 * Returns 0 for success, -1 for failure, with errno set to an
118 * appropriate error code.
119 */
lock_setlock(int fd,int exclusive,int nonblock,const char * filename)120 EXPORTED int lock_setlock(int fd, int exclusive, int nonblock,
121 const char *filename __attribute__((unused)))
122 {
123 int r;
124 int op = (exclusive ? LOCK_EX : LOCK_SH);
125 if (nonblock) op |= LOCK_NB;
126
127 for (;;) {
128 r = flock(fd, op);
129 if (r != -1) return 0;
130 if (errno == EINTR) continue;
131 return -1;
132 }
133 }
134
135 /*
136 * Release any lock on 'fd'. Always returns success.
137 */
lock_unlock(int fd,const char * filename)138 EXPORTED int lock_unlock(int fd, const char *filename __attribute__((unused)))
139 {
140 int r;
141
142 for (;;) {
143 r = flock(fd, LOCK_UN);
144 if (r != -1) return 0;
145 if (errno == EINTR) continue;
146 /* xxx help! */
147 return -1;
148 }
149 }
150
151