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


[docs]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
[docs]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