libfuse: fuse -> fuse3
[fuse.git] / lib / ulockmgr.c
blob78f68592de2f5a7d952f0bc2f217b24ccd9262a1
1 /*
2 libulockmgr: Userspace Lock Manager Library
3 Copyright (C) 2006 Miklos Szeredi <miklos@szeredi.hu>
5 This program can be distributed under the terms of the GNU LGPLv2.
6 See the file COPYING.LIB
7 */
9 /* #define DEBUG 1 */
11 #include "config.h"
12 #include "ulockmgr.h"
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <unistd.h>
17 #include <pthread.h>
18 #include <errno.h>
19 #include <assert.h>
20 #include <signal.h>
21 #include <sys/stat.h>
22 #include <sys/socket.h>
23 #include <sys/wait.h>
25 struct message {
26 unsigned intr : 1;
27 unsigned nofd : 1;
28 pthread_t thr;
29 int cmd;
30 int fd;
31 struct flock lock;
32 int error;
35 struct fd_store {
36 struct fd_store *next;
37 int fd;
38 int inuse;
41 struct owner {
42 struct owner *next;
43 struct owner *prev;
44 struct fd_store *fds;
45 void *id;
46 size_t id_len;
47 int cfd;
50 static pthread_mutex_t ulockmgr_lock;
51 static int ulockmgr_cfd = -1;
52 static struct owner owner_list = { .next = &owner_list, .prev = &owner_list };
54 #define MAX_SEND_FDS 2
56 static void list_del_owner(struct owner *owner)
58 struct owner *prev = owner->prev;
59 struct owner *next = owner->next;
60 prev->next = next;
61 next->prev = prev;
64 static void list_add_owner(struct owner *owner, struct owner *next)
66 struct owner *prev = next->prev;
67 owner->next = next;
68 owner->prev = prev;
69 prev->next = owner;
70 next->prev = owner;
74 * There's a bug in the linux kernel (< 2.6.22) recv() implementation
75 * on AF_UNIX, SOCK_STREAM sockets, that could cause it to return
76 * zero, even if data was available. Retrying the recv will return
77 * the data in this case.
79 static int do_recv(int sock, void *buf, size_t len, int flags)
81 int res = recv(sock, buf, len, flags);
82 if (res == 0)
83 res = recv(sock, buf, len, flags);
85 return res;
88 static int ulockmgr_send_message(int sock, void *buf, size_t buflen,
89 int *fdp, int numfds)
91 struct msghdr msg;
92 struct cmsghdr *p_cmsg;
93 struct iovec vec;
94 size_t cmsgbuf[CMSG_SPACE(sizeof(int) * MAX_SEND_FDS) / sizeof(size_t)];
95 int res;
97 assert(numfds <= MAX_SEND_FDS);
98 msg.msg_control = cmsgbuf;
99 msg.msg_controllen = sizeof(cmsgbuf);
100 p_cmsg = CMSG_FIRSTHDR(&msg);
101 p_cmsg->cmsg_level = SOL_SOCKET;
102 p_cmsg->cmsg_type = SCM_RIGHTS;
103 p_cmsg->cmsg_len = CMSG_LEN(sizeof(int) * numfds);
104 memcpy(CMSG_DATA(p_cmsg), fdp, sizeof(int) * numfds);
105 msg.msg_controllen = p_cmsg->cmsg_len;
106 msg.msg_name = NULL;
107 msg.msg_namelen = 0;
108 msg.msg_iov = &vec;
109 msg.msg_iovlen = 1;
110 msg.msg_flags = 0;
111 vec.iov_base = buf;
112 vec.iov_len = buflen;
113 res = sendmsg(sock, &msg, MSG_NOSIGNAL);
114 if (res == -1) {
115 perror("libulockmgr: sendmsg");
116 return -1;
118 if ((size_t) res != buflen) {
119 fprintf(stderr, "libulockmgr: sendmsg short\n");
120 return -1;
122 return 0;
125 static int ulockmgr_start_daemon(void)
127 int sv[2];
128 int res;
129 char tmp[64];
131 res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
132 if (res == -1) {
133 perror("libulockmgr: socketpair");
134 return -1;
136 snprintf(tmp, sizeof(tmp), "exec ulockmgr_server %i", sv[0]);
137 res = system(tmp);
138 close(sv[0]);
139 if (res == -1 || !WIFEXITED(res) || WEXITSTATUS(res) != 0) {
140 close(sv[1]);
141 return -1;
143 ulockmgr_cfd = sv[1];
144 return 0;
147 static struct owner *ulockmgr_new_owner(const void *id, size_t id_len)
149 int sv[2];
150 int res;
151 char c = 'm';
152 struct owner *o;
154 if (ulockmgr_cfd == -1 && ulockmgr_start_daemon() == -1)
155 return NULL;
157 o = calloc(1, sizeof(struct owner) + id_len);
158 if (!o) {
159 fprintf(stderr, "libulockmgr: failed to allocate memory\n");
160 return NULL;
162 o->id = o + 1;
163 o->id_len = id_len;
164 res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
165 if (res == -1) {
166 perror("libulockmgr: socketpair");
167 goto out_free;
169 res = ulockmgr_send_message(ulockmgr_cfd, &c, sizeof(c), &sv[0], 1);
170 close(sv[0]);
171 if (res == -1) {
172 close(ulockmgr_cfd);
173 ulockmgr_cfd = -1;
174 goto out_close;
177 o->cfd = sv[1];
178 memcpy(o->id, id, id_len);
179 list_add_owner(o, &owner_list);
181 return o;
183 out_close:
184 close(sv[1]);
185 out_free:
186 free(o);
187 return NULL;
190 static int ulockmgr_send_request(struct message *msg, const void *id,
191 size_t id_len)
193 int sv[2];
194 int cfd;
195 struct owner *o;
196 struct fd_store *f = NULL;
197 struct fd_store *newf = NULL;
198 struct fd_store **fp;
199 int fd = msg->fd;
200 int cmd = msg->cmd;
201 int res;
202 int unlockall = (cmd == F_SETLK && msg->lock.l_type == F_UNLCK &&
203 msg->lock.l_start == 0 && msg->lock.l_len == 0);
205 for (o = owner_list.next; o != &owner_list; o = o->next)
206 if (o->id_len == id_len && memcmp(o->id, id, id_len) == 0)
207 break;
209 if (o == &owner_list)
210 o = NULL;
212 if (!o && cmd != F_GETLK && msg->lock.l_type != F_UNLCK)
213 o = ulockmgr_new_owner(id, id_len);
215 if (!o) {
216 if (cmd == F_GETLK) {
217 res = fcntl(msg->fd, F_GETLK, &msg->lock);
218 return (res == -1) ? -errno : 0;
219 } else if (msg->lock.l_type == F_UNLCK)
220 return 0;
221 else
222 return -ENOLCK;
225 if (unlockall)
226 msg->nofd = 1;
227 else {
228 for (fp = &o->fds; *fp; fp = &(*fp)->next) {
229 f = *fp;
230 if (f->fd == fd) {
231 msg->nofd = 1;
232 break;
237 if (!msg->nofd) {
238 newf = f = calloc(1, sizeof(struct fd_store));
239 if (!f) {
240 fprintf(stderr, "libulockmgr: failed to allocate memory\n");
241 return -ENOLCK;
245 res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
246 if (res == -1) {
247 perror("libulockmgr: socketpair");
248 free(newf);
249 return -ENOLCK;
252 cfd = sv[1];
253 sv[1] = msg->fd;
254 res = ulockmgr_send_message(o->cfd, msg, sizeof(struct message), sv,
255 msg->nofd ? 1 : 2);
256 close(sv[0]);
257 if (res == -1) {
258 free(newf);
259 close(cfd);
260 return -EIO;
263 if (newf) {
264 newf->fd = msg->fd;
265 newf->next = o->fds;
266 o->fds = newf;
268 if (f)
269 f->inuse++;
271 res = do_recv(cfd, msg, sizeof(struct message), MSG_WAITALL);
272 if (res == -1) {
273 perror("libulockmgr: recv");
274 msg->error = EIO;
275 } else if (res != sizeof(struct message)) {
276 fprintf(stderr, "libulockmgr: recv short\n");
277 msg->error = EIO;
278 } else if (cmd == F_SETLKW && msg->error == EAGAIN) {
279 pthread_mutex_unlock(&ulockmgr_lock);
280 while (1) {
281 sigset_t old;
282 sigset_t unblock;
283 int errno_save;
285 sigemptyset(&unblock);
286 sigaddset(&unblock, SIGUSR1);
287 pthread_sigmask(SIG_UNBLOCK, &unblock, &old);
288 res = do_recv(cfd, msg, sizeof(struct message),
289 MSG_WAITALL);
290 errno_save = errno;
291 pthread_sigmask(SIG_SETMASK, &old, NULL);
292 if (res == sizeof(struct message))
293 break;
294 else if (res >= 0) {
295 fprintf(stderr, "libulockmgr: recv short\n");
296 msg->error = EIO;
297 break;
298 } else if (errno_save != EINTR) {
299 errno = errno_save;
300 perror("libulockmgr: recv");
301 msg->error = EIO;
302 break;
304 msg->intr = 1;
305 res = send(o->cfd, msg, sizeof(struct message),
306 MSG_NOSIGNAL);
307 if (res == -1) {
308 perror("libulockmgr: send");
309 msg->error = EIO;
310 break;
312 if (res != sizeof(struct message)) {
313 fprintf(stderr, "libulockmgr: send short\n");
314 msg->error = EIO;
315 break;
318 pthread_mutex_lock(&ulockmgr_lock);
321 if (f)
322 f->inuse--;
323 close(cfd);
324 if (unlockall) {
325 for (fp = &o->fds; *fp;) {
326 f = *fp;
327 if (f->fd == fd && !f->inuse) {
328 *fp = f->next;
329 free(f);
330 } else
331 fp = &f->next;
333 if (!o->fds) {
334 list_del_owner(o);
335 close(o->cfd);
336 free(o);
338 /* Force OK on unlock-all, since it _will_ succeed once the
339 owner is deleted */
340 msg->error = 0;
343 return -msg->error;
346 #ifdef DEBUG
347 static uint32_t owner_hash(const unsigned char *id, size_t id_len)
349 uint32_t h = 0;
350 size_t i;
351 for (i = 0; i < id_len; i++)
352 h = ((h << 8) | (h >> 24)) ^ id[i];
354 return h;
356 #endif
358 static int ulockmgr_canonicalize(int fd, struct flock *lock)
360 off_t offset;
361 if (lock->l_whence == SEEK_CUR) {
362 offset = lseek(fd, 0, SEEK_CUR);
363 if (offset == (off_t) -1)
364 return -errno;
365 } else if (lock->l_whence == SEEK_END) {
366 struct stat stbuf;
367 int res = fstat(fd, &stbuf);
368 if (res == -1)
369 return -errno;
371 offset = stbuf.st_size;
372 } else
373 offset = 0;
375 lock->l_whence = SEEK_SET;
376 lock->l_start += offset;
378 if (lock->l_start < 0)
379 return -EINVAL;
381 if (lock->l_len < 0) {
382 lock->l_start += lock->l_len;
383 if (lock->l_start < 0)
384 return -EINVAL;
385 lock->l_len = -lock->l_len;
387 if (lock->l_len && lock->l_start + lock->l_len - 1 < 0)
388 return -EINVAL;
390 return 0;
393 int ulockmgr_op(int fd, int cmd, struct flock *lock, const void *owner,
394 size_t owner_len)
396 int err;
397 struct message msg;
398 sigset_t old;
399 sigset_t block;
401 if (cmd != F_GETLK && cmd != F_SETLK && cmd != F_SETLKW)
402 return -EINVAL;
404 if (lock->l_type != F_RDLCK && lock->l_type != F_WRLCK &&
405 lock->l_type != F_UNLCK)
406 return -EINVAL;
408 if (lock->l_whence != SEEK_SET && lock->l_whence != SEEK_CUR &&
409 lock->l_whence != SEEK_END)
410 return -EINVAL;
412 #ifdef DEBUG
413 fprintf(stderr, "libulockmgr: %i %i %i %lli %lli own: 0x%08x\n",
414 cmd, lock->l_type, lock->l_whence, lock->l_start, lock->l_len,
415 owner_hash(owner, owner_len));
416 #endif
418 /* Unlock should never block anyway */
419 if (cmd == F_SETLKW && lock->l_type == F_UNLCK)
420 cmd = F_SETLK;
422 memset(&msg, 0, sizeof(struct message));
423 msg.cmd = cmd;
424 msg.fd = fd;
425 msg.lock = *lock;
426 err = ulockmgr_canonicalize(fd, &msg.lock);
427 if (err)
428 return err;
430 sigemptyset(&block);
431 sigaddset(&block, SIGUSR1);
432 pthread_sigmask(SIG_BLOCK, &block, &old);
433 pthread_mutex_lock(&ulockmgr_lock);
434 err = ulockmgr_send_request(&msg, owner, owner_len);
435 pthread_mutex_unlock(&ulockmgr_lock);
436 pthread_sigmask(SIG_SETMASK, &old, NULL);
437 if (!err && cmd == F_GETLK) {
438 if (msg.lock.l_type == F_UNLCK)
439 lock->l_type = F_UNLCK;
440 else
441 *lock = msg.lock;
444 return err;