# Source code for logilab.common.daemon

    # 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 warnings

    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 = open(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