daemon.py 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. # -*- coding: utf-8-*-
  2. #
  3. # This file is part of stdd, the simple time display daemon,
  4. # written by Helmut Pozimski <helmut@pozimski.eu>,
  5. # licensed under the 3-clause BSD license
  6. import os
  7. import sys
  8. class Daemon(object):
  9. """ Tries to implement a well behaving unix daemon in a generic way,
  10. so the code could be used in different projects.
  11. """
  12. def __init__(self, pfile_path, pfile_name):
  13. """ Initializes the object. """
  14. self.__pfile_path = pfile_path
  15. self.__pfile_name = pfile_name
  16. self.__daemon = False
  17. def Daemonize(self):
  18. """ Turns the calling prozess into a daemon running on it's own """
  19. try:
  20. # Fork for the first time
  21. self.__pid = os.fork()
  22. except OSError:
  23. sys.exit(os.EX_OSERR)
  24. else:
  25. if self.__pid > 0:
  26. sys.exit(os.EX_OK)
  27. # Become session and group leader
  28. os.setsid()
  29. try:
  30. #Fork for the second time
  31. self.__pid = os.fork()
  32. except OSError:
  33. sys.exit(os.EX_OSERR)
  34. else:
  35. if self.__pid > 0:
  36. sys.exit(os.EX_OK)
  37. # Change cwd to / to avoid interfering with other mounted file systems
  38. os.chdir("/")
  39. # Reset the umask
  40. os.umask(0)
  41. # Close possibly open file descriptors
  42. os.close(0)
  43. os.close(1)
  44. os.close(2)
  45. # And redirect them to /dev/null
  46. os.open("/dev/null", 0)
  47. os.open("/dev/null", 1)
  48. os.open("/dev/null", 2)
  49. self.__daemon = True
  50. def DropPriv(self, uid, gid):
  51. """ If the daemon is running as root user, drop privileges and continue
  52. running as the defined unprivileged user """
  53. if os.getuid() == 0:
  54. os.setgid(gid)
  55. os.setuid(uid)
  56. def SetName(self, name, cmdline):
  57. """ Sets the name of the process shown visible in ps and top,
  58. this allows to make your daemon look more like a standalone
  59. program instead of a python script.
  60. """
  61. try:
  62. # First check if prctl is available, otherwise this function does nothing
  63. import prctl
  64. except ImportError:
  65. return False
  66. else:
  67. prctl.set_name(name)
  68. prctl.set_proctitle(cmdline)
  69. return True
  70. def Start(self):
  71. """ Performs the operations needed to "start" the daemon """
  72. if self.__daemon is True:
  73. if os.access(self.__pfile_path, os.F_OK & os.W_OK):
  74. self.__pidfile = open(os.path.join(self.__pfile_path, self.__pfile_name),
  75. "w")
  76. self.__pidfile.write(unicode(os.getpid()) + "\n")
  77. self.__pidfile.close()
  78. return True
  79. else:
  80. return False
  81. else:
  82. return False
  83. def Stop(self):
  84. """ Performs the operations needed to stop the daemon """
  85. if self.__daemon is True:
  86. try:
  87. os.remove(os.path.join(self.__pfile_path, self.__pfile_name))
  88. except OSError:
  89. return False
  90. else:
  91. return True
  92. else:
  93. return True