import cPickle import errno import os import pwd import tempfile import threading from config import PID_FILE import logger def as_daemon_thread(run): thr = threading.Thread(target=run) thr.setDaemon(True) thr.start() # after http://www.erlenstar.demon.co.uk/unix/faq_2.html def daemon(): """Daemonize the current process.""" if os.fork() != 0: os._exit(0) os.setsid() if os.fork() != 0: os._exit(0) os.chdir('/') os.umask(0) devnull = os.open(os.devnull, os.O_RDWR) for fd in range(3): os.dup2(devnull, fd) def deepcopy(obj): """Return a deep copy of obj.""" return cPickle.loads(cPickle.dumps(obj, -1)) def fork_as(su, function, *args): """fork(), cd / to avoid keeping unused directories open, close all nonstandard file descriptors (to avoid capturing open sockets), fork() again (to avoid zombies) and call with arguments in the grandchild process. If is not None, set our group and user ids appropriately in the child process.""" child_pid = os.fork() if child_pid == 0: try: os.chdir('/') # close all nonstandard file descriptors _SC_OPEN_MAX = 4 for fd in range(3, os.sysconf(_SC_OPEN_MAX)): try: os.close(fd) except OSError: pass # most likely an fd that isn't open pw_ent = pwd.getpwnam(su) os.setegid(pw_ent[3]) os.seteuid(pw_ent[2]) child_pid = os.fork() if child_pid == 0: function(*args) except: os.seteuid(os.getuid()) # undo su so we can write the log file os.setegid(os.getgid()) logger.log_exc() os._exit(0) else: os.waitpid(child_pid, 0) def pid_file(): """We use a pid file to ensure that only one copy of NM is running at a given time. If successful, this function will write a pid file containing the pid of the current process. The return value is the pid of the other running process, or None otherwise.""" other_pid = None # check for a pid file if os.access(PID_FILE, os.F_OK): # pid file exists, read it handle = open(PID_FILE) other_pid = int(handle.read()) handle.close() # check for a process with that pid by sending signal 0 try: os.kill(other_pid, 0) except OSError, e: if e.errno == errno.ESRCH: other_pid = None # doesn't exist else: raise # who knows if other_pid == None: # write a new pid file write_file(PID_FILE, lambda thefile: thefile.write(str(os.getpid()))) return other_pid def write_file(filename, do_write): """Write file atomically by opening a temporary file, using to write that file, and then renaming the temporary file.""" os.rename(write_temp_file(do_write), filename) def write_temp_file(do_write): fd, temporary_filename = tempfile.mkstemp() thefile = os.fdopen(fd, 'w') do_write(thefile) thefile.close() return temporary_filename