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.

444 lines
9.3 KiB

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