def _safe_duplicate_handle(h): try: h = win32api.DuplicateHandle(win32process.GetCurrentProcess(), h, win32process.GetCurrentProcess(), 0, True, win32con.DUPLICATE_SAME_ACCESS) return True, h except Exception as exc: if exc.winerror == winerror.ERROR_INVALID_HANDLE: return True, None return False, None
def get_process_handle(hProcess, handle): try: return win32api.DuplicateHandle(hProcess, handle, CURRENT_PROCESS, 0, 0, win32con.DUPLICATE_SAME_ACCESS) except win32api.error, (errno, errctx, errmsg): if errno in (winerror.ERROR_ACCESS_DENIED, winerror.ERROR_INVALID_PARAMETER, winerror.ERROR_INVALID_HANDLE, winerror.ERROR_NOT_SUPPORTED): return None else: raise
def MakePrivateHandle(handle, replace = 1): """Turn an inherited handle into a non inherited one. This avoids the handle duplication that occurs on CreateProcess calls which can create uncloseable pipes.""" ### Could change implementation to use SetHandleInformation()... flags = win32con.DUPLICATE_SAME_ACCESS proc = win32api.GetCurrentProcess() if replace: flags = flags | win32con.DUPLICATE_CLOSE_SOURCE newhandle = win32api.DuplicateHandle(proc,handle,proc,0,0,flags) if replace: handle.Detach() # handle was already deleted by the last call return newhandle
def startBackgroundProcess(self): """Method to start a process running in the background. """ with process_lock: # security attributes for pipes sAttrs = win32security.SECURITY_ATTRIBUTES() sAttrs.bInheritHandle = 1 # create pipes for the process to write to hStdin_r, hStdin = win32pipe.CreatePipe(sAttrs, 0) hStdout = win32file.CreateFile(_stringToUnicode(self.fStdout), win32file.GENERIC_WRITE | win32file.GENERIC_READ, win32file.FILE_SHARE_DELETE | win32file.FILE_SHARE_READ | win32file.FILE_SHARE_WRITE, sAttrs, win32file.CREATE_ALWAYS, win32file.FILE_ATTRIBUTE_NORMAL, None) hStderr = win32file.CreateFile(_stringToUnicode(self.fStderr), win32file.GENERIC_WRITE | win32file.GENERIC_READ, win32file.FILE_SHARE_DELETE | win32file.FILE_SHARE_READ | win32file.FILE_SHARE_WRITE, sAttrs, win32file.CREATE_ALWAYS, win32file.FILE_ATTRIBUTE_NORMAL, None) # set the info structure for the new process. StartupInfo = win32process.STARTUPINFO() StartupInfo.hStdInput = hStdin_r StartupInfo.hStdOutput = hStdout StartupInfo.hStdError = hStderr StartupInfo.dwFlags = win32process.STARTF_USESTDHANDLES # Create new handles for the thread ends of the pipes. The duplicated handles will # have their inheritence properties set to false so that any children inheriting these # handles will not have non-closeable handles to the pipes pid = win32api.GetCurrentProcess() tmp = win32api.DuplicateHandle(pid, hStdin, pid, 0, 0, win32con.DUPLICATE_SAME_ACCESS) win32file.CloseHandle(hStdin) hStdin = tmp # start the process, and close down the copies of the process handles # we have open after the process creation (no longer needed here) old_command = command = self.__quotePath(self.command) for arg in self.arguments: command = '%s %s' % (command, self.__quotePath(arg)) try: self.__hProcess, self.__hThread, self.pid, self.__tid = win32process.CreateProcess( None, command, None, None, 1, 0, self.environs or None, os.path.normpath(self.workingDir), StartupInfo) except pywintypes.error as e: raise ProcessError("Error creating process %s: %s" % (old_command, e)) win32file.CloseHandle(hStdin_r) win32file.CloseHandle(hStdout) win32file.CloseHandle(hStderr) # set the handle to the stdin of the process self.__stdin = hStdin
def _open_parent_file_handle(parent_process_handle, parent_file_handle, mode='r'): if mode not in ['r', 'w']: raise ValueError("mode must be 'r' or 'w'") my_file_handle = win32api.DuplicateHandle( parent_process_handle, parent_file_handle, win32api.GetCurrentProcess(), 0, #desiredAccess ignored because of DUPLICATE_SAME_ACCESS 0, #Inheritable win32con.DUPLICATE_SAME_ACCESS | win32con.DUPLICATE_CLOSE_SOURCE) infd = msvcrt.open_osfhandle(int(my_file_handle), os.O_RDONLY if mode == 'r' else os.O_WRONLY) f = _ParentPassedFile(os.fdopen(infd, mode), my_file_handle) return f
def __UninheritableHandle(self, handle): """Return a duplicate of a file handle that is not inheritable. 'handle' -- A file handle. returns -- A new handle that is a non-inheritable duplicate of the 'handle'. This method should only be used under Windows.""" assert sys.platform == "win32" current_process = win32api.GetCurrentProcess() return win32api.DuplicateHandle(current_process, handle, current_process, 0, 0, win32con.DUPLICATE_SAME_ACCESS)
def __init__(self, no): print "file:", no hpros = win32api.GetCurrentProcess() self.fno = win32api.DuplicateHandle(hpros, no, hpros, 0, 0, 2) om.create_object(self) self.buffer = "" self.recv_buffer = create_string_buffer(64) self.send_buffer = create_string_buffer(64) self.send_ch = SL.channel() self.recv_ch = SL.channel() self.recvol = OVERLAPPED() self.sendol = OVERLAPPED() self.recv_wsabuf = WSABUF() self.send_wsabuf = WSABUF()
def createProcess(self, cmd): self.start_time = time.time() hInputRead, hInputWriteTemp = self.newPipe() hOutReadTemp, hOutWrite = self.newPipe() pid = win32api.GetCurrentProcess() # This one is duplicated as inheritable. hErrWrite = win32api.DuplicateHandle(pid, hOutWrite, pid, 0, 1, win32con.DUPLICATE_SAME_ACCESS) # These are non-inheritable duplicates. hOutRead = self.dup(hOutReadTemp) hInputWrite = self.dup(hInputWriteTemp) # dup() closed hOutReadTemp, hInputWriteTemp si = win32process.STARTUPINFO() si.hStdInput = hInputRead si.hStdOutput = hOutWrite si.hStdError = hErrWrite si.dwFlags = win32process.STARTF_USESTDHANDLES | \ win32process.STARTF_USESHOWWINDOW si.wShowWindow = win32con.SW_HIDE # pass True to allow handles to be inherited. Inheritance is # problematic in general, but should work in the controlled # circumstances of a service process. create_flags = win32process.CREATE_NEW_CONSOLE info = win32process.CreateProcess(None, cmd, None, None, True, create_flags, None, None, si) # (NOTE: these really aren't necessary for Python - they are closed # as soon as they are collected) hOutWrite.Close() hErrWrite.Close() hInputRead.Close() # We don't use stdin hInputWrite.Close() # start a thread collecting output t = threading.Thread( target=self.outputCaptureThread, args = (hOutRead, )) t.start() self.output_thread = t return info
def manage_request(self, request, client_address): try: procHandle = win32api.GetCurrentProcess() th = win32api.DuplicateHandle(procHandle, win32api.GetCurrentThread(), procHandle, 0, 0, win32con.DUPLICATE_SAME_ACCESS) try: # Pretend Python doesn't have the interpreter lock. self.lckThreadHandles.acquire() self.thread_handles.append(th) self.lckThreadHandles.release() try: self.finish_request(request, client_address) except: s = StringIO.StringIO() traceback.print_exc(file=s) self.servicemanager.LogErrorMsg(s.getvalue()) finally: # Pretend Python doesn't have the interpreter lock... self.lckThreadHandles.acquire() self.thread_handles.remove(th) self.lckThreadHandles.release() except: s = StringIO.StringIO() traceback.print_exc(file=s) self.servicemanager.LogErrorMsg(s.getvalue())
def make_inheritable(token): '''Create an inheritable handle''' return win32api.DuplicateHandle(win32api.GetCurrentProcess(), token, win32api.GetCurrentProcess(), 0, 1, win32con.DUPLICATE_SAME_ACCESS)
def run(self, cmdline): # security attributes for pipes sAttrs = win32security.SECURITY_ATTRIBUTES() sAttrs.bInheritHandle = 1 # create pipes hStdin_r, self.hStdin_w = win32pipe.CreatePipe(sAttrs, 0) self.hStdout_r, hStdout_w = win32pipe.CreatePipe(sAttrs, 0) self.hStderr_r, hStderr_w = win32pipe.CreatePipe(sAttrs, 0) # set the info structure for the new process. StartupInfo = win32process.STARTUPINFO() StartupInfo.hStdInput = hStdin_r StartupInfo.hStdOutput = hStdout_w StartupInfo.hStdError = hStderr_w StartupInfo.dwFlags = win32process.STARTF_USESTDHANDLES # Mark doesn't support wShowWindow yet. # StartupInfo.dwFlags = StartupInfo.dwFlags | win32process.STARTF_USESHOWWINDOW # StartupInfo.wShowWindow = win32con.SW_HIDE # Create new output read handles and the input write handle. Set # the inheritance properties to FALSE. Otherwise, the child inherits # the these handles; resulting in non-closeable handles to the pipes # being created. pid = win32api.GetCurrentProcess() tmp = win32api.DuplicateHandle( pid, self.hStdin_w, pid, 0, 0, # non-inheritable!! win32con.DUPLICATE_SAME_ACCESS) # Close the inhertible version of the handle win32file.CloseHandle(self.hStdin_w) self.hStdin_w = tmp tmp = win32api.DuplicateHandle( pid, self.hStdout_r, pid, 0, 0, # non-inheritable! win32con.DUPLICATE_SAME_ACCESS) # Close the inhertible version of the handle win32file.CloseHandle(self.hStdout_r) self.hStdout_r = tmp # start the process. hProcess, hThread, dwPid, dwTid = win32process.CreateProcess( None, # program cmdline, # command line None, # process security attributes None, # thread attributes 1, # inherit handles, or USESTDHANDLES won't work. # creation flags. Don't access the console. 0, # Don't need anything here. # If you're in a GUI app, you should use # CREATE_NEW_CONSOLE here, or any subprocesses # might fall victim to the problem described in: # KB article: Q156755, cmd.exe requires # an NT console in order to perform redirection.. None, # no new environment None, # current directory (stay where we are) StartupInfo) # normally, we would save the pid etc. here... # Child is launched. Close the parents copy of those pipe handles # that only the child should have open. # You need to make sure that no handles to the write end of the # output pipe are maintained in this process or else the pipe will # not close when the child process exits and the ReadFile will hang. win32file.CloseHandle(hStderr_w) win32file.CloseHandle(hStdout_w) win32file.CloseHandle(hStdin_r) self.stdin = os.fdopen(msvcrt.open_osfhandle(self.hStdin_w, 0), "wb") self.stdin.write('hmmmmm\r\n') self.stdin.flush() self.stdin.close() self.stdout = os.fdopen(msvcrt.open_osfhandle(self.hStdout_r, 0), "rb") print("Read on stdout: ", repr(self.stdout.read())) self.stderr = os.fdopen(msvcrt.open_osfhandle(self.hStderr_r, 0), "rb") print("Read on stderr: ", repr(self.stderr.read()))
def DuplicateHandle(handle): """Duplicates a win32 handle.""" proc = win32api.GetCurrentProcess() return win32api.DuplicateHandle(proc,handle,proc,0,0,win32con.DUPLICATE_SAME_ACCESS)
def __init__(self, reactor, protocol, command, args, environment, path): _pollingfile._PollingTimer.__init__(self, reactor) self.protocol = protocol # security attributes for pipes sAttrs = win32security.SECURITY_ATTRIBUTES() sAttrs.bInheritHandle = 1 # create the pipes which will connect to the secondary process self.hStdoutR, hStdoutW = win32pipe.CreatePipe(sAttrs, 0) self.hStderrR, hStderrW = win32pipe.CreatePipe(sAttrs, 0) hStdinR, self.hStdinW = win32pipe.CreatePipe(sAttrs, 0) win32pipe.SetNamedPipeHandleState(self.hStdinW, win32pipe.PIPE_NOWAIT, None, None) # set the info structure for the new process. StartupInfo = win32process.STARTUPINFO() StartupInfo.hStdOutput = hStdoutW StartupInfo.hStdError = hStderrW StartupInfo.hStdInput = hStdinR StartupInfo.dwFlags = win32process.STARTF_USESTDHANDLES # Create new handles whose inheritance property is false pid = win32api.GetCurrentProcess() tmp = win32api.DuplicateHandle(pid, self.hStdoutR, pid, 0, 0, win32con.DUPLICATE_SAME_ACCESS) win32file.CloseHandle(self.hStdoutR) self.hStdoutR = tmp tmp = win32api.DuplicateHandle(pid, self.hStderrR, pid, 0, 0, win32con.DUPLICATE_SAME_ACCESS) win32file.CloseHandle(self.hStderrR) self.hStderrR = tmp tmp = win32api.DuplicateHandle(pid, self.hStdinW, pid, 0, 0, win32con.DUPLICATE_SAME_ACCESS) win32file.CloseHandle(self.hStdinW) self.hStdinW = tmp # Add the specified environment to the current environment - this is # necessary because certain operations are only supported on Windows # if certain environment variables are present. env = os.environ.copy() env.update(environment or {}) # create the process cmdline = ' '.join([cmdLineQuote(a) for a in args]) # TODO: error detection here. self.hProcess, hThread, dwPid, dwTid = win32process.CreateProcess( command, cmdline, None, None, 1, 0, env, path, StartupInfo) win32file.CloseHandle(hThread) # close handles which only the child will use win32file.CloseHandle(hStderrW) win32file.CloseHandle(hStdoutW) win32file.CloseHandle(hStdinR) self.closed = 0 self.closedNotifies = 0 # set up everything self.stdout = _pollingfile._PollableReadPipe( self.hStdoutR, lambda data: self.protocol.childDataReceived(1, data), self.outConnectionLost) self.stderr = _pollingfile._PollableReadPipe( self.hStderrR, lambda data: self.protocol.childDataReceived(2, data), self.errConnectionLost) self.stdin = _pollingfile._PollableWritePipe(self.hStdinW, self.inConnectionLost) for pipewatcher in self.stdout, self.stderr, self.stdin: self._addPollableResource(pipewatcher) # notify protocol self.protocol.makeConnection(self)
def startBackgroundProcess(self): """Method to start a process running in the background. """ with process_lock: # security attributes for pipes sAttrs = win32security.SECURITY_ATTRIBUTES() sAttrs.bInheritHandle = 1 # create pipes for the process to write to hStdin_r, hStdin = win32pipe.CreatePipe(sAttrs, 0) hStdout = win32file.CreateFile( self.stdout, win32file.GENERIC_WRITE | win32file.GENERIC_READ, win32file.FILE_SHARE_DELETE | win32file.FILE_SHARE_READ | win32file.FILE_SHARE_WRITE, sAttrs, win32file.CREATE_ALWAYS, win32file.FILE_ATTRIBUTE_NORMAL, None) hStderr = win32file.CreateFile( self.stderr, win32file.GENERIC_WRITE | win32file.GENERIC_READ, win32file.FILE_SHARE_DELETE | win32file.FILE_SHARE_READ | win32file.FILE_SHARE_WRITE, sAttrs, win32file.CREATE_ALWAYS, win32file.FILE_ATTRIBUTE_NORMAL, None) try: # set the info structure for the new process. StartupInfo = win32process.STARTUPINFO() StartupInfo.hStdInput = hStdin_r StartupInfo.hStdOutput = hStdout StartupInfo.hStdError = hStderr StartupInfo.dwFlags = win32process.STARTF_USESTDHANDLES # Create new handles for the thread ends of the pipes. The duplicated handles will # have their inheritence properties set to false so that any children inheriting these # handles will not have non-closeable handles to the pipes pid = win32api.GetCurrentProcess() tmp = win32api.DuplicateHandle(pid, hStdin, pid, 0, 0, win32con.DUPLICATE_SAME_ACCESS) win32file.CloseHandle(hStdin) hStdin = tmp # start the process, and close down the copies of the process handles # we have open after the process creation (no longer needed here) old_command = command = self.__quotePath(self.command) for arg in self.arguments: command = '%s %s' % (command, self.__quotePath(arg)) # Windows CreateProcess maximum lpCommandLine length is 32,768 # http://msdn.microsoft.com/en-us/library/ms682425%28VS.85%29.aspx if len(command) >= 32768: # pragma: no cover raise ValueError( "Command line length exceeded 32768 characters: %s..." % command[:1000]) dwCreationFlags = 0 if IS_PRE_WINDOWS_8: # pragma: no cover # In case PySys is itself running in a job, might need to explicitly breakaway from it so we can give # it its own, but only for old pre-windows 8/2012, which support nested jobs dwCreationFlags = dwCreationFlags | win32process.CREATE_BREAKAWAY_FROM_JOB if self.command.lower().endswith(('.bat', '.cmd')): # If we don't start suspended there's a slight race condition but due to some issues with # initially-suspended processes hanging (seen many years ago), to be safe, only bother to close the # race condition for shell scripts (which is the main use case for this anyway) dwCreationFlags = dwCreationFlags | win32con.CREATE_SUSPENDED self.__job = self._createParentJob() try: self.__hProcess, self.__hThread, self.pid, self.__tid = win32process.CreateProcess( None, command, None, None, 1, dwCreationFlags, self.environs, os.path.normpath(self.workingDir), StartupInfo) except pywintypes.error as e: raise ProcessError("Error creating process %s: %s" % (old_command, e)) try: if not self.disableKillingChildProcesses: win32job.AssignProcessToJobObject( self.__job, self.__hProcess) else: self.__job = None # pragma: no cover except Exception as e: # pragma: no cover # Shouldn't fail unless process already terminated (which can happen since # if we didn't use SUSPENDED there's an inherent race here) if win32process.GetExitCodeProcess( self.__hProcess) == win32con.STILL_ACTIVE: log.warning( 'Failed to associate process %s with new job: %s (this may prevent automatic cleanup of child processes)' % (self, e)) # force use of TerminateProcess not TerminateJobObject if this failed self.__job = None if (dwCreationFlags & win32con.CREATE_SUSPENDED) != 0: win32process.ResumeThread(self.__hThread) finally: win32file.CloseHandle(hStdin_r) win32file.CloseHandle(hStdout) win32file.CloseHandle(hStderr) # set the handle to the stdin of the process self.__stdin = hStdin
def __init__(self, args, bufsize=0, stdin=None, stdout=None, stderr=None, universal_newlines=False, close_fds=False, timeout_for_child_stream_duplication_event=30, **kwargs): if not isinstance(bufsize, int): raise TypeError("bufsize must be an integer") self.commandline_passed = {} self._cleanup_on_terminate = [] for s, p, m in [('stdin', stdin, 'w'), ('stdout', stdout, 'r'), ('stderr', stderr, 'r')]: if p is None: self.commandline_passed[s] = (None, 'null') elif p == subprocess.PIPE: if m == 'r': mode = 'rU' if universal_newlines else 'rb' else: mode = 'wb' piperead, pipewrite = os.pipe() myfile = os.fdopen(pipewrite if m == 'w' else piperead, mode, bufsize) childhandle = str( int( msvcrt.get_osfhandle(pipewrite if m == 'r' else piperead))) self._cleanup_on_terminate.append(pipewrite if m == 'r' else piperead) self.commandline_passed[s] = (myfile, childhandle, piperead, pipewrite) else: if isinstance(p, int): childhandle = msvcrt.get_osfhandle(stdin) else: # Assuming file-like object childhandle = msvcrt.get_osfhandle(p.fileno()) #The base implementation duplicates the handle, so we will too #It doesn't need to be inheritable for us, though cp = win32api.GetCurrentProcess() childhandle = win32api.DuplicateHandle( cp, childhandle, cp, 0, #desiredAccess ignored because of DUPLICATE_SAME_ACCESS 0, #Inheritable win32con.DUPLICATE_SAME_ACCESS) self.commandline_passed[s] = (None, str(int(childhandle)), childhandle, p) self._wait_for_child_duplication_event = win32event.CreateEvent( None, 1, #bManualReset 0, None) args += [ str(os.getpid()), str(int(self._wait_for_child_duplication_event)), self.commandline_passed['stdin'][1], self.commandline_passed['stdout'][1], self.commandline_passed['stderr'][1], ] super(HandlesOverCommandLinePopen, self).__init__(args, bufsize=bufsize, stdin=None, stdout=None, stderr=None, close_fds=close_fds, universal_newlines=universal_newlines, **kwargs) if timeout_for_child_stream_duplication_event: if not self.wait_for_child_stream_duplication_event( timeout_for_child_stream_duplication_event): logger.warning( "Timed out waiting for child process to duplicate its io streams" ) self.stdin = self.commandline_passed['stdin'][0] self.stdout = self.commandline_passed['stdout'][0] self.stderr = self.commandline_passed['stderr'][0]
def __init__(self, cmd, mode='t', cwd=None, env=None, avatar=None): log.info("Process.__init__(cmd=%r, mode=%r, cwd=%r, env=%r)", cmd, mode, cwd, env) # Keep a reference to ensure it is around for this object's destruction. self.__log = log self.mCmd = cmd self.mCwd = cwd self.mEnv = env self.mAvatar = avatar self.mMode = mode if self.mMode not in ('t', 'b'): raise ProcessError("'mode' must be 't' or 'b'.") self.mClosed = False si = win32process.STARTUPINFO() si.dwFlags = (win32con.STARTF_USESTDHANDLES ^ win32con.STARTF_USESHOWWINDOW) # Create pipes for std handles. # (Set the bInheritHandle flag so pipe handles are inherited.) saAttr = pywintypes.SECURITY_ATTRIBUTES() saAttr.bInheritHandle = 1 #XXX Should maybe try with os.pipe. Dunno what that does for # inheritability though. hChildStdinRd, hChildStdinWr = win32pipe.CreatePipe(saAttr, 0) hChildStdoutRd, hChildStdoutWr = win32pipe.CreatePipe(saAttr, 0) hChildStderrRd, hChildStderrWr = win32pipe.CreatePipe(saAttr, 0) try: # Duplicate the parent ends of the pipes so they are not # inherited. hChildStdinWrDup = win32api.DuplicateHandle( win32api.GetCurrentProcess(), hChildStdinWr, win32api.GetCurrentProcess(), 0, 0, # not inherited DUPLICATE_SAME_ACCESS) win32api.CloseHandle(hChildStdinWr) self._hChildStdinWr = hChildStdinWrDup hChildStdoutRdDup = win32api.DuplicateHandle( win32api.GetCurrentProcess(), hChildStdoutRd, win32api.GetCurrentProcess(), 0, 0, # not inherited DUPLICATE_SAME_ACCESS) win32api.CloseHandle(hChildStdoutRd) self._hChildStdoutRd = hChildStdoutRdDup hChildStderrRdDup = win32api.DuplicateHandle( win32api.GetCurrentProcess(), hChildStderrRd, win32api.GetCurrentProcess(), 0, 0, # not inherited DUPLICATE_SAME_ACCESS) win32api.CloseHandle(hChildStderrRd) self._hChildStderrRd = hChildStderrRdDup # Set the translation mode and buffering. self._mode = 't' if self._mode == 't': flags = os.O_TEXT else: flags = 0 fdChildStdinWr = msvcrt.open_osfhandle(self._hChildStdinWr, flags) fdChildStdoutRd = msvcrt.open_osfhandle(self._hChildStdoutRd, flags) fdChildStderrRd = msvcrt.open_osfhandle(self._hChildStderrRd, flags) self.stdin = _FileWrapper(descriptor=fdChildStdinWr, handle=self._hChildStdinWr) logres.info("[%s] Process._start(): create child stdin: %r", id(self), self.stdin) self.stdout = _FileWrapper(descriptor=fdChildStdoutRd, handle=self._hChildStdoutRd) logres.info("[%s] Process._start(): create child stdout: %r", id(self), self.stdout) self.stderr = _FileWrapper(descriptor=fdChildStderrRd, handle=self._hChildStderrRd) logres.info("[%s] Process._start(): create child stderr: %r", id(self), self.stderr) si.hStdInput = hChildStdinRd si.hStdOutput = hChildStdoutWr si.hStdError = hChildStderrWr #si.wShowWindow = show si.wShowWindow = 1 si.dwFlags |= win32process.STARTF_USESTDHANDLES creation_flags = win32process.CREATE_NEW_CONSOLE (self.mProcess, self.mThread, self.mProcessId, self.mThreadId)\ = _safeCreateProcess( self.mAvatar, # Avatar None, # App name cmd, # Command None, # Process security attribs None, # Primary thread security attribs 1, # Handles are inherited creation_flags, # Creation Flags self.mEnv, # Environment self.mCwd, # Current Working Directory si) # STARTUPINFO finally: # Close child ends of pipes on the parent's side (the # parent's ends of the pipe are closed in the _FileWrappers.) win32file.CloseHandle(hChildStdinRd) win32file.CloseHandle(hChildStdoutWr) win32file.CloseHandle(hChildStderrWr)
def __init__(self, reactor, protocol, command, args, environment, path): """ Create a new child process. """ _pollingfile._PollingTimer.__init__(self, reactor) BaseProcess.__init__(self, protocol) # security attributes for pipes sAttrs = win32security.SECURITY_ATTRIBUTES() sAttrs.bInheritHandle = 1 # create the pipes which will connect to the secondary process self.hStdoutR, hStdoutW = win32pipe.CreatePipe(sAttrs, 0) self.hStderrR, hStderrW = win32pipe.CreatePipe(sAttrs, 0) hStdinR, self.hStdinW = win32pipe.CreatePipe(sAttrs, 0) win32pipe.SetNamedPipeHandleState(self.hStdinW, win32pipe.PIPE_NOWAIT, None, None) # set the info structure for the new process. StartupInfo = win32process.STARTUPINFO() StartupInfo.hStdOutput = hStdoutW StartupInfo.hStdError = hStderrW StartupInfo.hStdInput = hStdinR StartupInfo.dwFlags = win32process.STARTF_USESTDHANDLES # Create new handles whose inheritance property is false currentPid = win32api.GetCurrentProcess() tmp = win32api.DuplicateHandle(currentPid, self.hStdoutR, currentPid, 0, 0, win32con.DUPLICATE_SAME_ACCESS) win32file.CloseHandle(self.hStdoutR) self.hStdoutR = tmp tmp = win32api.DuplicateHandle(currentPid, self.hStderrR, currentPid, 0, 0, win32con.DUPLICATE_SAME_ACCESS) win32file.CloseHandle(self.hStderrR) self.hStderrR = tmp tmp = win32api.DuplicateHandle(currentPid, self.hStdinW, currentPid, 0, 0, win32con.DUPLICATE_SAME_ACCESS) win32file.CloseHandle(self.hStdinW) self.hStdinW = tmp # Add the specified environment to the current environment - this is # necessary because certain operations are only supported on Windows # if certain environment variables are present. env = os.environ.copy() env.update(environment or {}) env = { os.fsdecode(key): os.fsdecode(value) for key, value in env.items() } # Make sure all the arguments are Unicode. args = [os.fsdecode(x) for x in args] cmdline = quoteArguments(args) # The command, too, needs to be Unicode, if it is a value. command = os.fsdecode(command) if command else command path = os.fsdecode(path) if path else path # TODO: error detection here. See #2787 and #4184. def doCreate(): flags = win32con.CREATE_NO_WINDOW self.hProcess, self.hThread, self.pid, dwTid = win32process.CreateProcess( command, cmdline, None, None, 1, flags, env, path, StartupInfo) try: doCreate() except pywintypes.error as pwte: if not _invalidWin32App(pwte): # This behavior isn't _really_ documented, but let's make it # consistent with the behavior that is documented. raise OSError(pwte) else: # look for a shebang line. Insert the original 'command' # (actually a script) into the new arguments list. sheb = _findShebang(command) if sheb is None: raise OSError("%r is neither a Windows executable, " "nor a script with a shebang line" % command) else: args = list(args) args.insert(0, command) cmdline = quoteArguments(args) origcmd = command command = sheb try: # Let's try again. doCreate() except pywintypes.error as pwte2: # d'oh, failed again! if _invalidWin32App(pwte2): raise OSError("%r has an invalid shebang line: " "%r is not a valid executable" % (origcmd, sheb)) raise OSError(pwte2) # close handles which only the child will use win32file.CloseHandle(hStderrW) win32file.CloseHandle(hStdoutW) win32file.CloseHandle(hStdinR) # set up everything self.stdout = _pollingfile._PollableReadPipe( self.hStdoutR, lambda data: self.proto.childDataReceived(1, data), self.outConnectionLost, ) self.stderr = _pollingfile._PollableReadPipe( self.hStderrR, lambda data: self.proto.childDataReceived(2, data), self.errConnectionLost, ) self.stdin = _pollingfile._PollableWritePipe(self.hStdinW, self.inConnectionLost) for pipewatcher in self.stdout, self.stderr, self.stdin: self._addPollableResource(pipewatcher) # notify protocol self.proto.makeConnection(self) self._addPollableResource(_Reaper(self))
def __init__(self, reactor, protocol, command, args, environment, path): self.reactor = reactor self.protocol = protocol self.outBuffer = reactor.AllocateReadBuffer(self.bufferSize) self.errBuffer = reactor.AllocateReadBuffer(self.bufferSize) # This is the buffer for *reading* stdin, which is only done to # determine if the other end of the pipe was closed. self.inBuffer = reactor.AllocateReadBuffer(self.bufferSize) # IO operation classes self.readOutOp = ops.ReadOutOp(self) self.readErrOp = ops.ReadErrOp(self) self.readInOp = ops.ReadInOp(self) self.writeInOp = ops.WriteInOp(self) self.writeBuffer = "" self.writing = False self.finished = False self.offset = 0 self.writeBufferedSize = 0 self.closingStdin = False self.closedStdin = False self.closedStdout = False self.closedStderr = False # Stdio handles self.hChildStdinRd = None self.hChildStdinWr = None self.hChildStdinWrDup = None self.hChildStdoutRd = None self.hChildStdoutWr = None self.hChildStdoutRdDup = None self.hChildStderrRd = None self.hChildStderrWr = None self.hChildStderrRdDup = None self.closedNotifies = 0 # increments to 3 (for stdin, stdout, stderr) self.closed = False # set to true when all 3 handles close self.exited = False # set to true when WFMO thread gets signalled proc handle. See doWaitForProcessExit. # Set the bInheritHandle flag so pipe handles are inherited. saAttr = win32security.SECURITY_ATTRIBUTES() saAttr.bInheritHandle = 1 currentPid = win32api.GetCurrentProcess( ) # -1 which stands for current process self.pid = os.getpid() # unique pid for pipe naming # Create a pipe for the child process's STDOUT. self.stdoutPipeName = r"\\.\pipe\twisted-iocp-stdout-%d-%d-%d" % ( self.pid, counter.next(), time.time()) self.hChildStdoutRd = win32pipe.CreateNamedPipe( self.stdoutPipeName, win32con.PIPE_ACCESS_INBOUND | win32con.FILE_FLAG_OVERLAPPED, # open mode win32con.PIPE_TYPE_BYTE, # pipe mode 1, # max instances self.pipeBufferSize, # out buffer size self.pipeBufferSize, # in buffer size 0, # timeout saAttr) self.hChildStdoutWr = win32file.CreateFile( self.stdoutPipeName, win32con.GENERIC_WRITE, win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE, saAttr, win32con.OPEN_EXISTING, win32con.FILE_FLAG_OVERLAPPED, 0) # Create noninheritable read handle and close the inheritable read # handle. self.hChildStdoutRdDup = win32api.DuplicateHandle( currentPid, self.hChildStdoutRd, currentPid, 0, 0, win32con.DUPLICATE_SAME_ACCESS) win32api.CloseHandle(self.hChildStdoutRd) self.hChildStdoutRd = self.hChildStdoutRdDup # Create a pipe for the child process's STDERR. self.stderrPipeName = r"\\.\pipe\twisted-iocp-stderr-%d-%d-%d" % ( self.pid, counter.next(), time.time()) self.hChildStderrRd = win32pipe.CreateNamedPipe( self.stderrPipeName, win32con.PIPE_ACCESS_INBOUND | win32con.FILE_FLAG_OVERLAPPED, # open mode win32con.PIPE_TYPE_BYTE, # pipe mode 1, # max instances self.pipeBufferSize, # out buffer size self.pipeBufferSize, # in buffer size 0, # timeout saAttr) self.hChildStderrWr = win32file.CreateFile( self.stderrPipeName, win32con.GENERIC_WRITE, win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE, saAttr, win32con.OPEN_EXISTING, win32con.FILE_FLAG_OVERLAPPED, 0) # Create noninheritable read handle and close the inheritable read # handle. self.hChildStderrRdDup = win32api.DuplicateHandle( currentPid, self.hChildStderrRd, currentPid, 0, 0, win32con.DUPLICATE_SAME_ACCESS) win32api.CloseHandle(self.hChildStderrRd) self.hChildStderrRd = self.hChildStderrRdDup # Create a pipe for the child process's STDIN. This one is opened # in duplex mode so we can read from it too in order to detect when # the child closes their end of the pipe. self.stdinPipeName = r"\\.\pipe\twisted-iocp-stdin-%d-%d-%d" % ( self.pid, counter.next(), time.time()) self.hChildStdinWr = win32pipe.CreateNamedPipe( self.stdinPipeName, win32con.PIPE_ACCESS_DUPLEX | win32con.FILE_FLAG_OVERLAPPED, # open mode win32con.PIPE_TYPE_BYTE, # pipe mode 1, # max instances self.pipeBufferSize, # out buffer size self.pipeBufferSize, # in buffer size 0, # timeout saAttr) self.hChildStdinRd = win32file.CreateFile( self.stdinPipeName, win32con.GENERIC_READ, win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE, saAttr, win32con.OPEN_EXISTING, win32con.FILE_FLAG_OVERLAPPED, 0) # Duplicate the write handle to the pipe so it is not inherited. self.hChildStdinWrDup = win32api.DuplicateHandle( currentPid, self.hChildStdinWr, currentPid, 0, 0, win32con.DUPLICATE_SAME_ACCESS) win32api.CloseHandle(self.hChildStdinWr) self.hChildStdinWr = self.hChildStdinWrDup # set the info structure for the new process. This is where # we tell the process to use the pipes for stdout/err/in. StartupInfo = win32process.STARTUPINFO() StartupInfo.hStdOutput = self.hChildStdoutWr StartupInfo.hStdError = self.hChildStderrWr StartupInfo.hStdInput = self.hChildStdinRd StartupInfo.dwFlags = win32process.STARTF_USESTDHANDLES # create the process cmdline = quoteArguments(args) self.hProcess, hThread, dwPid, dwTid = win32process.CreateProcess( command, # name cmdline, # command line None, # process security attributes None, # primary thread security attributes 1, # handles are inherited 0, # creation flags environment, # if NULL, use parent environment path, # current directory StartupInfo) # STARTUPINFO pointer # close handles which only the child will use win32file.CloseHandle(self.hChildStderrWr) win32file.CloseHandle(self.hChildStdoutWr) win32file.CloseHandle(self.hChildStdinRd) # Begin reading on stdout and stderr, before we have output on them. self.readOutOp.initiateOp(self.hChildStdoutRd, self.outBuffer) self.readErrOp.initiateOp(self.hChildStderrRd, self.errBuffer) # Read stdin which was opened in duplex mode so we can detect when # the child closed their end of the pipe. self.readInOp.initiateOp(self.hChildStdinWr, self.inBuffer) # When the process is done, call connectionLost(). # This function returns right away. Note I call this after # protocol.makeConnection to ensure that the protocol doesn't # have processEnded called before protocol.makeConnection. self.reactor.processWaiter.beginWait(self.reactor, self.hProcess, self) # notify protocol by calling protocol.makeConnection and specifying # ourself as the transport. self.protocol.makeConnection(self)
def processCreate(sName, asArgs): """ Returns a (pid, handle, tid) tuple on success. (-1, None) on failure (logged). """ # Construct a command line. sCmdLine = '' for sArg in asArgs: if sCmdLine == '': sCmdLine += '"' else: sCmdLine += ' "' sCmdLine += sArg sCmdLine += '"' # Try start the process. # pylint: disable=no-member dwCreationFlags = win32con.CREATE_NEW_PROCESS_GROUP oStartupInfo = win32process.STARTUPINFO() # pylint: disable=c-extension-no-member try: (hProcess, hThread, uPid, uTid) = win32process.CreateProcess( sName, # pylint: disable=c-extension-no-member sCmdLine, # CommandLine None, # ProcessAttributes None, # ThreadAttibutes 1, # fInheritHandles dwCreationFlags, None, # Environment None, # CurrentDirectory. oStartupInfo) except: reporter.logXcpt('sName="%s" sCmdLine="%s"' % (sName, sCmdLine)) return (-1, None, -1) # Dispense with the thread handle. try: hThread.Close() # win32api.CloseHandle(hThread); except: reporter.logXcpt() # Try get full access to the process. try: hProcessFullAccess = win32api.DuplicateHandle( # pylint: disable=c-extension-no-member win32api.GetCurrentProcess(), # pylint: disable=c-extension-no-member hProcess, win32api.GetCurrentProcess(), # pylint: disable=c-extension-no-member win32con.PROCESS_TERMINATE | win32con.PROCESS_QUERY_INFORMATION | win32con.SYNCHRONIZE | win32con.DELETE, False, 0) hProcess.Close() # win32api.CloseHandle(hProcess); hProcess = hProcessFullAccess except: reporter.logXcpt() reporter.log2('processCreate -> %#x, hProcess=%s %#x' % ( uPid, hProcess, hProcess.handle, )) return (uPid, hProcess, uTid)
def __init__(self, reactor, protocol, command, args, environment, path): _pollingfile._PollingTimer.__init__(self, reactor) BaseProcess.__init__(self, protocol) # security attributes for pipes sAttrs = win32security.SECURITY_ATTRIBUTES() sAttrs.bInheritHandle = 1 # create the pipes which will connect to the secondary process self.hStdoutR, hStdoutW = win32pipe.CreatePipe(sAttrs, 0) self.hStderrR, hStderrW = win32pipe.CreatePipe(sAttrs, 0) hStdinR, self.hStdinW = win32pipe.CreatePipe(sAttrs, 0) win32pipe.SetNamedPipeHandleState(self.hStdinW, win32pipe.PIPE_NOWAIT, None, None) # set the info structure for the new process. StartupInfo = win32process.STARTUPINFO() StartupInfo.hStdOutput = hStdoutW StartupInfo.hStdError = hStderrW StartupInfo.hStdInput = hStdinR StartupInfo.dwFlags = win32process.STARTF_USESTDHANDLES # Create new handles whose inheritance property is false currentPid = win32api.GetCurrentProcess() tmp = win32api.DuplicateHandle(currentPid, self.hStdoutR, currentPid, 0, 0, win32con.DUPLICATE_SAME_ACCESS) win32file.CloseHandle(self.hStdoutR) self.hStdoutR = tmp tmp = win32api.DuplicateHandle(currentPid, self.hStderrR, currentPid, 0, 0, win32con.DUPLICATE_SAME_ACCESS) win32file.CloseHandle(self.hStderrR) self.hStderrR = tmp tmp = win32api.DuplicateHandle(currentPid, self.hStdinW, currentPid, 0, 0, win32con.DUPLICATE_SAME_ACCESS) win32file.CloseHandle(self.hStdinW) self.hStdinW = tmp # Add the specified environment to the current environment - this is # necessary because certain operations are only supported on Windows # if certain environment variables are present. env = os.environ.copy() env.update(environment or {}) cmdline = quoteArguments(args) # TODO: error detection here. def doCreate(): self.hProcess, self.hThread, self.pid, dwTid = win32process.CreateProcess( command, cmdline, None, None, 1, 0, env, path, StartupInfo) try: doCreate() except pywintypes.error, pwte: if not _invalidWin32App(pwte): # This behavior isn't _really_ documented, but let's make it # consistent with the behavior that is documented. raise OSError(pwte) else: # look for a shebang line. Insert the original 'command' # (actually a script) into the new arguments list. sheb = _findShebang(command) if sheb is None: raise OSError( "%r is neither a Windows executable, " "nor a script with a shebang line" % command) else: args = list(args) args.insert(0, command) cmdline = quoteArguments(args) origcmd = command command = sheb try: # Let's try again. doCreate() except pywintypes.error, pwte2: # d'oh, failed again! if _invalidWin32App(pwte2): raise OSError( "%r has an invalid shebang line: " "%r is not a valid executable" % ( origcmd, sheb)) raise OSError(pwte2)
import msvcrt import win32api import win32con # Get file descriptor from argument ppid = int(sys.argv[1]) pipearg = int(sys.argv[2]) pipe2arg = int(sys.argv[3]) curproc = win32api.GetCurrentProcess() parent_process = win32api.OpenProcess(win32con.PROCESS_DUP_HANDLE, 0, int(ppid)) in_file_handle = win32api.DuplicateHandle( parent_process, pipearg, curproc, 0, #desiredAccess ignored because of DUPLICATE_SAME_ACCESS 0, #Inheritable win32con.DUPLICATE_SAME_ACCESS | win32con.DUPLICATE_CLOSE_SOURCE) out_file_handle = win32api.DuplicateHandle( parent_process, pipe2arg, curproc, 0, #desiredAccess ignored because of DUPLICATE_SAME_ACCESS 0, #Inheritable win32con.DUPLICATE_SAME_ACCESS | win32con.DUPLICATE_CLOSE_SOURCE) pipeinfd = msvcrt.open_osfhandle(int(in_file_handle), os.O_RDONLY) pipeoutfd = msvcrt.open_osfhandle(int(out_file_handle), os.O_WRONLY)
def make_inheritable(token): """Return a duplicate of handle, which is inheritable""" return win32api.DuplicateHandle(win32api.GetCurrentProcess(), token, win32api.GetCurrentProcess(), 0, 1, win32con.DUPLICATE_SAME_ACCESS)
def make_inheritable(self, handle): p = win32api.GetCurrentProcess() ret = win32api.DuplicateHandle(p, handle, p, 0, 1, win32con.DUPLICATE_SAME_ACCESS) win32api.CloseHandle(handle) return ret