# # executil.py - generic utility functions for executing programs # # Erik Troan # # Copyright 1999-2002 Red Hat, Inc. # # This software may be freely redistributed under the terms of the GNU # library public license. # # You should have received a copy of the GNU Library Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # import os import sys import types import select # # pthread_sigmask # # Python 2.3 and earlier use pthread_sigmask to block all # signals right before creating a new thread. Since exec-ed # processes inherit the signal mask of the thread that's # executing them, this causes problems if the exec-ed process # is expecting a sane signal mask. Some symptoms include # unreaped children and parents stuck in waitpid(), among others. # use_pthread_sigmask = False if sys.version_info[:3] < (2, 4, 0): try: import signal import pthread_sigmask use_pthread_sigmask = True i = 1 unblock_signal_list = [] while i < signal.NSIG: unblock_signal_list.append(i) i = i + 1 except: print """WARNING: You might want to install the pthread_sigmask module. Python versions earlier than 2.4 have problems with signals and spawned processes.""" pass def getfd(filespec, readOnly = 0): if type(filespec) == types.IntType: return (filespec, False) if filespec == None: filespec = "/dev/null" flags = os.O_RDWR | os.O_CREAT if (readOnly): flags = os.O_RDONLY fd = os.open(filespec, flags, 0644) return (fd, True) def exec_with_redirect(cmd, argv, stdin=0, stdout=1, stderr=2, setpgrp=True): cmd = os.path.abspath(cmd) if not os.access (cmd, os.X_OK): raise RuntimeError(cmd + " can not be run") stdout_opened = False stderr_opened = False (stdin, stdin_opened) = getfd(stdin) if stdout == stderr: (stdout, stdout_opened) = getfd(stdout) stderr = stdout else: (stdout, stdout_opened) = getfd(stdout) (stderr, stderr_opened) = getfd(stderr) childpid = os.fork() if (not childpid): # Become leader of a new process group if requested if setpgrp: os.setpgrp() if stdin != 0: os.dup2(stdin, 0) os.close(stdin) if stdout != 1: os.dup2(stdout, 1) if stdout != stderr: os.close(stdout) if stderr != 2: os.dup2(stderr, 2) os.close(stderr) # Set signal mask to something sane if we can if use_pthread_sigmask: # Unblock all signals before execing (ret, oldmask) = pthread_sigmask.pthread_sigmask( pthread_sigmask.SIG_UNBLOCK, unblock_signal_list) try: os.execv(cmd, argv) except OSError, e: print "Could not execute command '%s'. Reason: %s" % (cmd, e) sys.exit(1) # Close any files we may have opened if stdin_opened: os.close(stdin) if stdout_opened: os.close(stdout) if stderr != stdout and stderr_opened: os.close(stderr) return childpid