pidfile.py 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. #
  2. # This file is part of gunicorn released under the MIT license.
  3. # See the NOTICE for more information.
  4. import errno
  5. import os
  6. import tempfile
  7. class Pidfile:
  8. """\
  9. Manage a PID file. If a specific name is provided
  10. it and '"%s.oldpid" % name' will be used. Otherwise
  11. we create a temp file using os.mkstemp.
  12. """
  13. def __init__(self, fname):
  14. self.fname = fname
  15. self.pid = None
  16. def create(self, pid):
  17. oldpid = self.validate()
  18. if oldpid:
  19. if oldpid == os.getpid():
  20. return
  21. msg = "Already running on PID %s (or pid file '%s' is stale)"
  22. raise RuntimeError(msg % (oldpid, self.fname))
  23. self.pid = pid
  24. # Write pidfile
  25. fdir = os.path.dirname(self.fname)
  26. if fdir and not os.path.isdir(fdir):
  27. raise RuntimeError("%s doesn't exist. Can't create pidfile." % fdir)
  28. fd, fname = tempfile.mkstemp(dir=fdir)
  29. os.write(fd, ("%s\n" % self.pid).encode('utf-8'))
  30. if self.fname:
  31. os.rename(fname, self.fname)
  32. else:
  33. self.fname = fname
  34. os.close(fd)
  35. # set permissions to -rw-r--r--
  36. os.chmod(self.fname, 420)
  37. def rename(self, path):
  38. self.unlink()
  39. self.fname = path
  40. self.create(self.pid)
  41. def unlink(self):
  42. """ delete pidfile"""
  43. try:
  44. with open(self.fname) as f:
  45. pid1 = int(f.read() or 0)
  46. if pid1 == self.pid:
  47. os.unlink(self.fname)
  48. except Exception:
  49. pass
  50. def validate(self):
  51. """ Validate pidfile and make it stale if needed"""
  52. if not self.fname:
  53. return
  54. try:
  55. with open(self.fname) as f:
  56. try:
  57. wpid = int(f.read())
  58. except ValueError:
  59. return
  60. try:
  61. os.kill(wpid, 0)
  62. return wpid
  63. except OSError as e:
  64. if e.args[0] == errno.EPERM:
  65. return wpid
  66. if e.args[0] == errno.ESRCH:
  67. return
  68. raise
  69. except OSError as e:
  70. if e.args[0] == errno.ENOENT:
  71. return
  72. raise