lockfile.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. /* Copyright (c) 2003-2004, Roger Dingledine
  2. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
  3. * Copyright (c) 2007-2018, The Tor Project, Inc. */
  4. /* See LICENSE for licensing information */
  5. /**
  6. * \file lockfile.c
  7. *
  8. * \brief Implements lock files to prevent two Tor processes from using the
  9. * same data directory at the same time.
  10. **/
  11. #include "orconfig.h"
  12. #include "lib/fs/files.h"
  13. #include "lib/fs/lockfile.h"
  14. #include "lib/log/log.h"
  15. #include "lib/log/util_bug.h"
  16. #include "lib/malloc/malloc.h"
  17. #ifdef HAVE_SYS_FILE_H
  18. #include <sys/file.h>
  19. #endif
  20. #ifdef HAVE_FCNTL_H
  21. #include <fcntl.h>
  22. #endif
  23. #ifdef HAVE_UNISTD_H
  24. #include <unistd.h>
  25. #endif
  26. #ifdef _WIN32
  27. #include <windows.h>
  28. #include <sys/locking.h>
  29. #endif
  30. #include <errno.h>
  31. #include <string.h>
  32. /** Represents a lockfile on which we hold the lock. */
  33. struct tor_lockfile_t {
  34. /** Name of the file */
  35. char *filename;
  36. /** File descriptor used to hold the file open */
  37. int fd;
  38. };
  39. /** Try to get a lock on the lockfile <b>filename</b>, creating it as
  40. * necessary. If someone else has the lock and <b>blocking</b> is true,
  41. * wait until the lock is available. Otherwise return immediately whether
  42. * we succeeded or not.
  43. *
  44. * Set *<b>locked_out</b> to true if somebody else had the lock, and to false
  45. * otherwise.
  46. *
  47. * Return a <b>tor_lockfile_t</b> on success, NULL on failure.
  48. *
  49. * (Implementation note: because we need to fall back to fcntl on some
  50. * platforms, these locks are per-process, not per-thread. If you want
  51. * to do in-process locking, use tor_mutex_t like a normal person.
  52. * On Windows, when <b>blocking</b> is true, the maximum time that
  53. * is actually waited is 10 seconds, after which NULL is returned
  54. * and <b>locked_out</b> is set to 1.)
  55. */
  56. tor_lockfile_t *
  57. tor_lockfile_lock(const char *filename, int blocking, int *locked_out)
  58. {
  59. tor_lockfile_t *result;
  60. int fd;
  61. *locked_out = 0;
  62. log_info(LD_FS, "Locking \"%s\"", filename);
  63. fd = tor_open_cloexec(filename, O_RDWR|O_CREAT|O_TRUNC, 0600);
  64. if (fd < 0) {
  65. log_warn(LD_FS,"Couldn't open \"%s\" for locking: %s", filename,
  66. strerror(errno));
  67. return NULL;
  68. }
  69. #ifdef _WIN32
  70. _lseek(fd, 0, SEEK_SET);
  71. if (_locking(fd, blocking ? _LK_LOCK : _LK_NBLCK, 1) < 0) {
  72. if (errno != EACCES && errno != EDEADLOCK)
  73. log_warn(LD_FS,"Couldn't lock \"%s\": %s", filename, strerror(errno));
  74. else
  75. *locked_out = 1;
  76. close(fd);
  77. return NULL;
  78. }
  79. #elif defined(HAVE_FLOCK)
  80. if (flock(fd, LOCK_EX|(blocking ? 0 : LOCK_NB)) < 0) {
  81. if (errno != EWOULDBLOCK)
  82. log_warn(LD_FS,"Couldn't lock \"%s\": %s", filename, strerror(errno));
  83. else
  84. *locked_out = 1;
  85. close(fd);
  86. return NULL;
  87. }
  88. #else
  89. {
  90. struct flock lock;
  91. memset(&lock, 0, sizeof(lock));
  92. lock.l_type = F_WRLCK;
  93. lock.l_whence = SEEK_SET;
  94. if (fcntl(fd, blocking ? F_SETLKW : F_SETLK, &lock) < 0) {
  95. if (errno != EACCES && errno != EAGAIN)
  96. log_warn(LD_FS, "Couldn't lock \"%s\": %s", filename, strerror(errno));
  97. else
  98. *locked_out = 1;
  99. close(fd);
  100. return NULL;
  101. }
  102. }
  103. #endif /* defined(_WIN32) || ... */
  104. result = tor_malloc(sizeof(tor_lockfile_t));
  105. result->filename = tor_strdup(filename);
  106. result->fd = fd;
  107. return result;
  108. }
  109. /** Release the lock held as <b>lockfile</b>. */
  110. void
  111. tor_lockfile_unlock(tor_lockfile_t *lockfile)
  112. {
  113. tor_assert(lockfile);
  114. log_info(LD_FS, "Unlocking \"%s\"", lockfile->filename);
  115. #ifdef _WIN32
  116. _lseek(lockfile->fd, 0, SEEK_SET);
  117. if (_locking(lockfile->fd, _LK_UNLCK, 1) < 0) {
  118. log_warn(LD_FS,"Error unlocking \"%s\": %s", lockfile->filename,
  119. strerror(errno));
  120. }
  121. #elif defined(HAVE_FLOCK)
  122. if (flock(lockfile->fd, LOCK_UN) < 0) {
  123. log_warn(LD_FS, "Error unlocking \"%s\": %s", lockfile->filename,
  124. strerror(errno));
  125. }
  126. #else
  127. /* Closing the lockfile is sufficient. */
  128. #endif /* defined(_WIN32) || ... */
  129. close(lockfile->fd);
  130. lockfile->fd = -1;
  131. tor_free(lockfile->filename);
  132. tor_free(lockfile);
  133. }