posix_pidfile.cpp 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. //
  2. // $Id$
  3. //
  4. #include<__vic/posix/pidfile.h>
  5. #include<__vic/posix/file.h>
  6. #include<__vic/throw_errno.h>
  7. #include<__vic/to_text.h>
  8. #include<cerrno>
  9. #include<unistd.h>
  10. #include<fcntl.h>
  11. #if !defined(__hpux) && !defined(_AIX) && !defined(__sun)
  12. #define HAVE_FLOCK 1
  13. #endif
  14. #ifdef HAVE_FLOCK
  15. #include<sys/file.h>
  16. #endif
  17. namespace __vic { namespace posix {
  18. namespace {
  19. //----------------------------------------------------------------------------
  20. bool lock_exclusively(int fd)
  21. {
  22. errno = 0;
  23. #ifdef HAVE_FLOCK
  24. if(flock(fd, LOCK_EX | LOCK_NB))
  25. {
  26. int err = errno;
  27. if(err == EWOULDBLOCK) return false;
  28. throw_errno("flock: PID-file", err);
  29. }
  30. #else
  31. struct flock lck;
  32. lck.l_type = F_WRLCK;
  33. lck.l_whence = SEEK_SET;
  34. lck.l_start = lck.l_len = 0;
  35. if(fcntl(fd, F_SETLK, &lck) == -1)
  36. {
  37. int err = errno;
  38. if(err == EACCES || err == EAGAIN) return false;
  39. throw_errno("fcntl(F_SETLK): PID-file", err);
  40. }
  41. #endif
  42. return true;
  43. }
  44. //----------------------------------------------------------------------------
  45. // A function similar to FreeBSD's flopen()
  46. int flcreate(const char *fname)
  47. {
  48. errno = 0;
  49. int fd = open(fname, O_CREAT | O_EXCL | O_WRONLY, 0644);
  50. if(fd == -1)
  51. {
  52. int err = errno;
  53. if(err != EEXIST) throw_errno("open: PID-file", err);
  54. errno = 0;
  55. fd = open(fname, O_CREAT | O_WRONLY, 0644);
  56. if(fd == -1) throw_errno("open: PID-file");
  57. }
  58. if(!lock_exclusively(fd)) return -1;
  59. return fd;
  60. }
  61. //----------------------------------------------------------------------------
  62. void write_pid(int fd)
  63. {
  64. std::string st;
  65. to_text_append(getpid(), st);
  66. // !! may be not available on several UNICES
  67. if(ftruncate(fd, 0)) throw_errno("ftruncate: PID-file");
  68. if(lseek(fd, 0, SEEK_SET) != 0) throw_errno("lseek: PID-file");
  69. posix::file::write_all(fd, st.data(), st.length());
  70. if(fsync(fd)) throw_errno("fsync: PID-file");
  71. }
  72. //----------------------------------------------------------------------------
  73. } // namespace
  74. //----------------------------------------------------------------------------
  75. pidfile::pidfile(std::string fname) : name(__VIC_STD_MOVE(fname)), fd(-1)
  76. {
  77. }
  78. //----------------------------------------------------------------------------
  79. pidfile::~pidfile()
  80. {
  81. if(fd != -1) ::unlink(name.c_str());
  82. }
  83. //----------------------------------------------------------------------------
  84. void pidfile::create()
  85. {
  86. if(fd != -1) return;
  87. if((fd = flcreate(name.c_str())) == -1) throw already_exists();
  88. write_pid(fd);
  89. }
  90. //----------------------------------------------------------------------------
  91. void pidfile::prepare_to_daemon()
  92. {
  93. #ifndef HAVE_FLOCK
  94. if(fd != -1) { close(fd); fd = -1; }
  95. #endif
  96. }
  97. //----------------------------------------------------------------------------
  98. void pidfile::rewrite_pid()
  99. {
  100. #ifndef HAVE_FLOCK
  101. fd = open(name.c_str(), O_CREAT | O_WRONLY, 0644);
  102. // Reacquire lock
  103. if(fd == -1 || !lock_exclusively(fd))
  104. throw_errno("Reacquire PID-file lock failed");
  105. #endif
  106. write_pid(fd);
  107. }
  108. //----------------------------------------------------------------------------
  109. const char *pidfile::already_exists::what() const noexcept
  110. {
  111. return "PID-file already exists";
  112. }
  113. //----------------------------------------------------------------------------
  114. }} // namespace