ϪfUdZddlmZddlZddlZddlZddlZddlZddlZddl Z ddl Z ddl m Z ddl mZmZmZmZmZded<ded<es dd lmZmZdd lmZdd lmZmZmZdd lm Z dd l!m"Z"ddl#m$Z$m%Z%ddl&m'Z'm(Z(ddl)m*Z*ddl+m,Z,e*jZred ddl.Z/e/Z. ddl0Z1ddl2Z2e1Z0ejfZ3iZ4ded<d&dZ5dZ6dZ7GddejpZ9GddejpZ:Gdde Z;GddZ<e<Z=d Z> d'd!Z?ee"Gd"d#e;Z@ee"Gd$d%ejpe;ZAy#e$rYwxYw#e$rdZ.YwxYw#e$rdZ0YwxYw)(z UNIX Process management. Do NOT use this module directly - use reactor.spawnProcess() instead. Maintainer: Itamar Shtull-Trauring ) annotationsN) defaultdict) TYPE_CHECKINGDictListOptionalTupleint _PS_CLOSE_PS_DUP2)POSIX_SPAWN_CLOSEPOSIX_SPAWN_DUP2) implementer)abstracterrorfdesc) BaseProcess)IProcessTransport)CONNECTION_DONECONNECTION_LOST)failurelog)platform) switchUIDz^twisted.internet.process does not work on Windows. Use the reactor.spawnProcess() API instead.zDict[int, _BaseProcess]reapProcessHandlerschttjD]}|jy)z( Reap all registered processes. N)listrvalues reapProcess)processs :/usr/lib/python3/dist-packages/twisted/internet/process.pyreapAllProcessesr"Hs. +2245c8|tvr td tj|tj\}}|r|jy|t|<y#t $r6t jd|dt j|Yyd}Y\wxYw)z Register a process handler for the given pid, in case L{reapAllProcesses} is called. @param pid: the pid of the process. @param process: a process handler. z.Try to register an already registered process.Failed to reap :N) r RuntimeErroroswaitpidWNOHANG BaseExceptionrmsgerr processEnded)pidr auxPIDstatuss r!registerReapProcessHandlerr2Rs !!KLL C4V$$+C   /#a()  ; s'A8BBBcP|tvr t||k(s tdt|=y)zd Unregister a process handler previously registered with L{registerReapProcessHandler}. z+Try to unregister a process not registered.N)rr')r/r s r!unregisterReapProcessHandlerr4ms. & &+>s+Cw+NHIIC r#cBeZdZdZdZdZdZd dZdZdZ dZ d Z d Z y ) ProcessWritera (Internal) Helper class to write into a Process's input pipe. I am a helper which describes a selectable asynchronous writer to a process's input pipe, including stdin. @ivar enableReadHack: A flag which determines how readability on this write descriptor will be handled. If C{True}, then readability may indicate the reader for this write descriptor has been closed (ie, the connection has been lost). If C{False}, then readability events are ignored. rFctjj||tj|||_||_||_tjtj|jjsd|_n/|rd|_n% tj|jd|jr|j#yy#t $r d|_Y0wxYw)zJ Initialize, specifying a Process instance to connect to. FTrN)rFileDescriptor__init__rsetNonBlockingprocnamefdstatS_ISFIFOr(fstatfilenost_modeenableReadHackreadOSError startReading)selfreactorr<r=rB forceReadHacks r!r:zProcessWriter.__init__s ((w7 V$  }}RXXdkkm4<<=#(D  "&D   + q)          +&*# +s$C C32C3c|jS)z< Return the fileno() of my process's stdin. r>rHs r!rBzProcessWriter.fileno wwr#ctj|j|}|t|k(r|jr|j |Sz6 Write some data to the open process. )r writeToFDr>lenrDrG)rHdatarvs r! writeSomeDatazProcessWriter.writeSomeDatas>__TWWd + T?t22     r#cd|jtjj||yN) stopReadingrr9writerHrSs r!rYzProcessWriter.writes$ %%dD1r#cH|jrtS|jy)a The only way a write pipe can become "readable" is at EOF, because the child has closed it, and we're using a reactor which doesn't distinguish between readable and closed (such as the select reactor). Except that's not true on linux < 2.6.11. It has the following characteristics: write pipe is completely empty => POLLOUT (writable in select), write pipe is not completely empty => POLLIN (readable in select), write pipe's reader closed => POLLIN|POLLERR (readable and writable in select) That's what this funky code is for. If linux was not broken, this function could be simply "return CONNECTION_LOST". N)rDrrXrMs r!doReadzProcessWriter.doReads   " "    r#ctj|jtjj |||j j|j|y)z= See abstract.FileDescriptor.connectionLost. N) r setBlockingr>rr9connectionLostr<childConnectionLostr=rHreasons r!r_zProcessWriter.connectionLostsD $''"..tV< %%dii8r#N)F) __name__ __module__ __qualname____doc__ connectedicrDr:rBrUrYr\r_r#r!r6r6ws6 I BN > 2( 9r#r6c>eZdZdZdZdZdZdZdZdZ dZ d Z y ) ProcessReaderzx ProcessReader I am a selectable representation of a process's output pipe, such as stdout and stderr. Tctjj||tj|||_||_||_|jy)zA Initialize, specifying a process to connect to. N) rr9r:rr;r<r=r>rG)rHrIr<r=rBs r!r:zProcessReader.__init__sI ((w7 V$   r#c|jS)z= Return the fileno() of my process's stderr. rLrMs r!rBzProcessReader.filenorNr#c|dk(sJtS)Nr#)rrZs r!rUzProcessReader.writeSomeDatass{{r#cVtj|j|jS)z@ This is called when the pipe becomes readable. )r readFromFDr> dataReceivedrMs r!r\zProcessReader.doReads!):):;;r#cP|jj|j|yrW)r<childDataReceivedr=rZs r!rqzProcessReader.dataReceiveds ##DIIt4r#c|jrc|jsVd|_|j|jj d|j t jtyyy)Nr7r) rg disconnectingrXrI callLaterr_rFailurerrMs r!loseConnectionzProcessReader.loseConnection sT >>$"4"4!"D      LL " "4&&(H #5>r#ctjj|||jj |j |y)zk Close my end of the pipe, signal the Process (which signals the ProcessProtocol). N)rr9r_r<r`r=ras r!r_zProcessReader.connectionLosts2 ..tV< %%dii8r#N) rcrdrerfrgr:rBrUr\rqrxr_rir#r!rkrks1I  < 59r#rkc\eZdZUdZdZded<dZdZdZdZ dZ d Z d Z d Z d Zdd Zy) _BaseProcessz0 Base class for Process and PTYProcess. Nz Optional[int]r1c tj|jtj\}}|rt|||jyy#t$r+}|j t j k(rd}nYd}~Pd}~wwxYw#t$r<tjd|jdtjd}YwxYw)a Try to reap a process (without blocking) via waitpid. This is called when sigchild is caught or a Process object loses its "connection" (stdout is closed) This ought to result in reaping all zombie processes, since it will be called twice as often as it needs to be. (Unfortunately, this is a slightly experimental approach, since UNIX has no way to be really sure that your process is going to go away w/o blocking. I don't want to block.) Nr%r&) r(r)r/r*rFerrnoECHILDr+rr,r-r4r.)rHr/r1es r!rz_BaseProcess.reapProcess#s   jj2::> V  (d 3   f %  77ell*C    GGodhhZq1 2 GGIC s01A B !B?B B  B ACCcdx}}tj|rtj|}ntj|}|s|rt j |||St j |SrW)r( WIFEXITED WEXITSTATUSWTERMSIGrProcessTerminated ProcessDone)rHr1exitCodesigs r! _getReasonz_BaseProcess._getReasonAs_3 << ~~f-H++f%C s**8S&A A  ((r#c|dvrttd|}|j t t j |j|y#t $r-}|jtjk(r td}~wwxYw)a* Send the given signal C{signalID} to the process. It'll translate a few signals ('HUP', 'STOP', 'INT', 'KILL', 'TERM') from a string representation to its int value, otherwise it'll pass directly the value provided @type signalID: C{str} or C{int} )HUPSTOPINTKILLTERMSIGN) getattrsignalr/ProcessExitedAlreadyr(killrFr}ESRCH)rHsignalIDrs r! signalProcessz_BaseProcess.signalProcessKsv = =vXJ'78H 88 &( (  GGDHHh ' ww%++%*,,  s A B(BBctdtjD]M}tj|tjk(s*tj|tj OyNr7)rangerNSIG getsignalSIG_IGNSIG_DFL)rH signalnums r!_resetSignalDispositionz$_BaseProcess._resetSignalDisposition`sG q&++. 9I *fnn< i8 9r#cy)a0 Try to use posix_spawnp() instead of fork(), if possible. This implementation returns False because the non-PTY subclass implements the actual logic; we can't yet use this for pty processes. @return: a boolean indicating whether posix_spawnp() was used or not. Fri)rHpathuidgid executableargs environmentkwargss r!_trySpawnInsteadOfForkz#_BaseProcess._trySpawnInsteadOfForkksr#c |j|||||||rytj}tj t j |_|j dk(rT tjd|jd i||j||||||t j0d  |rtj2d |_y#t$r tjt jddd} dj|t!|t#|} | j%| t'j(| | j+t-d D]} t j.| n#t$rYnwxYwYwxYw#t$r|rtj2wxYw) a Fork and then exec sub-process. @param path: the path where to run the new process. @type path: L{bytes} or L{unicode} @param uid: if defined, the uid used to run the new process. @type uid: L{int} @param gid: if defined, the gid used to run the new process. @type gid: L{int} @param executable: the executable to run in a new process. @type executable: L{str} @param args: arguments used to create the new process. @type args: L{list}. @param environment: environment used for the new process. @type environment: L{dict}. @param kwargs: keyword arguments to L{_setupChild} method. Nrwbzutf-8)encodingz)Upon execvpe {} {} in environment id {} :filer7ri)rgc isenableddisabler(forkr/syssettrace _setupChild _execChildr+io TextIOWrapperfdopenformatstridrY traceback print_excflushrclose_exitenabler1) rHrrrrrrrcollectorEnabledstderrr,r>s r!_forkz_BaseProcess._forkxs2  & & #sJk6  <<> D wwyDHxx1}+LL&$D$$.v.OOD#sJkRV   IIK _%&""$!1!1"))At2Dw!WNVV&D 2k? S)!++8 "'()BHHRL)(G&1    sCF(+=C F%&B,FF% FF%FF%$F%(!G ct)zB Setup the child process. Override in subclasses. NotImplementedError)rHrrs r!rz_BaseProcess._setupChilds "##r#c,|rtj|||b|tj}|tj}tjdtj dt ||tj|||y)z? The exec() which is done in the forked child. Nr)r(chdirgeteuidgetegidsetuidsetgidrexecvpe)rHrrrrrrs r!rz_BaseProcess._execChildsk  HHTN ?co{jjl{jjl IIaL IIaL c3  :t[1r#cxdj|jj|j|jS)z5 String representation of a process. z<{} pid={} status={}>)r __class__rcr/r1rMs r!__repr__z_BaseProcess.__repr__s2'-- NN # # HH KK  r#)returnr)rcrdrerfr1__annotations__r/rrrrrrrrrrir#r!r{r{sG!FM C&<)* 9 iV$ 2" r#r{cheZdZdZej Zej ZeZdZ dZ dZ dZ dZ dZy) _FDDetectorav This class contains the logic necessary to decide which of the available system techniques should be used to detect the open file descriptors for the current process. The chosen technique gets monkey-patched into the _listOpenFDs method of this class so that the detection only needs to occur once. @ivar listdir: The implementation of listdir to use. This gets overwritten by the test cases. @ivar getpid: The implementation of getpid to use, returns the PID of the running process. @ivar openfile: The implementation of open() to use, by default the Python builtin. cT|j|j|jg|_yrW)_procFDImplementation_devFDImplementation_fallbackFDImplementation_implementationsrMs r!r:z_FDDetector.__init__s'  & &  % %  * *! r#cL|j|_|jS)z Return an iterable of file descriptors which I{may} be open in this process. This will try to return the fewest possible descriptors without missing any. )_getImplementation _listOpenFDsrMs r!rz_FDDetector._listOpenFDs!s$!335  ""r#c|jD]5} |}|jdd5|}ddd|k7s3|cSS#t$rYEwxYw#1swY%xYw)a Pick a method which gives correct results for C{_listOpenFDs} in this runtime environment. This involves a lot of very platform-specific checks, some of which may be relatively expensive. Therefore the returned method should be saved and re-used, rather than always calling this method to determine what it is. See the implementation for the details of how a method is selected. z /dev/nullrN)rr+openfile)rHimplbeforeafters r!rz_FDDetector._getImplementation,sx)) D {C0     !    sAA AAA cbd}|j|Dcgc] }t|}}|Scc}w)z Simple implementation for systems where /dev/fd actually works. See: http://www.freebsd.org/cgi/man.cgi?fdescfs z/dev/fd)listdirr )rHdnamer>results r!rz _FDDetector._devFDImplementationIs3 $(LL$78b#b'88 9s,cd|jfz}|j|Dcgc] }t|c}Scc}w)zk Simple implementation for systems where /proc/pid/fd exists (we assume it works). z /proc/%d/fd)getpidrr )rHrr>s r!rz!_FDDetector._procFDImplementationRs8  00"&,,u"56BB666s=c ddl}td|j|jd}t |S#t$rd}Yt |SwxYw)au Fallback implementation where either the resource module can inform us about the upper bound of how many FDs to expect, or where we just guess a constant maximum if there is no resource module. All possible file descriptors from 0 to that upper bound are returned with no attempt to exclude invalid file descriptor values. rNir7)resourcemin getrlimit RLIMIT_NOFILE ImportErrorr)rHrmaxfdss r!rz%_FDDetector._fallbackFDImplementationZs[ N x11(2H2HI!LMFV} F V} s9 AAN)rcrdrerfr(rropenrr:rrrrrrir#r!rrs>  jjG YYFH  #:7r#rc*tjS)zZ Use the global detector object to figure out which FD implementation to use. )detectorrrir#r!rrrs  ""r#cFt|}tt}|jD]\}}||j |t |t |j zt |jzddfd }g} i} t|jD]\}}||j|||r |x} | |<| j ||| f|| vr4| j || ||f||r`| j || |fw||k(r*||s|} | j||| f|| |f|| fg| j |||f|jD] \} }| |vs |r| j || f"| S)a` Get the C{file_actions} parameter for C{posix_spawn} based on the parameters describing the current process state. @param fdState: A list of 2-tuples of (file descriptor, close-on-exec flag). @param doClose: the integer to use for the 'close' instruction @param doDup2: the integer to use for the 'dup2' instruction rcFvr dz vr jSr)add) allocatednextFDsr! allocateFDz#_getFileActions..allocateFDs/ ! aKF ! f r#)rr ) dictrritemsappendsetrkeyssortedremoveextend)fdStatechildToParentFDdoClosedoDup2 fdStateDictparentToChildreninChildinParentrr relocationsnewtempFDeachFD uninheritablerrs @@r!_getFileActionsrzs"w-K-8->,2243"))'23K I _++-..I _))+,,I F%'FK#O$9$9$;<!;"))'2 G $)3 5C+g& MM67C0 1 { " MM6;x#8'B C#H- w H(=>?7"x( (\FMM#Xv6#VW5$f- vx9:C!;F"-!2!2!4-  ( MM7F+ ,- Mr#ceZdZdZdZdZdZdZeZ e Z ddZ dZ eedd[ dZd Zd Zd Zd Zd ZdZdZdZdZdZdZdZdZdZdZdZ dZ!y)Processa An operating-system Process. This represents an operating-system process with arbitrary input/output pipes connected to it. Those pipes may represent standard input, standard output, and standard error, or any other file descriptor. On UNIX, this is implemented using posix_spawnp() when possible (or fork(), exec(), pipe() and fcntl() when not). These calls may not exist elsewhere so this code is not cross-platform. (also, windows can only select on sockets...) FrNc ||_|s(d| jvsJd| jvsJtj||i|_i} | dddd} |j } | r t d| gfd} i} | jD]\}}| rt d|z||dk(r'| \}}| rt d||fz|| |<|| |<C|dk(r'| \}}| rt d||fz|| |<|| |<ot|tk(s J|d || |<| r t d | | r t d | |j||||||| ||_| jD]v\}}tj| || |dk(r#|j||||}||j|<| |dk(sR|j!||||d }||j|<x |j|jj#|t)|j*|y#t$rD]} tj| wxYw#t$rt%j&Y`wxYw)  Spawn an operating-system process. This is where the hard work of disconnecting all currently open files / forking / executing the new process happens. (This is executed automatically when a Process is instantiated.) This will also run the subprocess as a given user ID and group ID, if specified. (Implementation Note: this doesn't support all the arcane nuances of setXXuid on UNIX: it will assume that either your effective or real UID is 0.) rwN)rr7rchildFDsc`tj\}}j||g||fSrW)r(piper)rr _openedPipess r!rzProcess.__init__..pipes-779DAq   A 'a4Kr#z[%d]zreadFD=%d, writeFD=%dz should be an intfdmaphelpers)rT)rJ)_reactorrr{r:pipesdebugprintrtyper rr+r(rprotoprocessReaderFactoryprocessWriterFactorymakeConnectionrr-r2r/)rHrIrrrrr#rrrrr rrchildFDtargetreadFDwriteFDparentFDreaderwriterrs @r!r:zProcess.__init__s0  hoo// //hoo// //dE*   H    *h '    #+>>#3 ,&7*F3S=&*fOFG58IIJ%,E'N'-GG$s]&*fOFG58IIJ%+E'N'.GG$<3.N6*CH#%'I #'I  I-,I-c |Z|X|?tjj|tjjdk7st|jddry|j d}g} t D]I} tj| tjtj} | j| | fK|tj}tdtjD cgc]*} tj | tj"k(r| ,} } tj$|||t'| |t(t*| |_d|_y #t$rYwxYwcc} w) z Try to use posix_spawnp() instead of fork(), if possible. @return: a boolean indicating whether posix_spawnp() was used or not. ._neverUseSpawnFrr7)rr) file_actions setsigdefrT)r(rabspathrrgetrfcntlF_GETFD FD_CLOEXECrrFenvironrrrrr posix_spawnprr r r/r1)rHrrrrrrrrrr isCloseOnExec everySignal setSigDefs r!rzProcess._trySpawnInsteadOfForkWsI_!(=QTAU(Ut}}&6> 7#"n 8F 8 % FEMM5CSCS T  67  8  **K %Q 4  ,>   ??   ( (   /   s?3E"5/E1" E.-E.r9c&|j}|r!tj}|jd|j }t D]3}||vr|r|j k(r tj|5|rtd|t|jD]}||}||k(r(|rtd|ztj|5||j vrjtj|}|rtd||fztj|t!|j#D]\} } | |k(s ||| <|rtd||fztj$||g} |j D]+}|| vs||jvs| j'|-|rtd| | D]}tj||j)y#t$rYwxYw) a fdmap[childFD] = parentFD The child wants to end up with 'childFD' attached to what used to be the parent's parentFD. As an example, a bash command run like 'command 2>&1' would correspond to an fdmap of {0:0, 1:1, 2:1}. 'command >foo.txt' would be {0:0, 1:os.open('foo.txt'), 2:2}. This is accomplished in two steps:: 1. close all file descriptors that aren't values of fdmap. This means 0 .. maxfds (or just the open fds within that range, if the platform supports '/proc//fd'). 2. for each childFD:: - if fdmap[childFD] == childFD, the descriptor is already in place. Make sure the CLOEXEC flag is not set, then delete the entry from fdmap. - if childFD is in fdmap.values(), then the target descriptor is busy. Use os.dup() to move it elsewhere, update all fdmap[childFD] items that point to it, then close the original. Then fall through to the next case. - now fdmap[childFD] is not in fdmap.values(), and is free. Use os.dup2() to move it to the right place, then close the original. zstarting _setupChild rrz%d already in placezos.dup(%d) -> %dzos.dup2(%d,%d)oldN) debug_childrrrYrrrBr(rr+r!rrr_unsetCloseOnExecduprrdup2rr) rHrr errfddestListr>childr( newtargetcpr>s r!rzProcess._setupChilds<   JJE KK0 1<<>. BX~u||~-     '5u -EJJL) 'E5\F/&8uE''.ELLN*!#u I0E93EEERHHUO $U[[] 311:'0E!H1*fe_<5I&- '@,,. #B}UZZ\)JJrN #  %5 ) B HHRL  $$&g!  s)H HHc@|j|j|yrWrrYrHr'rSs r! writeToChildzProcess.writeToChilds 7!!$'r#c\||jvr|j|jyyrW)rrx)rHr's r! closeChildFDzProcess.closeChildFDs* djj JJw  . . 0 !r#c|jjD]#}t|ts|j %yrW)rr isinstancerkrXrHrHs r!pauseProducingzProcess.pauseProducings1""$ A!]+  r#c|jjD]#}t|ts|j %yrW)rrrPrkrGrQs r!resumeProducingzProcess.resumeProducings2""$ !A!]+  !r#c&|jdy)zD Call this to close standard input on this process. rNrNrMs r! closeStdinzProcess.closeStdins !r#c&|jdyrrVrMs r! closeStdoutzProcess.closeStdout !r#c&|jdyNrrVrMs r! closeStderrzProcess.closeStderr rZr#cd|j|j|jyrW)rWr]rYrMs r!rxzProcess.loseConnection s$   r#c^d|jvr|jdj|yyz Call this to write to standard input on this process. NOTE: This will silently lose data if there is no standard input. rNrJrZs r!rYz Process.writes*  ? JJqM   % r#cd|jvr |jdj||y|jy)z Call this to register producer for standard input. If there is no standard input producer.stopProducing() will be called immediately. rN)rregisterProducer stopProducing)rHproducer streamings r!rbzProcess.registerProducers3  ? JJqM * *8Y ?  " " $r#c\d|jvr|jdjyy)z= Call this to unregister producer for standard input.rN)runregisterProducerrMs r!rgzProcess.unregisterProducer&s(  ? JJqM , , . r#c^d|jvr|jdj|yyr`)r writeSequence)rHseqs r!rizProcess.writeSequence,s*  ? JJqM ' ' , r#c<|jj||yrWr#rs)rHr=rSs r!rszProcess.childDataReceived5s $$T40r#ctj|j|j|j|= |jj ||jy#t $rtjY0wxYwrW) r(rrrBr#r`r+rr-maybeCallProcessEnded)rHr'rbs r!r`zProcess.childConnectionLost8sm G$++-. JJw   JJ * *7 3 ""$  GGI sA++B  B c|jry|js|jytj |yrW)r lostProcessrr{rnrMs r!rnzProcess.maybeCallProcessEndedCs4 ::      **40r#ctrWrrMs r!getHostzProcess.getHostP !##r#ctrWrrMs r!getPeerzProcess.getPeerTrsr#NNN)"rcrdrerfr r?r1r/r6r%rkr$r:rrr(rrLrNrRrTrWrYr]rxrYrbrgrirsr`rnrrrurir#r!rrs  EK F C((  v3p-^r>4(0 "^'@(1 !   & %/ -1 % 1$$r#rcheZdZdZdZdZ ddZdZdZdZ dZ d Z d Z d Z d Zd ZdZdZy) PTYProcessz< An operating-system Process that uses PTY support. rNc >t!t| ttfs t dt j j||tj||t| ttfr| \} } } ntj\} } |j||||||| | tj| tj| | |_|j#d|_d|_ |j(j+|t1|j2|y#t$rBt| ttfs*tj| tj| wxYw#t$rt-j.YwxYw)rNz:cannot use PTYProcess on platforms without the pty module.)masterfdslavefdr7r)ptyrPtuplerrrr9r:r{openptyrr+r(rrr;r>rGrgr1r#r&rr-r2r/) rHrIrrrrr#rrusePTYrzr{_s r!r:zPTYProcess.__init__bs]0 ;z&5$-@%L  ((w7dE* fudm ,#) Hgq # Hg  JJ!  "  X&    JJ % %d + #488T2# fudm4"!     GGI sD.<E<.A E9<FFctj|tjtj |t j dtdD]}||k7s tj|tj|dtj|dtj|dtD]}|dkDs tj| |jy#t$rY=wxYw)a9 Set up child process after C{fork()} but before C{exec()}. This involves: - closing C{masterfd}, since it is not used in the subprocess - creating a new session with C{os.setsid} - changing the controlling terminal of the process (and the new session) to point at C{slavefd} - duplicating C{slavefd} to standard input, output, and error - closing all other open file descriptors (according to L{_listOpenFDs}) - re-setting all signal handlers to C{SIG_DFL} @param masterfd: The master end of a PTY file descriptors opened with C{openpty}. @type masterfd: L{int} @param slavefd: The slave end of a PTY opened with C{openpty}. @type slavefd: L{int} rrr7rN) r(rsetsidr5ioctltermios TIOCSCTTYrrBrr+r)rHrzr{r>s r!rzPTYProcess._setupChilds6   GW..3( BW}     . BAvHHRL  $$&%sC88 DDcyrWrirMs r!rWzPTYProcess.closeStdins r#cyrWrirMs r!rYzPTYProcess.closeStdout r#cyrWrirMs r!r]zPTYProcess.closeStderrrr#cJtjjfdS)zM Called when my standard output stream is ready for reading. c<jjd|Srrl)rSrHs r!z#PTYProcess.doRead..s$**">">q$"Gr#)rrpr>rMs`r!r\zPTYProcess.doReads" GGG  r#c|jS)zR This returns the file number of standard output on this process. rLrMs r!rBzPTYProcess.filenorNr#cN|jdk(rtj|yyr\)rpr{rnrMs r!rnz PTYProcess.maybeCallProcessEndeds%   q  . .t 4 !r#ctjj||tj|j |xj dz c_|jy)zU I call this to clean up when one or all of my connections has died. r7N)rr9r_r(rr>rprnras r!r_zPTYProcess.connectionLostsG ..tV<  A ""$r#cBtj|j|SrP)rrQr>rZs r!rUzPTYProcess.writeSomeDatastww--r#ctrWr)rH descriptors r!rNzPTYProcess.closeChildFDrsr#ctrWrrKs r!rLzPTYProcess.writeToChild rsr#rv)rcrdrerfr1r/r:rrWrYr]r\rBrnr_rUrNrLrir#r!rxrxYs]F C  A3F.'`     5%. $$r#rx)rNone) rzList[Tuple[int, bool]]rzDict[int, int]rr rr rzList[Tuple[int, ...]])Brf __future__rr}rrr(rr?rr collectionsrtypingrrrrr rr r rr rzope.interfacertwisted.internetrrrtwisted.internet._baseprocessrtwisted.internet.interfacesrtwisted.internet.mainrrtwisted.pythonrrtwisted.python.runtimertwisted.python.utilr isWindowsr|_ptyr5_fcntlrrrr"r2r4r9r6rkr{rrrrrrxrir#r!rs # #==   S'3359B'+)8  6   C E11/1,1+6!e9H++e9P99H++99xg ;g TggT =#J #J#JJ  J  JZ N$lN$ N$b  s$((,s$ s$w!    * C Es6 E"%E.,E;"E+*E+.E87E8;FF