daemon.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. # copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
  2. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
  3. #
  4. # This file is part of logilab-common.
  5. #
  6. # logilab-common is free software: you can redistribute it and/or modify it under
  7. # the terms of the GNU Lesser General Public License as published by the Free
  8. # Software Foundation, either version 2.1 of the License, or (at your option) any
  9. # later version.
  10. #
  11. # logilab-common is distributed in the hope that it will be useful, but WITHOUT
  12. # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  13. # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
  14. # details.
  15. #
  16. # You should have received a copy of the GNU Lesser General Public License along
  17. # with logilab-common. If not, see <http://www.gnu.org/licenses/>.
  18. """A daemonize function (for Unices)"""
  19. __docformat__ = "restructuredtext en"
  20. import os
  21. import errno
  22. import signal
  23. import sys
  24. import time
  25. import warnings
  26. def setugid(user):
  27. """Change process user and group ID
  28. Argument is a numeric user id or a user name"""
  29. try:
  30. from pwd import getpwuid
  31. passwd = getpwuid(int(user))
  32. except ValueError:
  33. from pwd import getpwnam
  34. passwd = getpwnam(user)
  35. if hasattr(os, 'initgroups'): # python >= 2.7
  36. os.initgroups(passwd.pw_name, passwd.pw_gid)
  37. else:
  38. import ctypes
  39. if ctypes.CDLL(None).initgroups(passwd.pw_name, passwd.pw_gid) < 0:
  40. err = ctypes.c_int.in_dll(ctypes.pythonapi,"errno").value
  41. raise OSError(err, os.strerror(err), 'initgroups')
  42. os.setgid(passwd.pw_gid)
  43. os.setuid(passwd.pw_uid)
  44. os.environ['HOME'] = passwd.pw_dir
  45. def daemonize(pidfile=None, uid=None, umask=077):
  46. """daemonize a Unix process. Set paranoid umask by default.
  47. Return 1 in the original process, 2 in the first fork, and None for the
  48. second fork (eg daemon process).
  49. """
  50. # http://www.faqs.org/faqs/unix-faq/programmer/faq/
  51. #
  52. # fork so the parent can exit
  53. if os.fork(): # launch child and...
  54. return 1
  55. # disconnect from tty and create a new session
  56. os.setsid()
  57. # fork again so the parent, (the session group leader), can exit.
  58. # as a non-session group leader, we can never regain a controlling
  59. # terminal.
  60. if os.fork(): # launch child again.
  61. return 2
  62. # move to the root to avoit mount pb
  63. os.chdir('/')
  64. # set umask if specified
  65. if umask is not None:
  66. os.umask(umask)
  67. # redirect standard descriptors
  68. null = os.open('/dev/null', os.O_RDWR)
  69. for i in range(3):
  70. try:
  71. os.dup2(null, i)
  72. except OSError, e:
  73. if e.errno != errno.EBADF:
  74. raise
  75. os.close(null)
  76. # filter warnings
  77. warnings.filterwarnings('ignore')
  78. # write pid in a file
  79. if pidfile:
  80. # ensure the directory where the pid-file should be set exists (for
  81. # instance /var/run/cubicweb may be deleted on computer restart)
  82. piddir = os.path.dirname(pidfile)
  83. if not os.path.exists(piddir):
  84. os.makedirs(piddir)
  85. f = file(pidfile, 'w')
  86. f.write(str(os.getpid()))
  87. f.close()
  88. os.chmod(pidfile, 0644)
  89. # change process uid
  90. if uid:
  91. setugid(uid)
  92. return None