You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

425 lines
8.0 KiB

  1. /*
  2. ulockmgr_server: Userspace Lock Manager Server
  3. Copyright (C) 2006 Miklos Szeredi <miklos@szeredi.hu>
  4. This program can be distributed under the terms of the GNU GPL.
  5. See the file COPYING.
  6. */
  7. /* #define DEBUG 1 */
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <unistd.h>
  12. #include <fcntl.h>
  13. #include <dirent.h>
  14. #include <pthread.h>
  15. #include <stdint.h>
  16. #include <errno.h>
  17. #include <assert.h>
  18. #include <sys/types.h>
  19. #include <sys/socket.h>
  20. #include <sys/wait.h>
  21. struct message {
  22. unsigned intr : 1;
  23. unsigned nofd : 1;
  24. pthread_t thr;
  25. int cmd;
  26. int fd;
  27. struct flock lock;
  28. int error;
  29. };
  30. struct fd_store {
  31. struct fd_store *next;
  32. int fd;
  33. int origfd;
  34. int inuse;
  35. };
  36. struct owner {
  37. struct fd_store *fds;
  38. pthread_mutex_t lock;
  39. };
  40. struct req_data {
  41. struct owner *o;
  42. int cfd;
  43. struct fd_store *f;
  44. struct message msg;
  45. };
  46. #define MAX_SEND_FDS 2
  47. static int receive_message(int sock, void *buf, size_t buflen, int *fdp,
  48. int *numfds)
  49. {
  50. struct msghdr msg;
  51. struct iovec iov;
  52. size_t ccmsg[CMSG_SPACE(sizeof(int) * MAX_SEND_FDS) / sizeof(size_t)];
  53. struct cmsghdr *cmsg;
  54. int res;
  55. int i;
  56. assert(*numfds <= MAX_SEND_FDS);
  57. iov.iov_base = buf;
  58. iov.iov_len = buflen;
  59. memset(&msg, 0, sizeof(msg));
  60. memset(ccmsg, -1, sizeof(ccmsg));
  61. msg.msg_iov = &iov;
  62. msg.msg_iovlen = 1;
  63. msg.msg_control = ccmsg;
  64. msg.msg_controllen = sizeof(ccmsg);
  65. res = recvmsg(sock, &msg, MSG_WAITALL);
  66. if (!res) {
  67. /* retry on zero return, see do_recv() in ulockmgr.c */
  68. res = recvmsg(sock, &msg, MSG_WAITALL);
  69. if (!res)
  70. return 0;
  71. }
  72. if (res == -1) {
  73. perror("ulockmgr_server: recvmsg");
  74. return -1;
  75. }
  76. if ((size_t) res != buflen) {
  77. fprintf(stderr, "ulockmgr_server: short message received\n");
  78. return -1;
  79. }
  80. cmsg = CMSG_FIRSTHDR(&msg);
  81. if (cmsg) {
  82. if (cmsg->cmsg_type != SCM_RIGHTS) {
  83. fprintf(stderr,
  84. "ulockmgr_server: unknown control message %d\n",
  85. cmsg->cmsg_type);
  86. return -1;
  87. }
  88. memcpy(fdp, CMSG_DATA(cmsg), sizeof(int) * *numfds);
  89. if (msg.msg_flags & MSG_CTRUNC) {
  90. fprintf(stderr,
  91. "ulockmgr_server: control message truncated\n");
  92. for (i = 0; i < *numfds; i++)
  93. close(fdp[i]);
  94. *numfds = 0;
  95. }
  96. } else {
  97. if (msg.msg_flags & MSG_CTRUNC) {
  98. fprintf(stderr,
  99. "ulockmgr_server: control message truncated(*)\n");
  100. /* There's a bug in the Linux kernel, that if
  101. not all file descriptors were allocated,
  102. then the cmsg header is not filled in */
  103. cmsg = (struct cmsghdr *) ccmsg;
  104. memcpy(fdp, CMSG_DATA(cmsg), sizeof(int) * *numfds);
  105. for (i = 0; i < *numfds; i++)
  106. close(fdp[i]);
  107. }
  108. *numfds = 0;
  109. }
  110. return res;
  111. }
  112. static int closefrom(int minfd)
  113. {
  114. DIR *dir = opendir("/proc/self/fd");
  115. if (dir) {
  116. int dfd = dirfd(dir);
  117. struct dirent *ent;
  118. while ((ent = readdir(dir))) {
  119. char *end;
  120. int fd = strtol(ent->d_name, &end, 10);
  121. if (ent->d_name[0] && !end[0] && fd >= minfd &&
  122. fd != dfd)
  123. close(fd);
  124. }
  125. closedir(dir);
  126. }
  127. return 0;
  128. }
  129. static void send_reply(int cfd, struct message *msg)
  130. {
  131. int res = send(cfd, msg, sizeof(struct message), MSG_NOSIGNAL);
  132. if (res == -1)
  133. perror("ulockmgr_server: sending reply");
  134. #ifdef DEBUG
  135. fprintf(stderr, "ulockmgr_server: error: %i\n", msg->error);
  136. #endif
  137. }
  138. static void *process_request(void *d_)
  139. {
  140. struct req_data *d = d_;
  141. int res;
  142. assert(d->msg.cmd == F_SETLKW);
  143. res = fcntl(d->f->fd, F_SETLK, &d->msg.lock);
  144. if (res == -1 && errno == EAGAIN) {
  145. d->msg.error = EAGAIN;
  146. d->msg.thr = pthread_self();
  147. send_reply(d->cfd, &d->msg);
  148. res = fcntl(d->f->fd, F_SETLKW, &d->msg.lock);
  149. }
  150. d->msg.error = (res == -1) ? errno : 0;
  151. pthread_mutex_lock(&d->o->lock);
  152. d->f->inuse--;
  153. pthread_mutex_unlock(&d->o->lock);
  154. send_reply(d->cfd, &d->msg);
  155. close(d->cfd);
  156. free(d);
  157. return NULL;
  158. }
  159. static void process_message(struct owner *o, struct message *msg, int cfd,
  160. int fd)
  161. {
  162. struct fd_store *f = NULL;
  163. struct fd_store *newf = NULL;
  164. struct fd_store **fp;
  165. struct req_data *d;
  166. pthread_t tid;
  167. int res;
  168. #ifdef DEBUG
  169. fprintf(stderr, "ulockmgr_server: %i %i %i %lli %lli\n",
  170. msg->cmd, msg->lock.l_type, msg->lock.l_whence,
  171. msg->lock.l_start, msg->lock.l_len);
  172. #endif
  173. if (msg->cmd == F_SETLK && msg->lock.l_type == F_UNLCK &&
  174. msg->lock.l_start == 0 && msg->lock.l_len == 0) {
  175. for (fp = &o->fds; *fp;) {
  176. f = *fp;
  177. if (f->origfd == msg->fd && !f->inuse) {
  178. close(f->fd);
  179. *fp = f->next;
  180. free(f);
  181. } else
  182. fp = &f->next;
  183. }
  184. if (!msg->nofd)
  185. close(fd);
  186. msg->error = 0;
  187. send_reply(cfd, msg);
  188. close(cfd);
  189. return;
  190. }
  191. if (msg->nofd) {
  192. for (fp = &o->fds; *fp; fp = &(*fp)->next) {
  193. f = *fp;
  194. if (f->origfd == msg->fd)
  195. break;
  196. }
  197. if (!*fp) {
  198. fprintf(stderr, "ulockmgr_server: fd %i not found\n",
  199. msg->fd);
  200. msg->error = EIO;
  201. send_reply(cfd, msg);
  202. close(cfd);
  203. return;
  204. }
  205. } else {
  206. newf = f = malloc(sizeof(struct fd_store));
  207. if (!f) {
  208. msg->error = ENOLCK;
  209. send_reply(cfd, msg);
  210. close(cfd);
  211. return;
  212. }
  213. f->fd = fd;
  214. f->origfd = msg->fd;
  215. f->inuse = 0;
  216. }
  217. if (msg->cmd == F_GETLK || msg->cmd == F_SETLK ||
  218. msg->lock.l_type == F_UNLCK) {
  219. res = fcntl(f->fd, msg->cmd, &msg->lock);
  220. msg->error = (res == -1) ? errno : 0;
  221. send_reply(cfd, msg);
  222. close(cfd);
  223. if (newf) {
  224. newf->next = o->fds;
  225. o->fds = newf;
  226. }
  227. return;
  228. }
  229. d = malloc(sizeof(struct req_data));
  230. if (!d) {
  231. msg->error = ENOLCK;
  232. send_reply(cfd, msg);
  233. close(cfd);
  234. free(newf);
  235. return;
  236. }
  237. f->inuse++;
  238. d->o = o;
  239. d->cfd = cfd;
  240. d->f = f;
  241. d->msg = *msg;
  242. res = pthread_create(&tid, NULL, process_request, d);
  243. if (res) {
  244. msg->error = ENOLCK;
  245. send_reply(cfd, msg);
  246. close(cfd);
  247. free(d);
  248. f->inuse--;
  249. free(newf);
  250. return;
  251. }
  252. if (newf) {
  253. newf->next = o->fds;
  254. o->fds = newf;
  255. }
  256. pthread_detach(tid);
  257. }
  258. static void sigusr1_handler(int sig)
  259. {
  260. (void) sig;
  261. /* Nothing to do */
  262. }
  263. static void process_owner(int cfd)
  264. {
  265. struct owner o;
  266. struct sigaction sa;
  267. memset(&sa, 0, sizeof(struct sigaction));
  268. sa.sa_handler = sigusr1_handler;
  269. sigemptyset(&sa.sa_mask);
  270. if (sigaction(SIGUSR1, &sa, NULL) == -1) {
  271. perror("ulockmgr_server: cannot set sigusr1 signal handler");
  272. exit(1);
  273. }
  274. memset(&o, 0, sizeof(struct owner));
  275. pthread_mutex_init(&o.lock, NULL);
  276. while (1) {
  277. struct message msg;
  278. int rfds[2];
  279. int res;
  280. int numfds = 2;
  281. res = receive_message(cfd, &msg, sizeof(msg), rfds, &numfds);
  282. if (!res)
  283. break;
  284. if (res == -1)
  285. exit(1);
  286. if (msg.intr) {
  287. if (numfds != 0)
  288. fprintf(stderr,
  289. "ulockmgr_server: too many fds for intr\n");
  290. pthread_kill(msg.thr, SIGUSR1);
  291. } else {
  292. if (numfds != 2)
  293. continue;
  294. pthread_mutex_lock(&o.lock);
  295. process_message(&o, &msg, rfds[0], rfds[1]);
  296. pthread_mutex_unlock(&o.lock);
  297. }
  298. }
  299. if (o.fds)
  300. fprintf(stderr,
  301. "ulockmgr_server: open file descriptors on exit\n");
  302. }
  303. int main(int argc, char *argv[])
  304. {
  305. int nullfd;
  306. char *end;
  307. int cfd;
  308. sigset_t empty;
  309. if (argc != 2 || !argv[1][0])
  310. goto out_inval;
  311. cfd = strtol(argv[1], &end, 10);
  312. if (*end)
  313. goto out_inval;
  314. /* demonize current process */
  315. switch(fork()) {
  316. case -1:
  317. perror("ulockmgr_server: fork");
  318. exit(1);
  319. case 0:
  320. break;
  321. default:
  322. _exit(0);
  323. }
  324. if (setsid() == -1) {
  325. perror("ulockmgr_server: setsid");
  326. exit(1);
  327. }
  328. (void) chdir("/");
  329. sigemptyset(&empty);
  330. sigprocmask(SIG_SETMASK, &empty, NULL);
  331. if (dup2(cfd, 4) == -1) {
  332. perror("ulockmgr_server: dup2");
  333. exit(1);
  334. }
  335. cfd = 4;
  336. nullfd = open("/dev/null", O_RDWR);
  337. if (nullfd >= 0) {
  338. dup2(nullfd, 0);
  339. dup2(nullfd, 1);
  340. }
  341. close(3);
  342. closefrom(5);
  343. while (1) {
  344. char c;
  345. int sock;
  346. int pid;
  347. int numfds = 1;
  348. int res = receive_message(cfd, &c, sizeof(c), &sock, &numfds);
  349. if (!res)
  350. break;
  351. if (res == -1)
  352. exit(1);
  353. assert(numfds == 1);
  354. pid = fork();
  355. if (pid == -1) {
  356. perror("ulockmgr_server: fork");
  357. close(sock);
  358. continue;
  359. }
  360. if (pid == 0) {
  361. close(cfd);
  362. pid = fork();
  363. if (pid == -1) {
  364. perror("ulockmgr_server: fork");
  365. _exit(1);
  366. }
  367. if (pid == 0)
  368. process_owner(sock);
  369. _exit(0);
  370. }
  371. waitpid(pid, NULL, 0);
  372. close(sock);
  373. }
  374. return 0;
  375. out_inval:
  376. fprintf(stderr, "%s should be started by libulockmgr\n", argv[0]);
  377. return 1;
  378. }