2 ulockmgr_server: Userspace Lock Manager Server
3 Copyright (C) 2006 Miklos Szeredi <miklos@szeredi.hu>
5 This program can be distributed under the terms of the GNU GPL.
21 #include <sys/types.h>
22 #include <sys/socket.h>
36 struct fd_store *next;
54 #define MAX_SEND_FDS 2
56 static int receive_message(int sock, void *buf, size_t buflen, int *fdp,
61 size_t ccmsg[CMSG_SPACE(sizeof(int) * MAX_SEND_FDS) / sizeof(size_t)];
66 assert(*numfds <= MAX_SEND_FDS);
70 memset(&msg, 0, sizeof(msg));
71 memset(ccmsg, -1, sizeof(ccmsg));
74 msg.msg_control = ccmsg;
75 msg.msg_controllen = sizeof(ccmsg);
77 res = recvmsg(sock, &msg, MSG_WAITALL);
79 /* retry on zero return, see do_recv() in ulockmgr.c */
80 res = recvmsg(sock, &msg, MSG_WAITALL);
85 perror("ulockmgr_server: recvmsg");
88 if ((size_t) res != buflen) {
89 fprintf(stderr, "ulockmgr_server: short message received\n");
93 cmsg = CMSG_FIRSTHDR(&msg);
95 if (!cmsg->cmsg_type == SCM_RIGHTS) {
97 "ulockmgr_server: unknown control message %d\n",
101 memcpy(fdp, CMSG_DATA(cmsg), sizeof(int) * *numfds);
102 if (msg.msg_flags & MSG_CTRUNC) {
104 "ulockmgr_server: control message truncated\n");
105 for (i = 0; i < *numfds; i++)
110 if (msg.msg_flags & MSG_CTRUNC) {
112 "ulockmgr_server: control message truncated(*)\n");
114 /* There's a bug in the Linux kernel, that if
115 not all file descriptors were allocated,
116 then the cmsg header is not filled in */
117 cmsg = (struct cmsghdr *) ccmsg;
118 memcpy(fdp, CMSG_DATA(cmsg), sizeof(int) * *numfds);
119 for (i = 0; i < *numfds; i++)
127 static int closefrom(int minfd)
129 DIR *dir = opendir("/proc/self/fd");
131 int dfd = dirfd(dir);
133 while ((ent = readdir(dir))) {
135 int fd = strtol(ent->d_name, &end, 10);
136 if (ent->d_name[0] && !end[0] && fd >= minfd &&
145 static void send_reply(int cfd, struct message *msg)
147 int res = send(cfd, msg, sizeof(struct message), MSG_NOSIGNAL);
149 perror("ulockmgr_server: sending reply");
151 fprintf(stderr, "ulockmgr_server: error: %i\n", msg->error);
155 static void *process_request(void *d_)
157 struct req_data *d = d_;
160 assert(d->msg.cmd == F_SETLKW);
161 res = fcntl(d->f->fd, F_SETLK, &d->msg.lock);
162 if (res == -1 && errno == EAGAIN) {
163 d->msg.error = EAGAIN;
164 d->msg.thr = pthread_self();
165 send_reply(d->cfd, &d->msg);
166 res = fcntl(d->f->fd, F_SETLKW, &d->msg.lock);
168 d->msg.error = (res == -1) ? errno : 0;
169 pthread_mutex_lock(&d->o->lock);
171 pthread_mutex_unlock(&d->o->lock);
172 send_reply(d->cfd, &d->msg);
179 static void process_message(struct owner *o, struct message *msg, int cfd,
182 struct fd_store *f = NULL;
183 struct fd_store *newf = NULL;
184 struct fd_store **fp;
190 fprintf(stderr, "ulockmgr_server: %i %i %i %lli %lli\n",
191 msg->cmd, msg->lock.l_type, msg->lock.l_whence,
192 msg->lock.l_start, msg->lock.l_len);
195 if (msg->cmd == F_SETLK && msg->lock.l_type == F_UNLCK &&
196 msg->lock.l_start == 0 && msg->lock.l_len == 0) {
197 for (fp = &o->fds; *fp;) {
199 if (f->origfd == msg->fd && !f->inuse) {
210 send_reply(cfd, msg);
216 for (fp = &o->fds; *fp; fp = &(*fp)->next) {
218 if (f->origfd == msg->fd)
222 fprintf(stderr, "ulockmgr_server: fd %i not found\n",
225 send_reply(cfd, msg);
230 newf = f = malloc(sizeof(struct fd_store));
233 send_reply(cfd, msg);
243 if (msg->cmd == F_GETLK || msg->cmd == F_SETLK ||
244 msg->lock.l_type == F_UNLCK) {
245 res = fcntl(f->fd, msg->cmd, &msg->lock);
246 msg->error = (res == -1) ? errno : 0;
247 send_reply(cfd, msg);
256 d = malloc(sizeof(struct req_data));
259 send_reply(cfd, msg);
270 res = pthread_create(&tid, NULL, process_request, d);
273 send_reply(cfd, msg);
288 static void sigusr1_handler(int sig)
294 static void process_owner(int cfd)
299 memset(&sa, 0, sizeof(struct sigaction));
300 sa.sa_handler = sigusr1_handler;
301 sigemptyset(&sa.sa_mask);
303 if (sigaction(SIGUSR1, &sa, NULL) == -1) {
304 perror("ulockmgr_server: cannot set sigusr1 signal handler");
308 memset(&o, 0, sizeof(struct owner));
309 pthread_mutex_init(&o.lock, NULL);
316 res = receive_message(cfd, &msg, sizeof(msg), rfds, &numfds);
325 "ulockmgr_server: too many fds for intr\n");
326 pthread_kill(msg.thr, SIGUSR1);
331 pthread_mutex_lock(&o.lock);
332 process_message(&o, &msg, rfds[0], rfds[1]);
333 pthread_mutex_unlock(&o.lock);
338 "ulockmgr_server: open file descriptors on exit\n");
341 int main(int argc, char *argv[])
348 if (argc != 2 || !argv[1][0])
351 cfd = strtol(argv[1], &end, 10);
355 /* demonize current process */
358 perror("ulockmgr_server: fork");
366 if (setsid() == -1) {
367 perror("ulockmgr_server: setsid");
374 sigprocmask(SIG_SETMASK, &empty, NULL);
376 if (dup2(cfd, 4) == -1) {
377 perror("ulockmgr_server: dup2");
381 nullfd = open("/dev/null", O_RDWR);
393 int res = receive_message(cfd, &c, sizeof(c), &sock, &numfds);
402 perror("ulockmgr_server: fork");
410 perror("ulockmgr_server: fork");
417 waitpid(pid, NULL, 0);
423 fprintf(stderr, "%s should be started by libulockmgr\n", argv[0]);