aboutsummaryrefslogtreecommitdiff
path: root/lib/ulockmgr.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ulockmgr.c')
-rw-r--r--lib/ulockmgr.c702
1 files changed, 352 insertions, 350 deletions
diff --git a/lib/ulockmgr.c b/lib/ulockmgr.c
index e38fdc5..6703cd0 100644
--- a/lib/ulockmgr.c
+++ b/lib/ulockmgr.c
@@ -1,9 +1,9 @@
/*
- libulockmgr: Userspace Lock Manager Library
- Copyright (C) 2006 Miklos Szeredi <miklos@szeredi.hu>
+ libulockmgr: Userspace Lock Manager Library
+ Copyright (C) 2006 Miklos Szeredi <miklos@szeredi.hu>
- This program can be distributed under the terms of the GNU LGPLv2.
- See the file COPYING.LIB
+ This program can be distributed under the terms of the GNU LGPLv2.
+ See the file COPYING.LIB
*/
/* #define DEBUG 1 */
@@ -22,28 +22,28 @@
#include <sys/wait.h>
struct message {
- unsigned intr : 1;
- unsigned nofd : 1;
- pthread_t thr;
- int cmd;
- int fd;
- struct flock lock;
- int error;
+ unsigned intr : 1;
+ unsigned nofd : 1;
+ pthread_t thr;
+ int cmd;
+ int fd;
+ struct flock lock;
+ int error;
};
struct fd_store {
- struct fd_store *next;
- int fd;
- int inuse;
+ struct fd_store *next;
+ int fd;
+ int inuse;
};
struct owner {
- struct owner *next;
- struct owner *prev;
- struct fd_store *fds;
- void *id;
- size_t id_len;
- int cfd;
+ struct owner *next;
+ struct owner *prev;
+ struct fd_store *fds;
+ void *id;
+ size_t id_len;
+ int cfd;
};
static pthread_mutex_t ulockmgr_lock;
@@ -54,19 +54,19 @@ static struct owner owner_list = { .next = &owner_list, .prev = &owner_list };
static void list_del_owner(struct owner *owner)
{
- struct owner *prev = owner->prev;
- struct owner *next = owner->next;
- prev->next = next;
- next->prev = prev;
+ struct owner *prev = owner->prev;
+ struct owner *next = owner->next;
+ prev->next = next;
+ next->prev = prev;
}
static void list_add_owner(struct owner *owner, struct owner *next)
{
- struct owner *prev = next->prev;
- owner->next = next;
- owner->prev = prev;
- prev->next = owner;
- next->prev = owner;
+ struct owner *prev = next->prev;
+ owner->next = next;
+ owner->prev = prev;
+ prev->next = owner;
+ next->prev = owner;
}
/*
@@ -74,365 +74,367 @@ static void list_add_owner(struct owner *owner, struct owner *next)
* on AF_UNIX, SOCK_STREAM sockets, that could cause it to return
* zero, even if data was available. Retrying the recv will return
* the data in this case.
-*/
+ */
static int do_recv(int sock, void *buf, size_t len, int flags)
{
- int res = recv(sock, buf, len, flags);
- if (res == 0)
- res = recv(sock, buf, len, flags);
+ int res = recv(sock, buf, len, flags);
+ if (res == 0)
+ res = recv(sock, buf, len, flags);
- return res;
+ return res;
}
static int ulockmgr_send_message(int sock, void *buf, size_t buflen,
- int *fdp, int numfds)
+ int *fdp, int numfds)
{
- struct msghdr msg;
- struct cmsghdr *p_cmsg;
- struct iovec vec;
- size_t cmsgbuf[CMSG_SPACE(sizeof(int) * MAX_SEND_FDS) / sizeof(size_t)];
- int res;
-
- assert(numfds <= MAX_SEND_FDS);
- msg.msg_control = cmsgbuf;
- msg.msg_controllen = sizeof(cmsgbuf);
- p_cmsg = CMSG_FIRSTHDR(&msg);
- p_cmsg->cmsg_level = SOL_SOCKET;
- p_cmsg->cmsg_type = SCM_RIGHTS;
- p_cmsg->cmsg_len = CMSG_LEN(sizeof(int) * numfds);
- memcpy(CMSG_DATA(p_cmsg), fdp, sizeof(int) * numfds);
- msg.msg_controllen = p_cmsg->cmsg_len;
- msg.msg_name = NULL;
- msg.msg_namelen = 0;
- msg.msg_iov = &vec;
- msg.msg_iovlen = 1;
- msg.msg_flags = 0;
- vec.iov_base = buf;
- vec.iov_len = buflen;
- res = sendmsg(sock, &msg, MSG_NOSIGNAL);
- if (res == -1) {
- perror("libulockmgr: sendmsg");
- return -1;
- }
- if ((size_t) res != buflen) {
- fprintf(stderr, "libulockmgr: sendmsg short\n");
- return -1;
- }
- return 0;
+ struct msghdr msg;
+ struct cmsghdr *p_cmsg;
+ struct iovec vec;
+ size_t cmsgbuf[CMSG_SPACE(sizeof(int) * MAX_SEND_FDS) / sizeof(size_t)];
+ int res;
+
+ assert(numfds <= MAX_SEND_FDS);
+ msg.msg_control = cmsgbuf;
+ msg.msg_controllen = sizeof(cmsgbuf);
+ p_cmsg = CMSG_FIRSTHDR(&msg);
+ p_cmsg->cmsg_level = SOL_SOCKET;
+ p_cmsg->cmsg_type = SCM_RIGHTS;
+ p_cmsg->cmsg_len = CMSG_LEN(sizeof(int) * numfds);
+ memcpy(CMSG_DATA(p_cmsg), fdp, sizeof(int) * numfds);
+ msg.msg_controllen = p_cmsg->cmsg_len;
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_iov = &vec;
+ msg.msg_iovlen = 1;
+ msg.msg_flags = 0;
+ vec.iov_base = buf;
+ vec.iov_len = buflen;
+ res = sendmsg(sock, &msg, MSG_NOSIGNAL);
+ if (res == -1) {
+ perror("libulockmgr: sendmsg");
+ return -1;
+ }
+ if ((size_t) res != buflen) {
+ fprintf(stderr, "libulockmgr: sendmsg short\n");
+ return -1;
+ }
+ return 0;
}
static int ulockmgr_start_daemon(void)
{
- int sv[2];
- int res;
- char tmp[64];
-
- res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
- if (res == -1) {
- perror("libulockmgr: socketpair");
- return -1;
- }
- snprintf(tmp, sizeof(tmp), "exec ulockmgr_server %i", sv[0]);
- res = system(tmp);
- close(sv[0]);
- if (res == -1 || !WIFEXITED(res) || WEXITSTATUS(res) != 0) {
- close(sv[1]);
- return -1;
- }
- ulockmgr_cfd = sv[1];
- return 0;
+ int sv[2];
+ int res;
+ char tmp[64];
+
+ res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
+ if (res == -1) {
+ perror("libulockmgr: socketpair");
+ return -1;
+ }
+ snprintf(tmp, sizeof(tmp), "exec ulockmgr_server %i", sv[0]);
+ res = system(tmp);
+ close(sv[0]);
+ if (res == -1 || !WIFEXITED(res) || WEXITSTATUS(res) != 0) {
+ close(sv[1]);
+ return -1;
+ }
+ ulockmgr_cfd = sv[1];
+ return 0;
}
static struct owner *ulockmgr_new_owner(const void *id, size_t id_len)
{
- int sv[2];
- int res;
- char c = 'm';
- struct owner *o;
-
- if (ulockmgr_cfd == -1 && ulockmgr_start_daemon() == -1)
- return NULL;
-
- o = calloc(1, sizeof(struct owner) + id_len);
- if (!o) {
- fprintf(stderr, "libulockmgr: failed to allocate memory\n");
- return NULL;
- }
- o->id = o + 1;
- o->id_len = id_len;
- res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
- if (res == -1) {
- perror("libulockmgr: socketpair");
- goto out_free;
- }
- res = ulockmgr_send_message(ulockmgr_cfd, &c, sizeof(c), &sv[0], 1);
- close(sv[0]);
- if (res == -1) {
- close(ulockmgr_cfd);
- ulockmgr_cfd = -1;
- goto out_close;
- }
-
- o->cfd = sv[1];
- memcpy(o->id, id, id_len);
- list_add_owner(o, &owner_list);
-
- return o;
-
- out_close:
- close(sv[1]);
- out_free:
- free(o);
- return NULL;
+ int sv[2];
+ int res;
+ char c = 'm';
+ struct owner *o;
+
+ if (ulockmgr_cfd == -1 && ulockmgr_start_daemon() == -1)
+ return NULL;
+
+ o = calloc(1, sizeof(struct owner) + id_len);
+ if (!o) {
+ fprintf(stderr, "libulockmgr: failed to allocate memory\n");
+ return NULL;
+ }
+ o->id = o + 1;
+ o->id_len = id_len;
+ res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
+ if (res == -1) {
+ perror("libulockmgr: socketpair");
+ goto out_free;
+ }
+ res = ulockmgr_send_message(ulockmgr_cfd, &c, sizeof(c), &sv[0], 1);
+ close(sv[0]);
+ if (res == -1) {
+ close(ulockmgr_cfd);
+ ulockmgr_cfd = -1;
+ goto out_close;
+ }
+
+ o->cfd = sv[1];
+ memcpy(o->id, id, id_len);
+ list_add_owner(o, &owner_list);
+
+ return o;
+
+out_close:
+ close(sv[1]);
+out_free:
+ free(o);
+ return NULL;
}
static int ulockmgr_send_request(struct message *msg, const void *id,
- size_t id_len)
+ size_t id_len)
{
- int sv[2];
- int cfd;
- struct owner *o;
- struct fd_store *f = NULL;
- struct fd_store *newf = NULL;
- struct fd_store **fp;
- int fd = msg->fd;
- int cmd = msg->cmd;
- int res;
- int unlockall = (cmd == F_SETLK && msg->lock.l_type == F_UNLCK &&
- msg->lock.l_start == 0 && msg->lock.l_len == 0);
-
- for (o = owner_list.next; o != &owner_list; o = o->next)
- if (o->id_len == id_len && memcmp(o->id, id, id_len) == 0)
- break;
-
- if (o == &owner_list)
- o = NULL;
-
- if (!o && cmd != F_GETLK && msg->lock.l_type != F_UNLCK)
- o = ulockmgr_new_owner(id, id_len);
-
- if (!o) {
- if (cmd == F_GETLK) {
- res = fcntl(msg->fd, F_GETLK, &msg->lock);
- return (res == -1) ? -errno : 0;
- } else if (msg->lock.l_type == F_UNLCK)
- return 0;
- else
- return -ENOLCK;
- }
-
- if (unlockall)
- msg->nofd = 1;
- else {
- for (fp = &o->fds; *fp; fp = &(*fp)->next) {
- f = *fp;
- if (f->fd == fd) {
- msg->nofd = 1;
- break;
- }
- }
- }
-
- if (!msg->nofd) {
- newf = f = calloc(1, sizeof(struct fd_store));
- if (!f) {
- fprintf(stderr, "libulockmgr: failed to allocate memory\n");
- return -ENOLCK;
- }
- }
-
- res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
- if (res == -1) {
- perror("libulockmgr: socketpair");
- free(newf);
- return -ENOLCK;
- }
-
- cfd = sv[1];
- sv[1] = msg->fd;
- res = ulockmgr_send_message(o->cfd, msg, sizeof(struct message), sv,
- msg->nofd ? 1 : 2);
- close(sv[0]);
- if (res == -1) {
- free(newf);
- close(cfd);
- return -EIO;
- }
-
- if (newf) {
- newf->fd = msg->fd;
- newf->next = o->fds;
- o->fds = newf;
- }
- if (f)
- f->inuse++;
-
- res = do_recv(cfd, msg, sizeof(struct message), MSG_WAITALL);
- if (res == -1) {
- perror("libulockmgr: recv");
- msg->error = EIO;
- } else if (res != sizeof(struct message)) {
- fprintf(stderr, "libulockmgr: recv short\n");
- msg->error = EIO;
- } else if (cmd == F_SETLKW && msg->error == EAGAIN) {
- pthread_mutex_unlock(&ulockmgr_lock);
- while (1) {
- sigset_t old;
- sigset_t unblock;
- int errno_save;
-
- sigemptyset(&unblock);
- sigaddset(&unblock, SIGUSR1);
- pthread_sigmask(SIG_UNBLOCK, &unblock, &old);
- res = do_recv(cfd, msg, sizeof(struct message), MSG_WAITALL);
- errno_save = errno;
- pthread_sigmask(SIG_SETMASK, &old, NULL);
- if (res == sizeof(struct message))
- break;
- else if (res >= 0) {
- fprintf(stderr, "libulockmgr: recv short\n");
- msg->error = EIO;
- break;
- } else if (errno_save != EINTR) {
- errno = errno_save;
- perror("libulockmgr: recv");
- msg->error = EIO;
- break;
- }
- msg->intr = 1;
- res = send(o->cfd, msg, sizeof(struct message), MSG_NOSIGNAL);
- if (res == -1) {
- perror("libulockmgr: send");
- msg->error = EIO;
- break;
- }
- if (res != sizeof(struct message)) {
- fprintf(stderr, "libulockmgr: send short\n");
- msg->error = EIO;
- break;
- }
- }
- pthread_mutex_lock(&ulockmgr_lock);
-
- }
- if (f)
- f->inuse--;
- close(cfd);
- if (unlockall) {
- for (fp = &o->fds; *fp;) {
- f = *fp;
- if (f->fd == fd && !f->inuse) {
- *fp = f->next;
- free(f);
- } else
- fp = &f->next;
- }
- if (!o->fds) {
- list_del_owner(o);
- close(o->cfd);
- free(o);
- }
- /* Force OK on unlock-all, since it _will_ succeed once the
- owner is deleted */
- msg->error = 0;
- }
-
- return -msg->error;
+ int sv[2];
+ int cfd;
+ struct owner *o;
+ struct fd_store *f = NULL;
+ struct fd_store *newf = NULL;
+ struct fd_store **fp;
+ int fd = msg->fd;
+ int cmd = msg->cmd;
+ int res;
+ int unlockall = (cmd == F_SETLK && msg->lock.l_type == F_UNLCK &&
+ msg->lock.l_start == 0 && msg->lock.l_len == 0);
+
+ for (o = owner_list.next; o != &owner_list; o = o->next)
+ if (o->id_len == id_len && memcmp(o->id, id, id_len) == 0)
+ break;
+
+ if (o == &owner_list)
+ o = NULL;
+
+ if (!o && cmd != F_GETLK && msg->lock.l_type != F_UNLCK)
+ o = ulockmgr_new_owner(id, id_len);
+
+ if (!o) {
+ if (cmd == F_GETLK) {
+ res = fcntl(msg->fd, F_GETLK, &msg->lock);
+ return (res == -1) ? -errno : 0;
+ } else if (msg->lock.l_type == F_UNLCK)
+ return 0;
+ else
+ return -ENOLCK;
+ }
+
+ if (unlockall)
+ msg->nofd = 1;
+ else {
+ for (fp = &o->fds; *fp; fp = &(*fp)->next) {
+ f = *fp;
+ if (f->fd == fd) {
+ msg->nofd = 1;
+ break;
+ }
+ }
+ }
+
+ if (!msg->nofd) {
+ newf = f = calloc(1, sizeof(struct fd_store));
+ if (!f) {
+ fprintf(stderr, "libulockmgr: failed to allocate memory\n");
+ return -ENOLCK;
+ }
+ }
+
+ res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
+ if (res == -1) {
+ perror("libulockmgr: socketpair");
+ free(newf);
+ return -ENOLCK;
+ }
+
+ cfd = sv[1];
+ sv[1] = msg->fd;
+ res = ulockmgr_send_message(o->cfd, msg, sizeof(struct message), sv,
+ msg->nofd ? 1 : 2);
+ close(sv[0]);
+ if (res == -1) {
+ free(newf);
+ close(cfd);
+ return -EIO;
+ }
+
+ if (newf) {
+ newf->fd = msg->fd;
+ newf->next = o->fds;
+ o->fds = newf;
+ }
+ if (f)
+ f->inuse++;
+
+ res = do_recv(cfd, msg, sizeof(struct message), MSG_WAITALL);
+ if (res == -1) {
+ perror("libulockmgr: recv");
+ msg->error = EIO;
+ } else if (res != sizeof(struct message)) {
+ fprintf(stderr, "libulockmgr: recv short\n");
+ msg->error = EIO;
+ } else if (cmd == F_SETLKW && msg->error == EAGAIN) {
+ pthread_mutex_unlock(&ulockmgr_lock);
+ while (1) {
+ sigset_t old;
+ sigset_t unblock;
+ int errno_save;
+
+ sigemptyset(&unblock);
+ sigaddset(&unblock, SIGUSR1);
+ pthread_sigmask(SIG_UNBLOCK, &unblock, &old);
+ res = do_recv(cfd, msg, sizeof(struct message),
+ MSG_WAITALL);
+ errno_save = errno;
+ pthread_sigmask(SIG_SETMASK, &old, NULL);
+ if (res == sizeof(struct message))
+ break;
+ else if (res >= 0) {
+ fprintf(stderr, "libulockmgr: recv short\n");
+ msg->error = EIO;
+ break;
+ } else if (errno_save != EINTR) {
+ errno = errno_save;
+ perror("libulockmgr: recv");
+ msg->error = EIO;
+ break;
+ }
+ msg->intr = 1;
+ res = send(o->cfd, msg, sizeof(struct message),
+ MSG_NOSIGNAL);
+ if (res == -1) {
+ perror("libulockmgr: send");
+ msg->error = EIO;
+ break;
+ }
+ if (res != sizeof(struct message)) {
+ fprintf(stderr, "libulockmgr: send short\n");
+ msg->error = EIO;
+ break;
+ }
+ }
+ pthread_mutex_lock(&ulockmgr_lock);
+
+ }
+ if (f)
+ f->inuse--;
+ close(cfd);
+ if (unlockall) {
+ for (fp = &o->fds; *fp;) {
+ f = *fp;
+ if (f->fd == fd && !f->inuse) {
+ *fp = f->next;
+ free(f);
+ } else
+ fp = &f->next;
+ }
+ if (!o->fds) {
+ list_del_owner(o);
+ close(o->cfd);
+ free(o);
+ }
+ /* Force OK on unlock-all, since it _will_ succeed once the
+ owner is deleted */
+ msg->error = 0;
+ }
+
+ return -msg->error;
}
#ifdef DEBUG
static uint32_t owner_hash(const unsigned char *id, size_t id_len)
{
- uint32_t h = 0;
- size_t i;
- for (i = 0; i < id_len; i++)
- h = ((h << 8) | (h >> 24)) ^ id[i];
+ uint32_t h = 0;
+ size_t i;
+ for (i = 0; i < id_len; i++)
+ h = ((h << 8) | (h >> 24)) ^ id[i];
- return h;
+ return h;
}
#endif
static int ulockmgr_canonicalize(int fd, struct flock *lock)
{
- off_t offset;
- if (lock->l_whence == SEEK_CUR) {
- offset = lseek(fd, 0, SEEK_CUR);
- if (offset == (off_t) -1)
- return -errno;
- } else if (lock->l_whence == SEEK_END) {
- struct stat stbuf;
- int res = fstat(fd, &stbuf);
- if (res == -1)
- return -errno;
-
- offset = stbuf.st_size;
- } else
- offset = 0;
-
- lock->l_whence = SEEK_SET;
- lock->l_start += offset;
-
- if (lock->l_start < 0)
- return -EINVAL;
-
- if (lock->l_len < 0) {
- lock->l_start += lock->l_len;
- if (lock->l_start < 0)
- return -EINVAL;
- lock->l_len = -lock->l_len;
- }
- if (lock->l_len && lock->l_start + lock->l_len - 1 < 0)
- return -EINVAL;
-
- return 0;
+ off_t offset;
+ if (lock->l_whence == SEEK_CUR) {
+ offset = lseek(fd, 0, SEEK_CUR);
+ if (offset == (off_t) -1)
+ return -errno;
+ } else if (lock->l_whence == SEEK_END) {
+ struct stat stbuf;
+ int res = fstat(fd, &stbuf);
+ if (res == -1)
+ return -errno;
+
+ offset = stbuf.st_size;
+ } else
+ offset = 0;
+
+ lock->l_whence = SEEK_SET;
+ lock->l_start += offset;
+
+ if (lock->l_start < 0)
+ return -EINVAL;
+
+ if (lock->l_len < 0) {
+ lock->l_start += lock->l_len;
+ if (lock->l_start < 0)
+ return -EINVAL;
+ lock->l_len = -lock->l_len;
+ }
+ if (lock->l_len && lock->l_start + lock->l_len - 1 < 0)
+ return -EINVAL;
+
+ return 0;
}
int ulockmgr_op(int fd, int cmd, struct flock *lock, const void *owner,
- size_t owner_len)
+ size_t owner_len)
{
- int err;
- struct message msg;
- sigset_t old;
- sigset_t block;
+ int err;
+ struct message msg;
+ sigset_t old;
+ sigset_t block;
- if (cmd != F_GETLK && cmd != F_SETLK && cmd != F_SETLKW)
- return -EINVAL;
+ if (cmd != F_GETLK && cmd != F_SETLK && cmd != F_SETLKW)
+ return -EINVAL;
- if (lock->l_whence != SEEK_SET && lock->l_whence != SEEK_CUR &&
- lock->l_whence != SEEK_END)
- return -EINVAL;
+ if (lock->l_whence != SEEK_SET && lock->l_whence != SEEK_CUR &&
+ lock->l_whence != SEEK_END)
+ return -EINVAL;
#ifdef DEBUG
- fprintf(stderr, "libulockmgr: %i %i %i %lli %lli own: 0x%08x\n",
- cmd, lock->l_type, lock->l_whence, lock->l_start, lock->l_len,
- owner_hash(owner, owner_len));
+ fprintf(stderr, "libulockmgr: %i %i %i %lli %lli own: 0x%08x\n",
+ cmd, lock->l_type, lock->l_whence, lock->l_start, lock->l_len,
+ owner_hash(owner, owner_len));
#endif
- /* Unlock should never block anyway */
- if (cmd == F_SETLKW && lock->l_type == F_UNLCK)
- cmd = F_SETLK;
-
- memset(&msg, 0, sizeof(struct message));
- msg.cmd = cmd;
- msg.fd = fd;
- msg.lock = *lock;
- err = ulockmgr_canonicalize(fd, &msg.lock);
- if (err)
- return err;
-
- sigemptyset(&block);
- sigaddset(&block, SIGUSR1);
- pthread_sigmask(SIG_BLOCK, &block, &old);
- pthread_mutex_lock(&ulockmgr_lock);
- err = ulockmgr_send_request(&msg, owner, owner_len);
- pthread_mutex_unlock(&ulockmgr_lock);
- pthread_sigmask(SIG_SETMASK, &old, NULL);
- if (!err && cmd == F_GETLK) {
- if (msg.lock.l_type == F_UNLCK)
- lock->l_type = F_UNLCK;
- else
- *lock = msg.lock;
- }
-
- return err;
+ /* Unlock should never block anyway */
+ if (cmd == F_SETLKW && lock->l_type == F_UNLCK)
+ cmd = F_SETLK;
+
+ memset(&msg, 0, sizeof(struct message));
+ msg.cmd = cmd;
+ msg.fd = fd;
+ msg.lock = *lock;
+ err = ulockmgr_canonicalize(fd, &msg.lock);
+ if (err)
+ return err;
+
+ sigemptyset(&block);
+ sigaddset(&block, SIGUSR1);
+ pthread_sigmask(SIG_BLOCK, &block, &old);
+ pthread_mutex_lock(&ulockmgr_lock);
+ err = ulockmgr_send_request(&msg, owner, owner_len);
+ pthread_mutex_unlock(&ulockmgr_lock);
+ pthread_sigmask(SIG_SETMASK, &old, NULL);
+ if (!err && cmd == F_GETLK) {
+ if (msg.lock.l_type == F_UNLCK)
+ lock->l_type = F_UNLCK;
+ else
+ *lock = msg.lock;
+ }
+
+ return err;
}