Package logilab :: Package common :: Module daemon

[frames] | no frames]

# Source Code for Module logilab.common.daemon

      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
     20  __docformat__ = "restructuredtext en"
     21
     22  import os
     23  import errno
     24  import signal
     25  import sys
     26  import time
     27  import warnings
     28
     29  from six.moves import range
     30
     31 -def setugid(user):
     32      """Change process user and group ID
     33
     34      Argument is a numeric user id or a user name"""
     35      try:
     36          from pwd import getpwuid
     37          passwd = getpwuid(int(user))
     38      except ValueError:
     39          from pwd import getpwnam
     40          passwd = getpwnam(user)
     41
     42      if hasattr(os, 'initgroups'): # python >= 2.7
     43          os.initgroups(passwd.pw_name, passwd.pw_gid)
     44      else:
     45          import ctypes
     46          if ctypes.CDLL(None).initgroups(passwd.pw_name, passwd.pw_gid) < 0:
     47              err = ctypes.c_int.in_dll(ctypes.pythonapi,"errno").value
     48              raise OSError(err, os.strerror(err), 'initgroups')
     49      os.setgid(passwd.pw_gid)
     50      os.setuid(passwd.pw_uid)
     51      os.environ['HOME'] = passwd.pw_dir
     52
     53
     54 -def daemonize(pidfile=None, uid=None, umask=0o77):
     55      """daemonize a Unix process. Set paranoid umask by default.
     56
     57      Return 1 in the original process, 2 in the first fork, and None for the
     58      second fork (eg daemon process).
     59      """
     60      # http://www.faqs.org/faqs/unix-faq/programmer/faq/
     61      #
     62      # fork so the parent can exit
     63      if os.fork():   # launch child and...
     64          return 1
     65      # disconnect from tty and create a new session
     66      os.setsid()
     67      # fork again so the parent, (the session group leader), can exit.
     68      # as a non-session group leader, we can never regain a controlling
     69      # terminal.
     70      if os.fork():   # launch child again.
     71          return 2
     72      # move to the root to avoit mount pb
     73      os.chdir('/')
     74      # redirect standard descriptors
     75      null = os.open('/dev/null', os.O_RDWR)
     76      for i in range(3):
     77          try:
     78              os.dup2(null, i)
     79          except OSError as e:
     80              if e.errno != errno.EBADF:
     81                  raise
     82      os.close(null)
     83      # filter warnings
     84      warnings.filterwarnings('ignore')
     85      # write pid in a file
     86      if pidfile:
     87          # ensure the directory where the pid-file should be set exists (for
     88          # instance /var/run/cubicweb may be deleted on computer restart)
     89          piddir = os.path.dirname(pidfile)
     90          if not os.path.exists(piddir):
     91              os.makedirs(piddir)
     92          f = file(pidfile, 'w')
     93          f.write(str(os.getpid()))
     94          f.close()
     95      # set umask if specified
     96      if umask is not None:
     97          os.umask(umask)
     98      # change process uid
     99      if uid:
    100          setugid(uid)
    101      return None
    102