
    <iʧ                        S r SSKrSSKrSSKrSSKrSSKrSSKrSSKrSSKrSSK	r	SSK
r
SSKrSSKrSSKrSSKrSSKrSSKrSSKrSSKrSSKrSSKJr  SSKJr  \R.                  R0                  R3                  SSSS5      r\\\\\R<                  \\S	 \ \\!\0r"0 r#S
/r$Sr%Sr&Sr'Sr(Sr)Sr*Sr+Sr,Sr-Sr.Sr/Sr0Sr1Sr2Sr3Sr4Sr5Sr6Sr7Sr8\Rr                  " \Rt                  5      r; \Rx                  Rz                  r=S\=l>        \Rr                  " \R~                  5      \Rr                  " \;5      /\=l@        SqASqBS qC\R                  " 5       rE " S! S"\F5      rG " S# S$\G5      rH " S% S&\I5      rJS' rKS( rLS) rMS* rNS+ rOSDS, jrPS- rQSES. jrRS/ rSSFS1 jrTS2 rUS3 rVS4 rWS5 rXS6 rYS7 rZSES8 jr[S9 r\S: r]S; r^SES< jr_S= r`\S0SSS4S> jraS? rbS@ rcSA rdSB reSC rf\Srg\Trh\Uri\Vrj\Xrk\Yrl\Zrm\\rn\]rog!   Sr= N= f)GaA	  
Helper functions for working with the underlying system. These are mostly os
dependent, only working on linux, osx, and bsd. In almost all cases they're
best-effort, providing **None** if the lookup fails.

.. versionchanged:: 1.3.0
   Dropped the get_* prefix from several function names. The old names still
   work, but are deprecated aliases.

.. versionchanged:: 1.5.0
   Added the **SYSTEM_CALL_TIME** global, which tracks total time spent making
   system commands.

**Module Overview:**

::

  is_windows - checks if we're running on windows
  is_mac - checks if we're running on a mac
  is_gentoo - checks if we're running on gentoo
  is_slackware - checks if we're running on slackware
  is_bsd - checks if we're running on the bsd family of operating systems

  is_available - determines if a command is available on this system
  is_running - determines if a given process is running
  size_of - provides the memory usage of an object
  call - runs the given system command and provides back the results

  name_by_pid - gets the name for a process by the given pid
  pid_by_name - gets the pid for a process by the given name
  pid_by_port - gets the pid for a process listening to a given port
  pid_by_open_file - gets the pid for the process with an open file
  pids_by_user - provides processes owned by a user
  cwd - provides the current working directory for a given process
  user - provides the user a process is running under
  start_time - provides the unix timestamp when the process started
  tail - provides lines from the end of a file
  bsd_jail_id - provides the BSD jail id a given process is running within
  bsd_jail_path - provides the path of the given BSD jail

  is_tarfile - checks if the given path is a tarball
  expand_path - expands relative paths and ~ entries
  files_with_suffix - provides files with the given suffix

  get_process_name - provides our process' name
  set_process_name - changes our process' name

.. data:: Status (enum)

  State of a subprocess.

  .. versionadded:: 1.6.0

  ====================  ===========
  Status                Description
  ====================  ===========
  PENDING               not yet started
  RUNNING               currently being performed
  DONE                  completed successfully
  FAILED                failed with an exception
  ====================  ===========
    N)	UNDEFINED)logPENDINGRUNNINGDONEFAILEDc                 \    [         R                  R                  U R                  5       5      $ N)	itertoolschainfrom_iterableitems)ds    J/home/james-whalen/.local/lib/python3.13/site-packages/stem/util/system.py<lambda>r   f   s    )////	:    ulimitzps -A co commandzps -ao ucomm=zps -p %s -o commzpgrep -x %szpidof %szps -o pid -C %szps axczlsof -tc %sznetstat -npltuzsockstat -4l -P tcp -p %szlsof -wnP -iTCP -sTCP:LISTENzlsof -tw %szps -o pid -u %szps -o pid -U %szpwdx %szlsof -a -p %s -d cwd -Fnzps -p %s -o jidz	jls -j %si      g        c                   $    \ rS rSrSrS rS rSrg)	CallError   a  
Error response when making a system call. This is an **OSError** subclass
with additional information about the process. Depending on the nature of the
error not all of these attributes will be available.

:var str msg: exception string
:var str command: command that was ran
:var int exit_status: exit code of the process
:var float runtime: time the command took to run
:var str stdout: stdout of the process
:var str stderr: stderr of the process
c                 L    Xl         X l        X0l        X@l        XPl        X`l        g r
   )msgcommandexit_statusruntimestdoutstderr)selfr   r   r   r   r   r   s          r   __init__CallError.__init__   s!    HL"LKKr   c                     U R                   $ r
   )r   )r    s    r   __str__CallError.__str__   s    88Or   )r   r   r   r   r   r   N)__name__
__module____qualname____firstlineno____doc__r!   r$   __static_attributes__ r   r   r   r      s    r   r   c                   ,   ^  \ rS rSrSrU 4S jrSrU =r$ )CallTimeoutError   z{
Error response when making a system call that has timed out.

.. versionadded:: 1.6.0

:var float timeout: time we waited
c                 <   > [         [        U ]  XX4XV5        Xpl        g r
   )superr.   r!   timeout)	r    r   r   r   r   r   r   r2   	__class__s	           r   r!   CallTimeoutError.__init__   s    	
D*3v^Lr   )r2   )r&   r'   r(   r)   r*   r!   r+   __classcell__)r3   s   @r   r.   r.      s     r   r.   c                   >    \ rS rSrSrS	S jrS rS r\S 5       r	Sr
g)

DaemonTask   a  
Invokes the given function in a subprocess, returning the value.

.. versionadded:: 1.6.0

:var function runner: function to be invoked by the subprocess
:var tuple args: arguments to provide to the subprocess
:var int priority: subprocess nice priority

:var stem.util.system.State status: state of the subprocess
:var float runtime: seconds subprocess took to complete
:var object result: return value of subprocess if successful
:var exception error: exception raised by subprocess if it failed
Nc                     Xl         X l        X0l        [        R                  U l        S U l        S U l        S U l        S U l	        S U l
        U(       a  U R                  5         g g r
   )runnerargspriorityStater   statusr   resulterror_process_piperun)r    r:   r;   r<   starts        r   r!   DaemonTask.__init__   sP    KIM--DKDLDKDJDMDJ
hhj r   c                 l   U R                   [        R                  :X  a  [        R                  " 5       u  U l        n[        R                  " [        R                  XR                  U R                  U R                  4S9U l        U R                  R                  5         [        R                  U l         gg)zP
Invokes the task if it hasn't already been started. If it has this is a
no-op.
)targetr;   N)r>   r=   r   multiprocessingPiperB   Processr7   _run_wrapperr<   r:   r;   rA   rD   r   )r    
child_pipes     r   rC   DaemonTask.run   s     {{emm#.335dj*%--z7N7NXbdqdqsws~s~  AE  AJ  AJ  XK  Ldm
mmMMdk	 $r   c                    U R                   [        R                  :X  a  U R                  5         U R                   [        R                  :X  a  U R
                  R                  5         U R                  R                  5       nUS   U l         US   U l	        U R                   [        R                  :X  a  US   U l        O(U R                   [        R                  :X  a
  US   U l        U R                   [        R                  :X  a  U R                  $ U R                   [        R                  :X  a  U R                  e[        SU R                   -  5      e)z
Provides the result of the daemon task. If still running this blocks until
the task is completed.

:returns: response of the function we ran

:raises: exception raised by the function if it failed with one
r         z+BUG: unexpected status from daemon task, %s)r>   r=   r   rC   r   rA   joinrB   recvr   r   r?   r   r@   RuntimeError)r    responses     r   rQ   DaemonTask.join  s     {{emm#
hhj{{emm#
mm"hQKdka[dl	

	"qk;;%,,&a[
{{ejj [[		$JJFTUUr   c                    [         R                   " 5       n[        R                  " U5         U(       a  U" U6 OU" 5       nU R                  [        R
                  [         R                   " 5       U-
  U45        U R                  5         g ! [         aB  nU R                  [        R                  [         R                   " 5       U-
  U45         S nANXS nAff = f! U R                  5         f = fr
   )	timeosnicesendr=   r   	Exceptionr   close)connr<   r:   r;   
start_timer?   excs          r   rK   DaemonTask._run_wrapper+  s    JGGH $vt}&(f
iiTYY[:5v>? jjl  ?
iityy{Z7=>>? jjls*   AB	 	
C8CC CC C*)	rB   rA   r;   r@   r<   r?   r:   r   r>   )Nr   F)r&   r'   r(   r)   r*   r!   rC   rQ   staticmethodrK   r+   r,   r   r   r7   r7      s,     
"V@ 
 
r   r7   c                  2    [         R                  " 5       S:H  $ )zZ
Checks if we are running on Windows.

:returns: **bool** to indicate if we're on Windows
Windowsplatformsystemr,   r   r   
is_windowsrg   9  s     
	i	''r   c                  2    [         R                  " 5       S:H  $ )zX
Checks if we are running on Mac OSX.

:returns: **bool** to indicate if we're on a Mac
Darwinrd   r,   r   r   is_macrj   C  s     
	h	&&r   c                  @    [         R                  R                  S5      $ )zW
Checks if we're running on Gentoo.

:returns: **bool** to indicate if we're on Gentoo
z/etc/gentoo-releaserX   pathexistsr,   r   r   	is_gentooro   M  s     
-	..r   c                  @    [         R                  R                  S5      $ )zp
Checks if we are running on a Slackware system.

:returns: **bool** to indicate if we're on a Slackware system
z/etc/slackware-versionrl   r,   r   r   is_slackwarerq   W  s     
0	11r   c                  2    [         R                  " 5       S;   $ )z
Checks if we are within the BSD family of operating systems. This currently
recognizes Macs, FreeBSD, and OpenBSD but may be expanded later.

:returns: **bool** to indicate if we're on a BSD OS
)ri   FreeBSDOpenBSDNetBSDrd   r,   r   r   is_bsdrv   a  s     
	H	HHr   c                 @   SU ;   a  U R                  S5      S   n U [        ;   a  gU(       a  U [        ;   a	  [        U    $ S[        R                  ;  a  gSn[        R                  S   R                  [        R
                  5       H  n[        R                  R                  X05      n[        5       (       a  US-  n[        R                  R                  U5      (       d  M\  [        R                  " U[        R                  5      (       d  M  Sn  O   U[        U '   U$ )a=  
Checks the current PATH to see if a command is available or not. If more
than one command is present (for instance "ls -a | grep foo") then this
just checks the first.

Note that shell (like cd and ulimit) aren't in the PATH so this lookup will
try to assume that it's available. This only happends for recognized shell
commands (those in SHELL_COMMANDS).

:param str command: command to search for
:param bool cached: makes use of available cached results if **True**

:returns: **True** if an executable we can use by that name exists in the
  PATH, **False** otherwise
 r   TPATHF.exe)splitSHELL_COMMANDSCMD_AVAILABLE_CACHErX   environpathseprm   rQ   rg   rn   accessX_OK)r   cached
cmd_existsrm   cmd_paths        r   is_availabler   l  s    " 	G^mmC #G'00w''RZZ*jj &&rzz2dww||D*H||&h	ww~~hBIIh$@$@j 3 ",g	r   c                    [        U [        5      (       a   [        R                  " U S5        g[        S5      (       a  [        5       (       a  [        n[        nO[        n[        n[        US5      nU(       d  [        US5      nU(       aW  U Vs/ s H  oDR                  5       PM     nn[        R                  R                  U 5      (       a  U /n U  H
  nXS;   d  M
    g   gg! [         a     gf = fs  snf )a{  
Checks for if a process with a given name or pid is running.

.. versionchanged:: 1.6.0
   Added support for list and pid arguments.

:param str,list,int command: process name if a str, multiple process names if
  a list, or pid if an int to be checked

:returns: **True** if the process is running, **False** if it's not among ps
  results, and **None** if ps can't be queried
r   TFpsN)
isinstanceintrX   killOSErrorr   rv   IS_RUNNING_PS_BSDIS_RUNNING_PS_LINUXcallstripstemutil_is_str)r   primary_resolversecondary_resolvercommand_listingccmds         r   
is_runningr     s     gggq" $xx*.,,+T2O/6o,;<OqOo<			7	#	#)#!  	S  < =s   C% C5%
C21C2c                    [         R                  R                  5       (       a  [        S5      eUc  [	        5       nO[        U 5      U;   a  g [        R                  " U 5      nUR                  [        U 5      5        [        U 5      [        ;   a-  [        [        U 5         " U 5       H  nU[        X15      -  nM     U$ ! [         a    [        R                  " S5      n N~f = f)a.  
Provides the `approximate memory usage of an object
<https://code.activestate.com/recipes/577504/>`_. This can recurse tuples,
lists, deques, dicts, and sets. To teach this function to inspect additional
object types expand SIZE_RECURSES...

::

  stem.util.system.SIZE_RECURSES[SomeClass] = SomeClass.get_elements

.. versionadded:: 1.6.0

:param object obj: object to provide the size of
:param set exclude: object ids to exclude from size estimation

:returns: **int** with the size of the object in bytes

:raises: **NotImplementedError** if using PyPy
z'PyPy does not implement sys.getsizeof()r   )r   prereqis_pypyNotImplementedErrorsetidsys	getsizeof	TypeErroraddtypeSIZE_RECURSESsize_of)objexcludesizeentrys       r   r   r     s    * 
[[
G
HH_eG	#w'==D 
++bg	#Y-tCy)#.
ge%%d / 
+ 
 ==Ds   C    C#"C#c                    Sn[         R                  R                  R                  5       (       aZ   [         R                  R                  R	                  U [         R                  R                  R
                  R                  5      S   nU(       dE   [        [        U -  5      nU(       a+  [        U5      S:X  a  US   S:X  a  US   R                  5       nU$ ! [         a     NZf = f! [         a    Sn NRf = f)a,  
Attempts to determine the name a given process is running under (not
including arguments). This uses...

::

  1. Information from /proc
  2. ps -p <pid> -o command

:param int pid: process id of the process to be queried

:returns: **str** with the process name, **None** if it can't be determined
Nr   rP   COMMANDrO   )r   r   procr   statsStatr   IOErrorr   GET_NAME_BY_PID_PSr   lenr   )pidprocess_nameresultss      r   name_by_pidr      s     ,	YY^^  ""YY^^))#tyy~~/B/B/J/JKANl 
'#-.g 3w<1$y)@QZ%%'l	)  
  gs$   AC C( 
C%$C%(C76C7Fc                    [        S5      (       aR  [        [        U -  S5      nU(       a8   [        [	        [
        U5      5      nU(       a  U$ [        U5      S:X  a  US   $  [        S5      (       ar  [        [        U -  S5      nU(       aX  [        U5      S:X  aI   [        [	        [
        US   R                  5       5      5      nU(       a  U$ [        U5      S:X  a  US   $  [        S5      (       a  [        5       (       dU  [        [        U -  S5      nU(       a;   [        [	        [
        USS 5      5      nU(       a  U$ [        U5      S:X  a  US   $  [        5       (       a  [        [        S5      nU(       au  U Vs/ s H0  oDR                  SU -  5      (       d  M  UR                  5       S   PM2     nn [        [	        [
        U5      5      nU(       a  U$ [        U5      S:X  a  US   $  [        S5      (       aR  [        [        U -  S5      nU(       a8   [        [	        [
        U5      5      nU(       a  U$ [        U5      S:X  a  US   $  [        S	5      (       a  [        5       (       a  U R                  S
5      (       d  U S
-   n / n[         R"                  R$                  R                  S	S5      nU(       a  [&        R(                  " SU -  5      nU HF  nUR+                  U5      nU(       d  M  UR-                  [        UR/                  S5      5      5        MH     U(       a  U$ [        U5      S:  a  US   $ [0        R2                  " SU -  5        U(       a  / $ S$ ! [         a     GNf = f! [         a     GNf = f! [         a     GN?f = fs  snf ! [         a     GNf = f! [         a     GNif = f)a  
Attempts to determine the process id for a running process, using...

::

  1. pgrep -x <name>
  2. pidof <name>
  3. ps -o pid -C <name> (linux)
     ps axc | egrep " <name>$" (bsd)
  4. lsof -tc <name>
  5. tasklist | str <name>.exe

:param str process_name: process name for which to fetch the pid
:param bool multiple: provides a list of all pids if **True**, otherwise
  results with multiple processes are discarded

:returns:
  Response depends upon the 'multiple' argument as follows...

  * if **False** then this provides an **int** with the process id or **None** if it can't be determined
  * if **True** then this provides a **list** of all **int** process ids, and an empty list if it can't be determined
pgrepNrO   r   pidofr   z %slsoftasklistrz   z^\s*%s\s+(?P<pid>[0-9]*)r   z failed to resolve a pid for '%s')r   r   GET_PID_BY_NAME_PGREPlistmapr   r   
ValueErrorGET_PID_BY_NAME_PIDOFr{   rv   GET_PID_BY_NAME_PS_LINUXGET_PID_BY_NAME_PS_BSDendswithGET_PID_BY_NAME_LSOFrg   r   r   rf   recompilesearchappendgroupr   debug)	r   multipler   pidsrprocess_idstasklist_regexlinematchs	            r   pid_by_namer   +  sT   @ '(<7>GCW%&+Y!^a.  '(<7>G3w<1$CWQZ--/01+Y!^a. * $88-<dCg		c#wqr{+,$K4yA~7N 
 xx+T2g	)0UAJJu|?S4T<1779Q<U	c#w'($K4yA~7N & &',6=GCW%&+Y!^a. 
 **,,  ((!F*lKii##J5Gzz">"MNn$%%d+5


SU!34
5	  
{a1~)).=>!T!{  *  @  	
	 V  	
	8  s   !M) M) 2M: M: $N N N#N=!N! N! !N2 N2 )
M76M7:
NN
NN!
N/.N/2
O ?O c                    [        S5      (       a  [        [        S5      nU(       a  U Vs/ s H  nSU -  U;   d  M  UPM     nn[        U5      S:X  aj  [        US   R	                  5       5      S:X  aJ  US   R	                  5       S   nUSUR                  S5       nUR                  5       (       a  [        U5      $ [        S	5      (       a  [        [        U -  S5      nU(       a  U Vs/ s H@  n[        UR	                  5       5      S:X  d  M"  S
U -  UR	                  5       S   ;   d  M>  UPMB     nn[        U5      S:X  a6  US   R	                  5       S   nUR                  5       (       a  [        U5      $ [        S5      (       a  [        [        S5      nU(       a  U Vs/ s H@  n[        UR	                  5       5      S:X  d  M"  S
U -  UR	                  5       S   ;   d  M>  UPMB     nn[        U5      S:X  a6  US   R	                  5       S   nUR                  5       (       a  [        U5      $ gs  snf s  snf s  snf )a  
Attempts to determine the process id for a process with the given port,
using...

::

  1. netstat -npltu | grep 127.0.0.1:<port>
  2. sockstat -4l -P tcp -p <port>
  3. lsof -wnP -iTCP -sTCP:LISTEN | grep ":<port>"

Most queries limit results to listening TCP connections. This function likely
won't work on Mac OSX.

:param int port: port where the process we're looking for is listening

:returns: **int** with the process id, **None** if it can't be determined
netstatNz127.0.0.1:%srO   r         /sockstatz:%s   rP   r   
      )
r   r   GET_PID_BY_PORT_NETSTATr   r{   findisdigitr   GET_PID_BY_PORT_SOCKSTATGET_PID_BY_PORT_LSOF)portr   r   r   s       r   pid_by_portr     s   N )*D1G#BGq~'<'AGgB	W	s71:#3#3#56!;!*""$Q'(w||C();;==S/* *+d2D9G#`GqAGGI!(;RSRYRYR[\]R^@^Gg`	W	aj #;;==S/* &'.G#aGqAGGI"(<%$,STSZSZS\]^S_A_Gga	W	aj #;;==S/	S CB a@ bs.   H4H4,!H9H9-H9%!H>
H>&H>c                     [        S5      (       aU  [        [        U -  / 5      n[        U5      S:X  a3  US   R	                  5       nUR                  5       (       a  [        U5      $ g)z
Attempts to determine the process id for a process with the given open file,
using...

::

  lsof -w <path>

:param str path: location of the socket file to query against

:returns: **int** with the process id, **None** if it can't be determined
r   rO   r   N)r   r   GET_PID_BY_FILE_LSOFr   r   r   r   )rm   r   r   s      r   pid_by_open_filer   N  sV    4 &'$.3G
7|qAJc	3x	r   c                     [        S5      (       aZ  [        5       (       a  [        [        U -  S5      nO[        [        U -  S5      nU(       a   [        [        [        USS 5      5      $ g! [         a     gf = f)z
Provides processes owned by a given user.

.. versionadded:: 1.5.0

:param str user: user to look up processes for

:returns: **list** with the process ids, **None** if it can't be determined
r   NrO   )	r   rv   r   GET_PIDS_BY_USER_BSDGET_PIDS_BY_USER_LINUXr   r   r   r   )userr   s     r   pids_by_userr   t  sv    " $xx)D0$7g+d2D9gCWQR[)** 
  	s   A, ,
A98A9c                    [         R                  R                  R                  5       (       a*   [         R                  R                  R	                  U 5      $ SU -  n[        S5      (       a  [        [        U -  S5      nU(       d  [        R                  " SU-  5        OUS   R                  S5      (       a  [        R                  " SU-  5        O[        U5      S:w  d4  US   R                  S	5      S:w  d  US   R                  S
U -  5      (       d  [        R                  " U< SU< 35        O&US   R                  S	S5      S   R                  5       $ [        S5      (       ax  [        [         U -  / 5      n[        U5      S:  a9  US   R                  S5      (       a   US   SS R                  5       nS	U;  a  U$  g[        R                  " U< SU< 35        g! [
         a     GNf = f)z
Provides the working directory of the given process.

:param int pid: process id of the process to be queried

:returns: **str** with the absolute path for the process' present working
  directory, **None** if it can't be determined
zcwd(%s):pwdxNz!%s pwdx didn't return any resultsr   zNo such processz'%s pwdx processes reported for this pidrO   rx   z%s: z% we got unexpected output from pwdx: r   rP   r   zn/z% we got unexpected output from lsof: )r   r   r   r   cwdr   r   GET_CWD_PWDXr   r   r   r   count
startswithr{   r   GET_CWD_LSOF)r   logging_prefixr   lsof_results       r   r   r     s    
YY^^  ""YY^^$$
 #.&
 <#%t,G	ii3nDE			.	/	/	ii9NJK	W	gaj..s3q8
@U@UV\_bVb@c@c	ii~wWXQZc1%a(..00" &<#%r*G
7|qWR[33D99BKO))+k 
K	 
 
 
 
ii~wWX	i  
s   (G$ $
G21G2c                    [        U [        5      (       a  U S:  a  g[        R                  R                  R                  5       (       an   SSKn[        R                  R                  R                  U 5      nU(       a9  UR                  5       (       a$  UR                  [        U5      5      R                  $ [        S5      (       a1  [        SU -  / 5      n[        U5      S:  a  US   R                  5       $ g!    NF= f)z
Provides the user a process is running under.

:param int pid: process id of the process to be queried

:returns: **str** with the username a process is running under, **None** if
  it can't be determined
r   Nr   zps -o user %srP   rO   )r   r   r   r   r   r   pwduidr   getpwuidpw_namer   r   r   )r   r   r   r   s       r   r   r     s     
C		q	YY^^  ""IINNs#c	||CH%--- $?S("-G
7|qQZ	
s   A,C: :C>c                 n   [        U [        5      (       a  U S:  a  g[        R                  R                  R                  5       (       ac   [        [        R                  R                  R                  U [        R                  R                  R                  R                  5      S   5      $  [        SU -  / 5      n[        U5      S:  aR  US   R                  5       n[        R                  " 5       [        R                  R                  R!                  U5      -
  $  g! [         a     Nf = f!    g= f)z
Provides the unix timestamp when the given process started.

:param int pid: process id of the process to be queried

:returns: **float** for the unix timestamp when the process began, **None**
  if it can't be determined
r   Nzps -p %s -o etimerP   rO   )r   r   r   r   r   r   floatr   r   
START_TIMEr   r   r   r   rW   	str_toolsparse_short_time_label)r   
ps_resultsetimes      r   r^   r^     s     
C		q	YY^^  ""499>>''TYY^^-@-@-K-KLQOPP	)C/4J
:!m!!#eYY[499..EEeLLL  
  
		s    A!D  .A/D0  
D-,D-0D4c              #     #    [        U [        5      (       a-  [        U S5       n[        X!5       H  nUv   M	      SSS5        gU R	                  SS5        U R                  5       nSnSnUb  US:  a  US:  a  U[        -
  S:  aD  U R	                  U[        -  S5        U R                  [        5      U-   R                  SS5      u  pgO&U R	                  SS5        U R                  U5      U-   n[        UR                  5       5       HA  nUb  US:  d  M  Ub  US-  n[        R                  R                  R                  U5      v   MC     U[        -  nUS-  nUb  US:  a	  US:  a  M  gggg! , (       d  f       GN<= f7f)	as  
Provides lines of a file starting with the end. For instance,
'tail -n 50 /tmp/my_log' could be done with...

::

  reversed(list(tail('/tmp/my_log', 50)))

:param str,file target: path or file object to read from
:param int lines: number of lines to read

:returns: **generator** that reads lines, starting with the end

:raises: **IOError** if unable to read the file
rbNr   rP   r   r      
rO   )r   stropentailseektell
BLOCK_SIZEreadr{   reversed
splitlinesr   r   r   _to_unicode)rG   linestarget_filer   block_end_byteblock_numbercontentcompleted_liness           r   r  r    sg    " 	fd	{{*$
 + 	 
	 	++a;;=.,'	%!)!);#a'kk,+Q/"(++j"9G"C!J!J5RS!Tg kk!QN3g=o3356	%!)
1*%ii!!--d33 7 j NAL% 
%!)!);));) 
	s)   "FE2CFAF.F2
F<Fc                    [        [        U -  / 5      n[        U5      S:X  aS  [        US   R                  5       5      S:X  a3  US   R	                  5       nUR                  5       (       a  [        U5      $ [        R                  " 5       nUS:X  a  [        R                  " SU -  5        g[        R                  " SU < SU< 35        g)a  
Gets the jail id for a process. These seem to only exist for FreeBSD (this
style for jails does not exist on Linux, OSX, or OpenBSD).

:param int pid: process id of the jail id to be queried

:returns: **int** for the jail id, zero if this can't be determined
rP   rO   rs   z)Unable to get the jail id for process %s.zbsd_jail_id(z): jail ids do not exist on r   )r   GET_BSD_JAIL_ID_PSr   r{   r   r   r   re   rf   r   warnr   )r   	ps_outputjidos_names       r   bsd_jail_idr  N  s    $ %+R0)^qS1!3!3!56!;
A,


C
{{}}XoOO'	HH83>? 
 IIWMN	
r   c                     U S:w  aX  [        [        U -  / 5      n[        U5      S:X  a6  [        US   R                  5       5      S:X  a  US   R                  5       S   $ g)z
Provides the path of the given FreeBSD jail.

:param int jid: jail id to be queried

:returns: **str** of the path prefix, **None** if this can't be determined
r   rP   rO         N)r   GET_BSD_JAIL_PATHr   r{   )r  
jls_outputs     r   bsd_jail_pathr  q  s_     	AX
 '#-r2J
:!JqM$7$7$9 :a ?]  "1%%	r   c                      [         R                  " U 5      $ ! [        [        4 a    [        R
                  " U 5      S   S:H  s $ f = f)z
Returns if the path belongs to a tarfile or not.

.. versionadded:: 1.2.0

:param str path: path to be checked

:returns: **True** if the path belongs to a tarball, **False** otherwise
r   zapplication/x-tar)tarfile
is_tarfiler   AttributeError	mimetypes
guess_type)rm   s    r   r!  r!    sK    (@d##
>	" @%a(,???@s    ,AAc                 R   [        5       (       a"  U R                  SS5      R                  S5      nOU R                  S5      nU(       a$  [        R                  R                  U5      (       a   U$ UR                  S5      (       a!  [        R                  R                  U5      nU$ U(       d  [        R                  " 5       nUR                  S5      (       d  UR                  S5      (       a  USS nOUS:X  a  S	nUS	:X  a  UnU$ [        R                  R                  X5      nU$ )
au  
Provides an absolute path, expanding tildes with the user's home and
appending a current working directory if the path was relative.

:param str path: path to be expanded
:param str cwd: current working directory to expand relative paths with, our
  process' if this is **None**

:returns: **str** of the path expanded to be an absolute path, never with an
  ending slash
r   \~z./z.\rP   N. )
rg   replacerstriprX   rm   isabsr   
expandusergetcwdrQ   )rm   r   relative_paths      r   expand_pathr0    s     \\LLd+2248MKK$M	"''--66, 
+ $$GG&&}5M& 
 IIKc %%)A)A%)H)H#AB'm	#	mm 
 ggll36m	r   c              #   P  #    [         R                  R                  U 5      (       a  U R                  U5      (       a  U v   gg[         R                  " U 5       HH  u  p#nU H<  nUR                  U5      (       d  M  [         R                  R                  X%5      v   M>     MJ     g7f)a%  
Iterates over files in a given directory, providing filenames with a certain
suffix.

.. versionadded:: 1.2.0

:param str base_path: directory to be iterated over
:param str suffix: filename suffix to look for

:returns: iterator that yields the absolute path for files with the given suffix
N)rX   rm   isfiler   walkrQ   )	base_pathsuffixroot_filesfilenames         r   files_with_suffixr:    s|      WW^^I&!!o " ''),(V$$T,
,  -s   A6B&<*B&c           	         [        U [        5      (       a  U R                  S5      nO[        [	        [        U 5      5      nSu  pxp[
        R
                  " 5       n US   [        ;   n[        R                  " U[        R                  [        R                  XUS9nU(       ay  UR                  5       ch  [
        R
                  " 5       U-
  U:  a#  [        SU-  SR                  U5      SUSSU5      e[
        R                  " S5        UR                  5       c  Mh  UR                  5       u  pU	R                  5       U
R                  5       p[
        R
                  " 5       U-
  n[         R"                  " S	X4-  5        [         R$                  " 5       (       a|  S
U -  nU	(       a)  U
(       a"  [         R&                  " USU	< SU
< 3-   5        OGU	(       a  [         R&                  " USU	-  -   5        O#U
(       a  [         R&                  " USU
-  -   5        UR                  5       nU(       d  US:w  a  [)        SX4-  5      eU	(       aN  U	R+                  SS5      R-                  5       [.           [0        [
        R
                  " 5       U-
  -  qSSS5        $ / [.           [0        [
        R
                  " 5       U-
  -  qSSS5        $ ! , (       d  f       $ = f! , (       d  f       $ = f! [         ai    [         R"                  " SX4-  5        U[2        :w  aC  Us [.           [0        [
        R
                  " 5       U-
  -  qSSS5        $ ! , (       d  f       $ = fe [(         a  n[         R"                  " SU < SU< S35        U[2        :w  aF  Us SnA[.           [0        [
        R
                  " 5       U-
  -  qSSS5        $ ! , (       d  f       $ = f[5        [        U5      SR                  U5      XxX5      eSnAff = f! [.           [0        [
        R
                  " 5       U-
  -  qSSS5        f ! , (       d  f       f = f= f)a  
call(command, default = UNDEFINED, ignore_exit_status = False)

Issues a command in a subprocess, blocking until completion and returning the
results. This is not actually ran in a shell so pipes and other shell syntax
are not permitted.

.. versionchanged:: 1.5.0
   Providing additional information upon failure by raising a CallError. This
   is a subclass of OSError, providing backward compatibility.

.. versionchanged:: 1.5.0
   Added env argument.

.. versionchanged:: 1.6.0
   Added timeout and cwd arguments.

:param str,list command: command to be issued
:param object default: response if the query fails
:param bool ignore_exit_status: reports failure if our command's exit status
  was non-zero
:param float timeout: maximum seconds to wait, blocks indefinitely if
  **None**
:param dict env: environment variables

:returns: **list** with the lines of output from the command

:raises:
  * **CallError** if this fails and no default was provided
  * **CallTimeoutError** if the timeout is reached without a default
rx   )NNNNr   )r   r   shellr   envNz)Process didn't finish after %0.1f secondsr)  gMbP?z System call: %s (runtime: %0.2f)zReceived from system (%s)z
, stdout:
z	
stderr:
z, stdout:
%sz, stderr:
%sz%s returned exit status %izutf-8r*  z(System call (timeout): %s (after %0.4fs)zSystem call (failed): z	 (error: ))r   r  r{   r   r   rW   r|   
subprocessPopenPIPEpollr.   rQ   sleepcommunicater   r   r   
is_tracingtracer   decoder
  SYSTEM_CALL_TIME_LOCKSYSTEM_CALL_TIMEr   r   )r   defaultignore_exit_statusr2   r   r=  command_listr   r   r   r   r^   is_shell_commandprocesstrace_prefixr_   s                   r   r   r     s?   J ==%LC)*L)?&+yy{*53#A.8|jooPZP_P_iy  MP  QGLLN"99;#g- !Lw!VX[X`X`amXnptv}  @B  DF  HO  P  P

5	 LLN" ((*NF\\^V\\^FiikJ&GII0G3EEF
~~07:l	F		,!PPQ		,6!99:		,6!99:,,.K+"20G3IIJJ]]7I.99;$ 
$))+
22 
	!   
$))+
22 
				 
 II8G;MMN)n 
$))+
22 
		 	 ^IIEF)n 
$))+
22 
		 c#h 6f]]^ 
$))+
22 
		s   B>K( EK( - KK(  K
K	
K%	(0O=P   M
M	
O=#*O8O=P   O
O	&O88O==P   Q P0'	Q0
P>:Qc                     [         c  [        S[        R                  " 5       -  / 5      n [	        U 5      S:X  a  U S   S;   a  U S   q OS/ [        5       p![        S5       H(  n X#   c    O! UR                  [        X#   5      5        M*     SR                  U5      q [	        [         5      q[         $ ! [         a       M4  f = f)zc
Provides the present name of our process.

:returns: **str** with the present name of our process
zps -p %i -o argsrP   r   )r   ARGSrO   d   rx   )_PROCESS_NAMEr   rX   getpidr   argc_tranger   r   r  rQ   _MAX_NAME_LENGTH)r  r;   argcis       r   get_process_namerZ  J  s      '"))+5r:I
9~y|/BBlm vxDSz!	W_ 
 	CL!  hhtnm=)	  	
	s   "B00
B?>B?c                     [        U 5        [        R                  " 5       S:X  a  [        U 5        g[        R                  " 5       S;   a  [	        U 5        gg)z
Renames our current process from "python <args>" to a custom name. This is
best-effort, not necessarily working on all platforms.

:param str process_name: new name for our process

:raises: **IOError** if the process cannot be renamed
Linux)ri   rs   rt   N)	_set_argvre   rf   _set_prctl_name_set_proc_title)r   s    r   set_process_namer`  ~  s@    4 L__'!L!<<L! =r   c                    [         c  g[        5       n[        R                  " S5      [	        5       p2[        U[        R
                  " U5      5        [        U 5      [        :  a  [        S5      e[        [        U5      [        U 5      5      n[        R                  " UR                  SUS-   5        U R                  S5      n[        R                  " UR                  U[        U 5      5        U qg)zc
Overwrites our argv in a similar fashion to how it's done in C with:
strcpy(argv[0], 'new_name');
Nr   zmCan't rename process to something longer than our initial name (this would overwrite memory used for the env)rO   utf8)Py_GetArgcArgvrZ  ctypesc_intrU  pointerr   rW  r   maxmemsetcontentsencodememmoverS  )r   current_nameargvrX  	zero_sizeprocess_name_encodeds         r   r]  r]    s     
 "#,||Av~~d+,))
  B  C  C #l#S%67)--q)a-0%,,V4.. 4c,6GH-r   c                 d   [         R                  " [         R                  R                  S5      5      n[         R                  " [        U 5      S-   5      n[        R                  R                  R                  U 5      Ul	        UR                  [        [         R                  " U5      SSS5        g)z
Sets the prctl name, which is used by top and killall. This appears to be
Linux specific and has the max of 15 characters.

This is from...
http://stackoverflow.com/questions/564695/is-there-a-way-to-change-effective-process-name-in-python/923034#923034
r   rO   r   N)rd  CDLLr   find_librarycreate_string_bufferr   r   r   	_to_bytesvalueprctlPR_SET_NAMEbyrefr   libcname_buffers      r   r^  r^    su     
V[[--c2	3$++C,=,AB+ii))33LA+**[&,,{3Q1=r   c                 D   [         R                  " [         R                  R                  S5      5      n[         R                  " [        U 5      S-   5      nU R                  5       Ul         UR                  [         R                  " U5      5        g! [         a     gf = f)z
BSD specific calls (should be compataible with both FreeBSD and OpenBSD:
http://fxr.watson.org/fxr/source/gen/setproctitle.c?v=FREEBSD-LIBC
http://www.rootr.net/man/man/setproctitle/3
r   rO   N)rd  rq  r   rr  rs  r   rj  ru  setproctitlerx  r"  ry  s      r   r_  r_    s|     
V[[--c2	3$++C,=,AB+"))++	fll;/0	 	 			s   ,%B 
BB)Tr
   )F)pr*   collectionsrd  ctypes.utilr   r#  rH   rX   re   r   r?  r   r   	threadingrW   stem.prereqr   	stem.utilstem.util.enumstem.util.procstem.util.str_toolsr   r   r   enumUppercaseEnumr=   tupleiterr   dequedictr   	frozensetr   r}   r|   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r  r  rw  POINTERc_char_prU  	pythonapirc  restypere  argtypesrS  rW  rI  RLockrH  r   r   r.   objectr7   rg   rj   ro   rq   rv   r   r   r   r   r   r   r   r   r   r   r^   r  r  r  r!  r0  r:  r   rZ  r`  r]  r^  r_  get_name_by_pidget_pid_by_nameget_pid_by_portget_pid_by_open_fileget_cwdget_userget_start_timeget_bsd_jail_idget_bsd_jail_pathr,   r   r   <module>r     s  =~       	  	  
          		$$
		 T:tT   ( # ' % " , ! $ * 6 5 $ * ( )&  
 		(
##22..
NN6<< 
NN6.     !)  4y W Wt('/2I(V;|(V(Vh"Vup#L@BJB>2j F,@4*Z-. &ETY]ei b3J1h"D<>	0 ' 
! a*.s   &AG& &G,