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.
22 #include <sys/types.h>
23 #include <sys/socket.h>
37 struct fd_store
*next
;
55 #define MAX_SEND_FDS 2
57 static int receive_message(int sock
, void *buf
, size_t buflen
, int *fdp
,
62 size_t ccmsg
[CMSG_SPACE(sizeof(int) * MAX_SEND_FDS
) / sizeof(size_t)];
67 assert(*numfds
<= MAX_SEND_FDS
);
71 memset(&msg
, 0, sizeof(msg
));
72 memset(ccmsg
, -1, sizeof(ccmsg
));
75 msg
.msg_control
= ccmsg
;
76 msg
.msg_controllen
= sizeof(ccmsg
);
78 res
= recvmsg(sock
, &msg
, MSG_WAITALL
);
80 /* retry on zero return, see do_recv() in ulockmgr.c */
81 res
= recvmsg(sock
, &msg
, MSG_WAITALL
);
86 perror("ulockmgr_server: recvmsg");
89 if ((size_t) res
!= buflen
) {
90 fprintf(stderr
, "ulockmgr_server: short message received\n");
94 cmsg
= CMSG_FIRSTHDR(&msg
);
96 if (!cmsg
->cmsg_type
== SCM_RIGHTS
) {
98 "ulockmgr_server: unknown control message %d\n",
102 memcpy(fdp
, CMSG_DATA(cmsg
), sizeof(int) * *numfds
);
103 if (msg
.msg_flags
& MSG_CTRUNC
) {
105 "ulockmgr_server: control message truncated\n");
106 for (i
= 0; i
< *numfds
; i
++)
111 if (msg
.msg_flags
& MSG_CTRUNC
) {
113 "ulockmgr_server: control message truncated(*)\n");
115 /* There's a bug in the Linux kernel, that if
116 not all file descriptors were allocated,
117 then the cmsg header is not filled in */
118 cmsg
= (struct cmsghdr
*) ccmsg
;
119 memcpy(fdp
, CMSG_DATA(cmsg
), sizeof(int) * *numfds
);
120 for (i
= 0; i
< *numfds
; i
++)
128 static int closefrom(int minfd
)
130 DIR *dir
= opendir("/proc/self/fd");
132 int dfd
= dirfd(dir
);
134 while ((ent
= readdir(dir
))) {
136 int fd
= strtol(ent
->d_name
, &end
, 10);
137 if (ent
->d_name
[0] && !end
[0] && fd
>= minfd
&&
146 static void send_reply(int cfd
, struct message
*msg
)
148 int res
= send(cfd
, msg
, sizeof(struct message
), MSG_NOSIGNAL
);
150 perror("ulockmgr_server: sending reply");
152 fprintf(stderr
, "ulockmgr_server: error: %i\n", msg
->error
);
156 static void *process_request(void *d_
)
158 struct req_data
*d
= d_
;
161 assert(d
->msg
.cmd
== F_SETLKW
);
162 res
= fcntl(d
->f
->fd
, F_SETLK
, &d
->msg
.lock
);
163 if (res
== -1 && errno
== EAGAIN
) {
164 d
->msg
.error
= EAGAIN
;
165 d
->msg
.thr
= pthread_self();
166 send_reply(d
->cfd
, &d
->msg
);
167 res
= fcntl(d
->f
->fd
, F_SETLKW
, &d
->msg
.lock
);
169 d
->msg
.error
= (res
== -1) ? errno
: 0;
170 pthread_mutex_lock(&d
->o
->lock
);
172 pthread_mutex_unlock(&d
->o
->lock
);
173 send_reply(d
->cfd
, &d
->msg
);
180 static void process_message(struct owner
*o
, struct message
*msg
, int cfd
,
183 struct fd_store
*f
= NULL
;
184 struct fd_store
*newf
= NULL
;
185 struct fd_store
**fp
;
191 fprintf(stderr
, "ulockmgr_server: %i %i %i %lli %lli\n",
192 msg
->cmd
, msg
->lock
.l_type
, msg
->lock
.l_whence
,
193 msg
->lock
.l_start
, msg
->lock
.l_len
);
196 if (msg
->cmd
== F_SETLK
&& msg
->lock
.l_type
== F_UNLCK
&&
197 msg
->lock
.l_start
== 0 && msg
->lock
.l_len
== 0) {
198 for (fp
= &o
->fds
; *fp
;) {
200 if (f
->origfd
== msg
->fd
&& !f
->inuse
) {
211 send_reply(cfd
, msg
);
217 for (fp
= &o
->fds
; *fp
; fp
= &(*fp
)->next
) {
219 if (f
->origfd
== msg
->fd
)
223 fprintf(stderr
, "ulockmgr_server: fd %i not found\n",
226 send_reply(cfd
, msg
);
231 newf
= f
= malloc(sizeof(struct fd_store
));
234 send_reply(cfd
, msg
);
244 if (msg
->cmd
== F_GETLK
|| msg
->cmd
== F_SETLK
||
245 msg
->lock
.l_type
== F_UNLCK
) {
246 res
= fcntl(f
->fd
, msg
->cmd
, &msg
->lock
);
247 msg
->error
= (res
== -1) ? errno
: 0;
248 send_reply(cfd
, msg
);
257 d
= malloc(sizeof(struct req_data
));
260 send_reply(cfd
, msg
);
271 res
= pthread_create(&tid
, NULL
, process_request
, d
);
274 send_reply(cfd
, msg
);
289 static void sigusr1_handler(int sig
)
295 static void process_owner(int cfd
)
300 memset(&sa
, 0, sizeof(struct sigaction
));
301 sa
.sa_handler
= sigusr1_handler
;
302 sigemptyset(&sa
.sa_mask
);
304 if (sigaction(SIGUSR1
, &sa
, NULL
) == -1) {
305 perror("ulockmgr_server: cannot set sigusr1 signal handler");
309 memset(&o
, 0, sizeof(struct owner
));
310 pthread_mutex_init(&o
.lock
, NULL
);
317 res
= receive_message(cfd
, &msg
, sizeof(msg
), rfds
, &numfds
);
326 "ulockmgr_server: too many fds for intr\n");
327 pthread_kill(msg
.thr
, SIGUSR1
);
332 pthread_mutex_lock(&o
.lock
);
333 process_message(&o
, &msg
, rfds
[0], rfds
[1]);
334 pthread_mutex_unlock(&o
.lock
);
339 "ulockmgr_server: open file descriptors on exit\n");
342 int main(int argc
, char *argv
[])
349 if (argc
!= 2 || !argv
[1][0])
352 cfd
= strtol(argv
[1], &end
, 10);
356 /* demonize current process */
359 perror("ulockmgr_server: fork");
367 if (setsid() == -1) {
368 perror("ulockmgr_server: setsid");
375 sigprocmask(SIG_SETMASK
, &empty
, NULL
);
377 if (dup2(cfd
, 4) == -1) {
378 perror("ulockmgr_server: dup2");
382 nullfd
= open("/dev/null", O_RDWR
);
394 int res
= receive_message(cfd
, &c
, sizeof(c
), &sock
, &numfds
);
403 perror("ulockmgr_server: fork");
411 perror("ulockmgr_server: fork");
418 waitpid(pid
, NULL
, 0);
424 fprintf(stderr
, "%s should be started by libulockmgr\n", argv
[0]);