text: # copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
  # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
  #
  # This file is part of logilab-common.
  #
  # logilab-common is free software: you can redistribute it and/or modify it under
  # the terms of the GNU Lesser General Public License as published by the Free
  # Software Foundation, either version 2.1 of the License, or (at your option) any
  # later version.
  #
  # logilab-common is distributed in the hope that it will be useful, but WITHOUT
  # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  # FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
  # details.
  #
  # You should have received a copy of the GNU Lesser General Public License along
  # with logilab-common.  If not, see <http://www.gnu.org/licenses/>.
  """A daemonize function (for Unices)"""
  
  __docformat__ = "restructuredtext en"
  
  import os
  import errno
  import signal
  import sys
  import time
  import warnings
  
  from six.moves import range
  
  def setugid(user):
      """Change process user and group ID
  
      Argument is a numeric user id or a user name"""
      try:
          from pwd import getpwuid
          passwd = getpwuid(int(user))
      except ValueError:
          from pwd import getpwnam
          passwd = getpwnam(user)
  
      if hasattr(os, 'initgroups'): # python >= 2.7
          os.initgroups(passwd.pw_name, passwd.pw_gid)
      else:
          import ctypes
          if ctypes.CDLL(None).initgroups(passwd.pw_name, passwd.pw_gid) < 0:
              err = ctypes.c_int.in_dll(ctypes.pythonapi,"errno").value
              raise OSError(err, os.strerror(err), 'initgroups')
      os.setgid(passwd.pw_gid)
      os.setuid(passwd.pw_uid)
      os.environ['HOME'] = passwd.pw_dir
  
  
  def daemonize(pidfile=None, uid=None, umask=0o77):
      """daemonize a Unix process. Set paranoid umask by default.
  
      Return 1 in the original process, 2 in the first fork, and None for the
      second fork (eg daemon process).
      """
      # http://www.faqs.org/faqs/unix-faq/programmer/faq/
      #
      # fork so the parent can exit
      if os.fork():   # launch child and...
          return 1
      # disconnect from tty and create a new session
      os.setsid()
      # fork again so the parent, (the session group leader), can exit.
      # as a non-session group leader, we can never regain a controlling
      # terminal.
      if os.fork():   # launch child again.
          return 2
      # move to the root to avoit mount pb
      os.chdir('/')
      # redirect standard descriptors
      null = os.open('/dev/null', os.O_RDWR)
      for i in range(3):
          try:
              os.dup2(null, i)
          except OSError as e:
              if e.errno != errno.EBADF:
                  raise
      os.close(null)
      # filter warnings
      warnings.filterwarnings('ignore')
      # write pid in a file
      if pidfile:
          # ensure the directory where the pid-file should be set exists (for
          # instance /var/run/cubicweb may be deleted on computer restart)
          piddir = os.path.dirname(pidfile)
          if not os.path.exists(piddir):
              os.makedirs(piddir)
          f = file(pidfile, 'w')
          f.write(str(os.getpid()))
          f.close()
      # set umask if specified
      if umask is not None:
          os.umask(umask)
      # change process uid
      if uid:
          setugid(uid)
      return None
  